Salome HOME
Issue #2231: Wrong name of partition objects leads to wrong python dump
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Partition.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 "FeaturesPlugin_Partition.h"
22
23 #include <ModelAPI_Data.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_AttributeBoolean.h>
26 #include <ModelAPI_AttributeReference.h>
27 #include <ModelAPI_AttributeInteger.h>
28 #include <ModelAPI_BodyBuilder.h>
29 #include <ModelAPI_ResultBody.h>
30 #include <ModelAPI_AttributeSelectionList.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_Validator.h>
33
34 #include <GeomAlgoAPI_CompoundBuilder.h>
35 #include <GeomAlgoAPI_Partition.h>
36 #include <GeomAlgoAPI_MakeShapeCustom.h>
37 #include <GeomAlgoAPI_MakeShapeList.h>
38 #include <GeomAlgoAPI_ShapeTools.h>
39
40 #include <GeomAPI_Face.h>
41 #include <GeomAPI_ShapeExplorer.h>
42 #include <GeomAPI_ShapeIterator.h>
43
44 #include <iostream>
45 #include <sstream>
46
47 static GeomShapePtr findBase(const GeomShapePtr theObjectShape,
48                              const GeomShapePtr theResultShape,
49                              const GeomAPI_Shape::ShapeType theShapeType,
50                              const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape);
51
52 //=================================================================================================
53 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
54 {
55 }
56
57 //=================================================================================================
58 void FeaturesPlugin_Partition::initAttributes()
59 {
60   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
61 }
62
63 //=================================================================================================
64 void FeaturesPlugin_Partition::execute()
65 {
66   ListOfShape anObjects, aPlanes;
67
68   // Getting objects.
69   AttributeSelectionListPtr anObjectsSelList = selectionList(BASE_OBJECTS_ID());
70   for(int anIndex = 0; anIndex < anObjectsSelList->size(); ++anIndex) {
71     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anIndex);
72     GeomShapePtr anObject = anObjectAttr->value();
73     if(!anObject.get()) {
74       // It could be a construction plane.
75       ResultPtr aContext = anObjectAttr->context();
76       aPlanes.push_back(anObjectAttr->context()->shape());
77     } else {
78       anObjects.push_back(anObject);
79     }
80   }
81
82   if(anObjects.empty()) {
83     static const std::string aFeatureError = "Error: No objects for partition.";
84     setError(aFeatureError);
85     return;
86   }
87
88   std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
89     GeomAlgoAPI_ShapeTools::getBoundingBox(anObjects, 1.0);
90
91   // Resize planes.
92   ListOfShape aTools;
93   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
94   for(ListOfShape::const_iterator anIt = aPlanes.cbegin(); anIt != aPlanes.cend(); ++anIt) {
95     GeomShapePtr aPlane = *anIt;
96     GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
97     std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(new GeomAlgoAPI_MakeShapeCustom);
98     aMkShCustom->addModified(aPlane, aTool);
99     aMakeShapeList->appendAlgo(aMkShCustom);
100     aTools.push_back(aTool);
101   }
102
103   // Create single result.
104   std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
105     new GeomAlgoAPI_Partition(anObjects, aTools));
106
107   // Checking that the algorithm worked properly.
108   if (!aPartitionAlgo->isDone()) {
109     static const std::string aFeatureError = "Error: Partition algorithm failed.";
110     setError(aFeatureError);
111     return;
112   }
113   if (aPartitionAlgo->shape()->isNull()) {
114     static const std::string aShapeError = "Error: Resulting shape is Null.";
115     setError(aShapeError);
116     return;
117   }
118   if (!aPartitionAlgo->isValid()) {
119     std::string aFeatureError = "Error: Resulting shape is not valid.";
120     setError(aFeatureError);
121     return;
122   }
123   aMakeShapeList->appendAlgo(aPartitionAlgo);
124   GeomShapePtr aResultShape = aPartitionAlgo->shape();
125
126   int aResultIndex = 0;
127   if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
128     for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
129       storeResult(anObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
130       ++aResultIndex;
131     }
132   } else {
133     storeResult(anObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
134     ++aResultIndex;
135   }
136
137   // Remove the rest results if there were produced in the previous pass.
138   removeResults(aResultIndex);
139 }
140
141 //=================================================================================================
142 void FeaturesPlugin_Partition::storeResult(
143   ListOfShape& theObjects, ListOfShape& thePlanes,
144   const GeomShapePtr theResultShape,
145   const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
146   const int theIndex)
147 {
148   // Find base. The most complicated is the real modified object (#1799 if box is partitioned by
149   // two planes the box is the base, not planes, independently on the order in the list).
150   GeomShapePtr aBaseShape;
151   for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
152     GeomShapePtr anObjectShape = *anIt;
153     GeomShapePtr aCandidate =
154       findBase(anObjectShape, theResultShape, GeomAPI_Shape::VERTEX, theMakeShape);
155     if(!aCandidate.get()) {
156       aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::EDGE, theMakeShape);
157     }
158     if (!aCandidate.get())
159       aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::FACE, theMakeShape);
160
161     if(aCandidate.get()) {
162       if (!aBaseShape.get() || aBaseShape->shapeType() > aCandidate->shapeType()) {
163         aBaseShape = aCandidate;
164       }
165     }
166   }
167
168   // Create result body.
169   ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
170
171   // Store modified shape.
172   if(!aBaseShape.get() || aBaseShape->isEqual(theResultShape)) {
173     aResultBody->store(theResultShape, false);
174     setResult(aResultBody, theIndex);
175     return;
176   }
177
178   const int aDelTag = 1;
179   /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
180   const int aSubTag = 2;
181   int aModTag = aSubTag + 10000;
182   const std::string aModName = "Modified";
183
184   aResultBody->storeModified(aBaseShape, theResultShape, aSubTag);
185
186   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
187   theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
188   int anIndex = 1;
189   for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
190     GeomShapePtr aShape = *anIt;
191     std::string aModEdgeName = aModName + "_Edge_" + std::to_string((long long)anIndex);
192     aResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::EDGE,
193       aModTag, aModEdgeName, *aMapOfSubShapes.get(), false, true, true);
194     std::string aModFaceName = aModName + "_Face_" + std::to_string((long long)anIndex++);
195     aResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::FACE,
196       aModTag + 1, aModFaceName, *aMapOfSubShapes.get(), false, true, true);
197     aResultBody->loadDeletedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::FACE, aDelTag);
198   }
199
200   setResult(aResultBody, theIndex);
201 }
202
203
204 //=================================================================================================
205 GeomShapePtr findBase(const GeomShapePtr theObjectShape,
206                       const GeomShapePtr theResultShape,
207                       const GeomAPI_Shape::ShapeType theShapeType,
208                       const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
209 {
210   GeomShapePtr aBaseShape;
211   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
212   for(GeomAPI_ShapeExplorer anObjectSubShapesExp(theObjectShape, theShapeType);
213       anObjectSubShapesExp.more();
214       anObjectSubShapesExp.next()) {
215     GeomShapePtr anObjectSubShape = anObjectSubShapesExp.current();
216     ListOfShape aModifiedShapes;
217     theMakeShape->modified(anObjectSubShape, aModifiedShapes);
218     for(ListOfShape::const_iterator
219         aModIt = aModifiedShapes.cbegin(); aModIt != aModifiedShapes.cend(); ++aModIt) {
220       GeomShapePtr aModShape = *aModIt;
221       if(aMapOfSubShapes->isBound(aModShape)) {
222         aModShape = aMapOfSubShapes->find(aModShape);
223       }
224       if(theResultShape->isSubShape(aModShape)) {
225         aBaseShape = theObjectShape;
226         break;
227       }
228     }
229     if(aBaseShape.get()) {
230       break;
231     }
232   }
233
234   return aBaseShape;
235 }