FeaturesPlugin_RevolutionBoolean.h
FeaturesPlugin_RevolutionCut.h
FeaturesPlugin_RevolutionFuse.h
+ FeaturesPlugin_Union.h
FeaturesPlugin_ValidatorTransform.h
FeaturesPlugin_Validators.h
FeaturesPlugin_RemoveSubShapes.h
FeaturesPlugin_RevolutionBoolean.cpp
FeaturesPlugin_RevolutionCut.cpp
FeaturesPlugin_RevolutionFuse.cpp
+ FeaturesPlugin_Union.cpp
FeaturesPlugin_ValidatorTransform.cpp
FeaturesPlugin_Validators.cpp
FeaturesPlugin_RemoveSubShapes.cpp
intersection_widget.xml
pipe_widget.xml
remove_subshapes_widget.xml
+ union_widget.xml
)
SET(TEXT_RESOURCES
std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
ListOfShape aListWithObject;
aListWithObject.push_back(anObject);
- GeomAlgoAPI_MakeShape aBoolAlgo; (aListWithObject, aTools, (GeomAlgoAPI_Boolean::OperationType)aType);
+ GeomAlgoAPI_MakeShape aBoolAlgo;
switch(aType) {
case BOOL_CUT: aBoolAlgo = GeomAlgoAPI_Boolean(aListWithObject, aTools, GeomAlgoAPI_Boolean::BOOL_CUT); break;
} else if((anObjects.size() + aTools.size()) > 1){
std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
aTools,
- (GeomAlgoAPI_Boolean::OperationType)aType));
+ GeomAlgoAPI_Boolean::BOOL_FUSE));
// Checking that the algorithm worked properly.
if(!aFuseAlgo->isDone()) {
ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
// Store modified shape.
- if(aBaseShape->isEqual(theResultShape)) {
+ if(!aBaseShape.get() || aBaseShape->isEqual(theResultShape)) {
aResultBody->store(theResultShape);
setResult(aResultBody, theIndex);
return;
#include <FeaturesPlugin_RevolutionCut.h>
#include <FeaturesPlugin_RevolutionFuse.h>
#include <FeaturesPlugin_Rotation.h>
+#include <FeaturesPlugin_Union.h>
#include <FeaturesPlugin_ValidatorTransform.h>
#include <FeaturesPlugin_Validators.h>
new FeaturesPlugin_ValidatorRemoveSubShapesResult);
aFactory->registerValidator("FeaturesPlugin_ValidatorPipePath",
new FeaturesPlugin_ValidatorPipePath);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorUnionSelection",
+ new FeaturesPlugin_ValidatorUnionSelection);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorUnionArguments",
+ new FeaturesPlugin_ValidatorUnionArguments);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new FeaturesPlugin_RevolutionFuse);
} else if (theFeatureID == FeaturesPlugin_RemoveSubShapes::ID()) {
return FeaturePtr(new FeaturesPlugin_RemoveSubShapes);
+ } else if (theFeatureID == FeaturesPlugin_Union::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Union);
}
// feature of such kind is not found
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: FeaturesPlugin_Union.cpp
+// Created: 17 June 2016
+// Author: Dmitry Bobylev
+
+#include "FeaturesPlugin_Union.h"
+
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_PaveFiller.h>
+
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_ResultCompSolid.h>
+#include <ModelAPI_Tools.h>
+
+//=================================================================================================
+FeaturesPlugin_Union::FeaturesPlugin_Union()
+{
+}
+
+//=================================================================================================
+void FeaturesPlugin_Union::initAttributes()
+{
+ data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+//=================================================================================================
+void FeaturesPlugin_Union::execute()
+{
+ ListOfShape anObjects;
+ std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
+
+ // Getting objects.
+ AttributeSelectionListPtr anObjectsSelList = selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
+ for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
+ AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+ std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
+ if(!anObject.get()) {
+ return;
+ }
+ ResultPtr aContext = anObjectAttr->context();
+ ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
+ if(aResCompSolidPtr.get()) {
+ std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
+ std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
+ for(; anIt != aCompSolidsObjects.end(); anIt++) {
+ if(anIt->first->isEqual(aContextShape)) {
+ aCompSolidsObjects[anIt->first].push_back(anObject);
+ break;
+ }
+ }
+ if(anIt == aCompSolidsObjects.end()) {
+ aCompSolidsObjects[aContextShape].push_back(anObject);
+ }
+ } else {
+ anObjects.push_back(anObject);
+ }
+ }
+
+ // Collecting solids from compsolids which will not be modified in boolean operation and will be added to result.
+ ListOfShape aShapesToAdd;
+ for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
+ anIt != aCompSolidsObjects.end(); anIt++) {
+ std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
+ ListOfShape& aUsedInOperationSolids = anIt->second;
+ anObjects.insert(anObjects.end(), aUsedInOperationSolids.begin(), aUsedInOperationSolids.end());
+
+ // Collect solids from compsolid which will not be modified in boolean operation.
+ for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
+ std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
+ ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
+ for(; anIt != aUsedInOperationSolids.end(); anIt++) {
+ if(aSolidInCompSolid->isEqual(*anIt)) {
+ break;
+ }
+ }
+ if(anIt == aUsedInOperationSolids.end()) {
+ aShapesToAdd.push_back(aSolidInCompSolid);
+ }
+ }
+ }
+
+ if(anObjects.size() < 2) {
+ setError("Error: Not enough objects for operation. Should be at least 2.");
+ return;
+ }
+
+ // Fuse objects.
+ ListOfShape aTools;
+ aTools.splice(aTools.begin(), anObjects, anObjects.begin());
+ std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
+ aTools,
+ GeomAlgoAPI_Boolean::BOOL_FUSE));
+
+ // Checking that the algorithm worked properly.
+ GeomAlgoAPI_MakeShapeList aMakeShapeList;
+ GeomAPI_DataMapOfShapeShape aMapOfShapes;
+ if(!aFuseAlgo->isDone()) {
+ setError("Error: Boolean algorithm failed.");
+ return;
+ }
+ if(aFuseAlgo->shape()->isNull()) {
+ setError("Error: Resulting shape is Null.");
+ return;
+ }
+ if(!aFuseAlgo->isValid()) {
+ setError("Error: Resulting shape is not valid.");
+ return;
+ }
+
+ GeomShapePtr aShape = aFuseAlgo->shape();
+ aMakeShapeList.appendAlgo(aFuseAlgo);
+ aMapOfShapes.merge(aFuseAlgo->mapOfSubShapes());
+
+ // Store original shapes for naming.
+ anObjects.splice(anObjects.begin(), aTools);
+ anObjects.insert(anObjects.end(), aShapesToAdd.begin(), aShapesToAdd.end());
+
+ // Combine result with not used solids from compsolid.
+ if(aShapesToAdd.size() > 0) {
+ aShapesToAdd.push_back(aShape);
+ std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
+ if(!aFillerAlgo->isDone()) {
+ setError("Error: PaveFiller algorithm failed.");
+ return;
+ }
+ if(aFillerAlgo->shape()->isNull()) {
+ setError("Error: Resulting shape is Null.");
+ return;
+ }
+ if(!aFillerAlgo->isValid()) {
+ setError("Error: Resulting shape is not valid.");
+ return;
+ }
+
+ aShape = aFillerAlgo->shape();
+ aMakeShapeList.appendAlgo(aFillerAlgo);
+ aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
+ }
+
+ // Store result and naming.
+ const int aModifyTag = 1;
+ const int aDeletedTag = 2;
+ const int aSubsolidsTag = 3; /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
+ const std::string aModName = "Modified";
+
+ std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data());
+ aResultBody->storeModified(anObjects.front(), aShape, aSubsolidsTag);
+
+ for(ListOfShape::const_iterator anIter = anObjects.begin(); anIter != anObjects.end(); ++anIter) {
+ aResultBody->loadAndOrientModifiedShapes(&aMakeShapeList, *anIter, GeomAPI_Shape::FACE,
+ aModifyTag, aModName, aMapOfShapes);
+ aResultBody->loadDeletedShapes(&aMakeShapeList, *anIter, GeomAPI_Shape::FACE, aDeletedTag);
+ }
+
+ setResult(aResultBody);
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: FeaturesPlugin_Union.h
+// Created: 17 June 2016
+// Author: Dmitry Bobylev
+
+#ifndef FeaturesPlugin_Union_H_
+#define FeaturesPlugin_Union_H_
+
+#include "FeaturesPlugin.h"
+#include <ModelAPI_Feature.h>
+
+#include <GeomAPI_Shape.h>
+
+class GeomAlgoAPI_MakeShape;
+
+/// \class FeaturesPlugin_Union
+/// \ingroup Plugins
+/// \brief Feature for applying of Union operations on Shapes. Union removes shared shapes from
+/// several shapes and combines them into one.
+class FeaturesPlugin_Union : public ModelAPI_Feature
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Union");
+ return MY_ID;
+ }
+
+ /// Attribute name of base objects.
+ inline static const std::string& BASE_OBJECTS_ID()
+ {
+ static const std::string MY_BASE_OBJECTS_ID("base_objects");
+ return MY_BASE_OBJECTS_ID;
+ }
+
+ /// \return the kind of a feature.
+ FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = FeaturesPlugin_Union::ID();
+ return MY_KIND;
+ }
+
+ /// Creates a new part document if needed
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Use plugin manager for features creation
+ FeaturesPlugin_Union();
+};
+
+#endif
#include "FeaturesPlugin_Validators.h"
+#include "FeaturesPlugin_Union.h"
+
#include <ModelAPI_Attribute.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_ShapeIterator.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
#include <GeomAlgoAPI_ShapeBuilder.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <GeomAlgoAPI_WireBuilder.h>
{
return false;
}
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const
+{
+ AttributeSelectionListPtr aBaseObjectsAttrList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+ if(!aBaseObjectsAttrList.get()) {
+ theError = "Error: This validator can only work with selection list in \"" + FeaturesPlugin_Union::ID() + "\" feature.";
+ return false;
+ }
+
+ for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
+ bool isSameFound = false;
+ AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
+ ResultCompSolidPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(anAttrSelectionInList->context());
+ if(!aResult.get()) {
+ continue;
+ }
+ if(aResult->numberOfSubs() > 0) {
+ theError = "Error: Whole compsolids not allowed for selection.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorUnionArguments::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const
+{
+ // Check feature kind.
+ if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
+ theError = "Error: This validator supports only \"" + FeaturesPlugin_Union::ID() + "\" feature.";
+ return false;
+ }
+
+ // Get base objects attribute list.
+ AttributeSelectionListPtr aBaseObejctsAttrList = theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
+ if(!aBaseObejctsAttrList.get()) {
+ theError = "Error: Could not get \"" + FeaturesPlugin_Union::BASE_OBJECTS_ID() + "\" attribute.";
+ return false;
+ }
+
+ // Get all shapes.
+ ListOfShape aBaseShapesList;
+ for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
+ AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
+ GeomShapePtr aShape = anAttrSelectionInList->value();
+ aBaseShapesList.push_back(aShape);
+ }
+
+ // Make componud and find connected.
+ GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
+ ListOfShape aCombined, aFree;
+ GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCombined, aFree);
+
+ if(aFree.size() > 0 || aCombined.size() > 1) {
+ theError = "Error: Not all shapes have shared topology.";
+ return false;
+ }
+
+ return true;
+}
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorUnionArguments::isNotObligatory(std::string theFeature,
+ std::string theAttribute)
+{
+ return false;
+}
virtual bool isNotObligatory(std::string theFeature, std::string theAttribute);
};
+/// \class FeaturesPlugin_ValidatorUnionSelection
+/// \ingroup Validators
+/// \brief Validates selection for "Union" feature.
+class FeaturesPlugin_ValidatorUnionSelection: public ModelAPI_AttributeValidator
+{
+public:
+ /// \return True if the attribute is valid. It checks whether the selection
+ /// is acceptable for operation.
+ /// \param[in] theAttribute an attribute to check.
+ /// \param[in] theArguments a filter parameters.
+ /// \param[out] theError error message.
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const;
+};
+
+/// \class FeaturesPlugin_ValidatorUnionArguments
+/// \ingroup Validators
+/// \brief Validator for the "Union" feature.
+class FeaturesPlugin_ValidatorUnionArguments: public ModelAPI_FeatureValidator
+{
+ public:
+ //! \return true if result is valid shape.
+ //! \param theFeature the checked feature
+ //! \param theArguments arguments of the feature (not used)
+ //! \param theError error message
+ virtual bool isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const;
+
+ /// \return true if the attribute in feature is not obligatory for the feature execution
+ virtual bool isNotObligatory(std::string theFeature, std::string theAttribute);
+};
+
#endif
--- /dev/null
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from ModelAPI import *
+from GeomDataAPI import *
+from GeomAlgoAPI import *
+from GeomAPI import *
+import math
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+
+# Create a part for extrusion
+aSession.startOperation()
+aPartFeature = aDocument.addFeature("Part")
+aSession.finishOperation()
+assert (len(aPartFeature.results()) == 1)
+
+aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
+aPart = aPartResult.partDoc()
+
+#=========================================================================
+# Create a sketch to extrude
+#=========================================================================
+aSession.startOperation()
+aSketchFeature = featureToCompositeFeature(aPart.addFeature("Sketch"))
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+
+# Create circles
+aSketchCircle = aSketchFeature.addFeature("SketchCircle")
+anCircleCentr = geomDataAPI_Point2D(aSketchCircle.attribute("CircleCenter"))
+aCircleRadius = aSketchCircle.real("CircleRadius")
+anCircleCentr.setValue(-25, 0)
+aCircleRadius.setValue(50)
+aSketchCircle = aSketchFeature.addFeature("SketchCircle")
+anCircleCentr = geomDataAPI_Point2D(aSketchCircle.attribute("CircleCenter"))
+aCircleRadius = aSketchCircle.real("CircleRadius")
+anCircleCentr.setValue(25, 0)
+aCircleRadius.setValue(50)
+aSession.finishOperation()
+aSketchResult = aSketchFeature.firstResult()
+
+#=========================================================================
+# Make extrusion on sketch
+#=========================================================================
+# Create extrusion
+aSession.startOperation()
+anExtrusionFeature = aPart.addFeature("Extrusion")
+anExtrusionFeature.selectionList("base").append(aSketchResult, None)
+anExtrusionFeature.string("CreationMethod").setValue("BySizes")
+anExtrusionFeature.real("to_size").setValue(50)
+anExtrusionFeature.real("from_size").setValue(0)
+anExtrusionFeature.real("to_offset").setValue(0) #TODO: remove
+anExtrusionFeature.real("from_offset").setValue(0) #TODO: remove
+anExtrusionFeature.execute()
+aSession.finishOperation()
+anExtrusionResult = modelAPI_ResultCompSolid(modelAPI_ResultBody(anExtrusionFeature.firstResult()))
+
+#=========================================================================
+# Make union on extrusion
+#=========================================================================
+aSession.startOperation()
+aUnionFeature = aPart.addFeature("Union")
+aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(0), None);
+aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(1), None);
+aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(2), None);
+aSession.finishOperation()
+assert (len(aUnionFeature.results()) > 0)
+anUnionResult = modelAPI_ResultCompSolid(modelAPI_ResultBody(aUnionFeature.firstResult()))
+assert (anUnionResult.numberOfSubs() == 0)
auto_preview="false">
<source path="boolean_widget.xml"/>
</feature>
+ <feature id="Intersection" title="Intersection" tooltip="Intersect objects with tools" icon="icons/Features/intersection.png">
+ <source path="intersection_widget.xml"/>
+ </feature>
<feature id="Partition" title="Partition" tooltip="Perform partition operations with solids" icon="icons/Features/partition.png"
auto_preview="false">
<source path="partition_widget.xml"/>
</feature>
+ <feature id="Union" title="Union" tooltip="Perform union operations with shapes" icon="icons/Features/union.png">
+ <source path="union_widget.xml"/>
+ </feature>
<feature id="Remove_SubShapes" title="Remove Sub-Shapes" tooltip="Allows to remove sub-shapes from wires, shells, compsolids and compounds" icon="icons/Features/remove_subshapes.png">
<source path="remove_subshapes_widget.xml"/>
</feature>
- <feature id="Intersection" title="Intersection" tooltip="Intersect objects with tools" icon="icons/Features/intersection.png">
- <source path="intersection_widget.xml"/>
- </feature>
</group>
<group id="Collections">
<feature id="Group"
--- /dev/null
+<!-- Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+<source>
+ <multi_selector id="base_objects"
+ label="Base objects:"
+ tooltip="Select solids for union."
+ type_choice="solids"
+ concealment="true">
+ <validator id="FeaturesPlugin_ValidatorUnionSelection"/>
+ </multi_selector>
+ <validator id="GeomValidators_MinObjectsSelected" parameters="base_objects,2"/>
+ <validator id="FeaturesPlugin_ValidatorUnionArguments"/>
+</source>