1 // Copyright (C) 2014-2020 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_ConstraintAngle.h"
21 #include <SketchPlugin_Line.h>
22 #include <SketchPlugin_Tools.h>
23 #include <SketcherPrs_Tools.h>
25 #include <ModelAPI_AttributeDouble.h>
26 #include <ModelAPI_AttributeInteger.h>
27 #include <ModelAPI_EventReentrantMessage.h>
28 #include <ModelAPI_Session.h>
29 #include <ModelAPI_Validator.h>
31 #include <GeomDataAPI_Point2D.h>
33 #include <GeomAPI_Angle2d.h>
34 #include <GeomAPI_Dir2d.h>
35 #include <GeomAPI_Lin2d.h>
36 #include <GeomAPI_Pnt2d.h>
37 #include <GeomAPI_XY.h>
39 #include <SketcherPrs_Factory.h>
40 #include <SketcherPrs_Tools.h>
46 const double tolerance = 1.e-7;
47 #define PI 3.1415926535897932
49 /// \brief Calculate intersection point of two lines
50 static std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2);
53 SketchPlugin_ConstraintAngle::SketchPlugin_ConstraintAngle()
55 myFlyoutUpdate = false;
58 void SketchPlugin_ConstraintAngle::initAttributes()
60 ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
62 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
63 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
64 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
65 data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
67 data()->addAttribute(ANGLE_VALUE_ID(), ModelAPI_AttributeDouble::typeId());
68 data()->addAttribute(TYPE_ID(), ModelAPI_AttributeInteger::typeId());
70 data()->addAttribute(ANGLE_REVERSED_FIRST_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
71 data()->addAttribute(ANGLE_REVERSED_SECOND_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
73 data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
74 aValidators->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
76 data()->addAttribute(PREV_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
77 data()->attribute(PREV_TYPE_ID())->setIsArgument(false);
78 aValidators->registerNotObligatory(getKind(), PREV_TYPE_ID());
79 if (attribute(TYPE_ID())->isInitialized())
80 integer(PREV_TYPE_ID())->setValue(integer(TYPE_ID())->value());
82 data()->addAttribute(SELECTED_FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
83 data()->attribute(SELECTED_FIRST_POINT_ID())->setIsArgument(false);
84 aValidators->registerNotObligatory(getKind(), SELECTED_FIRST_POINT_ID());
86 data()->addAttribute(SELECTED_SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
87 data()->attribute(SELECTED_SECOND_POINT_ID())->setIsArgument(false);
88 aValidators->registerNotObligatory(getKind(), SELECTED_SECOND_POINT_ID());
90 AttributeIntegerPtr aVerAttr = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(
91 data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId()));
92 aVerAttr->setIsArgument(false);
93 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
94 if (!aVerAttr->isInitialized()) {
95 // this is a newly created feature (not read from file),
96 // so, initialize the latest version
97 aVerAttr->setValue(THE_VERSION_1);
101 void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName,
102 std::string& theDefault)
104 theSection = "Visualization";
105 theName = "sketch_dimension_color";
106 theDefault = SKETCH_DIMENSION_COLOR;
109 void SketchPlugin_ConstraintAngle::execute()
111 std::shared_ptr<ModelAPI_Data> aData = data();
113 AttributeRefAttrPtr anAttrA = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
114 AttributeRefAttrPtr anAttrB = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
115 if (!anAttrA->isInitialized() || !anAttrB->isInitialized())
118 AttributeIntegerPtr aVersion = integer(VERSION_ID());
119 if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
122 AttributeDoublePtr anAttrValue = real(ANGLE_VALUE_ID());
123 if (!anAttrValue->isInitialized())
126 // the value should to be computed here, not in the
127 // getAISObject in order to change the model value
128 // inside the object transaction. This is important for creating a constraint by preselection.
129 // The display of the presentation in this case happens after the transaction commit
130 std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
131 GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
132 if(!aFlyOutAttr->isInitialized())
133 compute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
136 AISObjectPtr SketchPlugin_ConstraintAngle::getAISObject(AISObjectPtr thePrevious)
141 AISObjectPtr anAIS = SketcherPrs_Factory::angleConstraint(this, sketch(),
143 if (anAIS.get() && !thePrevious.get())
144 SketchPlugin_Tools::setDimensionColor(anAIS);
149 std::string SketchPlugin_ConstraintAngle::processEvent(
150 const std::shared_ptr<Events_Message>& theMessage)
152 std::string aFilledAttributeName;
154 std::shared_ptr<ModelAPI_EventReentrantMessage> aReentrantMessage =
155 std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
156 if (aReentrantMessage.get()) {
157 aFilledAttributeName = ENTITY_A();
158 refattr(ENTITY_A())->setObject(aReentrantMessage->selectedObject());
159 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SELECTED_FIRST_POINT_ID()))
160 ->setValue(aReentrantMessage->clickedPoint());
162 return aFilledAttributeName;
166 void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
171 std::shared_ptr<ModelAPI_Data> aData = data();
175 if (theID == TYPE_ID())
178 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
179 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
180 if (!aLineA || !aLineB)
183 AttributeIntegerPtr aVersion = integer(VERSION_ID());
184 if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
187 if (theID == ENTITY_A() || theID == ENTITY_B() ||
188 theID == TYPE_ID() || theID == ANGLE_VALUE_ID()) {
190 } else if (theID == FLYOUT_VALUE_PNT()) {
195 void SketchPlugin_ConstraintAngle::calculateAngle()
197 // update *_REVERSED_* flags
198 calculateAnglePosition();
200 std::shared_ptr<ModelAPI_Data> aData = data();
201 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
202 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
203 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
205 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
206 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
207 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
208 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
210 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
211 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
213 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
214 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
216 AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
217 if (!anAngleValueAttr->isInitialized()) {
218 std::shared_ptr<GeomAPI_Angle2d> anAng(
219 new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
220 anAngleValueAttr->setValue(getAngleForType(fabs(anAng->angleDegree())));
223 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aLine1, false, aLine2, false));
224 double anAngle = anAng->angleDegree();
226 anAngle /= fabs(anAngle);
227 anAngle *= getAngleForType(anAngleValueAttr->value(), isReversed1, isReversed2);
229 // update value of the constraint to be passed to the solver
230 real(SketchPlugin_Constraint::VALUE())->setValue(anAngle);
233 void SketchPlugin_ConstraintAngle::calculateAnglePosition()
235 if (attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
236 attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized())
237 return; // already calculated
239 DataPtr aData = data();
240 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
241 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
243 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
244 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
245 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
246 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
248 bool isReversed1 = false;
249 bool isReversed2 = false;
251 GeomPnt2dPtr aSelected1 = SketcherPrs_Tools::getPoint(this, SELECTED_FIRST_POINT_ID());
252 GeomPnt2dPtr aSelected2 = SketcherPrs_Tools::getPoint(this, SELECTED_SECOND_POINT_ID());
253 if (aSelected1 && aSelected2) {
254 GeomPnt2dPtr anInterPnt = intersect(aLineA, aLineB);
257 std::shared_ptr<GeomAPI_XY> anInterXY = anInterPnt->xy();
258 isReversed1 = aSelected1->xy()->decreased(anInterXY)->dot(
259 aEndA->xy()->decreased(aStartA->xy())) < -tolerance;
260 isReversed2 = aSelected2->xy()->decreased(anInterXY)->dot(
261 aEndB->xy()->decreased(aStartB->xy())) < -tolerance;
264 // no point is selected (document opened or Python script is loaded),
265 // calculate basing on the value
266 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
267 isReversed1 = anAng->isReversed(0);
268 isReversed2 = anAng->isReversed(1);
271 // adjust reversed flags according to the angle type
272 AttributeIntegerPtr aTypeAttr = integer(TYPE_ID());
273 if (aTypeAttr && aTypeAttr->isInitialized() &&
274 (SketcherPrs_Tools::AngleType)(aTypeAttr->value()) == SketcherPrs_Tools::ANGLE_COMPLEMENTARY)
275 isReversed1 = !isReversed1;
277 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
278 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
281 // Convert angle value from the DIRECT to any given type.
282 static double angleForType(const double theAngle, const int theType)
284 double anAngle = theAngle;
285 switch ((SketcherPrs_Tools::AngleType)theType) {
286 case SketcherPrs_Tools::ANGLE_DIRECT:
289 case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
290 anAngle = 180.0 - theAngle;
292 case SketcherPrs_Tools::ANGLE_BACKWARD:
293 anAngle = 360.0 - theAngle;
301 double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle,
305 double anAngle = angleForType(theAngle, integer(TYPE_ID())->value());
306 if (isReversed1 != isReversed2)
307 anAngle = 180.0 - anAngle;
311 // Convert angle value or a text expression from one angle type to another
312 static void convertAngle(AttributeDoublePtr theAngle,
313 const int thePrevType, const int theNewType)
315 if (theAngle->isInitialized()) {
316 if (theAngle->text().empty()) {
317 // calculate value related to the type twice:
318 // the first time - to return to direct angle,
319 // the second time - to apply new type
320 double aValue = angleForType(theAngle->value(), thePrevType);
321 aValue = angleForType(aValue, theNewType);
322 theAngle->setValue(aValue);
325 // process the parametric value
326 std::string anAngleText = theAngle->text();
327 std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)$",
328 std::regex_constants::ECMAScript);
330 double anAnglePrefix = 0.0;
331 static const char aSignPrefix[2] = { '-', '+' };
335 if (std::regex_search(anAngleText, aResult, anAngleRegex)) {
336 anAnglePrefix = std::atof(aResult[1].str().c_str());
337 aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1;
338 anAngleText = aResult[3].str();
341 if (thePrevType != SketcherPrs_Tools::ANGLE_DIRECT)
342 aSignInd = 1 - aSignInd;
343 anAnglePrefix = angleForType(anAnglePrefix, thePrevType);
345 if (theNewType != SketcherPrs_Tools::ANGLE_DIRECT)
346 aSignInd = 1 - aSignInd;
347 anAnglePrefix = angleForType(anAnglePrefix, theNewType);
349 std::ostringstream aText;
350 bool isPrintSign = true;
351 if (fabs(anAnglePrefix) > tolerance)
352 aText << anAnglePrefix;
354 isPrintSign = aSignInd == 0;
356 aText << " " << aSignPrefix[aSignInd] << " (";
357 aText << anAngleText << (isPrintSign ? ")" : "");
358 theAngle->setText(aText.str());
363 void SketchPlugin_ConstraintAngle::updateAngleValue()
365 AttributeIntegerPtr anAngleType = integer(TYPE_ID());
366 AttributeIntegerPtr aPrevAngleType = integer(PREV_TYPE_ID());
367 convertAngle(real(ANGLE_VALUE_ID()), aPrevAngleType->value(), anAngleType->value());
368 aPrevAngleType->setValue(anAngleType->value());
371 static GeomPnt2dPtr lineBoundary(const FeaturePtr& theLine, const bool theReversed,
372 const GeomPnt2dPtr& thePointToAvoid)
374 GeomPnt2dPtr aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
375 theReversed ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
376 if (aPoint->distance(thePointToAvoid) < tolerance) {
377 // extremity is equal to the intersection point,
378 // thus recalculate it using another boundary point
379 aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
380 theReversed ? SketchPlugin_Line::END_ID() : SketchPlugin_Line::START_ID());
381 aPoint->setX(thePointToAvoid->x() * 2.0 - aPoint->x());
382 aPoint->setY(thePointToAvoid->y() * 2.0 - aPoint->y());
387 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
389 if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
394 std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
395 GeomDataAPI_Point2D>(attribute(theAttributeId));
397 DataPtr aData = data();
398 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
399 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
400 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
402 if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
405 // Intersection of lines
406 std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
410 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
411 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
413 int anAngleType = integer(TYPE_ID())->value();
415 bool isSupplementary = anAngleType == (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY;
417 // point on lines to compose an angle
418 GeomPnt2dPtr aPointA = lineBoundary(aLineA, isReversed1 ^ isSupplementary, anInter);
419 GeomPnt2dPtr aPointB = lineBoundary(aLineB, isReversed2, anInter);
421 myFlyoutUpdate = true;
422 if (aFlyOutAttr->isInitialized()) {
423 std::shared_ptr<GeomAPI_XY> aFlyoutPoint = aFlyOutAttr->pnt()->xy();
424 std::shared_ptr<GeomAPI_XY> anInterXY = anInter->xy();
425 std::shared_ptr<GeomAPI_XY> aDirIF = aFlyoutPoint->decreased(anInterXY);
426 std::shared_ptr<GeomAPI_XY> aDirIA = aPointA->xy()->decreased(anInterXY);
427 std::shared_ptr<GeomAPI_XY> aDirIB = aPointB->xy()->decreased(anInterXY);
428 double aSign = aDirIA->cross(aDirIB);
429 aSign /= fabs(aSign);
430 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD)
433 double cross1 = aSign * aDirIA->cross(aDirIF);
434 if (cross1 < -tolerance)
435 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(!isReversed2);
436 double cross2 = aSign * aDirIF->cross(aDirIB);
437 if (cross2 < -tolerance)
438 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(!isReversed1);
440 // the direction is reversed only once
441 if ((cross1 + tolerance) * (cross2 + tolerance) < 0.0) {
442 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
443 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_BACKWARD,
444 (int)SketcherPrs_Tools::ANGLE_DIRECT);
446 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
447 (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY);
448 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
449 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
450 (int)SketcherPrs_Tools::ANGLE_BACKWARD);
457 // default position of the presentation
458 double aX = (aPointA->x() + aPointB->x() + anInter->x()) / 3.;
459 double aY = (aPointA->y() + aPointB->y() + anInter->y()) / 3.;
460 aFlyOutAttr->setValue(aX, aY);
462 myFlyoutUpdate = false;
467 void SketchPlugin_ConstraintAngle::updateVersion()
469 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
471 // Calculate angle value by the old algorithm and
472 // update the corresponding attribute to meet the new requirements.
473 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_A());
474 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_B());
476 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
477 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
478 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
479 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
481 std::shared_ptr<GeomAPI_Angle2d> anAng;
483 if (boolean(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
484 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) {
485 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
486 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
488 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
489 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
490 anAng.reset(new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
493 anAng.reset(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
495 bool isReversed1 = anAng->isReversed(0);
496 bool isReversed2 = anAng->isReversed(1);
498 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
499 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
501 double anAngleValue = anAng->angleDegree();
502 double aConstValue = real(ANGLE_VALUE_ID())->value();
504 AttributeIntegerPtr aType = integer(TYPE_ID());
505 switch ((SketcherPrs_Tools::AngleType)aType->value()) {
506 case SketcherPrs_Tools::ANGLE_DIRECT:
507 if (anAngleValue < 0.0 && aConstValue > 180.0)
508 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_BACKWARD,
509 SketcherPrs_Tools::ANGLE_DIRECT);
511 case SketcherPrs_Tools::ANGLE_BACKWARD:
512 if (anAngleValue < 0.0 && aConstValue < 180.0)
513 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_DIRECT,
514 SketcherPrs_Tools::ANGLE_BACKWARD);
519 data()->blockSendAttributeUpdated(aWasBlocked, false);
520 integer(VERSION_ID())->setValue(THE_VERSION_1);
524 // =============== Auxiliary functions ==================================
525 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
527 // Start and end points of lines
528 const std::string& aLineStartAttr = SketchPlugin_Line::START_ID();
529 const std::string& aLineEndAttr = SketchPlugin_Line::END_ID();
530 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineStartAttr);
531 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineEndAttr);
532 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineStartAttr);
533 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineEndAttr);
534 if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
535 std::shared_ptr<GeomAPI_Pnt2d>();
537 // Lines and their intersection point
538 std::shared_ptr<GeomAPI_Lin2d> aLA(new GeomAPI_Lin2d(aStartA, aEndA));
539 std::shared_ptr<GeomAPI_Lin2d> aLB(new GeomAPI_Lin2d(aStartB, aEndB));
540 return aLA->intersect(aLB);