Ejemplo n.º 1
0
class ExportCAFMethod (object):

    def __init__(self, name="name", tol=1.0E-10):
        self.name = name
        self.step = STEPCAFControl_Writer()
        self.step.SetNameMode(True)
        self.h_doc = TDocStd_Document()
        self.x_app = XCAFApp_Application.GetApplication().GetObject()
        self.x_app.NewDocument(
            TCollection_ExtendedString("MDTV-CAF"), self.h_doc)
        self.doc = self.h_doc.GetObject()
        self.h_shape_tool = XCAFDoc_DocumentTool_ShapeTool(self.doc.Main())
        self.shape_tool = self.h_shape_tool.GetObject()
        Interface_Static_SetCVal("write.step.schema", "AP214")

    def Add(self, shape, name="name"):
        """
        STEPControl_AsIs                   translates an Open CASCADE shape to its highest possible STEP representation.
        STEPControl_ManifoldSolidBrep      translates an Open CASCADE shape to a STEP manifold_solid_brep or brep_with_voids entity.
        STEPControl_FacetedBrep            translates an Open CASCADE shape into a STEP faceted_brep entity.
        STEPControl_ShellBasedSurfaceModel translates an Open CASCADE shape into a STEP shell_based_surface_model entity.
        STEPControl_GeometricCurveSet      translates an Open CASCADE shape into a STEP geometric_curve_set entity.
        """
        label = self.shape_tool.AddShape(shape)
        self.step.Transfer(self.h_doc, STEPControl_AsIs)

    def Write(self, filename=None):
        if not filename:
            filename = self.name
        path, ext = os.path.splitext(filename)
        if not ext:
            ext = ".stp"
        status = self.step.Write(path + ext)
        assert(status == IFSelect_RetDone)
Ejemplo n.º 2
0
    def test_write_step_file(self) -> None:
        """Exports a colored box into a STEP file"""
        ### initialisation
        doc = TDocStd_Document(TCollection_ExtendedString("pythonocc-doc"))
        self.assertTrue(doc is not None)

        # Get root assembly
        shape_tool = XCAFDoc_DocumentTool.ShapeTool(doc.Main())
        colors = XCAFDoc_DocumentTool.ColorTool(doc.Main())
        ### create the shape to export
        test_shape = BRepPrimAPI_MakeBox(100.0, 100.0, 100.0).Shape()

        ### add shape
        shp_label = shape_tool.AddShape(test_shape)
        ### set a color for this shape
        r = 1.0
        g = b = 0.5
        red_color = Quantity_Color(r, g, b,
                                   Quantity_TypeOfColor.Quantity_TOC_RGB)
        colors.SetColor(shp_label, red_color, XCAFDoc_ColorGen)
        # write file
        WS = XSControl_WorkSession()
        writer = STEPCAFControl_Writer(WS, False)
        writer.Transfer(doc, STEPControl_AsIs)
        status = writer.Write("./test_io/test_ocaf_generated.stp")
        self.assertTrue(status)
        self.assertTrue(os.path.isfile("./test_io/test_ocaf_generated.stp"))
Ejemplo n.º 3
0
    def doc_linter(self, doc=None):
        """Clean self.doc by cycling through a STEP save/load cycle."""

        if doc is None:
            doc = self.doc
        # Create a file object to save to
        fname = "deleteme.txt"
        # Initialize STEP exporter
        WS = XSControl_WorkSession()
        step_writer = STEPCAFControl_Writer(WS, False)
        # Transfer shapes and write file
        step_writer.Transfer(doc, STEPControl_AsIs)
        status = step_writer.Write(fname)
        assert status == IFSelect_RetDone
        # Create new TreeModel and read STEP data
        tmodel = TreeModel("DOC")
        shape_tool = tmodel.shape_tool
        color_tool = tmodel.color_tool
        step_reader = STEPCAFControl_Reader()
        step_reader.SetColorMode(True)
        step_reader.SetLayerMode(True)
        step_reader.SetNameMode(True)
        step_reader.SetMatMode(True)
        status = step_reader.ReadFile(fname)
        if status == IFSelect_RetDone:
            logger.info("Transfer doc to STEPCAFControl_Reader")
            step_reader.Transfer(tmodel.doc)
            os.remove(fname)
        return tmodel.doc
