pythonocc-core
pythonocc-core copied to clipboard
Extract STEP Entity Instance Id's of Shapes
Let's suppose I'm using this STEP file data as input:
#417=ADVANCED_FACE('face_1',(#112),#405,.F.);
#418=ADVANCED_FACE('face_2',(#113),#406,.F.);
#419=ADVANCED_FACE('face_3',(#114),#407,.F.);
Then the following code will print the names of the ADVANCED_FACE
instances (face_1
,face_2
and face_3
):
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopAbs import TopAbs_FACE
from OCC.Core.StepRepr import StepRepr_RepresentationItem
reader = STEPControl_Reader()
tr = reader.WS().TransferReader()
reader.ReadFile('model.stp')
reader.TransferRoots()
shape = reader.OneShape()
exp = TopExp_Explorer(shape, TopAbs_FACE)
while exp.More():
s = exp.Current()
exp.Next()
item = tr.EntityFromShapeResult(s, 1)
item = StepRepr_RepresentationItem.DownCast(item)
name = item.Name().ToCString()
print(name)
How can I access the identifiers of the individual shapes? (#417
,#418
and #419
)
This issue is similar to #522. But #522 does not provide a solution for accessing ID's
Put this after roots transfer:
model = reader.StepModel()
and this into cycle where you retrieving face's names:
id = model.IdentLabel(item)
print(id)
@temurka1 Thank you so much! Here is the code for anyone reading this in the future.
@flolu I would also recommend to split loop - you are using XSControl_TransferReader::EntityFromShapeResult(..) which could be slow for large STEP files. It's better to collect faces into TopTools_HSequenceOfShape and then pass collected faces to XSControl_TransferReader::EntitiesFromShapeList(..) and iterate over returned list
@temurka1 Performance is not that relevant for my use case, but you may provide an example for future readers. Thanks :)
@flolu Hello, how do you add the names "face_1" and "face_2" of ADVANCED FACE to the step file. I'm building a dataset containing tens of thousands of step files. I need to name the ADVANCED FACE in the step file, but I don't know how you do this. Please help me, thank you!
@MaFangchang I did not add the labels myself. They were added by the creators of the CAD models I'm working with.
@flolu Hello, how do you add the names "face_1" and "face_2" of ADVANCED FACE to the step file. I'm building a dataset containing tens of thousands of step files. I need to name the ADVANCED FACE in the step file, but I don't know how you do this. Please help me, thank you!
I figured this out a while ago, its quite complicated. Here some example code.
@MaFangchang the intersting part is at the end of my code, see
# set names of the entities
and
item.SetName(TCollection_HAsciiString('banana_' + str(counter)))
The faces are called banana_0
to banana_5
in the step file.
Result: Modell2.zip
@tpaviot If you want, you can add this to the examples: How to colorize single faces and add entity names in the step file.
import numpy as np
from OCC.Core.BRepAdaptor import BRepAdaptor_Surface
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Core.GeomAbs import GeomAbs_Cylinder
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_sRGB
from OCC.Core.STEPCAFControl import STEPCAFControl_Writer
from OCC.Core.STEPConstruct import stepconstruct_FindEntity
from OCC.Core.STEPControl import STEPControl_AsIs
from OCC.Core.TCollection import TCollection_ExtendedString, TCollection_HAsciiString
from OCC.Core.TDataStd import TDataStd_Name
from OCC.Core.TDocStd import TDocStd_Document
from OCC.Core.TopoDS import TopoDS_Compound, topods
from OCC.Core.XCAFDoc import XCAFDoc_DocumentTool, XCAFDoc_ColorSurf
from OCC.Core.XSControl import XSControl_WorkSession
from OCC.Core.gp import gp_Pnt, gp_Ax2, gp_Dir
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere, BRepPrimAPI_MakeCylinder
from OCC.Extend.TopologyUtils import TopologyExplorer
# data for Modell 2
name = "Modell2"
sph_centre = np.array([0, 0, 0])
sph_diameter = 50
cyl_diameters = np.array([22, 20, 21, 19, 19, 19])
cyl_height = np.array([30, 30, 30, 30, 30, 30])
cyl_vectors = np.array([[-1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[0, -1, 0],
[0, 0, -1]], dtype=float)
# normalize vectors
cyl_vectors = cyl_vectors / np.linalg.nor
m(cyl_vectors, axis=1, keepdims=True)
# colors for the faces
COLORS = [[0.00784314, 0.24313725, 1. ],
[1. , 0.48627451, 0. ],
[0.10196078, 0.78823529, 0.21960784],
[0.90980392, 0. , 0.04313725],
[0.54509804, 0.16862745, 0.88627451],
[0.62352941, 0.28235294, 0. ],
[0.94509804, 0.29803922, 0.75686275],
[0.63921569, 0.63921569, 0.63921569],
[1. , 0.76862745, 0. ],
[0. , 0.84313725, 1. ]]
def create_node_buildvolume(sph_diameter: float,
cyl_diameters: np.ndarray,
cyl_height: np.ndarray,
cyl_vectors: np.ndarray) -> TopoDS_Compound:
"""
Create 3D buildvolume containing a sphere and cylinders
Args:
sph_diameter (float): Diameter of the sphere D
cyl_diameters (np.array): List of diameters of the cylinders [d1, d2]
cyl_height (np.array): List of lengths of the cylinders [l1, l2]
cyl_vectors (np.array): List of midline vectors of the cylinders [[x1, y1, z1], [x1, y1, z1]]
Returns:
TopoDS_Compound: 3D Model of the buildvolume
"""
sph_radius = sph_diameter / 2
origin = gp_Pnt(0.0, 0.0, 0.0)
sphere = BRepPrimAPI_MakeSphere(origin, sph_radius).Solid()
for i in range(len(cyl_vectors)):
cylinder_origin = gp_Ax2(origin, gp_Dir(*cyl_vectors[i, :]))
cyl = BRepPrimAPI_MakeCylinder(cylinder_origin, cyl_diameters[i]/2, cyl_height[i]+sph_radius).Solid()
sphere = BRepAlgoAPI_Fuse(sphere, cyl).Shape()
return topods.Compound(sphere)
# create model
buildvolume = create_node_buildvolume(sph_diameter, cyl_diameters, cyl_height, cyl_vectors)
# create TDocStd_Document
doc = TDocStd_Document(TCollection_ExtendedString("color-doc"))
# get shape tool
shapeTool = XCAFDoc_DocumentTool.ShapeTool(doc.Main())
# get color tool
colorTool = XCAFDoc_DocumentTool.ColorTool(doc.Main())
# create new empty shape
buildvolume_Label = shapeTool.NewShape()
# set the shape of the new model to the one created
shapeTool.SetShape(buildvolume_Label, buildvolume)
# set name of the whole model
TDataStd_Name.Set(buildvolume_Label, TCollection_ExtendedString(name))
# color all cylindrical faces
color_index = 0
topoexp = TopologyExplorer(buildvolume)
for face in topoexp.faces():
surface = BRepAdaptor_Surface(face)
if surface.GetType() == GeomAbs_Cylinder:
cyl_Label = shapeTool.AddSubShape(buildvolume_Label, face)
if not cyl_Label.IsNull():
shapeTool.SetShape(cyl_Label, face)
else:
shapeTool.FindShape(face, cyl_Label)
colorTool.SetColor(face,
Quantity_Color(*COLORS[color_index % len(COLORS)], Quantity_TOC_sRGB),
XCAFDoc_ColorSurf)
color_index += 1
# create WorkSession to create STEPCAFControl_Writer and FinderProcess
WS = XSControl_WorkSession()
# create stepCAFWriter from WorkSession
stepCAFWriter = STEPCAFControl_Writer(WS)
# create FinderProcess from WorkSession
finderProcess = WS.TransferWriter().FinderProcess()
# transfer the model to the stepCAFWriter
stepCAFWriter.Transfer(doc, STEPControl_AsIs)
###
# set names of the entities
###
topoexp = TopologyExplorer(buildvolume)
counter = 0
for face in topoexp.faces():
surface = BRepAdaptor_Surface(face)
if surface.GetType() == GeomAbs_Cylinder:
item = stepconstruct_FindEntity(finderProcess, face)
if item:
item.SetName(TCollection_HAsciiString('banana_' + str(counter)))
counter += 1
# Export as step file
status = stepCAFWriter.Write(f"{name}.stp")
@MaFangchang I did not add the labels myself. They were added by the creators of the CAD models I'm working with.
OK, thank you for your reply.
@flolu Hello, how do you add the names "face_1" and "face_2" of ADVANCED FACE to the step file. I'm building a dataset containing tens of thousands of step files. I need to name the ADVANCED FACE in the step file, but I don't know how you do this. Please help me, thank you!
I figured this out a while ago, its quite complicated. Here some example code. @MaFangchang the intersting part is at the end of my code, see
# set names of the entities
anditem.SetName(TCollection_HAsciiString('banana_' + str(counter)))
The faces are calledbanana_0
tobanana_5
in the step file.Result: Modell2.zip
@tpaviot If you want, you can add this to the examples: How to colorize single faces and add entity names in the step file.
import numpy as np from OCC.Core.BRepAdaptor import BRepAdaptor_Surface from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse from OCC.Core.GeomAbs import GeomAbs_Cylinder from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_sRGB from OCC.Core.STEPCAFControl import STEPCAFControl_Writer from OCC.Core.STEPConstruct import stepconstruct_FindEntity from OCC.Core.STEPControl import STEPControl_AsIs from OCC.Core.TCollection import TCollection_ExtendedString, TCollection_HAsciiString from OCC.Core.TDataStd import TDataStd_Name from OCC.Core.TDocStd import TDocStd_Document from OCC.Core.TopoDS import TopoDS_Compound, topods from OCC.Core.XCAFDoc import XCAFDoc_DocumentTool, XCAFDoc_ColorSurf from OCC.Core.XSControl import XSControl_WorkSession from OCC.Core.gp import gp_Pnt, gp_Ax2, gp_Dir from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere, BRepPrimAPI_MakeCylinder from OCC.Extend.TopologyUtils import TopologyExplorer # data for Modell 2 name = "Modell2" sph_centre = np.array([0, 0, 0]) sph_diameter = 50 cyl_diameters = np.array([22, 20, 21, 19, 19, 19]) cyl_height = np.array([30, 30, 30, 30, 30, 30]) cyl_vectors = np.array([[-1, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [0, -1, 0], [0, 0, -1]], dtype=float) # normalize vectors cyl_vectors = cyl_vectors / np.linalg.nor m(cyl_vectors, axis=1, keepdims=True) # colors for the faces COLORS = [[0.00784314, 0.24313725, 1. ], [1. , 0.48627451, 0. ], [0.10196078, 0.78823529, 0.21960784], [0.90980392, 0. , 0.04313725], [0.54509804, 0.16862745, 0.88627451], [0.62352941, 0.28235294, 0. ], [0.94509804, 0.29803922, 0.75686275], [0.63921569, 0.63921569, 0.63921569], [1. , 0.76862745, 0. ], [0. , 0.84313725, 1. ]] def create_node_buildvolume(sph_diameter: float, cyl_diameters: np.ndarray, cyl_height: np.ndarray, cyl_vectors: np.ndarray) -> TopoDS_Compound: """ Create 3D buildvolume containing a sphere and cylinders Args: sph_diameter (float): Diameter of the sphere D cyl_diameters (np.array): List of diameters of the cylinders [d1, d2] cyl_height (np.array): List of lengths of the cylinders [l1, l2] cyl_vectors (np.array): List of midline vectors of the cylinders [[x1, y1, z1], [x1, y1, z1]] Returns: TopoDS_Compound: 3D Model of the buildvolume """ sph_radius = sph_diameter / 2 origin = gp_Pnt(0.0, 0.0, 0.0) sphere = BRepPrimAPI_MakeSphere(origin, sph_radius).Solid() for i in range(len(cyl_vectors)): cylinder_origin = gp_Ax2(origin, gp_Dir(*cyl_vectors[i, :])) cyl = BRepPrimAPI_MakeCylinder(cylinder_origin, cyl_diameters[i]/2, cyl_height[i]+sph_radius).Solid() sphere = BRepAlgoAPI_Fuse(sphere, cyl).Shape() return topods.Compound(sphere) # create model buildvolume = create_node_buildvolume(sph_diameter, cyl_diameters, cyl_height, cyl_vectors) # create TDocStd_Document doc = TDocStd_Document(TCollection_ExtendedString("color-doc")) # get shape tool shapeTool = XCAFDoc_DocumentTool.ShapeTool(doc.Main()) # get color tool colorTool = XCAFDoc_DocumentTool.ColorTool(doc.Main()) # create new empty shape buildvolume_Label = shapeTool.NewShape() # set the shape of the new model to the one created shapeTool.SetShape(buildvolume_Label, buildvolume) # set name of the whole model TDataStd_Name.Set(buildvolume_Label, TCollection_ExtendedString(name)) # color all cylindrical faces color_index = 0 topoexp = TopologyExplorer(buildvolume) for face in topoexp.faces(): surface = BRepAdaptor_Surface(face) if surface.GetType() == GeomAbs_Cylinder: cyl_Label = shapeTool.AddSubShape(buildvolume_Label, face) if not cyl_Label.IsNull(): shapeTool.SetShape(cyl_Label, face) else: shapeTool.FindShape(face, cyl_Label) colorTool.SetColor(face, Quantity_Color(*COLORS[color_index % len(COLORS)], Quantity_TOC_sRGB), XCAFDoc_ColorSurf) color_index += 1 # create WorkSession to create STEPCAFControl_Writer and FinderProcess WS = XSControl_WorkSession() # create stepCAFWriter from WorkSession stepCAFWriter = STEPCAFControl_Writer(WS) # create FinderProcess from WorkSession finderProcess = WS.TransferWriter().FinderProcess() # transfer the model to the stepCAFWriter stepCAFWriter.Transfer(doc, STEPControl_AsIs) ### # set names of the entities ### topoexp = TopologyExplorer(buildvolume) counter = 0 for face in topoexp.faces(): surface = BRepAdaptor_Surface(face) if surface.GetType() == GeomAbs_Cylinder: item = stepconstruct_FindEntity(finderProcess, face) if item: item.SetName(TCollection_HAsciiString('banana_' + str(counter))) counter += 1 # Export as step file status = stepCAFWriter.Write(f"{name}.stp")
Thank you very much. Your code is very helpful to me.
And it's possible to do the inverse of this?
from let's say this ID:
#28=TRIANGULATED_FACE('',#26,10,((-1000.,-0.,-0.)),$,(),((10,9,8),(10,8,7),(10,7,6),(10,6,5),(10,5,4),(10,4,3),(10,3,2),(10,
2,1)));
Get the solids faces edges?