1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
20 #include "SketchPlugin_Fillet.h"
22 #include "SketchPlugin_Arc.h"
23 #include "SketchPlugin_Line.h"
24 #include "SketchPlugin_Point.h"
25 #include "SketchPlugin_Sketch.h"
26 #include "SketchPlugin_ConstraintEqual.h"
27 #include "SketchPlugin_ConstraintCoincidence.h"
28 #include "SketchPlugin_ConstraintLength.h"
29 #include "SketchPlugin_ConstraintMiddle.h"
30 #include "SketchPlugin_ConstraintTangent.h"
31 #include "SketchPlugin_ConstraintRadius.h"
32 #include "SketchPlugin_Tools.h"
34 #include <ModelAPI_AttributeRefAttr.h>
35 #include <ModelAPI_Data.h>
36 #include <ModelAPI_Events.h>
37 #include <ModelAPI_Session.h>
38 #include <ModelAPI_Tools.h>
39 #include <ModelAPI_Validator.h>
41 #include <GeomAlgoAPI_Circ2dBuilder.h>
42 #include <GeomAlgoAPI_EdgeBuilder.h>
44 #include <GeomAPI_Circ2d.h>
45 #include <GeomAPI_Dir2d.h>
46 #include <GeomAPI_Lin2d.h>
47 #include <GeomAPI_Pnt2d.h>
48 #include <GeomAPI_XY.h>
50 #include <GeomDataAPI_Point2D.h>
52 #include <Events_Loop.h>
56 const double tolerance = 1.e-7;
57 const double paramTolerance = 1.e-4;
58 const double PI = 3.141592653589793238463;
60 /// \brief Attract specified point on theNewArc to the attribute of theFeature
61 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
62 FeaturePtr theFeature, const std::string& theFeatureAttribute);
65 /// \brief Calculate radius of a fillet.
66 /// It should not be greater than 1/3 of shortest edge length.
67 static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]);
69 /// \brief Calculates center of fillet arc and coordinates of tangency points
70 static void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
71 double theFilletRadius,
72 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
73 std::shared_ptr<GeomAPI_XY>& theCenter,
74 std::shared_ptr<GeomAPI_XY>& theTangentA,
75 std::shared_ptr<GeomAPI_XY>& theTangentB);
77 /// Get coincide edges for fillet
78 static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
80 static std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
81 const AttributePtr theAttribute);
83 SketchPlugin_Fillet::SketchPlugin_Fillet()
84 : myFilletCreated(false)
88 void SketchPlugin_Fillet::initAttributes()
90 data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
93 void SketchPlugin_Fillet::execute()
95 // Wait all constraints being created, then send update events
96 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
97 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
99 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
101 // set flag here to avoid building Fillet presentation if "Redisplay" event appears
102 myFilletCreated = true;
104 // Calculate Fillet parameters if does not yet
105 if (!myBaseFeatures[0] || !myBaseFeatures[1])
106 calculateFilletParameters();
108 // Create arc feature.
109 FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID());
111 // Set arc attributes.
112 bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true);
113 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
114 aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
116 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
117 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
118 aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
119 std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
120 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
121 aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
122 if(aStartPoint->isInitialized() && aEndPoint->isInitialized()
123 && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance
124 || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) {
125 std::dynamic_pointer_cast<SketchPlugin_Arc>(aFilletArc)->setReversed(false);
127 aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y());
128 aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y());
129 aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked);
130 aFilletArc->execute();
132 // Delete features with refs to points of edges.
133 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint1;
134 int aFeatInd1 = myIsReversed ? 1 : 0;
135 int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1);
136 aStartPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
137 myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
138 std::set<FeaturePtr> aFeaturesToBeRemoved1 =
139 findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1);
141 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint2;
142 int aFeatInd2 = myIsReversed ? 0 : 1;
143 int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1);
144 aStartPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
145 myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
146 std::set<FeaturePtr> aFeaturesToBeRemoved2 =
147 findFeaturesToRemove(myBaseFeatures[aFeatInd2], aStartPoint2);
149 aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end());
150 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1);
151 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
153 // Update fillet edges.
154 recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
155 myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]);
156 recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
157 myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]);
159 // Create coincidence features.
160 FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
161 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
162 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
163 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
164 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
165 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
166 aRefAttr->setAttr(myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
167 aConstraint->execute();
168 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
169 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
170 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
171 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
172 aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
173 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
174 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
175 aRefAttr->setAttr(myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
176 aConstraint->execute();
177 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
179 // Create tangent features.
180 for (int i = 0; i < 2; i++) {
181 aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
182 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
183 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
184 aRefAttr->setObject(aFilletArc->lastResult());
185 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
186 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
187 bool isArc = myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID();
188 aRefAttr->setObject(isArc ? myBaseFeatures[i]->lastResult() :
189 myBaseFeatures[i]->firstResult());
190 aConstraint->execute();
191 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
194 // Send events to update the sub-features by the solver.
195 if(isUpdateFlushed) {
196 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
200 AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
202 if(myFilletCreated) {
203 return AISObjectPtr();
206 SketchPlugin_Sketch* aSketch = sketch();
208 return AISObjectPtr();
211 if (!calculateFilletParameters())
212 return AISObjectPtr();
214 // Create arc for presentation.
215 std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
216 std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
218 std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
220 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
221 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
222 std::shared_ptr<GeomAPI_Shape> anArcShape =
223 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir());
225 AISObjectPtr anAISObject = thePrevious;
226 if(!anAISObject.get()) {
227 anAISObject = AISObjectPtr(new GeomAPI_AISObject);
229 anAISObject->createShape(anArcShape);
233 bool SketchPlugin_Fillet::calculateFilletParameters()
236 AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID());
237 if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject())
239 std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
240 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
241 if (!aFilletPoint2D.get())
244 if (!findFeaturesContainingFilletPoint(aFilletPoint2D)) {
245 setError("Error: Selected point does not have two suitable edges for fillet.");
249 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
250 double aRadius = calculateFilletRadius(myBaseFeatures);
252 // Calculate arc attributes.
253 static const int aNbFeatures = 2;
254 // First pair of points relate to first feature, second pair - to second.
255 std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
256 for (int i = 0; i < aNbFeatures; i++) {
257 std::string aStartAttr, aEndAttr;
258 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
259 aStartAttr = SketchPlugin_Line::START_ID();
260 aEndAttr = SketchPlugin_Line::END_ID();
261 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
262 aStartAttr = SketchPlugin_Arc::START_ID();
263 aEndAttr = SketchPlugin_Arc::END_ID();
264 } else { // Wrong argument.
265 setError("Error: One of the points has wrong coincide feature");
268 myFeatAttributes[2*i] = aStartAttr;
269 aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
270 myBaseFeatures[i]->attribute(aStartAttr))->pnt();
271 myFeatAttributes[2*i+1] = aEndAttr;
272 aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
273 myBaseFeatures[i]->attribute(aEndAttr))->pnt();
275 for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
276 for (int j = 0; j < 2; j++) // loop on start-end of each feature
277 if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
278 myIsNotInversed[aFeatInd] = (j==0);
283 std::shared_ptr<GeomAPI_Ax3> aSketchPlane = SketchPlugin_Sketch::plane(sketch());
284 calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane,
285 myCenterXY, myTangentXY1, myTangentXY2);
287 // Tangent directions of the features in coincident point.
288 std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
289 for (int i = 0; i < aNbFeatures; i++) {
290 std::shared_ptr<GeomAPI_XY> aDir;
291 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
292 aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
293 if (!myIsNotInversed[i])
294 aDir = aDir->multiplied(-1.0);
295 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
296 std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
297 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
298 myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
299 aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
300 aDir = aDir->decreased(aCenterPoint->xy());
302 double x = aDir->x();
303 double y = aDir->y();
306 if (myIsNotInversed[i] ==
307 std::dynamic_pointer_cast<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
308 aDir = aDir->multiplied(-1.0);
310 aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
313 // By default, the start point of fillet arc is connected to FeatureA,
314 // and the end point - to FeatureB. But when the angle between TangentDirA and
315 // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
316 double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
317 // where A and B - angles between corresponding tanget direction and the X axis
318 myIsReversed = cosBA > 0.0;
321 std::shared_ptr<GeomAPI_XY> aTmp = myTangentXY1;
322 myTangentXY1 = myTangentXY2;
328 bool SketchPlugin_Fillet::findFeaturesContainingFilletPoint(
329 std::shared_ptr<GeomDataAPI_Point2D> theFilletPoint)
331 // Obtain constraint coincidence for the fillet point.
332 FeaturePtr aConstraintCoincidence;
333 const std::set<AttributePtr>& aRefsList = theFilletPoint->owner()->data()->refsToMe();
334 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
335 anIt != aRefsList.cend();
337 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
338 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
339 if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
340 AttributeRefAttrPtr anAttrRefA =
341 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_A());
342 AttributeRefAttrPtr anAttrRefB =
343 aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_B());
344 if(anAttrRefA.get() && !anAttrRefA->isObject()) {
345 AttributePtr anAttrA = anAttrRefA->attr();
346 if(theFilletPoint == anAttrA) {
347 aConstraintCoincidence = aFeature;
351 if(anAttrRefB.get() && !anAttrRefB->isObject()) {
352 AttributePtr anAttrB = anAttrRefB->attr();
353 if(theFilletPoint == anAttrB) {
354 aConstraintCoincidence = aFeature;
361 if(!aConstraintCoincidence.get())
364 // Get coincide edges.
365 std::set<FeaturePtr> anEdgeFeatures = getCoincides(aConstraintCoincidence);
366 std::set<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
367 for (int i = 0; aLinesIt != anEdgeFeatures.end() && i < 2; ++aLinesIt, ++i)
368 myBaseFeatures[i] = *aLinesIt;
370 return myBaseFeatures[0] && myBaseFeatures[1];
373 // ========= Auxiliary functions =================
374 void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
375 FeaturePtr theFeature, const std::string& theFeatureAttribute)
377 std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
378 theNewArc->attribute(theNewArcAttribute))->pnt();
379 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
380 theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
383 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const AttributePtr& theAttribute)
385 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
386 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
388 aPoint = aPointAttr->pnt();
392 static std::shared_ptr<GeomAPI_Lin2d> toLine(const FeaturePtr& theFeature)
394 std::shared_ptr<GeomAPI_Lin2d> aLine;
395 if (theFeature->getKind() == SketchPlugin_Line::ID()) {
396 std::shared_ptr<GeomAPI_Pnt2d> aStart =
397 toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) );
398 std::shared_ptr<GeomAPI_Pnt2d> aEnd =
399 toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) );
400 aLine = std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart, aEnd));
405 static std::shared_ptr<GeomAPI_Circ2d> toCircle(const FeaturePtr& theFeature)
407 std::shared_ptr<GeomAPI_Circ2d> aCircle;
408 if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
409 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
410 toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) );
411 std::shared_ptr<GeomAPI_Pnt2d> aStart =
412 toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) );
413 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aStart));
419 void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
420 double theFilletRadius,
421 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
422 std::shared_ptr<GeomAPI_XY>& theCenter,
423 std::shared_ptr<GeomAPI_XY>& theTangentA,
424 std::shared_ptr<GeomAPI_XY>& theTangentB)
426 GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
427 GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
429 GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane);
430 aCircBuilder.addTangentCurve(aShapeA);
431 aCircBuilder.addTangentCurve(aShapeB);
432 aCircBuilder.setRadius(theFilletRadius);
434 std::shared_ptr<GeomAPI_Circ2d> aFilletCircle = aCircBuilder.circle();
438 theCenter = aFilletCircle->center()->xy();
440 std::shared_ptr<GeomAPI_Pnt2d> aTgPoints[2];
441 for (int i = 0; i < 2; ++i) {
442 std::shared_ptr<GeomAPI_Circ2d> aCircle = toCircle(theFilletFeatures[i]);
444 aTgPoints[i] = aCircle->project(aFilletCircle->center());
446 std::shared_ptr<GeomAPI_Lin2d> aLine = toLine(theFilletFeatures[i]);
448 aTgPoints[i] = aLine->project(aFilletCircle->center());
451 theTangentA = aTgPoints[0]->xy();
452 theTangentB = aTgPoints[1]->xy();
455 double calculateFilletRadius(FeaturePtr theFilletFeatures[2])
457 double aLengths[2] = { 0, 0 };
458 for (int i = 0; i < 2; ++i) {
459 GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape();
460 std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(aShape);
462 aLengths[i] = anEdge->length();
464 return std::min(aLengths[0], aLengths[1]) / 6.0;
467 std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
469 std::set<FeaturePtr> aCoincides;
471 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt =
472 SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
474 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
475 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
477 SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
478 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
481 // Remove points from set of coincides.
482 std::set<FeaturePtr> aNewSetOfCoincides;
483 for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
484 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
485 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
486 if(aSketchEntity.get() && aSketchEntity->isCopy()) {
489 if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
490 aNewSetOfCoincides.insert(*anIt);
491 } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
492 AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
493 std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
494 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
495 if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
498 aNewSetOfCoincides.insert(*anIt);
501 aCoincides = aNewSetOfCoincides;
503 // If we still have more than two coincides remove auxilary entities from set of coincides.
504 if(aCoincides.size() > 2) {
505 aNewSetOfCoincides.clear();
506 for(std::set<FeaturePtr>::iterator
507 anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
508 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
509 aNewSetOfCoincides.insert(*anIt);
512 aCoincides = aNewSetOfCoincides;
518 std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
519 const AttributePtr theAttribute) {
520 std::set<FeaturePtr> aFeaturesToBeRemoved;
521 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
522 std::list<ResultPtr> aResults = theFeature->results();
523 for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
524 aResultsIt != aResults.cend();
526 ResultPtr aResult = *aResultsIt;
527 std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
528 aRefs.insert(aResultRefs.begin(), aResultRefs.end());
530 for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
531 anIt != aRefs.cend();
533 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
534 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
535 if(aFeature->getKind() == SketchPlugin_Fillet::ID()) {
538 if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID()
539 || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()
540 || aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
541 aFeaturesToBeRemoved.insert(aFeature);
543 std::list<AttributePtr> anAttrs =
544 aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
545 for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
546 aRefAttrsIt != anAttrs.cend();
548 AttributeRefAttrPtr anAttrRefAttr =
549 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
550 if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
551 aFeaturesToBeRemoved.insert(aFeature);
556 return aFeaturesToBeRemoved;