Salome HOME
Fix regressions found by unit tests
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintCollinear.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <SketchSolver_ConstraintCollinear.h>
4 #include <SketchSolver_Error.h>
5
6 #include <PlaneGCSSolver_ConstraintWrapper.h>
7 #include <PlaneGCSSolver_EdgeWrapper.h>
8 #include <PlaneGCSSolver_PointWrapper.h>
9 #include <PlaneGCSSolver_UpdateCoincidence.h>
10
11 #include <SketchPlugin_Line.h>
12
13 static ConstraintWrapperPtr createPointsOnLine(
14     std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint1,
15     std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint2,
16     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theLine)
17 {
18   std::shared_ptr<GCS::Line> aGCSLine = std::dynamic_pointer_cast<GCS::Line>(theLine->entity());
19
20   std::list<GCSConstraintPtr> aConstrList;
21   if (thePoint1)
22     aConstrList.push_back( GCSConstraintPtr(
23         new GCS::ConstraintPointOnLine(*thePoint1->point(), *aGCSLine)) );
24   if (thePoint2)
25     aConstrList.push_back( GCSConstraintPtr(
26         new GCS::ConstraintPointOnLine(*thePoint2->point(), *aGCSLine)) );
27
28   return aConstrList.empty() ?  ConstraintWrapperPtr() : ConstraintWrapperPtr(
29       new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_COLLINEAR));
30 }
31
32
33 void SketchSolver_ConstraintCollinear::process()
34 {
35   cleanErrorMsg();
36   if (!myBaseConstraint || !myStorage) {
37     // Not enough parameters are assigned
38     return;
39   }
40
41   EntityWrapperPtr aValue;
42   std::vector<EntityWrapperPtr> anAttributes;
43   getAttributes(aValue, anAttributes);
44   if (!myErrorMsg.empty())
45     return;
46   if (anAttributes.empty()) {
47     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
48     return;
49   }
50
51   for (int i = 0; i < 2; ++i) {
52     AttributeRefAttrPtr aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
53     FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
54     myPoints[2*i] = myStorage->entity(aLine->attribute(SketchPlugin_Line::START_ID()));
55     myPoints[2*i + 1] = myStorage->entity(aLine->attribute(SketchPlugin_Line::END_ID()));
56   }
57
58   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
59   myStorage->notify(myBaseConstraint);
60 }
61
62 void SketchSolver_ConstraintCollinear::notify(const FeaturePtr&      theFeature,
63                                               PlaneGCSSolver_Update* theUpdater)
64 {
65   if (theFeature == myBaseConstraint && myInSolver)
66     return; // the constraint is already being updated
67
68   PlaneGCSSolver_UpdateCoincidence* anUpdater =
69       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
70
71   bool isPointOnOppositeLine[4];
72   std::list<EntityWrapperPtr>::reverse_iterator anIt = myAttributes.rbegin();
73   for (int i = 0; i < 2; ++i, ++anIt) {
74     isPointOnOppositeLine[2*i] = anUpdater->isPointOnEntity(myPoints[2*i], *anIt);
75     isPointOnOppositeLine[2*i + 1] = anUpdater->isPointOnEntity(myPoints[2*i + 1], *anIt);
76   }
77
78   // both points of one line is on another line => lines are already collinear,
79   // would like to show "conflicting constraints"
80   if (isPointOnOppositeLine[0] && isPointOnOppositeLine[1])
81     isPointOnOppositeLine[1] = false;
82   if (isPointOnOppositeLine[2] && isPointOnOppositeLine[3])
83     isPointOnOppositeLine[3] = false;
84
85   bool aConstraintToApply[4] = {false, false, false, false};
86   ConstraintWrapperPtr aNewConstraint;
87   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoints[2];
88   std::shared_ptr<PlaneGCSSolver_EdgeWrapper> aLine;
89
90   if (isPointOnOppositeLine[0] || isPointOnOppositeLine[1]) {
91     // one of points of first line is already on the second line,
92     // make another point of first line to be coincident with second line
93     for (int i = 0; i < 2; ++i) {
94       if (isPointOnOppositeLine[i])
95         continue;
96
97       if (!myIsConstraintApplied[i])
98         aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i]);
99       aConstraintToApply[i] = true;
100     }
101     aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(myAttributes.back());
102   } else {
103     // verify second line and add necessary constraints
104     for (int i = 0; i < 2; ++i) {
105       if (isPointOnOppositeLine[i + 2])
106         continue;
107
108       if (!myIsConstraintApplied[i+2])
109         aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i + 2]);
110       aConstraintToApply[i+2] = true;
111     }
112     aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(myAttributes.front());
113   }
114
115   bool isNew = false;
116   for (int i = 0; i < 4; ++i) {
117     if (aConstraintToApply[i] != myIsConstraintApplied[i])
118       isNew = true;
119     myIsConstraintApplied[i] = aConstraintToApply[i];
120   }
121
122   if (isNew) {
123     mySolverConstraint = createPointsOnLine(aPoints[0], aPoints[1], aLine);
124     if (myInSolver) {
125       myStorage->removeConstraint(myBaseConstraint);
126       myInSolver = false;
127     }
128     if (mySolverConstraint) {
129       myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
130       myInSolver = true;
131     }
132   }
133 }