Update behavior of FUSE operation to keep hierarchy of compounds.
FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse(
const std::shared_ptr<ModelAPI_Feature>& theFeature,
const std::list<ModelHighAPI_Selection>& theMainObjects,
- const bool theRemoveEdges)
+ const bool theRemoveEdges,
+ const int theVersion)
: ModelHighAPI_Interface(theFeature)
{
if (initialize()) {
fillAttribute(FeaturesPlugin_BooleanFuse::CREATION_METHOD_SIMPLE(), mycreationMethod);
+ fillAttribute(theVersion, theFeature->integer(FeaturesPlugin_Boolean::VERSION_ID()));
fillAttribute(theMainObjects, mymainObjects);
fillAttribute(theRemoveEdges, myremoveEdges);
const std::shared_ptr<ModelAPI_Feature>& theFeature,
const std::list<ModelHighAPI_Selection>& theMainObjects,
const std::list<ModelHighAPI_Selection>& theToolObjects,
- const bool theRemoveEdges)
+ const bool theRemoveEdges,
+ const int theVersion)
: ModelHighAPI_Interface(theFeature)
{
if(initialize()) {
fillAttribute(FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED(), mycreationMethod);
+ fillAttribute(theVersion, theFeature->integer(FeaturesPlugin_Boolean::VERSION_ID()));
fillAttribute(theMainObjects, mymainObjects);
fillAttribute(theToolObjects, mytoolObjects);
fillAttribute(theRemoveEdges, myremoveEdges);
aBase->selectionList(FeaturesPlugin_BooleanFuse::TOOL_LIST_ID());
AttributeBooleanPtr aRemoveEdges =
aBase->boolean(FeaturesPlugin_BooleanFuse::REMOVE_INTERSECTION_EDGES_ID());
+ AttributeIntegerPtr aVersion =
+ aBase->integer(FeaturesPlugin_BooleanFuse::VERSION_ID());
theDumper << "(" << aDocName << ", " << anObjects;
theDumper << ", " << aTools;
}
- if (aRemoveEdges->value()) {
- theDumper << ", " << true;
+ bool hasVersion = aVersion && aVersion->isInitialized();
+ if (aRemoveEdges->value() || hasVersion) {
+ theDumper << ", " << aRemoveEdges->value();
+ }
+
+ if (hasVersion) {
+ theDumper << ", " << aVersion->value();
}
theDumper << ")" << std::endl;
//==================================================================================================
BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
const std::list<ModelHighAPI_Selection>& theObjects,
- const bool theRemoveEdges)
+ const bool theRemoveEdges,
+ const int theVersion)
{
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_BooleanFuse::ID());
return BooleanFusePtr(new FeaturesAPI_BooleanFuse(aFeature,
theObjects,
- theRemoveEdges));
+ theRemoveEdges,
+ theVersion));
}
//==================================================================================================
BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
const std::list<ModelHighAPI_Selection>& theMainObjects,
const std::list<ModelHighAPI_Selection>& theToolObjects,
- const bool theRemoveEdges)
+ const bool theRemoveEdges,
+ const int theVersion)
{
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_BooleanFuse::ID());
return BooleanFusePtr(new FeaturesAPI_BooleanFuse(aFeature,
theMainObjects,
theToolObjects,
- theRemoveEdges));
+ theRemoveEdges,
+ theVersion));
}
/// Constructor with values.
FEATURESAPI_EXPORT
- FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theMainObjects,
- const bool theRemoveEdges = false);
+ FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<ModelHighAPI_Selection>& theMainObjects,
+ const bool theRemoveEdges = false,
+ const int theVersion = 0);
/// Constructor with values.
FEATURESAPI_EXPORT
FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
const std::list<ModelHighAPI_Selection>& theMainObjects,
const std::list<ModelHighAPI_Selection>& theToolObjects,
- const bool theRemoveEdges = false);
+ const bool theRemoveEdges = false,
+ const int theVersion = 0);
/// Destructor.
FEATURESAPI_EXPORT
FEATURESAPI_EXPORT
BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
const std::list<ModelHighAPI_Selection>& theObjects,
- const bool theRemoveEdges = false);
+ const bool theRemoveEdges = false,
+ const int theVersion = 0);
/// \ingroup CPPHighAPI
/// \brief Create Boolean Fuse feature.
BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
const std::list<ModelHighAPI_Selection>& theMainObjects,
const std::list<ModelHighAPI_Selection>& theToolObjects,
- const bool theRemoveEdges = false);
+ const bool theRemoveEdges = false,
+ const int theVersion = 0);
#endif // FeaturesAPI_BooleanFuse_H_
TestBooleanFuse_MultiLevelCompound_v0_1.py
TestBooleanFuse_MultiLevelCompound_v0_2.py
TestBooleanFuse_MultiLevelCompound_v0_3.py
+ TestBooleanFuse_MultiLevelCompound_v0_4.py
+ TestBooleanFuse_MultiLevelCompound_v20190506_1.py
+ TestBooleanFuse_MultiLevelCompound_v20190506_2.py
+ TestBooleanFuse_MultiLevelCompound_v20190506_3.py
+ TestBooleanFuse_MultiLevelCompound_v20190506_4.py
TestBooleanSmash_MultiLevelCompound0.py
TestBooleanSplit_MultiLevelCompound0.py
TestPartition_MultiLevelCompound0.py
#include <GeomAlgoAPI_MakeShapeList.h>
#include <GeomAlgoAPI_Partition.h>
#include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_ShapeBuilder.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <GeomAlgoAPI_Tools.h>
#include <GeomAPI_Face.h>
const GeomShapePtr& theParent)
{
myParent[theShape] = theParent;
- mySubshapes[theParent].push_back(theShape);
+
+ MapShapeToIndex::iterator aFound = myParentIndices.find(theParent);
+ size_t anIndex = myParentIndices.size();
+ if (aFound == myParentIndices.end()) {
+ myParentIndices[theParent] = anIndex;
+ mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape()));
+ } else
+ anIndex = aFound->second;
+
+ mySubshapes[anIndex].second.push_back(theShape);
}
GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::Parent(const GeomShapePtr& theShape,
if (theMarkProcessed) {
// mark the parent and all its subs as processed by Boolean algorithm
myProcessedObjects.insert(aParent);
- const ListOfShape& aSubs = mySubshapes[aParent];
+ const ListOfShape& aSubs = mySubshapes[myParentIndices[aParent]].second;
for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt)
myProcessedObjects.insert(*anIt);
}
theUsed.clear();
theNotUsed.clear();
- const ListOfShape& aSubs = mySubshapes.find(theCompShape)->second;
+ MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape);
+ if (aFoundIndex == myParentIndices.end())
+ return; // no such shape
+
+ const ListOfShape& aSubs = mySubshapes[aFoundIndex->second].second;
SetOfShape aSubsSet;
aSubsSet.insert(aSubs.begin(), aSubs.end());
- for (GeomAPI_ShapeExplorer anExp(theCompShape, GeomAPI_Shape::SOLID);
- anExp.more(); anExp.next()) {
+ for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) {
GeomShapePtr aCurrent = anExp.current();
if (aSubsSet.find(aCurrent) == aSubsSet.end())
theNotUsed.push_back(aCurrent);
return myObjects.empty();
}
+void FeaturesPlugin_Boolean::ObjectHierarchy::CompoundsOfUnusedObjects(
+ ListOfShape& theDestination) const
+{
+ SetOfShape aUsedObjects;
+ aUsedObjects.insert(myObjects.begin(), myObjects.end());
+
+ for (std::vector<ShapeAndSubshapes>::const_iterator anIt = mySubshapes.begin();
+ anIt != mySubshapes.end(); ++anIt) {
+ MapShapeToParent::const_iterator aParent = myParent.find(anIt->first);
+ if ((aParent == myParent.end() || !aParent->second) &&
+ anIt->first->shapeType() == GeomAPI_Shape::COMPOUND) {
+ // this is a top-level compound
+ GeomShapePtr aCompound = collectUnusedSubs(anIt->first, aUsedObjects);
+ // add to destination non-empty compounds only
+ if (aCompound)
+ theDestination.push_back(aCompound);
+ }
+ }
+}
+
+GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::collectUnusedSubs(
+ GeomShapePtr theTopLevelCompound,
+ const SetOfShape& theUsed) const
+{
+ GeomShapePtr aResult = theTopLevelCompound->emptyCopied();
+ bool isResultEmpty = true;
+
+ for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) {
+ GeomShapePtr aCurrent = aSub.current();
+ if (theUsed.find(aCurrent) != theUsed.end())
+ continue; // already used
+
+ MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent);
+ if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND ||
+ aFoundIndex == myParentIndices.end()) {
+ bool isAddShape = true;
+ // check compsolid is fully unused in the Boolean operation
+ if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) {
+ for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next())
+ isAddShape = theUsed.find(anIt.current()) == theUsed.end();
+ }
+
+ if (isAddShape) { // low-level shape, add it
+ GeomAlgoAPI_ShapeBuilder::add(aResult, aCurrent);
+ isResultEmpty = false;
+ }
+ } else {
+ GeomShapePtr aCompound = collectUnusedSubs(aCurrent, theUsed);
+ if (aCompound) {
+ GeomAlgoAPI_ShapeBuilder::add(theTopLevelCompound, aCompound);
+ isResultEmpty = false;
+ }
+ }
+ }
+ return isResultEmpty ? GeomShapePtr() : aResult;
+}
+
+
FeaturesPlugin_Boolean::ObjectHierarchy::Iterator FeaturesPlugin_Boolean::ObjectHierarchy::Begin()
{
return Iterator(this);
return MY_TOOL_LIST_ID;
}
+ /// Attribute name of the version of Boolean feature
+ inline static const std::string& VERSION_ID()
+ {
+ static const std::string MY_VERSION_ID("version");
+ return MY_VERSION_ID;
+ }
+
/// \return boolean operation type.
FEATURESPLUGIN_EXPORT OperationType operationType();
/// Auxiliary class to store hierarchy of Boolean operation objects/tools
/// and their parent shapes (compounds or compsolids)
class ObjectHierarchy {
- typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator> MapShapeToSubshapes;
+ typedef std::pair<GeomShapePtr, ListOfShape> ShapeAndSubshapes;
typedef std::map<GeomShapePtr, GeomShapePtr, GeomAPI_Shape::Comparator> MapShapeToParent;
+ typedef std::map<GeomShapePtr, size_t, GeomAPI_Shape::Comparator> MapShapeToIndex;
typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
- ListOfShape myObjects;
- MapShapeToParent myParent;
- MapShapeToSubshapes mySubshapes;
+ ListOfShape myObjects; ///< list of objects/tools of Boolean operation
+ MapShapeToParent myParent; ///< refer a shape to compound/compsolid containing it
+ /// indices of compounds/compsolids to keep the order of parent shapes
+ /// corresponding to the order of objects
+ MapShapeToIndex myParentIndices;
+ /// list of shape and its subshapes stored according to the index of parent shape
+ std::vector<ShapeAndSubshapes> mySubshapes;
SetOfShape myProcessedObjects;
ListOfShape& theUsed,
ListOfShape& theNotUsed) const;
+ /// Generates the list of top-level compounds, which contain the objects of Boolean operation.
+ /// The generated list will contain only shapes unused during the Boolean operation.
+ void CompoundsOfUnusedObjects(ListOfShape& theDestination) const;
+
/// Return \c true if there is no object in hierarchy
bool IsEmpty() const;
const GeomAPI_Shape::ShapeType theMinType = GeomAPI_Shape::COMPOUND,
const GeomAPI_Shape::ShapeType theMaxType = GeomAPI_Shape::SHAPE) const;
+ private:
+ GeomShapePtr collectUnusedSubs(const GeomShapePtr theTopLevelCompound,
+ const SetOfShape& theUsed) const;
+
public:
class Iterator {
friend class ObjectHierarchy;
#include <ModelAPI_ResultBody.h>
#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <ModelAPI_AttributeString.h>
#include <ModelAPI_Session.h>
#include <GeomAlgoAPI_Boolean.h>
#include <GeomAlgoAPI_MakeShapeList.h>
#include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_ShapeBuilder.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <GeomAlgoAPI_Tools.h>
#include <GeomAlgoAPI_UnifySameDomain.h>
+
#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_ShapeIterator.h>
+
+static const int THE_FUSE_VERSION_1 = 20190506;
//==================================================================================================
FeaturesPlugin_BooleanFuse::FeaturesPlugin_BooleanFuse()
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
+
+ AttributePtr aVerAttr = data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId());
+ aVerAttr->setIsArgument(false);
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
+ if (!integer(VERSION_ID())->isInitialized() &&
+ !selectionList(OBJECT_LIST_ID())->isInitialized() &&
+ !selectionList(TOOL_LIST_ID())->isInitialized()) {
+ // this is a newly created feature (not read from file),
+ // so, initialize the latest version
+ integer(VERSION_ID())->setValue(THE_FUSE_VERSION_1);
+ }
}
//==================================================================================================
return;
}
+ // version of FUSE feature
+ AttributeIntegerPtr aVersionAttr = integer(VERSION_ID());
+ int aFuseVersion = 0;
+ if (aVersionAttr && aVersionAttr->isInitialized())
+ aFuseVersion = aVersionAttr->value();
+
+//// isSimpleCreation = isSimpleCreation && aFuseVersion < THE_FUSE_VERSION_1;
+
// Collecting all solids which will be fused.
ListOfShape aSolidsToFuse;
aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
aMakeShapeList->appendAlgo(aUnifyAlgo);
}
+ if (aFuseVersion == THE_FUSE_VERSION_1) {
+ // merge hierarchies of compounds containing objects and tools
+ // and append the result of the FUSE operation
+ aShape = keepUnusedSubsOfCompound(aShape, anObjectsHierarchy, aToolsHierarchy, aMakeShapeList);
+ }
+
int aResultIndex = 0;
ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
// remove the rest results if there were produced in the previous pass
removeResults(aResultIndex);
}
+
+//==================================================================================================
+GeomShapePtr FeaturesPlugin_BooleanFuse::keepUnusedSubsOfCompound(
+ const GeomShapePtr& theFuseResult,
+ const ObjectHierarchy& theObjectsHierarchy,
+ const ObjectHierarchy& theToolsHierarchy,
+ std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList)
+{
+ ListOfShape aCompounds;
+ theObjectsHierarchy.CompoundsOfUnusedObjects(aCompounds);
+ theToolsHierarchy.CompoundsOfUnusedObjects(aCompounds);
+
+ GeomShapePtr aResultShape = theFuseResult;
+ if (!aCompounds.empty()) {
+ aResultShape = aCompounds.front();
+ aCompounds.pop_front();
+
+ std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
+ for (ListOfShape::iterator anIt = aCompounds.begin(); anIt != aCompounds.end(); ++anIt) {
+ for (GeomAPI_ShapeIterator aSub(*anIt); aSub.more(); aSub.next())
+ aBuilder->add(aResultShape, aSub.current());
+ }
+
+ aBuilder->add(aResultShape, theFuseResult);
+
+ theMakeShapeList->appendAlgo(aBuilder);
+ }
+ return aResultShape;
+}
#include "FeaturesPlugin_Boolean.h"
+class GeomAlgoAPI_MakeShapeList;
+
/// \class FeaturesPlugin_BooleanFuse
/// \ingroup Plugins
/// \brief Feature for applying of Boolean Fuse operation.
/// Use plugin manager for features creation.
FeaturesPlugin_BooleanFuse();
+
+private:
+ /// Process unused sub-shapes of compounds.
+ /// Keep the compound hierarchy, but merge top-level compounds
+ /// into a single compound and add the result of the FUSE operation.
+ GeomShapePtr keepUnusedSubsOfCompound(
+ const GeomShapePtr& theFuseResult,
+ const ObjectHierarchy& theObjectsHierarchy,
+ const ObjectHierarchy& theToolsHierarchy,
+ std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList);
};
#endif
Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True)
-
-model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
-
model.end()
-from GeomAPI import GeomAPI_Shape
-
-model.testNbResults(Fuse_1, 1)
-model.testNbSubResults(Fuse_1, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [78])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [156])
-model.testResultsVolumes(Fuse_1, [1589.048622670478835])
-
-assert(model.checkPythonDump())
+assert(Fuse_1.feature().error() != "")
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 6, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1")])
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Fuse_1, [1589.04862264177882])
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 10, 20)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OX"), 40, 2)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OY"), 40, 2)
+LinearCopy_2.result().subResult(0).subResult(0).setColor(255, 170, 0)
+LinearCopy_2.result().subResult(0).subResult(1).setColor(255, 170, 0)
+LinearCopy_2.result().subResult(1).subResult(0).setColor(0, 0, 255)
+LinearCopy_2.result().subResult(1).subResult(1).setColor(0, 0, 255)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+SketchLine_1 = Sketch_1.addLine(7, 0, -7, 0)
+SketchLine_2 = Sketch_1.addLine(-7, 0, -7, 5)
+SketchLine_3 = Sketch_1.addLine(-7, 5, 7, 5)
+SketchLine_4 = Sketch_1.addLine(7, 5, 7, 0)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_5 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_5.result(), 7, True)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchAPI_Line(SketchLine_5).startPoint(), SketchLine_1.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 14)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchLine_6 = Sketch_1.addLine(5, 12, -5, 12)
+SketchLine_7 = Sketch_1.addLine(-5, 12, -5, 15)
+SketchLine_8 = Sketch_1.addLine(-5, 15, 5, 15)
+SketchLine_9 = Sketch_1.addLine(5, 15, 5, 12)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_7.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_8.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_7.result(), 3)
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_8.result(), 10)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.endPoint(), SketchLine_5.result(), 5, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchLine_6.startPoint(), SketchLine_3.result(), 7, True)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 60, 20)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_9r-SketchLine_8r-SketchLine_7r-SketchLine_6r")], model.selection(), 55, 15)
+LinearCopy_3 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OY"), 40, 2)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_2_1")], model.selection("EDGE", "PartSet/OZ"), 90, 2)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_3_1"), model.selection("COMPOUND", "AngularCopy_1_1")])
+Compound_1.result().subResult(0).subResult(0).setColor(0, 170, 0)
+Compound_1.result().subResult(0).subResult(1).setColor(0, 170, 0)
+Compound_1.result().subResult(1).subResult(0).setColor(0, 255, 0)
+Compound_1.result().subResult(1).subResult(1).setColor(0, 255, 0)
+Fuse_1_objects_1 = [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("SOLID", "Compound_1_1_1_1"), model.selection("COMPOUND", "Compound_1_1_2")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, False, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [4])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [5])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [50])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [208])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [416])
+model.testResultsVolumes(Fuse_1, [38109.5099691938])
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1_objects_1 = [model.selection("SOLID", "Compound_1_1_1_1"), model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, True, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [3])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [6])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [70])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [140])
+model.testResultsVolumes(Fuse_1, [5016.039439659862])
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True, 20190506)
+model.end()
+
+assert(Fuse_1.feature().error() != "")
--- /dev/null
+# Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1")], False, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [4])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [7])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [32])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [94])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [188])
+model.testResultsVolumes(Fuse_1, [5516.039439629021])
+
+assert(model.checkPythonDump())