X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_ConstraintSplit.cpp;h=ccf819ab626e340bb18825946e1a40a6387a9e3d;hb=8f060aedd5949990421a96e3b4086f43efa13d24;hp=a98724cfa1c5c7647f2c39749b74a88761d69bf6;hpb=15111f4cbb13a94699c54f152ce308820e8f24dc;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index a98724cfa..ccf819ab6 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -1,25 +1,25 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> // File: SketchPlugin_ConstraintSplit.cpp -// Created: 17 Jul 2016 +// Created: 25 Aug 2016 // Author: Natalia ERMOLAEVA #include "SketchPlugin_ConstraintSplit.h" -//#include -//#include -//#include +#include #include -//#include +#include #include -//#include +#include + #include #include -//#include #include +#include #include #include +#include #include #include @@ -28,56 +28,29 @@ #include #include #include +#include +#include +#include +#include -//#include #include -//#include -//#include -// -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -// +#include +#include +#include + +#include #include -// -//#include -// -//const double tolerance = 1.e-7; -//const double paramTolerance = 1.e-4; - -///// \brief Attract specified point on theNewArc to the attribute of theFeature -//static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, -// FeaturePtr theFeature, const std::string& theFeatureAttribute); -// -///// \brief Calculates center of fillet arc and coordinates of tangency points -//static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, -// double theRadius, bool theNotInversed[2], -// std::shared_ptr& theCenter, -// std::shared_ptr& theTangentA, -// std::shared_ptr& theTangentB); -// -///// Get point on 1/3 length of edge from fillet point -//static void getPointOnEdge(const FeaturePtr theFeature, -// const std::shared_ptr theFilletPoint, -// std::shared_ptr& thePoint); -// -///// Get distance from point to feature -//static double getProjectionDistance(const FeaturePtr theFeature, -// const std::shared_ptr thePoint); -// -///// Get coincide edges for fillet -//static std::set getCoincides(const FeaturePtr& theConstraintCoincidence); + +#include + +//#define DEBUG_SPLIT +#ifdef DEBUG_SPLIT +#include +#endif + +static const double PI = 3.141592653589793238463; SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit() -//: myListOfPointsChangedInCode(false), -// myRadiusChangedByUser(false), -// myRadiusChangedInCode(false), -// myRadiusInitialized(false) { } @@ -86,9 +59,6 @@ void SketchPlugin_ConstraintSplit::initAttributes() data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); - - //data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId()); - //data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttrList::typeId()); } void SketchPlugin_ConstraintSplit::execute() @@ -102,10 +72,12 @@ void SketchPlugin_ConstraintSplit::execute() setError("Error: Base object is not initialized."); return; } - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aFirstPointAttr.get() || !aFirstPointAttr->isInitialized() || - !aSecondPointAttr.get() || !aSecondPointAttr->isInitialized()) { + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() || + !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) { setError("Error: Sub-shape is not initialized."); return; } @@ -117,720 +89,806 @@ void SketchPlugin_ConstraintSplit::execute() Events_Loop::loop()->setFlushed(anUpdateEvent, false); + // Find feature constraints FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - std::string aFeatureKind = aBaseFeature->getKind(); - FeaturePtr aSplitFeature, aBeforeFeature, anAfterFeature; - /*if (aFeatureKind == SketchPlugin_Line::ID()) - splitLine(aSplitFeature, anOtherFeatures); - else*/ if (aFeatureKind == SketchPlugin_Arc::ID()) - splitArc(aSplitFeature, aBeforeFeature, anAfterFeature); - /*if (aFeatureKind == SketchPlugin_Circle::ID()) - splitCircle(aSplitFeature, anOtherFeatures); - FeaturePtr aSplitFeature; - std::set anOtherFeatures;*/ + ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + std::set aFeaturesToDelete, aFeaturesToUpdate; - // Send events to update the sub-features by the solver. - if(isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); + std::map aTangentFeatures; + std::map aCoincidenceToFeature; + getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature); + + std::map > aBaseRefAttributes; + std::list aRefsToFeature; + getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature); + + std::map aBasePointModifiedAttributes; + +#ifdef DEBUG_SPLIT + std::cout << std::endl; + std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl; + std::cout << std::endl; + + SketchPlugin_Sketch* aSketch = sketch(); + std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl; + for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) { + std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl; } -} -void SketchPlugin_ConstraintSplit::attributeChanged(const std::string& theID) -{ -/* if(theID == SketchPlugin_Constraint::ENTITY_A()) { - if(myListOfPointsChangedInCode) { - return; + std::cout << std::endl; + std::cout << "---- IN PARAMETERS ----" << std::endl; + std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl; + std::cout << std::endl; + + if (!aCoincidenceToFeature.empty()) { + std::cout << "Coincidences to base feature[" << + aCoincidenceToFeature.size() << "]: " << std::endl; + std::map::const_iterator anIt = aCoincidenceToFeature.begin(), + aLast = aCoincidenceToFeature.end(); + for (int i = 1; anIt != aLast; anIt++, i++) { + FeaturePtr aFeature = (*anIt).first; + std::string anAttributeId = (*anIt).second.first; + std::shared_ptr aPointAttr = (*anIt).second.second; + + std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl; + std::cout << " -Attribute to correct:" << anAttributeId << std::endl; + std::cout << " -Point attribute:" << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; } + } - // 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 (!aTangentFeatures.empty()) { + std::cout << std::endl; + std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl; + std::map::const_iterator anIt = aTangentFeatures.begin(), + aLast = aTangentFeatures.end(); + for (int i = 1; anIt != aLast; anIt++, i++) { + FeaturePtr aFeature = (*anIt).first; + std::string anAttributeId = (*anIt).second.first; + std::shared_ptr aPointAttr = (*anIt).second.second; + + std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl; + std::cout << " -Attribute to correct:" << anAttributeId << std::endl; + std::cout << " -Point attribute:" << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; } + } - // 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; - } + std::map >::const_iterator + aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end(); + std::cout << std::endl << "References to attributes of base feature [" << + aBaseRefAttributes.size() << "]" << std::endl; + for (; aRefIt != aRefLast; aRefIt++) { + AttributePtr aBaseAttr = aRefIt->first; + std::list aRefAttributes = aRefIt->second; + std::string aRefsInfo; + std::list::const_iterator aRefAttrIt = aRefAttributes.begin(), + aRefAttrLast = aRefAttributes.end(); + for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) { + if (!aRefsInfo.empty()) + aRefsInfo.append(","); + AttributePtr aRAttr = *aRefAttrIt; + aRefsInfo.append(aRAttr->id()); + FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner()); + aRefsInfo.append("(" + aRFeature->name() + ") "); + } + std::shared_ptr aPointAttr = + std::dynamic_pointer_cast(aBaseAttr); + std::cout << aPointAttr->id().c_str() << + ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl; + } + std::cout << std::endl; + std::cout << std::endl << "References to base feature [" << + aRefsToFeature.size() << "]" << std::endl; + std::list::const_iterator aRefAttrIt = aRefsToFeature.begin(), + aRefAttrLast = aRefsToFeature.end(); + std::string aRefsInfo; + for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) { + if (!aRefsInfo.empty()) + aRefsInfo.append(","); + AttributePtr aRAttr = *aRefAttrIt; + aRefsInfo.append(aRAttr->id()); + FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner()); + aRefsInfo.append("(" + aRFeature->name() + ") "); + } + std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl; - // 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; - } - } - } - } + std::cout << std::endl; + std::cout << "---- SPLIT ----" << std::endl; + std::cout << std::endl; +#endif - if(!aConstraintCoincidence.get()) { - myNewPoints.clear(); - setError("Error: No coincident edges at one of the selected points."); - return; - } + std::string aFeatureKind = aBaseFeature->getKind(); + FeaturePtr aSplitFeature, anAfterFeature; + std::set aFurtherCoincidences; + std::set aCreatedFeatures; + std::set> aModifiedAttributes; + if (aFeatureKind == SketchPlugin_Line::ID()) + splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, + aModifiedAttributes); + else if (aFeatureKind == SketchPlugin_Arc::ID()) + splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, + aModifiedAttributes); + if (aFeatureKind == SketchPlugin_Circle::ID()) { + FeaturePtr aCircleFeature = aBaseFeature; + splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, + aCreatedFeatures, aModifiedAttributes); + + updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature); + + AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()); + aFeaturesToDelete.insert(aCircleFeature); + // as circle is removed, temporary fill this attribute*/ + aBaseObjectAttr->setObject(ResultPtr()); + } - // 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; - } +#ifdef DEBUG_SPLIT + std::cout << "---- OUT PARAMETERS ----" << std::endl; + std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl; + std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl; + std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl; + std::cout << std::endl; + + std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl; + std::set::const_iterator aFIt = aCreatedFeatures.begin(), + aFLast = aCreatedFeatures.end(); + for (; aFIt != aFLast; aFIt++) { + std::cout << getFeatureInfo(*aFIt) << std::endl; + } + std::cout << std::endl; + + std::cout << "Attributes for further Coincidences:" << std::endl; + std::set::const_iterator anIt = aFurtherCoincidences.begin(), + aLast = aFurtherCoincidences.end(); + for (; anIt != aLast; anIt++) { + AttributePtr anAttribute = *anIt; + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner()); + std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) + << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl; + } - if(aCoincides.size() != 2) { - myNewPoints.clear(); - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; - } + std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl; + std::set >::const_iterator + aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end(); + std::string aResInfo; + for (; aPIt != aPLast; aPIt++) { + if (!aResInfo.empty()) + aResInfo += "\n"; - // 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::pair aPair = *aPIt; - // Set new default radius if it was not changed by user. - if(!myRadiusChangedByUser) { - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(aMinimumRadius); - myRadiusChangedInCode = false; - } + AttributePtr anAttr = aPair.first; + aResInfo.append(anAttr->id()); + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner()); + aResInfo.append("(" + aFeature->name() + ") "); - } else if(theID == SketchPlugin_Constraint::VALUE()) { - if(myRadiusInitialized && !myRadiusChangedInCode) { - myRadiusChangedByUser = true; - } - if(!myRadiusInitialized) { - myRadiusInitialized = true; - } + aResInfo.append(" - is modified to - "); + + anAttr = aPair.second; + aResInfo.append(anAttr->id()); + aFeature = ModelAPI_Feature::feature(anAttr->owner()); + aResInfo.append("(" + aFeature->name() + ") "); } -*/ -} + std::cout << aResInfo << std::endl; +#endif + + std::set aFeatureResults; + aFeatureResults.insert(getFeatureResult(aBaseFeature)); + if (anAfterFeature.get() && anAfterFeature != aBaseFeature) + aFeatureResults.insert(getFeatureResult(anAfterFeature)); + + // coincidence to feature + updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences, + aFeatureResults, aSplitFeature); + // tangency + updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences); + + updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes); + + // delete constraints +#ifdef DEBUG_SPLIT + std::cout << "remove features and references:" << std::endl; + std::set::const_iterator aDIt = aFeaturesToDelete.begin(), + aDLast = aFeaturesToDelete.end(); + for (; aDIt != aDLast; aDIt++) { + std::cout << getFeatureInfo(*aDIt, false) << std::endl; + std::cout << std::endl; + } +#endif + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete); + +#ifdef DEBUG_SPLIT + std::cout << "update features after split:" << std::endl; + std::set::const_iterator anUIt = aFeaturesToUpdate.begin(), + anULast = aFeaturesToUpdate.end(); + for (; anUIt != anULast; anUIt++) { + std::cout << getFeatureInfo(*anUIt, false) << std::endl; + std::cout << std::endl; + } +#endif + updateFeaturesAfterSplit(aFeaturesToUpdate); -//AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) -//{ -// if (!sketch()) -// return thePrevious; -// -// AISObjectPtr anAIS = thePrevious; -// /// TODO: Equal constraint presentation should be put here -// return anAIS; -//} + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } + +#ifdef DEBUG_SPLIT + std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl; + for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) { + std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl; + } +#endif +} 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) +AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) { - 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); + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::VALUE())); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr( + data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr( + data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + + if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() && + aFirstPointAttrOfSplit->isInitialized() && + aSecondPointAttrOfSplit->isInitialized()) { + + ResultPtr aResult = getFeatureResult(aBaseFeature); + GeomShapePtr aBaseShape = aResult->shape(); + std::list > aPoints; + + std::shared_ptr aStartPnt2d = aFirstPointAttrOfSplit->pnt(); + std::shared_ptr aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y()); + aPoints.push_back(aStartPoint); + + std::shared_ptr aSecondPnt2d = aSecondPointAttrOfSplit->pnt(); + std::shared_ptr aSecondPoint = + sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y()); + aPoints.push_back(aSecondPoint); + + std::set > aSplitShapes; + + GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes); + std::shared_ptr aShape = + GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes); + + AISObjectPtr anAIS = thePrevious; + if (aShape) { + if (!anAIS) + anAIS = AISObjectPtr(new GeomAPI_AISObject); + anAIS->createShape(aShape); + anAIS->setWidth(5); + std::vector aColor; + aColor = Config_PropManager::color("Visualization", "sketch_entity_color", + SKETCH_ENTITY_COLOR); + anAIS->setColor(aColor[0], aColor[1], aColor[2]); } + return anAIS; } + return AISObjectPtr(); } -/// \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 SketchPlugin_ConstraintSplit::getPointOfRefAttr( + const AttributePtr& theAttribute) { - 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); + AttributePoint2DPtr aPointAttribute; + + if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + if (aRefAttr.get() && aRefAttr->isInitialized()) { + AttributePtr anAttribute = aRefAttr->attr(); + if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId()) + aPointAttribute = std::dynamic_pointer_cast(anAttribute); } } + return aPointAttribute; } -/// \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) +void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature, + AttributePoint2DPtr& theStartPointAttr, + AttributePoint2DPtr& theEndPointAttr) { - 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); - } + std::string aFeatureKind = theFeature->getKind(); + std::string aStartAttributeName, anEndAttributeName; + if (aFeatureKind == SketchPlugin_Line::ID()) { + aStartAttributeName = SketchPlugin_Line::START_ID(); + anEndAttributeName = SketchPlugin_Line::END_ID(); + } + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + aStartAttributeName = SketchPlugin_Arc::START_ID(); + anEndAttributeName = SketchPlugin_Arc::END_ID(); + } + if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) { + theStartPointAttr = std::dynamic_pointer_cast( + theFeature->attribute(aStartAttributeName)); + theEndPointAttr = std::dynamic_pointer_cast( + theFeature->attribute(anEndAttributeName)); } } -void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], - std::shared_ptr& theCenter, - std::shared_ptr& theTangentA, - std::shared_ptr& theTangentB) +void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeaturesToDelete, + std::set& theFeaturesToUpdate, + std::map& theTangentFeatures, + std::map& theCoincidenceToFeature) { - 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())); - } + std::shared_ptr aData = data(); - // 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; + // 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); + + std::set aRefsList = aBaseFeatureResult->data()->refsToMe(); + std::set aFRefsList = aBaseFeature->data()->refsToMe(); + aRefsList.insert(aFRefsList.begin(), aFRefsList.end()); + + 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_ConstraintLength::ID()) + theFeaturesToUpdate.insert(aRefFeature); + else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) { + if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion + /// until tangency between arc and line is implemented + theFeaturesToDelete.insert(aRefFeature); + 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)); + // get the point not lying on the splitting feature + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i)); + if (!aRefAttr || aRefAttr->isObject()) + continue; + AttributePoint2DPtr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (!aPoint) + continue; + if (aPoint->owner() != aBaseFeature) { + aTangentPoint = aPoint; + break; + } + } + } + if (aTangentPoint.get()) { + FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1); + std::string anAttributeToBeModified = aFeature1 == aBaseFeature + ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B(); + theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint); + } + else /// there is not coincident point between tangent constraint + theFeaturesToDelete.insert(aRefFeature); } - //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; + 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 == aBaseFeature; + anAttributeToBeModified = anAttrA->id(); + if (!isToFeature) { + aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object()) + : FeaturePtr(); + isToFeature = aFeature.get() && aFeature == aBaseFeature; + anAttributeToBeModified = anAttrB->id(); + } + 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 == aBaseFeature) { + anAttribute = anAttrB->attr(); + anAttributeToBeModified = anAttrA->id(); + } + } + } + if (!anAttribute.get() && !anAttrB->isObject()) { + AttributePtr aCurAttribute = anAttrB->attr(); + if (aCurAttribute.get()) { + FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner()); + if (aCurFeature.get() && aCurFeature == aBaseFeature) { + anAttribute = anAttrA->attr(); + anAttributeToBeModified = anAttrB->id(); + } + } + } + if (anAttribute.get()) + aCoincidentPoint = std::dynamic_pointer_cast(anAttribute); + } + if (aCoincidentPoint.get() && isToFeature) + theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified, + aCoincidentPoint); } } } -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; +void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature, + std::map >& theRefs, + std::list& theRefsToFeature) +{ + theRefs.clear(); + + std::list aPointAttributes = + theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::set aPointAttributesSet; + + std::list::const_iterator aPIt = + aPointAttributes.begin(), aPLast = aPointAttributes.end(); + for (; aPIt != aPLast; aPIt++) + aPointAttributesSet.insert(*aPIt); + + std::set aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe(); + std::set aFRefsList = theFeature->data()->refsToMe(); + aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end()); + + std::set::const_iterator aIt; + for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) { + AttributePtr anAttr = (*aIt); + FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner()); + if (anAttrFeature.get() != this && + anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttr); + if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes + AttributePtr anAttrInRef = aRefAttr->attr(); + if (anAttrInRef.get() && + aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) { + if (theRefs.find(anAttrInRef) != theRefs.end()) + theRefs[anAttrInRef].push_back(aRefAttr); + else { + std::list anAttrList; + anAttrList.push_back(aRefAttr); + theRefs[anAttrInRef] = anAttrList; + } + } + } + else { /// find attributes referenced to feature itself + theRefsToFeature.push_back(anAttr); + } } - double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; - aCirc->D0(aPntParameter, thePoint); } } -double getProjectionDistance(const FeaturePtr theFeature, - const std::shared_ptr thePoint) +void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature( + const std::map, IdToPointPair>& theCoincidenceToFeature, + const std::set >& theFurtherCoincidences, + const std::set& theFeatureResults, + const FeaturePtr& theSplitFeature) { - 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); - } - return -1; -} + if (theCoincidenceToFeature.empty()) + return; -std::set getCoincides(const FeaturePtr& theConstraintCoincidence) -{ - 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; + // we should build coincidence constraints to end of the split feature + std::set > aNewCoincidencesToSplitFeature; + AttributePoint2DPtr aStartPointAttr, anEndPointAttr; + getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr); + if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end()) + aNewCoincidencesToSplitFeature.insert(aStartPointAttr); + if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end()) + aNewCoincidencesToSplitFeature.insert(anEndPointAttr); + + std::map::const_iterator aCIt = theCoincidenceToFeature.begin(), + aCLast = theCoincidenceToFeature.end(); +#ifdef DEBUG_SPLIT + std::cout << std::endl; + std::cout << "Coincidences to feature(modified):"<< std::endl; +#endif + for (; aCIt != aCLast; aCIt++) { + FeaturePtr aCoincFeature = aCIt->first; + std::string anAttributeId = aCIt->second.first; + AttributePoint2DPtr aCoincPoint = aCIt->second.second; + std::set::const_iterator aFCIt = theFurtherCoincidences.begin(), + aFCLast = theFurtherCoincidences.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; + } + if (aFeaturePointAttribute.get()) { + aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr()); + aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute); + // create new coincidences to split feature points + std::set::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(), + aSFLast = aNewCoincidencesToSplitFeature.end(); + for (; aSFIt != aSFLast; aSFIt++) { + AttributePoint2DPtr aSFAttribute = *aSFIt; + if (aCoincPnt->isEqual(aSFAttribute->pnt())) { + std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A(); + if (anAttributeId == SketchPlugin_Constraint::ENTITY_A()) + aSecondAttribute = SketchPlugin_Constraint::ENTITY_B(); + createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr()); + } } - aNewSetOfCoincides.insert(*anIt); } - } - aCoincides = aNewSetOfCoincides; + else { + /// find feature by shape intersected the point + ResultPtr aResultForCoincidence = *(theFeatureResults.begin()); + + if (theFeatureResults.size() > 1) { // try to find point on additional feature + ResultPtr anAddtionalResult = *(theFeatureResults.begin()++); + GeomShapePtr aShape = anAddtionalResult->shape(); - // 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); + std::shared_ptr aPnt2d = aCoincPoint->pnt(); + std::shared_ptr aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y()); + + std::shared_ptr aProjectedPoint; + if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint)) + aResultForCoincidence = anAddtionalResult; } + aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence); } - aCoincides = aNewSetOfCoincides; +#ifdef DEBUG_SPLIT + std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl; +#endif } +} - return aCoincides; +void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature( + const std::map, IdToPointPair>& theTangentFeatures, + const std::set >& theFurtherCoincidences) +{ + if (theTangentFeatures.empty()) + return; + + std::map::const_iterator aTIt = theTangentFeatures.begin(), + aTLast = theTangentFeatures.end(); +#ifdef DEBUG_SPLIT + std::cout << std::endl; + std::cout << "Tangencies to feature(modified):"<< std::endl; +#endif + for (; aTIt != aTLast; aTIt++) { + FeaturePtr aTangentFeature = aTIt->first; + std::string anAttributeId = aTIt->second.first; + AttributePoint2DPtr aTangentPoint = aTIt->second.second; + std::set::const_iterator aFCIt = theFurtherCoincidences.begin(), + aFCLast = theFurtherCoincidences.end(); + std::shared_ptr aCoincPnt = aTangentPoint->pnt(); + AttributePoint2DPtr aFeaturePointAttribute; + /// here we rely on created coincidence between further coincidence point and tangent result + for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) { + AttributePoint2DPtr aFCAttribute = *aFCIt; + if (aCoincPnt->isEqual(aFCAttribute->pnt())) + aFeaturePointAttribute = aFCAttribute; + } + if (aFeaturePointAttribute.get()) { + FeaturePtr aFeature = + std::dynamic_pointer_cast(aFeaturePointAttribute->owner()); + aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature)); + } +#ifdef DEBUG_SPLIT + std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl; +#endif + } } -*/ -std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRefAttr( - const AttributePtr& theAttribute) +void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints( + const ResultPtr& theFeatureBaseResult, + const std::list& theRefsToFeature) { - AttributePoint2DPtr aPointAttribute; + std::list::const_iterator anIt = theRefsToFeature.begin(), + aLast = theRefsToFeature.end(); + for (; anIt != aLast; anIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIt); + if (aRefAttr.get()) + aRefAttr->setObject(theFeatureBaseResult); + } +} - if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); - if (aRefAttr.get() && aRefAttr->isInitialized()) { - AttributePtr anAttribute = aRefAttr->attr(); - if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId()) - aPointAttribute = std::dynamic_pointer_cast(anAttribute); +void SketchPlugin_ConstraintSplit::updateRefAttConstraints( + const std::map >& theBaseRefAttributes, + const std::set >& theModifiedAttributes) +{ +#ifdef DEBUG_SPLIT + std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl; +#endif + + std::set >::const_iterator + anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end(); + for (; anIt != aLast; anIt++) { + AttributePtr anAttribute = anIt->first; + + /// not found in references + if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) + continue; + std::list aRefAttributes = theBaseRefAttributes.at(anAttribute); + std::list::const_iterator aRefIt = aRefAttributes.begin(), + aRLast = aRefAttributes.end(); + + AttributePtr aNewAttribute = anIt->second; + for (; aRefIt != aRLast; aRefIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); + if (aRefAttr.get()) { + aRefAttr->setAttr(aNewAttribute); +#ifdef DEBUG_SPLIT + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner()); + std::cout << " -" << getFeatureInfo(aFeature) << std::endl; +#endif + } } } - return aPointAttribute; } -void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr, - AttributePoint2DPtr& theEndPointAttr) +void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { - AttributePoint2DPtr aPointAttribute; + std::set aCreatedFeatures; + FeaturePtr aConstraintFeature; + theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature + + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch) + return; AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( data()->attribute(SketchPlugin_Constraint::VALUE())); FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); - std::string aFeatureKind = aBaseFeature->getKind(); - std::string aStartAttributeName, anEndAttributeName; - if (aFeatureKind == SketchPlugin_Line::ID()) { - aStartAttributeName = SketchPlugin_Line::START_ID(); - anEndAttributeName = SketchPlugin_Line::END_ID(); + if (aFeatureKind != SketchPlugin_Line::ID()) + return; + + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + + getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) { + setError("Error: Feature has no start and end points."); + return; } - else if (aFeatureKind == SketchPlugin_Arc::ID()) { - aStartAttributeName = SketchPlugin_Arc::START_ID(); - anEndAttributeName = SketchPlugin_Arc::END_ID(); + + arrangePointsOnLine(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 + + /// create a split feature + theSplitFeature = + createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theCreatedFeatures.insert(theSplitFeature); + + // before split feature + if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Line::START_ID()))); } - if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) { - theStartPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(aStartAttributeName)); - theEndPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(anEndAttributeName)); + 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_Line::START_ID()), aSecondPointAttrOfSplit); + aFeature->execute(); // to update result + } + else { + aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); + theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + aFeature->attribute(SketchPlugin_Line::END_ID()))); + } + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theSplitFeature->attribute(SketchPlugin_Line::END_ID()), + aFeature->attribute(SketchPlugin_Line::START_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_Line::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_Line::END_ID()))); + + if (!theBaseFeatureModified.get()) + theBaseFeatureModified = aFeature; + else + theAfterFeature = aFeature; + } + else { + thePoints.insert(std::dynamic_pointer_cast + (theSplitFeature->attribute(SketchPlugin_Line::END_ID()))); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Line::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 (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + /// move end arc point to start of split + fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), + aFirstPointAttrOfSplit); + theBaseFeatureModified->execute(); // to update result + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), + theSplitFeature->attribute(SketchPlugin_Line::START_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()))); + } + else + thePoints.insert(std::dynamic_pointer_cast + (theSplitFeature->attribute(SketchPlugin_Line::START_ID()))); + + // additional constraints between split and base features + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(theSplitFeature)); + theCreatedFeatures.insert(aConstraintFeature); + if (theAfterFeature.get()) { + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(theAfterFeature)); + theCreatedFeatures.insert(aConstraintFeature); } } void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, - FeaturePtr& theBeforeFeature, - FeaturePtr& theAfterFeature) + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { + std::set aCreatedFeatures; + FeaturePtr aConstraintFeature; + theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature + SketchPlugin_Sketch* aSketch = sketch(); if (!aSketch) return; @@ -842,72 +900,246 @@ void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, if (aFeatureKind != SketchPlugin_Arc::ID()) return; - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); - AttributePoint2DPtr aStartPointAttr, anEndPointAttr; - getFeaturePoints(aStartPointAttr, anEndPointAttr); - if (!aStartPointAttr.get() && !anEndPointAttr.get()) { + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) { setError("Error: Feature has no start and end points."); return; } - arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr); + // manually change type of arc to avoid incorrect self-constrainting of the tangent arc + aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue( + SketchPlugin_Arc::ARC_TYPE_CENTER_START_END()); + + 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 = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr); - static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); - aFactory->validate(theSplitFeature); // need to be validated to update the "Apply" state if not previewed - std::string anError = theSplitFeature->error(); + theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theCreatedFeatures.insert(theSplitFeature); - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { - theBeforeFeature = aBaseFeature; ///< use base feature to store all constraints here + // before split feature + if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Arc::START_ID()))); + } + else { + theBaseFeatureModified = 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())); } - 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); + // 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 = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); + theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + aFeature->attribute(SketchPlugin_Arc::END_ID()))); } + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theSplitFeature->attribute(SketchPlugin_Arc::END_ID()), + aFeature->attribute(SketchPlugin_Arc::START_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (aFeature->attribute(SketchPlugin_Arc::END_ID()))); + + if (!theBaseFeatureModified.get()) + theBaseFeatureModified = aFeature; else - theAfterFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); + theAfterFeature = aFeature; + } + else { + thePoints.insert(std::dynamic_pointer_cast + (theSplitFeature->attribute(SketchPlugin_Arc::END_ID()))); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + 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 (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + /// move end arc point to start of split + fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), + aFirstPointAttrOfSplit); + theBaseFeatureModified->execute(); // to update result + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), + theSplitFeature->attribute(SketchPlugin_Arc::START_ID())); + theCreatedFeatures.insert(aConstraintFeature); - createConstraint(SketchPlugin_ConstraintCoincidence::ID(), - theSplitFeature->attribute(SketchPlugin_Arc::END_ID()), - theAfterFeature->attribute(SketchPlugin_Arc::START_ID())); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->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), + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(), + getFeatureResult(aBaseFeature), getFeatureResult(theSplitFeature)); - createConstraint(SketchPlugin_ConstraintTangent::ID(), getFeatureResult(theSplitFeature), - getFeatureResult(aBaseFeature)); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(), + getFeatureResult(theSplitFeature), + getFeatureResult(aBaseFeature)); + theCreatedFeatures.insert(aConstraintFeature); if (theAfterFeature.get()) { - createConstraint(SketchPlugin_ConstraintEqual::ID(), getFeatureResult(aBaseFeature), - getFeatureResult(theAfterFeature)); - createConstraint(SketchPlugin_ConstraintTangent::ID(), getFeatureResult(theSplitFeature), - getFeatureResult(theAfterFeature)); + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(theAfterFeature)); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(), + getFeatureResult(theSplitFeature), + getFeatureResult(theAfterFeature)); + theCreatedFeatures.insert(aConstraintFeature); } } -void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr, - const AttributePoint2DPtr& theEndPointAttr, - AttributePoint2DPtr& theFirstPointAttr, - AttributePoint2DPtr& theLastPointAttr) +void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) +{ + std::set aCreatedFeatures; + FeaturePtr aConstraintFeature; + theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature + + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch) + return; + + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::VALUE())); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + std::string aFeatureKind = aBaseFeature->getKind(); + if (aFeatureKind != SketchPlugin_Circle::ID()) + return; + + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + + /// split feature + theSplitFeature = + createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + bool aSplitReversed = std::dynamic_pointer_cast(theSplitFeature)->isReversed(); + theCreatedFeatures.insert(theSplitFeature); + + /// base feature is a left part of the circle + theBaseFeatureModified = createArcFeature(aBaseFeature, + aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + std::dynamic_pointer_cast( + theBaseFeatureModified)->setReversed(!aSplitReversed); + theBaseFeatureModified->execute(); + + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), + theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID()))); + + theCreatedFeatures.insert(theBaseFeatureModified); + + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()))); + + // additional constraints between split and base features + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), + theSplitFeature->attribute(SketchPlugin_Arc::END_ID())); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()), + theSplitFeature->attribute(SketchPlugin_Arc::START_ID())); + theCreatedFeatures.insert(aConstraintFeature); + + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(), + getFeatureResult(theSplitFeature), + getFeatureResult(theBaseFeatureModified)); + theCreatedFeatures.insert(aConstraintFeature); +} + +void SketchPlugin_ConstraintSplit::arrangePointsOnLine( + const AttributePoint2DPtr& theStartPointAttr, + const AttributePoint2DPtr& theEndPointAttr, + AttributePoint2DPtr& theFirstPointAttr, + AttributePoint2DPtr& theLastPointAttr) const { - /// if first point is closer to last point, wrap first and last values + // if first point is closer to last point, swap first and last values if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) > - theEndPointAttr->pnt()->distance(theLastPointAttr->pnt())) { + theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) { AttributePoint2DPtr aTmpPoint = theFirstPointAttr; theFirstPointAttr = theLastPointAttr; theLastPointAttr = aTmpPoint; } } +void SketchPlugin_ConstraintSplit::arrangePointsOnArc( + const FeaturePtr& theArc, + const std::shared_ptr& theStartPointAttr, + const std::shared_ptr& theEndPointAttr, + std::shared_ptr& theFirstPointAttr, + std::shared_ptr& theSecondPointAttr) const +{ + static const double anAngleTol = 1.e-12; + + std::shared_ptr aCenter = std::dynamic_pointer_cast( + theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value(); + + // collect directions to each point + std::shared_ptr aStartDir( + new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + std::shared_ptr aFirstPtDir( + new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + std::shared_ptr aSecondPtDir( + new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + + // sort points by their angular values + double aFirstPtAngle = aStartDir->angle(aFirstPtDir); + double aSecondPtAngle = aStartDir->angle(aSecondPtDir); + double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI; + if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.)) + aFirstPtAngle += aPeriod; + if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.)) + aSecondPtAngle += aPeriod; + + if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) { + AttributePoint2DPtr aTmpPoint = theFirstPointAttr; + theFirstPointAttr = theSecondPointAttr; + theSecondPointAttr = aTmpPoint; + } +} + void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute, const AttributePtr& theSourceAttribute) { @@ -917,7 +1149,25 @@ void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModified theSourceAttribute); if (aModifiedAttribute.get() && aSourceAttribute.get()) - aSourceAttribute->setValue(aModifiedAttribute->pnt()); + aModifiedAttribute->setValue(aSourceAttribute->pnt()); +} + +FeaturePtr SketchPlugin_ConstraintSplit::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); + aFeature->execute(); // to obtain result + + return aFeature; } FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature, @@ -929,24 +1179,41 @@ FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theB if (!aSketch || !theBaseFeature.get()) return aFeature; - aFeature = aSketch->addFeature(theBaseFeature->getKind()); - // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated" + 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 aFeature->data()->blockSendAttributeUpdated(true); aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue( SketchPlugin_Arc::ARC_TYPE_CENTER_START_END()); + fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()), - theBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID())); + theBaseFeature->attribute(aCenterAttributeId)); fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr); fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr); + + /// 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::INVERSED_ID())->value(); + aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed); + } aFeature->data()->blockSendAttributeUpdated(false); - aFeature->execute(); + aFeature->execute(); // to obtain result return aFeature; } -void SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId, +FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId, const AttributePtr& theFirstAttribute, const AttributePtr& theSecondAttribute) { @@ -958,9 +1225,12 @@ void SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstr aRefAttr = std::dynamic_pointer_cast( aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); aRefAttr->setAttr(theSecondAttribute); + + return aConstraint; } -void SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId, +FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects( + const std::string& theConstraintId, const ObjectPtr& theFirstObject, const ObjectPtr& theSecondObject) { @@ -972,12 +1242,36 @@ void SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstr aRefAttr = std::dynamic_pointer_cast( aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); aRefAttr->setObject(theSecondObject); + + return aConstraint; +} + +void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit( + const std::set& theFeaturesToUpdate) +{ + std::set::const_iterator anIt = theFeaturesToUpdate.begin(), + aLast = theFeaturesToUpdate.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aRefFeature = std::dynamic_pointer_cast(*anIt); + std::string aRefFeatureKind = aRefFeature->getKind(); + if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) { + std::shared_ptr aLenghtFeature = + std::dynamic_pointer_cast(*anIt); + if (aLenghtFeature.get()) { + std::shared_ptr aValueAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE())); + double aValue; + if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get()) + aValueAttr->setValue(aValue); + } + } + } } -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()) @@ -990,3 +1284,85 @@ std::shared_ptr SketchPlugin_ConstraintSplit::getFeatureResult( return aResult; } +std::set > SketchPlugin_ConstraintSplit::getEdgeAttributes( + const std::shared_ptr& theFeature) +{ + std::set > anAttributes; + + std::string aFeatureKind = theFeature->getKind(); + if (aFeatureKind == SketchPlugin_Line::ID()) { + anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID())); + anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID())); + } + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID())); + anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID())); + } + else if (aFeatureKind == SketchPlugin_Circle::ID()) { + } + + return anAttributes; +} + +#ifdef _DEBUG +std::string SketchPlugin_ConstraintSplit::getFeatureInfo( + const std::shared_ptr& theFeature, + const bool isUseAttributesInfo) +{ + std::string anInfo; + if (!theFeature.get()) { + return "none"; + } + + if (theFeature->data()->isValid()) + anInfo.append(theFeature->data()->name().c_str()); + + if (isUseAttributesInfo) { + std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature, + getEdgeAttributes(theFeature)); + /// processing of feature with point 2d attributes, like line, arc, circle + if (!aPointsInfo.empty()) { + anInfo += ": "; + anInfo += "\n"; + anInfo += aPointsInfo; + } + else { /// process constraint coincidence, find points in ref attr attributes + std::list anAttrs = theFeature->data()->attributes( + ModelAPI_AttributeRefAttr::typeId()); + std::list::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end(); + std::string anAttributesInfo; + for(; anIt != aLast; anIt++) { + if (!anAttributesInfo.empty()) { + anAttributesInfo.append(", "); + anAttributesInfo += "\n"; + } + AttributePtr anAttr = *anIt; + std::string aValue = "not defined"; + std::string aType = anAttr->attributeType(); + if (aType == ModelAPI_AttributeRefAttr::typeId()) { + std::shared_ptr aRefAttr = + std::dynamic_pointer_cast(anAttr); + if (aRefAttr.get()) { + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + aValue = "" + getFeatureInfo(aFeature, false); + } + else { + AttributePtr anAttribute = aRefAttr->attr(); + if (anAttribute.get()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner()); + aValue = "" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) + + " [" + getFeatureInfo(aFeature, false) + "]"; + } + } + } + } + anAttributesInfo.append(" " + anAttr->id() + ": " + aValue); + } + if (!anAttributesInfo.empty()) + anInfo = anInfo + "\n" + anAttributesInfo; + } + } + return anInfo; +} +#endif