1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_Fillet.cpp
4 // Created: 19 Mar 2015
5 // Author: Artem ZHIDKOV
7 #include "SketchPlugin_Fillet.h"
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_Line.h"
11 #include "SketchPlugin_Point.h"
12 #include "SketchPlugin_Sketch.h"
13 #include "SketchPlugin_ConstraintEqual.h"
14 #include "SketchPlugin_ConstraintCoincidence.h"
15 #include "SketchPlugin_ConstraintLength.h"
16 #include "SketchPlugin_ConstraintTangent.h"
17 #include "SketchPlugin_ConstraintRadius.h"
18 #include "SketchPlugin_Tools.h"
20 #include <ModelAPI_AttributeRefAttr.h>
21 #include <ModelAPI_Data.h>
22 #include <ModelAPI_Events.h>
23 #include <ModelAPI_Session.h>
24 #include <ModelAPI_Tools.h>
25 #include <ModelAPI_Validator.h>
27 #include <GeomAlgoAPI_EdgeBuilder.h>
29 #include <GeomAPI_Circ2d.h>
30 #include <GeomAPI_Dir2d.h>
31 #include <GeomAPI_Lin2d.h>
32 #include <GeomAPI_Pnt2d.h>
33 #include <GeomAPI_XY.h>
35 #include <GeomDataAPI_Point2D.h>
37 #include <Events_Loop.h>
41 const double tolerance = 1.e-7;
42 const double paramTolerance = 1.e-4;
43 const double PI = 3.141592653589793238463;
45 /// \brief Attract specified point on theNewArc to the attribute of theFeature
46 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
47 FeaturePtr theFeature, const std::string& theFeatureAttribute);
50 /// \brief Calculate radius of a fillet.
51 /// It should not be greater than 1/3 of shortest edge length.
52 static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]);
54 /// \brief Calculates center of fillet arc and coordinates of tangency points
55 static void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
56 double theFilletRadius,
57 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
58 std::shared_ptr<GeomAPI_XY>& theCenter,
59 std::shared_ptr<GeomAPI_XY>& theTangentA,
60 std::shared_ptr<GeomAPI_XY>& theTangentB);
62 /// Get coincide edges for fillet
63 static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
65 static std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
66 const AttributePtr theAttribute);
68 SketchPlugin_Fillet::SketchPlugin_Fillet()
69 : myFilletCreated(false)
73 void SketchPlugin_Fillet::initAttributes()
75 data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
78 void SketchPlugin_Fillet::execute()
80 // Wait all constraints being created, then send update events
81 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
82 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
84 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
86 // Calculate Fillet parameters if does not yet
87 if (!myBaseFeatures[0] || !myBaseFeatures[1])
88 calculateFilletParameters();
90 // Create arc feature.
91 FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID());
93 // Set arc attributes.
94 bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true);
95 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
96 aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
98 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
99 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
100 aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
101 std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
102 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
103 aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
104 if(aStartPoint->isInitialized() && aEndPoint->isInitialized()
105 && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance
106 || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) {
107 std::dynamic_pointer_cast<SketchPlugin_Arc>(aFilletArc)->setReversed(false);
109 aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y());
110 aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y());
111 aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked);
112 aFilletArc->execute();
114 // Delete features with refs to points of edges.
115 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint1;
116 int aFeatInd1 = myIsReversed ? 1 : 0;
117 int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1);
118 aStartPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
119 myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
120 std::set<FeaturePtr> aFeaturesToBeRemoved1 =
121 findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1);
123 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint2;
124 int aFeatInd2 = myIsReversed ? 0 : 1;
125 int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1);
126 aStartPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
127 myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
128 std::set<FeaturePtr> aFeaturesToBeRemoved2 =
129 findFeaturesToRemove(myBaseFeatures[aFeatInd2], aStartPoint2);
131 aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end());
132 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1);
133 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
135 // Update fillet edges.
136 recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
137 myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]);
138 recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
139 myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]);
141 // Create coincidence features.
142 FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
143 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
144 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
145 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
146 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
147 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
148 aRefAttr->setAttr(myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
149 aConstraint->execute();
150 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
151 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
152 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
153 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
154 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
155 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
156 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
157 aRefAttr->setAttr(myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
158 aConstraint->execute();
159 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
161 // Create tangent features.
162 for (int i = 0; i < 2; i++) {
163 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
164 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
165 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
166 aRefAttr->setObject(aFilletArc->lastResult());
167 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
168 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
169 bool isArc = myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID();
170 aRefAttr->setObject(isArc ? myBaseFeatures[i]->lastResult() :
171 myBaseFeatures[i]->firstResult());
172 aConstraint->execute();
173 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
176 // Send events to update the sub-features by the solver.
177 if(isUpdateFlushed) {
178 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
181 myFilletCreated = true;
184 AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
186 if(myFilletCreated) {
187 return AISObjectPtr();
190 SketchPlugin_Sketch* aSketch = sketch();
192 return AISObjectPtr();
195 if (!calculateFilletParameters())
196 return AISObjectPtr();
198 // Create arc for presentation.
199 std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
200 std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
202 std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
204 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
205 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
206 std::shared_ptr<GeomAPI_Shape> anArcShape =
207 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir());
209 AISObjectPtr anAISObject = thePrevious;
210 if(!anAISObject.get()) {
211 anAISObject = AISObjectPtr(new GeomAPI_AISObject);
213 anAISObject->createShape(anArcShape);
217 bool SketchPlugin_Fillet::calculateFilletParameters()
220 AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID());
221 if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject())
223 std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
224 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
225 if (!aFilletPoint2D.get())
228 if (!findFeaturesContainingFilletPoint(aFilletPoint2D)) {
229 setError("Error: Selected point does not have two suitable edges for fillet.");
233 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
234 double aRadius = calculateFilletRadius(myBaseFeatures);
236 // Calculate arc attributes.
237 static const int aNbFeatures = 2;
238 // First pair of points relate to first feature, second pair - to second.
239 std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
240 for (int i = 0; i < aNbFeatures; i++) {
241 std::string aStartAttr, aEndAttr;
242 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
243 aStartAttr = SketchPlugin_Line::START_ID();
244 aEndAttr = SketchPlugin_Line::END_ID();
245 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
246 aStartAttr = SketchPlugin_Arc::START_ID();
247 aEndAttr = SketchPlugin_Arc::END_ID();
248 } else { // Wrong argument.
249 setError("Error: One of the points has wrong coincide feature");
252 myFeatAttributes[2*i] = aStartAttr;
253 aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
254 myBaseFeatures[i]->attribute(aStartAttr))->pnt();
255 myFeatAttributes[2*i+1] = aEndAttr;
256 aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
257 myBaseFeatures[i]->attribute(aEndAttr))->pnt();
259 for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
260 for (int j = 0; j < 2; j++) // loop on start-end of each feature
261 if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
262 myIsNotInversed[aFeatInd] = (j==0);
267 std::shared_ptr<GeomAPI_Ax3> aSketchPlane = SketchPlugin_Sketch::plane(sketch());
268 calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane,
269 myCenterXY, myTangentXY1, myTangentXY2);
271 // Tangent directions of the features in coincident point.
272 std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
273 for (int i = 0; i < aNbFeatures; i++) {
274 std::shared_ptr<GeomAPI_XY> aDir;
275 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
276 aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
277 if (!myIsNotInversed[i])
278 aDir = aDir->multiplied(-1.0);
279 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
280 std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
281 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
282 myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
283 aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
284 aDir = aDir->decreased(aCenterPoint->xy());
286 double x = aDir->x();
287 double y = aDir->y();
290 if (myIsNotInversed[i] ==
291 std::dynamic_pointer_cast<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
292 aDir = aDir->multiplied(-1.0);
294 aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
297 // By default, the start point of fillet arc is connected to FeatureA,
298 // and the end point - to FeatureB. But when the angle between TangentDirA and
299 // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
300 double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
301 // where A and B - angles between corresponding tanget direction and the X axis
302 myIsReversed = cosBA > 0.0;
305 std::shared_ptr<GeomAPI_XY> aTmp = myTangentXY1;
306 myTangentXY1 = myTangentXY2;
312 bool SketchPlugin_Fillet::findFeaturesContainingFilletPoint(
313 std::shared_ptr<GeomDataAPI_Point2D> theFilletPoint)
315 // Obtain constraint coincidence for the fillet point.
316 FeaturePtr aConstraintCoincidence;
317 const std::set<AttributePtr>& aRefsList = theFilletPoint->owner()->data()->refsToMe();
318 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
319 anIt != aRefsList.cend();
321 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
322 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
323 if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
324 AttributeRefAttrPtr anAttrRefA =
325 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_A());
326 AttributeRefAttrPtr anAttrRefB =
327 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_B());
328 if(anAttrRefA.get() && !anAttrRefA->isObject()) {
329 AttributePtr anAttrA = anAttrRefA->attr();
330 if(theFilletPoint == anAttrA) {
331 aConstraintCoincidence = aFeature;
335 if(anAttrRefB.get() && !anAttrRefB->isObject()) {
336 AttributePtr anAttrB = anAttrRefB->attr();
337 if(theFilletPoint == anAttrB) {
338 aConstraintCoincidence = aFeature;
345 if(!aConstraintCoincidence.get())
348 // Get coincide edges.
349 std::set<FeaturePtr> anEdgeFeatures = getCoincides(aConstraintCoincidence);
350 std::set<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
351 for (int i = 0; aLinesIt != anEdgeFeatures.end() && i < 2; ++aLinesIt, ++i)
352 myBaseFeatures[i] = *aLinesIt;
354 return myBaseFeatures[0] && myBaseFeatures[1];
357 // ========= Auxiliary functions =================
358 void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
359 FeaturePtr theFeature, const std::string& theFeatureAttribute)
361 std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
362 theNewArc->attribute(theNewArcAttribute))->pnt();
363 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
364 theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
367 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const AttributePtr& theAttribute)
369 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
370 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
372 aPoint = aPointAttr->pnt();
376 static std::shared_ptr<GeomAPI_Lin2d> toLine(const FeaturePtr& theFeature)
378 std::shared_ptr<GeomAPI_Lin2d> aLine;
379 if (theFeature->getKind() == SketchPlugin_Line::ID()) {
380 std::shared_ptr<GeomAPI_Pnt2d> aStart =
381 toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) );
382 std::shared_ptr<GeomAPI_Pnt2d> aEnd =
383 toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) );
384 aLine = std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart, aEnd));
389 static std::shared_ptr<GeomAPI_Circ2d> toCircle(const FeaturePtr& theFeature)
391 std::shared_ptr<GeomAPI_Circ2d> aCircle;
392 if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
393 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
394 toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) );
395 std::shared_ptr<GeomAPI_Pnt2d> aStart =
396 toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) );
397 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aStart));
403 void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
404 double theFilletRadius,
405 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
406 std::shared_ptr<GeomAPI_XY>& theCenter,
407 std::shared_ptr<GeomAPI_XY>& theTangentA,
408 std::shared_ptr<GeomAPI_XY>& theTangentB)
410 GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
411 GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
413 std::shared_ptr<GeomAPI_Circ2d> aFilletCircle(
414 new GeomAPI_Circ2d(aShapeA, aShapeB, theFilletRadius, theSketchPlane));
415 if (!aFilletCircle->implPtr<char>())
418 theCenter = aFilletCircle->center()->xy();
420 std::shared_ptr<GeomAPI_Pnt2d> aTgPoints[2];
421 for (int i = 0; i < 2; ++i) {
422 std::shared_ptr<GeomAPI_Circ2d> aCircle = toCircle(theFilletFeatures[i]);
424 aTgPoints[i] = aCircle->project(aFilletCircle->center());
426 std::shared_ptr<GeomAPI_Lin2d> aLine = toLine(theFilletFeatures[i]);
428 aTgPoints[i] = aLine->project(aFilletCircle->center());
431 theTangentA = aTgPoints[0]->xy();
432 theTangentB = aTgPoints[1]->xy();
435 double calculateFilletRadius(FeaturePtr theFilletFeatures[2])
437 double aLengths[2] = { 0, 0 };
438 for (int i = 0; i < 2; ++i) {
439 GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape();
440 std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(aShape);
442 aLengths[i] = anEdge->length();
444 return std::min(aLengths[0], aLengths[1]) / 6.0;
447 std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
449 std::set<FeaturePtr> aCoincides;
451 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt =
452 SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
454 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
455 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
457 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
458 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
461 // Remove points from set of coincides.
462 std::set<FeaturePtr> aNewSetOfCoincides;
463 for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
464 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
465 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
466 if(aSketchEntity.get() && aSketchEntity->isCopy()) {
469 if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
470 aNewSetOfCoincides.insert(*anIt);
471 } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
472 AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
473 std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
474 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
475 if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
478 aNewSetOfCoincides.insert(*anIt);
481 aCoincides = aNewSetOfCoincides;
483 // If we still have more than two coincides remove auxilary entities from set of coincides.
484 if(aCoincides.size() > 2) {
485 aNewSetOfCoincides.clear();
486 for(std::set<FeaturePtr>::iterator
487 anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
488 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
489 aNewSetOfCoincides.insert(*anIt);
492 aCoincides = aNewSetOfCoincides;
498 std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
499 const AttributePtr theAttribute) {
500 std::set<FeaturePtr> aFeaturesToBeRemoved;
501 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
502 std::list<ResultPtr> aResults = theFeature->results();
503 for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
504 aResultsIt != aResults.cend();
506 ResultPtr aResult = *aResultsIt;
507 std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
508 aRefs.insert(aResultRefs.begin(), aResultRefs.end());
510 for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
511 anIt != aRefs.cend();
513 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
514 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
515 if(aFeature->getKind() == SketchPlugin_Fillet::ID()) {
518 if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID()
519 || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()) {
520 aFeaturesToBeRemoved.insert(aFeature);
522 std::list<AttributePtr> anAttrs =
523 aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
524 for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
525 aRefAttrsIt != anAttrs.cend();
527 AttributeRefAttrPtr anAttrRefAttr =
528 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
529 if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
530 aFeaturesToBeRemoved.insert(aFeature);
535 return aFeaturesToBeRemoved;