X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_ConstraintSplit.cpp;h=ccf819ab626e340bb18825946e1a40a6387a9e3d;hb=8f060aedd5949990421a96e3b4086f43efa13d24;hp=62b5385542a78518eb9042b2305f53a659b36c3b;hpb=023c72db1a0c06efe73559cc2ff37c841842823a;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index 62b538554..ccf819ab6 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -1,26 +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 @@ -29,59 +28,29 @@ #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) { } @@ -90,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() @@ -106,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; } @@ -124,83 +92,234 @@ void SketchPlugin_ConstraintSplit::execute() // Find feature constraints FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + std::set aFeaturesToDelete, aFeaturesToUpdate; - std::set aFeaturesToDelete; std::map aTangentFeatures; std::map aCoincidenceToFeature; - std::map aCoincidenceToPoint; - getConstraints(aFeaturesToDelete, aTangentFeatures, aCoincidenceToFeature, aCoincidenceToPoint); + 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; + } + + 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; + } + } + + 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; + } + } + 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; + + + std::cout << std::endl; + std::cout << "---- SPLIT ----" << std::endl; + std::cout << std::endl; +#endif std::string aFeatureKind = aBaseFeature->getKind(); FeaturePtr aSplitFeature, anAfterFeature; std::set aFurtherCoincidences; - /*if (aFeatureKind == SketchPlugin_Line::ID()) - splitLine(aSplitFeature, anOtherFeatures); - else*/ if (aFeatureKind == SketchPlugin_Arc::ID()) - splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences); - /*if (aFeatureKind == SketchPlugin_Circle::ID()) - splitCircle(aSplitFeature, anOtherFeatures); - FeaturePtr aSplitFeature; - std::set anOtherFeatures;*/ - - //setConstraints(aSplitFeature, aBaseFeature, anAfterFeature, aFeaturesToDelete, aTangentFeatures, - // aCoincidenceToFeature, aCoincidenceToPoint); - if (false) { + 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()); + } + +#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; + } + + 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"; + + std::pair aPair = *aPIt; + + AttributePtr anAttr = aPair.first; + aResInfo.append(anAttr->id()); + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner()); + aResInfo.append("(" + aFeature->name() + ") "); + + 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()) + if (anAfterFeature.get() && anAfterFeature != aBaseFeature) 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; - } - if (aFeaturePointAttribute.get()) { - aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute); - } - else { - /// find feature by shape intersected the point - ResultPtr aResultForCoincidence = *(aFeatureResults.begin()); - - if (aFeatureResults.size() > 1) { // try to find point on additional feature - ResultPtr anAddtionalResult = *(aFeatureResults.begin()++); - GeomShapePtr aShape = anAddtionalResult->shape(); + updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences, + aFeatureResults, aSplitFeature); + // tangency + updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences); - std::shared_ptr aPnt2d = aCoincPoint->pnt(); - std::shared_ptr aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y()); + updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes); - std::shared_ptr aProjectedPoint; - if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint)) - aResultForCoincidence = anAddtionalResult; - } - aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence); - } - } - // coincidence to points - // TODO - // tangency - // TODO - } // 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); + // 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 @@ -208,13 +327,64 @@ bool SketchPlugin_ConstraintSplit::isMacro() const return true; } +AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) +{ + 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(); +} + std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRefAttr( - const AttributePtr& theAttribute) + const AttributePtr& theAttribute) { AttributePoint2DPtr aPointAttribute; if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); if (aRefAttr.get() && aRefAttr->isInitialized()) { AttributePtr anAttribute = aRefAttr->attr(); if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId()) @@ -224,16 +394,11 @@ std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRef return aPointAttribute; } -void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr, +void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature, + AttributePoint2DPtr& theStartPointAttr, AttributePoint2DPtr& theEndPointAttr) { - AttributePoint2DPtr aPointAttribute; - - 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 aFeatureKind = theFeature->getKind(); std::string aStartAttributeName, anEndAttributeName; if (aFeatureKind == SketchPlugin_Line::ID()) { aStartAttributeName = SketchPlugin_Line::START_ID(); @@ -245,16 +410,16 @@ void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStar } if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) { theStartPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(aStartAttributeName)); + theFeature->attribute(aStartAttributeName)); theEndPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(anEndAttributeName)); + theFeature->attribute(anEndAttributeName)); } } void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeaturesToDelete, + std::set& theFeaturesToUpdate, std::map& theTangentFeatures, - std::map& theCoincidenceToFeature, - std::map& theCoincidenceToPoint) + std::map& theCoincidenceToFeature) { std::shared_ptr aData = data(); @@ -264,7 +429,10 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); - const std::set& aRefsList = aBaseFeatureResult->data()->refsToMe(); + 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); @@ -274,28 +442,45 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu 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 - theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented + /// 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)); - aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature); + 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_B() : SketchPlugin_Constraint::ENTITY_A(); + ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B(); theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint); } - else - theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint + else /// there is not coincident point between tangent constraint + theFeaturesToDelete.insert(aRefFeature); } } else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) { @@ -307,26 +492,27 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu 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(); + isToFeature = aFeature.get() && aFeature == aBaseFeature; + anAttributeToBeModified = anAttrA->id(); if (!isToFeature) { aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object()) : FeaturePtr(); - isToFeature = aFeature.get() && aFeature == aRefFeature; - anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_A(); + 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 == aRefFeature) { - anAttribute = anAttrA->attr(); - anAttributeToBeModified = SketchPlugin_Constraint::ENTITY_A(); + if (aCurFeature.get() && aCurFeature == aBaseFeature) { + anAttribute = anAttrB->attr(); + anAttributeToBeModified = anAttrA->id(); } } } @@ -334,53 +520,375 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu 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 (aCurFeature.get() && aCurFeature == aBaseFeature) { + anAttribute = anAttrA->attr(); + anAttributeToBeModified = anAttrB->id(); } } } 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, + if (aCoincidentPoint.get() && isToFeature) + theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified, aCoincidentPoint); + } + } +} + +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); } - 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) +void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature( + const std::map, IdToPointPair>& theCoincidenceToFeature, + const std::set >& theFurtherCoincidences, + const std::set& theFeatureResults, + const FeaturePtr& theSplitFeature) { - // coincidence to feature + if (theCoincidenceToFeature.empty()) + return; + // 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()); + } + } + } + else { + /// find feature by shape intersected the point + ResultPtr aResultForCoincidence = *(theFeatureResults.begin()); - // coincidence to points + if (theFeatureResults.size() > 1) { // try to find point on additional feature + ResultPtr anAddtionalResult = *(theFeatureResults.begin()++); + GeomShapePtr aShape = anAddtionalResult->shape(); - // tangency + std::shared_ptr aPnt2d = aCoincPoint->pnt(); + std::shared_ptr aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y()); - // delete constraints + std::shared_ptr aProjectedPoint; + if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint)) + aResultForCoincidence = anAddtionalResult; + } + aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence); + } +#ifdef DEBUG_SPLIT + std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl; +#endif + } +} -}*/ +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 + } +} + +void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints( + const ResultPtr& theFeatureBaseResult, + const std::list& theRefsToFeature) +{ + 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); + } +} + +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 + } + } + } +} + +void SketchPlugin_ConstraintSplit::splitLine(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_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; + } + + 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()))); + } + 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& theBaseFeature, + FeaturePtr& theBaseFeatureModified, FeaturePtr& theAfterFeature, - std::set& thePoints) + 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; @@ -392,93 +900,201 @@ 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); // before split feature - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { - theBaseFeature = aBaseFeature; ///< use base feature to store all constraints here + 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 } // after split feature - if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) { + if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) { FeaturePtr aFeature; - if (!theBaseFeature.get()) { + if (!theBaseFeatureModified.get()) { aFeature = aBaseFeature; ///< use base feature to store all constraints here - fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr); + fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit); + aFeature->execute(); // to update result } - else - aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); - - createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + 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 - (theBaseFeature->attribute(SketchPlugin_Arc::START_ID()))); + (aFeature->attribute(SketchPlugin_Arc::START_ID()))); thePoints.insert(std::dynamic_pointer_cast - (theBaseFeature->attribute(SketchPlugin_Arc::END_ID()))); + (aFeature->attribute(SketchPlugin_Arc::END_ID()))); - if (!theBaseFeature.get()) - theBaseFeature = aFeature; + if (!theBaseFeatureModified.get()) + theBaseFeatureModified = aFeature; else theAfterFeature = aFeature; } - else + 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 (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->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()), + 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); + thePoints.insert(std::dynamic_pointer_cast - (theBaseFeature->attribute(SketchPlugin_Arc::START_ID()))); + (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()))); thePoints.insert(std::dynamic_pointer_cast - (theBaseFeature->attribute(SketchPlugin_Arc::END_ID()))); + (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()) > theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) { AttributePoint2DPtr aTmpPoint = theFirstPointAttr; @@ -487,6 +1103,43 @@ void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theS } } +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) { @@ -499,6 +1152,24 @@ void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModified 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, const AttributePtr& theFirstPointAttr, const AttributePtr& theSecondPointAttr) @@ -508,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) { @@ -537,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) { @@ -551,6 +1242,30 @@ 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( @@ -569,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