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