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