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_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());
135 static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
136 std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage(
137 new ModelAPI_EventReentrantMessage(anId, this));
138 Events_Loop::loop()->send(aMessage);
141 AISObjectPtr SketchPlugin_ConstraintAngle::getAISObject(AISObjectPtr thePrevious)
146 AISObjectPtr anAIS = SketcherPrs_Factory::angleConstraint(this, sketch(),
148 if (anAIS.get() && !thePrevious.get())
149 SketchPlugin_Tools::setDimensionColor(anAIS);
154 std::string SketchPlugin_ConstraintAngle::processEvent(
155 const std::shared_ptr<Events_Message>& theMessage)
157 std::string aFilledAttributeName;
159 std::shared_ptr<ModelAPI_EventReentrantMessage> aReentrantMessage =
160 std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
161 if (aReentrantMessage.get()) {
162 aFilledAttributeName = ENTITY_A();
163 refattr(ENTITY_A())->setObject(aReentrantMessage->selectedObject());
164 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SELECTED_FIRST_POINT_ID()))
165 ->setValue(aReentrantMessage->clickedPoint());
167 return aFilledAttributeName;
171 void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
176 std::shared_ptr<ModelAPI_Data> aData = data();
180 if (theID == TYPE_ID())
183 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
184 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
185 if (!aLineA || !aLineB)
188 AttributeIntegerPtr aVersion = integer(VERSION_ID());
189 if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
192 if (theID == ENTITY_A() || theID == ENTITY_B() ||
193 theID == TYPE_ID() || theID == ANGLE_VALUE_ID()) {
195 } else if (theID == FLYOUT_VALUE_PNT()) {
200 void SketchPlugin_ConstraintAngle::calculateAngle()
202 // update *_REVERSED_* flags
203 calculateAnglePosition();
205 std::shared_ptr<ModelAPI_Data> aData = data();
206 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
207 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
208 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
210 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
211 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
212 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
213 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
215 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
216 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
218 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
219 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
221 AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
222 if (!anAngleValueAttr->isInitialized()) {
223 std::shared_ptr<GeomAPI_Angle2d> anAng(
224 new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
225 anAngleValueAttr->setValue(getAngleForType(fabs(anAng->angleDegree())));
228 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aLine1, false, aLine2, false));
229 double anAngle = anAng->angleDegree();
231 anAngle /= fabs(anAngle);
232 anAngle *= getAngleForType(anAngleValueAttr->value(), isReversed1, isReversed2);
234 // update value of the constraint to be passed to the solver
235 real(SketchPlugin_Constraint::VALUE())->setValue(anAngle);
238 void SketchPlugin_ConstraintAngle::calculateAnglePosition()
240 if (attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
241 attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized())
242 return; // already calculated
244 DataPtr aData = data();
245 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
246 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
248 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
249 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
250 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
251 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
253 bool isReversed1 = false;
254 bool isReversed2 = false;
256 GeomPnt2dPtr aSelected1 = SketcherPrs_Tools::getPoint(this, SELECTED_FIRST_POINT_ID());
257 GeomPnt2dPtr aSelected2 = SketcherPrs_Tools::getPoint(this, SELECTED_SECOND_POINT_ID());
258 if (aSelected1 && aSelected2) {
259 GeomPnt2dPtr anInterPnt = intersect(aLineA, aLineB);
262 std::shared_ptr<GeomAPI_XY> anInterXY = anInterPnt->xy();
263 isReversed1 = aSelected1->xy()->decreased(anInterXY)->dot(
264 aEndA->xy()->decreased(aStartA->xy())) < -tolerance;
265 isReversed2 = aSelected2->xy()->decreased(anInterXY)->dot(
266 aEndB->xy()->decreased(aStartB->xy())) < -tolerance;
269 // no point is selected (document opened or Python script is loaded),
270 // calculate basing on the value
271 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
272 isReversed1 = anAng->isReversed(0);
273 isReversed2 = anAng->isReversed(1);
276 // adjust reversed flags according to the angle type
277 AttributeIntegerPtr aTypeAttr = integer(TYPE_ID());
278 if (aTypeAttr && aTypeAttr->isInitialized() &&
279 (SketcherPrs_Tools::AngleType)(aTypeAttr->value()) == SketcherPrs_Tools::ANGLE_COMPLEMENTARY)
280 isReversed1 = !isReversed1;
282 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
283 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
286 // Convert angle value from the DIRECT to any given type.
287 static double angleForType(const double theAngle, const int theType)
289 double anAngle = theAngle;
290 switch ((SketcherPrs_Tools::AngleType)theType) {
291 case SketcherPrs_Tools::ANGLE_DIRECT:
294 case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
295 anAngle = 180.0 - theAngle;
297 case SketcherPrs_Tools::ANGLE_BACKWARD:
298 anAngle = 360.0 - theAngle;
306 double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle,
310 double anAngle = angleForType(theAngle, integer(TYPE_ID())->value());
311 if (isReversed1 != isReversed2)
312 anAngle = 180.0 - anAngle;
316 // Convert angle value or a text expression from one angle type to another
317 static void convertAngle(AttributeDoublePtr theAngle,
318 const int thePrevType, const int theNewType)
320 if (theAngle->isInitialized()) {
321 if (theAngle->text().empty()) {
322 // calculate value related to the type twice:
323 // the first time - to return to direct angle,
324 // the second time - to apply new type
325 double aValue = angleForType(theAngle->value(), thePrevType);
326 aValue = angleForType(aValue, theNewType);
327 theAngle->setValue(aValue);
330 // process the parametric value
331 std::string anAngleText = theAngle->text();
332 std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)$",
333 std::regex_constants::ECMAScript);
335 double anAnglePrefix = 0.0;
336 static const char aSignPrefix[2] = { '-', '+' };
340 if (std::regex_search(anAngleText, aResult, anAngleRegex)) {
341 anAnglePrefix = std::atof(aResult[1].str().c_str());
342 aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1;
343 anAngleText = aResult[3].str();
346 if (thePrevType != SketcherPrs_Tools::ANGLE_DIRECT)
347 aSignInd = 1 - aSignInd;
348 anAnglePrefix = angleForType(anAnglePrefix, thePrevType);
350 if (theNewType != SketcherPrs_Tools::ANGLE_DIRECT)
351 aSignInd = 1 - aSignInd;
352 anAnglePrefix = angleForType(anAnglePrefix, theNewType);
354 std::ostringstream aText;
355 bool isPrintSign = true;
356 if (fabs(anAnglePrefix) > tolerance)
357 aText << anAnglePrefix;
359 isPrintSign = aSignInd == 0;
361 aText << " " << aSignPrefix[aSignInd] << " (";
362 aText << anAngleText << (isPrintSign ? ")" : "");
363 theAngle->setText(aText.str());
368 void SketchPlugin_ConstraintAngle::updateAngleValue()
370 AttributeIntegerPtr anAngleType = integer(TYPE_ID());
371 AttributeIntegerPtr aPrevAngleType = integer(PREV_TYPE_ID());
372 convertAngle(real(ANGLE_VALUE_ID()), aPrevAngleType->value(), anAngleType->value());
373 aPrevAngleType->setValue(anAngleType->value());
376 static GeomPnt2dPtr lineBoundary(const FeaturePtr& theLine, const bool theReversed,
377 const GeomPnt2dPtr& thePointToAvoid)
379 GeomPnt2dPtr aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
380 theReversed ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
381 if (aPoint->distance(thePointToAvoid) < tolerance) {
382 // extremity is equal to the intersection point,
383 // thus recalculate it using another boundary point
384 aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
385 theReversed ? SketchPlugin_Line::END_ID() : SketchPlugin_Line::START_ID());
386 aPoint->setX(thePointToAvoid->x() * 2.0 - aPoint->x());
387 aPoint->setY(thePointToAvoid->y() * 2.0 - aPoint->y());
392 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
394 if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
399 std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
400 GeomDataAPI_Point2D>(attribute(theAttributeId));
402 DataPtr aData = data();
403 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
404 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
405 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
407 if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
410 // Intersection of lines
411 std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
415 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
416 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
418 int anAngleType = integer(TYPE_ID())->value();
420 bool isSupplementary = anAngleType == (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY;
422 // point on lines to compose an angle
423 GeomPnt2dPtr aPointA = lineBoundary(aLineA, isReversed1 ^ isSupplementary, anInter);
424 GeomPnt2dPtr aPointB = lineBoundary(aLineB, isReversed2, anInter);
426 myFlyoutUpdate = true;
427 if (aFlyOutAttr->isInitialized()) {
428 std::shared_ptr<GeomAPI_XY> aFlyoutPoint = aFlyOutAttr->pnt()->xy();
429 std::shared_ptr<GeomAPI_XY> anInterXY = anInter->xy();
430 std::shared_ptr<GeomAPI_XY> aDirIF = aFlyoutPoint->decreased(anInterXY);
431 std::shared_ptr<GeomAPI_XY> aDirIA = aPointA->xy()->decreased(anInterXY);
432 std::shared_ptr<GeomAPI_XY> aDirIB = aPointB->xy()->decreased(anInterXY);
433 double aSign = aDirIA->cross(aDirIB);
434 aSign /= fabs(aSign);
435 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD)
438 double cross1 = aSign * aDirIA->cross(aDirIF);
439 if (cross1 < -tolerance)
440 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(!isReversed2);
441 double cross2 = aSign * aDirIF->cross(aDirIB);
442 if (cross2 < -tolerance)
443 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(!isReversed1);
445 // the direction is reversed only once
446 if ((cross1 + tolerance) * (cross2 + tolerance) < 0.0) {
447 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
448 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_BACKWARD,
449 (int)SketcherPrs_Tools::ANGLE_DIRECT);
451 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
452 (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY);
453 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
454 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
455 (int)SketcherPrs_Tools::ANGLE_BACKWARD);
462 // default position of the presentation
463 double aX = (aPointA->x() + aPointB->x() + anInter->x()) / 3.;
464 double aY = (aPointA->y() + aPointB->y() + anInter->y()) / 3.;
465 aFlyOutAttr->setValue(aX, aY);
467 myFlyoutUpdate = false;
472 void SketchPlugin_ConstraintAngle::updateVersion()
474 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
476 // Calculate angle value by the old algorithm and
477 // update the corresponding attribute to meet the new requirements.
478 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_A());
479 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_B());
481 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
482 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
483 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
484 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
486 std::shared_ptr<GeomAPI_Angle2d> anAng;
488 if (boolean(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
489 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) {
490 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
491 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
493 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
494 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
495 anAng.reset(new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
498 anAng.reset(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
500 bool isReversed1 = anAng->isReversed(0);
501 bool isReversed2 = anAng->isReversed(1);
503 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
504 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
506 double anAngleValue = anAng->angleDegree();
507 double aConstValue = real(ANGLE_VALUE_ID())->value();
509 AttributeIntegerPtr aType = integer(TYPE_ID());
510 switch ((SketcherPrs_Tools::AngleType)aType->value()) {
511 case SketcherPrs_Tools::ANGLE_DIRECT:
512 if (anAngleValue < 0.0 && aConstValue > 180.0)
513 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_BACKWARD,
514 SketcherPrs_Tools::ANGLE_DIRECT);
516 case SketcherPrs_Tools::ANGLE_BACKWARD:
517 if (anAngleValue < 0.0 && aConstValue < 180.0)
518 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_DIRECT,
519 SketcherPrs_Tools::ANGLE_BACKWARD);
524 data()->blockSendAttributeUpdated(aWasBlocked, false);
525 integer(VERSION_ID())->setValue(THE_VERSION_1);
529 // =============== Auxiliary functions ==================================
530 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
532 // Start and end points of lines
533 const std::string& aLineStartAttr = SketchPlugin_Line::START_ID();
534 const std::string& aLineEndAttr = SketchPlugin_Line::END_ID();
535 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineStartAttr);
536 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineEndAttr);
537 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineStartAttr);
538 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineEndAttr);
539 if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
540 std::shared_ptr<GeomAPI_Pnt2d>();
542 // Lines and their intersection point
543 std::shared_ptr<GeomAPI_Lin2d> aLA(new GeomAPI_Lin2d(aStartA, aEndA));
544 std::shared_ptr<GeomAPI_Lin2d> aLB(new GeomAPI_Lin2d(aStartB, aEndB));
545 return aLA->intersect(aLB);