1 // Copyright (C) 2014-2023 CEA, EDF
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
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_ConstraintDistance.h"
27 #include "SketchPlugin_ConstraintEqual.h"
28 #include "SketchPlugin_ConstraintCoincidence.h"
29 #include "SketchPlugin_ConstraintLength.h"
30 #include "SketchPlugin_ConstraintMiddle.h"
31 #include "SketchPlugin_ConstraintTangent.h"
32 #include "SketchPlugin_ConstraintRadius.h"
33 #include "SketchPlugin_Tools.h"
34 #include "SketchPlugin_Validators.h"
36 #include <ModelAPI_AttributeDouble.h>
37 #include <ModelAPI_AttributeInteger.h>
38 #include <ModelAPI_AttributeRefAttr.h>
39 #include <ModelAPI_Data.h>
40 #include <ModelAPI_Events.h>
41 #include <ModelAPI_Session.h>
42 #include <ModelAPI_Tools.h>
43 #include <ModelAPI_Validator.h>
45 #include <GeomAlgoAPI_Circ2dBuilder.h>
46 #include <GeomAlgoAPI_EdgeBuilder.h>
48 #include <GeomAPI_Circ2d.h>
49 #include <GeomAPI_Dir2d.h>
50 #include <GeomAPI_Lin2d.h>
51 #include <GeomAPI_Pnt2d.h>
52 #include <GeomAPI_XY.h>
54 #include <GeomDataAPI_Point2D.h>
56 #include <Events_Loop.h>
57 #include <Events_InfoMessage.h>
61 const double tolerance = 1.e-7;
62 const double paramTolerance = 1.e-4;
63 const double PI = 3.141592653589793238463;
65 /// \brief Attract specified point on theNewArc to the attribute of theFeature
66 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
67 FeaturePtr theFeature, const std::string& theFeatureAttribute);
70 /// \brief Calculate radius of a fillet.
71 /// It should not be greater than 1/3 of shortest edge length.
72 static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]);
74 /// \brief Calculates center of fillet arc and coordinates of tangency points
75 static void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
76 double theFilletRadius,
77 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
78 std::shared_ptr<GeomAPI_XY>& theCenter,
79 std::shared_ptr<GeomAPI_XY>& theTangentA,
80 std::shared_ptr<GeomAPI_XY>& theTangentB);
82 static std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
83 const AttributePtr theAttribute);
85 SketchPlugin_Fillet::SketchPlugin_Fillet()
86 : myIsReversed(false), myFilletCreated(false)
88 myIsNotInversed[0] = myIsNotInversed[1] = true;
91 void SketchPlugin_Fillet::initAttributes()
93 data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
96 void SketchPlugin_Fillet::execute()
98 // Wait all constraints being created, then send update events
99 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
100 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
102 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
104 // set flag here to avoid building Fillet presentation if "Redisplay" event appears
105 myFilletCreated = true;
107 // create feature for fillet arc
108 FeaturePtr aFilletArc = createFilletArc();
110 setError("Error: unable to create a fillet arc.");
114 // collect features referred to the edges participating in fillet
115 AttributePoint2DPtr aFilletPoints[2];
118 std::set<FeaturePtr> aFeaturesToBeRemoved;
119 for (int i = 0; i < 2; ++i) {
120 bool isFirstIndex = (i == 0);
121 aFeatInd[i] = myIsReversed == isFirstIndex ? 1 : 0;
122 anAttrInd[i] = (myIsReversed == isFirstIndex ? 2 : 0) + (myIsNotInversed[aFeatInd[i]] ? 0 : 1);
123 aFilletPoints[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
124 myBaseFeatures[aFeatInd[i]]->attribute(myFeatAttributes[anAttrInd[i]]));
125 std::set<FeaturePtr> aRemove =
126 findFeaturesToRemove(myBaseFeatures[aFeatInd[i]], aFilletPoints[i]);
127 aFeaturesToBeRemoved.insert(aRemove.begin(), aRemove.end());
130 // keep "distance" constraints and remove all other references
131 removeReferencesButKeepDistances(aFeaturesToBeRemoved, aFilletPoints);
133 // Update fillet edges.
134 recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
135 myBaseFeatures[aFeatInd[0]], myFeatAttributes[anAttrInd[0]]);
136 recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
137 myBaseFeatures[aFeatInd[1]], myFeatAttributes[anAttrInd[1]]);
139 FeaturePtr aConstraint;
141 // Create coincidence features.
142 aConstraint = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
143 SketchPlugin_ConstraintCoincidence::ID(),
144 aFilletArc->attribute(SketchPlugin_Arc::START_ID()),
145 myBaseFeatures[aFeatInd[0]]->attribute(myFeatAttributes[anAttrInd[0]]));
146 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
147 aConstraint = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
148 SketchPlugin_ConstraintCoincidence::ID(),
149 aFilletArc->attribute(SketchPlugin_Arc::END_ID()),
150 myBaseFeatures[aFeatInd[1]]->attribute(myFeatAttributes[anAttrInd[1]]));
151 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
153 // Create tangent features.
154 for (int i = 0; i < 2; i++) {
155 aConstraint = SketchPlugin_Tools::createConstraintObjectObject(sketch(),
156 SketchPlugin_ConstraintTangent::ID(),
157 aFilletArc->lastResult(),
158 myBaseFeatures[i]->lastResult());
159 aConstraint->execute();
160 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
163 // Send events to update the sub-features by the solver.
165 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
168 AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
170 if(myFilletCreated) {
171 return AISObjectPtr();
174 SketchPlugin_Sketch* aSketch = sketch();
176 return AISObjectPtr();
179 if (!calculateFilletParameters())
180 return AISObjectPtr();
182 // Create arc for presentation.
183 std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
184 std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
186 std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
188 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
189 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
190 std::shared_ptr<GeomAPI_Shape> anArcShape =
191 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir());
193 AISObjectPtr anAISObject = thePrevious;
194 if(!anAISObject.get()) {
195 anAISObject = AISObjectPtr(new GeomAPI_AISObject);
197 anAISObject->createShape(anArcShape);
198 bool isAxiliary = false;
199 AttributeBooleanPtr aAttr = boolean(AUXILIARY_ID());
201 isAxiliary = aAttr->value();
202 SketchPlugin_Tools::customizeFeaturePrs(anAISObject, isAxiliary);
206 bool SketchPlugin_Fillet::calculateFilletParameters()
209 AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID());
210 if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject())
212 std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
213 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
214 if (!aFilletPoint2D.get())
217 Events_InfoMessage anError;
218 FeaturePtr anEdge1, anEdge2;
219 if (!SketchPlugin_FilletVertexValidator::isValidVertex
220 (aPointRefAttr, anError, anEdge1, anEdge2)) {
221 setError(anError.messageString());
224 myBaseFeatures[0] = anEdge1;
225 myBaseFeatures[1] = anEdge2;
227 std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
228 double aRadius = calculateFilletRadius(myBaseFeatures);
230 // Calculate arc attributes.
231 static const int aNbFeatures = 2;
232 // First pair of points relate to first feature, second pair - to second.
233 std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
234 for (int i = 0; i < aNbFeatures; i++) {
235 std::string aStartAttr, aEndAttr;
236 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
237 aStartAttr = SketchPlugin_Line::START_ID();
238 aEndAttr = SketchPlugin_Line::END_ID();
239 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
240 aStartAttr = SketchPlugin_Arc::START_ID();
241 aEndAttr = SketchPlugin_Arc::END_ID();
242 } else { // Wrong argument.
243 setError("Error: One of the points has wrong coincide feature");
246 myFeatAttributes[2*i] = aStartAttr;
247 aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
248 myBaseFeatures[i]->attribute(aStartAttr))->pnt();
249 myFeatAttributes[2*i+1] = aEndAttr;
250 aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
251 myBaseFeatures[i]->attribute(aEndAttr))->pnt();
253 for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
254 for (int j = 0; j < 2; j++) // loop on start-end of each feature
255 if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
256 myIsNotInversed[aFeatInd] = (j==0);
261 std::shared_ptr<GeomAPI_Ax3> aSketchPlane = SketchPlugin_Sketch::plane(sketch());
262 calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane,
263 myCenterXY, myTangentXY1, myTangentXY2);
265 // Tangent directions of the features in coincident point.
266 std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
267 for (int i = 0; i < aNbFeatures; i++) {
268 std::shared_ptr<GeomAPI_XY> aDir;
269 if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
270 aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
271 if (!myIsNotInversed[i])
272 aDir = aDir->multiplied(-1.0);
273 } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
274 std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
275 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
276 myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
277 aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
278 aDir = aDir->decreased(aCenterPoint->xy());
280 double x = aDir->x();
281 double y = aDir->y();
284 if (myIsNotInversed[i] ==
285 std::dynamic_pointer_cast<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
286 aDir = aDir->multiplied(-1.0);
288 aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
291 // By default, the start point of fillet arc is connected to FeatureA,
292 // and the end point - to FeatureB. But when the angle between TangentDirA and
293 // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
294 double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
295 // where A and B - angles between corresponding tanget direction and the X axis
296 myIsReversed = cosBA > 0.0;
299 std::shared_ptr<GeomAPI_XY> aTmp = myTangentXY1;
300 myTangentXY1 = myTangentXY2;
306 FeaturePtr SketchPlugin_Fillet::createFilletArc()
308 // Calculate Fillet parameters if does not yet
309 if (!myBaseFeatures[0] || !myBaseFeatures[1])
310 calculateFilletParameters();
312 // fix for issue #2810 (sometimes, myCenterXY is NULL, fillet should report an error)
316 // Create arc feature.
317 FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID());
319 // Set arc attributes.
320 bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true);
321 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
322 aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
324 std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
325 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
326 aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
327 std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
328 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
329 aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
330 if(aStartPoint->isInitialized() && aEndPoint->isInitialized()
331 && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance
332 || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) {
333 std::dynamic_pointer_cast<SketchPlugin_Arc>(aFilletArc)->setReversed(false);
335 aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y());
336 aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y());
337 aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked);
338 aFilletArc->execute();
343 FeaturePtr SketchPlugin_Fillet::createFilletApex(const GeomPnt2dPtr& theCoordinates)
345 FeaturePtr anApex = sketch()->addFeature(SketchPlugin_Point::ID());
346 AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
347 anApex->attribute(SketchPlugin_Point::COORD_ID()));
348 aCoord->setValue(theCoordinates);
349 anApex->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
351 // additional coincidence constraints
352 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
353 FeaturePtr aConstraint;
354 for (int i = 0; i < 2; i++) {
355 aConstraint = SketchPlugin_Tools::createConstraintAttrObject(sketch(),
356 SketchPlugin_ConstraintCoincidence::ID(),
358 myBaseFeatures[i]->lastResult());
359 aConstraint->execute();
360 ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
367 AttributePtr myPoints[2];
368 std::wstring myValueText;
369 double myValueDouble;
370 GeomPnt2dPtr myFlyoutPoint;
374 void SketchPlugin_Fillet::removeReferencesButKeepDistances(
375 std::set<FeaturePtr>& theFeaturesToRemove,
376 const AttributePoint2DPtr theFilletPoints[2])
378 FeaturePtr aFilletApex;
379 std::list<Length> aLengthToDistance;
381 std::set<FeaturePtr>::iterator aFeat = theFeaturesToRemove.begin();
382 while (aFeat != theFeaturesToRemove.end()) {
383 std::shared_ptr<SketchPlugin_ConstraintDistance> aDistance =
384 std::dynamic_pointer_cast<SketchPlugin_ConstraintDistance>(*aFeat);
387 aFilletApex = createFilletApex(theFilletPoints[0]->pnt());
388 // update attributes of distance constraints
389 bool isUpdated = false;
390 for (int attrInd = 0; attrInd < CONSTRAINT_ATTR_SIZE && !isUpdated; ++attrInd) {
391 AttributeRefAttrPtr aRefAttr =
392 aDistance->refattr(SketchPlugin_Constraint::ATTRIBUTE(attrInd));
393 if (aRefAttr && !aRefAttr->isObject() &&
394 (aRefAttr->attr() == theFilletPoints[0] || aRefAttr->attr() == theFilletPoints[1])) {
395 aRefAttr->setAttr(aFilletApex->attribute(SketchPlugin_Point::COORD_ID()));
399 // avoid distance from removing if it is updated
400 std::set<FeaturePtr>::iterator aKeepIt = aFeat++;
402 theFeaturesToRemove.erase(aKeepIt);
405 std::shared_ptr<SketchPlugin_ConstraintLength> aLength =
406 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*aFeat);
409 aFilletApex = createFilletApex(theFilletPoints[0]->pnt());
410 // remove Length, but create new distance constraint
411 AttributeRefAttrPtr aRefAttr =
412 aLength->refattr(SketchPlugin_Constraint::ENTITY_A());
413 FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
415 aLengthToDistance.push_back(Length());
416 Length& aNewLength = aLengthToDistance.back();
418 for (int i = 0; i < 2; ++i) {
419 AttributePtr anAttr = aLine->attribute(
420 i == 0 ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
421 if (anAttr == theFilletPoints[0] || anAttr == theFilletPoints[1])
422 aNewLength.myPoints[i] = aFilletApex->attribute(SketchPlugin_Point::COORD_ID());
424 aNewLength.myPoints[i] = anAttr;
427 AttributeDoublePtr aValue = aLength->real(SketchPlugin_Constraint::VALUE());
428 aNewLength.myValueDouble = aValue->value();
429 aNewLength.myValueText = aValue->text();
430 // auxiliary attributes
431 AttributePoint2DPtr aFlyoutAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
432 aLength->attribute(SketchPlugin_ConstraintLength::FLYOUT_VALUE_PNT()));
433 if (aFlyoutAttr && aFlyoutAttr->isInitialized())
434 aNewLength.myFlyoutPoint = SketchPlugin_Tools::flyoutPointCoordinates(aLength);
435 AttributeIntegerPtr aLocationAttr =
436 aLength->integer(SketchPlugin_ConstraintLength::LOCATION_TYPE_ID());
437 if (aLocationAttr && aLocationAttr->isInitialized())
438 aNewLength.myLocationType = aLocationAttr->value();
440 aNewLength.myLocationType = -1;
449 ModelAPI_Tools::removeFeaturesAndReferences(theFeaturesToRemove);
450 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
452 // restore Length constraints as point-point distances
453 FeaturePtr aConstraint;
454 std::list<Length>::iterator anIt = aLengthToDistance.begin();
455 for (; anIt != aLengthToDistance.end(); ++anIt) {
456 aConstraint = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
457 SketchPlugin_ConstraintDistance::ID(), anIt->myPoints[0], anIt->myPoints[1]);
459 AttributeDoublePtr aValue = aConstraint->real(SketchPlugin_Constraint::VALUE());
460 if (anIt->myValueText.empty())
461 aValue->setValue(anIt->myValueDouble);
463 aValue->setText(anIt->myValueText);
464 // set flyout point if exists
465 if (anIt->myFlyoutPoint) {
466 AttributePoint2DPtr aFlyoutAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
467 aConstraint->attribute(SketchPlugin_ConstraintDistance::FLYOUT_VALUE_PNT()));
468 aFlyoutAttr->setValue(anIt->myFlyoutPoint);
470 // set location type if initialized
471 if (anIt->myLocationType >= 0) {
472 AttributeIntegerPtr aLocationType =
473 aConstraint->integer(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID());
474 aLocationType->setValue(anIt->myLocationType);
476 aConstraint->execute();
477 ModelAPI_EventCreator::get()->sendUpdated(aConstraint,
478 Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
482 // ========= Auxiliary functions =================
483 void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
484 FeaturePtr theFeature, const std::string& theFeatureAttribute)
486 std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
487 theNewArc->attribute(theNewArcAttribute))->pnt();
488 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
489 theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
492 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const AttributePtr& theAttribute)
494 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
495 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
497 aPoint = aPointAttr->pnt();
501 static std::shared_ptr<GeomAPI_Lin2d> toLine(const FeaturePtr& theFeature)
503 std::shared_ptr<GeomAPI_Lin2d> aLine;
504 if (theFeature->getKind() == SketchPlugin_Line::ID()) {
505 std::shared_ptr<GeomAPI_Pnt2d> aStart =
506 toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) );
507 std::shared_ptr<GeomAPI_Pnt2d> aEnd =
508 toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) );
509 aLine = std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart, aEnd));
514 static std::shared_ptr<GeomAPI_Circ2d> toCircle(const FeaturePtr& theFeature)
516 std::shared_ptr<GeomAPI_Circ2d> aCircle;
517 if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
518 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
519 toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) );
520 std::shared_ptr<GeomAPI_Pnt2d> aStart =
521 toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) );
522 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aStart));
528 void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
529 double theFilletRadius,
530 const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
531 std::shared_ptr<GeomAPI_XY>& theCenter,
532 std::shared_ptr<GeomAPI_XY>& theTangentA,
533 std::shared_ptr<GeomAPI_XY>& theTangentB)
535 GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
536 GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
538 GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane);
539 aCircBuilder.addTangentCurve(aShapeA);
540 aCircBuilder.addTangentCurve(aShapeB);
541 aCircBuilder.setRadius(theFilletRadius);
543 std::shared_ptr<GeomAPI_Circ2d> aFilletCircle = aCircBuilder.circle();
547 theCenter = aFilletCircle->center()->xy();
549 std::shared_ptr<GeomAPI_Pnt2d> aTgPoints[2];
550 for (int i = 0; i < 2; ++i) {
551 std::shared_ptr<GeomAPI_Circ2d> aCircle = toCircle(theFilletFeatures[i]);
553 aTgPoints[i] = aCircle->project(aFilletCircle->center());
555 std::shared_ptr<GeomAPI_Lin2d> aLine = toLine(theFilletFeatures[i]);
557 aTgPoints[i] = aLine->project(aFilletCircle->center());
560 theTangentA = aTgPoints[0]->xy();
561 theTangentB = aTgPoints[1]->xy();
564 double calculateFilletRadius(FeaturePtr theFilletFeatures[2])
566 double aLengths[2] = { 0, 0 };
567 for (int i = 0; i < 2; ++i) {
568 GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape();
569 std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(aShape);
571 aLengths[i] = anEdge->length();
573 return (aLengths[0] < aLengths[1] ? aLengths[0] : aLengths[1]) / 6.0;
576 std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
577 const AttributePtr theAttribute) {
578 std::set<FeaturePtr> aFeaturesToBeRemoved;
579 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
580 std::list<ResultPtr> aResults = theFeature->results();
581 for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
582 aResultsIt != aResults.cend();
584 ResultPtr aResult = *aResultsIt;
585 std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
586 aRefs.insert(aResultRefs.begin(), aResultRefs.end());
588 for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
589 anIt != aRefs.cend();
591 std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
592 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
593 if(aFeature->getKind() == SketchPlugin_Fillet::ID()) {
596 if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID()
597 || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()
598 || aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
599 aFeaturesToBeRemoved.insert(aFeature);
601 std::list<AttributePtr> anAttrs =
602 aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
603 for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
604 aRefAttrsIt != anAttrs.cend();
606 AttributeRefAttrPtr anAttrRefAttr =
607 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
608 if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
609 aFeaturesToBeRemoved.insert(aFeature);
614 return aFeaturesToBeRemoved;