From 023c72db1a0c06efe73559cc2ff37c841842823a Mon Sep 17 00:00:00 2001 From: nds Date: Fri, 29 Jul 2016 11:31:57 +0300 Subject: [PATCH] Issue #1664: In the Sketcher, add the function Split a segment: split of arc, move of constraints --- src/PartSet/PartSet_Tools.cpp | 25 +- src/PartSet/PartSet_WidgetPoint2d.cpp | 4 +- .../SketchPlugin_ConstraintCoincidence.cpp | 65 ++ .../SketchPlugin_ConstraintCoincidence.h | 13 + .../SketchPlugin_ConstraintSplit.cpp | 901 +++++------------- .../SketchPlugin_ConstraintSplit.h | 40 +- src/SketchPlugin/SketchPlugin_Validators.cpp | 41 +- 7 files changed, 363 insertions(+), 726 deletions(-) diff --git a/src/PartSet/PartSet_Tools.cpp b/src/PartSet/PartSet_Tools.cpp index 6495c3ce9..70a6138dc 100755 --- a/src/PartSet/PartSet_Tools.cpp +++ b/src/PartSet/PartSet_Tools.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include @@ -740,26 +742,9 @@ GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute, std::shared_ptr PartSet_Tools::getPoint(std::shared_ptr& theFeature, const std::string& theAttribute) { - std::shared_ptr aPointAttr; - - if (!theFeature->data()) - return std::shared_ptr(); - - FeaturePtr aFeature; - std::shared_ptr anAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute)); - if (!anAttr) - return std::shared_ptr(); - - aFeature = ModelAPI_Feature::feature(anAttr->object()); - - if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID()) - aPointAttr = std::dynamic_pointer_cast( - aFeature->data()->attribute(SketchPlugin_Point::COORD_ID())); - - else if (anAttr->attr()) { - aPointAttr = std::dynamic_pointer_cast(anAttr->attr()); - } + std::shared_ptr aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr( + theFeature.get(), theAttribute, SketchPlugin_Point::ID(), + SketchPlugin_Point::COORD_ID()); if (aPointAttr.get() != NULL) return aPointAttr->pnt(); return std::shared_ptr(); diff --git a/src/PartSet/PartSet_WidgetPoint2d.cpp b/src/PartSet/PartSet_WidgetPoint2d.cpp index 9b58bab81..f4490eb73 100644 --- a/src/PartSet/PartSet_WidgetPoint2d.cpp +++ b/src/PartSet/PartSet_WidgetPoint2d.cpp @@ -589,7 +589,9 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo void PartSet_WidgetPoint2D::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) { - if (isEditingMode()) + PartSet_Module* aModule = dynamic_cast(myWorkshop->module()); + + if (isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditStarted()) return; gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp index 4b9a022bf..5f79a167e 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp @@ -6,6 +6,14 @@ #include "SketchPlugin_ConstraintCoincidence.h" +#include +#include +#include +#include + +#include +#include + #include SketchPlugin_ConstraintCoincidence::SketchPlugin_ConstraintCoincidence() @@ -31,3 +39,60 @@ AISObjectPtr SketchPlugin_ConstraintCoincidence::getAISObject(AISObjectPtr thePr thePrevious); return anAIS; } + +FeaturePtr SketchPlugin_ConstraintCoincidence::findCoincidenceFeature(const FeaturePtr& theFeature1, + const FeaturePtr& theFeature2) +{ + FeaturePtr aResultFeature; + + std::list anAttrList; + if (theFeature1->getKind() == SketchPlugin_Circle::ID() || + theFeature2->getKind() == SketchPlugin_Circle::ID()) + return aResultFeature; + + if (theFeature2->getKind() == SketchPlugin_Line::ID()) { + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID())); + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID())); + } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) { + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID())); + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID())); + } + + const std::set& aRefsList = theFeature1->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefsList.begin(); + for (; aRefIt != aRefsList.end() && !aResultFeature.get(); ++aRefIt) { + FeaturePtr aConstrFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); + if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) + continue; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); + AttributePtr anAttr = aRefAttr->attr(); + if (anAttr->id() == SketchPlugin_Arc::CENTER_ID()) + continue; + + anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()); + if (anAttr == *aRefIt) + anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()); + + aRefAttr = std::dynamic_pointer_cast(anAttr); + if (!aRefAttr) + continue; + anAttr = aRefAttr->attr(); + for (std::list::const_iterator anIt = anAttrList.begin(); + anIt != anAttrList.end() && !aResultFeature.get(); ++anIt) + if (*anIt == anAttr) + aResultFeature = aConstrFeature; + } + return aResultFeature; +} + +AttributePoint2DPtr SketchPlugin_ConstraintCoincidence::getPoint(const FeaturePtr& theFeature) +{ + AttributePoint2DPtr aPoint = ModelGeomAlgo_Point2D::getPointOfRefAttr(theFeature.get(), + SketchPlugin_Constraint::ENTITY_A(), + SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + if (!aPoint.get()) + aPoint = ModelGeomAlgo_Point2D::getPointOfRefAttr(theFeature.get(), + SketchPlugin_Constraint::ENTITY_B(), + SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + return aPoint; +} diff --git a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.h b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.h index ffc4ce1b9..4990259e2 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.h +++ b/src/SketchPlugin/SketchPlugin_ConstraintCoincidence.h @@ -12,6 +12,8 @@ #include #include +class GeomDataAPI_Point2D; + /** \class SketchPlugin_ConstraintCoincidence * \ingroup Plugins * \brief Feature for creation of a new constraint which defines equivalence of two points @@ -44,6 +46,17 @@ class SketchPlugin_ConstraintCoincidence : public SketchPlugin_ConstraintBase /// \brief Request for initialization of data model of the feature: adding all attributes SKETCHPLUGIN_EXPORT virtual void initAttributes(); + /// Returns coincident feature if there is a coincidence built on the given features + /// \param theFeature1 the first feature + /// \param theFeature2 the second feature + static FeaturePtr findCoincidenceFeature(const FeaturePtr& theFeature1, + const FeaturePtr& theFeature2); + + /// Returns point of coincidence feature + /// \param theFeature a coincidence feature + /// \return point 2d attribute. Coincidence always has at least one point 2d attribute + static std::shared_ptr getPoint(const FeaturePtr& theFeature); + /// \brief Use plugin manager for features creation SketchPlugin_ConstraintCoincidence(); }; diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index 67e5a2a65..62b538554 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -17,6 +17,7 @@ #include //#include #include +#include #include #include @@ -28,21 +29,24 @@ #include #include #include +#include +#include +#include //#include #include //#include //#include // -//#include -//#include +#include +#include +#include //#include //#include -//#include -//#include -//#include //#include // + +#include #include // //#include @@ -117,672 +121,92 @@ void SketchPlugin_ConstraintSplit::execute() Events_Loop::loop()->setFlushed(anUpdateEvent, false); + // Find feature constraints FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + + std::set aFeaturesToDelete; + std::map aTangentFeatures; + std::map aCoincidenceToFeature; + std::map aCoincidenceToPoint; + getConstraints(aFeaturesToDelete, aTangentFeatures, aCoincidenceToFeature, aCoincidenceToPoint); + + std::string aFeatureKind = aBaseFeature->getKind(); - FeaturePtr aSplitFeature, aBeforeFeature, anAfterFeature; + FeaturePtr aSplitFeature, anAfterFeature; + std::set aFurtherCoincidences; /*if (aFeatureKind == SketchPlugin_Line::ID()) splitLine(aSplitFeature, anOtherFeatures); else*/ if (aFeatureKind == SketchPlugin_Arc::ID()) - splitArc(aSplitFeature, aBeforeFeature, anAfterFeature); + splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences); /*if (aFeatureKind == SketchPlugin_Circle::ID()) splitCircle(aSplitFeature, anOtherFeatures); FeaturePtr aSplitFeature; std::set anOtherFeatures;*/ - // Send events to update the sub-features by the solver. - if(isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); - } -} - -void SketchPlugin_ConstraintSplit::attributeChanged(const std::string& theID) -{ -/* if(theID == SketchPlugin_Constraint::ENTITY_A()) { - if(myListOfPointsChangedInCode) { - return; + //setConstraints(aSplitFeature, aBaseFeature, anAfterFeature, aFeaturesToDelete, aTangentFeatures, + // aCoincidenceToFeature, aCoincidenceToPoint); + if (false) { + std::set aFeatureResults; + aFeatureResults.insert(getFeatureResult(aBaseFeature)); + if (anAfterFeature.get()) + aFeatureResults.insert(getFeatureResult(anAfterFeature)); + + // coincidence to feature + std::map::const_iterator aCIt = aCoincidenceToFeature.begin(), + aCLast = aCoincidenceToFeature.end(); + for (; aCIt != aCLast; aCIt++) { + FeaturePtr aCoincFeature = aCIt->first; + std::string anAttributeId = aCIt->second.first; + AttributePoint2DPtr aCoincPoint = aCIt->second.second; + std::set::const_iterator aFCIt = aFurtherCoincidences.begin(), + aFCLast = aFurtherCoincidences.end(); + std::shared_ptr aCoincPnt = aCoincPoint->pnt(); + AttributePoint2DPtr aFeaturePointAttribute; + for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt) { + AttributePoint2DPtr aFCAttribute = *aFCIt; + if (aCoincPnt->isEqual(aFCAttribute->pnt())) + aFeaturePointAttribute = aFCAttribute; } - - // Clear results. - clearResults(); - - // Clear list of new points. - myNewPoints.clear(); - - // Get list of points for fillets and current radius. - AttributeRefAttrListPtr aRefListOfFilletPoints = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributeDoublePtr aRadiusAttribute = real(VALUE()); - int aListSize = aRefListOfFilletPoints->size(); - if(aListSize == 0 && !myRadiusChangedByUser) { - // If list is empty reset radius to zero (if it was not changed by user). - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(0); - myRadiusChangedInCode = false; - return; + if (aFeaturePointAttribute.get()) { + aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute); } + else { + /// find feature by shape intersected the point + ResultPtr aResultForCoincidence = *(aFeatureResults.begin()); - // Iterate over points to get base lines an calculate radius for fillets. - double aMinimumRadius = 0; - std::list> aSelectedPointsList = aRefListOfFilletPoints->list(); - std::list>::iterator anIter = aSelectedPointsList.begin(); - std::set aPointsToSkeep; - for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) { - AttributePtr aFilletPointAttr = (*anIter).second; - std::shared_ptr aFilletPoint2D = - std::dynamic_pointer_cast(aFilletPointAttr); - if(!aFilletPoint2D.get()) { - myNewPoints.clear(); - setError("Error: One of the selected points is invalid."); - return; - } - - // If point or coincident point is already in list remove it from attribute. - if(aPointsToSkeep.find(aFilletPointAttr) != aPointsToSkeep.end()) { - myListOfPointsChangedInCode = true; - aRefListOfFilletPoints->remove(aFilletPointAttr); - myListOfPointsChangedInCode = false; - continue; - } - - // Obtain constraint coincidence for the fillet point. - FeaturePtr aConstraintCoincidence; - const std::set& aRefsList = aFilletPointAttr->owner()->data()->refsToMe(); - for(std::set::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { - std::shared_ptr anAttr = (*anIt); - FeaturePtr aConstrFeature = std::dynamic_pointer_cast(anAttr->owner()); - if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); - AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); - if(anAttrRefA.get()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(aFilletPointAttr == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - if(anAttrRefB.get()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aFilletPointAttr == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - } - } - - if(!aConstraintCoincidence.get()) { - myNewPoints.clear(); - setError("Error: No coincident edges at one of the selected points."); - return; - } - - // Get coincides from constraint. - std::set aCoincides; - - - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoincides); - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoincides); - - // Remove points from set of coincides. Also get all attributes which is equal to this point to exclude it. - std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::set aNewSetOfCoincides; - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - std::string aFeatureKind = (*anIt)->getKind(); - if(aFeatureKind == SketchPlugin_Point::ID()) { - AttributePtr anAttr = (*anIt)->attribute(SketchPlugin_Point::COORD_ID()); - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(anAttr); - if(aPoint2D.get() && aFilletPnt2d->isEqual(aPoint2D->pnt())) { - aPointsToSkeep.insert(anAttr); - } - } else if(aFeatureKind == SketchPlugin_Line::ID()) { - AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Line::START_ID()); - std::shared_ptr aPointStart2D = - std::dynamic_pointer_cast(anAttrStart); - if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { - aPointsToSkeep.insert(anAttrStart); - } - AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID()); - std::shared_ptr aPointEnd2D = - std::dynamic_pointer_cast(anAttrEnd); - if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { - aPointsToSkeep.insert(anAttrEnd); - } - aNewSetOfCoincides.insert(*anIt); - } else if(aFeatureKind == SketchPlugin_Arc::ID() ) { - AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr aPointCenter2D = - std::dynamic_pointer_cast(anAttrCenter); - if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) { - aPointsToSkeep.insert(anAttrCenter); - continue; - } - AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID()); - std::shared_ptr aPointStart2D = - std::dynamic_pointer_cast(anAttrStart); - if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { - aPointsToSkeep.insert(anAttrStart); - } - AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID()); - std::shared_ptr aPointEnd2D = - std::dynamic_pointer_cast(anAttrEnd); - if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { - aPointsToSkeep.insert(anAttrEnd); - } - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoincides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - } + if (aFeatureResults.size() > 1) { // try to find point on additional feature + ResultPtr anAddtionalResult = *(aFeatureResults.begin()++); + GeomShapePtr aShape = anAddtionalResult->shape(); - if(aCoincides.size() != 2) { - myNewPoints.clear(); - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; - } + std::shared_ptr aPnt2d = aCoincPoint->pnt(); + std::shared_ptr aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y()); - // Store base point for fillet. - aPointsToSkeep.insert(aFilletPointAttr); - myNewPoints.insert(aFilletPointAttr); - - // Get base lines for fillet. - FeaturePtr anOldFeatureA, anOldFeatureB; - std::set::iterator aLinesIt = aCoincides.begin(); - anOldFeatureA = *aLinesIt++; - anOldFeatureB = *aLinesIt; - - // Getting radius value if it was not changed by user. - if(!myRadiusChangedByUser) { - // Getting points located at 1/3 of edge length from fillet point. - std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::shared_ptr aPntA, aPntB; - getPointOnEdge(anOldFeatureA, aFilletPnt2d, aPntA); - getPointOnEdge(anOldFeatureB, aFilletPnt2d, aPntB); - - /// Getting distances. - double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA); - double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB); - double aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0; - aMinimumRadius = aMinimumRadius == 0 ? aRadius : aRadius < aMinimumRadius ? aRadius : aMinimumRadius; + std::shared_ptr aProjectedPoint; + if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint)) + aResultForCoincidence = anAddtionalResult; } - } - - // Set new default radius if it was not changed by user. - if(!myRadiusChangedByUser) { - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(aMinimumRadius); - myRadiusChangedInCode = false; - } - - } else if(theID == SketchPlugin_Constraint::VALUE()) { - if(myRadiusInitialized && !myRadiusChangedInCode) { - myRadiusChangedByUser = true; - } - if(!myRadiusInitialized) { - myRadiusInitialized = true; + aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence); } } -*/ -} - -//AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) -//{ -// if (!sketch()) -// return thePrevious; -// -// AISObjectPtr anAIS = thePrevious; -// /// TODO: Equal constraint presentation should be put here -// return anAIS; -//} - -bool SketchPlugin_ConstraintSplit::isMacro() const -{ - return true; -} - -//void SketchPlugin_ConstraintSplit::clearResults() -//{ -///* // Clear auxiliary flag on initial objects. -// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); -// aPointsIter != myPointFeaturesMap.end();) { -// const FilletFeatures& aFilletFeatures = aPointsIter->second; -// std::list>::const_iterator aFeatureIt; -// for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin(); -// aFeatureIt != aFilletFeatures.baseEdgesState.cend(); -// ++aFeatureIt) { -// aFeatureIt->first->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second); -// } -// ++aPointsIter; -// } -// -// // And remove all produced features. -// DocumentPtr aDoc = sketch()->document(); -// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); -// aPointsIter != myPointFeaturesMap.end();) { -// // Remove all produced constraints. -// const FilletFeatures& aFilletFeatures = aPointsIter->second; -// std::list::const_iterator aFeatureIt; -// for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin(); -// aFeatureIt != aFilletFeatures.resultConstraints.cend(); -// ++aFeatureIt) { -// aDoc->removeFeature(*aFeatureIt); -// } -// -// // Remove all result edges. -// for(aFeatureIt = aFilletFeatures.resultEdges.cbegin(); -// aFeatureIt != aFilletFeatures.resultEdges.cend(); -// ++aFeatureIt) { -// aDoc->removeFeature(*aFeatureIt); -// } -// -// // Remove point from map. -// myPointFeaturesMap.erase(aPointsIter++); -// } -//*/ -//}; -// -// -//// ========= Auxiliary functions ================= -//void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, -// FeaturePtr theFeature, const std::string& theFeatureAttribute) -//{ -// std::shared_ptr anArcPoint = std::dynamic_pointer_cast( -// theNewArc->attribute(theNewArcAttribute))->pnt(); -// std::dynamic_pointer_cast( -// theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); -//} - -/*/// \brief Find intersections of lines shifted along normal direction -void possibleFilletCenterLineLine( - std::shared_ptr thePointA, std::shared_ptr theDirA, - std::shared_ptr thePointB, std::shared_ptr theDirB, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); - std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); - std::shared_ptr aPntA, aPntB; - double aDet = theDirA->cross(theDirB); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); - double aVX = aDirAT->xy()->dot(aPntA); - double aVY = aDirBT->xy()->dot(aPntB); - std::shared_ptr aPoint(new GeomAPI_XY( - (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, - (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); - theCenters.push_back(aPoint); - } - } -} - -/// \brief Find intersections of line shifted along normal direction in both sides -/// and a circle with extended radius -void possibleFilletCenterLineArc( - std::shared_ptr theStartLine, std::shared_ptr theDirLine, - std::shared_ptr theCenterArc, double theRadiusArc, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x())); - std::shared_ptr aPnt; - double aDirNorm2 = theDirLine->dot(theDirLine); - double aRad = 0.0; - double aDirX = theDirLine->x(); - double aDirX2 = theDirLine->x() * theDirLine->x(); - double aDirY2 = theDirLine->y() * theDirLine->y(); - double aDirXY = theDirLine->x() * theDirLine->y(); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius)); - double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc)); - double aCoeff2 = aCoeff * aCoeff; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRad = theRadiusArc + aStepB * theRadius; - double aD = aRad * aRad * aDirNorm2 - aCoeff2; - if (aD < 0.0) - continue; - double aDs = sqrt(aD); - double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2; - double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2; - double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2; - double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } + // coincidence to points + // TODO + // tangency + // TODO } -} + // delete constraints + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete); -/// \brief Find intersections of two circles with extended radii -void possibleFilletCenterArcArc( - std::shared_ptr theCenterA, double theRadiusA, - std::shared_ptr theCenterB, double theRadiusB, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aCenterDir = theCenterB->decreased(theCenterA); - double aCenterDist2 = aCenterDir->dot(aCenterDir); - double aCenterDist = sqrt(aCenterDist2); - - double aRadA, aRadB; - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aRadA = theRadiusA + aStepA * theRadius; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRadB = theRadiusB + aStepB * theRadius; - if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist) - continue; // there is no intersections - - double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist); - double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist); - - double x1 = theCenterA->x() + (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist; - double y1 = theCenterA->y() + (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist; - - double x2 = theCenterA->x() + (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist; - double y2 = theCenterA->y() + (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } - } -} - -void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], - std::shared_ptr& theCenter, - std::shared_ptr& theTangentA, - std::shared_ptr& theTangentB) -{ - static const int aNbFeatures = 2; - FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB}; - std::shared_ptr aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures]; - std::shared_ptr aStartPoint, aEndPoint; - - for (int i = 0; i < aNbFeatures; i++) { - if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::END_ID())); - } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::END_ID())); - aCenter[i] = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy(); - } else - return; - aStart[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) : - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y())); - aEnd[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) : - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y())); - } - - if (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aDir[2]; - std::shared_ptr aDirT[2]; - for (int i = 0; i < aNbFeatures; i++) { - aDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i]))); - aDirT[i] = std::shared_ptr(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x())); - } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], theRadius, aSuspectCenters); - double aDot = 0.0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); - theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); - if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) - continue; // incorrect position - aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); - theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); - if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) - continue; // incorrect position - // the center is found, stop searching - theCenter = *anIt; - return; - } - } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) || - (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID())) { - int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; - double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); - std::shared_ptr aDirLine = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); - std::shared_ptr aDirT = std::shared_ptr( - new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); - - std::shared_ptr aStartArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - double anArcAngle = aEndArcDir->angle(aStartArcDir); - - // get possible centers and filter them - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], anArcRadius, theRadius, aSuspectCenters); - double aDot = 0.0; - // the line is forward into the arc - double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy()); - std::shared_ptr aLineTgPoint, anArcTgPoint; - // The possible centers are ranged by their positions. - // If the point is not satisfy one of criteria, the weight is decreased with penalty. - int aBestWeight = 0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - int aWeight = 2; - aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt)); - aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot)); - // Check the point is placed on the correct arc (penalty if false) - if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc) - aWeight -= 1; - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd]))); - double aCurAngle = aCurDir->angle(aStartArcDir); - if (anArcAngle < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle)) - continue; - if (aWeight > aBestWeight) - aBestWeight = aWeight; - else if (aWeight < aBestWeight || - aStart[aLineInd]->distance(*anIt) > - aStart[aLineInd]->distance(theCenter)) // <-- take closer point - continue; - // the center is found, stop searching - theCenter = *anIt; - anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius)); - if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { - theTangentA = aLineTgPoint; - theTangentB = anArcTgPoint; - } else { - theTangentA = anArcTgPoint; - theTangentB = aLineTgPoint; - } - //return; - } - } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID()) { - double anArcRadius[aNbFeatures]; - double anArcAngle[aNbFeatures]; - std::shared_ptr aStartArcDir[aNbFeatures]; - for (int i = 0; i < aNbFeatures; i++) { - anArcRadius[i] = aStart[i]->distance(aCenter[i]); - aStartArcDir[i] = std::shared_ptr( - new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); - anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]); - } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], anArcRadius[1], theRadius, aSuspectCenters); - double aDot = 0.0; - std::shared_ptr aLineTgPoint, anArcTgPoint; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0]))); - double aCurAngle = aCurDir->angle(aStartArcDir[0]); - if (anArcAngle[0] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0])) - continue; // incorrect position - theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0])); - - aCurDir = std::shared_ptr(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1]))); - aCurAngle = aCurDir->angle(aStartArcDir[1]); - if (anArcAngle[1] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1])) - continue; // incorrect position - theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1])); - - // the center is found, stop searching - theCenter = *anIt; - return; - } - } -} - -void getPointOnEdge(const FeaturePtr theFeature, - const std::shared_ptr theFilletPoint, - std::shared_ptr& thePoint) { - if(theFeature->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - if(aPntStart->distance(theFilletPoint) > 1.e-7) { - aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - } - thePoint.reset( new GeomAPI_Pnt2d(aPntStart->xy()->added( aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) ); - } else { - std::shared_ptr aPntTemp; - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); - if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) { - aPntTemp = aPntStart; - aPntStart = aPntEnd; - aPntEnd = aPntTemp; - } - std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); - double aStartParameter(0), anEndParameter(0); - aCirc->parameter(aPntStart, paramTolerance, aStartParameter); - aCirc->parameter(aPntEnd, paramTolerance, anEndParameter); - if(aPntStart->distance(theFilletPoint) > tolerance) { - double aTmpParameter = aStartParameter; - aStartParameter = anEndParameter; - anEndParameter = aTmpParameter; - } - double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; - aCirc->D0(aPntParameter, thePoint); - } -} - -double getProjectionDistance(const FeaturePtr theFeature, - const std::shared_ptr thePoint) -{ - std::shared_ptr aProjectPnt; - if(theFeature->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - std::shared_ptr aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd)); - aProjectPnt = aLin->project(thePoint); - } else { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); - std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); - aProjectPnt = aCirc->project(thePoint); - } - if(aProjectPnt.get()) { - return aProjectPnt->distance(thePoint); + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); } - return -1; } -std::set getCoincides(const FeaturePtr& theConstraintCoincidence) +bool SketchPlugin_ConstraintSplit::isMacro() const { - std::set aCoincides; - - std::shared_ptr aFilletPnt = SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence); - - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoincides); - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoincides); - - // Remove points from set of coincides. - std::set aNewSetOfCoincides; - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if((*anIt)->getKind() == SketchPlugin_Line::ID()) { - aNewSetOfCoincides.insert(*anIt); - } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { - AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr aPointCenter2D = - std::dynamic_pointer_cast(anAttrCenter); - if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) { - continue; - } - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoincides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - } - - return aCoincides; + return true; } -*/ std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRefAttr( const AttributePtr& theAttribute) @@ -827,9 +251,135 @@ void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStar } } +void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeaturesToDelete, + std::map& theTangentFeatures, + std::map& theCoincidenceToFeature, + std::map& theCoincidenceToPoint) +{ + std::shared_ptr aData = data(); + + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::VALUE())); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + + const std::set& aRefsList = aBaseFeatureResult->data()->refsToMe(); + std::set::const_iterator aIt; + for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) { + std::shared_ptr aAttr = (*aIt); + FeaturePtr aRefFeature = std::dynamic_pointer_cast(aAttr->owner()); + std::string aRefFeatureKind = aRefFeature->getKind(); + if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() || + aRefFeatureKind == SketchPlugin_MultiRotation::ID() || + aRefFeatureKind == SketchPlugin_MultiTranslation::ID()) + theFeaturesToDelete.insert(aRefFeature); + else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) { + if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion + theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented + else { + std::string anAttributeToBeModified; + AttributePoint2DPtr aTangentPoint; + ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object(); + ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object(); + if (aResult1.get() && aResult2.get()) { + FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature + (ModelAPI_Feature::feature(aResult1), + ModelAPI_Feature::feature(aResult2)); + aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature); + } + if (aTangentPoint.get()) { + FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1); + std::string anAttributeToBeModified = aFeature1 == aBaseFeature + ? SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A(); + theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint); + } + else + theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint + } + } + else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) { + std::string anAttributeToBeModified; + AttributePoint2DPtr aCoincidentPoint; + AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B()); + bool isToFeature = false; + if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature + FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object()) + : FeaturePtr(); + isToFeature = aFeature.get() && aFeature == aRefFeature; + anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_B(); + if (!isToFeature) { + aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object()) + : FeaturePtr(); + isToFeature = aFeature.get() && aFeature == aRefFeature; + anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_A(); + } + if (isToFeature) + aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature); + } + if (!isToFeature) { /// coincidence to point on base feature + AttributePtr anAttribute; + if (!anAttrA->isObject()) { + AttributePtr aCurAttribute = anAttrA->attr(); + if (aCurAttribute.get()) { + FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner()); + if (aCurFeature.get() && aCurFeature == aRefFeature) { + anAttribute = anAttrA->attr(); + anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_A(); + } + } + } + if (!anAttribute.get() && !anAttrB->isObject()) { + AttributePtr aCurAttribute = anAttrB->attr(); + if (aCurAttribute.get()) { + FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner()); + if (aCurFeature.get() && aCurFeature == aRefFeature) { + anAttribute = anAttrB->attr(); + anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_B(); + } + } + } + if (anAttribute.get()) + aCoincidentPoint = std::dynamic_pointer_cast(anAttribute); + } + if (aCoincidentPoint.get()) { + if (isToFeature) + theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified, + aCoincidentPoint); + else + theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified, + aCoincidentPoint); + } + else + theFeaturesToDelete.insert(aRefFeature); /// this case should not happen + } + } +} + +/*void SketchPlugin_ConstraintSplit::setConstraints(const FeaturePtr& theSplitFeature, + const FeaturePtr& theBaseFeature, + const FeaturePtr& theAfterFeature, + const std::set>& theFeaturesToDelete, + const std::map, std::shared_ptr >& theTangentFeatures, + const std::map, std::shared_ptr >& theCoincidenceToFeature, + const std::map, std::shared_ptr >& theCoincidenceToPoint) +{ + // coincidence to feature + + + // coincidence to points + + // tangency + + // delete constraints + +}*/ + void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, - FeaturePtr& theBeforeFeature, - FeaturePtr& theAfterFeature) + FeaturePtr& theBaseFeature, + FeaturePtr& theAfterFeature, + std::set& thePoints) { SketchPlugin_Sketch* aSketch = sketch(); if (!aSketch) @@ -859,34 +409,63 @@ void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, aFactory->validate(theSplitFeature); // need to be validated to update the "Apply" state if not previewed std::string anError = theSplitFeature->error(); + // before split feature if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { - theBeforeFeature = aBaseFeature; ///< use base feature to store all constraints here + theBaseFeature = aBaseFeature; ///< use base feature to store all constraints here /// move end arc point to start of split - fillAttribute(theBeforeFeature->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr); - createConstraint(SketchPlugin_ConstraintCoincidence::ID(), - theBeforeFeature->attribute(SketchPlugin_Arc::END_ID()), - theSplitFeature->attribute(SketchPlugin_Arc::START_ID())); } + // after split feature if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) { - if (!theBeforeFeature) { - theAfterFeature = aBaseFeature; ///< use base feature to store all constraints here - fillAttribute(theAfterFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr); + FeaturePtr aFeature; + if (!theBaseFeature.get()) { + aFeature = aBaseFeature; ///< use base feature to store all constraints here + fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr); } else - theAfterFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); + aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); createConstraint(SketchPlugin_ConstraintCoincidence::ID(), theSplitFeature->attribute(SketchPlugin_Arc::END_ID()), - theAfterFeature->attribute(SketchPlugin_Arc::START_ID())); + aFeature->attribute(SketchPlugin_Arc::START_ID())); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeature->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeature->attribute(SketchPlugin_Arc::END_ID()))); + + if (!theBaseFeature.get()) + theBaseFeature = aFeature; + else + theAfterFeature = aFeature; + } + else + thePoints.insert(std::dynamic_pointer_cast + (theSplitFeature->attribute(SketchPlugin_Arc::END_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 (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + /// move end arc point to start of split + fillAttribute(theBaseFeature->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr); + createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeature->attribute(SketchPlugin_Arc::END_ID()), + theSplitFeature->attribute(SketchPlugin_Arc::START_ID())); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeature->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeature->attribute(SketchPlugin_Arc::END_ID()))); } + else + thePoints.insert(std::dynamic_pointer_cast + (theSplitFeature->attribute(SketchPlugin_Arc::START_ID()))); // additional constraints between split and base features createConstraint(SketchPlugin_ConstraintEqual::ID(), getFeatureResult(aBaseFeature), getFeatureResult(theSplitFeature)); createConstraint(SketchPlugin_ConstraintTangent::ID(), getFeatureResult(theSplitFeature), getFeatureResult(aBaseFeature)); - if (theAfterFeature.get() && theAfterFeature != aBaseFeature) { + if (theAfterFeature.get()) { createConstraint(SketchPlugin_ConstraintEqual::ID(), getFeatureResult(aBaseFeature), getFeatureResult(theAfterFeature)); createConstraint(SketchPlugin_ConstraintTangent::ID(), getFeatureResult(theSplitFeature), @@ -974,10 +553,10 @@ void SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstr aRefAttr->setObject(theSecondObject); } -std::shared_ptr SketchPlugin_ConstraintSplit::getFeatureResult( +std::shared_ptr SketchPlugin_ConstraintSplit::getFeatureResult( const std::shared_ptr& theFeature) { - std::shared_ptr aResult; + std::shared_ptr aResult; std::string aFeatureKind = theFeature->getKind(); if (aFeatureKind == SketchPlugin_Line::ID()) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.h b/src/SketchPlugin/SketchPlugin_ConstraintSplit.h index b083ff2ad..e4f456514 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.h +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.h @@ -13,6 +13,9 @@ class GeomDataAPI_Point2D; class ModelAPI_Feature; +class ModelAPI_Result; + +typedef std::pair > IdToPointPair; /** \class SketchPlugin_ConstraintSplit * \ingroup Plugins @@ -53,10 +56,6 @@ class SketchPlugin_ConstraintSplit : public SketchPlugin_ConstraintBase /// \brief Request for initialization of data model of the feature: adding all attributes SKETCHPLUGIN_EXPORT virtual void initAttributes(); - /// Called on change of any argument-attribute of this object - /// \param theID identifier of changed attribute - SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); - /// Returns the AIS preview //SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); @@ -96,13 +95,42 @@ private: // const std::shared_ptr& theStartPointAttr, // const std::shared_ptr& theEndPointAttr); + /// Obtains those constraints of the feature that should be modified. output maps contain + /// point of coincidence and attribute id to be modified after split + /// \param theFeaturesToDelete [out] constrains that will be deleted after split + /// \param theTangentFeatures [out] tangent feature to be connected to new feature + /// \param theCoincidenceToFeature [out] coincidence to feature to be connected to new feature + /// \param theCoincidenceToPoint [out] coincidence to point be connected to new feature + void getConstraints(std::set>& theFeaturesToDelete, + std::map, IdToPointPair>& theTangentFeatures, + std::map, IdToPointPair>& theCoincidenceToFeature, + std::map, IdToPointPair>& theCoincidenceToPoint); + + /// Obtains those constraints of the feature that should be modified + /// \param theSplitFeature a result split feature + /// \param theBaseFeature a modified base feature + /// \param theAfterFeature an additional created feature if source segement contain three parts + /// \param theFeaturesToDelete [out] constrains that will be deleted after split + /// \param theTangentFeatures [out] tangent feature to be connected to new feature + /// \param theCoincidenceToFeature [out] coincidence to feature to be connected to new feature + /// \param theCoincidenceToPoint [out] coincidence to point be connected to new feature + /*void setConstraints(const FeaturePtr& theSplitFeature, + const FeaturePtr& theBaseFeature, + const FeaturePtr& theAfterFeature, + const std::set>& theFeaturesToDelete, + const std::map, IdToPointPair>& theTangentFeatures, + const std::map, IdToPointPair>& theCoincidenceToFeature, + const std::map, IdToPointPair>& theCoincidenceToPoint);*/ + /// 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 void splitArc(std::shared_ptr& theSplitFeature, std::shared_ptr& theBeforeFeature, - std::shared_ptr& theAfterFeature); + std::shared_ptr& theAfterFeature, + std::set >& thePoints); /// 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 @@ -149,7 +177,7 @@ private: /// 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( + std::shared_ptr getFeatureResult( const std::shared_ptr& theFeature); private: //std::set myNewPoints; ///< set of new points diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 8f4c1fc1d..98c74cb2e 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -110,44 +110,9 @@ bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribut static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2) { - FeaturePtr aConstrFeature; - std::list anAttrList; - if (theFeature1->getKind() == SketchPlugin_Circle::ID() || - theFeature2->getKind() == SketchPlugin_Circle::ID()) - return false; - if (theFeature2->getKind() == SketchPlugin_Line::ID()) { - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID())); - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID())); - } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) { - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID())); - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID())); - } - - const std::set& aRefsList = theFeature1->data()->refsToMe(); - std::set::const_iterator aRefIt = aRefsList.begin(); - for (; aRefIt != aRefsList.end(); ++aRefIt) { - aConstrFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); - if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) - continue; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); - AttributePtr anAttr = aRefAttr->attr(); - if (anAttr->id() == SketchPlugin_Arc::CENTER_ID()) - continue; - - anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()); - if (anAttr == *aRefIt) - anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()); - - aRefAttr = std::dynamic_pointer_cast(anAttr); - if (!aRefAttr) - continue; - anAttr = aRefAttr->attr(); - for (std::list::const_iterator anIt = anAttrList.begin(); - anIt != anAttrList.end(); ++anIt) - if (*anIt == anAttr) - return true; - } - return false; + FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature + (theFeature1, theFeature2); + return aCoincidenceFeature.get(); } bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, -- 2.39.2