From dd13cb25347ee9182bd090bcaab4001a88d13e6d Mon Sep 17 00:00:00 2001 From: WandererFan Date: Fri, 18 Nov 2016 09:52:55 -0500 Subject: [PATCH] Fix handling of BezierCurves Replace custom bbox code with OCC/Base code Refactor duplicate code Geometry/DrawProjectSplit --- src/Mod/TechDraw/App/DrawProjectSplit.cpp | 26 +-- src/Mod/TechDraw/App/DrawProjectSplit.h | 8 +- src/Mod/TechDraw/App/DrawUtil.cpp | 26 ++- src/Mod/TechDraw/App/DrawUtil.h | 1 + src/Mod/TechDraw/App/Geometry.cpp | 112 +++++----- src/Mod/TechDraw/App/Geometry.h | 31 ++- src/Mod/TechDraw/App/GeometryObject.cpp | 260 ++-------------------- src/Mod/TechDraw/App/GeometryObject.h | 15 +- src/Mod/TechDraw/Gui/QGIViewPart.cpp | 43 +++- 9 files changed, 152 insertions(+), 370 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawProjectSplit.cpp b/src/Mod/TechDraw/App/DrawProjectSplit.cpp index addb679d5a..8cf21adf4e 100644 --- a/src/Mod/TechDraw/App/DrawProjectSplit.cpp +++ b/src/Mod/TechDraw/App/DrawProjectSplit.cpp @@ -124,8 +124,8 @@ std::vector DrawProjectSplit::getEdgesForWalker(TopoDS_Shape shape, TechDrawGeometry::GeometryObject* DrawProjectSplit::buildGeometryObject( - TopoDS_Shape shape, - gp_Pnt& inputCenter, + TopoDS_Shape shape, + gp_Pnt& inputCenter, Base::Vector3d direction) { TechDrawGeometry::GeometryObject* geometryObject = new TechDrawGeometry::GeometryObject("DrawProjectSplit"); @@ -231,30 +231,10 @@ std::vector DrawProjectSplit::getEdges(TechDrawGeometry::GeometryOb Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n"); } newEdges = removeDuplicateEdges(newEdges); - return newEdges; } -double DrawProjectSplit::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2) -{ - Standard_Real minDist = -1; - - BRepExtrema_DistShapeShape extss(s1, s2); - if (!extss.IsDone()) { - Base::Console().Message("FE - BRepExtrema_DistShapeShape failed"); - return -1; - } - int count = extss.NbSolution(); - if (count != 0) { - minDist = extss.Value(); - } else { - minDist = -1; - } - return minDist; -} - - //this routine is the big time consumer. gets called many times (and is slow?)) //note param gets modified here bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds) @@ -276,7 +256,7 @@ bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, b } } if (!outOfBox) { - double dist = simpleMinDist(v,e); + double dist = DrawUtil::simpleMinDist(v,e); if (dist < 0.0) { Base::Console().Error("DPS::isOnEdge - simpleMinDist failed: %.3f\n",dist); result = false; diff --git a/src/Mod/TechDraw/App/DrawProjectSplit.h b/src/Mod/TechDraw/App/DrawProjectSplit.h index 07165129dd..ec04f27e05 100644 --- a/src/Mod/TechDraw/App/DrawProjectSplit.h +++ b/src/Mod/TechDraw/App/DrawProjectSplit.h @@ -46,8 +46,7 @@ class BaseGeom; namespace TechDraw { -struct splitPoint -{ +struct splitPoint { int i; Base::Vector3d v; double param; @@ -69,8 +68,6 @@ public: static bool edgeEqual(const edgeSortItem& e1, const edgeSortItem& e2); std::string dump(void); }; - - class TechDrawExport DrawProjectSplit { public: @@ -84,16 +81,13 @@ public: static bool isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds = false); static std::vector splitEdges(std::vector orig, std::vector splits); static std::vector split1Edge(TopoDS_Edge e, std::vector splitPoints); - static double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); static std::vector sortSplits(std::vector& s, bool ascend); static bool splitCompare(const splitPoint& p1, const splitPoint& p2); static bool splitEqual(const splitPoint& p1, const splitPoint& p2); - static std::vector removeDuplicateEdges(std::vector& inEdges); static std::vector sortEdges(std::vector& e, bool ascend); - protected: static std::vector getEdges(TechDrawGeometry::GeometryObject* geometryObject); diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index d10f518bde..2422e93668 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -39,14 +39,15 @@ #include #include #include -#include -#include #include +#include +#include +#include #include +#include #include #include #include -#include #include #endif @@ -139,6 +140,23 @@ bool DrawUtil::isZeroEdge(TopoDS_Edge e) } return result; } +double DrawUtil::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2) +{ + Standard_Real minDist = -1; + + BRepExtrema_DistShapeShape extss(s1, s2); + if (!extss.IsDone()) { + Base::Console().Message("DU::simpleMinDist - BRepExtrema_DistShapeShape failed"); + return -1; + } + int count = extss.NbSolution(); + if (count != 0) { + minDist = extss.Value(); + } else { + minDist = -1; + } + return minDist; +} //! assumes 2d on XY //! quick angle for straight edges @@ -211,7 +229,6 @@ double DrawUtil::angleWithX(TopoDS_Edge e, TopoDS_Vertex v) return result; } - bool DrawUtil::isFirstVert(TopoDS_Edge e, TopoDS_Vertex v) { bool result = false; @@ -286,6 +303,7 @@ int DrawUtil::vectorCompare(const Base::Vector3d& v1, const Base::Vector3d& v2) } + //based on Function provided by Joe Dowsett, 2014 double DrawUtil::sensibleScale(double working_scale) { diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index 4500ecdd9a..3c7a1636b5 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -47,6 +47,7 @@ class TechDrawExport DrawUtil { static std::string makeGeomName(std::string geomType, int index); static bool isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2); static bool isZeroEdge(TopoDS_Edge e); + static double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); static double sensibleScale(double working_scale); static double angleWithX(TopoDS_Edge e, bool reverse); static double angleWithX(TopoDS_Edge e, TopoDS_Vertex v); diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index 0bd2eaded2..ceb325c9c3 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -54,8 +54,9 @@ #include #include #include -//#include + #include "Geometry.h" +#include "DrawUtil.h" using namespace TechDrawGeometry; @@ -64,7 +65,6 @@ Wire::Wire() { } - Wire::Wire(const TopoDS_Wire &w) { TopExp_Explorer edges(w, TopAbs_EDGE); @@ -72,10 +72,8 @@ Wire::Wire(const TopoDS_Wire &w) const auto edge( TopoDS::Edge(edges.Current()) ); geoms.push_back( BaseGeom::baseFactory(edge) ); } - } - Wire::~Wire() { for(auto it : geoms) { @@ -84,7 +82,6 @@ Wire::~Wire() geoms.clear(); } - Face::~Face() { for(auto it : wires) { @@ -93,14 +90,13 @@ Face::~Face() wires.clear(); } - BaseGeom::BaseGeom() : geomType(NOTDEF), - extractType(Plain), + extractType(Plain), //obs classOfEdge(ecNONE), visible(true), reversed(false), - ref3D(-1) + ref3D(-1) //obs? { } @@ -137,13 +133,7 @@ double BaseGeom::minDist(Base::Vector2D p) double minDist = -1.0; gp_Pnt pnt(p.fX,p.fY,0.0); TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(pnt); - BRepExtrema_DistShapeShape extss(occEdge, v); - if (extss.IsDone()) { - int count = extss.NbSolution(); - if (count != 0) { - minDist = extss.Value(); - } - } + minDist = TechDraw::DrawUtil::simpleMinDist(occEdge,v); return minDist; } @@ -181,13 +171,22 @@ Base::Vector2D BaseGeom::nearPoint(Base::Vector2D p) return result; } +std::string BaseGeom::dump() +{ + Base::Vector2D start = getStartPoint(); + Base::Vector2D end = getEndPoint(); + std::stringstream ss; + ss << "BaseGeom: s:(" << start.fX << "," << start.fY << ") e:(" << end.fX << "," << end.fY << ") "; + ss << "type: " << geomType << " class: " << classOfEdge << " viz: " << visible << " rev: " << reversed; + return ss.str(); +} + //! Convert 1 OCC edge into 1 BaseGeom (static factory method) BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge) { BaseGeom* result = NULL; BRepAdaptor_Curve adapt(edge); - switch(adapt.GetType()) { case GeomAbs_Circle: { double f = adapt.FirstParameter(); @@ -197,11 +196,9 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge) if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { Circle *circle = new Circle(edge); - //circle->extractType = extractionType; result = circle; } else { AOC *aoc = new AOC(edge); - //aoc->extractType = extractionType; result = aoc; } } break; @@ -212,40 +209,47 @@ BaseGeom* BaseGeom::baseFactory(TopoDS_Edge edge) gp_Pnt e = adapt.Value(l); if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { Ellipse *ellipse = new Ellipse(edge); - //ellipse->extractType = extractionType; result = ellipse; } else { AOE *aoe = new AOE(edge); - //aoe->extractType = extractionType; result = aoe; } } break; + case GeomAbs_BezierCurve: { + Handle_Geom_BezierCurve bez = adapt.Bezier(); + //if (bez->Degree() < 4) { + result = new BezierSegment(edge); + //} + // OCC is quite happy with Degree > 3 but QtGui handles only 2,3 + } break; case GeomAbs_BSplineCurve: { BSpline *bspline = 0; Generic* gen = NULL; try { bspline = new BSpline(edge); - //bspline->extractType = extractionType; if (bspline->isLine()) { gen = new Generic(edge); - //gen->extractType = extractionType; result = gen; delete bspline; + bspline = nullptr; } else { result = bspline; } break; } catch (Standard_Failure) { - delete bspline; - delete gen; - bspline = 0; - // Move onto generating a primitive + if (bspline != nullptr) { + delete bspline; + bspline = nullptr; + } + if (gen != nullptr) { + delete gen; + gen = nullptr; + } } } default: { Generic *primitive = new Generic(edge); - //primitive->extractType = extractionType; result = primitive; } break; } @@ -306,8 +310,6 @@ Circle::Circle(const TopoDS_Edge &e) gp_Circ circ = c.Circle(); const gp_Pnt& p = circ.Location(); - //const gp_Ax2& p1 = circ.Position(); - //const gp_Pnt& l = p1.Location(); radius = circ.Radius(); center = Base::Vector2D(p.X(), p.Y()); @@ -364,17 +366,6 @@ double AOC::distToArc(Base::Vector3d p) Base::Vector2D p2(p.x,p.y); double result = minDist(p2); return result; -// double minDist = -1.0; -// gp_Pnt pnt(p.x,p.y,p.z); -// TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(pnt); -// BRepExtrema_DistShapeShape extss(occEdge, v); -// if (extss.IsDone()) { -// int count = extss.NbSolution(); -// if (count != 0) { -// minDist = extss.Value(); -// } -// } -// return minDist; } @@ -443,6 +434,8 @@ BSpline::BSpline(const TopoDS_Edge &e) double f,l; gp_Pnt s,m,ePt; //if startpoint == endpoint conversion to BSpline will fail + //Base::Console().Message("TRACE - Geometry::BSpline - start(%.3f,%.3f,%.3f) end(%.3f,%.3f,%.3f)\n", + // s.X(),s.Y(),s.Z(),ePt.X(),ePt.Y(),ePt.Z()); if (spline->Degree() > 3) { //if spline is too complex, approximate it Standard_Real tol3D = 0.001; //1/1000 of a mm? screen can't resolve this @@ -464,36 +457,36 @@ BSpline::BSpline(const TopoDS_Edge &e) s = c.Value(f); m = c.Value((l+f)/2.0); ePt = c.Value(l); - Base::Console().Log("Error - Geometry::BSpline - from:(%.3f,%.3f) to:(%.3f,%.3f) poles: %d\n", + Base::Console().Log("Error - Geometry::BSpline - no result- from:(%.3f,%.3f) to:(%.3f,%.3f) poles: %d\n", s.X(),s.Y(),ePt.X(),ePt.Y(),spline->NbPoles()); - //throw Base::Exception("Geometry::BSpline - could not approximate curve"); + throw Base::Exception("Geometry::BSpline - could not approximate curve"); } } } GeomConvert_BSplineCurveToBezierCurve crt(spline); - BezierSegment tempSegment; gp_Pnt controlPoint; if (fail) { + BezierSegment tempSegment; tempSegment.poles = 3; - tempSegment.pnts[0] = Base::Vector2D(s.X(),s.Y()); - tempSegment.pnts[1] = Base::Vector2D(m.X(),m.Y()); - tempSegment.pnts[2] = Base::Vector2D(ePt.X(),ePt.Y()); + tempSegment.degree = 2; + tempSegment.pnts.push_back(Base::Vector2D(s.X(),s.Y())); + tempSegment.pnts.push_back(Base::Vector2D(m.X(),m.Y())); + tempSegment.pnts.push_back(Base::Vector2D(ePt.X(),ePt.Y())); segments.push_back(tempSegment); } else { for (Standard_Integer i = 1; i <= crt.NbArcs(); ++i) { + BezierSegment tempSegment; Handle_Geom_BezierCurve bezier = crt.Arc(i); if (bezier->Degree() > 3) { - throw Base::Exception("Geometry::BSpline - converted curve degree > 3"); + Base::Console().Log("Geometry::BSpline - converted curve degree > 3\n"); } tempSegment.poles = bezier->NbPoles(); - // Note: We really only need to keep the pnts[0] for the first Bezier segment, - // assuming this only gets used as in QGIViewPart::drawPainterPath - // ...it also gets used in GeometryObject::calcBoundingBox(), similar note applies + tempSegment.degree = bezier->Degree(); for (int pole = 1; pole <= tempSegment.poles; ++pole) { controlPoint = bezier->Pole(pole); - tempSegment.pnts[pole - 1] = Base::Vector2D(controlPoint.X(), controlPoint.Y()); + tempSegment.pnts.push_back(Base::Vector2D(controlPoint.X(), controlPoint.Y())); } segments.push_back(tempSegment); } @@ -513,6 +506,23 @@ bool BSpline::isLine() return result; } +BezierSegment::BezierSegment(const TopoDS_Edge &e) +{ + geomType = BEZIER; + occEdge = e; + BRepAdaptor_Curve c(e); + Handle_Geom_BezierCurve bez = c.Bezier(); + poles = bez->NbPoles(); + degree = bez->Degree(); + if (poles > 4) { + Base::Console().Log("Warning - BezierSegment has degree > 3: %d\n",degree); + } + for (int i = 1; i <= poles; ++i) { + gp_Pnt controlPoint = bez->Pole(i); + pnts.push_back(Base::Vector2D(controlPoint.X(), controlPoint.Y())); + } +} + //**** Vertex Vertex::Vertex(double x, double y) diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index fb9a44901c..252c31ea26 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -33,7 +33,7 @@ namespace TechDrawGeometry { -enum ExtractionType { //obs sb vis/hid + hard/smooth/seam/out(edgeClass?) +enum ExtractionType { //obs Plain, WithHidden, WithSmooth @@ -54,6 +54,7 @@ enum GeomType { ARCOFCIRCLE, ELLIPSE, ARCOFELLIPSE, + BEZIER, BSPLINE, GENERIC }; @@ -70,7 +71,7 @@ class TechDrawExport BaseGeom edgeClass classOfEdge; bool visible; bool reversed; - int ref3D; + int ref3D; //obs? TopoDS_Edge occEdge; //projected Edge std::vector findEndPoints(); @@ -80,6 +81,7 @@ class TechDrawExport BaseGeom Base::Vector2D nearPoint(Base::Vector2D p); Base::Vector2D nearPoint(const BaseGeom* p); static BaseGeom* baseFactory(TopoDS_Edge edge); + std::string dump(); }; typedef std::vector BaseGeomPtrVector; @@ -158,23 +160,18 @@ class TechDrawExport AOC: public Circle double distToArc(Base::Vector3d p); }; -/// Handles degree 1 to 3 Bezier segments -/*! - * \todo extend this to higher orders if necessary - */ -struct BezierSegment +class TechDrawExport BezierSegment: public BaseGeom { - /// Number of entries in pnts that are valid - int poles; +public: + BezierSegment(const TopoDS_Edge &e); + BezierSegment() {} + ~BezierSegment() = default; - /// Control points for this segment - /*! - * Note that first and last used points define the endpoints for this - * segment, so when we know that a sequence of BezierSegment objects are - * going to be strung together, then we only need to know the start of - * the first element (or the end of the last element). - */ - Base::Vector2D pnts[4]; + int poles; + int degree; + + //Base::Vector2D pnts[4]; + std::vector pnts; }; class TechDrawExport BSpline: public BaseGeom diff --git a/src/Mod/TechDraw/App/GeometryObject.cpp b/src/Mod/TechDraw/App/GeometryObject.cpp index 9c9d1f993b..afd993a465 100644 --- a/src/Mod/TechDraw/App/GeometryObject.cpp +++ b/src/Mod/TechDraw/App/GeometryObject.cpp @@ -281,6 +281,10 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca continue; } base = BaseGeom::baseFactory(edge); + if (base == nullptr) { + Base::Console().Message("Error - GO::addGeomFromCompound - baseFactory failed for edge: %d\n",i); + throw Base::Exception("GeometryObject::addGeomFromCompound - baseFactory failed"); + } base->classOfEdge = category; base->visible = visible; edgeGeom.push_back(base); @@ -352,182 +356,6 @@ void GeometryObject::addFaceGeom(Face* f) faceGeom.push_back(f); } -/////////////// bbox routines - -Base::BoundBox3d GeometryObject::boundingBoxOfBspline(const BSpline *spline) const -{ - Base::BoundBox3d bb; - for (std::vector::const_iterator segItr( spline->segments.begin() ); - segItr != spline->segments.end(); ++segItr) { - switch (segItr->poles) { - case 0: // Degenerate, but safe ignore - break; - case 2: // Degenerate - straight line - bb.Add(Base::Vector3d( segItr->pnts[1].fX, - segItr->pnts[1].fY, - 0 )); - // fall through - case 1: // Degenerate - just a point - bb.Add(Base::Vector3d( segItr->pnts[0].fX, - segItr->pnts[0].fY, - 0 )); - break; - case 3: { - double - px[3] = { segItr->pnts[0].fX, - segItr->pnts[1].fX, - segItr->pnts[2].fX }, - py[3] = { segItr->pnts[0].fY, - segItr->pnts[1].fY, - segItr->pnts[2].fY }, - slns[4] = { 0, 1 }; // Consider the segment's end points - - // if's are to prevent problems with divide-by-0 - if ((2 * px[1] - px[0] - px[2]) == 0) { - slns[2] = -1; - } else { - slns[2] = (px[1] - px[0]) / (2 * px[1] - px[0] - px[2]); - } - if ((2 * py[1] - py[0] - py[2]) == 0) { - slns[3] = -1; - } else { - slns[3] = (py[1] - py[0]) / (2 * py[1] - py[0] - py[2]); - } - - // evaluate B(t) at the endpoints and zeros - for (int s(0); s < 4; ++s) { - double t( slns[s] ); - if (t < 0 || t > 1) { - continue; - } - double tx( px[0] * (1 - t) * (1 - t) + - px[1] * 2 * (1 - t) * t + - px[2] * t * t ), - ty( py[0] * (1 - t) * (1 - t) + - py[1] * 2 * (1 - t) * t + - py[2] * t * t ); - bb.Add( Base::Vector3d(tx, ty, 0) ); - } - } break; - case 4: { - double - px[4] = { segItr->pnts[0].fX, - segItr->pnts[1].fX, - segItr->pnts[2].fX, - segItr->pnts[3].fX }, - py[4] = { segItr->pnts[0].fY, - segItr->pnts[1].fY, - segItr->pnts[2].fY, - segItr->pnts[3].fY }, - // If B(t) is the cubic Bezier, find t where B'(t) == 0 - // - // For control points P0-P3, B'(t) works out to be: - // B'(t) = t^2 * (-3P0 + 9P1 - 9P2 + 3P3) + - // t * (6P0 - 12P1 + 6P2) + - // 3 * (P1 - P0) - // - // So, we use the quadratic formula! - ax = -3 * px[0] + 9 * px[1] - 9 * px[2] + 3 * px[3], - ay = -3 * py[0] + 9 * py[1] - 9 * py[2] + 3 * py[3], - bx = 6 * px[0] - 12 * px[1] + 6 * px[2], - by = 6 * py[0] - 12 * py[1] + 6 * py[2], - cx = 3 * px[1] - 3 * px[0], - cy = 3 * py[1] - 3 * py[0], - - slns[6] = { 0, 1 }; // Consider the segment's end points - - // if's are to prevent problems with divide-by-0 and NaN - if ( (2 * ax) == 0 || (bx * bx - 4 * ax * cx) < 0 ) { - slns[2] = -1; - slns[3] = -1; - } else { - slns[2] = (-bx + sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); - slns[3] = (-bx - sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); - } - if ((2 * ay) == 0 || (by * by - 4 * ay * cy) < 0 ) { - slns[4] = -1; - slns[5] = -1; - } else { - slns[4] = (-by + sqrt(by * by - 4 * ay * cy)) / (2 * ay); - slns[5] = (-by - sqrt(by * by - 4 * ay * cy)) / (2 * ay); - } - - // evaluate B(t) at the endpoints and zeros - for (int s(0); s < 6; ++s) { - double t( slns[s] ); - if (t < 0 || t > 1) { - continue; - } - double tx( px[0] * (1 - t) * (1 - t) * (1 - t) + - px[1] * 3 * (1 - t) * (1 - t) * t + - px[2] * 3 * (1 - t) * t * t + - px[3] * t * t * t ), - ty( py[0] * (1 - t) * (1 - t) * (1 - t) + - py[1] * 3 * (1 - t) * (1 - t) * t + - py[2] * 3 * (1 - t) * t * t + - py[3] * t * t * t ); - bb.Add( Base::Vector3d(tx, ty, 0) ); - } - - } break; - default: - throw Base::Exception("Invalid degree bezier segment in GeometryObject::calcBoundingBox"); - } - } - return bb; -} - -Base::BoundBox3d GeometryObject::boundingBoxOfAoe(const Ellipse *aoe, - double start, - double end, bool cw) const -{ - // Using the ellipse form: - // (xc, yc) = centre of ellipse - // phi = angle of ellipse major axis off X axis - // a, b = half of major, minor axes - // - // x(theta) = xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi) - // y(theta) = yc + a*cos(theta)*sin(phi) + b*sin(theta)*cos(phi) - - double a (aoe->major / 2.0), - b (aoe->minor / 2.0), - phi (aoe->angle), - xc (aoe->center.fX), - yc (aoe->center.fY); - - if (a == 0 || b == 0) { - // Degenerate case - TODO: handle as line instead of throwing - throw Base::Exception("Ellipse with invalid major axis in GeometryObject::boundingBoxOfAoe()"); - } - - // Calculate points of interest for the bounding box. These are points - // where d(x)/d(theta) and d(y)/d(theta) = 0 (where the x and y extremes - // of the ellipse would be if it were complete), and arc endpoints. - double testAngles[6] = { atan(tan(phi) * (-b / a)), - testAngles[0] + M_PI }; - if (tan(phi) == 0) { - testAngles[2] = M_PI / 2.0; - testAngles[3] = 3.0 * M_PI / 2.0; - } else { - testAngles[2] = atan((1.0 / tan(phi)) * (b / a)); - testAngles[3] = testAngles[2] + M_PI; - } - testAngles[4] = start; - testAngles[5] = end; - - // Add extremes to bounding box, if they are within the arc - Base::BoundBox3d bb; - for (int ai(0); ai < 6; ++ai) { - double theta(testAngles[ai]); - if (isWithinArc(theta, start, end, cw) ) { - bb.Add( Base::Vector3d(xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi), - yc + a*cos(theta)*sin(phi) - b*sin(theta)*cos(phi), - 0) ); - } - } - - return bb; -} bool GeometryObject::isWithinArc(double theta, double first, double last, bool cw) const @@ -569,78 +397,19 @@ bool GeometryObject::isWithinArc(double theta, double first, Base::BoundBox3d GeometryObject::calcBoundingBox() const { - Base::BoundBox3d bbox; - - // First calculate bounding box based on vertices - for(std::vector::const_iterator it( vertexGeom.begin() ); - it != vertexGeom.end(); ++it) { - bbox.Add( Base::Vector3d((*it)->pnt.fX, (*it)->pnt.fY, 0.) ); - } - - // Now, consider geometry where vertices don't define bounding box eg circles + Bnd_Box testBox; + testBox.SetGap(0.0); for (std::vector::const_iterator it( edgeGeom.begin() ); it != edgeGeom.end(); ++it) { - switch ((*it)->geomType) { - case CIRCLE: { - Circle *c = static_cast(*it); - bbox.Add( Base::BoundBox3d(-c->radius + c->center.fX, - -c->radius + c->center.fY, - 0, - c->radius + c->center.fX, - c->radius + c->center.fY, - 0) ); - } break; - - case ARCOFCIRCLE: { - AOC *arc = static_cast(*it); - - // Endpoints of arc - bbox.Add( Base::Vector3d(arc->radius * cos(arc->startAngle), - arc->radius * sin(arc->startAngle), - 0.0) ); - bbox.Add( Base::Vector3d(arc->radius * cos(arc->endAngle), - arc->radius * sin(arc->endAngle), - 0.0) ); - - // Extreme X and Y values if they're within the arc - for (double theta = 0.0; theta < 6.5; theta += M_PI / 2.0) { - if (isWithinArc(theta, arc->startAngle, arc->endAngle, arc->cw)) { - bbox.Add( Base::Vector3d(arc->radius * cos(theta), - arc->radius * sin(theta), - 0.0) ); - } - } - } break; - - case ELLIPSE: { - bbox.Add( boundingBoxOfAoe(static_cast(*it)) ); - } break; - - case ARCOFELLIPSE: { - AOE *aoe = static_cast(*it); - double start = aoe->startAngle, - end = aoe->endAngle; - bool cw = aoe->cw; - bbox.Add( boundingBoxOfAoe(static_cast(*it), start, end, cw) ); - } break; - - case BSPLINE: { - bbox.Add( boundingBoxOfBspline(static_cast(*it)) ); - } break; - - case GENERIC: { - // this case ends up just drawing line segments between points - Generic *gen = static_cast(*it); - for (std::vector::const_iterator segIt = gen->points.begin(); - segIt != gen->points.end(); ++segIt) { - bbox.Add( Base::Vector3d(segIt->fX, segIt->fY, 0) ); - } - } break; - - default: - throw Base::Exception("Unknown geomType in GeometryObject::calcBoundingBox()"); - } + BRepBndLib::Add((*it)->occEdge, testBox); } + if (testBox.IsVoid()) { + Base::Console().Log("INFO - GO::calcBoundingBox - testBox is void\n"); + } + double xMin,xMax,yMin,yMax,zMin,zMax; + testBox.Get(xMin,yMin,zMin,xMax,yMax,zMax); + + Base::BoundBox3d bbox(xMin,yMin,zMin,xMax,yMax,zMax); return bbox; } @@ -762,4 +531,3 @@ TopoDS_Shape TechDrawGeometry::scaleShape(const TopoDS_Shape &input, } return transShape; } - diff --git a/src/Mod/TechDraw/App/GeometryObject.h b/src/Mod/TechDraw/App/GeometryObject.h index 2585228836..cf25e125cf 100644 --- a/src/Mod/TechDraw/App/GeometryObject.h +++ b/src/Mod/TechDraw/App/GeometryObject.h @@ -100,21 +100,8 @@ protected: void addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass category, bool visible); - /// Helper for calcBoundingBox() - /*! Note that the name of this function isn't totally accurate due to - * TechDraw::Bsplines being composed of BezierSegments. - */ - Base::BoundBox3d boundingBoxOfBspline(const BSpline *spline) const; - /// Helper for calcBoundingBox() - /*! - * AOE = arc of ellipse. Defaults allow this to be used for regular - * ellipses as well as arcs. - */ - Base::BoundBox3d boundingBoxOfAoe(const Ellipse *aoe, double start = 0, - double end = 2 * M_PI, bool cw = false) const; - - /// Helper for boundingBoxOf(Aoc|Aoe)() + //similar function in Geometry? /*! * Returns true iff angle theta is in [first, last], where the arc goes * clockwise (cw=true) or counterclockwise (cw=false) from first to last. diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.cpp b/src/Mod/TechDraw/Gui/QGIViewPart.cpp index f1e62ebc1a..b2439243b5 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewPart.cpp @@ -147,11 +147,11 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) case TechDrawGeometry::ARCOFCIRCLE: { TechDrawGeometry::AOC *geom = static_cast(baseGeom); - //double x = geom->center.fX - geom->radius; - //double y = geom->center.fY - geom->radius; pathArc(path, geom->radius, geom->radius, 0., geom->largeArc, geom->cw, geom->endPnt.fX, geom->endPnt.fY, geom->startPnt.fX, geom->startPnt.fY); +// double x = geom->center.fX - geom->radius; +// double y = geom->center.fY - geom->radius; //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFCIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius); } break; case TechDrawGeometry::ELLIPSE: { @@ -169,7 +169,7 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) pathArc(path, geom->major, geom->minor, geom->angle, false, false, startX, startY, endX, endY); - //Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",x, y, geom->major, geom->minor); + //Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",geom->center.fX,geom->center.fY, geom->major, geom->minor); } break; case TechDrawGeometry::ARCOFELLIPSE: { TechDrawGeometry::AOE *geom = static_cast(baseGeom); @@ -180,6 +180,33 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFELLIPSE R1:%.3f R2:%.3f From: (%.3f,%.3f) To: (%.3f,%.3f)\n",geom->major, geom->minor,geom->startPnt.fX, geom->startPnt.fY,geom->endPnt.fX, geom->endPnt.fY); } break; + case TechDrawGeometry::BEZIER: { + TechDrawGeometry::BezierSegment *geom = static_cast(baseGeom); + + // Move painter to the beginning + path.moveTo(geom->pnts[0].fX, geom->pnts[0].fY); + //Base::Console().Message("TRACE -drawPainterPath - making an BEZIER From: (%.3f,%.3f)\n",geom->pnts[0].fX,geom->pnts[0].fY); + + if ( geom->poles == 2 ) { + // Degree 1 bezier = straight line... + path.lineTo(geom->pnts[1].fX, geom->pnts[1].fY); + + } else if ( geom->poles == 3 ) { + path.quadTo(geom->pnts[1].fX, geom->pnts[1].fY, + geom->pnts[2].fX, geom->pnts[2].fY); + + } else if ( geom->poles == 4 ) { + path.cubicTo(geom->pnts[1].fX, geom->pnts[1].fY, + geom->pnts[2].fX, geom->pnts[2].fY, + geom->pnts[3].fX, geom->pnts[3].fY); + } else { //can only handle lines,quads,cubes + Base::Console().Error("Bad pole count (%d) for BezierSegment\n",geom->poles); + auto itBez = geom->pnts.begin() + 1; + for (; itBez != geom->pnts.end();itBez++) { + path.lineTo((*itBez).fX, (*itBez).fY); //show something for debugging + } + } + } break; case TechDrawGeometry::BSPLINE: { TechDrawGeometry::BSpline *geom = static_cast(baseGeom); @@ -364,10 +391,10 @@ void QGIViewPart::drawViewPart() } item->setPrettyNormal(); //debug a path - //QPainterPath edgePath=drawPainterPath(*itEdge); - //std::stringstream edgeId; - //edgeId << "QGIVP.edgePath" << i; - //dumpPath(edgeId.str().c_str(),edgePath); +// QPainterPath edgePath=drawPainterPath(*itEdge); +// std::stringstream edgeId; +// edgeId << "QGIVP.edgePath" << i; +// dumpPath(edgeId.str().c_str(),edgePath); } } @@ -760,7 +787,7 @@ void QGIViewPart::dumpPath(const char* text,QPainterPath path) } else if (elem.isCurveTo()) { typeName = "CurveTo"; } else { - typeName = "Unknown"; + typeName = "CurveData"; } Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f,%.3f) M:%d L:%d C:%d\n",iElem, elem.type,typeName,elem.x,elem.y,elem.isMoveTo(),elem.isLineTo(),elem.isCurveTo());