[TD]add ability to filter obvious geometry errors

- also add checks for geometry errors
This commit is contained in:
wandererfan
2019-12-08 20:34:47 -05:00
committed by WandererFan
parent 17b61adf16
commit e1e9c7e7bd
6 changed files with 218 additions and 197 deletions

View File

@@ -41,6 +41,7 @@
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Elips.hxx>
#include <Precision.hxx>
#include <BRep_Builder.hxx>
#include <BRepAdaptor_Curve.hxx>
@@ -52,6 +53,7 @@
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <GProp_GProps.hxx>
#include <GeomLProp_SLProps.hxx>
#include <BRepAdaptor_Surface.hxx>
@@ -641,6 +643,69 @@ PyObject* DrawUtil::colorToPyTuple(App::Color color)
return pTuple;
}
//check for crazy edge. This is probably a geometry error of some sort.
bool DrawUtil::isCrazy(TopoDS_Edge e)
{
bool result = false;
double ratio = 1.0;
if (e.IsNull()) {
result = true;
return result;
}
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
GetGroup("Preferences")->GetGroup("Mod/TechDraw/debug");
bool crazyOK = hGrp->GetBool("allowCrazyEdge", true);
if (crazyOK) {
return false;
}
BRepAdaptor_Curve adapt(e);
double edgeLength = GCPnts_AbscissaPoint::Length(adapt, Precision::Confusion());
if (edgeLength < 0.00001) { //edge is scaled. this is 0.00001 mm on paper
Base::Console().Log("DU::isCrazy - edge crazy short: %.7f\n", edgeLength);
result = true;
return result;
}
if (edgeLength > 9999.9) { //edge is scaled. this is 10 m on paper. can't be right?
Base::Console().Log("DU::isCrazy - edge crazy long: %.3f\n", edgeLength);
result = true;
return result;
}
double start = BRepLProp_CurveTool::FirstParameter(adapt);
double end = BRepLProp_CurveTool::LastParameter(adapt);
BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion());
const gp_Pnt& vStart = propStart.Value();
BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion());
const gp_Pnt& vEnd = propEnd.Value();
double distance = vStart.Distance(vEnd);
if (adapt.GetType() == GeomAbs_BSplineCurve) {
if (distance > 0.001) { // not a closed loop
ratio = edgeLength / distance;
if (ratio > 9999.9) { // 10,000x
result = true; //this is crazy edge
}
}
} else if (adapt.GetType() == GeomAbs_Ellipse) {
gp_Elips ellp = adapt.Ellipse();
double major = ellp.MajorRadius();
double minor = ellp.MinorRadius();
if (minor < 0.001) { //too narrow
Base::Console().Log("DU::isCrazy - ellipse is crazy narrow: %.7f\n", minor);
result = true;
} else if (major > 9999.9) { //too big
Base::Console().Log("DU::isCrazy - ellipse is crazy wide: %.3f\n", major);
result = true;
}
}
// Base::Console().Message("DU::isCrazy - returns: %d ratio: %.3f\n", result, ratio);
return result;
}
// Supplementary mathematical functions
// ====================================
@@ -1048,7 +1113,6 @@ void DrawUtil::dumpEdges(const char* text, const TopoDS_Shape& s)
}
}
void DrawUtil::dump1Vertex(const char* text, const TopoDS_Vertex& v)
{
Base::Console().Message("DUMP - dump1Vertex - %s\n",text);
@@ -1069,7 +1133,11 @@ void DrawUtil::dumpEdge(const char* label, int i, TopoDS_Edge e)
// vStart.X(),vStart.Y(),vStart.Z(),start,vEnd.X(),vEnd.Y(),vEnd.Z(),end);
Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f) end:(%.2f,%.3f,%.3f) Orient: %d\n",label,i,
vStart.X(),vStart.Y(),vStart.Z(),vEnd.X(),vEnd.Y(),vEnd.Z(), e.Orientation());
double edgeLength = GCPnts_AbscissaPoint::Length(adapt, Precision::Confusion());
Base::Console().Message(">>>>>>> length: %.3f distance: %.3f ration: %.3f type: %d\n", edgeLength,
vStart.Distance(vEnd), edgeLength / vStart.Distance(vEnd), adapt.GetType());
}
const char* DrawUtil::printBool(bool b)
{
return (b ? "True" : "False");

View File

@@ -114,6 +114,7 @@ class TechDrawExport DrawUtil {
static std::vector<std::string> tokenize(std::string csvLine, std::string delimiter = ",$$$,");
static App::Color pyTupleToColor(PyObject* pColor);
static PyObject* colorToPyTuple(App::Color color);
static bool isCrazy(TopoDS_Edge e);
// Supplementary mathematical functions
static int sgn(double x);

View File

@@ -229,11 +229,6 @@ void BaseGeom::Restore(Base::XMLReader &reader)
m_sourceIndex = reader.getAttributeAsInteger("value");
reader.readElement("CosmeticTag");
cosmeticTag = reader.getAttribute("value");
// reader.readElement("Tag");
// std::string temp = reader.getAttribute("value");
// boost::uuids::string_generator gen;
// boost::uuids::uuid u1 = gen(temp);
// tag = u1;
}
std::vector<Base::Vector3d> BaseGeom::findEndPoints()
@@ -393,6 +388,14 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
if (edge.IsNull()) {
Base::Console().Message("BG::baseFactory - input edge is NULL \n");
}
//weed out rubbish edges before making geometry
if (!validateEdge(edge)) {
return result;
}
Generic *primitive = new Generic(edge);
result = primitive;
BRepAdaptor_Curve adapt(edge);
switch(adapt.GetType()) {
case GeomAbs_Circle: {
@@ -401,6 +404,9 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
gp_Pnt s = adapt.Value(f);
gp_Pnt e = adapt.Value(l);
//don't understand this test.
//if first to last is > 1 radian? are circles parameterize by rotation angle?
//if start and end points are close?
if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) {
Circle *circle = new Circle(edge);
result = circle;
@@ -430,7 +436,6 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
result->reversed = true;
}
//}
// OCC is quite happy with Degree > 3 but QtGui handles only 2,3
} break;
case GeomAbs_BSplineCurve: {
@@ -438,6 +443,8 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
Generic* gen = NULL;
Circle* circ = nullptr;
AOC* aoc = nullptr;
TopoDS_Edge circEdge;
bool isArc = false;
try {
bspline = new BSpline(edge);
@@ -447,7 +454,7 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
delete bspline;
bspline = nullptr;
} else {
TopoDS_Edge circEdge = bspline->asCircle(isArc);
circEdge = bspline->asCircle(isArc);
if (!circEdge.IsNull()) {
if (isArc) {
aoc = new AOC(circEdge);
@@ -461,12 +468,15 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
bspline = nullptr;
}
} else {
// Base::Console().Message("Geom::baseFactory - circEdge is Null\n");
result = bspline;
}
}
break;
}
catch (Standard_Failure&) {
catch (const Standard_Failure& e) {
Base::Console().Error("Geom::baseFactory - OCC error - %s - while making spline\n",
e.GetMessageString());
if (bspline != nullptr) {
delete bspline;
bspline = nullptr;
@@ -475,16 +485,39 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge)
delete gen;
gen = nullptr;
}
break;
}
}
catch (...) {
Base::Console().Error("Geom::baseFactory - unknown error occurred while making spline\n");
if (bspline != nullptr) {
delete bspline;
bspline = nullptr;
}
if (gen != nullptr) {
delete gen;
gen = nullptr;
}
break;
} break;
} // end bspline case
default: {
Generic *primitive = new Generic(edge);
primitive = new Generic(edge);
result = primitive;
} break;
}
if ( (primitive != nullptr) &&
(primitive != result) ) {
delete primitive;
}
return result;
}
bool BaseGeom::validateEdge(TopoDS_Edge edge)
{
return !DrawUtil::isCrazy(edge);
}
Ellipse::Ellipse(const TopoDS_Edge &e)
{
@@ -515,10 +548,17 @@ AOE::AOE(const TopoDS_Edge &e) : Ellipse(e)
gp_Pnt m = c.Value((l+f)/2.0);
gp_Pnt ePt = c.Value(l);
gp_Vec v1(m,s);
gp_Vec v2(m,ePt);
gp_Vec v3(0,0,1);
double a = v3.DotCross(v1,v2);
double a;
try {
gp_Vec v1(m,s);
gp_Vec v2(m,ePt);
gp_Vec v3(0,0,1);
a = v3.DotCross(v1,v2);
}
catch (const Standard_Failure& e) {
Base::Console().Error("Geom::AOE::AOE - OCC error - %s - while making AOE in ctor\n",
e.GetMessageString());
}
startAngle = fmod(f,2.0*M_PI);
endAngle = fmod(l,2.0*M_PI);
@@ -564,34 +604,6 @@ std::string Circle::toString(void) const
return baseCSV + ",$$$," + ss.str();
}
//bool Circle::fromCSV(std::string lineSpec)
//{
// if (lineSpec.length() == 0) {
// Base::Console().Message( "Circle::fromCSV - lineSpec empty\n");
// return false;
// }
// std::vector<std::string> tokens = DrawUtil::tokenize(lineSpec);
// //"baseCSV,$$$,circleCSV"
// if (tokens.size() != 2) {
// Base::Console().Message("CosmeticEdge::fromCSV - tokenize failed - size: %d\n",tokens.size());
// }
// BaseGeom::fromCSV(tokens[0]);
// unsigned int maxCells = 4;
// std::vector<std::string> values = DrawUtil::split(tokens[1]);
// if (values.size() < maxCells) {
// Base::Console().Message( "Circle::fromCSV(%s) invalid CSV entry\n",lineSpec.c_str() );
// return false;
// }
// double x = atof(values[0].c_str());
// double y = atof(values[1].c_str());
// double z = atof(values[2].c_str());
// center = Base::Vector3d(x,y,z);
// radius = atof(values[3].c_str());
// return true;
//}
void Circle::Save(Base::Writer &writer) const
{
BaseGeom::Save(writer);
@@ -627,11 +639,11 @@ AOC::AOC(const TopoDS_Edge &e) : Circle(e)
double l = c.LastParameter();
gp_Pnt s = c.Value(f);
gp_Pnt m = c.Value((l+f)/2.0);
gp_Pnt ePt = c.Value(l);
gp_Pnt ePt = c.Value(l); //if start == end, it isn't an arc!
gp_Vec v1(m,s); //vector mid to start
gp_Vec v2(m,ePt); //vector mid to end
gp_Vec v3(0,0,1); //stdZ
double a = v3.DotCross(v1,v2);
double a = v3.DotCross(v1,v2); //error if v1 = v2?
startAngle = fmod(f,2.0*M_PI);
endAngle = fmod(l,2.0*M_PI);
@@ -733,46 +745,6 @@ std::string AOC::toString(void) const
return result;
}
//bool AOC::fromCSV(std::string lineSpec)
//{
//// Base::Console().Message( "AOC::fromCSV(%s)\n", lineSpec.c_str());
// if (lineSpec.length() == 0) {
// Base::Console().Message( "AOC::fromCSV - lineSpec empty\n");
// return false;
// }
// std::vector<std::string> tokens = DrawUtil::tokenize(lineSpec);
// //"(baseCSV,$$$,circleCSV),$$$,AOCCSV"
// // [0] [1] [2]
// if (tokens.size() != 3) {
// Base::Console().Message("CosmeticEdge::fromCSV - tokenize failed - size: %d\n",tokens.size());
// }
// Circle::fromCSV(tokens[0] + ",$$$," + tokens[1]); //extra work here.
// unsigned int maxCells = 13;
// std::vector<std::string> values = DrawUtil::split(tokens[2]); // we are only interested in last token
// if (values.size() < maxCells) {
// Base::Console().Message( "AOC::fromCSV(%s) invalid CSV entry\n",lineSpec.c_str() );
// return false;
// }
// double x = atof(values[0].c_str());
// double y = atof(values[1].c_str());
// double z = atof(values[2].c_str());
// startPnt = Base::Vector3d(x,y,z);
// x = atof(values[3].c_str());
// y = atof(values[4].c_str());
// z = atof(values[5].c_str());
// endPnt = Base::Vector3d(x,y,z);
// x = atof(values[6].c_str());
// y = atof(values[7].c_str());
// z = atof(values[8].c_str());
// midPnt = Base::Vector3d(x,y,z);
// startAngle = atof(values[9].c_str());
// endAngle = atof(values[10].c_str());
// cw = atoi(values[11].c_str());
// largeArc = atoi(values[12].c_str());
// return true;
//}
void AOC::Save(Base::Writer &writer) const
{
Circle::Save(writer);
@@ -873,35 +845,6 @@ std::string Generic::toString(void) const
return baseCSV + ",$$$," + genericCSV;
}
//bool Generic::fromCSV(std::string lineSpec)
//{
// std::vector<std::string> tokens = DrawUtil::tokenize(lineSpec);
// //"baseCSV,$$$,genericCSV"
// if (tokens.size() != 2) {
// Base::Console().Message("Generic::fromCSV - tokenize failed - size: %d\n",tokens.size());
// }
// BaseGeom::fromCSV(tokens[0]);
// if (lineSpec.length() == 0) {
// Base::Console().Message( "Generic::fromCSV - lineSpec empty\n");
// return false;
// }
// std::vector<std::string> values = DrawUtil::split(tokens[1]);
// if (!values.empty()) {
// double count = atoi(values[0].c_str());
// points.clear();
// int i = 0;
// for ( ; i < count; i++) {
// int idx = i * 3;
// double x = atof(values[idx+1].c_str());
// double y = atof(values[idx+2].c_str());
// double z = atof(values[idx+3].c_str());
// points.push_back(Base::Vector3d(x, y, z));
// }
// }
// return true;
//}
void Generic::Save(Base::Writer &writer) const
{
@@ -1189,99 +1132,105 @@ TopoDS_Edge BSpline::asCircle(bool& arc)
gp_Pnt s = c.Value(f);
gp_Pnt e = c.Value(l);
arc = !c.IsClosed();
if (s.IsEqual(e, 0.001)) { //more reliable
arc = false;
} else {
arc = true;
}
// arc = !c.IsClosed(); //reliable?
Handle(Geom_BSplineCurve) spline = c.BSpline();
if (spline->NbPoles() < 5) { //need 5 poles (s-p1-pm-p2-e) for algo
return result; //how to do with fewer poles?
}
// get three points on curve (non extreme poles)
int nb_poles = spline->NbPoles();
gp_Pnt p1 = spline->Pole(2); //OCC numbering starts at 1!!
gp_Pnt p2 = spline->Pole(nb_poles-1);
gp_Pnt pm;
if (nb_poles == 5) {
pm = spline->Pole(3); //5 poles => 2.5 => 2
} else {
pm = spline->Pole(nb_poles / 2);
}
// project three poles onto the curve
GeomAPI_ProjectPointOnCurve proj1;
GeomAPI_ProjectPointOnCurve proj2;
GeomAPI_ProjectPointOnCurve projm;
try {
// get three points on curve (non extreme poles)
int nb_poles = spline->NbPoles();
gp_Pnt p1 = spline->Pole(2); //OCC numbering starts at 1!!
gp_Pnt p2 = spline->Pole(nb_poles-1);
gp_Pnt pm;
if (nb_poles == 5) {
pm = spline->Pole(3); //5 poles => 2.5 => 2
} else {
pm = spline->Pole(nb_poles / 2);
}
// project three poles onto the curve
GeomAPI_ProjectPointOnCurve proj1;
GeomAPI_ProjectPointOnCurve proj2;
GeomAPI_ProjectPointOnCurve projm;
proj1.Init(p1, curve, f, l);
proj1.Perform(p1);
proj2.Init(p2, curve, f, l);
proj2.Perform(p2);
projm.Init(pm, curve, f, l);
projm.Perform(pm);
}
catch(const StdFail_NotDone &e) {
Base::Console().Log("Geometry::asCircle - init: %s\n",e.GetMessageString());
return result;
}
if ( (proj1.NbPoints() == 0) ||
(proj2.NbPoints() == 0) ||
(projm.NbPoints() == 0) ) {
return result;
}
gp_Pnt pc1, pc2, pcm;
if ( (proj1.NbPoints() == 0) ||
(proj2.NbPoints() == 0) ||
(projm.NbPoints() == 0) ) {
return result;
}
gp_Pnt pc1, pc2, pcm;
// get projected points
try {
// get projected points
pc1 = proj1.NearestPoint();
pc2 = proj2.NearestPoint();
pcm = projm.NearestPoint();
}
catch(const StdFail_NotDone &e) {
Base::Console().Log("Geometry::asCircle - nearPoint: %s\n",e.GetMessageString());
return result;
}
// make 2 circles and find their radii
gce_MakeCirc gce_circ1 = gce_MakeCirc(s,pc1,pcm); //3 point circle
if (gce_circ1.Status() != gce_Done) {
return result;
}
gp_Circ circle1 = gce_circ1.Value();
double radius1 = circle1.Radius();
gp_Pnt center1 = circle1.Location();
Base::Vector3d vc1 = DrawUtil::gpPnt2V3(center1);
// make 2 circles and find their radii
gce_MakeCirc gce_circ1 = gce_MakeCirc(s,pc1,pcm); //3 point circle
if (gce_circ1.Status() != gce_Done) {
return result;
}
gp_Circ circle1 = gce_circ1.Value();
double radius1 = circle1.Radius();
gp_Pnt center1 = circle1.Location();
Base::Vector3d vc1 = DrawUtil::gpPnt2V3(center1);
gce_MakeCirc gce_circ2 = gce_MakeCirc(pcm,pc2,e);
if (gce_circ2.Status() != gce_Done) {
return result;
}
gp_Circ circle2 = gce_circ2.Value();
double radius2 = circle2.Radius();
gp_Pnt center2 = circle2.Location();
Base::Vector3d vc2 = DrawUtil::gpPnt2V3(center2);
gce_MakeCirc gce_circ2 = gce_MakeCirc(pcm,pc2,e);
if (gce_circ2.Status() != gce_Done) {
return result;
}
gp_Circ circle2 = gce_circ2.Value();
double radius2 = circle2.Radius();
gp_Pnt center2 = circle2.Location();
Base::Vector3d vc2 = DrawUtil::gpPnt2V3(center2);
// compare radii & centers
double allowError = 0.001; //mm^-3 good enough for printing
double radius;
Base::Vector3d center;
if ( (DrawUtil::fpCompare(radius2,radius1, allowError)) &&
(vc1.IsEqual(vc2,allowError)) ) {
if (arc) {
GC_MakeArcOfCircle makeArc(s,pcm,e);
Handle(Geom_TrimmedCurve) tCurve = makeArc.Value();
BRepBuilderAPI_MakeEdge newEdge(tCurve);
result = newEdge;
} else {
radius = (radius1 + radius2) / 2.0;
center = (vc1 + vc2) / 2.0;
gp_Pnt gCenter(center.x,center.y,center.z);
gp_Ax2 stdZ(gCenter,gp_Dir(0,0,1));
gp_Circ newCirc(stdZ,radius);
BRepBuilderAPI_MakeEdge newEdge(newCirc);
result = newEdge;
// compare radii & centers
double allowError = 0.001; //mm^-3 good enough for printing
double radius;
Base::Vector3d center;
if ( (DrawUtil::fpCompare(radius2,radius1, allowError)) &&
(vc1.IsEqual(vc2,allowError)) ) {
if (arc) {
GC_MakeArcOfCircle makeArc(s,pcm,e);
Handle(Geom_TrimmedCurve) tCurve = makeArc.Value();
BRepBuilderAPI_MakeEdge newEdge(tCurve);
result = newEdge;
} else {
radius = (radius1 + radius2) / 2.0;
center = (vc1 + vc2) / 2.0;
gp_Pnt gCenter(center.x,center.y,center.z);
gp_Ax2 stdZ(gCenter,gp_Dir(0,0,1));
gp_Circ newCirc(stdZ,radius);
BRepBuilderAPI_MakeEdge newEdge(newCirc);
result = newEdge;
}
}
}
catch (const Standard_Failure& e) {
Base::Console().Log("Geom::asCircle - OCC error - %s - while approx spline as circle\n",
e.GetMessageString());
TopoDS_Edge nullReturn;
result = nullReturn;
}
catch (...) {
Base::Console().Log("Geom::asCircle - unknown error occurred while approx spline as circle\n");
TopoDS_Edge nullReturn;
result = nullReturn;
}
return result;
}
@@ -1472,14 +1421,6 @@ std::string Vertex::getTagAsString(void) const
return tmp;
}
//void Vertex::assignTag(const TechDraw::Vertex* v)
//{
// if(v->getTypeId() == this->getTypeId())
// this->tag = v->tag;
// else
// throw Base::TypeError("Vertex tag can not be assigned as types do not match.");
//}
void Vertex::dump(const char* title)
{
Base::Console().Message("TD::Vertex - %s - point: %s vis: %d cosmetic: %d cosLink: %d cosTag: %s\n",

View File

@@ -106,6 +106,7 @@ class TechDrawExport BaseGeom
Base::Vector3d nearPoint(Base::Vector3d p);
Base::Vector3d nearPoint(const BaseGeom* p);
static BaseGeom* baseFactory(TopoDS_Edge edge);
static bool validateEdge(TopoDS_Edge edge);
bool closed(void);
BaseGeom* copy();
std::string dump();

View File

@@ -480,7 +480,7 @@ void GeometryObject::extractGeometry(edgeClass category, bool hlrVisible)
//! update edgeGeom and vertexGeom from Compound of edges
void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass category, bool hlrVisible)
{
// Base::Console().Message("GO::addGeomFromCompound()\n");
// Base::Console().Message("GO::addGeomFromCompound(%d, %d)\n", category, hlrVisible);
if(edgeCompound.IsNull()) {
Base::Console().Log("TechDraw::GeometryObject::addGeomFromCompound edgeCompound is NULL\n");
return; // There is no OpenCascade Geometry to be calculated
@@ -492,19 +492,25 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca
for ( ; edges.More(); edges.Next(),i++) {
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
if (edge.IsNull()) {
//Base::Console().Log("INFO - GO::addGeomFromCompound - edge: %d is NULL\n",i);
Base::Console().Log("GO::addGeomFromCompound - edge: %d is NULL\n",i);
continue;
}
if (DrawUtil::isZeroEdge(edge)) {
Base::Console().Log("INFO - GO::addGeomFromCompound - edge: %d is zeroEdge\n",i);
Base::Console().Log("GO::addGeomFromCompound - edge: %d is zeroEdge\n",i);
continue;
}
if (DrawUtil::isCrazy(edge)) {
Base::Console().Log("GO::addGeomFromCompound - edge: %d is crazy\n",i);
continue;
}
base = BaseGeom::baseFactory(edge);
if (base == nullptr) {
Base::Console().Log("Error - GO::addGeomFromCompound - baseFactory failed for edge: %d\n",i);
throw Base::ValueError("GeometryObject::addGeomFromCompound - baseFactory failed");
continue;
// throw Base::ValueError("GeometryObject::addGeomFromCompound - baseFactory failed");
}
base->source(0); //object geometry
base->sourceIndex(i-1);
base->classOfEdge = category;

View File

@@ -148,6 +148,10 @@ QPainterPath QGIViewPart::geomToPainterPath(TechDraw::BaseGeom *baseGeom, double
Q_UNUSED(rot);
QPainterPath path;
if (baseGeom == nullptr) {
return path;
}
switch(baseGeom->geomType) {
case CIRCLE: {
TechDraw::Circle *geom = static_cast<TechDraw::Circle *>(baseGeom);