Salome HOME
Non planar faces 35156
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Interpolation.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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 "BuildPlugin_Interpolation.h"
21
22 #include <ModelAPI_AttributeBoolean.h>
23 #include <ModelAPI_AttributeDouble.h>
24 #include <ModelAPI_AttributeInteger.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_AttributeTables.h>
29 #include <ModelAPI_Events.h>
30 #include <ModelAPI_ResultBody.h>
31 #include <ModelAPI_ResultParameter.h>
32 #include <ModelAPI_Session.h>
33 #include <ModelAPI_Validator.h>
34
35 #include <Events_InfoMessage.h>
36
37 #include <Locale_Convert.h>
38
39 #include <GeomAlgoAPI_ShapeTools.h>
40 #include <GeomAlgoAPI_CurveBuilder.h>
41 #include <GeomAlgoAPI_PointBuilder.h>
42
43 #include <GeomAPI_Edge.h>
44 #include <GeomAPI_Lin.h>
45 #include <GeomAPI_ShapeExplorer.h>
46
47 #include <algorithm>
48 #include <sstream>
49
50 //=================================================================================================
51 BuildPlugin_Interpolation::BuildPlugin_Interpolation()
52 {
53 }
54
55 //=================================================================================================
56 void BuildPlugin_Interpolation::initAttributes()
57 {
58   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
59   data()->addAttribute(CLOSED_ID(), ModelAPI_AttributeBoolean::typeId());
60   data()->addAttribute(REORDER_ID(), ModelAPI_AttributeBoolean::typeId());
61   data()->addAttribute(USE_TANGENTS_ID(), ModelAPI_AttributeString::typeId());
62   data()->addAttribute(TANGENT_START_ID(), ModelAPI_AttributeSelection::typeId());
63   data()->addAttribute(TANGENT_END_ID(), ModelAPI_AttributeSelection::typeId());
64
65   data()->addAttribute(CREATION_METHOD_ID(), ModelAPI_AttributeString::typeId());
66   data()->addAttribute(CREATION_METHOD_BY_SELECTION_ID(), ModelAPI_AttributeString::typeId());
67   data()->addAttribute(CREATION_METHOD_ANALYTICAL_ID(), ModelAPI_AttributeString::typeId());
68   data()->addAttribute(EXPRESSION_ERROR_ID(), ModelAPI_AttributeString::typeId());
69   data()->addAttribute(VARIABLE_ID(), ModelAPI_AttributeString::typeId());
70   data()->addAttribute(VALUE_ID(), ModelAPI_AttributeTables::typeId());
71   data()->string(EXPRESSION_ERROR_ID())->setIsArgument(false);
72   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXPRESSION_ERROR_ID());
73
74   data()->addAttribute(XT_ID(), ModelAPI_AttributeString::typeId());
75   data()->addAttribute(YT_ID(), ModelAPI_AttributeString::typeId());
76   data()->addAttribute(ZT_ID(), ModelAPI_AttributeString::typeId());
77   data()->addAttribute(MINT_ID(), ModelAPI_AttributeDouble::typeId());
78   data()->addAttribute(MAXT_ID(), ModelAPI_AttributeDouble::typeId());
79   data()->addAttribute(NUMSTEP_ID(), ModelAPI_AttributeInteger::typeId());
80
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
82                                                  CREATION_METHOD_ANALYTICAL_ID());
83   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(),
84                                                  CREATION_METHOD_BY_SELECTION_ID());
85   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VARIABLE_ID());
86   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VALUE_ID());
87   data()->addAttribute(ARGUMENTS_ID(), ModelAPI_AttributeRefList::typeId());
88   data()->reflist(ARGUMENTS_ID())->setIsArgument(false);
89   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ARGUMENTS_ID());
90
91   if (string(XT_ID())->value() == ""
92      && string(YT_ID())->value() == ""
93      && string(ZT_ID())->value() == "") {
94       string(XT_ID())->setValue("t");
95       string(YT_ID())->setValue("t");
96       string(ZT_ID())->setValue("t");
97       real(MINT_ID())->setValue(0);
98       real(MAXT_ID())->setValue(100);
99       integer(NUMSTEP_ID())->setValue(10);
100       updateCoordinates();
101   }
102 }
103
104 //=================================================================================================
105 void BuildPlugin_Interpolation::attributeChanged(const std::string& theID)
106 {
107   if ((theID == XT_ID()
108     || theID == YT_ID()
109     || theID == ZT_ID()
110     || theID == MINT_ID()
111     || theID == MAXT_ID()
112     || theID == NUMSTEP_ID())
113     && string(XT_ID())->value() !=""
114     && string(YT_ID())->value() !=""
115     && string(ZT_ID())->value() !=""
116     && string(CREATION_METHOD_ID())->value() == CREATION_METHOD_ANALYTICAL_ID()) {
117     updateCoordinates();
118   }
119 }
120
121 //=================================================================================================
122 void BuildPlugin_Interpolation::updateCoordinates()
123 {
124     double aMint = real(MINT_ID())->value();
125     double aMaxt = real(MAXT_ID())->value();
126     int aNbrStep = integer(NUMSTEP_ID())->value();
127
128     if (aMaxt < aMint) {
129       setError("The minimum value of the parameter must be less than maximum value !!!");
130     }
131
132     double aScale = (aMaxt - aMint)/aNbrStep;
133     string(VARIABLE_ID())->setValue("t");
134
135     tables(VALUE_ID())->setSize(aNbrStep+1,4);
136     for (int step = 0; step <= aNbrStep; step++) {
137       ModelAPI_AttributeTables::Value aVal;
138       aVal.myDouble = step * aScale + aMint;
139       tables(VALUE_ID())->setValue(aVal,step,0);
140     }
141
142     outErrorMessage="";
143     evaluate(outErrorMessage);
144     data()->string(EXPRESSION_ERROR_ID())->setValue(outErrorMessage);
145     if (!outErrorMessage.empty()) {
146       setError("Error: Python interpreter ");
147       return;
148     }
149 }
150
151 //=================================================================================================
152 static GeomDirPtr selectionToDir(const AttributeSelectionPtr& theSelection)
153 {
154   GeomDirPtr aDir;
155   GeomEdgePtr anEdge;
156
157   GeomShapePtr aShape = theSelection->value();
158   if (!aShape && theSelection->context()) {
159     aShape = theSelection->context()->shape();
160   }
161
162   if (aShape && aShape->isEdge()) {
163     anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
164   }
165
166   if (anEdge && anEdge->isLine()) {
167     aDir = anEdge->line()->direction();
168   }
169
170   return aDir;
171 }
172
173 //=================================================================================================
174 void BuildPlugin_Interpolation::execute()
175 {
176   if (string(CREATION_METHOD_ID())->value() == CREATION_METHOD_BY_SELECTION_ID()) {
177     // Get closed flag value
178     bool isClosed = boolean(CLOSED_ID())->value();
179
180     // Get reorder flag value
181     bool isToReorder = boolean(REORDER_ID())->value();
182
183     // Get use tangents flag value
184     bool isToUseTangents = isClosed? false : (!string(USE_TANGENTS_ID())->value().empty());
185
186     // Get tangent for start and end points
187     GeomDirPtr aDirStart, aDirEnd;
188     if (isToUseTangents) {
189       aDirStart = selectionToDir(selection(TANGENT_START_ID()));
190       aDirEnd = selectionToDir(selection(TANGENT_END_ID()));
191     }
192
193     // Get base objects list.
194     AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID());
195
196     // Collect points.
197     std::list<GeomPointPtr> aPoints;
198     std::set<GeomShapePtr> aContexts;
199     for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
200       AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
201
202       GeomShapePtr aContextShape = aSelection->context()->shape();
203       aContexts.insert(aContextShape);
204
205       GeomShapePtr aShape = aSelection->value();
206       if (!aShape.get()) {
207         aShape = aContextShape;
208       }
209
210       GeomPointPtr aPoint = GeomAlgoAPI_PointBuilder::point(aShape);
211       aPoints.push_back(aPoint);
212     }
213
214     // Create curve from points
215     GeomEdgePtr anEdge =
216       GeomAlgoAPI_CurveBuilder::edge(aPoints, isClosed, isToReorder, aDirStart, aDirEnd);
217     if (!anEdge.get()) {
218       setError("Error: Result curve is empty.");
219       return;
220     }
221
222     // Store result.
223     ResultBodyPtr aResultBody = document()->createBody(data());
224     std::set<GeomShapePtr>::const_iterator aContextIt = aContexts.begin();
225     for (; aContextIt != aContexts.end(); aContextIt++) {
226       aResultBody->storeModified(*aContextIt, anEdge, aContextIt == aContexts.begin());
227     }
228     int aVertexIndex = 1;
229     for (GeomAPI_ShapeExplorer anExp(anEdge, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) {
230       std::string aVertexName = "Vertex_" + std::to_string((long long)aVertexIndex);
231       aResultBody->generated(anExp.current(), aVertexName);
232     }
233
234     setResult(aResultBody);
235
236   } else {
237     if (string(XT_ID())->value() == ""
238         ||string(YT_ID())->value() == ""
239         ||string(ZT_ID())->value() == ""
240         ||tables(VALUE_ID())->rows()== 0)
241       return;
242
243     bool aWasBlocked = data()->blockSendAttributeUpdated(true);
244     updateCoordinates();
245     data()->blockSendAttributeUpdated(aWasBlocked, false);
246
247     AttributeTablesPtr aTable = tables(VALUE_ID());
248     std::list<std::vector<double>> aCoordPoints;
249     for (int step = 0; step < aTable->rows(); step++) {
250       std::vector<double> aCoordPoint;
251       ModelAPI_AttributeTables::Value aValue;
252       //x
253       aValue = aTable->value(step, 1);
254       aCoordPoint.push_back(aValue.myDouble);
255       //y
256       aValue = aTable->value(step, 2);
257       aCoordPoint.push_back(aValue.myDouble);
258       //
259       aValue = aTable->value(step, 3);
260       aCoordPoint.push_back(aValue.myDouble);
261
262       aCoordPoints.push_back(aCoordPoint);
263     }
264
265     std::list<GeomPointPtr> aPoints;
266     std::list<std::vector<double>>::const_iterator anItCoordPoints = aCoordPoints.begin();
267
268     for (; anItCoordPoints!=aCoordPoints.end(); ++anItCoordPoints) {
269
270       GeomVertexPtr aVertex = GeomAlgoAPI_PointBuilder::vertex((*anItCoordPoints)[0],
271                                                                (*anItCoordPoints)[1],
272                                                                (*anItCoordPoints)[2]);
273       aPoints.push_back(aVertex->point());
274     }
275
276     // test if some points are identical
277     std::list<GeomPointPtr>::const_iterator anItPoint1 = aPoints.begin();
278     std::list<GeomPointPtr>::const_iterator anItPoint2;
279     for(; anItPoint1 != aPoints.end(); ++ anItPoint1) {
280       anItPoint2 = anItPoint1;
281       ++anItPoint2;
282       for(; anItPoint2 != aPoints.end(); ++ anItPoint2)
283           if ((*anItPoint2)->isEqual(*anItPoint1)) {
284             setError("Error: Several points are identical");
285             return;
286           }
287     }
288
289     // Create curve from points
290     GeomEdgePtr anEdge =
291       GeomAlgoAPI_CurveBuilder::edge(aPoints, false, false,GeomDirPtr(),GeomDirPtr());
292     if (!anEdge.get()) {
293       setError("Error: Result curve is empty.");
294       return;
295     }
296
297     ResultBodyPtr aResultBody = document()->createBody(data());
298     // Load the result
299     aResultBody->store(anEdge);
300     int aVertexIndex = 1;
301     for (GeomAPI_ShapeExplorer anExp(anEdge, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) {
302       std::string aVertexName = "Vertex_" + std::to_string((long long)aVertexIndex);
303       aResultBody->generated(anExp.current(), aVertexName);
304       aVertexIndex++;
305     }
306     setResult(aResultBody);
307   }
308 }
309
310 //=================================================================================================
311 void BuildPlugin_Interpolation::evaluate(std::string& theError)
312 {
313   FeaturePtr aMyPtr = std::dynamic_pointer_cast<ModelAPI_Feature>(data()->owner());
314   std::shared_ptr<ModelAPI_BuildEvalMessage> aProcessMessage =
315     ModelAPI_BuildEvalMessage::send(aMyPtr, this);
316
317   if (aProcessMessage->isProcessed()) {
318     theError = aProcessMessage->error();
319
320     const std::list<ResultParameterPtr>& aParamsList = aProcessMessage->params();
321     //store the list of parameters to store if changed
322     AttributeRefListPtr aParams = reflist(ARGUMENTS_ID());
323     aParams->clear();
324     std::list<ResultParameterPtr>::const_iterator aNewIter = aParamsList.begin();
325     for (; aNewIter != aParamsList.end(); aNewIter++) {
326       aParams->append(*aNewIter);
327     }
328   } else { // error: python interpreter is not active
329     theError = "Python interpreter is not available";
330   }
331 }