Ejemplo n.º 4
0
    def test_write_step_file(self):
        ''' Exports a colored box into a STEP file '''
        ### initialisation
        h_doc = Handle_TDocStd_Document()
        assert (h_doc.IsNull())
        # Create the application
        app = XCAFApp_Application.GetApplication().GetObject()
        app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), h_doc)
        # Get root assembly
        doc = h_doc.GetObject()
        h_shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main())
        l_Colors = XCAFDoc_DocumentTool_ColorTool(doc.Main())
        shape_tool = h_shape_tool.GetObject()
        colors = l_Colors.GetObject()
        ### create the shape to export
        test_shape = BRepPrimAPI_MakeBox(100., 100., 100.).Shape()

        ### add shape
        shp_label = shape_tool.AddShape(test_shape)
        ### set a color for this shape
        r = 1
        g = b = 0.5
        red_color = Quantity_Color(r, g, b, 0)
        colors.SetColor(shp_label, red_color, XCAFDoc_ColorGen)
        # write file
        WS = XSControl_WorkSession()
        writer = STEPCAFControl_Writer(WS.GetHandle(), False)
        writer.Transfer(h_doc, STEPControl_AsIs)
        status = writer.Write("./test_io/test_ocaf_generated.stp")
        assert status
        assert os.path.isfile("./test_io/test_ocaf_generated.stp")
Ejemplo n.º 5
0
    def transfer_step(self, schema='AP203', units=None):
        """
        Transfer the document in preparation for STEP export.

        :param str schema: Schema for STEP file ('AP203', or 'AP214').
        :param units: Units to convert STEP file to.
        :type units: str or None

        :return: *True* if transferred, *False* otherwise.
        :rtype: bool
        """
        self._step_writer = STEPCAFControl_Writer()
        self._step_writer.SetNameMode(True)
        self._step_writer.SetColorMode(True)

        Interface_Static.SetCVal('write.step.schema', schema)
        try:
            units = units_dict[units]
        except KeyError:
            units = Settings.units
        Interface_Static.SetCVal('write.step.unit', units)

        self._step_writer.Transfer(self._doc)

        tw = self._step_writer.ChangeWriter().WS().TransferWriter()
        self._step_fp = tw.FinderProcess()

        return True
Ejemplo n.º 6
0
 def __init__(self, name="name", tol=1.0E-10):
     self.name = name
     self.step = STEPCAFControl_Writer()
     self.step.SetNameMode(True)
     self.doc = TDocStd_Document(TCollection_ExtendedString(""))
     self.x_app = XCAFApp_Application.GetApplication()
     self.x_app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), self.doc)
     self.shape_tool = XCAFDoc_DocumentTool_ShapeTool(self.doc.Main())
     Interface_Static_SetCVal("write.step.schema", "AP214")
     Interface_Static_SetCVal('write.step.unit', 'mm')
Ejemplo n.º 7
0
    def testRTStep(self, doc):
        """A 'short-circuit' Round Trip test. Write doc back to step file."""

        fname = "../testRoundTrip.stp"

        # initialize the STEP exporter
        step_writer = STEPCAFControl_Writer()

        # transfer shapes and write file
        step_writer.Transfer(doc)
        status = step_writer.Write(fname)
        assert (status == IFSelect_RetDone)
Ejemplo n.º 8
0
    def saveStep(self):
        """Export self.doc to STEP file."""

        prompt = 'Choose filename for step file.'
        fnametuple = QFileDialog.getSaveFileName(
            None, prompt, './', "STEP files (*.stp *.STP *.step)")
        fname, _ = fnametuple
        if not fname:
            print("Save step cancelled.")
            return
        # Reconstruct XCAFDoc related code from stepXD.StepImporter
        labels = TDF_LabelSequence()
        shape_tool = XCAFDoc_DocumentTool_ShapeTool(self.doc.Main())
        shape_tool.GetShapes(labels)
        logger.info('Number of labels at root : %i', labels.Length())
        try:
            rootlabel = labels.Value(1)  # First label at root
        except RuntimeError:
            return
        name = rootlabel.GetLabelName()
        logger.info('Name of root label: %s', name)
        isAssy = shape_tool.IsAssembly(rootlabel)
        logger.info("First label at root holds an assembly? %s", isAssy)

        # Modify self.doc by adding active part to rootlabel.
        #Standard_Boolean expand = Standard_False; //default
        #TDF_Label aLabel = myAssembly->AddComponent (aShape [,expand]);
        newLabel = shape_tool.AddComponent(rootlabel, self.activePart, True)
        #set a name to newlabel (as a reminder using OCAF), use:
        #TCollection_ExtendedString aName ...;
        #// contains the desired name for this Label (ASCII)
        #TDataStd_Name::Set (aLabel, aName);
        newName = TCollection_ExtendedString(
            self._nameDict[self.activePartUID])
        TDataStd_Name.Set(newLabel, newName)
        logger.info('Name of new part: %s', newName)
        #myAssembly->UpdateAssemblies();
        shape_tool.UpdateAssemblies()

        # initialize the STEP exporter
        step_writer = STEPCAFControl_Writer()

        # transfer shapes and write file
        step_writer.Transfer(self.doc)
        status = step_writer.Write(fname)
        assert status == IFSelect_RetDone
