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 <FeaturesPlugin_CompositeSketch.h>
23 #include <ModelAPI_AttributeSelectionList.h>
24 #include <ModelAPI_AttributeReference.h>
25 #include <ModelAPI_BodyBuilder.h>
26 #include <ModelAPI_ResultConstruction.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_Validator.h>
30 #include <GeomAlgoAPI_CompoundBuilder.h>
31 #include <GeomAlgoAPI_Prism.h>
32 #include <GeomAlgoAPI_Revolution.h>
33 #include <GeomAlgoAPI_ShapeTools.h>
34 #include <GeomAlgoAPI_SketchBuilder.h>
36 #include <GeomAPI_PlanarEdges.h>
37 #include <GeomAPI_ShapeExplorer.h>
42 static void storeSubShape(ResultBodyPtr theResultBody,
43 const GeomShapePtr theShape,
44 const GeomAPI_Shape::ShapeType theType,
45 const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
46 const std::string theName,
50 //=================================================================================================
51 void FeaturesPlugin_CompositeSketch::initCompositeSketchAttribtues(const int theInitFlags)
53 // Initialize sketch launcher.
54 if(theInitFlags & InitSketchLauncher) {
55 data()->addAttribute(SKETCH_ID(), ModelAPI_AttributeReference::typeId());
56 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SKETCH_ID());
59 // Initialize selection list.
60 if(theInitFlags & InitBaseObjectsList) {
61 data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
65 //=================================================================================================
66 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::addFeature(std::string theID)
68 FeaturePtr aNew = document()->addFeature(theID, false);
70 data()->reference(SKETCH_ID())->setValue(aNew);
73 // Set as current also after it becomes sub to set correctly enabled for other sketch subs.
74 document()->setCurrentFeature(aNew, false);
78 //=================================================================================================
79 int FeaturesPlugin_CompositeSketch::numberOfSubs(bool forTree) const
81 ObjectPtr aObj = data()->reference(SKETCH_ID())->value();
82 return aObj.get() ? 1 : 0;
85 //=================================================================================================
86 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::subFeature(const int theIndex,
90 return std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
93 return std::shared_ptr<ModelAPI_Feature>();
96 //=================================================================================================
97 int FeaturesPlugin_CompositeSketch::subFeatureId(const int theIndex) const
100 FeaturePtr aFeature =
101 std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
103 return aFeature->data()->featureId();
110 //=================================================================================================
111 bool FeaturesPlugin_CompositeSketch::isSub(ObjectPtr theObject) const
113 // Check is this feature of result
114 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
115 if(!aFeature.get()) {
119 ObjectPtr aSub = data()->reference(SKETCH_ID())->value();
120 return aSub == theObject;
123 //=================================================================================================
124 void FeaturesPlugin_CompositeSketch::removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature)
126 AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
127 if(aBaseObjectsSelectionList.get() && aBaseObjectsSelectionList->size() > 0) {
128 aBaseObjectsSelectionList->clear();
131 reference(SKETCH_ID())->setValue(ObjectPtr());
134 //=================================================================================================
135 void FeaturesPlugin_CompositeSketch::getBaseShapes(ListOfShape& theBaseShapesList,
136 const bool theIsMakeShells)
138 theBaseShapesList.clear();
140 ListOfShape aBaseFacesList;
141 std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
142 AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
143 if(!aBaseObjectsSelectionList.get()) {
144 setError("Error: Could not get base objects selection list.");
147 if(aBaseObjectsSelectionList->size() == 0) {
148 setError("Error: Base objects list is empty.");
151 for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
152 AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
153 if(!aBaseObjectSelection.get()) {
154 setError("Error: Selected base object is empty.");
157 GeomShapePtr aBaseShape = aBaseObjectSelection->value();
158 if(aBaseShape.get() && !aBaseShape->isNull()) {
159 GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
160 if(aST == GeomAPI_Shape::SOLID || aST == GeomAPI_Shape::COMPSOLID) {
161 setError("Error: Selected shapes has unsupported type.");
164 ResultConstructionPtr aConstruction =
165 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
166 if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
167 aST == GeomAPI_Shape::WIRE) {
168 // It is a wire on the sketch, store it to make face later.
169 aSketchWiresMap[aConstruction].push_back(aBaseShape);
172 aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
173 theBaseShapesList.push_back(aBaseShape);
176 // This may be the whole sketch result selected, check and get faces.
177 ResultConstructionPtr aConstruction =
178 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
179 if(!aConstruction.get()) {
180 setError("Error: Selected sketches does not have results.");
183 int aFacesNum = aConstruction->facesNum();
185 // Probably it can be construction.
186 aBaseShape = aConstruction->shape();
187 if(aBaseShape.get() && !aBaseShape->isNull()) {
188 GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
189 if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE &&
190 aST != GeomAPI_Shape::WIRE &&
191 aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
192 setError("Error: Selected shapes has unsupported type.");
195 aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
196 theBaseShapesList.push_back(aBaseShape);
199 for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
200 GeomShapePtr aBaseFace = aConstruction->face(aFaceIndex);
201 if(!aBaseFace.get() || aBaseFace->isNull()) {
202 setError("Error: One of the faces on selected sketch is null.");
205 aBaseFacesList.push_back(aBaseFace);
211 // Make faces from sketch wires.
212 for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
213 anIt != aSketchWiresMap.cend(); ++anIt) {
214 const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
215 std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
216 const ListOfShape& aWiresList = (*anIt).second;
218 GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
219 aSketchPlanarEdges->norm(),
222 aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
225 // Searching faces with common edges.
226 if(theIsMakeShells && aBaseFacesList.size() > 1) {
228 ListOfShape aFreeFaces;
229 GeomShapePtr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
230 GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL,
231 aShells, aFreeFaces);
232 theBaseShapesList.insert(theBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
233 theBaseShapesList.insert(theBaseShapesList.end(), aShells.begin(), aShells.end());
235 theBaseShapesList.insert(theBaseShapesList.end(), aBaseFacesList.begin(),
236 aBaseFacesList.end());
240 //=================================================================================================
241 bool FeaturesPlugin_CompositeSketch::isMakeShapeValid(
242 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
244 // Check that algo is done.
245 if(!theMakeShape->isDone()) {
246 setError("Error: " + getKind() + " algorithm failed.");
250 // Check if shape is not null.
251 if(!theMakeShape->shape().get() || theMakeShape->shape()->isNull()) {
252 setError("Error: Resulting shape is null.");
256 // Check that resulting shape is valid.
257 if(!theMakeShape->isValid()) {
258 setError("Error: Resulting shape is not valid.");
265 //=================================================================================================
266 void FeaturesPlugin_CompositeSketch::storeResult(const GeomShapePtr theBaseShape,
267 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
270 // Create result body.
271 ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
273 // Store generated shape.
274 aResultBody->storeGenerated(theBaseShape, theMakeShape->shape());
276 // Store generated edges/faces.
278 storeGenerationHistory(aResultBody, theBaseShape, theMakeShape, aGenTag);
280 setResult(aResultBody, theIndex);
283 //=================================================================================================
284 void FeaturesPlugin_CompositeSketch::storeGenerationHistory(ResultBodyPtr theResultBody,
285 const GeomShapePtr theBaseShape,
286 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
289 GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
290 GeomAPI_Shape::ShapeType aShapeTypeToExplode = GeomAPI_Shape::SHAPE;
291 std::string aGenName = "Generated_";
293 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
294 switch(aBaseShapeType) {
295 case GeomAPI_Shape::EDGE: {
296 aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
299 case GeomAPI_Shape::WIRE: {
300 //std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
301 //GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
302 //ListOfShape aV1History, aV2History;
303 //theMakeShape->generated(aV1, aV1History);
304 //theMakeShape->generated(aV2, aV2History);
305 //if(!aV1History.empty()) {
306 // theResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", theTag++);
308 //if(!aV2History.empty()) {
309 // theResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", theTag++);
311 aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
314 case GeomAPI_Shape::FACE:
315 case GeomAPI_Shape::SHELL: {
316 aShapeTypeToExplode = GeomAPI_Shape::EDGE;
319 case GeomAPI_Shape::COMPOUND: {
320 aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
324 if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
325 aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
326 theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(), theBaseShape,
327 GeomAPI_Shape::VERTEX,
328 theTag++, aGenName + "Edge",
329 *aMapOfSubShapes.get());
331 if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
332 aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
333 theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(),
334 theBaseShape, GeomAPI_Shape::EDGE,
335 theTag++, aGenName + "Face",
336 *aMapOfSubShapes.get());
338 // issue #2197: make naming of edges generated from vertices
339 if (aShapeTypeToExplode == GeomAPI_Shape::EDGE) {
340 GeomAPI_DataMapOfShapeShape aFacesFromFromEdges;
341 GeomAPI_ShapeExplorer anEdgeExp(theBaseShape, GeomAPI_Shape::EDGE);
342 for(; anEdgeExp.more(); anEdgeExp.next()) {
343 ListOfShape aGenerated;
344 theMakeShape->generated(anEdgeExp.current(), aGenerated);
345 ListOfShape::iterator aGenIter = aGenerated.begin();
346 for(; aGenIter != aGenerated.end(); aGenIter++) {
347 aFacesFromFromEdges.bind(*aGenIter, anEdgeExp.current());
351 // closed revolution of 1-3 faces can not distinguish lateral and base edges
352 if (aFacesFromFromEdges.size() <= 3) {
353 bool isClosed = false; // lateral edges are closed (in full revolution)
354 GeomAPI_DataMapOfShapeShape anEdgesFromVertices;
355 GeomAPI_ShapeExplorer aVertExp(theBaseShape, GeomAPI_Shape::VERTEX);
356 for(int anIndex = 1; aVertExp.more(); aVertExp.next()) {
357 ListOfShape aGenerated;
358 theMakeShape->generated(aVertExp.current(), aGenerated);
359 ListOfShape::iterator aGenIter = aGenerated.begin();
360 for(; aGenIter != aGenerated.end(); aGenIter++) {
361 std::shared_ptr<GeomAPI_Shape> aGenerated = *aGenIter;
362 if (anEdgesFromVertices.isBound(aGenerated)) // already here
364 std::ostringstream aStream;
365 aStream<<"Lateral_Edge_"<<anIndex++;
366 theResultBody->generated(aGenerated, aStream.str(), theTag++);
368 anEdgesFromVertices.bind(aGenerated, aVertExp.current());
369 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aGenerated));
370 isClosed = isClosed || anEdge->isClosed();
374 GeomAPI_ShapeExplorer anEdgesExp(theMakeShape->shape(), GeomAPI_Shape::EDGE);
375 for(int anIndex = 1; anEdgesExp.more(); anEdgesExp.next()) {
376 if (!anEdgesFromVertices.isBound(anEdgesExp.current())) {
378 std::ostringstream aStream;
379 aStream<<"Base_Edge_"<<anIndex++;
380 theResultBody->generated(anEdgesExp.current(), aStream.str(), theTag++);
381 // only one orientation is needed
382 anEdgesFromVertices.bind(anEdgesExp.current(), anEdgesExp.current());
389 std::shared_ptr<GeomAlgoAPI_MakeSweep> aMakeSweep =
390 std::dynamic_pointer_cast<GeomAlgoAPI_MakeSweep>(theMakeShape);
391 if(aMakeSweep.get()) {
392 // Store from shapes.
393 storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
394 aMakeSweep->fromShapes(), "From_", theTag);
397 storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
398 aMakeSweep->toShapes(), "To_", theTag);
402 //=================================================================================================
403 void FeaturesPlugin_CompositeSketch::storeShapes(ResultBodyPtr theResultBody,
404 const GeomAPI_Shape::ShapeType theBaseShapeType,
405 const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
406 const ListOfShape& theShapes,
407 const std::string theName,
410 GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
411 std::string aShapeTypeStr = "Face";
412 switch(theBaseShapeType) {
413 case GeomAPI_Shape::VERTEX: {
414 aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
415 aShapeTypeStr = "Vertex";
418 case GeomAPI_Shape::EDGE:
419 case GeomAPI_Shape::WIRE: {
420 aShapeTypeToExplore = GeomAPI_Shape::EDGE;
421 aShapeTypeStr = "Edge";
424 case GeomAPI_Shape::FACE:
425 case GeomAPI_Shape::SHELL: {
426 aShapeTypeToExplore = GeomAPI_Shape::FACE;
427 aShapeTypeStr = "Face";
430 case GeomAPI_Shape::COMPOUND: {
431 aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
439 for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
440 GeomShapePtr aShape = *anIt;
442 if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
443 std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
444 storeSubShape(theResultBody,
449 aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex,
452 std::string aName = theName + aShapeTypeStr;
453 storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
454 theMapOfSubShapes, aName, aShapeIndex, theTag);
459 void storeSubShape(ResultBodyPtr theResultBody,
460 const GeomShapePtr theShape,
461 const GeomAPI_Shape::ShapeType theType,
462 const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
463 const std::string theName,
467 for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
468 GeomShapePtr aSubShape = anExp.current();
469 if(theMapOfSubShapes->isBound(aSubShape)) {
470 aSubShape = theMapOfSubShapes->find(aSubShape);
472 std::ostringstream aStr;
473 aStr << theName << "_" << theShapeIndex++;
474 theResultBody->generated(aSubShape, aStr.str(), theTag++);