From 8003ea80e59d7bc43d9d0aa3fc9a08b95edf419e Mon Sep 17 00:00:00 2001 From: edi271 Date: Sat, 29 Jan 2022 08:39:47 +0100 Subject: [PATCH] [TD] Include Intersection method into DrawUtil class --- src/Mod/TechDraw/App/Geometry.cpp | 165 ++++++++++++++++++ src/Mod/TechDraw/App/Geometry.h | 14 +- src/Mod/TechDraw/Gui/CommandExtensionPack.cpp | 132 +------------- 3 files changed, 180 insertions(+), 131 deletions(-) diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index e880864b3f..54ae761456 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -543,6 +543,171 @@ bool BaseGeom::validateEdge(TopoDS_Edge edge) return !DrawUtil::isCrazy(edge); } +std::vector BaseGeom::intersection(TechDraw::BaseGeomPtr geom2) +{ + // find intersection vertex(es) between two edges + // permitted are: line, circle or arc of circle + // call: interPoints = line1.intersection(line2); + # define unknown 0 + # define isGeneric 1 + # define isArcOrCircle 2 + // we check the type of the two objects + int edge1(unknown), edge2(unknown); + if (this->geomType == TechDraw::CIRCLE || + this->geomType == TechDraw::ARCOFCIRCLE) + edge1 = isArcOrCircle; + else if (this->geomType == TechDraw::GENERIC) + edge1 = isGeneric; + if (geom2->geomType == TechDraw::CIRCLE || + geom2->geomType == TechDraw::ARCOFCIRCLE) + edge2 = isArcOrCircle; + else if (geom2->geomType == TechDraw::GENERIC) + edge2 = isGeneric; + // we calculate the intersections + std::vector interPoints; + if (edge1 == isGeneric && edge2 == isGeneric) + intersectionLL(shared_from_this(), geom2, interPoints); + else if (edge1 == isArcOrCircle && edge2 == isGeneric) + intersectionCL(shared_from_this(), geom2, interPoints); + else if (edge1 == isGeneric && edge2 == isArcOrCircle) + intersectionCL(geom2, shared_from_this(), interPoints); + else if (edge1 == isArcOrCircle && edge2 == isArcOrCircle) + intersectionCC(shared_from_this(), geom2, interPoints); + return interPoints; +} + +void BaseGeom::intersectionLL(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints) +{ + // find intersection vertex of two lines + // Taken from: + TechDraw::GenericPtr gen1 = std::static_pointer_cast(geom1); + TechDraw::GenericPtr gen2 = std::static_pointer_cast(geom2); + // we calculate vectors to start points and direction verctors + Base::Vector3d startPnt1 = gen1->points.at(0); + Base::Vector3d endPnt1 = gen1->points.at(1); + Base::Vector3d startPnt2 = gen2->points.at(0); + Base::Vector3d endPnt2 = gen2->points.at(1); + Base::Vector3d dir1 = endPnt1 - startPnt1; + Base::Vector3d dir2 = endPnt2 - startPnt2; + // we create equations a*x+b*y+c=0 for both lines + float a1 = -dir1.y; + float b1 = dir1.x; + float c1 = -startPnt1.x * dir1.y + startPnt1.y * dir1.x; + float a2 = -dir2.y; + float b2 = dir2.x; + float c2 = -startPnt2.x * dir2.y + startPnt2.y * dir2.x; + float denom = a1 * b2 - a2 * b1; + if (abs(denom) >= 0.01) + // lines not (nearly) parallel, we calculate intersections + { + float xIntersect = (c1 * b2 - c2 * b1) / denom; + float yIntersect = (a1 * c2 - a2 * c1) / denom; + yIntersect = -yIntersect; + Base::Vector3d interPoint(xIntersect, yIntersect, 0.0); + interPoints.push_back(interPoint); + } +} + +void BaseGeom::intersectionCL(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints) +{ + // find intersection vertex(es) between one circle and one line + // Taken from: + TechDraw::CirclePtr gen1 = std::static_pointer_cast(geom1); + TechDraw::GenericPtr gen2 = std::static_pointer_cast(geom2); + // we calculate vectors to circle center, start point and direction vector + Base::Vector3d cirleCenter = gen1->center; + Base::Vector3d startPnt = gen2->points.at(0); + Base::Vector3d endPnt = gen2->points.at(1); + Base::Vector3d dir = endPnt - startPnt; + // we create equations of the circle: (x-x0)^2+(y-y0)^2=r^2 + // and the line: a*x+b*y+c=0 + float r0 = gen1->radius; + float x0 = cirleCenter.x; + float y0 = cirleCenter.y; + float a = -dir.y; + float b = dir.x; + float c = -startPnt.x * dir.y + startPnt.y * dir.x; + // we shift line and circle so that the circle center is in the origin + // and calculate constant d of new line equation + float d = c - a * x0 - b * y0; + float ab = a * a + b * b; + float rootArg = r0 * r0 * ab - d * d; + if (rootArg > 0) + // line and circle have common points + { + if (rootArg < 0.01) + // line is the tangent line, one intersection point + { + float x1 = x0 + a * d / ab; + float y1 = -y0 + b * d / ab; + Base::Vector3d interPoint1(x1, y1, 0.0); + interPoints.push_back(interPoint1); + } + else + // line is crossing the circle, two intersection points + { + float root = sqrt(rootArg); + float x1 = x0 + (a * d + b * root) / ab; + float y1 = -y0 - (b * d - a * root) / ab; + float x2 = x0 + (a * d - b * root) / ab; + float y2 = -y0 - (b * d + a * root) / ab; + Base::Vector3d interPoint1(x1, y1, 0.0); + interPoints.push_back(interPoint1); + Base::Vector3d interPoint2(x2, y2, 0.0); + interPoints.push_back(interPoint2); + } + } +} + +void BaseGeom::intersectionCC(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints) +{ + // find intersection vertex(es) between two circles + // Taken from: + TechDraw::CirclePtr gen1 = std::static_pointer_cast(geom1); + TechDraw::CirclePtr gen2 = std::static_pointer_cast(geom2); + Base::Vector3d Center1 = gen1->center; + Base::Vector3d Center2 = gen2->center; + float r1 = gen1->radius; + float r2 = gen2->radius; + // we calculate the distance d12 of the centers, and the + // two orthonormal vectors m and n + float d12 = (Center2 - Center1).Length(); + Base::Vector3d m = (Center2 - Center1).Normalize(); + Base::Vector3d n(-m.y, m.x, 0.0); + // we calculate d0, the distance from center1 to the tie line + // and rootArg, the square of the distance of the intersection points + float d0 = (r1 * r1 - r2 * r2 + d12 * d12) / (2 * d12); + float rootArg = r1 * r1 - d0 * d0; + if (rootArg > 0) + // the circles have intersection points + { + if (rootArg < 0.1) + // the circles touch, one intersection point + { + Base::Vector3d interPoint1 = -Center1 + m * d0; + interPoint1.y = -interPoint1.y; + interPoints.push_back(interPoint1); + } + else + // the circles have two intersection points + { + float e0 = sqrt(rootArg); + Base::Vector3d interPoint1 = Center1 + m * d0 + n * e0; + interPoint1.y = -interPoint1.y; + interPoints.push_back(interPoint1); + Base::Vector3d interPoint2 = Center1 + m * d0 - n * e0; + interPoint2.y = -interPoint2.y; + interPoints.push_back(interPoint2); + } + } +} + Ellipse::Ellipse(const TopoDS_Edge &e) { geomType = ELLIPSE; diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index a374500dd2..1364eb9df2 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -93,7 +93,7 @@ using BSplinePtr = std::shared_ptr; class Generic; using GenericPtr = std::shared_ptr; -class TechDrawExport BaseGeom +class TechDrawExport BaseGeom : public std::enable_shared_from_this { public: BaseGeom(); @@ -132,11 +132,23 @@ class TechDrawExport BaseGeom bool closed(void); BaseGeomPtr copy(); std::string dump(); + std::vector intersection(TechDraw::BaseGeomPtr geom2); //Uniqueness boost::uuids::uuid getTag() const; virtual std::string getTagAsString(void) const; +private: + void intersectionLL(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints); + void intersectionCL(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints); + void intersectionCC(TechDraw::BaseGeomPtr geom1, + TechDraw::BaseGeomPtr geom2, + std::vector& interPoints); + protected: int m_source; //0 - geom, 1 - cosmetic edge, 2 - centerline int m_sourceIndex; diff --git a/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp b/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp index 18f75d3665..f09c9dfe29 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp @@ -83,10 +83,6 @@ namespace TechDrawGui { void _setLineAttributes(TechDraw::CosmeticEdge* cosEdge); void _setLineAttributes(TechDraw::CenterLine* cosEdge); void _setLineAttributes(TechDraw::CosmeticEdge* cosEdge, int style, float weight, App::Color color); - void _intersection(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints); - void _intersectionLL(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints); - void _intersectionCL(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints); - void _intersectionCC(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints); float _getAngle(Base::Vector3d center, Base::Vector3d point); std::vector _getVertexPoints(std::vector SubNames, TechDraw::DrawViewPart* objFeat); bool _checkSel(Gui::Command* cmd, @@ -828,7 +824,7 @@ void CmdTechDrawExtensionVertexAtIntersection::activated(int iMsg) TechDraw::BaseGeomPtr geom1 = objFeat->getGeomByIndex(GeoId1); int GeoId2 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); TechDraw::BaseGeomPtr geom2 = objFeat->getGeomByIndex(GeoId2); - _intersection(geom1, geom2, interPoints); + interPoints = geom1->intersection(geom2); if (!interPoints.empty()) { double scale = objFeat->getScale(); std::string id1 = objFeat->addCosmeticVertex(interPoints[0] / scale); @@ -1852,130 +1848,6 @@ namespace TechDrawGui { return angle; } - void _intersection(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints) { - // find intersection vertex(es) between two edges -#define unknown 0 -#define isLine 1 -#define isCircle 2 - int edge1(unknown), edge2(unknown); - if (geom1->geomType == TechDraw::CIRCLE || - geom1->geomType == TechDraw::ARCOFCIRCLE) - edge1 = isCircle; - else if (geom1->geomType == TechDraw::GENERIC) - edge1 = isLine; - if (geom2->geomType == TechDraw::CIRCLE || - geom2->geomType == TechDraw::ARCOFCIRCLE) - edge2 = isCircle; - else if (geom2->geomType == TechDraw::GENERIC) - edge2 = isLine; - if (edge1 == isLine && edge2 == isLine) - _intersectionLL(geom1, geom2, interPoints); - else if (edge1 == isCircle && edge2 == isLine) - _intersectionCL(geom1, geom2, interPoints); - else if (edge1 == isLine && edge2 == isCircle) - _intersectionCL(geom2, geom1, interPoints); - else if (edge1 == isCircle && edge2 == isCircle) - _intersectionCC(geom2, geom1, interPoints); - } - - void _intersectionLL(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints) { - // find intersection vertex of two lines - // Taken from: - TechDraw::GenericPtr gen1 = std::static_pointer_cast(geom1); - TechDraw::GenericPtr gen2 = std::static_pointer_cast(geom2); - Base::Vector3d startPnt1 = gen1->points.at(0); - Base::Vector3d endPnt1 = gen1->points.at(1); - Base::Vector3d startPnt2 = gen2->points.at(0); - Base::Vector3d endPnt2 = gen2->points.at(1); - Base::Vector3d dir1 = endPnt1 - startPnt1; - Base::Vector3d dir2 = endPnt2 - startPnt2; - float a1 = -dir1.y; - float b1 = dir1.x; - float c1 = -startPnt1.x * dir1.y + startPnt1.y * dir1.x; - float a2 = -dir2.y; - float b2 = dir2.x; - float c2 = -startPnt2.x * dir2.y + startPnt2.y * dir2.x; - float denom = a1 * b2 - a2 * b1; - if (abs(denom) >= 0.01) { - float xIntersect = (c1 * b2 - c2 * b1) / denom; - float yIntersect = (a1 * c2 - a2 * c1) / denom; - yIntersect = -yIntersect; - Base::Vector3d interPoint(xIntersect, yIntersect, 0.0); - interPoints.push_back(interPoint); - } - } - - void _intersectionCL(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints) { - // find intersection vertex(es) between one circle and one line - // Taken from: - TechDraw::CirclePtr gen1 = std::static_pointer_cast(geom1); - TechDraw::GenericPtr gen2 = std::static_pointer_cast(geom2); - Base::Vector3d cirleCenter = gen1->center; - Base::Vector3d startPnt = gen2->points.at(0); - Base::Vector3d endPnt = gen2->points.at(1); - Base::Vector3d dir = endPnt - startPnt; - float r0 = gen1->radius; - float x0 = cirleCenter.x; - float y0 = cirleCenter.y; - float a = -dir.y; - float b = dir.x; - float c = -startPnt.x * dir.y + startPnt.y * dir.x; - float d = c - a * x0 - b * y0; - float ab = a * a + b * b; - float rootArg = r0 * r0 * ab - d * d; - if (rootArg > 0) { - if (rootArg < 0.01) { - float x1 = x0 + a * d / ab; - float y1 = -y0 + b * d / ab; - Base::Vector3d interPoint1(x1, y1, 0.0); - interPoints.push_back(interPoint1); - } - else { - float root = sqrt(rootArg); - float x1 = x0 + (a * d + b * root) / ab; - float y1 = -y0 - (b * d - a * root) / ab; - float x2 = x0 + (a * d - b * root) / ab; - float y2 = -y0 - (b * d + a * root) / ab; - Base::Vector3d interPoint1(x1, y1, 0.0); - interPoints.push_back(interPoint1); - Base::Vector3d interPoint2(x2, y2, 0.0); - interPoints.push_back(interPoint2); - } - } - } - - void _intersectionCC(TechDraw::BaseGeomPtr geom1, TechDraw::BaseGeomPtr geom2, std::vector& interPoints) { - // find intersection vertex(es) between two circles - // Taken from: - TechDraw::CirclePtr gen1 = std::static_pointer_cast(geom1); - TechDraw::CirclePtr gen2 = std::static_pointer_cast(geom2); - Base::Vector3d Center1 = gen1->center; - Base::Vector3d Center2 = gen2->center; - float r1 = gen1->radius; - float r2 = gen2->radius; - float d12 = (Center2 - Center1).Length(); - Base::Vector3d m = (Center2 - Center1).Normalize(); - Base::Vector3d n(-m.y, m.x, 0.0); - float d0 = (r1 * r1 - r2 * r2 + d12 * d12) / (2 * d12); - float rootArg = r1 * r1 - d0 * d0; - if (rootArg > 0) { - if (rootArg < 0.1) { - Base::Vector3d interPoint1 = -Center1 + m * d0; - interPoint1.y = -interPoint1.y; - interPoints.push_back(interPoint1); - } - else { - float e0 = sqrt(rootArg); - Base::Vector3d interPoint1 = Center1 + m * d0 + n * e0; - interPoint1.y = -interPoint1.y; - interPoints.push_back(interPoint1); - Base::Vector3d interPoint2 = Center1 + m * d0 - n * e0; - interPoint2.y = -interPoint2.y; - interPoints.push_back(interPoint2); - } - } - } - Base::Vector3d _circleCenter(Base::Vector3d p1, Base::Vector3d p2, Base::Vector3d p3) { Base::Vector2d v1(p1.x, p1.y); Base::Vector2d v2(p2.x, p2.y); @@ -2100,4 +1972,4 @@ void CreateTechDrawCommandsExtensions(void) rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadHoleBottom()); rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadBoltBottom()); rcCmdMgr.addCommand(new CmdTechDrawExtensionAreaAnnotation()); -} +} \ No newline at end of file