Ejemplo n.º 9
0
    def saveStepDoc(self):
        """Export self.doc to STEP file."""

        prompt = 'Choose filename for step file.'
        fnametuple = QFileDialog.getSaveFileName(
            None, prompt, './', "STEP files (*.stp *.STP *.step)")
        fname, _ = fnametuple
        if not fname:
            print("Save step cancelled.")
            return

        # initialize STEP exporter
        WS = XSControl_WorkSession()
        step_writer = STEPCAFControl_Writer(WS, False)

        # transfer shapes and write file
        step_writer.Transfer(self.doc, STEPControl_AsIs)
        status = step_writer.Write(fname)
        assert status == IFSelect_RetDone
Ejemplo n.º 10
0
    def write_file(self):
        r"""Write file"""
        work_session = XSControl_WorkSession()
        writer = STEPCAFControl_Writer(work_session.GetHandle(), False)

        transfer_status = writer.Transfer(self.h_doc, STEPControl_AsIs)
        if transfer_status != IFSelect_RetDone:
            msg = "An error occurred while transferring a shape " \
                  "to the STEP writer"
            logger.error(msg)
            raise StepShapeTransferException(msg)
        logger.info('Writing STEP file')

        write_status = writer.Write(self.filename)
        if write_status == IFSelect_RetDone:
            logger.info("STEP file write successful.")
        else:
            msg = "An error occurred while writing the STEP file"
            logger.error(msg)
            raise StepFileWriteException(msg)
Ejemplo n.º 11
0
def export_STEPFile_single(shape, filename, tol=1.0E-6):
    """
    Exports a .stp file containing the input shapes

    Parameters
    ----------
    shape : TopoDS_Shape

    filename : string
        The output filename
    """

    step = STEPCAFControl_Writer()
    step.SetNameMode(True)
    step.SetPropsMode(True)
    h_doc = TDocStd_Document()
    x_app = XCAFApp_Application.GetApplication().GetObject()
    x_app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), h_doc)
    doc = h_doc.GetObject()
    h_shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main())
    shape_tool = h_shape_tool.GetObject()
    Interface_Static_SetCVal("write.step.schema", "AP214")

    # transfer shapes
    print(filename)
    shape_tool.AddShape(shape)
    step.Transfer(h_doc, STEPControl_AsIs)
    status = step.Write(filename)
    assert(status == IFSelect_RetDone)
