diff --git a/src/Mod/Part/App/FeatureExtrusion.cpp b/src/Mod/Part/App/FeatureExtrusion.cpp index abbfea7e3f..ae1645a945 100644 --- a/src/Mod/Part/App/FeatureExtrusion.cpp +++ b/src/Mod/Part/App/FeatureExtrusion.cpp @@ -416,7 +416,7 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoDS_Shape& for (auto itInner = resultPrisms.begin(); itInner != resultPrisms.end(); ++itInner) { if (itOuter == itInner) continue; - // get center of mass of first shape + // get MomentOfInertia of first shape BRepGProp::VolumeProperties(*itInner, tempProperties); momentOfInertiaInitial = tempProperties.MomentOfInertia(gp_Ax1(gp_Pnt(), params.dir)); BRepAlgoAPI_Cut mkCut(*itInner, *itOuter); @@ -442,6 +442,13 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoDS_Shape& The first input one will now be taken as outer one.\n"); } + // we can have the case of nested inner wires, therefore check for inner wires in inner wires + // these will become outer ones, inner of inner of inner reamin inner and so on + if (numInnerWires > 1) { + std::vector toCheck = isInnerWire; // all inner wires need to be checked + checkInnerWires(isInnerWire, params, toCheck, true, resultPrisms); + } + // at first create offset wires for the reversed part of extrusion // it is important that these wires are the first loft section if (bRev) { @@ -539,51 +546,41 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoDS_Shape& if (params.solid) { // we only need to cut if we have inner wires if (numInnerWires > 0) { - TopoDS_Shape result; - BRep_Builder builder; - TopoDS_Compound compOuter; - TopoDS_Shape outerCutShape; - // when there is more than one outer wire make a compound of the outer shells - rows = 0; - if ((numWires - numInnerWires) > 1) { - builder.MakeCompound(compOuter); - for (auto it = shells.begin(); it != shells.end(); ++it) { - if (!isInnerWire[rows]) - builder.Add(compOuter, *it); - ++rows; + // we take every outer wire prism and cut subsequently all inner wires prisms from it + // every resulting shape is the final drafted extrusion shape + std::vector::iterator isInnerWireIterator = isInnerWire.begin(); + std::vector::iterator isInnerWireIteratorLoop; + for (auto itOuter = shells.begin(); itOuter != shells.end(); ++itOuter) { + if (*isInnerWireIterator == true) { + ++isInnerWireIterator; + continue; } - outerCutShape = compOuter; - } - else { // take the shell directly without a compound - for (auto it = shells.begin(); it != shells.end(); ++it) { - if (!isInnerWire[rows]) { - outerCutShape = *it; - break; + isInnerWireIteratorLoop = isInnerWire.begin(); + for (auto itInner = shells.begin(); itInner != shells.end(); ++itInner) { + if (itOuter == itInner || *isInnerWireIteratorLoop == false) { + ++isInnerWireIteratorLoop; + continue; } - ++rows; + // get MomentOfInertia of first shape + BRepGProp::VolumeProperties(*itInner, tempProperties); + momentOfInertiaInitial = tempProperties.MomentOfInertia(gp_Ax1(gp_Pnt(), params.dir)); + BRepAlgoAPI_Cut mkCut(*itOuter, *itInner); + if (!mkCut.IsDone()) + Standard_Failure::Raise("Extrusion: Final cut out failed"); + BRepGProp::VolumeProperties(mkCut.Shape(), tempProperties); + momentOfInertiaFinal = tempProperties.MomentOfInertia(gp_Ax1(gp_Pnt(), params.dir)); + // if the whole shape was cut away the resulting shape is not Null but its MomentOfInertia is 0.0 + // therefore we have a valid cut if the MomentOfInertia is not zero and changed + if ((momentOfInertiaInitial != momentOfInertiaFinal) + && (momentOfInertiaFinal > Precision::Confusion())) { + // immediately update the outer shape since more inner wire prism might cut it + *itOuter = mkCut.Shape(); + } + ++isInnerWireIteratorLoop; } + drafts.push_back(*itOuter); + ++isInnerWireIterator; } - // now the compound of the inner, no matter if we only have one inner - TopoDS_Compound compInner; - builder.MakeCompound(compInner); - rows = 0; - for (auto it = shells.begin(); it != shells.end(); ++it) { - if (isInnerWire[rows]) - builder.Add(compInner, *it); - ++rows; - } - // cut the inner from the outer - BRepAlgoAPI_Cut mkCutFinal(outerCutShape, compInner); - if (!mkCutFinal.IsDone()) - Standard_Failure::Raise("Extrusion: Cut of inner structures failed"); - result = mkCutFinal.Shape(); - // de-assemble the result to return every solid independently - for (TopoDS_Iterator anExp(result); anExp.More(); anExp.Next()) { - if (anExp.Value().ShapeType() == TopAbs_SOLID) - drafts.push_back(anExp.Value()); - } - if (drafts.empty()) // should never happen, we already checked the success of the cut of solids - Standard_Failure::Raise("Extrusion: The extrusion result is no solid shape"); } else // we already have the results for (auto it = shells.begin(); it != shells.end(); ++it) @@ -609,6 +606,75 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoDS_Shape& } } +void Extrusion::checkInnerWires (std::vector& isInnerWire, const ExtrusionParameters& params, + std::vector& checklist, bool forInner, std::vector prisms) +{ + GProp_GProps tempProperties; + Standard_Real momentOfInertiaInitial; + Standard_Real momentOfInertiaFinal; + int numCheckWires = 0; + std::vector::iterator isInnerWireIterator = isInnerWire.begin(); + std::vector::iterator toCheckIterator = checklist.begin(); + // create an array with false used later to store what can be cancelled from the checklist + std::vector toDisable; + for (auto numChecks : checklist) + toDisable.push_back(false); + int outer = -1; + // we cut every prism to be checked from the other to be checked ones + // if nothing happens, a prism can be cancelled from the checklist + for (auto itOuter = prisms.begin(); itOuter != prisms.end(); ++itOuter) { + ++outer; + if (*toCheckIterator == false) { + ++isInnerWireIterator; + ++toCheckIterator; + continue; + } + auto toCheckIteratorInner = checklist.begin(); + bool saveIsInnerWireIterator = *isInnerWireIterator; + for (auto itInner = prisms.begin(); itInner != prisms.end(); ++itInner) { + if (itOuter == itInner || *toCheckIteratorInner == false) { + ++toCheckIteratorInner; + continue; + } + // get MomentOfInertia of first shape + BRepGProp::VolumeProperties(*itInner, tempProperties); + momentOfInertiaInitial = tempProperties.MomentOfInertia(gp_Ax1(gp_Pnt(), params.dir)); + BRepAlgoAPI_Cut mkCut(*itInner, *itOuter); + if (!mkCut.IsDone()) + Standard_Failure::Raise("Extrusion: Cut out failed"); + BRepGProp::VolumeProperties(mkCut.Shape(), tempProperties); + momentOfInertiaFinal = tempProperties.MomentOfInertia(gp_Ax1(gp_Pnt(), params.dir)); + // if the whole shape was cut away the resulting shape is not Null but its MomentOfInertia is 0.0 + // therefore we have an inner wire if the MomentOfInertia is not zero and changed + if ((momentOfInertiaInitial != momentOfInertiaFinal) + && (momentOfInertiaFinal > Precision::Confusion())) { + *isInnerWireIterator = !forInner; + ++numCheckWires; + *toCheckIterator = true; + break; + } + ++toCheckIteratorInner; + } + if (saveIsInnerWireIterator == *isInnerWireIterator) + // nothing was changed and we can remove it from the list to be checked + // but we cannot do this before the foor loop was fully run + toDisable[outer] = true; + ++isInnerWireIterator; + ++toCheckIterator; + } + + // cancel prisms from the checklist whose wire state did not change + size_t i = 0; + for (auto disable : toDisable) { + if (disable) + checklist[i] = false; + ++i; + } + // recursively call the function until all wires are checked + if (numCheckWires > 1) + checkInnerWires(isInnerWire, params, checklist, !forInner, prisms); +}; + void Extrusion::createTaperedPrismOffset(TopoDS_Wire sourceWire, const gp_Vec& translation, double offset, diff --git a/src/Mod/Part/App/FeatureExtrusion.h b/src/Mod/Part/App/FeatureExtrusion.h index bf527dfb51..dbe069babe 100644 --- a/src/Mod/Part/App/FeatureExtrusion.h +++ b/src/Mod/Part/App/FeatureExtrusion.h @@ -123,6 +123,9 @@ public: //mode enumerations protected: static void makeDraft(const ExtrusionParameters& params, const TopoDS_Shape&, std::list&); + static void checkInnerWires(std::vector& isInnerWire, const ExtrusionParameters& params, + std::vector& checklist, bool forInner, std::vector prisms); + static void createTaperedPrismOffset(TopoDS_Wire sourceWire, const gp_Vec& translation, double offset,