Help me please! How to get the solid from its one surface.

If a surface is set, how to know which solid in this context the face belongs to.

Roman Lygin's picture

Hi TengDX,

This question is often posted, maybe you already found an answer. Just in case you did not, here it is.

Assume aShape is a shape that contains your solid - btw, this can only be compound of (compound of ...) solid(s). Or of compsolids, what is unlikely. aFace is a face you know (note a "face" term, not a surface which is a geometric entity underlying a face).

TopoDS_Solid aResSolid;
TopTools_IndexedDataMapOfShapeListOfShape anAncestorsMap;
TopExp::MapShapesAndAncestors (aShape, TopAbs_FACE, TopAbs_SOLID, anAncestorMap);
if (anAncestorsMap.Contains (aFace)) {
const TopTools_ListOfShape& aSolidList = anAncestorsMap.FindFromKey (aFace);
aResSolid = aSolidList.First();
//or search another solid if there are severals
}

Hope this helps.
Roman

Roman Lygin's picture

Correction to the above:
aResSolid = TopoDS::Solid (aSolidList.First());

TengDX's picture

Hi Roman. Thank you for your answer. There is some difference in my application. When to operate an solid in the AIS_InteractiveContext, I want to get the solid from the selected face. So I implement this function with the following code:

Handle(AIS_Shape) CSketchDesignDoc::GetShapeFromFace( Handle(AIS_Shape) face)
{
AIS_ListOfInteractive aList;
myAISContext->DisplayedObjects(aList);

AIS_ListIteratorOfListOfInteractive aListIterator; for(aListIterator.Initialize(aList);aListIterator.More();aListIterator.Next())
{
Handle_AIS_InteractiveObject curItem = aListIterator.Value();
Handle_AIS_Shape pShape = Handle_AIS_Shape::DownCast (curItem);

TopoDS_Shape shape = pShape->Shape();
TopAbs_ShapeEnum typeEnum = shape.ShapeType();
if ( typeEnum != TopAbs_SOLID)
continue;
else
{
TopTools_IndexedDataMapOfShapeListOfShape anAncestorMap;
TopExp::MapShapesAndAncestors (shape, TopAbs_FACE,
TopAbs_SOLID, anAncestorMap);

if ( anAncestorMap.Contains( TopoDS::Face(face->Shape())))
{
AfxMessageBox("Face is found");
return pShape;
}
}
}
}
return NULL;
}

Would you help me check these code, and I debug for many times and failed. Thank you for your kindness again.

Roman Lygin's picture

Hi TengDX,

If I understand correctly, you have several solids in InteractiveContext (at neutral point) and you want to find the one the selected face belongs to, right ?
I would expect your code should work but I'd just optimize it as follows. I'd write:
...
else
{
TopTools_IndexedMapOfShape aChildrenMap;
TopExp::MapShapes( shape, TopAbs_FACE, aChildrenMap); //stores all faces of the shape
if (aChildrenMap.Contains (face->Shape())
{
...//solid is found
}
}

I even would write my own function and use it instead of TopExp::Map() as follows:

Standard_Boolan IsChild (const TopoDS_Shape& theParent, const TopoDS_Shape& theChild)
{
for (TopExp_Explorer anExp (theParent, theChild.ShapeType()); anExp.More(); anExp.Next()) {
if (anExp.CurrentValue() == theChild)
return Standard_True;
}
return Standard_False;
}

...
else
{
if (IsChild (shape, face->Shape()))
{
... //solid is found
}
}

Hope this helps.
Roman

TengDX's picture

Hi, Roman,

Thank you very much. I adopt your advice and it works!!! Can you tell me what difference between the two methods. I really want to know the reason.

Thank you again.

TengDX

Roman Lygin's picture

Hi TengDX,

Probably you already got the difference. Just in case if not, or for other reviewers - here it is.
- TopExp::Map() iterates and stores ALL children in the map
- own IsChild() iterates until THE FIRST matching subshape is found, i.e. it should be time saving in average.

Roman