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_ConstraintMiddle.h"
17 #include "SketchPlugin_ConstraintTangent.h"
18 #include "SketchPlugin_ConstraintRadius.h"
19 #include "SketchPlugin_Tools.h"
21 #include <ModelAPI_AttributeRefAttr.h>
22 #include <ModelAPI_Data.h>
23 #include <ModelAPI_Events.h>
24 #include <ModelAPI_Session.h>
25 #include <ModelAPI_Tools.h>
26 #include <ModelAPI_Validator.h>
28 #include <GeomAlgoAPI_Circ2dBuilder.h>
29 #include <GeomAlgoAPI_EdgeBuilder.h>
31 #include <GeomAPI_Circ2d.h>
32 #include <GeomAPI_Dir2d.h>
33 #include <GeomAPI_Lin2d.h>
34 #include <GeomAPI_Pnt2d.h>
35 #include <GeomAPI_XY.h>
37 #include <GeomDataAPI_Point2D.h>
39 #include <Events_Loop.h>
43 const double tolerance = 1.e-7;
44 const double paramTolerance = 1.e-4;
45 const double PI = 3.141592653589793238463;
47 /// \brief Attract specified point on theNewArc to the attribute of theFeature
48 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
49 FeaturePtr theFeature, const std::string& theFeatureAttribute);
52 /// \brief Calculate radius of a fillet.
53 /// It should not be greater than 1/3 of shortest edge length.
54 static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]);
56 /// \brief Calculates center of fillet arc and coordinates of tangency points
57 static void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
58 double theFilletRadius,
59 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
60 std::shared_ptr<GeomAPI_XY>& theCenter,
61 std::shared_ptr<GeomAPI_XY>& theTangentA,
62 std::shared_ptr<GeomAPI_XY>& theTangentB);
64 /// Get coincide edges for fillet
65 static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
67 static std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
68 const AttributePtr theAttribute);
70 SketchPlugin_Fillet::SketchPlugin_Fillet()
71 : myFilletCreated(false)
75 void SketchPlugin_Fillet::initAttributes()
77 data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
80 void SketchPlugin_Fillet::execute()
82 // Wait all constraints being created, then send update events
83 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
84 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
86 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
88 // Calculate Fillet parameters if does not yet
89 if (!myBaseFeatures[0] || !myBaseFeatures[1])
90 calculateFilletParameters();
92 // Create arc feature.
93 FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID());
95 // Set arc attributes.
96 bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true);
97 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
98 aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
100 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
101 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
102 aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
103 std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
104 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
105 aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
106 if(aStartPoint->isInitialized() && aEndPoint->isInitialized()
107 && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance
108 || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) {
109 std::dynamic_pointer_cast<SketchPlugin_Arc>(aFilletArc)->setReversed(false);
111 aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y());
112 aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y());
113 aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked);
114 aFilletArc->execute();
116 // Delete features with refs to points of edges.
117 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint1;
118 int aFeatInd1 = myIsReversed ? 1 : 0;
119 int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1);
120 aStartPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
121 myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
122 std::set<FeaturePtr> aFeaturesToBeRemoved1 =
123 findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1);
125 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint2;
126 int aFeatInd2 = myIsReversed ? 0 : 1;
127 int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1);
128 aStartPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
129 myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
130 std::set<FeaturePtr> aFeaturesToBeRemoved2 =
131 findFeaturesToRemove(myBaseFeatures[aFeatInd2], aStartPoint2);
133 aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end());
134 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1);
135 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
137 // Update fillet edges.
138 recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
139 myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]);
140 recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
141 myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]);
143 // Create coincidence features.
144 FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
145 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
146 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
147 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
148 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
149 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
150 aRefAttr->setAttr(myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
151 aConstraint->execute();
152 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
153 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
154 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
155 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
156 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
157 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
158 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
159 aRefAttr->setAttr(myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
160 aConstraint->execute();
161 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
163 // Create tangent features.
164 for (int i = 0; i < 2; i++) {
165 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
166 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
167 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
168 aRefAttr->setObject(aFilletArc->lastResult());
169 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
170 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
171 bool isArc = myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID();
172 aRefAttr->setObject(isArc ? myBaseFeatures[i]->lastResult() :
173 myBaseFeatures[i]->firstResult());
174 aConstraint->execute();
175 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
178 // Send events to update the sub-features by the solver.
179 if(isUpdateFlushed) {
180 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
183 myFilletCreated = true;
186 AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
188 if(myFilletCreated) {
189 return AISObjectPtr();
192 SketchPlugin_Sketch* aSketch = sketch();
194 return AISObjectPtr();
197 if (!calculateFilletParameters())
198 return AISObjectPtr();
200 // Create arc for presentation.
201 std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
202 std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
204 std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
206 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
207 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
208 std::shared_ptr<GeomAPI_Shape> anArcShape =
209 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir());
211 AISObjectPtr anAISObject = thePrevious;
212 if(!anAISObject.get()) {
213 anAISObject = AISObjectPtr(new GeomAPI_AISObject);
215 anAISObject->createShape(anArcShape);
219 bool SketchPlugin_Fillet::calculateFilletParameters()
222 AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID());
223 if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject())
225 std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
226 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
227 if (!aFilletPoint2D.get())
230 if (!findFeaturesContainingFilletPoint(aFilletPoint2D)) {
231 setError("Error: Selected point does not have two suitable edges for fillet.");
235 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
236 double aRadius = calculateFilletRadius(myBaseFeatures);
238 // Calculate arc attributes.
239 static const int aNbFeatures = 2;
240 // First pair of points relate to first feature, second pair - to second.
241 std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
242 for (int i = 0; i < aNbFeatures; i++) {
243 std::string aStartAttr, aEndAttr;
244 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
245 aStartAttr = SketchPlugin_Line::START_ID();
246 aEndAttr = SketchPlugin_Line::END_ID();
247 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
248 aStartAttr = SketchPlugin_Arc::START_ID();
249 aEndAttr = SketchPlugin_Arc::END_ID();
250 } else { // Wrong argument.
251 setError("Error: One of the points has wrong coincide feature");
254 myFeatAttributes[2*i] = aStartAttr;
255 aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
256 myBaseFeatures[i]->attribute(aStartAttr))->pnt();
257 myFeatAttributes[2*i+1] = aEndAttr;
258 aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
259 myBaseFeatures[i]->attribute(aEndAttr))->pnt();
261 for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
262 for (int j = 0; j < 2; j++) // loop on start-end of each feature
263 if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
264 myIsNotInversed[aFeatInd] = (j==0);
269 std::shared_ptr<GeomAPI_Ax3> aSketchPlane = SketchPlugin_Sketch::plane(sketch());
270 calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane,
271 myCenterXY, myTangentXY1, myTangentXY2);
273 // Tangent directions of the features in coincident point.
274 std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
275 for (int i = 0; i < aNbFeatures; i++) {
276 std::shared_ptr<GeomAPI_XY> aDir;
277 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
278 aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
279 if (!myIsNotInversed[i])
280 aDir = aDir->multiplied(-1.0);
281 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
282 std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
283 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
284 myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
285 aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
286 aDir = aDir->decreased(aCenterPoint->xy());
288 double x = aDir->x();
289 double y = aDir->y();
292 if (myIsNotInversed[i] ==
293 std::dynamic_pointer_cast<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
294 aDir = aDir->multiplied(-1.0);
296 aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
299 // By default, the start point of fillet arc is connected to FeatureA,
300 // and the end point - to FeatureB. But when the angle between TangentDirA and
301 // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
302 double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
303 // where A and B - angles between corresponding tanget direction and the X axis
304 myIsReversed = cosBA > 0.0;
307 std::shared_ptr<GeomAPI_XY> aTmp = myTangentXY1;
308 myTangentXY1 = myTangentXY2;
314 bool SketchPlugin_Fillet::findFeaturesContainingFilletPoint(
315 std::shared_ptr<GeomDataAPI_Point2D> theFilletPoint)
317 // Obtain constraint coincidence for the fillet point.
318 FeaturePtr aConstraintCoincidence;
319 const std::set<AttributePtr>& aRefsList = theFilletPoint->owner()->data()->refsToMe();
320 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
321 anIt != aRefsList.cend();
323 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
324 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
325 if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
326 AttributeRefAttrPtr anAttrRefA =
327 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_A());
328 AttributeRefAttrPtr anAttrRefB =
329 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_B());
330 if(anAttrRefA.get() && !anAttrRefA->isObject()) {
331 AttributePtr anAttrA = anAttrRefA->attr();
332 if(theFilletPoint == anAttrA) {
333 aConstraintCoincidence = aFeature;
337 if(anAttrRefB.get() && !anAttrRefB->isObject()) {
338 AttributePtr anAttrB = anAttrRefB->attr();
339 if(theFilletPoint == anAttrB) {
340 aConstraintCoincidence = aFeature;
347 if(!aConstraintCoincidence.get())
350 // Get coincide edges.
351 std::set<FeaturePtr> anEdgeFeatures = getCoincides(aConstraintCoincidence);
352 std::set<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
353 for (int i = 0; aLinesIt != anEdgeFeatures.end() && i < 2; ++aLinesIt, ++i)
354 myBaseFeatures[i] = *aLinesIt;
356 return myBaseFeatures[0] && myBaseFeatures[1];
359 // ========= Auxiliary functions =================
360 void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
361 FeaturePtr theFeature, const std::string& theFeatureAttribute)
363 std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
364 theNewArc->attribute(theNewArcAttribute))->pnt();
365 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
366 theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
369 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const AttributePtr& theAttribute)
371 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
372 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
374 aPoint = aPointAttr->pnt();
378 static std::shared_ptr<GeomAPI_Lin2d> toLine(const FeaturePtr& theFeature)
380 std::shared_ptr<GeomAPI_Lin2d> aLine;
381 if (theFeature->getKind() == SketchPlugin_Line::ID()) {
382 std::shared_ptr<GeomAPI_Pnt2d> aStart =
383 toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) );
384 std::shared_ptr<GeomAPI_Pnt2d> aEnd =
385 toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) );
386 aLine = std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart, aEnd));
391 static std::shared_ptr<GeomAPI_Circ2d> toCircle(const FeaturePtr& theFeature)
393 std::shared_ptr<GeomAPI_Circ2d> aCircle;
394 if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
395 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
396 toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) );
397 std::shared_ptr<GeomAPI_Pnt2d> aStart =
398 toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) );
399 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aStart));
405 void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
406 double theFilletRadius,
407 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
408 std::shared_ptr<GeomAPI_XY>& theCenter,
409 std::shared_ptr<GeomAPI_XY>& theTangentA,
410 std::shared_ptr<GeomAPI_XY>& theTangentB)
412 GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
413 GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
415 GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane);
416 aCircBuilder.addTangentCurve(aShapeA);
417 aCircBuilder.addTangentCurve(aShapeB);
418 aCircBuilder.setRadius(theFilletRadius);
420 std::shared_ptr<GeomAPI_Circ2d> aFilletCircle = aCircBuilder.circle();
424 theCenter = aFilletCircle->center()->xy();
426 std::shared_ptr<GeomAPI_Pnt2d> aTgPoints[2];
427 for (int i = 0; i < 2; ++i) {
428 std::shared_ptr<GeomAPI_Circ2d> aCircle = toCircle(theFilletFeatures[i]);
430 aTgPoints[i] = aCircle->project(aFilletCircle->center());
432 std::shared_ptr<GeomAPI_Lin2d> aLine = toLine(theFilletFeatures[i]);
434 aTgPoints[i] = aLine->project(aFilletCircle->center());
437 theTangentA = aTgPoints[0]->xy();
438 theTangentB = aTgPoints[1]->xy();
441 double calculateFilletRadius(FeaturePtr theFilletFeatures[2])
443 double aLengths[2] = { 0, 0 };
444 for (int i = 0; i < 2; ++i) {
445 GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape();
446 std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(aShape);
448 aLengths[i] = anEdge->length();
450 return std::min(aLengths[0], aLengths[1]) / 6.0;
453 std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
455 std::set<FeaturePtr> aCoincides;
457 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt =
458 SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
460 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
461 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
463 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
464 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
467 // Remove points from set of coincides.
468 std::set<FeaturePtr> aNewSetOfCoincides;
469 for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
470 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
471 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
472 if(aSketchEntity.get() && aSketchEntity->isCopy()) {
475 if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
476 aNewSetOfCoincides.insert(*anIt);
477 } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
478 AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
479 std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
480 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
481 if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
484 aNewSetOfCoincides.insert(*anIt);
487 aCoincides = aNewSetOfCoincides;
489 // If we still have more than two coincides remove auxilary entities from set of coincides.
490 if(aCoincides.size() > 2) {
491 aNewSetOfCoincides.clear();
492 for(std::set<FeaturePtr>::iterator
493 anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
494 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
495 aNewSetOfCoincides.insert(*anIt);
498 aCoincides = aNewSetOfCoincides;
504 std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
505 const AttributePtr theAttribute) {
506 std::set<FeaturePtr> aFeaturesToBeRemoved;
507 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
508 std::list<ResultPtr> aResults = theFeature->results();
509 for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
510 aResultsIt != aResults.cend();
512 ResultPtr aResult = *aResultsIt;
513 std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
514 aRefs.insert(aResultRefs.begin(), aResultRefs.end());
516 for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
517 anIt != aRefs.cend();
519 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
520 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
521 if(aFeature->getKind() == SketchPlugin_Fillet::ID()) {
524 if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID()
525 || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()
526 || aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
527 aFeaturesToBeRemoved.insert(aFeature);
529 std::list<AttributePtr> anAttrs =
530 aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
531 for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
532 aRefAttrsIt != anAttrs.cend();
534 AttributeRefAttrPtr anAttrRefAttr =
535 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
536 if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
537 aFeaturesToBeRemoved.insert(aFeature);
542 return aFeaturesToBeRemoved;