1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Model_ResultConstruction.h>
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>
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>
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>
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");
62 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
63 std::string& theDefault)
65 theSection = "Visualization";
66 theName = "result_construction_color";
67 theDefault = DEFAULT_COLOR();
70 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
72 if (myShape != theShape) {
75 static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
76 ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
81 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
86 bool Model_ResultConstruction::updateShape()
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
105 Model_ResultConstruction::Model_ResultConstruction()
110 bool Model_ResultConstruction::isInHistory()
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
116 return true; // unknown case
119 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
121 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
122 if (aData.get() && aData->isValid()) {
124 TDataStd_UAttribute::Set(aData->label(), kIS_IN_HISTORY);
126 aData->label().ForgetAttribute(kIS_IN_HISTORY);
130 bool Model_ResultConstruction::isInfinite()
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);
136 return false; // unknown case
139 void Model_ResultConstruction::setInfinite(const bool theInfinite)
141 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
142 if (aData.get() && aData->isValid()) {
144 TDataStd_UAttribute::Set(aData->label(), kIS_INFINITE);
146 aData->label().ForgetAttribute(kIS_INFINITE);
150 int Model_ResultConstruction::facesNum(const bool theUpdateNaming)
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()) {
164 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
166 std::shared_ptr<GeomAPI_Face> aResult;
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()));
186 void Model_ResultConstruction::setIsConcealed(const bool theValue)
188 // do nothing: the construction element is never concealed
191 void Model_ResultConstruction::storeShape(std::shared_ptr<GeomAPI_Shape> theShape)
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
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);
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);
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);
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);
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))
281 aNewIndices.ChangeFind(aTopoFace).Append(anIndex);
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;
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())) {
308 else if (anOldIndices->Contains(-aNewIndIter.Value())) { // different orientation
315 if (aNotFound < aBestNotFound) {
316 if (aFound > aBestFound) {
317 aBestNotFound = aNotFound;
323 if (aBestTag != 0) { // found an appropriate face
324 aFacesOrder.Bind(aBestTag, aNewIter.Key());
326 anUnorderedFaces.Append(aNewIter.Key());
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
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();
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());
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;
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)
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");
379 anEdgesBuilder->Modify(anEdgeIndices.Find(anIndex), aPutEdges.Current());
383 TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str()));
384 aMyDoc->addNamingName(aLab, aName.str());