1 // Copyright (C) 2014-2019 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
20 #include "SketchPlugin_Tools.h"
22 #include "SketchPlugin_Arc.h"
23 #include "SketchPlugin_Circle.h"
24 #include "SketchPlugin_ConstraintCoincidence.h"
25 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
26 #include "SketchPlugin_ConstraintLength.h"
27 #include "SketchPlugin_ConstraintTangent.h"
28 #include "SketchPlugin_Ellipse.h"
29 #include "SketchPlugin_EllipticArc.h"
30 #include "SketchPlugin_Line.h"
31 #include "SketchPlugin_Point.h"
32 #include "SketchPlugin_Projection.h"
33 #include "SketchPlugin_SketchEntity.h"
34 #include "SketchPlugin_Split.h"
35 #include "SketchPlugin_Trim.h"
37 #include <SketcherPrs_Tools.h>
39 #include <ModelAPI_AttributeDouble.h>
40 #include <ModelAPI_AttributeInteger.h>
42 #include <ModelGeomAlgo_Point2D.h>
43 #include <ModelGeomAlgo_Shape.h>
45 #include <GeomAPI_Dir2d.h>
46 #include <GeomAPI_Edge.h>
47 #include <GeomAPI_Pnt2d.h>
48 #include <GeomAPI_XY.h>
50 #include <GeomAlgoAPI_CompoundBuilder.h>
51 #include <GeomAlgoAPI_ShapeTools.h>
53 #include <GeomDataAPI_Point.h>
54 #include <GeomDataAPI_Point2D.h>
60 namespace SketchPlugin_Tools {
62 void clearExpressions(AttributeDoublePtr theAttribute)
64 theAttribute->setText(std::string());
67 void clearExpressions(AttributePointPtr theAttribute)
69 theAttribute->setText(std::string(), std::string(), std::string());
72 void clearExpressions(AttributePoint2DPtr theAttribute)
74 theAttribute->setText(std::string(), std::string());
77 void clearExpressions(AttributePtr theAttribute)
80 AttributeDoublePtr anAttributeDouble =
81 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
82 if (anAttributeDouble.get())
83 clearExpressions(anAttributeDouble);
85 AttributePointPtr anAttributePoint =
86 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
87 if (anAttributePoint.get())
88 clearExpressions(anAttributePoint);
90 AttributePoint2DPtr anAttributePoint2D =
91 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
92 if (anAttributePoint2D.get())
93 clearExpressions(anAttributePoint2D);
96 void clearExpressions(FeaturePtr theFeature)
98 if (!theFeature.get())
101 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
102 std::list<AttributePtr>::iterator anAttributeIt = anAttributes.begin();
103 for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
104 clearExpressions(*anAttributeIt);
108 std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin)
110 std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
111 SketchPlugin_Constraint::ENTITY_A());
112 if (aPnt.get() == NULL)
113 aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
117 std::set<FeaturePtr> findCoincidentConstraints(const ObjectPtr& theObject)
119 std::set<FeaturePtr> aCoincident;
120 const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
121 std::set<AttributePtr>::const_iterator aIt;
122 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
123 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
124 if (aConstrFeature && (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
125 aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()))
126 aCoincident.insert(aConstrFeature);
131 void findCoincidences(const FeaturePtr theStartCoin,
132 const std::string& theAttr,
133 std::set<FeaturePtr>& theList,
134 const bool theIsAttrOnly)
136 AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
140 FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
141 if(theList.find(aObj) == theList.end()) {
142 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincidencePoint(theStartCoin);
143 if(aOrig.get() == NULL) {
146 if(!theIsAttrOnly || !aPnt->isObject()) {
147 theList.insert(aObj);
149 std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(aObj);
150 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
151 for (; aCIt != aCoincidences.end(); ++aCIt) {
152 FeaturePtr aConstrFeature = *aCIt;
153 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincidencePoint(aConstrFeature);
154 if(aPnt.get() && aOrig->isEqual(aPnt)) {
155 findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A(),
156 theList, theIsAttrOnly);
157 findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B(),
158 theList, theIsAttrOnly);
164 std::set<FeaturePtr> findFeaturesCoincidentToPoint(const AttributePoint2DPtr& thePoint)
166 std::set<FeaturePtr> aCoincidentFeatures;
168 FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
169 aCoincidentFeatures.insert(anOwner);
171 std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(anOwner);
172 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
173 for (; aCIt != aCoincidences.end(); ++aCIt) {
174 bool isPointUsedInCoincidence = false;
175 AttributeRefAttrPtr anOtherCoincidentAttr;
176 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
177 AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
180 if (!aRefAttr->isObject() && aRefAttr->attr() == thePoint)
181 isPointUsedInCoincidence = true;
183 anOtherCoincidentAttr = aRefAttr;
186 if (isPointUsedInCoincidence) {
188 if (anOtherCoincidentAttr->isObject())
189 anObj = anOtherCoincidentAttr->object();
191 anObj = anOtherCoincidentAttr->attr()->owner();
192 aCoincidentFeatures.insert(ModelAPI_Feature::feature(anObj));
196 return aCoincidentFeatures;
199 // Container for point-point coincidences.
200 // Useful to find points coincident to a given point.
201 class CoincidentPoints
203 static const int THE_DEFAULT_INDEX = -1;
206 void addCoincidence(const AttributePtr& thePoint1, const int theIndex1,
207 const AttributePtr& thePoint2, const int theIndex2)
209 auto aFound1 = find(thePoint1, theIndex1);
210 auto aFound2 = find(thePoint2, theIndex2);
211 if (aFound1 == myCoincidentPoints.end()) {
212 if (aFound2 == myCoincidentPoints.end()) {
213 std::map<AttributePtr, std::set<int> > aNewSet;
214 aNewSet[thePoint1].insert(theIndex1);
216 aNewSet[thePoint2].insert(theIndex2);
217 myCoincidentPoints.push_back(aNewSet);
219 (*aFound2)[thePoint1].insert(theIndex1);
220 } else if (aFound2 == myCoincidentPoints.end()) {
222 (*aFound1)[thePoint2].insert(theIndex2);
224 for (auto it = aFound2->begin(); it != aFound2->end(); ++it)
225 (*aFound1)[it->first].insert(it->second.begin(), it->second.end());
226 myCoincidentPoints.erase(aFound2);
230 void coincidentPoints(const AttributePoint2DPtr& thePoint,
231 std::set<AttributePoint2DPtr>& thePoints,
232 std::map<AttributePoint2DArrayPtr, int>& thePointsInArray)
234 collectCoincidentPoints(thePoint);
236 auto aFound = find(thePoint, THE_DEFAULT_INDEX);
237 if (aFound != myCoincidentPoints.end()) {
238 for (auto it = aFound->begin(); it != aFound->end(); ++it) {
239 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(it->first);
241 thePoints.insert(aPoint);
243 AttributePoint2DArrayPtr aPointArray =
244 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(it->first);
246 thePointsInArray[aPointArray] = *it->second.begin();
253 void coincidences(const FeaturePtr& theFeature,
254 std::set<FeaturePtr>& theCoincidences) const
256 // iterate through coincideces for the given feature
257 std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
258 if (theFeature->getKind() == SketchPlugin_Point::ID()) {
259 std::set<FeaturePtr> aCoincToRes =
260 SketchPlugin_Tools::findCoincidentConstraints(theFeature->lastResult());
261 aCoincidences.insert(aCoincToRes.begin(), aCoincToRes.end());
262 }
\r std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
263 for (; aCIt != aCoincidences.end(); ++aCIt)
265 if (theCoincidences.find(*aCIt) != theCoincidences.end())
266 continue; // already processed
267 theCoincidences.insert(*aCIt);
268 // iterate on coincident attributes
269 for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
270 AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
274 if (aRefAttr->isObject()) {
275 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
276 if (aFeature->getKind() == SketchPlugin_Point::ID())
280 anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
281 if (anOwner && anOwner != theFeature)
282 coincidences(anOwner, theCoincidences);
287 // Iteratively search points coincident to the given point
288 // (two points may be coincident through the third point)
289 void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
291 AttributePtr aPoints[2];
292 int anIndicesInArray[2];
294 FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
295 std::set<FeaturePtr> aCoincidences;
296 coincidences(anOwner, aCoincidences);
298 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
299 for (; aCIt != aCoincidences.end(); ++aCIt) {
300 aPoints[0] = aPoints[1] = AttributePtr();
301 anIndicesInArray[0] = anIndicesInArray[1] = THE_DEFAULT_INDEX;
302 for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
303 AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
306 if (aRefAttr->isObject()) {
307 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
308 if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
309 aPoints[aPtInd++] = aFeature->attribute(SketchPlugin_Point::COORD_ID());
312 AttributePoint2DPtr aPointAttr =
313 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
314 AttributePoint2DArrayPtr aPointArray =
315 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(aRefAttr->attr());
317 aPoints[aPtInd++] = aPointAttr;
318 else if (aPointArray) {
319 AttributeIntegerPtr anIndexAttr = (*aCIt)->integer(i == 0 ?
320 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
321 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
322 aPoints[aPtInd] = aPointArray;
323 anIndicesInArray[aPtInd++] = anIndexAttr->value();
328 if (aPoints[0] && aPoints[1])
329 addCoincidence(aPoints[0], anIndicesInArray[0], aPoints[1], anIndicesInArray[1]);
333 std::list< std::map<AttributePtr, std::set<int> > >::iterator find(const AttributePtr& thePoint,
336 auto aSeek = myCoincidentPoints.begin();
337 for (; aSeek != myCoincidentPoints.end(); ++aSeek) {
338 auto aFound = aSeek->find(thePoint);
339 if (aFound != aSeek->end() && aFound->second.find(theIndex) != aFound->second.end())
342 return myCoincidentPoints.end();
346 std::list< std::map<AttributePtr, std::set<int> > > myCoincidentPoints;
349 std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
351 std::set<AttributePoint2DPtr> aPoints;
352 std::map<AttributePoint2DArrayPtr, int> aPointsInArray;
353 findPointsCoincidentToPoint(thePoint, aPoints, aPointsInArray);
357 void findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint,
358 std::set<AttributePoint2DPtr>& thePoints,
359 std::map<AttributePoint2DArrayPtr, int>& thePointsInArray)
361 CoincidentPoints aCoincidentPoints;
362 aCoincidentPoints.coincidentPoints(thePoint, thePoints, thePointsInArray);
366 void resetAttribute(SketchPlugin_Feature* theFeature,
367 const std::string& theId)
369 AttributePtr anAttr = theFeature->attribute(theId);
375 void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
376 const std::string& theId,
377 const AttributePtr theAttr,
378 const ObjectPtr theObject,
379 const bool theIsCanBeTangent)
381 AttributeRefAttrPtr aRefAttr = theFeature->refattr(theId);
382 if(aRefAttr.get() && aRefAttr->isInitialized()) {
383 FeaturePtr aConstraint;
384 if(!theIsCanBeTangent) {
385 aConstraint = theFeature->sketch()
386 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
388 if(aRefAttr->isObject()) {
389 ObjectPtr anObject = aRefAttr->object();
390 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
391 if(aFeature->getKind() == SketchPlugin_Point::ID()) {
392 aConstraint = theFeature->sketch()
393 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
395 aConstraint = theFeature->sketch()
396 ->addFeature(SketchPlugin_ConstraintTangent::ID());
399 aConstraint = theFeature->sketch()
400 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
403 AttributeRefAttrPtr aRefAttrA = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
404 aRefAttr->isObject() ? aRefAttrA->setObject(aRefAttr->object())
405 : aRefAttrA->setAttr(aRefAttr->attr());
406 AttributeRefAttrPtr aRefAttrB = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
407 if(theObject.get()) {
408 aRefAttrB->setObject(theObject);
409 } else if(theAttr.get()) {
410 aRefAttrB->setAttr(theAttr);
415 void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr& theRefAttr,
416 const AttributePtr& theDefaultAttr,
417 std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
418 std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
420 AttributePtr anAttr = theDefaultAttr;
421 if (theRefAttr->isObject()) {
422 FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
424 if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
425 theTangentCurve = aTgFeature->lastResult()->shape();
428 anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
431 anAttr = theRefAttr->attr();
433 thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
437 FeaturePtr createConstraintAttrAttr(SketchPlugin_Sketch* theSketch,
438 const std::string& theConstraintId,
439 const AttributePtr& theFirstAttribute,
440 const AttributePtr& theSecondAttribute)
442 FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
443 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
444 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
445 aRefAttr->setAttr(theFirstAttribute);
447 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
448 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
449 aRefAttr->setAttr(theSecondAttribute);
451 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
452 std::cout << "<createConstraint to attribute> :"
453 << " first attribute - " << theFirstAttribute->id()
454 << " second attribute - " << theSecondAttribute->id()
461 FeaturePtr createConstraintAttrObject(SketchPlugin_Sketch* theSketch,
462 const std::string& theConstraintId,
463 const AttributePtr& theFirstAttribute,
464 const ObjectPtr& theSecondObject)
466 FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
467 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
468 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
469 aRefAttr->setAttr(theFirstAttribute);
471 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
472 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
473 aRefAttr->setObject(theSecondObject);
475 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
476 std::cout << "<createConstraint to attribute> :"
477 << " first attribute - " << theFirstAttribute->id()
478 << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
485 FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
486 const std::string& theConstraintId,
487 const ObjectPtr& theFirstObject,
488 const ObjectPtr& theSecondObject)
490 FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
491 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
492 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
493 aRefAttr->setObject(theFirstObject);
495 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
496 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
497 aRefAttr->setObject(theSecondObject);
499 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
500 std::cout << "<createConstraint to attribute> :"
501 << " first object - " << ModelAPI_Feature::feature(theFirstObject)->getKind()
502 << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
509 void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
510 const std::string& theEllipsePoint)
512 SketchPlugin_Sketch* aSketch =
513 std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
515 FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
516 aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
517 aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
519 AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
520 theEllipseFeature->attribute(theEllipsePoint));
522 AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
523 aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
524 aCoord->setValue(anElPoint->x(), anElPoint->y());
526 aPointFeature->execute();
527 std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
528 aPointFeature->data()->setName(aName);
529 aPointFeature->lastResult()->data()->setName(aName);
531 createConstraintAttrAttr(aSketch,
532 SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
535 void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
536 const std::string& theStartPoint,
537 const std::string& theEndPoint)
539 SketchPlugin_Sketch* aSketch =
540 std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
542 FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
543 aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
544 aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
546 AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
547 theEllipseFeature->attribute(theStartPoint));
548 AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
549 theEllipseFeature->attribute(theEndPoint));
551 AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
552 aLineFeature->attribute(SketchPlugin_Line::START_ID()));
553 aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
555 AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
556 aLineFeature->attribute(SketchPlugin_Line::END_ID()));
557 aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
559 aLineFeature->execute();
560 std::string aName = theEllipseFeature->name() + "_" +
561 (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
562 aLineFeature->data()->setName(aName);
563 aLineFeature->lastResult()->data()->setName(aName);
565 createConstraintAttrAttr(aSketch,
566 SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
567 createConstraintAttrAttr(aSketch,
568 SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
571 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
573 // currently process Length constraints only
574 if (theConstraint->getKind() != SketchPlugin_ConstraintLength::ID())
575 return GeomPnt2dPtr();
577 AttributeRefAttrPtr aLineAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
578 if (!aLineAttr || !aLineAttr->isObject())
579 return GeomPnt2dPtr();
580 FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
581 if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
582 return GeomPnt2dPtr();
584 std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
585 aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
586 std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
587 aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
589 std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
590 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
591 theConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
592 std::shared_ptr<GeomAPI_Pnt2d> aFltPnt = aFlyoutAttr->pnt();
594 std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
596 double X = aStartPnt->x() + aFltPnt->x() * aLineDir->x() - aFltPnt->y() * aLineDir->y();
597 double Y = aStartPnt->y() + aFltPnt->x() * aLineDir->y() + aFltPnt->y() * aLineDir->x();
599 return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
603 void customizeFeaturePrs(const AISObjectPtr& thePrs, bool isAxiliary)
605 std::vector<int> aColor;
608 thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
609 aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
610 aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
613 thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
614 aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
615 aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
617 thePrs->setWidth(aWidth);
618 thePrs->setColor(aColor[0], aColor[1], aColor[2]);
621 void setDimensionColor(const AISObjectPtr& theDimPrs)
623 std::vector<int> aColor = Config_PropManager::color("Visualization", "sketch_dimension_color");
624 if (aColor.size() == 3)
625 theDimPrs->setColor(aColor[0], aColor[1], aColor[2]);
628 void replaceInName(ObjectPtr theObject, const std::string& theSource, const std::string& theDest)
630 std::string aName = theObject->data()->name();
631 size_t aPos = aName.find(theSource);
632 if (aPos != std::string::npos) {
633 std::string aNewName = aName.substr(0, aPos) + theDest
634 + aName.substr(aPos + theSource.size());
635 theObject->data()->setName(aNewName);
639 } // namespace SketchPlugin_Tools
642 // =================================================================================================
643 // namespace SketchPlugin_SegmentationTools
644 // =================================================================================================
646 void SketchPlugin_SegmentationTools::getFeaturePoints(const FeaturePtr& theFeature,
647 AttributePoint2DPtr& theStartPointAttr,
648 AttributePoint2DPtr& theEndPointAttr)
650 std::string aFeatureKind = theFeature->getKind();
651 std::string aStartAttributeName, anEndAttributeName;
652 if (aFeatureKind == SketchPlugin_Line::ID()) {
653 aStartAttributeName = SketchPlugin_Line::START_ID();
654 anEndAttributeName = SketchPlugin_Line::END_ID();
656 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
657 aStartAttributeName = SketchPlugin_Arc::START_ID();
658 anEndAttributeName = SketchPlugin_Arc::END_ID();
660 else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
661 aStartAttributeName = SketchPlugin_EllipticArc::START_POINT_ID();
662 anEndAttributeName = SketchPlugin_EllipticArc::END_POINT_ID();
664 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
665 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
666 theFeature->attribute(aStartAttributeName));
667 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
668 theFeature->attribute(anEndAttributeName));
673 void SketchPlugin_SegmentationTools::getRefAttributes(
674 const FeaturePtr& theFeature,
675 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
676 std::list<AttributePtr>& theRefsToFeature)
680 std::list<AttributePtr> aPointAttributes =
681 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
682 std::set<AttributePtr> aPointAttributesSet;
684 std::list<AttributePtr>::const_iterator aPIt =
685 aPointAttributes.begin(), aPLast = aPointAttributes.end();
686 for (; aPIt != aPLast; aPIt++)
687 aPointAttributesSet.insert(*aPIt);
689 std::set<AttributePtr> aRefsAttributes = theFeature->lastResult()->data()->refsToMe();
690 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
691 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
693 std::set<AttributePtr>::const_iterator aIt;
694 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
695 AttributePtr anAttr = (*aIt);
696 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
697 if (!anAttrFeature->isMacro() && // <- skip reference from Trim or Split feature
698 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
699 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
700 if (!aRefAttr->isObject()) { // find attributes referenced to feature point attributes
701 AttributePtr anAttrInRef = aRefAttr->attr();
702 if (anAttrInRef.get() &&
703 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
704 if (theRefs.find(anAttrInRef) != theRefs.end())
705 theRefs[anAttrInRef].push_back(aRefAttr);
707 std::list<AttributePtr> anAttrList;
708 anAttrList.push_back(aRefAttr);
709 theRefs[anAttrInRef] = anAttrList;
713 else { // find attributes referenced to feature itself
714 theRefsToFeature.push_back(anAttr);
720 GeomShapePtr SketchPlugin_SegmentationTools::getSubShape(
721 SketchPlugin_Feature* theFeature,
722 const std::string& theObjectAttributeId,
723 const std::string& thePointAttributeId,
724 std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
725 std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
727 GeomShapePtr aBaseShape;
729 AttributeReferencePtr anObjectAttr = theFeature->reference(theObjectAttributeId);
730 ObjectPtr aBaseObject = anObjectAttr->value();
731 if (!aBaseObject.get())
735 AttributePoint2DPtr aPointAttr =
736 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(thePointAttributeId));
737 std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
738 std::shared_ptr<GeomAPI_Pnt> anAttributePnt =
739 theFeature->sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
741 if (theCashedShapes.find(aBaseObject) == theCashedShapes.end())
742 fillObjectShapes(theFeature, aBaseObject, theCashedShapes, theObjectToPoints);
744 std::shared_ptr<GeomAPI_Pnt> aStartPoint;
745 std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
746 const std::set<GeomShapePtr>& aShapes = theCashedShapes[aBaseObject];
747 std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
748 for (; anIt != aLast; anIt++) {
749 GeomShapePtr aCurrentShape = *anIt;
750 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
751 if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
752 if (theFeature->getKind() == SketchPlugin_Split::ID()) {
753 // for Split operation collect start and end points of the shape
754 if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
755 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
756 aStartPoint = anEdge->firstPoint();
757 aSecondPoint = anEdge->lastPoint();
761 aBaseShape = aCurrentShape;
766 if (!aStartPoint.get() || !aSecondPoint.get())
769 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
770 if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
771 ResultPtr aResult = aBaseFeature->lastResult();
772 GeomShapePtr aResultShape = aResult->shape();
773 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
775 aPoints.push_back(aStartPoint);
776 aPoints.push_back(aSecondPoint);
778 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
779 GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
780 aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
785 void SketchPlugin_SegmentationTools::fillObjectShapes(
786 SketchPlugin_Feature* theOpFeature,
787 const ObjectPtr& theObject,
788 std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
789 std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
791 SketchPlugin_Sketch* aSketch = theOpFeature->sketch();
793 GeomAlgoAPI_ShapeTools::PointToRefsMap aPoints;
794 std::set<GeomShapePtr> aShapes;
796 std::set<AttributePoint2DPtr > aRefAttributes;
798 FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
799 std::set<ResultPtr> anEdgeShapes;
801 ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
802 if (!anEdgeShapes.empty()) {
803 GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
805 // coincidences to the feature
806 ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
807 aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
808 // layed on feature coincidences to divide it on several shapes
809 std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
810 std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
811 aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
812 std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
813 aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
814 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
815 aData->attribute(SketchPlugin_Sketch::NORM_ID()));
816 std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
818 ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
819 aX->dir(), aY, aPoints);
821 if (theOpFeature->getKind() == SketchPlugin_Trim::ID()) {
822 // collect all intersection points with other edges for Trim operation only
823 std::list<FeaturePtr> aFeatures;
824 for (int i = 0; i < aSketch->numberOfSubs(); i++) {
825 FeaturePtr aFeature = aSketch->subFeature(i);
826 if (aFeature.get() && aFeature->getKind() != SketchPlugin_Projection::ID())
827 aFeatures.push_back(aFeature);
829 ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPoints);
832 if (!aPoints.empty())
833 GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes);
835 theObjectToPoints[theObject] = aPoints;
836 theCashedShapes[theObject] = aShapes;
839 void SketchPlugin_SegmentationTools::updateRefAttConstraints(
840 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
841 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
843 #if defined DEBUG_SPLIT || defined DEBUG_TRIM
844 std::cout << "updateRefAttConstraints" << std::endl;
847 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
848 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
849 for (; anIt != aLast; anIt++) {
850 AttributePtr anAttribute = anIt->first;
851 AttributePtr aNewAttribute = anIt->second;
853 // not found in references
854 if (!aNewAttribute.get() ||
855 theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
857 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
858 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
859 aRLast = aRefAttributes.end();
861 for (; aRefIt != aRLast; aRefIt++) {
862 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
863 if (aRefAttr.get()) {
864 aRefAttr->setAttr(aNewAttribute);
866 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
867 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
874 void SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(
875 const std::set<FeaturePtr>& theFeaturesToUpdate)
877 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
878 aLast = theFeaturesToUpdate.end();
879 for (; anIt != aLast; anIt++) {
880 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
881 std::string aRefFeatureKind = aRefFeature->getKind();
882 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
883 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
884 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
885 if (aLenghtFeature.get()) {
886 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
887 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
889 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
890 aValueAttr->setValue(aValue);
896 AISObjectPtr SketchPlugin_SegmentationTools::getAISObject(
897 AISObjectPtr thePrevious,
898 SketchPlugin_Feature* theOpFeature,
899 const std::string& thePreviewObjectAttrName,
900 const std::string& thePreviewPointAttrName,
901 const std::string& theSelectedObjectAttrName,
902 const std::string& theSelectedPointAttrName)
904 #if defined DEBUG_SPLIT || defined DEBUG_TRIM_METHODS
905 std::cout << "getAISObject: " << theOpFeature->data()->name() << std::endl;
908 AISObjectPtr anAIS = thePrevious;
910 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
911 std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
912 std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap> aObjectToPoints;
913 GeomShapePtr aPreviewShape = getSubShape(theOpFeature,
914 thePreviewObjectAttrName, thePreviewPointAttrName, aCashedShapes, aObjectToPoints);
915 if (aPreviewShape.get())
916 aShapes.push_back(aPreviewShape);
917 GeomShapePtr aSelectedShape = getSubShape(theOpFeature,
918 theSelectedObjectAttrName, theSelectedPointAttrName, aCashedShapes, aObjectToPoints);
919 if (aSelectedShape.get())
920 aShapes.push_back(aSelectedShape);
923 return AISObjectPtr();
925 GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
926 if (!aBaseShape.get())
927 return AISObjectPtr();
929 if (aBaseShape.get()) {
931 anAIS = AISObjectPtr(new GeomAPI_AISObject);
932 anAIS->createShape(aBaseShape);
934 std::vector<int> aColor;
935 aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
936 double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
937 int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
938 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
939 // width when there is not base object should be extened in several points
940 // in order to see this preview over highlight
941 anAIS->setWidth(aWidth+4);
942 anAIS->setLineStyle(aLineStyle);
945 anAIS = AISObjectPtr();
949 #define GEOM_DATA_POINT2D(f, a) std::dynamic_pointer_cast<GeomDataAPI_Point2D>((f)->attribute(a))
951 FeaturePtr SketchPlugin_SegmentationTools::createLineFeature(
952 const FeaturePtr& theBaseFeature,
953 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
954 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
957 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
958 std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
959 SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
960 if (!aSketch || !theBaseFeature.get())
963 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
965 GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::START_ID())->setValue(theFirstPoint);
966 GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::END_ID())->setValue(theSecondPoint);
968 aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
969 theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
970 aFeature->execute(); // to obtain result
978 std::string myCenter;
982 std::string myReversed;
986 ArcAttributes(const std::string& theKind) : myKind(theKind)
988 if (myKind == SketchPlugin_Arc::ID()) {
989 myCenter = SketchPlugin_Arc::CENTER_ID();
990 myStart = SketchPlugin_Arc::START_ID();
991 myEnd = SketchPlugin_Arc::END_ID();
992 myReversed = SketchPlugin_Arc::REVERSED_ID();
994 else if (myKind == SketchPlugin_Circle::ID()) {
995 myCenter = SketchPlugin_Circle::CENTER_ID();
997 else if (myKind == SketchPlugin_Ellipse::ID()) {
998 myCenter = SketchPlugin_Ellipse::CENTER_ID();
999 myFocus = SketchPlugin_Ellipse::FIRST_FOCUS_ID();
1001 else if (myKind == SketchPlugin_EllipticArc::ID()) {
1002 myCenter = SketchPlugin_EllipticArc::CENTER_ID();
1003 myFocus = SketchPlugin_EllipticArc::FIRST_FOCUS_ID();
1004 myStart = SketchPlugin_EllipticArc::START_POINT_ID();
1005 myEnd = SketchPlugin_EllipticArc::END_POINT_ID();
1006 myReversed = SketchPlugin_EllipticArc::REVERSED_ID();
1011 FeaturePtr SketchPlugin_SegmentationTools::createArcFeature(
1012 const FeaturePtr& theBaseFeature,
1013 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
1014 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
1016 FeaturePtr aFeature;
1017 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1018 std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
1019 SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
1020 if (!aSketch || !theBaseFeature.get())
1023 ArcAttributes aBaseAttrs(theBaseFeature->getKind());
1024 ArcAttributes aTargetAttrs;
1025 if (aBaseAttrs.myKind == SketchPlugin_Arc::ID() ||
1026 aBaseAttrs.myKind == SketchPlugin_Circle::ID())
1027 aTargetAttrs = ArcAttributes(SketchPlugin_Arc::ID());
1028 else if (aBaseAttrs.myKind == SketchPlugin_Ellipse::ID() ||
1029 aBaseAttrs.myKind == SketchPlugin_EllipticArc::ID())
1030 aTargetAttrs = ArcAttributes(SketchPlugin_EllipticArc::ID());
1032 if (aTargetAttrs.myKind.empty())
1035 aFeature = aSketch->addFeature(aTargetAttrs.myKind);
1036 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1037 // the "attribute updated"
1038 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1039 bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1041 GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myCenter)->setValue(
1042 GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myCenter)->pnt());
1043 if (!aTargetAttrs.myFocus.empty()) {
1044 GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myFocus)->setValue(
1045 GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myFocus)->pnt());
1047 GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myStart)->setValue(theFirstPoint);
1048 GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myEnd)->setValue(theSecondPoint);
1050 aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
1051 theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
1053 /// fill referersed state of created arc as it is on the base arc
1054 bool aReversed = aBaseAttrs.myReversed.empty() ? false :
1055 theBaseFeature->boolean(aBaseAttrs.myReversed)->value();
1056 aFeature->boolean(aTargetAttrs.myReversed)->setValue(aReversed);
1058 aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
1059 aFeature->data()->blockSendAttributeUpdated(aWasBlocked);