Salome HOME
Issue #2166: wrong conflicting constraint error when create point on external edge
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Solver.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    PlaneGCSSolver_Solver.cpp
4 // Created: 14 Dec 2014
5 // Author:  Artem ZHIDKOV
6
7 #include <PlaneGCSSolver_Solver.h>
8 #include <Events_LongOp.h>
9
10
11 PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
12   : myEquationSystem(new GCS::System),
13     myDiagnoseBeforeSolve(false),
14     myInitilized(false),
15     myConfCollected(false),
16     myDOF(0)
17 {
18 }
19
20 PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver()
21 {
22   clear();
23 }
24
25 void PlaneGCSSolver_Solver::clear()
26 {
27   myEquationSystem->clear();
28   myParameters.clear();
29   myConstraints.clear();
30   myConflictingIDs.clear();
31   myDOF = 0;
32 }
33
34 void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint)
35 {
36   myEquationSystem->addConstraint(theConstraint.get());
37   myConstraints[theConstraint->getTag()].insert(theConstraint);
38   if (theConstraint->getTag() >= 0)
39     myDOF = -1;
40   myInitilized = false;
41 }
42
43 void PlaneGCSSolver_Solver::removeConstraint(ConstraintID theID)
44 {
45   myConstraints.erase(theID);
46   if (myConstraints.empty()) {
47     myEquationSystem->clear();
48     myDOF = (int)myParameters.size();
49   } else {
50     myEquationSystem->clearByTag(theID);
51     if (theID >= 0)
52       myDOF = -1;
53   }
54   myInitilized = false;
55 }
56
57 double* PlaneGCSSolver_Solver::createParameter()
58 {
59   double* aResult = new double(0);
60   myParameters.push_back(aResult);
61   if (myConstraints.empty() && myDOF >= 0)
62     ++myDOF; // calculate DoF by hand if and only if there is no constraints yet
63   else
64     myDiagnoseBeforeSolve = true;
65   return aResult;
66 }
67
68 void PlaneGCSSolver_Solver::addParameters(const GCS::SET_pD& theParams)
69 {
70   GCS::SET_pD aParams(theParams);
71   // leave new parameters only
72   GCS::VEC_pD::iterator anIt = myParameters.begin();
73   for (; anIt != myParameters.end(); ++anIt)
74     if (aParams.find(*anIt) != aParams.end())
75       aParams.erase(*anIt);
76
77   myParameters.insert(myParameters.end(), aParams.begin(), aParams.end());
78   if (myConstraints.empty() && myDOF >=0)
79     myDOF += (int)aParams.size(); // calculate DoF by hand only if there is no constraints yet
80   else
81     myDiagnoseBeforeSolve = true;
82 }
83
84 void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams)
85 {
86   for (int i = (int)myParameters.size() - 1; i >= 0; --i)
87     if (theParams.find(myParameters[i]) != theParams.end()) {
88       myParameters.erase(myParameters.begin() + i);
89       --myDOF;
90     }
91   if (!myConstraints.empty())
92     myDiagnoseBeforeSolve = true;
93 }
94
95 void PlaneGCSSolver_Solver::initialize()
96 {
97   Events_LongOp::start(this);
98   if (myDiagnoseBeforeSolve)
99     diagnose();
100   myEquationSystem->declareUnknowns(myParameters);
101   myEquationSystem->initSolution();
102   Events_LongOp::end(this);
103
104   myInitilized = true;
105 }
106
107 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
108 {
109   // clear list of conflicting constraints
110   if (myConfCollected) {
111     myConflictingIDs.clear();
112     myConfCollected = false;
113   }
114
115   if (myParameters.empty())
116     return STATUS_INCONSISTENT;
117
118   GCS::SolveStatus aResult = GCS::Success;
119   Events_LongOp::start(this);
120   if (myInitilized) {
121     aResult = (GCS::SolveStatus)myEquationSystem->solve();
122   } else {
123     if (myDiagnoseBeforeSolve)
124       diagnose();
125     aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters);
126   }
127   Events_LongOp::end(this);
128
129   // collect information about conflicting constraints every time,
130   // sometimes solver reports about succeeded recalculation but has conflicting constraints
131   // (for example, apply horizontal constraint for a copied feature)
132   collectConflicting();
133   if (!myConflictingIDs.empty())
134     aResult = GCS::Failed;
135
136   SolveStatus aStatus;
137   if (aResult == GCS::Failed)
138     aStatus = STATUS_FAILED;
139   else {
140     myEquationSystem->applySolution();
141     if (myDOF < 0)
142       myDOF = myEquationSystem->dofsNumber();
143     aStatus = STATUS_OK;
144   }
145
146   myInitilized = false;
147   return aStatus;
148 }
149
150 void PlaneGCSSolver_Solver::undo()
151 {
152   myEquationSystem->undoSolution();
153 }
154
155 bool PlaneGCSSolver_Solver::isConflicting(const ConstraintID& theConstraint) const
156 {
157   if (!myConfCollected)
158     const_cast<PlaneGCSSolver_Solver*>(this)->collectConflicting();
159   return myConflictingIDs.find((int)theConstraint) != myConflictingIDs.end();
160 }
161
162 void PlaneGCSSolver_Solver::collectConflicting()
163 {
164   GCS::VEC_I aConflict;
165   myEquationSystem->getConflicting(aConflict);
166   myConflictingIDs.insert(aConflict.begin(), aConflict.end());
167
168   myEquationSystem->getRedundant(aConflict);
169   myConflictingIDs.insert(aConflict.begin(), aConflict.end());
170
171   myConfCollected = true;
172 }
173
174 int PlaneGCSSolver_Solver::dof()
175 {
176   if (myDOF < 0 && !myConstraints.empty())
177     diagnose();
178   return myDOF;
179 }
180
181 void PlaneGCSSolver_Solver::diagnose()
182 {
183   myEquationSystem->declareUnknowns(myParameters);
184   myDOF = myEquationSystem->diagnose();
185   myDiagnoseBeforeSolve = false;
186 }