-// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+// Copyright (C) 2014-2022 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
#include "FeaturesPlugin_Partition.h"
#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeReference.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <list>
#include <sstream>
-static const int THE_PARTITION_VERSION_1 = 20190506;
+
+static const double DEFAULT_FUZZY = 1.e-5;
//=================================================================================================
void FeaturesPlugin_Partition::initAttributes()
{
data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
- initVersion(THE_PARTITION_VERSION_1, selectionList(BASE_OBJECTS_ID()));
+
+ data()->addAttribute(USE_FUZZY_ID(), ModelAPI_AttributeBoolean::typeId());
+ data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId());
+ boolean(USE_FUZZY_ID())->setValue(false); // Do NOT use the fuzzy parameter by default.
+ real(FUZZY_PARAM_ID())->setValue(DEFAULT_FUZZY);
+
+ initVersion(BOP_VERSION_9_4(), selectionList(BASE_OBJECTS_ID()));
}
//=================================================================================================
void FeaturesPlugin_Partition::execute()
{
- ObjectHierarchy anObjects;
+ GeomAPI_ShapeHierarchy anObjects;
ListOfShape aPlanes;
// Getting objects.
processAttribute(BASE_OBJECTS_ID(), anObjects, aPlanes);
- if(anObjects.IsEmpty()) {
+ if(anObjects.empty()) {
static const std::string aFeatureError = "Error: No objects for partition.";
setError(aFeatureError);
return;
}
- ListOfShape aBaseObjects = anObjects.Objects();
+ // Getting fuzzy parameter.
+ // Used as additional tolerance to eliminate tiny results.
+ // Using -1 as fuzzy value in the GeomAlgoAPI means to ignore it during the boolean operation!
+ bool aUseFuzzy = boolean(USE_FUZZY_ID())->value();
+ double aFuzzy = (aUseFuzzy ? real(FUZZY_PARAM_ID())->value() : -1);
+
+ ListOfShape aBaseObjects = anObjects.objects();
aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
// resize planes to the bounding box of operated shapes
std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
- resizePlanes(anObjects.Objects(), aPlanes, aMakeShapeList);
+ resizePlanes(anObjects.objects(), aPlanes, aMakeShapeList);
// cut unused solids of composolids from the objects of partition
ListOfShape aTargetObjects, anUnusedSubs;
std::string aError;
- if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aMakeShapeList, aError)) {
+ if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aFuzzy, aMakeShapeList, aError)) {
setError(aError);
return;
}
// perform partition first time to split target solids by planes
std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
- new GeomAlgoAPI_Partition(aTargetObjects, aPlanes));
+ new GeomAlgoAPI_Partition(aTargetObjects, aPlanes, aFuzzy));
// Checking that the algorithm worked properly.
if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
int aResultIndex = 0;
- int aPartitionVersion = version();
- if (aPartitionVersion < THE_PARTITION_VERSION_1) {
- // default behaviours of Partition
+ if (data()->version().empty()) {
+ // default behaviors of Partition
if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
}
GeomShapePtr aResultCompound =
- keepUnusedSubsOfCompound(aFirstShape, anObjects, ObjectHierarchy(), aMakeShapeList);
+ keepUnusedSubsOfCompound(aFirstShape, anObjects, GeomAPI_ShapeHierarchy(), aMakeShapeList);
if (anIt.more()) {
+ if (aResultCompound->shapeType() != GeomAPI_Shape::COMPOUND) {
+ // put the shape into compound
+ ListOfShape aShapes;
+ aShapes.push_back(aResultCompound);
+ aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+ }
std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
for (; anIt.more(); anIt.next())
aBuilder->add(aResultCompound, anIt.current());
//=================================================================================================
-
static bool cutSubs(ListOfShape& theSubsToCut,
const ListOfShape& theTools,
+ const double theFuzzy,
std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
std::string& theError)
{
// cut from current list of solids
std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo(
- new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT));
+ new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT, theFuzzy));
if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError))
return false;
theMakeShapeList->appendAlgo(aCutAlgo);
return true;
}
+//=================================================================================================
bool FeaturesPlugin_Partition::cutSubs(
- FeaturesPlugin_Partition::ObjectHierarchy& theHierarchy,
+ GeomAPI_ShapeHierarchy& theHierarchy,
ListOfShape& theUsed,
ListOfShape& theNotUsed,
+ const double theFuzzy,
std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
std::string& theError)
{
theUsed.clear();
theNotUsed.clear();
- ObjectHierarchy::Iterator anIt = theHierarchy.Begin();
+ GeomAPI_ShapeHierarchy::iterator anIt = theHierarchy.begin();
// compose a set of tools for the CUT operation:
// find the list of unused subs of the first argument or use itself
ListOfShape aToolsForUsed, aToolsForUnused;
- GeomShapePtr aFirstArgument = theHierarchy.Parent(*anIt);
+ GeomShapePtr aFirstArgument = theHierarchy.parent(*anIt, false);
if (aFirstArgument && aFirstArgument->shapeType() == GeomAPI_Shape::COMPSOLID) {
- theHierarchy.SplitCompound(aFirstArgument, theUsed, aToolsForUsed);
+ theHierarchy.splitCompound(aFirstArgument, theUsed, aToolsForUsed);
theNotUsed = aToolsForUsed;
}
else {
// cut subs
bool isOk = true;
- for (++anIt; anIt != theHierarchy.End() && isOk; ++anIt) {
+ for (++anIt; anIt != theHierarchy.end() && isOk; ++anIt) {
ListOfShape aUsed, aNotUsed;
- GeomShapePtr aParent = theHierarchy.Parent(*anIt);
- if (aParent && aParent->shapeType() <= GeomAPI_Shape::COMPSOLID) {
- theHierarchy.SplitCompound(aParent, aUsed, aNotUsed);
- if (aParent->shapeType() == GeomAPI_Shape::COMPOUND)
- aNotUsed.clear(); // do not cut unused subshapes of compound
+ GeomShapePtr aParent = theHierarchy.parent(*anIt, false);
+ if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) {
+ aParent = theHierarchy.parent(*anIt); // get parent once again to mark its subs as processed
+ theHierarchy.splitCompound(aParent, aUsed, aNotUsed);
}
else
aUsed.push_back(*anIt);
- isOk = ::cutSubs(aUsed, aToolsForUsed, theMakeShapeList, theError)
- && ::cutSubs(aNotUsed, aToolsForUnused, theMakeShapeList, theError);
+ isOk = ::cutSubs(aUsed, aToolsForUsed, theFuzzy, theMakeShapeList, theError)
+ && ::cutSubs(aNotUsed, aToolsForUnused, theFuzzy, theMakeShapeList, theError);
if (isOk) {
theUsed.insert(theUsed.end(), aUsed.begin(), aUsed.end());
theNotUsed.insert(theNotUsed.end(), aNotUsed.begin(), aNotUsed.end());