From: azv Date: Mon, 30 Sep 2019 10:38:02 +0000 (+0300) Subject: Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003) X-Git-Tag: V9_4_0a2~4^2~57 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c89cde85df4f88437eeae4f83248c75d066fba71;p=modules%2Fshaper.git Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003) Split and Trim features for ellipse and elliptic arc. --- diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.cpp b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp index a5c2b29fb..1c56d27e9 100644 --- a/src/SketchPlugin/SketchPlugin_EllipticArc.cpp +++ b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp @@ -145,13 +145,8 @@ static void calculateRadii(const GeomPnt2dPtr& theCenter, theCenter->xy()->multiplied(2.0)->decreased(theFocus->xy()))); theMajorRadius = 0.5 * (thePassed->distance(theFocus) + thePassed->distance(aSecondFocus)); - GeomDir2dPtr aXAxis(new GeomAPI_Dir2d(theFocus->x() - theCenter->x(), - theFocus->y() - theCenter->y())); - std::shared_ptr aPassedVec = thePassed->xy()->decreased(theCenter->xy()); - - double x = aPassedVec->dot(aXAxis->xy()) / theMajorRadius; - double y = abs(aPassedVec->cross(aXAxis->xy())); - theMinorRadius = y / sqrt(1.0 - x * x); + double aFocalDist = theCenter->distance(theFocus); + theMinorRadius = sqrt(theMajorRadius * theMajorRadius - aFocalDist * aFocalDist); } bool SketchPlugin_EllipticArc::fillCharacteristicPoints() @@ -162,6 +157,8 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints() std::dynamic_pointer_cast(data()->attribute(FIRST_FOCUS_ID())); std::shared_ptr aStartPointAttr = std::dynamic_pointer_cast(data()->attribute(START_POINT_ID())); + std::shared_ptr aEndPointAttr = + std::dynamic_pointer_cast(data()->attribute(END_POINT_ID())); if (!aCenterAttr->isInitialized() || !aFocusAttr->isInitialized() || @@ -176,7 +173,7 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints() double aMajorRadius = 0.0, aMinorRadius = 0.0; calculateRadii(aCenter2d, aFocus2d, aStart2d, aMajorRadius, aMinorRadius); - if (aMinorRadius < tolerance) + if (aMinorRadius < tolerance *aMajorRadius) return false; real(MAJOR_RADIUS_ID())->setValue(aMajorRadius); real(MINOR_RADIUS_ID())->setValue(aMinorRadius); @@ -200,8 +197,6 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints() ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius, aCenter2d->y() + aMinorDir2d->y() * aMinorRadius); - std::shared_ptr aEndPointAttr = - std::dynamic_pointer_cast(data()->attribute(END_POINT_ID())); if (aEndPointAttr->isInitialized()) { // recalculate REVERSED flag std::shared_ptr anEllipseForArc( diff --git a/src/SketchPlugin/SketchPlugin_Split.cpp b/src/SketchPlugin/SketchPlugin_Split.cpp index 8a07349df..a8f054eb8 100644 --- a/src/SketchPlugin/SketchPlugin_Split.cpp +++ b/src/SketchPlugin/SketchPlugin_Split.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -137,8 +138,7 @@ void SketchPlugin_Split::execute() //std::map aTangentFeatures; std::map aCoincidenceToFeature; - getConstraints(aFeaturesToDelete, aFeaturesToUpdate, /*aTangentFeatures, */ - aCoincidenceToFeature); + getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aCoincidenceToFeature); std::map > aBaseRefAttributes; std::list aRefsToFeature; @@ -239,18 +239,19 @@ void SketchPlugin_Split::execute() else if (aFeatureKind == SketchPlugin_Arc::ID()) aNewFeature = splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); + else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) + aNewFeature = splitEllipticArc(aSplitFeature, aBaseFeature, anAfterFeature, + aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); restoreCurrentFeature(); - if (aFeatureKind == SketchPlugin_Circle::ID()) { - FeaturePtr aCircleFeature = aBaseFeature; - aReplacingFeature = splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, + if (aFeatureKind == SketchPlugin_Circle::ID() || aFeatureKind == SketchPlugin_Ellipse::ID()) { + aFeaturesToDelete.insert(aBaseFeature); + aReplacingFeature = splitClosed(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); updateRefFeatureConstraints(aBaseFeature->lastResult(), aRefsToFeature); - AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()); - aFeaturesToDelete.insert(aCircleFeature); // as circle is removed, temporary fill this attribute*/ aBaseObjectAttr->setObject(ResultPtr()); } @@ -518,7 +519,8 @@ void SketchPlugin_Split::getConstraints(std::set& theFeaturesToDelet theFeaturesToDelete.insert(aRefFeature); else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) theFeaturesToUpdate.insert(aRefFeature); - else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) { + else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID() || + aRefFeatureKind == SketchPlugin_ConstraintCoincidenceInternal::ID()) { std::string anAttributeToBeModified; AttributePoint2DPtr aCoincidentPoint; AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A()); @@ -592,7 +594,7 @@ void SketchPlugin_Split::updateCoincidenceConstraintsToFeature( aNewCoincidencesToSplitFeature.insert(anEndPointAttr); std::map::const_iterator aCIt = theCoincidenceToFeature.begin(), - aCLast = theCoincidenceToFeature.end(); + aCLast = theCoincidenceToFeature.end(); #ifdef DEBUG_SPLIT std::cout << std::endl; std::cout << "Coincidences to feature(modified):"<< std::endl; @@ -668,10 +670,10 @@ void SketchPlugin_Split::updateRefFeatureConstraints( } FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature, - FeaturePtr& theBaseFeatureModified, - FeaturePtr& theAfterFeature, - std::set& thePoints, - std::set& theCreatedFeatures, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, std::set>& theModifiedAttributes) { FeaturePtr anNewFeature; @@ -680,16 +682,9 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature, FeaturePtr aConstraintFeature; theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch) - return anNewFeature; - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( data()->attribute(SELECTED_OBJECT())); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - std::string aFeatureKind = aBaseFeature->getKind(); - if (aFeatureKind != SketchPlugin_Line::ID()) - return anNewFeature; AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true); AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false); @@ -718,8 +713,8 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature, #endif // create a split feature - theSplitFeature = - createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theSplitFeature = SketchPlugin_SegmentationTools::createLineFeature( + aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt()); theCreatedFeatures.insert(theSplitFeature); // before split feature @@ -741,7 +736,8 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature, aFeature->execute(); // to update result } else { - aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); + aFeature = SketchPlugin_SegmentationTools::createLineFeature( + aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt()); theCreatedFeatures.insert(aFeature); theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_Line::END_ID()))); @@ -811,10 +807,10 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature, } FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature, - FeaturePtr& theBaseFeatureModified, - FeaturePtr& theAfterFeature, - std::set& thePoints, - std::set& theCreatedFeatures, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, std::set>& theModifiedAttributes) { FeaturePtr anNewFeature; @@ -823,16 +819,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature, FeaturePtr aConstraintFeature; theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch) - return anNewFeature; - - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - data()->attribute(SELECTED_OBJECT())); + AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT()); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - std::string aFeatureKind = aBaseFeature->getKind(); - if (aFeatureKind != SketchPlugin_Arc::ID()) - return anNewFeature; AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true); AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false); @@ -859,7 +847,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature, #endif // split feature - theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt()); theCreatedFeatures.insert(theSplitFeature); // before split feature @@ -881,7 +870,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature, aFeature->execute(); // to update result } else { - aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); + aFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt()); theCreatedFeatures.insert(aFeature); theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_Arc::END_ID()))); @@ -960,7 +950,151 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature, return anNewFeature; } -FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature, +FeaturePtr SketchPlugin_Split::splitEllipticArc(FeaturePtr& theSplitFeature, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) +{ + FeaturePtr anNewFeature; + + std::set aCreatedFeatures; + FeaturePtr aConstraintFeature; + theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature + + AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT()); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true); + AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false); + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + SketchPlugin_SegmentationTools::getFeaturePoints( + aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) { + setError("Error: Feature has no start and end points."); + return anNewFeature; + } + + arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase, + aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); +#ifdef DEBUG_SPLIT + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + std::cout << "Start point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl; + std::cout << "1st point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl; + std::cout << "2nd point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl; + std::cout << "End point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl; +#endif + + // split feature + theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt()); + theCreatedFeatures.insert(theSplitFeature); + + // before split feature + if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))); + } + else { + theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here + // move end arc point to start of split + } + + // after split feature + if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) { + FeaturePtr aFeature; + if (!theBaseFeatureModified.get()) { + aFeature = aBaseFeature; // use base feature to store all constraints here + fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit); + aFeature->execute(); // to update result + } + else { + aFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt()); + theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair( + anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + anNewFeature = aFeature; + } + aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(), + SketchPlugin_ConstraintCoincidence::ID(), + theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()), + aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + + if (!theBaseFeatureModified.get()) + theBaseFeatureModified = aFeature; + else + theAfterFeature = aFeature; + } + else { + thePoints.insert(std::dynamic_pointer_cast( + theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + } + // base split, that is defined before split feature should be changed at end + // (after the after feature creation). Otherwise modified value will be used in after feature + // before split feature + if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + // move end arc point to start of split + fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()), + aFirstPointAttrOfSplit); + theBaseFeatureModified->execute(); // to update result + aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(), + SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()), + theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + thePoints.insert(std::dynamic_pointer_cast( + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))); + thePoints.insert(std::dynamic_pointer_cast( + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + } + else + thePoints.insert(std::dynamic_pointer_cast( + theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))); + + // additional constraints between split and base features +#ifdef CREATE_CONSTRAINTS + aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(), + SketchPlugin_ConstraintEqual::ID(), + aBaseFeature->lastResult(), + theSplitFeature->lastResult()); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(), + SketchPlugin_ConstraintTangent::ID(), + theSplitFeature->lastResult(), + aBaseFeature->lastResult()); + theCreatedFeatures.insert(aConstraintFeature); + if (theAfterFeature.get()) { + aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(), + SketchPlugin_ConstraintEqual::ID(), + aBaseFeature->lastResult(), + theAfterFeature->lastResult()); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(), + SketchPlugin_ConstraintTangent::ID(), + theSplitFeature->lastResult(), + theAfterFeature->lastResult()); + theCreatedFeatures.insert(aConstraintFeature); + } +#endif + return anNewFeature; +} + +FeaturePtr SketchPlugin_Split::splitClosed(FeaturePtr& theSplitFeature, FeaturePtr& theBaseFeatureModified, FeaturePtr& theAfterFeature, std::set& thePoints, @@ -973,55 +1107,90 @@ FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature, FeaturePtr aConstraintFeature; theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch) - return anNewFeature; - - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - data()->attribute(SELECTED_OBJECT())); + AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT()); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - std::string aFeatureKind = aBaseFeature->getKind(); - if (aFeatureKind != SketchPlugin_Circle::ID()) - return anNewFeature; AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true); AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false); // split feature - theSplitFeature = - createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); - bool aSplitReversed = std::dynamic_pointer_cast(theSplitFeature)->isReversed(); + theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt()); + const std::string& aReversedAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID(); + bool aSplitReversed = theSplitFeature->boolean(aReversedAttrName)->value(); theCreatedFeatures.insert(theSplitFeature); // base feature is a left part of the circle - theBaseFeatureModified = createArcFeature(aBaseFeature, - aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theBaseFeatureModified = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt()); anNewFeature = theBaseFeatureModified; - std::dynamic_pointer_cast( - theBaseFeatureModified)->setReversed(!aSplitReversed); + theBaseFeatureModified->boolean(aReversedAttrName)->setValue(!aSplitReversed); theBaseFeatureModified->execute(); - theModifiedAttributes.insert( - std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), - theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID()))); + if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) { + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), + theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID()))); + } + else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) { + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::CENTER_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()), + theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID()))); + + // update the PARENT_ID reference for all the features created by the ellipse + const std::set& aRefs = aBaseFeature->data()->refsToMe(); + std::list aRefsToParent; + for (std::set::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) { + if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() || + (*aRef)->id() == SketchPlugin_Point::PARENT_ID()) + aRefsToParent.push_back(*aRef); + } + for (std::list::iterator aRef = aRefsToParent.begin(); + aRef != aRefsToParent.end(); ++aRef) + std::dynamic_pointer_cast(*aRef)->setValue(theSplitFeature); + } theCreatedFeatures.insert(theBaseFeatureModified); + const std::string& aStartAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID(); + const std::string& aEndAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID(); + thePoints.insert(std::dynamic_pointer_cast - (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()))); + (theBaseFeatureModified->attribute(aStartAttrName))); thePoints.insert(std::dynamic_pointer_cast - (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()))); + (theBaseFeatureModified->attribute(aEndAttrName))); // additional constraints between split and base features aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(), SketchPlugin_ConstraintCoincidence::ID(), - theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), - theSplitFeature->attribute(SketchPlugin_Arc::END_ID())); + theBaseFeatureModified->attribute(aEndAttrName), + theSplitFeature->attribute(aEndAttrName)); theCreatedFeatures.insert(aConstraintFeature); aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(), SketchPlugin_ConstraintCoincidence::ID(), - theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()), - theSplitFeature->attribute(SketchPlugin_Arc::START_ID())); + theBaseFeatureModified->attribute(aStartAttrName), + theSplitFeature->attribute(aStartAttrName)); theCreatedFeatures.insert(aConstraintFeature); #ifdef CREATE_CONSTRAINTS @@ -1058,9 +1227,14 @@ void SketchPlugin_Split::arrangePointsOnArc( { static const double anAngleTol = 1.e-12; + const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID(); + const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID(); + std::shared_ptr aCenter = std::dynamic_pointer_cast( - theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); + theArc->attribute(aCenterAttrName))->pnt(); + bool isReversed = theArc->boolean(aReversedAttrName)->value(); // collect directions to each point std::shared_ptr aStartDir( @@ -1110,71 +1284,6 @@ void SketchPlugin_Split::fillAttribute(const AttributePtr& theModifiedAttribute, } } -FeaturePtr SketchPlugin_Split::createLineFeature(const FeaturePtr& theBaseFeature, - const AttributePtr& theFirstPointAttr, - const AttributePtr& theSecondPointAttr) -{ - FeaturePtr aFeature; - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch || !theBaseFeature.get()) - return aFeature; - - aFeature = aSketch->addFeature(SketchPlugin_Line::ID()); - - fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr); - fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr); - - fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), - theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); - - aFeature->execute(); // to obtain result - - return aFeature; -} - -FeaturePtr SketchPlugin_Split::createArcFeature(const FeaturePtr& theBaseFeature, - const AttributePtr& theFirstPointAttr, - const AttributePtr& theSecondPointAttr) -{ - FeaturePtr aFeature; - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch || !theBaseFeature.get()) - return aFeature; - - std::string aCenterAttributeId; - if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) - aCenterAttributeId = SketchPlugin_Arc::CENTER_ID(); - else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID()) - aCenterAttributeId = SketchPlugin_Circle::CENTER_ID(); - - if (aCenterAttributeId.empty()) - return aFeature; - - aFeature = aSketch->addFeature(SketchPlugin_Arc::ID()); - // update fillet arc: make the arc correct for sure, so, it is not needed to process - // the "attribute updated" - // by arc; moreover, it may cause cyclicity in hte mechanism of updater - bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true); - - fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()), - theBaseFeature->attribute(aCenterAttributeId)); - fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr); - fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr); - - fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), - theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); - - // fill referersed state of created arc as it is on the base arc - if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) { - bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); - aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed); - } - aFeature->data()->blockSendAttributeUpdated(aWasBlocked); - aFeature->execute(); // to obtain result - - return aFeature; -} - #ifdef _DEBUG std::set > SketchPlugin_Split::getEdgeAttributes( const std::shared_ptr& theFeature) diff --git a/src/SketchPlugin/SketchPlugin_Split.h b/src/SketchPlugin/SketchPlugin_Split.h index 995b5800a..1c8273b6e 100644 --- a/src/SketchPlugin/SketchPlugin_Split.h +++ b/src/SketchPlugin/SketchPlugin_Split.h @@ -190,6 +190,20 @@ private: std::set>& theCreatedFeatures, std::set>& theModifiedAttributes); + /// Make the base object is splitted by the point attributes + /// \param theSplitFeature a result split feature + /// \param theBeforeFeature a feature between start point and the 1st point of split feature + /// \param theAfterFeature a feature between last point of split feature and the end point + /// \param thePoints a list of points where coincidences will be build + /// \param theCreatedFeatures a container of created features + /// \return new elliptic arc if it was created + FeaturePtr splitEllipticArc(std::shared_ptr& theSplitFeature, + std::shared_ptr& theBeforeFeature, + std::shared_ptr& theAfterFeature, + std::set >& thePoints, + std::set>& theCreatedFeatures, + std::set>& theModifiedAttributes); + /// Make the base object is splitted by the point attributes /// \param theSplitFeature a result split feature /// \param theBeforeFeature a feature between start point and the 1st point of split feature @@ -197,7 +211,7 @@ private: /// \param thePoints a list of points where coincidences will be build /// \param theCreatedFeatures a container of created features /// \return new arc if it was created - FeaturePtr splitCircle(std::shared_ptr& theSplitFeature, + FeaturePtr splitClosed(std::shared_ptr& theSplitFeature, std::shared_ptr& theBeforeFeature, std::shared_ptr& theAfterFeature, std::set >& thePoints, @@ -236,22 +250,6 @@ private: void fillAttribute(const AttributePtr& theModifiedAttribute, const AttributePtr& theSourceAttribute); - /// Creates a line feature filled by center of base feature and given points - /// \param theBaseFeature another arc feature - /// \param theFirstAttribute an attribute with coordinates for the start point - /// \param theSecondAttribute an attribute with coordinates for the end point - FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature, - const AttributePtr& theFirstPointAttr, - const AttributePtr& theSecondPointAttr); - - /// Creates an arc feature filled by center of base feature and given points - /// \param theBaseFeature another arc feature - /// \param theFirstAttribute an attribute with coordinates for the start point - /// \param theSecondAttribute an attribute with coordinates for the end point - FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature, - const AttributePtr& theFirstPointAttr, - const AttributePtr& theSecondPointAttr); - /// Returns attributes of the feature, used in edge build, for arc it is end and start points /// \param theFeature a feature /// \return container of attributes diff --git a/src/SketchPlugin/SketchPlugin_Tools.cpp b/src/SketchPlugin/SketchPlugin_Tools.cpp index 5aa9c1bf1..a285ea243 100644 --- a/src/SketchPlugin/SketchPlugin_Tools.cpp +++ b/src/SketchPlugin/SketchPlugin_Tools.cpp @@ -20,6 +20,7 @@ #include "SketchPlugin_Tools.h" #include "SketchPlugin_Arc.h" +#include "SketchPlugin_Circle.h" #include "SketchPlugin_ConstraintCoincidence.h" #include "SketchPlugin_ConstraintCoincidenceInternal.h" #include "SketchPlugin_ConstraintLength.h" @@ -845,3 +846,118 @@ AISObjectPtr SketchPlugin_SegmentationTools::getAISObject( anAIS = AISObjectPtr(); return anAIS; } + +#define GEOM_DATA_POINT2D(f, a) std::dynamic_pointer_cast((f)->attribute(a)) + +FeaturePtr SketchPlugin_SegmentationTools::createLineFeature( + const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint) +{ + FeaturePtr aFeature; + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theBaseFeature); + SketchPlugin_Sketch* aSketch = aSketchFeature->sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; + + aFeature = aSketch->addFeature(SketchPlugin_Line::ID()); + + GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::START_ID())->setValue(theFirstPoint); + GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::END_ID())->setValue(theSecondPoint); + + aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue( + theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); + aFeature->execute(); // to obtain result + + return aFeature; +} + +struct ArcAttributes +{ + std::string myKind; + std::string myCenter; + std::string myFocus; + std::string myStart; + std::string myEnd; + std::string myReversed; + + ArcAttributes() {} + + ArcAttributes(const std::string& theKind) : myKind(theKind) + { + if (myKind == SketchPlugin_Arc::ID()) { + myCenter = SketchPlugin_Arc::CENTER_ID(); + myStart = SketchPlugin_Arc::START_ID(); + myEnd = SketchPlugin_Arc::END_ID(); + myReversed = SketchPlugin_Arc::REVERSED_ID(); + } + else if (myKind == SketchPlugin_Circle::ID()) { + myCenter = SketchPlugin_Circle::CENTER_ID(); + } + else if (myKind == SketchPlugin_Ellipse::ID()) { + myCenter = SketchPlugin_Ellipse::CENTER_ID(); + myFocus = SketchPlugin_Ellipse::FIRST_FOCUS_ID(); + } + else if (myKind == SketchPlugin_EllipticArc::ID()) { + myCenter = SketchPlugin_EllipticArc::CENTER_ID(); + myFocus = SketchPlugin_EllipticArc::FIRST_FOCUS_ID(); + myStart = SketchPlugin_EllipticArc::START_POINT_ID(); + myEnd = SketchPlugin_EllipticArc::END_POINT_ID(); + myReversed = SketchPlugin_EllipticArc::REVERSED_ID(); + } + } +}; + +FeaturePtr SketchPlugin_SegmentationTools::createArcFeature( + const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint) +{ + FeaturePtr aFeature; + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theBaseFeature); + SketchPlugin_Sketch* aSketch = aSketchFeature->sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; + + ArcAttributes aBaseAttrs(theBaseFeature->getKind()); + ArcAttributes aTargetAttrs; + if (aBaseAttrs.myKind == SketchPlugin_Arc::ID() || + aBaseAttrs.myKind == SketchPlugin_Circle::ID()) + aTargetAttrs = ArcAttributes(SketchPlugin_Arc::ID()); + else if (aBaseAttrs.myKind == SketchPlugin_Ellipse::ID() || + aBaseAttrs.myKind == SketchPlugin_EllipticArc::ID()) + aTargetAttrs = ArcAttributes(SketchPlugin_EllipticArc::ID()); + + if (aTargetAttrs.myKind.empty()) + return aFeature; + + aFeature = aSketch->addFeature(aTargetAttrs.myKind); + // update fillet arc: make the arc correct for sure, so, it is not needed to process + // the "attribute updated" + // by arc; moreover, it may cause cyclicity in hte mechanism of updater + bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true); + + GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myCenter)->setValue( + GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myCenter)->pnt()); + if (!aTargetAttrs.myFocus.empty()) { + GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myFocus)->setValue( + GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myFocus)->pnt()); + } + GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myStart)->setValue(theFirstPoint); + GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myEnd)->setValue(theSecondPoint); + + aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue( + theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); + + /// fill referersed state of created arc as it is on the base arc + bool aReversed = aBaseAttrs.myReversed.empty() ? false : + theBaseFeature->boolean(aBaseAttrs.myReversed)->value(); + aFeature->boolean(aTargetAttrs.myReversed)->setValue(aReversed); + + aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update) + aFeature->data()->blockSendAttributeUpdated(aWasBlocked); + + return aFeature; +} diff --git a/src/SketchPlugin/SketchPlugin_Tools.h b/src/SketchPlugin/SketchPlugin_Tools.h index 74193772e..f29e192df 100644 --- a/src/SketchPlugin/SketchPlugin_Tools.h +++ b/src/SketchPlugin/SketchPlugin_Tools.h @@ -206,6 +206,25 @@ namespace SketchPlugin_SegmentationTools /// \param theFeaturesToUpdate a constraint index void updateFeaturesAfterOperation(const std::set& theFeaturesToUpdate); + + /// Creates a line feature filled by center of base feature and given points + /// \param theBaseFeature another arc feature + /// \param theFirstAttribute an attribute with coordinates for the start point + /// \param theSecondAttribute an attribute with coordinates for the end point + FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint); + + /// Creates a circular/elliptic arc feature filled by center + /// (or by center and focus for elliptic arc) of base feature and given points + /// \param theBaseFeature another circle or ellipse or circular/elliptic arc + /// \param theFirstAttribute an attribute with coordinates for the start point + /// \param theSecondAttribute an attribute with coordinates for the end point + FeaturePtr createArcFeature( + const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint); + }; // namespace SketchPlugin_SegmentationTools #endif // SKETCHPLUGIN_TOOLS_H_ \ No newline at end of file diff --git a/src/SketchPlugin/SketchPlugin_Trim.cpp b/src/SketchPlugin/SketchPlugin_Trim.cpp index 0be8a5a5f..b5c215c62 100644 --- a/src/SketchPlugin/SketchPlugin_Trim.cpp +++ b/src/SketchPlugin/SketchPlugin_Trim.cpp @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -64,6 +66,7 @@ #include +#define DEBUG_TRIM #ifdef DEBUG_TRIM #include #endif @@ -304,8 +307,9 @@ void SketchPlugin_Trim::execute() std::set> aModifiedAttributes; const std::string& aKind = aBaseFeature->getKind(); FeaturePtr aReplacingFeature, aNewFeature; - if (aKind == SketchPlugin_Circle::ID()) { - aReplacingFeature = trimCircle(aStartShapePoint2d, aLastShapePoint2d, + if (aKind == SketchPlugin_Circle::ID() || + aKind == SketchPlugin_Ellipse::ID()) { + aReplacingFeature = trimClosed(aStartShapePoint2d, aLastShapePoint2d, aFurtherCoincidences, aModifiedAttributes); aFeaturesToDelete.insert(aBaseFeature); @@ -322,6 +326,10 @@ void SketchPlugin_Trim::execute() aNewFeature = trimArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes, aFurtherCoincidences, aModifiedAttributes); } + else if (aKind == SketchPlugin_EllipticArc::ID()) { + aNewFeature = trimEllipticArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes, + aFurtherCoincidences, aModifiedAttributes); + } restoreCurrentFeature(); @@ -382,7 +390,7 @@ void SketchPlugin_Trim::execute() ResultPtr aReplacingResult; if (aReplacingFeature.get()) { aReplacingFeature->execute(); // need it to obtain result - aReplacingResult = getFeatureResult(aReplacingFeature); + aReplacingResult = aReplacingFeature->lastResult(); } for(std::list::const_iterator anIt = aRefsToFeature.begin(), aLast = aRefsToFeature.end(); @@ -457,7 +465,7 @@ void SketchPlugin_Trim::execute() aPreviewObject = ObjectPtr(); aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one - aBaseObject = getFeatureResult(aBaseFeature); + aBaseObject = aBaseFeature->lastResult(); std::shared_ptr aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(), aPreviewPnt2d->y()); ResultPtr aBaseResult = std::dynamic_pointer_cast(aBaseObject); @@ -468,7 +476,7 @@ void SketchPlugin_Trim::execute() aPreviewObject = aBaseResult; } if (!aPreviewObject.get() && aNewFeature.get()) { - ResultPtr aNewFeatureResult = getFeatureResult(aNewFeature); + ResultPtr aNewFeatureResult = aNewFeature->lastResult(); if (aNewFeatureResult.get()) { GeomShapePtr aShape = aNewFeatureResult->shape(); std::shared_ptr aProjectedPoint; @@ -643,7 +651,7 @@ void SketchPlugin_Trim::getConstraints(std::set& theFeaturesToDelete AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( aData->attribute(SketchPlugin_Trim::SELECTED_OBJECT())); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + ResultPtr aBaseFeatureResult = aBaseFeature->lastResult(); std::set aRefsList = aBaseFeatureResult->data()->refsToMe(); std::set aFRefsList = aBaseFeature->data()->refsToMe(); @@ -771,7 +779,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr& the // result is two lines: start line point - start shape point, // last shape point - last line point // create second line - anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint); + anNewFeature = SketchPlugin_SegmentationTools::createLineFeature( + aBaseFeature, aLastShapePoint, aLastFeaturePoint); thePoints.insert(std::dynamic_pointer_cast (anNewFeature->attribute(SketchPlugin_Line::START_ID()))); @@ -789,8 +798,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr& the // Collinear constraint for lines SketchPlugin_Tools::createConstraintObjectObject(sketch(), SketchPlugin_ConstraintCollinear::ID(), - getFeatureResult(aBaseFeature), - getFeatureResult(anNewFeature)); + aBaseFeature->lastResult(), + anNewFeature->lastResult()); } return anNewFeature; } @@ -857,7 +866,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr& theS else { // result is two arcs: start arc point - start shape point, last shape point - last arc point // create second arc - anNewFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint); + anNewFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aLastShapePoint, aLastArcPoint); thePoints.insert(std::dynamic_pointer_cast (anNewFeature->attribute(SketchPlugin_Arc::START_ID()))); @@ -875,8 +885,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr& theS // equal Radius constraint for arcs SketchPlugin_Tools::createConstraintObjectObject(sketch(), SketchPlugin_ConstraintEqual::ID(), - getFeatureResult(aBaseFeature), - getFeatureResult(anNewFeature)); + aBaseFeature->lastResult(), + anNewFeature->lastResult()); // coincident centers constraint SketchPlugin_Tools::createConstraintAttrAttr(sketch(), SketchPlugin_ConstraintCoincidence::ID(), @@ -892,34 +902,172 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr& theS return anNewFeature; } -FeaturePtr SketchPlugin_Trim::trimCircle(const std::shared_ptr& theStartShapePoint, - const std::shared_ptr& theLastShapePoint, - std::set& thePoints, +FeaturePtr SketchPlugin_Trim::trimEllipticArc( + const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::map >& theBaseRefAttributes, + std::set& thePoints, std::set>& theModifiedAttributes) { + FeaturePtr anNewFeature; // Check the base objects are initialized. - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT())); + AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT()); ObjectPtr aBaseObject = aBaseObjectAttr->value(); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - /// points of trim - //AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; - //getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + // points of trim + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + SketchPlugin_SegmentationTools::getFeaturePoints( + aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + + std::shared_ptr aStartArcPoint = aStartPointAttrOfBase->pnt(); + std::shared_ptr aLastArcPoint = anEndPointAttrOfBase->pnt(); + + std::shared_ptr aStartShapePoint = theStartShapePoint; + std::shared_ptr aLastShapePoint = theLastShapePoint; + arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase, + aStartShapePoint, aLastShapePoint); +#ifdef DEBUG_TRIM + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + if (aStartShapePoint.get()) + std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " << + aStartShapePoint->y() << "]" << std::endl; + std::cout << "Start arc attribute point: [" << aStartArcPoint->x() << ", " << + aStartArcPoint->y() << "]" << std::endl; + if (aLastShapePoint.get()) + std::cout << "Last shape point: [" << aLastShapePoint->x() << ", " << + aLastShapePoint->y() << "]" << std::endl; + std::cout << "Last arc attribute point: [" << aLastArcPoint->x() << ", " << + aLastArcPoint->y() << "]" << std::endl; +#endif + + bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint); + bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint); + if (isStartPoint || isLastPoint) { + // result is one arc: changed existing arc + std::string aModifiedAttribute = isStartPoint ? SketchPlugin_EllipticArc::START_POINT_ID() + : SketchPlugin_EllipticArc::END_POINT_ID(); + std::shared_ptr aPoint; + if (aStartShapePoint.get() && aLastShapePoint.get()) + aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint; + else + aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint; + + removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute), + theBaseRefAttributes); + + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); + } + else { + // result is two arcs: start arc point - start shape point, last shape point - last arc point + // create second arc + anNewFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, aLastShapePoint, aLastArcPoint); + thePoints.insert(std::dynamic_pointer_cast( + anNewFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()))); + + std::string aModifiedAttribute = SketchPlugin_EllipticArc::END_POINT_ID(); + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(aModifiedAttribute), + anNewFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()))); + + // modify base arc + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); - /// trim feature - FeaturePtr anNewFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint); + // make elliptic arcs equal + SketchPlugin_Tools::createConstraintObjectObject(sketch(), + SketchPlugin_ConstraintEqual::ID(), + aBaseFeature->lastResult(), + anNewFeature->lastResult()); + // coincident centers constraint + SketchPlugin_Tools::createConstraintAttrAttr(sketch(), + SketchPlugin_ConstraintCoincidence::ID(), + aBaseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID())); + +#ifdef DEBUG_TRIM + std::cout << "Created arc on points:" << std::endl; + std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " << + aStartShapePoint->y() << "]" << std::endl; +#endif + } + return anNewFeature; +} + +FeaturePtr SketchPlugin_Trim::trimClosed(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set& thePoints, + std::set>& theModifiedAttributes) +{ + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT()); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + // trim feature + FeaturePtr anNewFeature = SketchPlugin_SegmentationTools::createArcFeature( + aBaseFeature, theStartShapePoint, theLastShapePoint); // arc created by trim of circle is always correct, that means that it is not inversed - anNewFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(false); + const std::string& aReversedAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID(); + anNewFeature->boolean(aReversedAttrName)->setValue(false); + + if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) { + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), + anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID()))); + } + else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) { + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID()))); + theModifiedAttributes.insert(std::make_pair( + aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()), + anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID()))); + + // update the PARENT_ID reference for all the features created by the ellipse + const std::set& aRefs = aBaseFeature->data()->refsToMe(); + std::list aRefsToParent; + for (std::set::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) { + if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() || + (*aRef)->id() == SketchPlugin_Point::PARENT_ID()) + aRefsToParent.push_back(*aRef); + } + for (std::list::iterator aRef = aRefsToParent.begin(); + aRef != aRefsToParent.end(); ++aRef) + std::dynamic_pointer_cast(*aRef)->setValue(anNewFeature); + } - theModifiedAttributes.insert( - std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), - anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID()))); + const std::string& aStartAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID(); + const std::string& aEndAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID(); thePoints.insert(std::dynamic_pointer_cast - (anNewFeature->attribute(SketchPlugin_Arc::START_ID()))); + (anNewFeature->attribute(aStartAttrName))); thePoints.insert(std::dynamic_pointer_cast - (anNewFeature->attribute(SketchPlugin_Arc::END_ID()))); + (anNewFeature->attribute(aEndAttrName))); return anNewFeature; } @@ -952,9 +1100,14 @@ void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc, static const double anAngleTol = 1.e-12; + const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID(); + const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ? + SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID(); + std::shared_ptr aCenter = std::dynamic_pointer_cast( - theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); + theArc->attribute(aCenterAttrName))->pnt(); + bool isReversed = theArc->boolean(aReversedAttrName)->value(); // collect directions to each point std::shared_ptr aStartDir( @@ -998,7 +1151,6 @@ void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttrib } } - void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute, const AttributePtr& theSourceAttribute) { @@ -1022,100 +1174,3 @@ void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute, aModifiedAttribute->setValue(aSourceAttribute->value()); } } - -FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature, - const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint) -{ -#ifdef DEBUG_TRIM - std::cout << "---- createLineFeature ---" << std::endl; -#endif - - FeaturePtr aFeature; - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch || !theBaseFeature.get()) - return aFeature; - - aFeature = aSketch->addFeature(SketchPlugin_Line::ID()); - - fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint); - fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint); - - fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), - theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); - - aFeature->execute(); // to obtain result - -#ifdef DEBUG_TRIM - std::cout << "---- createLineFeature:end ---" << std::endl; -#endif - - return aFeature; -} - -FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature, - const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint) -{ - FeaturePtr aFeature; - SketchPlugin_Sketch* aSketch = sketch(); - if (!aSketch || !theBaseFeature.get()) - return aFeature; - - std::string aCenterAttributeId; - if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) - aCenterAttributeId = SketchPlugin_Arc::CENTER_ID(); - else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID()) - aCenterAttributeId = SketchPlugin_Circle::CENTER_ID(); - - if (aCenterAttributeId.empty()) - return aFeature; - -#ifdef DEBUG_TRIM - std::cout << "---- createArcFeature ---" << std::endl; -#endif - - aFeature = aSketch->addFeature(SketchPlugin_Arc::ID()); - // update fillet arc: make the arc correct for sure, so, it is not needed to process - // the "attribute updated" - // by arc; moreover, it may cause cyclicity in hte mechanism of updater - bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true); - - fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()), - theBaseFeature->attribute(aCenterAttributeId)); - fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint); - fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint); - - fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), - theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); - - /// fill referersed state of created arc as it is on the base arc - if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) { - bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); - aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed); - } - aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update) - aFeature->data()->blockSendAttributeUpdated(aWasBlocked); - - #ifdef DEBUG_TRIM - std::cout << "---- createArcFeature:end ---" << std::endl; - #endif - - return aFeature; -} - -std::shared_ptr SketchPlugin_Trim::getFeatureResult( - const std::shared_ptr& theFeature) -{ - std::shared_ptr aResult; - - std::string aFeatureKind = theFeature->getKind(); - if (aFeatureKind == SketchPlugin_Line::ID()) - aResult = theFeature->firstResult(); - else if (aFeatureKind == SketchPlugin_Arc::ID()) - aResult = theFeature->lastResult(); - else if (aFeatureKind == SketchPlugin_Circle::ID()) - aResult = theFeature->lastResult(); - - return aResult; -} diff --git a/src/SketchPlugin/SketchPlugin_Trim.h b/src/SketchPlugin/SketchPlugin_Trim.h index 91b9405d8..365cda33c 100644 --- a/src/SketchPlugin/SketchPlugin_Trim.h +++ b/src/SketchPlugin/SketchPlugin_Trim.h @@ -151,10 +151,19 @@ private: /// Make the base object is splitted by the point attributes /// \param thePoints a list of points where coincidences will be build - FeaturePtr trimCircle(const std::shared_ptr& theStartShapePoint, - const std::shared_ptr& theLastShapePoint, - std::set >& thePoints, - std::set>& theModifiedAttributes); + /// \return new elliptic arc if it was created + FeaturePtr trimEllipticArc(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::map >& theBaseRefAttributes, + std::set >& thePoints, + std::set>& theModifiedAttributes); + + /// Make the base object is splitted by the point attributes + /// \param thePoints a list of points where coincidences will be build + FeaturePtr trimClosed(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set >& thePoints, + std::set>& theModifiedAttributes); /// Correct the first and the second point to provide condition that the first is closer to /// the start point and the second point - to the last end of current segment. To rearrange @@ -194,28 +203,6 @@ private: void fillPointAttribute(const AttributePtr& theModifiedAttribute, const std::shared_ptr& thePoint); - /// Creates a line feature filled by center of base feature and given points - /// \param theBaseFeature another arc feature - /// \param theFirstAttribute an attribute with coordinates for the start point - /// \param theSecondAttribute an attribute with coordinates for the end point - FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature, - const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint); - - /// Creates an arc feature filled by center of base feature and given points - /// \param theBaseFeature another arc feature - /// \param theFirstAttribute an attribute with coordinates for the start point - /// \param theSecondAttribute an attribute with coordinates for the end point - FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature, - const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint); - - /// Result result of the feature to build constraint with. For arc, circle it is an edge result. - /// \param theFeature a feature - /// \return result object - std::shared_ptr getFeatureResult( - const std::shared_ptr& theFeature); - private: void findShapePoints(const std::string& theObjectAttributeId, const std::string& thePointAttributeId, diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 0ee6f65f3..1d5cc9c73 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -965,6 +965,8 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape(); std::shared_ptr aSFeature = std::dynamic_pointer_cast(anAttrFeature); + if (!aSFeature) + return false; SketchPlugin_Sketch* aSketch = aSFeature->sketch(); std::shared_ptr aData = aSketch->data(); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index 35cbb4d72..7f416c66b 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -76,6 +76,10 @@ static ConstraintWrapperPtr createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType, std::shared_ptr thePoint, std::shared_ptr theEntity); +static ConstraintWrapperPtr + createConstraintPointsCollinear(std::shared_ptr thePoint1, + std::shared_ptr thePoint2, + std::shared_ptr thePoint3); static ConstraintWrapperPtr createConstraintDistancePointPoint(std::shared_ptr theValue, std::shared_ptr thePoint1, @@ -194,13 +198,15 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint( std::shared_ptr aPoint1 = GCS_POINT_WRAPPER(thePoint1); std::shared_ptr aPoint2 = GCS_POINT_WRAPPER(thePoint2); + std::shared_ptr anEntity1 = GCS_EDGE_WRAPPER(theEntity1); switch (theType) { case CONSTRAINT_PT_PT_COINCIDENT: aResult = createConstraintCoincidence(aPoint1, aPoint2); break; case CONSTRAINT_PT_ON_CURVE: - aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_EDGE_WRAPPER(theEntity1)); + aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1): + createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1)); break; case CONSTRAINT_MIDDLE_POINT: aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2); @@ -211,34 +217,31 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint( case CONSTRAINT_PT_LINE_DISTANCE: aResult = createConstraintDistancePointLine(GCS_SCALAR_WRAPPER(theValue), aPoint1, - GCS_EDGE_WRAPPER(theEntity1)); + anEntity1); break; case CONSTRAINT_HORIZONTAL_DISTANCE: case CONSTRAINT_VERTICAL_DISTANCE: aResult = createConstraintHVDistance(theType, GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2); break; case CONSTRAINT_RADIUS: - aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue), - GCS_EDGE_WRAPPER(theEntity1)); + aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue), anEntity1); break; case CONSTRAINT_ANGLE: aResult = createConstraintAngle(theConstraint, GCS_SCALAR_WRAPPER(theValue), - GCS_EDGE_WRAPPER(theEntity1), GCS_EDGE_WRAPPER(theEntity2)); + anEntity1, GCS_EDGE_WRAPPER(theEntity2)); break; case CONSTRAINT_FIXED: break; case CONSTRAINT_HORIZONTAL: case CONSTRAINT_VERTICAL: - aResult = createConstraintHorizVert(theType, GCS_EDGE_WRAPPER(theEntity1)); + aResult = createConstraintHorizVert(theType, anEntity1); break; case CONSTRAINT_PARALLEL: - aResult = createConstraintParallel(GCS_EDGE_WRAPPER(theEntity1), - GCS_EDGE_WRAPPER(theEntity2)); + aResult = createConstraintParallel(anEntity1, GCS_EDGE_WRAPPER(theEntity2)); break; case CONSTRAINT_PERPENDICULAR: - aResult = createConstraintPerpendicular(GCS_EDGE_WRAPPER(theEntity1), - GCS_EDGE_WRAPPER(theEntity2)); + aResult = createConstraintPerpendicular(anEntity1, GCS_EDGE_WRAPPER(theEntity2)); break; case CONSTRAINT_EQUAL_LINES: case CONSTRAINT_EQUAL_ELLIPSES: @@ -246,7 +249,7 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint( case CONSTRAINT_EQUAL_LINE_ARC: case CONSTRAINT_EQUAL_RADIUS: aResult = createConstraintEqual(theType, - GCS_EDGE_WRAPPER(theEntity1), + anEntity1, GCS_EDGE_WRAPPER(theEntity2), anIntermediate); break; @@ -450,6 +453,17 @@ ConstraintWrapperPtr createConstraintPointOnEntity( return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType)); } +ConstraintWrapperPtr createConstraintPointsCollinear( + std::shared_ptr thePoint1, + std::shared_ptr thePoint2, + std::shared_ptr thePoint3) +{ + GCSConstraintPtr aNewConstr(new GCS::ConstraintPointOnLine( + *(thePoint1->point()), *(thePoint2->point()), *(thePoint3->point()))); + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PT_ON_CURVE)); +} + ConstraintWrapperPtr createConstraintMiddlePoint( std::shared_ptr thePoint, std::shared_ptr theEntity, diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp index b0520c45a..2c4d8eed3 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -22,8 +22,14 @@ #include #include +#include + #include +#include +#include +#include #include +#include static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint, const StoragePtr& theStorage, @@ -44,8 +50,146 @@ static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint, } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) { theExtremities[0] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::START_ID())); theExtremities[1] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::END_ID())); + } else if (aFeature->getKind() == SketchPlugin_EllipticArc::ID()) { + theExtremities[0] = theStorage->entity( + aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + theExtremities[1] = theStorage->entity( + aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())); + } + } +} + +static void getPointOwnerAndParent(const AttributeRefAttrPtr theRefAttr, + AttributePoint2DPtr& thePoint, + FeaturePtr& theOwner, + FeaturePtr& theParent) +{ + AttributePtr anAttr = theRefAttr->attr(); + if (theRefAttr->isObject()) { + FeaturePtr anOwner = ModelAPI_Feature::feature(theRefAttr->object()); + if (anOwner && anOwner->getKind() == SketchPlugin_Point::ID()) + anAttr = anOwner->attribute(SketchPlugin_Point::COORD_ID()); + else + return; + } + thePoint = std::dynamic_pointer_cast(anAttr); + if (thePoint) { + theOwner = ModelAPI_Feature::feature(thePoint->owner()); + if (theOwner) { + std::string aParentRefID; + if (theOwner->getKind() == SketchPlugin_Line::ID()) + aParentRefID = SketchPlugin_Line::PARENT_ID(); + else if (theOwner->getKind() == SketchPlugin_Point::ID()) + aParentRefID = SketchPlugin_Point::PARENT_ID(); + if (!aParentRefID.empty()) { + AttributeReferencePtr aParentRef = theOwner->reference(aParentRefID); + theParent = aParentRef ? ModelAPI_Feature::feature(aParentRef->value()) : FeaturePtr(); + } + } + } +} + +static void ellipseDiameters(FeaturePtr theEllipse, + std::pair& theMajorAxis, + std::pair& theMinorAxis) +{ + if (theEllipse->getKind() == SketchPlugin_Ellipse::ID()) { + theMajorAxis.first = SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(); + theMajorAxis.second = SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(); + theMinorAxis.first = SketchPlugin_Ellipse::MINOR_AXIS_START_ID(); + theMinorAxis.second = SketchPlugin_Ellipse::MINOR_AXIS_END_ID(); + } else if (theEllipse->getKind() == SketchPlugin_EllipticArc::ID()) { + theMajorAxis.first = SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(); + theMajorAxis.second = SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID(); + theMinorAxis.first = SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(); + theMinorAxis.second = SketchPlugin_EllipticArc::MINOR_AXIS_END_ID(); + } +} + +static void findDiameterOnEllipse(FeaturePtr theConstruction, + FeaturePtr theEllipse, + AttributePtr& theStart, + AttributePtr& theEnd) +{ + AttributePtr anEllipseAttr; + const std::set& aRefs = theConstruction->data()->refsToMe(); + for (std::set::const_iterator aRefIt = aRefs.begin(); + aRefIt != aRefs.end(); ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) { + AttributeRefAttrPtr aRefAttr; + if ((*aRefIt)->id() == SketchPlugin_Constraint::ENTITY_A()) + aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B()); + else + aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A()); + anEllipseAttr = aRefAttr->attr(); + break; } } + if (!anEllipseAttr) + return; + + std::pair aMajorAxis, aMinorAxis; + ellipseDiameters(theEllipse, aMajorAxis, aMinorAxis); + if (anEllipseAttr->id() == aMajorAxis.first) { + theStart = anEllipseAttr; + theEnd = theEllipse->attribute(aMajorAxis.second); + } + else if (anEllipseAttr->id() == aMajorAxis.second) { + theStart = theEllipse->attribute(aMajorAxis.first); + theEnd = anEllipseAttr; + } + else if (anEllipseAttr->id() == aMinorAxis.first) { + theStart = anEllipseAttr; + theEnd = theEllipse->attribute(aMinorAxis.second); + } + else if (anEllipseAttr->id() == aMinorAxis.second) { + theStart = theEllipse->attribute(aMinorAxis.first); + theEnd = anEllipseAttr; + } +} + +static void processEllipticArcExtremities(SketchSolver_ConstraintType& theType, + const ConstraintPtr& theConstraint, + const StoragePtr& theStorage, + std::vector& theAttributes, + EntityWrapperPtr theExtremities[2]) +{ + AttributePoint2DPtr aPointA, aPointB; + FeaturePtr anOwnerA, anOwnerB; + FeaturePtr aParentA, aParentB; + getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()), + aPointA, anOwnerA, aParentA); + getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()), + aPointB, anOwnerB, aParentB); + + AttributePtr anAxisStart, anAxisEnd, aPoint; + FeaturePtr aConstruction, anEllipticArc; + if (aParentA && aParentA == anOwnerB) { + aPoint = aPointB; + aConstruction = anOwnerA; + anEllipticArc = anOwnerB; + } + else if (aParentB && aParentB == anOwnerA) { + aPoint = aPointA; + aConstruction = anOwnerB; + anEllipticArc = anOwnerA; + } + + if (!anEllipticArc || anEllipticArc->getKind() != SketchPlugin_EllipticArc::ID() || + (aPoint->id() != SketchPlugin_EllipticArc::START_POINT_ID() && + aPoint->id() != SketchPlugin_EllipticArc::END_POINT_ID())) + return; + + findDiameterOnEllipse(aConstruction, anEllipticArc, anAxisStart, anAxisEnd); + + if (anAxisStart && anAxisEnd) { + theAttributes[0] = theStorage->entity(aPoint); + theAttributes[1] = theStorage->entity(anAxisStart); + theAttributes[2] = theStorage->entity(anAxisEnd); + theType = CONSTRAINT_PT_ON_CURVE; + getCoincidentFeatureExtremities(theConstraint, theStorage, theExtremities); + } } @@ -93,9 +237,14 @@ void SketchSolver_ConstraintCoincidence::getAttributes( return; } - if (theAttributes[1]) + if (theAttributes[1]) { myType = CONSTRAINT_PT_PT_COINCIDENT; - else if (theAttributes[2]) { + // if elliptic arc boundary point is connected with one of ellipse characteristics, + // it should be changed from point-point coincidence to coincidence between point + // and axis of the ellipse to decrease only 1 DoF instead of 2 DoF and avoid overconstraint. + processEllipticArcExtremities(myType, myBaseConstraint, myStorage, + theAttributes, myFeatureExtremities); + } else if (theAttributes[2]) { myType = CONSTRAINT_PT_ON_CURVE; // obtain extremity points of the coincident feature for further checking of multi-coincidence getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities); @@ -109,6 +258,32 @@ void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr& theFeatur PlaneGCSSolver_UpdateCoincidence* anUpdater = static_cast(theUpdater); bool isAccepted = anUpdater->addCoincidence(myAttributes.front(), myAttributes.back()); + // additionally process internal coincidence, set point coincident with ellipse/elliptic arc + // for correct processing further coincidences set by the user + if (isAccepted && + myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) { + AttributeRefAttrPtr aRefAttrA = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr aRefAttrB = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()); + if (aRefAttrA && aRefAttrB) { + AttributePoint2DPtr anAttrA, anAttrB; + FeaturePtr anOwnerA, anOwnerB; + FeaturePtr aParentA, aParentB; + getPointOwnerAndParent(aRefAttrA, anAttrA, anOwnerA, aParentA); + getPointOwnerAndParent(aRefAttrB, anAttrB, anOwnerB, aParentB); + + EntityWrapperPtr aPoint, anEntity; + if (aParentA == anOwnerB) { + aPoint = myStorage->entity(anAttrA); + anEntity = myStorage->entity(anOwnerB); + } + else if (aParentB == anOwnerA) { + aPoint = myStorage->entity(anAttrB); + anEntity = myStorage->entity(anOwnerA); + } + if (aPoint && anEntity) + anUpdater->addCoincidence(aPoint, anEntity); + } + } // additionally check the point is coincident to extremity of coincident feature if (myFeatureExtremities[0] && myFeatureExtremities[1]) {