Salome HOME
6ad810f2e6dd5c1f0d3f85c714515b40fa1e9ca8
[modules/shaper.git] / src / Model / Model_ResultConstruction.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 <Model_ResultConstruction.h>
22
23 #include <Model_Data.h>
24 #include <ModelAPI_CompositeFeature.h>
25 #include <GeomAlgoAPI_SketchBuilder.h>
26 #include <ModelAPI_Events.h>
27 #include <Model_Document.h>
28 #include <GeomAPI_PlanarEdges.h>
29 #include <GeomAPI_Shape.h>
30 #include <Events_Loop.h>
31
32 #include <TDF_ChildIDIterator.hxx>
33 #include <TNaming_NamedShape.hxx>
34 #include <TNaming_Builder.hxx>
35 #include <TDataStd_IntPackedMap.hxx>
36 #include <TDataStd_Name.hxx>
37 #include <TDataStd_UAttribute.hxx>
38 #include <BRep_Builder.hxx>
39 #include <TopoDS.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Vertex.hxx>
42 #include <TopoDS_ListOfShape.hxx>
43 #include <TopExp_Explorer.hxx>
44 #include <TopTools_MapOfShape.hxx>
45
46 #include <algorithm>
47
48
49 // identifier of the infinite result
50 Standard_GUID kIS_INFINITE("dea8cc5a-53f2-49c1-94e8-a947bed20a9f");
51 // identifier of the result not in history
52 Standard_GUID kIS_IN_HISTORY("a9aec01c-805e-44d1-b5d2-a63f06522f8a");
53
54
55 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
56                                        std::string& theDefault)
57 {
58   theSection = "Visualization";
59   theName = "result_construction_color";
60   theDefault = DEFAULT_COLOR();
61 }
62
63 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
64 {
65   if (myShape != theShape) {
66     if (!isInfinite())
67       storeShape(theShape);
68     if (!theShape.get() || !theShape->isEqual(myShape)) {
69       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
70       ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
71     }
72     myShape = theShape;
73   }
74 }
75
76 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
77 {
78   return myShape;
79 }
80
81 static std::string shortName(
82   std::shared_ptr<ModelAPI_ResultConstruction>& theConstr)
83 {
84   std::string aName = theConstr->data()->name();
85   // remove "-", "/" and "&" command-symbols
86   aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end());
87   aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end());
88   aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
89   // remove the last 's', 'e', 'f' and 'r' symbols:
90   // they are used as markers of start/end/forward/rewersed indicators
91   static const std::string aSyms("sefr");
92   std::string::iterator aSuffix = aName.end() - 1;
93   while(aSyms.find(*aSuffix) != std::string::npos) {
94     --aSuffix;
95   }
96   aName.erase(aSuffix + 1, aName.end());
97   return aName;
98 }
99
100
101 bool Model_ResultConstruction::updateShape()
102 {
103   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
104   if (aData && aData->isValid()) {
105     TDF_Label aShapeLab = aData->shapeLab();
106     Handle(TNaming_NamedShape) aNS;
107     if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
108       TopoDS_Shape aShape = aNS->Get();
109       if (!aShape.IsNull()) {
110         GeomShapePtr aGShape(new GeomAPI_Shape);
111         aGShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
112         myShape = aGShape; // restore the sketch sub-components
113         return true;
114       }
115     }
116   }
117   return false;
118 }
119
120 Model_ResultConstruction::Model_ResultConstruction()
121 {
122 }
123
124 bool Model_ResultConstruction::isInHistory()
125 {
126   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
127   if (aData.get() && aData->isValid()) {
128     return !aData->label().IsAttribute(kIS_IN_HISTORY); // by default no attribute, but in history
129   }
130   return true;  // unknown case
131 }
132
133 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
134 {
135   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
136   if (aData.get() && aData->isValid()) {
137     if (!isInHistory)
138       TDataStd_UAttribute::Set(aData->label(), kIS_IN_HISTORY);
139     else
140       aData->label().ForgetAttribute(kIS_IN_HISTORY);
141   }
142 }
143
144 bool Model_ResultConstruction::isInfinite()
145 {
146   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
147   if (aData.get() && aData->isValid()) {
148     return aData->label().IsAttribute(kIS_INFINITE);
149   }
150   return false;  // unknown case
151 }
152
153 void Model_ResultConstruction::setInfinite(const bool theInfinite)
154 {
155   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
156   if (aData.get() && aData->isValid()) {
157     if (theInfinite)
158       TDataStd_UAttribute::Set(aData->label(), kIS_INFINITE);
159     else
160       aData->label().ForgetAttribute(kIS_INFINITE);
161   }
162 }
163
164 int Model_ResultConstruction::facesNum(const bool theUpdateNaming)
165 {
166   int aResult = 0;
167   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
168   if (aData.get() && aData->isValid()) {
169     TDF_Label aShapeLab = aData->shapeLab();
170     TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
171     for (; anOldIter.More(); anOldIter.Next()) {
172       aResult++;
173     }
174   }
175   return aResult;
176 }
177
178 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
179 {
180   std::shared_ptr<GeomAPI_Face> aResult;
181   int anIndex = 0;
182   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
183   if (aData.get() && aData->isValid()) {
184     TDF_Label aShapeLab = aData->shapeLab();
185     TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
186     for (; anOldIter.More(); anOldIter.Next()) {
187       if (anIndex == theIndex) {
188         Handle(TNaming_NamedShape) aNS;
189         anOldIter.Value()->Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
190         aResult.reset(new GeomAPI_Face);
191         aResult->setImpl(new TopoDS_Shape(aNS->Get()));
192         break;
193       }
194       anIndex++;
195     }
196   }
197   return aResult;
198 }
199
200 void Model_ResultConstruction::setIsConcealed(const bool theValue)
201 {
202   // do nothing: the construction element is never concealed
203 }
204
205 void Model_ResultConstruction::storeShape(std::shared_ptr<GeomAPI_Shape> theShape)
206 {
207   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
208   if (aData && aData->isValid()) {
209     std::string aMyName = data()->name();
210     TDF_Label aShapeLab = aData->shapeLab();
211     if (!theShape.get() || theShape->isNull()) {
212       aShapeLab.ForgetAllAttributes();
213       TDataStd_Name::Set(aShapeLab, aMyName.c_str()); // restore name forgotten
214       return;
215     }
216     std::shared_ptr<Model_Document> aMyDoc =
217       std::dynamic_pointer_cast<Model_Document>(document());
218     const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
219     if (aShape.ShapeType() == TopAbs_VERTEX) {
220       aShapeLab.ForgetAllAttributes(); // clear all previously stored
221       TNaming_Builder aBuilder(aShapeLab);
222       aBuilder.Generated(aShape);
223       TDataStd_Name::Set(aShapeLab, aMyName.c_str());
224       aMyDoc->addNamingName(aShapeLab, aMyName);
225     } else if (aShape.ShapeType() == TopAbs_EDGE) { // store sub-vertices on sub-labels
226       aShapeLab.ForgetAllAttributes(); // clear all previously stored
227       TNaming_Builder aBuilder(aShapeLab);
228       aBuilder.Generated(aShape);
229
230       TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
231       for(int anIndex = 1; anExp.More(); anExp.Next(), anIndex++) {
232         TDF_Label aSubLab = aShapeLab.FindChild(anIndex);
233         TNaming_Builder aBuilder(aSubLab);
234         aBuilder.Generated(anExp.Current());
235         std::string aVertexName = aMyName + "_" + (anIndex == 1 ? "StartVertex" : "EndVertex");
236         TDataStd_Name::Set(aSubLab, aVertexName.c_str());
237         aMyDoc->addNamingName(aSubLab, aVertexName);
238       }
239       TDataStd_Name::Set(aShapeLab, aMyName.c_str());
240       aMyDoc->addNamingName(aShapeLab, aMyName);
241     } else { // this is probably sketch, so, work with it as with composite
242       std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
243         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theShape);
244       if (!aWirePtr.get())
245         return; // unknown case
246       ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
247       FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr);
248       CompositeFeaturePtr aComposite =
249         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
250       if (!aComposite || aComposite->numberOfSubs() == 0)
251         return; // unknown case
252       // collect indices of curves of current composite
253       NCollection_DataMap<Handle(Geom_Curve), int> aCurvesIndices;
254       NCollection_DataMap<int, TopoDS_Edge> anEdgeIndices;
255       std::map<int, std::string> aComponentsNames; // names of components that lay on index
256       const int aSubNum = aComposite->numberOfSubs();
257       for (int a = 0; a < aSubNum; a++) {
258         FeaturePtr aSub = aComposite->subFeature(a);
259         const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
260         std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
261         for (; aRes != aResults.cend(); aRes++) {
262           ResultConstructionPtr aConstr =
263             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
264           if (aConstr->shape() && aConstr->shape()->isEdge()) {
265             TopoDS_Edge anEdge = TopoDS::Edge(aConstr->shape()->impl<TopoDS_Shape>());
266             Standard_Real aFirst, aLast;
267             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
268             aCurvesIndices.Bind(aCurve, a);
269             anEdgeIndices.Bind(a, anEdge);
270             aComponentsNames[a] = shortName(aConstr);
271           }
272         }
273       }
274
275       std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
276       GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
277         aWirePtr->norm(), aWirePtr, aFaces);
278       NCollection_DataMap<TopoDS_Face, TColStd_ListOfInteger> aNewIndices; // edges indices
279       std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFIter = aFaces.begin();
280       for (; aFIter != aFaces.end(); aFIter++) {
281         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
282         // put them to a label, trying to keep the same faces on the same labels
283         if (aFace.get() && !aFace->isNull()) {
284           TopoDS_Face aTopoFace = TopoDS::Face(aFace->impl<TopoDS_Shape>());
285           aNewIndices.Bind(aTopoFace, TColStd_ListOfInteger());
286           // keep new indices of sub-elements used in this face
287           for (TopExp_Explorer anEdges(aTopoFace, TopAbs_EDGE); anEdges.More(); anEdges.Next()) {
288             TopoDS_Edge anEdge = TopoDS::Edge(anEdges.Current());
289             Standard_Real aFirst, aLast;
290             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
291             if (aCurvesIndices.IsBound(aCurve)) {
292               int anIndex = aCurvesIndices.Find(aCurve);
293               if ((aFirst > aLast) != (anEdge.Orientation() == TopAbs_REVERSED))
294                 anIndex = -anIndex;
295               aNewIndices.ChangeFind(aTopoFace).Append(anIndex);
296             }
297           }
298         }
299       }
300       NCollection_DataMap<int, TopoDS_Face> aFacesOrder; // faces -> tag where they must be set
301       NCollection_List<TopoDS_Face> anUnorderedFaces; // faces that may be located at any index
302       // searching for the best new candidate to old location
303       NCollection_DataMap<TopoDS_Face, TColStd_ListOfInteger>::Iterator aNewIter(aNewIndices);
304       for (; aNewIter.More(); aNewIter.Next()) {
305         double aBestFound = 0, aBestNotFound = 1.e+100;
306         int aBestTag = 0;
307         const TColStd_ListOfInteger& aNewInd = aNewIter.Value();
308         // old faces indices where they where located
309         TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
310         for (; anOldIter.More(); anOldIter.Next()) {
311           int aTag = anOldIter.Value()->Label().Tag();
312           if (aFacesOrder.IsBound(aTag))
313             continue; // already found a best candidate
314           Handle(TDataStd_IntPackedMap) anOldIndices =
315             Handle(TDataStd_IntPackedMap)::DownCast(anOldIter.Value());
316           double aFound = 0, aNotFound = 0;
317           TColStd_ListOfInteger::Iterator aNewIndIter(aNewInd);
318           for (; aNewIndIter.More(); aNewIndIter.Next()) {
319             if (anOldIndices->Contains(aNewIndIter.Value())) {
320               aFound += 1.;
321             }
322             else if (anOldIndices->Contains(-aNewIndIter.Value())) { // different orientation
323               aFound += 0.001;
324             }
325             else {
326               aNotFound += 1.;
327             }
328           }
329           if (aNotFound < aBestNotFound) {
330             if (aFound > aBestFound) {
331               aBestNotFound = aNotFound;
332               aBestFound = aFound;
333               aBestTag = aTag;
334             }
335           }
336         }
337         if (aBestTag != 0) { // found an appropriate face
338           aFacesOrder.Bind(aBestTag, aNewIter.Key());
339         } else {
340           anUnorderedFaces.Append(aNewIter.Key());
341         }
342       }
343       aShapeLab.ForgetAllAttributes(); // clear all previously stored
344       TDataStd_Name::Set(aShapeLab, aMyName.c_str()); // restore name forgotten
345       TNaming_Builder aBuilder(aShapeLab); // store the compound to get it ready on open of document
346       aBuilder.Generated(aShape);
347       aMyDoc->addNamingName(aShapeLab, aMyName);
348       // set new faces to the labels
349       int aCurrentTag = 1;
350       NCollection_List<TopoDS_Face>::Iterator anUnordered(anUnorderedFaces);
351       for(int aCurrentTag = 1; !aFacesOrder.IsEmpty() || anUnordered.More(); aCurrentTag++) {
352         TopoDS_Face aFaceToPut;
353         if (aFacesOrder.IsBound(aCurrentTag)) {
354           aFaceToPut = aFacesOrder.Find(aCurrentTag);
355           aFacesOrder.UnBind(aCurrentTag);
356         } else if (anUnordered.More()){
357           aFaceToPut = anUnordered.Value();
358           anUnordered.Next();
359         }
360
361         if (!aFaceToPut.IsNull()) {
362           TopTools_MapOfShape aFaceEdges;
363           for(TopExp_Explorer anEdges(aFaceToPut, TopAbs_EDGE); anEdges.More(); anEdges.Next()) {
364             aFaceEdges.Add(anEdges.Current());
365           }
366
367           TDF_Label aLab = aShapeLab.FindChild(aCurrentTag);
368           TNaming_Builder aFaceBuilder(aLab);
369           aFaceBuilder.Generated(aFaceToPut);
370           // store also indices of the new face edges
371           Handle(TDataStd_IntPackedMap) aNewMap = TDataStd_IntPackedMap::Set(aLab);
372           const TColStd_ListOfInteger& aNewInd = aNewIndices.Find(aFaceToPut);
373           std::stringstream aName;
374           aName<<"Face";
375           TopExp_Explorer aPutEdges(aFaceToPut, TopAbs_EDGE);
376           TNaming_Builder* anEdgesBuilder = 0;
377           for(TColStd_ListOfInteger::Iterator anIter(aNewInd); anIter.More(); anIter.Next()) {
378             int anIndex = anIter.Value();
379             int aModIndex = anIndex > 0 ? anIndex : -anIndex;
380             aNewMap->Add(anIndex);
381             aName<<"-"<<aComponentsNames[aModIndex];
382             if (anIter.Value() > 0)
383               aName<<"f";
384             else
385               aName<<"r";
386             // collect all edges of the face which are modified in sub-label of the face
387             if (anEdgeIndices.IsBound(aModIndex) &&
388                 !aFaceEdges.Contains(anEdgeIndices.Find(aModIndex))) {
389               if (!anEdgesBuilder) {
390                 TDF_Label anEdgesLabel = aLab.FindChild(1);
391                 anEdgesBuilder = new TNaming_Builder(anEdgesLabel);
392                 TDataStd_Name::Set(anEdgesLabel, "SubEdge");
393               }
394               anEdgesBuilder->Modify(anEdgeIndices.Find(aModIndex), aPutEdges.Current());
395             }
396             aPutEdges.Next();
397           }
398           TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str()));
399           aMyDoc->addNamingName(aLab, aName.str());
400         }
401       }
402     }
403   }
404 }