From 8235008ae7bfe2da4c57ed4d15df2511bbce5787 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 21 Feb 2013 18:37:33 +0430 Subject: [PATCH] PartDesign: Show overlapping transformations as rejected --- src/Mod/PartDesign/App/FeatureTransformed.cpp | 158 +++++++++++------- 1 file changed, 95 insertions(+), 63 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index 571e02f26..74399db01 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -98,9 +98,10 @@ App::DocumentObjectExecReturn *Transformed::execute(void) this->positionBySupport(); // get transformations from subclass by calling virtual method - std::list transformations; + std::vector transformations; try { - transformations = getTransformations(originals); + std::list t_list = getTransformations(originals); + transformations.insert(transformations.end(), t_list.begin(), t_list.end()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } @@ -122,6 +123,9 @@ App::DocumentObjectExecReturn *Transformed::execute(void) supportShape.setTransform(Base::Matrix4D()); TopoDS_Shape support = supportShape._Shape; + std::set::const_iterator> nointersect_trsfms; + std::set::const_iterator> overlapping_trsfms; + // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then // transform the compounds as a whole. But we choose to apply the transformations to each // Original separately. This way it is easier to discover what feature causes a fuse/cut @@ -129,6 +133,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) // safe to assume that in most cases there are few originals and many transformations for (std::vector::const_iterator o = originals.begin(); o != originals.end(); o++) { + // Extract the original shape and determine whether to cut or to fuse TopoDS_Shape shape; bool fuse; @@ -148,16 +153,13 @@ App::DocumentObjectExecReturn *Transformed::execute(void) return new App::DocumentObjectExecReturn("Only additive and subtractive features can be transformed"); } - // Transform the add/subshape and build a compound from the transformations, - BRep_Builder builder; - TopoDS_Compound transformedShapes; - builder.MakeCompound(transformedShapes); - std::vector v_transformedShapes; // collect all the transformed shapes for intersection testing - std::list::const_iterator t = transformations.begin(); - t++; // Skip first transformation, which is always the identity transformation + // Transform the add/subshape and collect the resulting shapes for overlap testing + std::vector::const_iterator> v_transformations; + std::vector v_transformedShapes; - for (; t != transformations.end(); t++) - { + std::vector::const_iterator t = transformations.begin(); + t++; // Skip first transformation, which is always the identity transformation + for (; t != transformations.end(); t++) { // Make an explicit copy of the shape because the "true" parameter to BRepBuilderAPI_Transform // seems to be pretty broken BRepBuilderAPI_Copy copy(shape); @@ -172,57 +174,81 @@ App::DocumentObjectExecReturn *Transformed::execute(void) // Check for intersection with support if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) { Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); - // Note: The removal happens in getSolid() after the fuse - rejected.push_back(*t); + nointersect_trsfms.insert(t); + } else { + v_transformations.push_back(t); + v_transformedShapes.push_back(mkTrf.Shape()); + // Note: Transformations that do not intersect the support are ignored in the overlap tests } - builder.Add(transformedShapes, mkTrf.Shape()); - v_transformedShapes.push_back(mkTrf.Shape()); - - /* - // Note: This method is only stable for Linear and Polar transformations. No need to - // make an explicit copy of the shape, either - TopoDS_Shape trfShape = shape.Moved(TopLoc_Location(*t)); - - // Check for intersection with support - Bnd_Box transformed_bb; - BRepBndLib::Add(trfShape, transformed_bb); - if (support_bb.Distance(transformed_bb) > Precision::Confusion()) { - Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); - // Note: The removal happens in getSolid() after the fuse - } - builder.Add(transformedShapes, trfShape); - v_transformedShapes.push_back(trfShape); - */ } - // Check for intersection of the original and the transformed shape - for (std::vector::const_iterator s = v_transformedShapes.begin(); s != v_transformedShapes.end(); s++) - { - // If there is only one transformed feature, this check is not necessary (though it might seem - // illogical to the user why we allow overlapping shapes in this case! - if (v_transformedShapes.size() == 1) - break; - - if (Part::checkIntersection(shape, *s, false, false)) - return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o)); - // Note: This limitation could be overcome by fusing the transformed features instead of - // compounding them, probably at the expense of quite a bit of performance and complexity - // in this code + if (v_transformedShapes.empty()) + break; // Skip the overlap check and go on to next original + // Check for overlapping of the original and the transformed shapes, and remove the overlapping transformations + if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId()) { + // If there is only one transformed feature, we allow an overlap (though it might seem + // illogical to the user why we allow overlapping shapes in this case!) + if (v_transformedShapes.size() > 1) + if (Part::checkIntersection(shape, v_transformedShapes.front(), false, false)) { + // For single transformations, if one overlaps, all overlap, as long as we have uniform increments + overlapping_trsfms.insert(v_transformations.begin(),v_transformations.end()); + v_transformedShapes.clear(); + } + } else { // For MultiTransform, just checking the first transformed shape is not sufficient - any two // features might overlap, even if the original and the first shape don't overlap! - if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId()) - break; - else { - // Check intersection with all other transformed shapes as well - std::vector::const_iterator s2 = s; + + std::set::iterator> rejected_iterators; + + std::vector::iterator s1 = v_transformedShapes.begin(); + std::vector::iterator s2 = s1; + s2++; + std::vector::const_iterator>::const_iterator t1 = v_transformations.begin(); + std::vector::const_iterator>::const_iterator t2 = t1; + t2++; + for (; s2 != v_transformedShapes.end();) { + // Check intersection with the original + if (Part::checkIntersection(shape, *s1, false, false)) { + rejected_iterators.insert(s1); + overlapping_trsfms.insert(*t1); + } + // Check intersection with other transformations + for (; s2 != v_transformedShapes.end(); s2++, t2++) + if (Part::checkIntersection(*s1, *s2, false, false)) { + rejected_iterators.insert(s1); + rejected_iterators.insert(s2); + overlapping_trsfms.insert(*t1); + overlapping_trsfms.insert(*t2); + } + s1++; + s2 = s1; s2++; - for (; s2 != v_transformedShapes.end(); s2++) - if (Part::checkIntersection(*s, *s2, false, false)) - return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o)); + t1++; + t2 = t1; + t2++; } + // Check intersection of last transformation with the original + if (Part::checkIntersection(shape, *s1, false, false)) { + rejected_iterators.insert(s1); + overlapping_trsfms.insert(*t1); + } + + for (std::set::iterator>::reverse_iterator it = rejected_iterators.rbegin(); + it != rejected_iterators.rend(); it++) + v_transformedShapes.erase(*it); } + if (v_transformedShapes.empty()) + break; // Skip the boolean operation and go on to next original + + // Build a compound from all the valid transformations + BRep_Builder builder; + TopoDS_Compound transformedShapes; + builder.MakeCompound(transformedShapes); + for (std::vector::const_iterator s = v_transformedShapes.begin(); s != v_transformedShapes.end(); s++) + builder.Add(transformedShapes, *s); + // Fuse/Cut the compounded transformed shapes with the support TopoDS_Shape result; @@ -231,19 +257,10 @@ App::DocumentObjectExecReturn *Transformed::execute(void) if (!mkFuse.IsDone()) return new App::DocumentObjectExecReturn("Fusion with support failed", *o); // we have to get the solids (fuse sometimes creates compounds) - // Note: Because getSolid() only returns the first solid in the explorer, all - // solids that are outside the support automatically disappear! result = this->getSolid(mkFuse.Shape()); // lets check if the result is a solid if (result.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *o); - // check if mkFuse created more than one solids - TopExp_Explorer xp; - xp.Init(mkFuse.Shape(),TopAbs_SOLID); - if (xp.More()) - xp.Next(); - if (!xp.More()) // There are no rejected transformations even - rejected.clear(); // if the bb check guessed that there would be } else { BRepAlgoAPI_Cut mkCut(support, transformedShapes); if (!mkCut.IsDone()) @@ -254,9 +271,24 @@ App::DocumentObjectExecReturn *Transformed::execute(void) support = result; // Use result of this operation for fuse/cut of next original } + if (!overlapping_trsfms.empty()) + // Concentrate on overlapping shapes since they are more serious + for (std::set::const_iterator>::const_iterator it = overlapping_trsfms.begin(); + it != overlapping_trsfms.end(); it++) + rejected.push_back(**it); + else + for (std::set::const_iterator>::const_iterator it = nointersect_trsfms.begin(); + it != nointersect_trsfms.end(); it++) + rejected.push_back(**it); + this->Shape.setValue(support); - - return App::DocumentObject::StdReturn; + if (!overlapping_trsfms.empty()) + return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences"); + // Note: This limitation could be overcome by fusing the transformed features instead of + // compounding them, probably at the expense of quite a bit of performance and complexity + // in this code + else + return App::DocumentObject::StdReturn; } }