Salome HOME
Implement Collinear constraint
[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_EntityWrapper.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_EntityWrapper> 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   PlaneGCSSolver_UpdateCoincidence* anUpdater =
66       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
67
68   bool isPointOnOppositeLine[4];
69   std::list<EntityWrapperPtr>::reverse_iterator anIt = myAttributes.rbegin();
70   for (int i = 0; i < 2; ++i, ++anIt) {
71     isPointOnOppositeLine[2*i] = anUpdater->isPointOnEntity(myPoints[2*i], *anIt);
72     isPointOnOppositeLine[2*i + 1] = anUpdater->isPointOnEntity(myPoints[2*i + 1], *anIt);
73   }
74
75   // both points of one line is on another line => lines are already collinear,
76   // would like to show "conflicting constraints"
77   if (isPointOnOppositeLine[0] && isPointOnOppositeLine[1])
78     isPointOnOppositeLine[1] = false;
79   if (isPointOnOppositeLine[2] && isPointOnOppositeLine[3])
80     isPointOnOppositeLine[3] = false;
81
82   bool aConstraintToApply[4] = {false, false, false, false};
83   ConstraintWrapperPtr aNewConstraint;
84   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoints[2];
85   std::shared_ptr<PlaneGCSSolver_EntityWrapper> aLine;
86
87   if (isPointOnOppositeLine[0] || isPointOnOppositeLine[1]) {
88     // one of points of first line is already on the second line,
89     // make another point of first line to be coincident with second line
90     for (int i = 0; i < 2; ++i) {
91       if (isPointOnOppositeLine[i])
92         continue;
93
94       if (!myIsConstraintApplied[i])
95         aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i]);
96       aConstraintToApply[i] = true;
97     }
98     aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(myAttributes.back());
99   } else {
100     // verify second line and add necessary constraints
101     for (int i = 0; i < 2; ++i) {
102       if (isPointOnOppositeLine[i + 2])
103         continue;
104
105       if (!myIsConstraintApplied[i+2])
106         aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i + 2]);
107       aConstraintToApply[i+2] = true;
108     }
109     aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(myAttributes.front());
110   }
111
112   bool isNew = false;
113   for (int i = 0; i < 4 && !isNew; ++i)
114     if (aConstraintToApply[i] != myIsConstraintApplied[i])
115       isNew = true;
116   if (isNew) {
117     mySolverConstraint = createPointsOnLine(aPoints[0], aPoints[1], aLine);
118     myStorage->removeConstraint(myBaseConstraint);
119     myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
120   }
121 }