PartDesign: Show overlapping transformations as rejected

This commit is contained in:
jrheinlaender 2013-02-21 18:37:33 +04:30 committed by logari81
parent 62dc05ffd9
commit 8235008ae7

View File

@ -98,9 +98,10 @@ App::DocumentObjectExecReturn *Transformed::execute(void)
this->positionBySupport();
// get transformations from subclass by calling virtual method
std::list<gp_Trsf> transformations;
std::vector<gp_Trsf> transformations;
try {
transformations = getTransformations(originals);
std::list<gp_Trsf> 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<std::vector<gp_Trsf>::const_iterator> nointersect_trsfms;
std::set<std::vector<gp_Trsf>::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<App::DocumentObject*>::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<TopoDS_Shape> v_transformedShapes; // collect all the transformed shapes for intersection testing
std::list<gp_Trsf>::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<std::vector<gp_Trsf>::const_iterator> v_transformations;
std::vector<TopoDS_Shape> v_transformedShapes;
for (; t != transformations.end(); t++)
{
std::vector<gp_Trsf>::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<TopoDS_Shape>::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<TopoDS_Shape>::const_iterator s2 = s;
std::set<std::vector<TopoDS_Shape>::iterator> rejected_iterators;
std::vector<TopoDS_Shape>::iterator s1 = v_transformedShapes.begin();
std::vector<TopoDS_Shape>::iterator s2 = s1;
s2++;
std::vector<std::vector<gp_Trsf>::const_iterator>::const_iterator t1 = v_transformations.begin();
std::vector<std::vector<gp_Trsf>::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<std::vector<TopoDS_Shape>::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<TopoDS_Shape>::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<std::vector<gp_Trsf>::const_iterator>::const_iterator it = overlapping_trsfms.begin();
it != overlapping_trsfms.end(); it++)
rejected.push_back(**it);
else
for (std::set<std::vector<gp_Trsf>::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;
}
}