From c3421008f5d9f227e265ebac5132ed866149ea56 Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 3 Apr 2017 14:38:13 +0300 Subject: [PATCH] Issue #2083: Creation of sketch arc by center have unexpected behavior Use intersection point as end point of an arc if the any feature has been selected --- src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp | 8 +- src/SketchPlugin/SketchPlugin_MacroArc.cpp | 97 +++++++++++++++++-- src/SketchPlugin/SketchPlugin_MacroArc.h | 3 +- src/SketchPlugin/SketchPlugin_MacroCircle.cpp | 8 +- src/SketchPlugin/SketchPlugin_Validators.cpp | 2 +- 5 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp index dbe5cbaa2..754ef43a2 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp @@ -125,9 +125,11 @@ private: Circ2dPtr circleByCenterAndPassingPoint() { const gp_Pnt2d& aCenter = myCenter->impl(); - GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter); - if (aBuilder.NbSolutions() > 0) - return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1))); + if (aCenter.SquareDistance(myPassingPoints[0]) > Precision::SquareConfusion()) { + GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter); + if (aBuilder.NbSolutions() > 0) + return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1))); + } return Circ2dPtr(); } diff --git a/src/SketchPlugin/SketchPlugin_MacroArc.cpp b/src/SketchPlugin/SketchPlugin_MacroArc.cpp index 1c8371853..e2d9940f3 100644 --- a/src/SketchPlugin/SketchPlugin_MacroArc.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroArc.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,69 @@ static void projectPointOnCircle(AttributePoint2DPtr& thePoint, const GeomAPI_Ci thePoint->setValue(aProjection); } +static void intersectShapeAndCircle(const GeomShapePtr& theShape, + const GeomAPI_Circ2d& theCircle, + const SketchPlugin_Sketch* theSketch, + AttributePoint2DPtr& theIntersection) +{ + if (!theShape->isEdge()) + return projectPointOnCircle(theIntersection, theCircle); + + // convert shape to unbounded + std::shared_ptr anEdge(new GeomAPI_Edge(theShape)); + if (anEdge->isLine()) { + static const double HALF_SIZE = 1.e6; + std::shared_ptr aLoc = anEdge->line()->location()->xyz(); + std::shared_ptr aDir = anEdge->line()->direction()->xyz(); + + std::shared_ptr aStart( + new GeomAPI_Pnt(aLoc->added(aDir->multiplied(-HALF_SIZE)))); + std::shared_ptr aEnd( + new GeomAPI_Pnt(aLoc->added(aDir->multiplied(HALF_SIZE)))); + anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, aEnd); + } else if (anEdge->isArc()) { + std::shared_ptr aCircle = anEdge->circle(); + anEdge = GeomAlgoAPI_EdgeBuilder::lineCircle( + aCircle->center(), aCircle->normal(), aCircle->radius()); + } + + // convert 2D circle to 3D object + std::shared_ptr aCenter2d = theCircle.center(); + std::shared_ptr aCenter(theSketch->to3D(aCenter2d->x(), aCenter2d->y())); + std::shared_ptr aNDir = std::dynamic_pointer_cast( + const_cast(theSketch)->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z())); + + GeomShapePtr aCircleShape = + GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, theCircle.radius()); + + GeomShapePtr anInter = anEdge->intersect(aCircleShape); + std::shared_ptr anInterPnt; + if (!anInter) + return projectPointOnCircle(theIntersection, theCircle); + if (anInter->isVertex()) { + std::shared_ptr aVertex(new GeomAPI_Vertex(anInter)); + anInterPnt = theSketch->to2D(aVertex->point()); + } else if (anInter->isCompound()) { + double aMinDist = 1.e300; + + GeomAPI_ShapeIterator anIt(anInter); + for (; anIt.more(); anIt.next()) { + GeomShapePtr aCurrent = anIt.current(); + if (!aCurrent->isVertex()) + continue; + std::shared_ptr aVertex(new GeomAPI_Vertex(aCurrent)); + std::shared_ptr aPnt = theSketch->to2D(aVertex->point()); + double aDist = aPnt->distance(theIntersection->pnt()); + if (aDist < aMinDist) { + aMinDist = aDist; + anInterPnt = aPnt; + } + } + } + theIntersection->setValue(anInterPnt); +} + SketchPlugin_MacroArc::SketchPlugin_MacroArc() : SketchPlugin_SketchEntity(), @@ -156,7 +220,7 @@ void SketchPlugin_MacroArc::attributeChanged(const std::string& theID) data()->blockSendAttributeUpdated(aWasBlocked, false); } -GeomShapePtr SketchPlugin_MacroArc::getArcShape() +GeomShapePtr SketchPlugin_MacroArc::getArcShape(bool isBound) { if(!myStart.get() || !myEnd.get() || !myCenter.get()) { return GeomShapePtr(); @@ -174,9 +238,15 @@ GeomShapePtr SketchPlugin_MacroArc::getArcShape() std::dynamic_pointer_cast(aSketch->attribute(SketchPlugin_Sketch::NORM_ID())); std::shared_ptr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z())); - GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ? - GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal) - : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal); + GeomShapePtr anArcShape; + if (isBound) { + anArcShape = boolean(REVERSED_ID())->value() ? + GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal) + : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal); + } else { + double aRadius = aCenter->distance(aStart); + anArcShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius); + } return anArcShape; } @@ -393,9 +463,24 @@ void SketchPlugin_MacroArc::fillByCenterAndTwoPassed() GeomAPI_Circ2d aCircleForArc(myCenter, myStart); - // End point should be a projection on circle. bool aWasBlocked = data()->blockSendAttributeUpdated(true); - projectPointOnCircle(anEndPointAttr, aCircleForArc); + // check the end point is referred to another feature + GeomShapePtr aRefShape; + AttributeRefAttrPtr aEndPointRefAttr = refattr(END_POINT_REF_ID()); + if (aEndPointRefAttr && aEndPointRefAttr->isInitialized()) { + if (aEndPointRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aEndPointRefAttr->object()); + if (aFeature) + aRefShape = aFeature->lastResult()->shape(); + } + } + if (aRefShape) { + // Calculate end point as an intersection between circle and another shape + intersectShapeAndCircle(aRefShape, aCircleForArc, sketch(), anEndPointAttr); + } else { + // End point should be a projection on circle. + projectPointOnCircle(anEndPointAttr, aCircleForArc); + } data()->blockSendAttributeUpdated(aWasBlocked, false); myEnd = anEndPointAttr->pnt(); diff --git a/src/SketchPlugin/SketchPlugin_MacroArc.h b/src/SketchPlugin/SketchPlugin_MacroArc.h index 812978381..e36fc5d9c 100644 --- a/src/SketchPlugin/SketchPlugin_MacroArc.h +++ b/src/SketchPlugin/SketchPlugin_MacroArc.h @@ -206,7 +206,8 @@ class SketchPlugin_MacroArc: public SketchPlugin_SketchEntity, SketchPlugin_MacroArc(); /// Returns shape of arc. - GeomShapePtr getArcShape(); + /// \param isBound if true prepare arc, otherwice create circle containing this arc + GeomShapePtr getArcShape(bool isBound = true); private: /// Set fields for center, start and end points diff --git a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp index 078543b7d..b14bc1420 100644 --- a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp @@ -282,6 +282,7 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch())); std::shared_ptr aPassedPoints[2]; // there is possible only two passed points + bool hasTangentCurve = false; int aPntIndex = 0; for (; aPntIndex < 2; ++aPntIndex) { AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]); @@ -299,6 +300,7 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() aCircBuilder.addPassingPoint(aPassedPoint); aPassedPoints[aPntIndex] = aPassedPoint; } else { + hasTangentCurve = true; aCircBuilder.addTangentCurve(aTangentCurve); // if the circle is tangent to any curve, // the third point will be initialized by the tangent point @@ -306,12 +308,14 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() std::dynamic_pointer_cast(aPassedAttr)->pnt()); } } + if (aPntIndex <= 1) + return; std::shared_ptr aCircle; - if (aPntIndex == 3) + if (hasTangentCurve) aCircle = aCircBuilder.circle(); - else if (aPntIndex == 2) { + else { // the circle is defined by two points, calculate its parameters manually std::shared_ptr aCenter(new GeomAPI_Pnt2d( (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5, diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index bb142b319..236a104d1 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1338,7 +1338,7 @@ bool SketchPlugin_ArcEndPointIntersectionValidator::isValid( return true; } - GeomShapePtr anArcShape = anArcFeature->getArcShape(); + GeomShapePtr anArcShape = anArcFeature->getArcShape(false); if(!anArcShape.get() || anArcShape->isNull()) { return true; -- 2.39.2