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 GeomShapePtr aGen = *aGenIter;
348 if (aGen.get() && !aGen->isNull()) {
349 if ((*aGenIter)->shapeType() == GeomAPI_Shape::FACE) { // normal case
350 aFacesFromFromEdges.bind(aGen, anEdgeExp.current());
356 // closed revolution of 1-3 faces can not distinguish lateral and base edges
357 if (aFacesFromFromEdges.size() <= 3) {
358 bool isClosed = false; // lateral edges are closed (in full revolution)
359 GeomAPI_DataMapOfShapeShape anEdgesFromVertices;
360 GeomAPI_ShapeExplorer aVertExp(theBaseShape, GeomAPI_Shape::VERTEX);
361 for(; aVertExp.more(); aVertExp.next()) {
362 ListOfShape aGenerated;
363 theMakeShape->generated(aVertExp.current(), aGenerated);
364 ListOfShape::iterator aGenIter = aGenerated.begin();
365 for(; aGenIter != aGenerated.end(); aGenIter++) {
366 std::shared_ptr<GeomAPI_Shape> aGenerated = *aGenIter;
367 if (anEdgesFromVertices.isBound(aGenerated)) // already here
369 std::ostringstream aStream;
370 aStream<<"Lateral_"<<theTag++;
371 theResultBody->generated(aGenerated, aStream.str(), theTag++);
373 anEdgesFromVertices.bind(aGenerated, aVertExp.current());
374 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aGenerated));
375 isClosed = isClosed || anEdge->isClosed();
379 GeomAPI_ShapeExplorer anEdgesExp(theMakeShape->shape(), GeomAPI_Shape::EDGE);
380 for(; anEdgesExp.more(); anEdgesExp.next()) {
381 if (!anEdgesFromVertices.isBound(anEdgesExp.current())) {
383 std::ostringstream aStream;
384 aStream<<"Base_Edge_"<<theTag++;
385 theResultBody->generated(anEdgesExp.current(), aStream.str(), theTag++);
386 // only one orientation is needed
387 anEdgesFromVertices.bind(anEdgesExp.current(), anEdgesExp.current());
390 } else if (aFacesFromFromEdges.size() == 1) { // 2233: sphere created by the revolution:
391 // vertices at degenerated edges will have the same name
392 GeomAPI_DataMapOfShapeShape aVertices;
393 GeomAPI_ShapeExplorer aVertExp(theMakeShape->shape(), GeomAPI_Shape::VERTEX);
394 for(int anIndex = 1; aVertExp.more(); aVertExp.next()) {
395 if (!aVertices.isBound(aVertExp.current())) {
397 std::ostringstream aStream;
398 aStream<<"Vertex_"<<theTag++;
399 theResultBody->generated(aVertExp.current(), aStream.str(), theTag++);
400 // only one orientation is needed
401 aVertices.bind(aVertExp.current(), aVertExp.current());
405 } else { // issue #2197, test case 4 : edges that produce fully-revolved face,
406 // but contain only 2 edges (on apex of revolution)
407 GeomAPI_ShapeExplorer anEdgeExp(theBaseShape, GeomAPI_Shape::EDGE);
408 for(; anEdgeExp.more(); anEdgeExp.next()) {
409 ListOfShape aGenerated;
410 theMakeShape->generated(anEdgeExp.current(), aGenerated);
411 ListOfShape::iterator aGenIter = aGenerated.begin();
412 for(; aGenIter != aGenerated.end(); aGenIter++) {
413 GeomShapePtr aGen = (*aGenIter);
414 if (aGen.get() && !aGen->isNull()) {
415 GeomAPI_ShapeExplorer aFaceEdgeExp(aGen, GeomAPI_Shape::EDGE);
418 GeomShapePtr aNotClosedEdge;
419 GeomEdgePtr aDegenerateEdge;
420 GeomAPI_DataMapOfShapeShape alreadyIterated;
421 for(; aFaceEdgeExp.more(); aFaceEdgeExp.next()) {
422 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aFaceEdgeExp.current()));
423 if (anEdge->isDegenerated()) {
424 aDegenerateEdge = anEdge;
427 if (alreadyIterated.isBound(anEdge))
429 alreadyIterated.bind(anEdge, anEdge);
431 if (anEdge->isClosed()) {
434 aNotClosedEdge = anEdge;
437 if (aNumEdges == 2 && aNumClosed == 1) {
438 std::ostringstream aStream;
439 aStream<<"Base_Edge_"<<theTag++;
440 theResultBody->generated(aNotClosedEdge, aStream.str(), theTag++);
441 if (aDegenerateEdge.get()) { // export vertex of the degenerated edge (apex) #2520
442 GeomAPI_ShapeExplorer anEdgeExp(aDegenerateEdge, GeomAPI_Shape::VERTEX);
443 if (anEdgeExp.more()) {
444 std::ostringstream aStream;
445 aStream << "Base_Vertex_" << theTag++;
446 theResultBody->generated(anEdgeExp.current(), aStream.str(), theTag++);
456 std::shared_ptr<GeomAlgoAPI_MakeSweep> aMakeSweep =
457 std::dynamic_pointer_cast<GeomAlgoAPI_MakeSweep>(theMakeShape);
458 if(aMakeSweep.get()) {
459 // Store from shapes.
460 storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
461 aMakeSweep->fromShapes(), "From_", theTag);
464 storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
465 aMakeSweep->toShapes(), "To_", theTag);
469 //=================================================================================================
470 void FeaturesPlugin_CompositeSketch::storeShapes(ResultBodyPtr theResultBody,
471 const GeomAPI_Shape::ShapeType theBaseShapeType,
472 const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
473 const ListOfShape& theShapes,
474 const std::string theName,
477 GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
478 std::string aShapeTypeStr = "Face";
479 switch(theBaseShapeType) {
480 case GeomAPI_Shape::VERTEX: {
481 aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
482 aShapeTypeStr = "Vertex";
485 case GeomAPI_Shape::EDGE:
486 case GeomAPI_Shape::WIRE: {
487 aShapeTypeToExplore = GeomAPI_Shape::EDGE;
488 aShapeTypeStr = "Edge";
491 case GeomAPI_Shape::FACE:
492 case GeomAPI_Shape::SHELL: {
493 aShapeTypeToExplore = GeomAPI_Shape::FACE;
494 aShapeTypeStr = "Face";
497 case GeomAPI_Shape::COMPOUND: {
498 aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
506 for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
507 GeomShapePtr aShape = *anIt;
509 if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
510 std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
511 storeSubShape(theResultBody,
516 aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex,
519 std::string aName = theName + aShapeTypeStr;
520 storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
521 theMapOfSubShapes, aName, aShapeIndex, theTag);
522 if (theBaseShapeType == GeomAPI_Shape::WIRE) { // issue 2289: special names also for vertices
523 aName = theName + "Vertex";
524 storeSubShape(theResultBody, aShape, GeomAPI_Shape::VERTEX,
525 theMapOfSubShapes, aName, aShapeIndex, theTag);
531 void storeSubShape(ResultBodyPtr theResultBody,
532 const GeomShapePtr theShape,
533 const GeomAPI_Shape::ShapeType theType,
534 const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
535 const std::string theName,
539 for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
540 GeomShapePtr aSubShape = anExp.current();
541 if(theMapOfSubShapes->isBound(aSubShape)) {
542 aSubShape = theMapOfSubShapes->find(aSubShape);
544 std::ostringstream aStr;
545 aStr << theName << "_" << theShapeIndex++;
546 theResultBody->generated(aSubShape, aStr.str(), theTag++);