Ejemplo n.º 12
0
 def externalGeometryAssembly(self):
     # Create a TDoc holding the assembly of structure parts with external geometry. When assembled, write the STEP file
     # Initialize the  writer
     shapes = []
     step_writer = STEPCAFControl_Writer()
     step_writer.SetNameMode(True)
     step_writer.SetPropsMode(True)
     # create the handle to a document
     doc = TDocStd_Document(TCollection_ExtendedString("ocx-doc"))
     # Get root assembly
     shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main())
     shape_tool.SetAutoNaming(False)
     l_colors = XCAFDoc_DocumentTool_ColorTool(doc.Main())
     l_layers = XCAFDoc_DocumentTool_LayerTool(doc.Main())
     l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main())
     aBuilder = BRep_Builder()
     # Loop over all Panels
     panelchildren = []
     for panel in self.model.panels:
         OCXCommon.LogMessage(panel, self.logging)
         guid = self.model.getGUID(panel)
         children = self.model.getPanelChildren(guid)
         panelchildren = panelchildren + children
         # Build the Panel compound
         compound = TopoDS_Compound()
         aBuilder.MakeCompound(compound)
         label = shape_tool.AddShape(compound)
         pname = panel.get('name')
         tname = TDataStd_Name()
         tname.Set(TCollection_ExtendedString(pname))
         label.AddAttribute(tname)
         for child in children:
             object = self.model.getObject(child)
             name = object.get('name')
             extg = ExternalGeometry(self.model, object, self.dict,
                                     self.logging)  # Init the creator
             extg.readExtGeometry()  # Read the Brep
             if extg.IsDone():
                 aBuilder.Add(compound, extg.Shape())
                 tname = TDataStd_Name()
                 label = shape_tool.AddShape(extg.Shape())
                 tname.Set(TCollection_ExtendedString(name))
                 label.AddAttribute(tname)
     # Root brackets
     compound = TopoDS_Compound()
     aBuilder.MakeCompound(compound)
     label = shape_tool.AddShape(compound)
     tname = TDataStd_Name()
     tname.Set(TCollection_ExtendedString('Brackets'))
     label.AddAttribute(tname)
     for br in self.model.brackets:
         guid = self.model.getGUID(br)
         name = br.get('name')
         if guid not in panelchildren:
             extg = ExternalGeometry(self.model, br, self.dict,
                                     self.logging)  # Init the creator
             extg.readExtGeometry()  # Read the Brep
             if extg.IsDone():
                 aBuilder.Add(compound, extg.Shape())
                 tname = TDataStd_Name()
                 label = shape_tool.AddShape(extg.Shape())
                 tname.Set(TCollection_ExtendedString(name))
                 label.AddAttribute(tname)
     # Root plates
     compound = TopoDS_Compound()
     aBuilder.MakeCompound(compound)
     label = shape_tool.AddShape(compound)
     tname = TDataStd_Name()
     tname.Set(TCollection_ExtendedString('Plates'))
     label.AddAttribute(tname)
     for pl in self.model.plates:
         guid = self.model.getGUID(pl)
         name = pl.get('name')
         if guid not in panelchildren:
             extg = ExternalGeometry(self.model, pl, self.dict,
                                     self.logging)  # Init the creator
             extg.readExtGeometry()  # Read the Brep
             if extg.IsDone():
                 aBuilder.Add(compound, extg.Shape())
                 tname = TDataStd_Name()
                 label = shape_tool.AddShape(extg.Shape())
                 tname.Set(TCollection_ExtendedString(name))
                 label.AddAttribute(tname)
     # Root pillars
     compound = TopoDS_Compound()
     aBuilder.MakeCompound(compound)
     label = shape_tool.AddShape(compound)
     tname = TDataStd_Name()
     tname.Set(TCollection_ExtendedString('Pillars'))
     label.AddAttribute(tname)
     for pil in self.model.pillars:
         guid = self.model.getGUID(pil)
         name = pil.get('name')
         if guid not in panelchildren:
             extg = ExternalGeometry(self.model, pil, self.dict,
                                     self.logging)  # Init the creator
             extg.readExtGeometry()  # Read the Brep
             if extg.IsDone():
                 aBuilder.Add(compound, extg.Shape())
                 tname = TDataStd_Name()
                 label = shape_tool.AddShape(extg.Shape())
                 tname.Set(TCollection_ExtendedString(name))
                 label.AddAttribute(tname)
     step_writer.Perform(
         doc, TCollection_AsciiString(self.model.ocxfile.stem + '.stp'))
     return
