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