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_Session.h>
28 #include <ModelAPI_Validator.h>
30 #include <GeomDataAPI_Point2D.h>
32 #include <GeomAPI_Angle2d.h>
33 #include <GeomAPI_Dir2d.h>
34 #include <GeomAPI_Lin2d.h>
35 #include <GeomAPI_Pnt2d.h>
36 #include <GeomAPI_XY.h>
38 #include <SketcherPrs_Factory.h>
39 #include <SketcherPrs_Tools.h>
45 const double tolerance = 1.e-7;
46 #define PI 3.1415926535897932
48 /// \brief Calculate intersection point of two lines
49 static std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2);
52 SketchPlugin_ConstraintAngle::SketchPlugin_ConstraintAngle()
54 myFlyoutUpdate = false;
57 void SketchPlugin_ConstraintAngle::initAttributes()
59 ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
61 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
62 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
63 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
64 data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
66 data()->addAttribute(ANGLE_VALUE_ID(), ModelAPI_AttributeDouble::typeId());
67 data()->addAttribute(TYPE_ID(), ModelAPI_AttributeInteger::typeId());
69 data()->addAttribute(ANGLE_REVERSED_FIRST_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
70 data()->addAttribute(ANGLE_REVERSED_SECOND_LINE_ID(), ModelAPI_AttributeBoolean::typeId());
72 data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
73 aValidators->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
75 data()->addAttribute(PREV_TYPE_ID(), ModelAPI_AttributeInteger::typeId());
76 data()->attribute(PREV_TYPE_ID())->setIsArgument(false);
77 aValidators->registerNotObligatory(getKind(), PREV_TYPE_ID());
78 if (attribute(TYPE_ID())->isInitialized())
79 integer(PREV_TYPE_ID())->setValue(integer(TYPE_ID())->value());
81 data()->addAttribute(SELECTED_FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
82 data()->attribute(SELECTED_FIRST_POINT_ID())->setIsArgument(false);
83 aValidators->registerNotObligatory(getKind(), SELECTED_FIRST_POINT_ID());
85 data()->addAttribute(SELECTED_SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
86 data()->attribute(SELECTED_SECOND_POINT_ID())->setIsArgument(false);
87 aValidators->registerNotObligatory(getKind(), SELECTED_SECOND_POINT_ID());
89 AttributeIntegerPtr aVerAttr = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(
90 data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId()));
91 aVerAttr->setIsArgument(false);
92 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
93 if (!aVerAttr->isInitialized()) {
94 // this is a newly created feature (not read from file),
95 // so, initialize the latest version
96 aVerAttr->setValue(THE_VERSION_1);
100 void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName,
101 std::string& theDefault)
103 theSection = "Visualization";
104 theName = "sketch_dimension_color";
105 theDefault = SKETCH_DIMENSION_COLOR;
108 void SketchPlugin_ConstraintAngle::execute()
110 std::shared_ptr<ModelAPI_Data> aData = data();
112 AttributeRefAttrPtr anAttrA = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
113 AttributeRefAttrPtr anAttrB = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
114 if (!anAttrA->isInitialized() || !anAttrB->isInitialized())
117 AttributeIntegerPtr aVersion = integer(VERSION_ID());
118 if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
121 AttributeDoublePtr anAttrValue = real(ANGLE_VALUE_ID());
122 if (!anAttrValue->isInitialized())
125 // the value should to be computed here, not in the
126 // getAISObject in order to change the model value
127 // inside the object transaction. This is important for creating a constraint by preselection.
128 // The display of the presentation in this case happens after the transaction commit
129 std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
130 GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
131 if(!aFlyOutAttr->isInitialized())
132 compute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
135 AISObjectPtr SketchPlugin_ConstraintAngle::getAISObject(AISObjectPtr thePrevious)
140 AISObjectPtr anAIS = SketcherPrs_Factory::angleConstraint(this, sketch(),
142 if (anAIS.get() && !thePrevious.get())
143 SketchPlugin_Tools::setDimensionColor(anAIS);
147 void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
152 std::shared_ptr<ModelAPI_Data> aData = data();
156 if (theID == TYPE_ID())
159 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
160 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
161 if (!aLineA || !aLineB)
164 AttributeIntegerPtr aVersion = integer(VERSION_ID());
165 if (!aVersion->isInitialized() || aVersion->value() < THE_VERSION_1)
168 if (theID == ENTITY_A() || theID == ENTITY_B() ||
169 theID == TYPE_ID() || theID == ANGLE_VALUE_ID()) {
171 } else if (theID == FLYOUT_VALUE_PNT()) {
176 void SketchPlugin_ConstraintAngle::calculateAngle()
178 // update *_REVERSED_* flags
179 calculateAnglePosition();
181 std::shared_ptr<ModelAPI_Data> aData = data();
182 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
183 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
184 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
186 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
187 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
188 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
189 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
191 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
192 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
194 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
195 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
197 AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID());
198 if (!anAngleValueAttr->isInitialized()) {
199 std::shared_ptr<GeomAPI_Angle2d> anAng(
200 new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
201 anAngleValueAttr->setValue(getAngleForType(fabs(anAng->angleDegree())));
204 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aLine1, false, aLine2, false));
205 double anAngle = anAng->angleDegree();
207 anAngle /= fabs(anAngle);
208 anAngle *= getAngleForType(anAngleValueAttr->value(), isReversed1, isReversed2);
210 // update value of the constraint to be passed to the solver
211 real(SketchPlugin_Constraint::VALUE())->setValue(anAngle);
214 void SketchPlugin_ConstraintAngle::calculateAnglePosition()
216 if (attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
217 attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized())
218 return; // already calculated
220 DataPtr aData = data();
221 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
222 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
224 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
225 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
226 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
227 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
229 bool isReversed1 = false;
230 bool isReversed2 = false;
232 GeomPnt2dPtr aSelected1 = SketcherPrs_Tools::getPoint(this, SELECTED_FIRST_POINT_ID());
233 GeomPnt2dPtr aSelected2 = SketcherPrs_Tools::getPoint(this, SELECTED_SECOND_POINT_ID());
234 if (aSelected1 && aSelected2) {
235 GeomPnt2dPtr anInterPnt = intersect(aLineA, aLineB);
238 std::shared_ptr<GeomAPI_XY> anInterXY = anInterPnt->xy();
239 isReversed1 = aSelected1->xy()->decreased(anInterXY)->dot(
240 aEndA->xy()->decreased(aStartA->xy())) < -tolerance;
241 isReversed2 = aSelected2->xy()->decreased(anInterXY)->dot(
242 aEndB->xy()->decreased(aStartB->xy())) < -tolerance;
245 // no point is selected (document opened or Python script is loaded),
246 // calculate basing on the value
247 std::shared_ptr<GeomAPI_Angle2d> anAng(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
248 isReversed1 = anAng->isReversed(0);
249 isReversed2 = anAng->isReversed(1);
252 // adjust reversed flags according to the angle type
253 AttributeIntegerPtr aTypeAttr = integer(TYPE_ID());
254 if (aTypeAttr && aTypeAttr->isInitialized() &&
255 (SketcherPrs_Tools::AngleType)(aTypeAttr->value()) == SketcherPrs_Tools::ANGLE_COMPLEMENTARY)
256 isReversed1 = !isReversed1;
258 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
259 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
262 // Convert angle value from the DIRECT to any given type.
263 static double angleForType(const double theAngle, const int theType)
265 double anAngle = theAngle;
266 switch ((SketcherPrs_Tools::AngleType)theType) {
267 case SketcherPrs_Tools::ANGLE_DIRECT:
270 case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
271 anAngle = 180.0 - theAngle;
273 case SketcherPrs_Tools::ANGLE_BACKWARD:
274 anAngle = 360.0 - theAngle;
282 double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle,
286 double anAngle = angleForType(theAngle, integer(TYPE_ID())->value());
287 if (isReversed1 != isReversed2)
288 anAngle = 180.0 - anAngle;
292 // Convert angle value or a text expression from one angle type to another
293 static void convertAngle(AttributeDoublePtr& theAngle,
294 const int thePrevType, const int theNewType)
296 if (theAngle->isInitialized()) {
297 if (theAngle->text().empty()) {
298 // calculate value related to the type twice:
299 // the first time - to return to direct angle,
300 // the second time - to apply new type
301 double aValue = angleForType(theAngle->value(), thePrevType);
302 aValue = angleForType(aValue, theNewType);
303 theAngle->setValue(aValue);
306 // process the parametric value
307 std::string anAngleText = theAngle->text();
308 std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)$",
309 std::regex_constants::ECMAScript);
311 double anAnglePrefix = 0.0;
312 static const char aSignPrefix[2] = { '-', '+' };
316 if (std::regex_search(anAngleText, aResult, anAngleRegex)) {
317 anAnglePrefix = std::atof(aResult[1].str().c_str());
318 aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1;
319 anAngleText = aResult[3].str();
322 if (thePrevType != SketcherPrs_Tools::ANGLE_DIRECT)
323 aSignInd = 1 - aSignInd;
324 anAnglePrefix = angleForType(anAnglePrefix, thePrevType);
326 if (theNewType != SketcherPrs_Tools::ANGLE_DIRECT)
327 aSignInd = 1 - aSignInd;
328 anAnglePrefix = angleForType(anAnglePrefix, theNewType);
330 std::ostringstream aText;
331 bool isPrintSign = true;
332 if (fabs(anAnglePrefix) > tolerance)
333 aText << anAnglePrefix;
335 isPrintSign = aSignInd == 0;
337 aText << " " << aSignPrefix[aSignInd] << " (";
338 aText << anAngleText << (isPrintSign ? ")" : "");
339 theAngle->setText(aText.str());
344 void SketchPlugin_ConstraintAngle::updateAngleValue()
346 AttributeIntegerPtr anAngleType = integer(TYPE_ID());
347 AttributeIntegerPtr aPrevAngleType = integer(PREV_TYPE_ID());
348 convertAngle(real(ANGLE_VALUE_ID()), aPrevAngleType->value(), anAngleType->value());
349 aPrevAngleType->setValue(anAngleType->value());
352 static GeomPnt2dPtr lineBoundary(const FeaturePtr& theLine, const bool theReversed,
353 const GeomPnt2dPtr& thePointToAvoid)
355 GeomPnt2dPtr aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
356 theReversed ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
357 if (aPoint->distance(thePointToAvoid) < tolerance) {
358 // extremity is equal to the intersection point,
359 // thus recalculate it using another boundary point
360 aPoint = SketcherPrs_Tools::getPoint(theLine.get(),
361 theReversed ? SketchPlugin_Line::END_ID() : SketchPlugin_Line::START_ID());
362 aPoint->setX(thePointToAvoid->x() * 2.0 - aPoint->x());
363 aPoint->setY(thePointToAvoid->y() * 2.0 - aPoint->y());
368 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
370 if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
375 std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
376 GeomDataAPI_Point2D>(attribute(theAttributeId));
378 DataPtr aData = data();
379 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
380 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A());
381 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B());
383 if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
386 // Intersection of lines
387 std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
391 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
392 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
394 int anAngleType = integer(TYPE_ID())->value();
396 bool isSupplementary = anAngleType == (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY;
398 // point on lines to compose an angle
399 GeomPnt2dPtr aPointA = lineBoundary(aLineA, isReversed1 ^ isSupplementary, anInter);
400 GeomPnt2dPtr aPointB = lineBoundary(aLineB, isReversed2, anInter);
402 myFlyoutUpdate = true;
403 if (aFlyOutAttr->isInitialized()) {
404 std::shared_ptr<GeomAPI_XY> aFlyoutPoint = aFlyOutAttr->pnt()->xy();
405 std::shared_ptr<GeomAPI_XY> anInterXY = anInter->xy();
406 std::shared_ptr<GeomAPI_XY> aDirIF = aFlyoutPoint->decreased(anInterXY);
407 std::shared_ptr<GeomAPI_XY> aDirIA = aPointA->xy()->decreased(anInterXY);
408 std::shared_ptr<GeomAPI_XY> aDirIB = aPointB->xy()->decreased(anInterXY);
409 double aSign = aDirIA->cross(aDirIB);
410 aSign /= fabs(aSign);
411 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD)
414 double cross1 = aSign * aDirIA->cross(aDirIF);
415 if (cross1 < -tolerance)
416 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(!isReversed2);
417 double cross2 = aSign * aDirIF->cross(aDirIB);
418 if (cross2 < -tolerance)
419 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(!isReversed1);
421 // the direction is reversed only once
422 if ((cross1 + tolerance) * (cross2 + tolerance) < 0.0) {
423 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
424 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_BACKWARD,
425 (int)SketcherPrs_Tools::ANGLE_DIRECT);
427 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
428 (int)SketcherPrs_Tools::ANGLE_COMPLEMENTARY);
429 if (anAngleType == (int)SketcherPrs_Tools::ANGLE_BACKWARD) {
430 convertAngle(real(ANGLE_VALUE_ID()), (int)SketcherPrs_Tools::ANGLE_DIRECT,
431 (int)SketcherPrs_Tools::ANGLE_BACKWARD);
438 // default position of the presentation
439 double aX = (aPointA->x() + aPointB->x() + anInter->x()) / 3.;
440 double aY = (aPointA->y() + aPointB->y() + anInter->y()) / 3.;
441 aFlyOutAttr->setValue(aX, aY);
443 myFlyoutUpdate = false;
448 void SketchPlugin_ConstraintAngle::updateVersion()
450 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
452 // Calculate angle value by the old algorithm and
453 // update the corresponding attribute to meet the new requirements.
454 FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_A());
455 FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(data(), ENTITY_B());
457 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID());
458 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID());
459 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID());
460 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID());
462 std::shared_ptr<GeomAPI_Angle2d> anAng;
464 if (boolean(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() &&
465 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) {
466 bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value();
467 bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value();
469 std::shared_ptr<GeomAPI_Lin2d> aLine1(new GeomAPI_Lin2d(aStartA, aEndA));
470 std::shared_ptr<GeomAPI_Lin2d> aLine2(new GeomAPI_Lin2d(aStartB, aEndB));
471 anAng.reset(new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2));
474 anAng.reset(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB));
476 bool isReversed1 = anAng->isReversed(0);
477 bool isReversed2 = anAng->isReversed(1);
479 boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1);
480 boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2);
482 double anAngleValue = anAng->angleDegree();
483 double aConstValue = real(ANGLE_VALUE_ID())->value();
485 AttributeIntegerPtr aType = integer(TYPE_ID());
486 switch ((SketcherPrs_Tools::AngleType)aType->value()) {
487 case SketcherPrs_Tools::ANGLE_DIRECT:
488 if (anAngleValue < 0.0 && aConstValue > 180.0)
489 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_BACKWARD,
490 SketcherPrs_Tools::ANGLE_DIRECT);
492 case SketcherPrs_Tools::ANGLE_BACKWARD:
493 if (anAngleValue < 0.0 && aConstValue < 180.0)
494 convertAngle(real(ANGLE_VALUE_ID()), SketcherPrs_Tools::ANGLE_DIRECT,
495 SketcherPrs_Tools::ANGLE_BACKWARD);
500 data()->blockSendAttributeUpdated(aWasBlocked, false);
501 integer(VERSION_ID())->setValue(THE_VERSION_1);
505 // =============== Auxiliary functions ==================================
506 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
508 // Start and end points of lines
509 const std::string& aLineStartAttr = SketchPlugin_Line::START_ID();
510 const std::string& aLineEndAttr = SketchPlugin_Line::END_ID();
511 GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineStartAttr);
512 GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineEndAttr);
513 GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineStartAttr);
514 GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineEndAttr);
515 if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
516 std::shared_ptr<GeomAPI_Pnt2d>();
518 // Lines and their intersection point
519 std::shared_ptr<GeomAPI_Lin2d> aLA(new GeomAPI_Lin2d(aStartA, aEndA));
520 std::shared_ptr<GeomAPI_Lin2d> aLB(new GeomAPI_Lin2d(aStartB, aEndB));
521 return aLA->intersect(aLB);