Ejemplo n.º 13
0
class XdeDocument(object):
    """
    Wrapper class to work with Extended Data Exchange.

    :param bool binary: If *True*, the document will be saved in a binary
        format. If *False*, the document will be saved in an XML format.
    """
    def __init__(self, binary=True):
        if binary:
            self._fmt = 'BinXCAF'
            self._ext = '.xbf'
        else:
            self._fmt = 'XmlXCAF'
            self._ext = '.xml'

        # Get application
        self._app = XCAFApp_Application.GetApplication()
        if binary:
            binxcafdrivers.DefineFormat(self._app)
        else:
            xmlxcafdrivers.DefineFormat(self._app)

        # Initialize document
        fmt = TCollection_ExtendedString(self._fmt)
        self._doc = TDocStd_Document(fmt)
        self._app.InitDocument(self._doc)

        # Exchange data
        self._shape = None
        self._step_writer = None
        self._step_fp = None

        self._init_tool()

    def _init_tool(self):
        self._tool = XCAFDoc_DocumentTool.ShapeTool(self._doc.Main())

    @property
    def main_label(self):
        """
        :return: The main label of the document.
        :rtype: afem.exchange.xde.XdeLabel
        """
        return XdeLabel(self._doc.Main())

    @property
    def shapes_label(self):
        """
        :return: The shapes label of the document.
        :rtype: afem.exchange.xde.XdeLabel
        """
        return XdeLabel(XCAFDoc_DocumentTool.ShapesLabel_(self._doc.Main()))

    def open(self, fn):
        """
        Open a document.

        :param str fn: The filename.

        :return: *True* if opened, *False* if not.
        :rtype: bool
        """
        if not fn.endswith(self._ext):
            fn += self._ext

        txt = TCollection_ExtendedString(fn)
        status, self._doc = self._app.Open(txt, self._doc)
        if status != PCDM_RS_OK:
            return False
        self._init_tool()
        return True

    def save_as(self, fn):
        """
        Save the document.

        :param str fn: The filename.

        :return: *True* if sucessfully saved, *False* if not.
        :rtype: bool
        """
        if not fn.endswith(self._ext):
            fn += self._ext

        txt = TCollection_ExtendedString(fn)
        status = self._app.SaveAs(self._doc, txt)
        return status == PCDM_SS_OK

    def close(self):
        """
        Close the document.

        :return: None.
        """
        self._doc.Close()

    def read_step(self, fn):
        """
        Read and translate a STEP file.

        :param str fn: The filename.

        :return: The shapes label.
        :rtype: afem.exchange.xde.Label.

        :raise RuntimeError: If the file cannot be read.
        """
        reader = STEPCAFControl_Reader()
        reader.SetNameMode(True)
        reader.SetColorMode(True)
        status = reader.Perform(fn, self._doc)
        if not status:
            raise RuntimeError("Error reading STEP file.")

        self._shape = Shape.wrap(reader.Reader().OneShape())
        label = XCAFDoc_DocumentTool.ShapesLabel_(self._doc.Main())
        return XdeLabel(label)

    def transfer_step(self, schema='AP203', units=None):
        """
        Transfer the document in preparation for STEP export.

        :param str schema: Schema for STEP file ('AP203', or 'AP214').
        :param units: Units to convert STEP file to.
        :type units: str or None

        :return: *True* if transferred, *False* otherwise.
        :rtype: bool
        """
        self._step_writer = STEPCAFControl_Writer()
        self._step_writer.SetNameMode(True)
        self._step_writer.SetColorMode(True)

        Interface_Static.SetCVal('write.step.schema', schema)
        try:
            units = units_dict[units]
        except KeyError:
            units = Settings.units
        Interface_Static.SetCVal('write.step.unit', units)

        self._step_writer.Transfer(self._doc)

        tw = self._step_writer.ChangeWriter().WS().TransferWriter()
        self._step_fp = tw.FinderProcess()

        return True

    def set_shape_name(self, shape, name):
        """
        Set the name of the STEP entity for the given shape. The shape(s)
        should be transferred before naming them.

        :param afem.topology.entities.Shape shape: The shape (or sub-shape).
        :param str name: The name.

        :return: *True* if name is set, *False* otherwise.
        :rtype: bool
        """
        if self._step_writer is None:
            raise RuntimeError('Document has not been transferred.')

        item = stepconstruct.FindEntity(self._step_fp, shape.object)
        if not item:
            return False

        item.SetName(TCollection_HAsciiString(name))
        return True

    def write_step(self, fn, schema='AP203', units=None):
        """
        Write the document to a STEP file.

        :param str fn: The filename.
        :param str schema: Schema for STEP file ('AP203', or 'AP214').
        :param units: Units to convert STEP file to.
        :type units: str or None

        :return: *True* if written successfully, *False* otherwise.
        """
        if self._step_writer is None:
            self.transfer_step(schema, units)

        status = self._step_writer.Write(fn)

        return int(status) < int(IFSelect_RetError)

    def is_top_level(self, label):
        """
        Check if label is top-level as opposed to a component of assembly or
        a sub-shape.

        :param afem.exchange.xde.XdeLabel label: The label

        :return: *True* if top-level, *False* otherwise.
        :rtype: bool
        """
        return self._tool.IsTopLevel(label.object)

    def is_sub_shape(self, label, shape):
        """
        Check if the shape is a sub-shape of the shape stored on the label.

        :param afem.exchange.xde.XdeLabel label: The label
        :param afem.topology.entities.Shape shape: The shape.

        :return: *True* if a sub-shape, *False* otherwise.
        :rtype: bool
        """
        return self._tool.IsSubShape(label.object, shape.object)

    def find_shape(self, shape, find_instance=False):
        """
        Find the label corresponding to the shape. This method searches only
        top-level shapes.

        :param afem.topology.entities.Shape shape: The shape.
        :param bool find_instance: If *False*, search for the non-located shape
            in an assembly. If *True*, search for the shape with the same
            location.

        :return: The shape label if found, *None* otherwise.
        :rtype: afem.exchange.xde.XdeLabel
        """
        label = self._tool.FindShape(shape.object, find_instance)
        if not label:
            return None
        return XdeLabel(label)

    def new_shape(self):
        """
        Create a new top-level label.

        :return: The label.
        :rtype: afem.exchange.xde.XdeLabel
        """
        return XdeLabel(self._tool.NewShape())

    def set_shape(self, label, shape):
        """
        Set the shape of the top-level label.

        :param afem.exchange.xde.XdeLabel label: The label.
        :param afem.topology.entities.Shape shape: The shape.

        :return: None.
        """
        self._tool.SetShape(label.object, shape.object)

    def add_shape(self, shape, name=None, make_assy=True):
        """
        Add a new top-level shape.

        :param afem.topology.entities.Shape shape: The shape.
        :param str name: The label name.
        :param bool make_assy: If *True*, then treat compounds as assemblies.

        :return: The shape label.
        :rtype: afem.exchange.xde.XdeLabel
        """
        label = XdeLabel(self._tool.AddShape(shape.object, make_assy))
        if name is not None:
            label.set_name(name)
        return label

    def remove_shape(self, label, remove_completely=True):
        """
        Remove a shape.

        :param afem.exchange.xde.XdeLabel label: The label.
        :param bool remove_completely: If *True*, removes all shapes. If
            *False*, only remove the shape with the same location.

        :return: *True* if removed, or *False* if not removed because it is not
            a free or top-level shape.
        :rtype: bool
        """
        return self._tool.RemoveShape(label.object, remove_completely)

    def get_shapes(self):
        """
        Get a list containing all top-level shapes.

        :return: List of top-level shapes.
        :rtype: list(afem.exchange.xde.XdeLabel)
        """
        labels = TDF_LabelSequence()
        self._tool.GetShapes(labels)
        return [XdeLabel(label) for label in labels]

    def get_shape_by_name(self, name):
        """
        Get a shape label by its name. This only applies to top-level shapes
        and will return the first match.

        :param str name: The name.

        :return: The label or *None* if not found.
        :rtype: afem.exchange.xde.XdeLabel or None
        """
        for label in self.get_shapes():
            if label.name == name:
                return label

    def find_subshape(self, label, shape):
        """
        Find a label for the sub-shape stored on the given label.

        :param afem.exchange.xde.XdeLabel label: The label.
        :param afem.topology.entities.Shape shape: The sub-shape.

        :return: The sub-shape label if found, *None* otherwise.
        :rtype: afem.exchange.xde.XdeLabel or None
        """
        sub_label = TDF_Label()
        status, sub_label = self._tool.FindSubShape(label.object, shape.object,
                                                    sub_label)
        if not status:
            return None
        return XdeLabel(sub_label)

    def add_subshape(self, label, shape, name=None):
        """
        Add a label for a sub-shape stored on the shape of the label.

        :param afem.exchange.xde.XdeLabel label: The label.
        :param afem.topology.entities.Shape shape: The sub-shape.
        :param str name: The name of the sub-shape label.

        :return: The sub-shape label.
        :rtype: afem.exchange.xde.XdeLabel
        """
        label = XdeLabel(self._tool.AddSubShape(label.object, shape.object))
        if name is None:
            return label
        label.set_name(name)
        return label

    def set_auto_naming(self, mode):
        """
        Set the option to auto-name shape labels. This only applies to
        top-level shapes.

        :param bool mode: The mode. If *True*, added shapes are automatically
            named based on their type (e.g., "SOLID", "SHELL", etc.).

        :return: None.
        """
        self._tool.SetAutoNaming_(mode)