X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_ConstraintSplit.cpp;h=ccf819ab626e340bb18825946e1a40a6387a9e3d;hb=8f060aedd5949990421a96e3b4086f43efa13d24;hp=5c0db4bda179cbc3f71cb2b0ac4f64584b380a9d;hpb=a69d83f22139a1c35e6c2ef45f465dfa40841233;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index 5c0db4bda..ccf819ab6 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -1,75 +1,56 @@ // 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 +#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 -//#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) { } @@ -78,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() @@ -89,1112 +67,1302 @@ void SketchPlugin_ConstraintSplit::execute() // Check the base objects are initialized. AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + aData->attribute(SketchPlugin_Constraint::VALUE())); if(!aBaseObjectAttr->isInitialized()) { setError("Error: Base object is not initialized."); return; } - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aLastPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aFirstPointAttr.get() || !aFirstPointAttr->isInitialized() || - !aLastPointAttr.get() || !aLastPointAttr->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; } - AttributePoint2DPtr aStartPointAttr = getFeaturePoint(true); - AttributePoint2DPtr anEndPointAttr = getFeaturePoint(false); - if (!aStartPointAttr.get() && !anEndPointAttr.get()) { - setError("Error: Circle is not processed."); /// TODO - return; - } - - /// if first point is closer to last point, wrap first and last values - if (aStartPointAttr->pnt()->distance(aFirstPointAttr->pnt()) > - anEndPointAttr->pnt()->distance(aLastPointAttr->pnt())) { - AttributePoint2DPtr aTmpPoint = aFirstPointAttr; - aFirstPointAttr = aLastPointAttr; - aLastPointAttr = aTmpPoint; - } - FeaturePtr aSplitFeature = createFeature(aFirstPointAttr, aLastPointAttr); - - std::set aLeftFeatures; - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) - aLeftFeatures.insert(createFeature(aStartPointAttr, aFirstPointAttr)); - if (!aLastPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) - aLeftFeatures.insert(createFeature(aLastPointAttr, anEndPointAttr)); - - /* - // Get fillet radius. - double aFilletRadius = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::VALUE()))->value(); - // Wait all constraints being created, then send update events static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); if (isUpdateFlushed) Events_Loop::loop()->setFlushed(anUpdateEvent, false); - for(std::set::iterator aPointsIter = myNewPoints.begin(); - aPointsIter != myNewPoints.end(); - ++aPointsIter) { - AttributePtr aPointAttr = *aPointsIter; - std::shared_ptr aFilletPoint2d = std::dynamic_pointer_cast(aPointAttr); - if(!aFilletPoint2d.get()) { - setError("Error: One of the selected points is empty."); - return; - } - std::shared_ptr aFilletPnt2d = aFilletPoint2d->pnt(); - - // Obtain base lines for fillet. - bool anIsNeedNewObjects = true; - FilletFeatures aFilletFeatures; - std::map::iterator aPrevPointsIter = myPointFeaturesMap.find(aPointAttr); - if(aPrevPointsIter != myPointFeaturesMap.end()) { - anIsNeedNewObjects = false; - aFilletFeatures = aPrevPointsIter->second; - } - FeaturePtr aBaseEdgeA, aBaseEdgeB; - if(!anIsNeedNewObjects) { - aBaseEdgeA = aFilletFeatures.baseEdgesState.front().first; - aBaseEdgeB = aFilletFeatures.baseEdgesState.back().first; - } else { - // Obtain constraint coincidence for the fillet point. - FeaturePtr aConstraintCoincidence; - const std::set& aRefsList = aFilletPoint2d->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() && !anAttrRefA->isObject()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(aFilletPoint2d == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - if(anAttrRefB.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aFilletPoint2d == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - } - } - if(!aConstraintCoincidence.get()) { - setError("Error: No coincident edges at one of the selected points."); - return; - } + // Find feature constraints + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + std::set aFeaturesToDelete, aFeaturesToUpdate; - // Get coincide edges. - std::set aCoincides = getCoincides(aConstraintCoincidence); - if(aCoincides.size() != 2) { - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; - } + std::map aTangentFeatures; + std::map aCoincidenceToFeature; + getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature); - std::set::iterator aLinesIt = aCoincides.begin(); - aBaseEdgeA = *aLinesIt++; - aBaseEdgeB = *aLinesIt; + std::map > aBaseRefAttributes; + std::list aRefsToFeature; + getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature); - std::pair aBasePairA = std::make_pair(aBaseEdgeA, aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); - std::pair aBasePairB = std::make_pair(aBaseEdgeB, aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); - aFilletFeatures.baseEdgesState.push_back(aBasePairA); - aFilletFeatures.baseEdgesState.push_back(aBasePairB); - } + std::map aBasePointModifiedAttributes; - if(!aBaseEdgeA.get() || !aBaseEdgeB.get()) { - setError("Error: One of the base edges is empty."); - return; - } +#ifdef DEBUG_SPLIT + std::cout << std::endl; + std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl; + std::cout << std::endl; - // Create new edges and arc if needed. - FeaturePtr aResultEdgeA, aResultEdgeB, aResultArc; - if(!anIsNeedNewObjects) { - // Obtain features from the list. - std::list::iterator aResultEdgesIt = aFilletFeatures.resultEdges.begin(); - aResultEdgeA = *aResultEdgesIt++; - aResultEdgeB = *aResultEdgesIt++; - aResultArc = *aResultEdgesIt; - } else { - // Copy edges and create arc. - aResultEdgeA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeA, sketch()); - aResultEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); - aResultEdgeB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeB, sketch()); - aResultEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); - aResultArc = sketch()->addFeature(SketchPlugin_Arc::ID()); - - aFilletFeatures.resultEdges.push_back(aResultEdgeA); - aFilletFeatures.resultEdges.push_back(aResultEdgeB); - aFilletFeatures.resultEdges.push_back(aResultArc); - } + 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; + } - // Calculate arc attributes - static const int aNbFeatures = 2; - FeaturePtr aBaseFeatures[aNbFeatures] = {aBaseEdgeA, aBaseEdgeB}; - FeaturePtr aResultFeatures[aNbFeatures] = {aResultEdgeA, aResultEdgeB}; - std::shared_ptr aTangentDir[aNbFeatures]; // tangent directions of the features in coincident point - bool isStart[aNbFeatures]; // indicates which point the features share - std::shared_ptr aStartEndPnt[aNbFeatures * 2]; // first pair of points relate to first feature, second pair - to second - std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features - for (int i = 0; i < aNbFeatures; i++) { - std::string aStartAttr, aEndAttr; - if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { - aStartAttr = SketchPlugin_Line::START_ID(); - aEndAttr = SketchPlugin_Line::END_ID(); - } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { - aStartAttr = SketchPlugin_Arc::START_ID(); - aEndAttr = SketchPlugin_Arc::END_ID(); - } else { // wrong argument - setError("Error: One of the points has wrong coincide feature"); - return; - } - aFeatAttributes[2*i] = aStartAttr; - aStartEndPnt[2*i] = std::dynamic_pointer_cast( - aBaseFeatures[i]->attribute(aStartAttr))->pnt(); - aFeatAttributes[2*i+1] = aEndAttr; - aStartEndPnt[2*i+1] = std::dynamic_pointer_cast( - aBaseFeatures[i]->attribute(aEndAttr))->pnt(); - } - for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) { - for (int j = 0; j < 2; j++) // loop on start-end of each feature - if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) { - isStart[aFeatInd] = (j==0); - break; - } - } - // tangent directions of the features - for (int i = 0; i < aNbFeatures; i++) { - std::shared_ptr aDir; - if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { - aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy()); - if (!isStart[i]) - aDir = aDir->multiplied(-1.0); - } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { - std::shared_ptr aCenterPoint = std::dynamic_pointer_cast( - aResultFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy(); - aDir = aDir->decreased(aCenterPoint->xy()); - - double x = aDir->x(); - double y = aDir->y(); - aDir->setX(-y); - aDir->setY(x); - if (isStart[i] == std::dynamic_pointer_cast(aBaseFeatures[i])->isReversed()) - aDir = aDir->multiplied(-1.0); - } - aTangentDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aDir)); + 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; } + } - // By default, the start point of fillet arc is connected to FeatureA, - // and the end point - to FeatureB. But when the angle between TangentDirA and - // TangentDirB greater 180 degree, the sequaence of features need to be reversed. - double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), where A and B - angles between corresponding tanget direction and the X axis - bool isReversed = cosBA > 0.0; - - // Calculate fillet arc parameters - std::shared_ptr aCenter, aTangentPntA, aTangentPntB; - calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, aFilletRadius, isStart, aCenter, aTangentPntA, aTangentPntB); - if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) { - setError("Can not create fillet with the specified parameters."); - 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; } - // update features - std::dynamic_pointer_cast( - aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->setValue(aTangentPntA->x(), aTangentPntA->y()); - aResultEdgeA->execute(); - std::dynamic_pointer_cast( - aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->setValue(aTangentPntB->x(), aTangentPntB->y()); - aResultEdgeB->execute(); - // 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 - aResultArc->data()->blockSendAttributeUpdated(true); - std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y()); - if(isReversed) { - std::shared_ptr aTmp = aTangentPntA; - aTangentPntA = aTangentPntB; - aTangentPntB = aTmp; - } - std::shared_ptr aStartPoint = std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndPoint = std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::END_ID())); - if(aStartPoint->isInitialized() && aEndPoint->isInitialized() && - (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance || - aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) { - std::dynamic_pointer_cast(aResultArc)->setReversed(false); - } - aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y()); - aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y()); - aResultArc->data()->blockSendAttributeUpdated(false); - aResultArc->execute(); - - if(anIsNeedNewObjects) { - // Create list of additional constraints: - // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc - // 1.1. coincidence - FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID())); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - int aFeatInd = isReversed ? 1 : 0; - int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1); - aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); - recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 1.2. coincidence - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID())); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aFeatInd = isReversed ? 0 : 1; - anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1); - aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); - recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 2. Fillet arc radius - //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID()); - //aRefAttr = std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - //aRefAttr->setObject(aNewArc->lastResult()); - //std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius); - //std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue( - // isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]); - //aConstraint->execute(); - //myProducedFeatures.push_back(aConstraint); - //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 3. Tangency of fillet arc and features - for (int i = 0; i < aNbFeatures; i++) { - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setObject(aResultArc->lastResult()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID(); - aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() : aResultFeatures[i]->firstResult()); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - } - // 4. Coincidence of free boundaries of base and copied features - for (int i = 0; i < aNbFeatures; i++) { - anAttrInd = 2*i + (isStart[i] ? 1 : 0); - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aFilletFeatures.resultConstraints.push_back(aConstraint); - } - // 4.1. Additional tangency constraints when the fillet is based on arcs. - // It is used to verify the created arc will be placed on a source. - for (int i = 0; i < aNbFeatures; ++i) { - if (aResultFeatures[i]->getKind() != SketchPlugin_Arc::ID()) - continue; - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setObject(aBaseFeatures[i]->lastResult()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setObject(aResultFeatures[i]->lastResult()); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - } - // 5. Tangent points should be placed on the base features - for (int i = 0; i < aNbFeatures; i++) { - anAttrInd = 2*i + (isStart[i] ? 0 : 1); - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setObject(aBaseFeatures[i]->lastResult()); - aFilletFeatures.resultConstraints.push_back(aConstraint); - } - // make base features auxiliary - aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); - aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); - - // exchange the naming IDs of newly created and old line that become auxiliary - sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA); - sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB); - - // store point and features in the map. - myPointFeaturesMap[aPointAttr] = aFilletFeatures; - } else { - // Update radius value - int aNbSubs = sketch()->numberOfSubs(); - FeaturePtr aSubFeature; - for (int aSub = 0; aSub < aNbSubs; aSub++) { - aSubFeature = sketch()->subFeature(aSub); - if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID()) - continue; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (!aRefAttr || !aRefAttr->isObject()) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - if (aFeature == aResultArc) { - AttributeDoublePtr aRadius = std::dynamic_pointer_cast( - aSubFeature->attribute(SketchPlugin_Constraint::VALUE())); - aRadius->setValue(aFilletRadius); - break; - } - } + } + + 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; + 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() && 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); // 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 } -void SketchPlugin_ConstraintSplit::attributeChanged(const std::string& theID) +bool SketchPlugin_ConstraintSplit::isMacro() const { -/* if(theID == SketchPlugin_Constraint::ENTITY_A()) { - if(myListOfPointsChangedInCode) { - return; + 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) +{ + AttributePoint2DPtr aPointAttribute; - // 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 (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; +} - // 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; - } +void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature, + AttributePoint2DPtr& theStartPointAttr, + AttributePoint2DPtr& theEndPointAttr) +{ + 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)); + } +} - // 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; - } +void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeaturesToDelete, + std::set& theFeaturesToUpdate, + std::map& theTangentFeatures, + std::map& theCoincidenceToFeature) +{ + std::shared_ptr aData = data(); - // 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; + // 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); } - - if(!aConstraintCoincidence.get()) { - myNewPoints.clear(); - setError("Error: No coincident edges at one of the selected points."); - 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); } - - // 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); + 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(); + } } - 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); + } + 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(); + } } - aNewSetOfCoincides.insert(*anIt); } + if (anAttribute.get()) + aCoincidentPoint = std::dynamic_pointer_cast(anAttribute); } - 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); + 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; } } - aCoincides = aNewSetOfCoincides; } - - if(aCoincides.size() != 2) { - myNewPoints.clear(); - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; + else { /// find attributes referenced to feature itself + theRefsToFeature.push_back(anAttr); } + } + } +} + +void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature( + const std::map, IdToPointPair>& theCoincidenceToFeature, + const std::set >& theFurtherCoincidences, + const std::set& theFeatureResults, + const FeaturePtr& theSplitFeature) +{ + if (theCoincidenceToFeature.empty()) + return; - // 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; + // 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()); - // Set new default radius if it was not changed by user. - if(!myRadiusChangedByUser) { - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(aMinimumRadius); - myRadiusChangedInCode = false; - } + if (theFeatureResults.size() > 1) { // try to find point on additional feature + ResultPtr anAddtionalResult = *(theFeatureResults.begin()++); + GeomShapePtr aShape = anAddtionalResult->shape(); - } else if(theID == SketchPlugin_Constraint::VALUE()) { - if(myRadiusInitialized && !myRadiusChangedInCode) { - myRadiusChangedByUser = true; - } - if(!myRadiusInitialized) { - myRadiusInitialized = true; + 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); } +#ifdef DEBUG_SPLIT + std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl; +#endif } -*/ } -//AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) -//{ -// if (!sketch()) -// return thePrevious; -// -// AISObjectPtr anAIS = thePrevious; -// /// TODO: Equal constraint presentation should be put here -// return anAIS; -//} - -bool SketchPlugin_ConstraintSplit::isMacro() const +void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature( + const std::map, IdToPointPair>& theTangentFeatures, + const std::set >& theFurtherCoincidences) { - return true; -} + if (theTangentFeatures.empty()) + return; -//void SketchPlugin_ConstraintSplit::clearResults() -//{ -///* // Clear auxiliary flag on initial objects. -// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); -// aPointsIter != myPointFeaturesMap.end();) { -// const FilletFeatures& aFilletFeatures = aPointsIter->second; -// std::list>::const_iterator aFeatureIt; -// for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin(); -// aFeatureIt != aFilletFeatures.baseEdgesState.cend(); -// ++aFeatureIt) { -// aFeatureIt->first->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second); -// } -// ++aPointsIter; -// } -// -// // And remove all produced features. -// DocumentPtr aDoc = sketch()->document(); -// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); -// aPointsIter != myPointFeaturesMap.end();) { -// // Remove all produced constraints. -// const FilletFeatures& aFilletFeatures = aPointsIter->second; -// std::list::const_iterator aFeatureIt; -// for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin(); -// aFeatureIt != aFilletFeatures.resultConstraints.cend(); -// ++aFeatureIt) { -// aDoc->removeFeature(*aFeatureIt); -// } -// -// // Remove all result edges. -// for(aFeatureIt = aFilletFeatures.resultEdges.cbegin(); -// aFeatureIt != aFilletFeatures.resultEdges.cend(); -// ++aFeatureIt) { -// aDoc->removeFeature(*aFeatureIt); -// } -// -// // Remove point from map. -// myPointFeaturesMap.erase(aPointsIter++); -// } -//*/ -//}; -// -// -//// ========= Auxiliary functions ================= -//void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, -// FeaturePtr theFeature, const std::string& theFeatureAttribute) -//{ -// std::shared_ptr anArcPoint = std::dynamic_pointer_cast( -// theNewArc->attribute(theNewArcAttribute))->pnt(); -// std::dynamic_pointer_cast( -// theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); -//} - -/*/// \brief Find intersections of lines shifted along normal direction -void possibleFilletCenterLineLine( - std::shared_ptr thePointA, std::shared_ptr theDirA, - std::shared_ptr thePointB, std::shared_ptr theDirB, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); - std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); - std::shared_ptr aPntA, aPntB; - double aDet = theDirA->cross(theDirB); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); - double aVX = aDirAT->xy()->dot(aPntA); - double aVY = aDirBT->xy()->dot(aPntB); - std::shared_ptr aPoint(new GeomAPI_XY( - (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, - (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); - theCenters.push_back(aPoint); + 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 } } -/// \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) +void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints( + const ResultPtr& theFeatureBaseResult, + const std::list& theRefsToFeature) { - 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); - } + 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); } } -/// \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::updateRefAttConstraints( + const std::map >& theBaseRefAttributes, + const std::set >& theModifiedAttributes) { - 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); +#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 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::splitLine(FeaturePtr& theSplitFeature, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { - 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())); + 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; } - 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())); - } + 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 + } - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], theRadius, aSuspectCenters); - double aDot = 0.0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); - theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); - if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) - continue; // incorrect position - aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); - theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); - if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) - continue; // incorrect position - // the center is found, stop searching - theCenter = *anIt; - return; - } - } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) || - (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID())) { - int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; - double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); - std::shared_ptr aDirLine = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); - std::shared_ptr aDirT = std::shared_ptr( - new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); - - std::shared_ptr aStartArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - double anArcAngle = aEndArcDir->angle(aStartArcDir); - - // get possible centers and filter them - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], anArcRadius, theRadius, aSuspectCenters); - double aDot = 0.0; - // the line is forward into the arc - double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy()); - std::shared_ptr aLineTgPoint, anArcTgPoint; - // The possible centers are ranged by their positions. - // If the point is not satisfy one of criteria, the weight is decreased with penalty. - int aBestWeight = 0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - int aWeight = 2; - aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt)); - aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot)); - // Check the point is placed on the correct arc (penalty if false) - if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc) - aWeight -= 1; - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd]))); - double aCurAngle = aCurDir->angle(aStartArcDir); - if (anArcAngle < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle)) - continue; - if (aWeight > aBestWeight) - aBestWeight = aWeight; - else if (aWeight < aBestWeight || - aStart[aLineInd]->distance(*anIt) > - aStart[aLineInd]->distance(theCenter)) // <-- take closer point - continue; - // the center is found, stop searching - theCenter = *anIt; - anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius)); - if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { - theTangentA = aLineTgPoint; - theTangentB = anArcTgPoint; - } else { - theTangentA = anArcTgPoint; - theTangentB = aLineTgPoint; - } - //return; - } - } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID()) { - double anArcRadius[aNbFeatures]; - double anArcAngle[aNbFeatures]; - std::shared_ptr aStartArcDir[aNbFeatures]; - for (int i = 0; i < aNbFeatures; i++) { - anArcRadius[i] = aStart[i]->distance(aCenter[i]); - aStartArcDir[i] = std::shared_ptr( - new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); - anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]); + // 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 } - - // 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 { + 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 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; +void SketchPlugin_ConstraintSplit::splitArc(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_Arc::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; + } + + // 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, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + theCreatedFeatures.insert(theSplitFeature); + + // 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 + } + + // 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 } - 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; + else { + aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); + theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + aFeature->attribute(SketchPlugin_Arc::END_ID()))); } - double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; - aCirc->D0(aPntParameter, thePoint); + 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 = 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); + + 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 + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(theSplitFeature)); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(), + getFeatureResult(theSplitFeature), + getFeatureResult(aBaseFeature)); + theCreatedFeatures.insert(aConstraintFeature); + if (theAfterFeature.get()) { + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(theAfterFeature)); + theCreatedFeatures.insert(aConstraintFeature); + aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(), + getFeatureResult(theSplitFeature), + getFeatureResult(theAfterFeature)); + theCreatedFeatures.insert(aConstraintFeature); } } -double getProjectionDistance(const FeaturePtr theFeature, - const std::shared_ptr thePoint) +void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature, + FeaturePtr& theBaseFeatureModified, + FeaturePtr& theAfterFeature, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { - 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; + 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); } -std::set getCoincides(const FeaturePtr& theConstraintCoincidence) +void SketchPlugin_ConstraintSplit::arrangePointsOnLine( + const AttributePoint2DPtr& theStartPointAttr, + const AttributePoint2DPtr& theEndPointAttr, + AttributePoint2DPtr& theFirstPointAttr, + AttributePoint2DPtr& theLastPointAttr) const { - std::set aCoincides; - - std::shared_ptr aFilletPnt = SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence); - - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoincides); - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoincides); - - // Remove points from set of coincides. - std::set aNewSetOfCoincides; - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if((*anIt)->getKind() == SketchPlugin_Line::ID()) { - aNewSetOfCoincides.insert(*anIt); - } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { - AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr aPointCenter2D = - std::dynamic_pointer_cast(anAttrCenter); - if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) { - continue; - } - aNewSetOfCoincides.insert(*anIt); - } + // 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; + theFirstPointAttr = theLastPointAttr; + theLastPointAttr = aTmpPoint; } - 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; +} + +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; } +} - return aCoincides; +void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute, + const AttributePtr& theSourceAttribute) +{ + AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast( + theModifiedAttribute); + AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast( + theSourceAttribute); + + if (aModifiedAttribute.get() && aSourceAttribute.get()) + aModifiedAttribute->setValue(aSourceAttribute->pnt()); } -*/ -std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRefAttr( - const AttributePtr& theAttribute) +FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature, + const AttributePtr& theFirstPointAttr, + const AttributePtr& theSecondPointAttr) { - AttributePoint2DPtr aPointAttribute; + FeaturePtr aFeature; + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; - if (theAttribute->id() == ModelAPI_AttributeRefAttr::typeId()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); - if (aRefAttr.get() && aRefAttr->isInitialized()) { - AttributePtr anAttribute = aRefAttr->attr(); - if (anAttribute.get() && anAttribute->id() == GeomDataAPI_Point2D::typeId()) - aPointAttribute = std::dynamic_pointer_cast(anAttribute); - } + 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) +{ + FeaturePtr aFeature; + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; + + std::string aCenterAttributeId; + if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) + aCenterAttributeId = SketchPlugin_Arc::CENTER_ID(); + else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID()) + aCenterAttributeId = SketchPlugin_Circle::CENTER_ID(); + + if (aCenterAttributeId.empty()) + return aFeature; + + aFeature = aSketch->addFeature(SketchPlugin_Arc::ID()); + // update fillet arc: make the arc correct for sure, so, it is not needed to process + // the "attribute updated" + // by arc; moreover, it may cause cyclicity in hte mechanism of updater + 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(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); } - return aPointAttribute; + aFeature->data()->blockSendAttributeUpdated(false); + aFeature->execute(); // to obtain result + + return aFeature; } -AttributePoint2DPtr SketchPlugin_ConstraintSplit::getFeaturePoint(const bool& theStartPoint) +FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId, + const AttributePtr& theFirstAttribute, + const AttributePtr& theSecondAttribute) { - AttributePoint2DPtr aPointAttribute; + FeaturePtr aConstraint = sketch()->addFeature(theConstraintId); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(theFirstAttribute); - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(theSecondAttribute); - std::string aFeatureKind = aBaseFeature->getKind(); - std::string anAttributeName; - if (aFeatureKind == SketchPlugin_Line::ID()) - anAttributeName = theStartPoint ? SketchPlugin_Line::START_ID() - : SketchPlugin_Line::END_ID(); - else if (aFeatureKind == SketchPlugin_Arc::ID()) { - anAttributeName = theStartPoint ? SketchPlugin_Arc::START_ID() - : SketchPlugin_Arc::END_ID(); + return aConstraint; +} + +FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects( + const std::string& theConstraintId, + const ObjectPtr& theFirstObject, + const ObjectPtr& theSecondObject) +{ + FeaturePtr aConstraint = sketch()->addFeature(theConstraintId); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(theFirstObject); + + 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); + } + } } - if (!anAttributeName.empty()) - aPointAttribute = std::dynamic_pointer_cast( - aBaseFeature->attribute(anAttributeName)); - return aPointAttribute; } -FeaturePtr SketchPlugin_ConstraintSplit::createFeature(const AttributePoint2DPtr& theStartPointAttr, - const AttributePoint2DPtr& theEndPointAttr) +std::shared_ptr SketchPlugin_ConstraintSplit::getFeatureResult( + const std::shared_ptr& theFeature) { - FeaturePtr aFeature; -/* - AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + std::shared_ptr aResult; - std::string aFeatureKind = aBaseFeature->getKind(); - aFeature = sketch()->addFeature(aFeatureKind); + std::string aFeatureKind = theFeature->getKind(); + if (aFeatureKind == SketchPlugin_Line::ID()) + aResult = theFeature->firstResult(); + else if (aFeatureKind == SketchPlugin_Arc::ID()) + aResult = theFeature->lastResult(); + else if (aFeatureKind == SketchPlugin_Circle::ID()) + aResult = theFeature->lastResult(); - if (aFeatureKind == SketchPlugin_Line::ID()) { - AttributePoint2DPtr aStartAttribute = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Line::START_ID())); - aStartAttribute->setValue(theStartPointAttr->pnt()); + return aResult; +} + +std::set > SketchPlugin_ConstraintSplit::getEdgeAttributes( + const std::shared_ptr& theFeature) +{ + std::set > anAttributes; - AttributePoint2DPtr anEndAttribute = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Line::END_ID())); - anEndAttribute->setValue(theEndPointAttr->pnt()); + 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()) { - AttributeStringPtr anArcType = std::dynamic_pointer_cast( - data()->addAttribute(SketchPlugin_Arc::ARC_TYPE(), ModelAPI_AttributeString::typeId())); + anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID())); + anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID())); + } + else if (aFeatureKind == SketchPlugin_Circle::ID()) { + } - AttributePoint2DPtr aPointAttribute = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::START_ID())); - aPointAttribute->setValue(theStartPointAttr->pnt()); + return anAttributes; +} - AttributePoint2DPtr anEndAttribute = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::END_ID())); - anEndAttribute->setValue(theEndPointAttr->pnt()); +#ifdef _DEBUG +std::string SketchPlugin_ConstraintSplit::getFeatureInfo( + const std::shared_ptr& theFeature, + const bool isUseAttributesInfo) +{ + std::string anInfo; + if (!theFeature.get()) { + return "none"; } -*/ - return aFeature; + + 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