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