def recognize_face(a_face): """ Takes a TopoDS shape and tries to identify its nature whether it is a plane a cylinder a torus etc. if a plane, returns the normal if a cylinder, returns the radius """ surf = BRepAdaptor_Surface(a_face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: print("--> plane") # look for the properties of the plane # first get the related gp_Pln gp_pln = surf.Plane() location = gp_pln.Location() # a point of the plane normal = gp_pln.Axis().Direction() # the plane normal # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Normal (global coordinates)", normal.X(), normal.Y(), normal.Z()) elif surf_type == GeomAbs_Cylinder: print("--> cylinder") # look for the properties of the cylinder # first get the related gp_Cyl gp_cyl = surf.Cylinder() location = gp_cyl.Location() # a point of the axis axis = gp_cyl.Axis().Direction() # the cylinder axis # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Axis (global coordinates)", axis.X(), axis.Y(), axis.Z()) else: # TODO there are plenty other type that can be checked # see documentation for the BRepAdaptor class # https://www.opencascade.com/doc/occt-6.9.1/refman/html/class_b_rep_adaptor___surface.html print("not implemented")
def face_is_plane(face): """ Returns True if the TopoDS_Shape is a plane, False otherwise """ surf = BRepAdaptor_Surface(face, True) surf_type = surf.GetType() return surf_type == GeomAbs_Plane
def type_face(face): if type(face) is not TopoDS_Face: print(face, 'not face') return None surf_adaptor = BRepAdaptor_Surface(face) return SURFACE_TYPE[surf_adaptor.GetType()]
def create_surface_object(self, face, f_id): surf = BRepAdaptor_Surface(face, True) surf_type = surf.GetType() if surf_type == GeomAbs_BSplineSurface: return BSplineSurface(face, surf, f_id) else: return None
def recognize_face(self, a_face): """ Takes a TopoDS shape and tries to identify its nature whether it is a plane a cylinder a torus etc. if a plane, returns the normal if a cylinder, returns the radius """ surf = BRepAdaptor_Surface(a_face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: print("--> plane") # look for the properties of the plane # first get the related gp_Pln gp_pln = surf.Plane() location = gp_pln.Location() # a point of the plane normal = gp_pln.Axis().Direction() # the plane normal x_axis = gp_pln.XAxis().Direction() # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Normal (global coordinates)", normal.X(), normal.Y(), normal.Z()) print("--> X_axis", x_axis.X(), x_axis.Y(), x_axis.Z()) centre = [location.X(), location.Y(), location.Z()] normal = [normal.X(), normal.Y(), normal.Z()] point_coords = [ centre[0] + normal[0], centre[1] + normal[1], centre[2] + normal[2] ] pnt = gp_Pnt(point_coords[0], point_coords[1], point_coords[2]) _in_solid = BRepClass3d_SolidClassifier(self.frame, pnt, 1e-5) if _in_solid.State() == 0: normal = [-normal[0], -normal[1], -normal[2]] print(point_coords) X_axis = [x_axis.X(), x_axis.Y(), x_axis.Z()] return (centre, normal, X_axis) elif surf_type == GeomAbs_Cylinder: print("--> cylinder") # look for the properties of the cylinder # first get the related gp_Cyl gp_cyl = surf.Cylinder() location = gp_cyl.Location() # a point of the axis axis = gp_cyl.Axis().Direction() # the cylinder axis # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Axis (global coordinates)", axis.X(), axis.Y(), axis.Z()) else: # TODO there are plenty other type that can be checked # see documentation for the BRepAdaptor class # https://www.opencascade.com/doc/occt-6.9.1/refman/html/class_b_rep_adaptor___surface.html print("not implemented")
def recognize_face(topods_face): """returns True if the TopoDS_Face is a planar surface""" if not isinstance(topods_face, TopoDS_Face): return "Not a face", None, None surf = BRepAdaptor_Surface(topods_face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: kind = "Plane" # look for the properties of the plane # first get the related gp_Pln gp_pln = surf.Plane() location = gp_pln.Location() # a point of the plane normal = gp_pln.Axis().Direction() # the plane normal tuple_to_return = (kind, location, normal) elif surf_type == GeomAbs_Cylinder: kind = "Cylinder" # look for the properties of the cylinder # first get the related gp_Cyl gp_cyl = surf.Cylinder() location = gp_cyl.Location() # a point of the axis axis = gp_cyl.Axis().Direction() # the cylinder axis # then export location and normal to the console output tuple_to_return = (kind, location, axis) elif surf_type == GeomAbs_Cone: kind = "Cone" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_Sphere: kind = "Sphere" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_Torus: kind = "Torus" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_BezierSurface: kind = "Bezier" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_BSplineSurface: kind = "BSpline" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_SurfaceOfRevolution: kind = "Revolution" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_SurfaceOfExtrusion: kind = "Extrusion" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_OffsetSurface: kind = "Offset" tuple_to_return = (kind, None, None) elif surf_type == GeomAbs_OtherSurface: kind = "Other" tuple_to_return = (kind, None, None) else: tuple_to_return = ("Unknwon", None, None) return tuple_to_return
def executeOnFile(file): global files_processed print('\n>> file', file_counter) compound = read_step_file(file, verbosity=False) # always 3 unknown entities ex = TopologyExplorer(compound) for face in ex.faces(): type_counter[BRepAdaptor_Surface(face).GetType()] += 1 if BRepAdaptor_Surface(face).GetType() == FILTER_TYPE: os.makedirs(OUTPUT_DIR, exist_ok=True) #TODO write model face to new file files_processed += 1
def project_to_XYZ(self): assert self.face != None surface = BRepAdaptor_Surface(self.face) if self.face.Orientation() == TopAbs_REVERSED: u_tmp = self.u self.reverse_u() xyz = surface.Value(self.u, self.v) self.u = u_tmp else: xyz = surface.Value(self.u, self.v) self.x = xyz.X() self.y = xyz.Y() self.z = xyz.Z()
def create_surface_object(self, face, f_id): surf = BRepAdaptor_Surface(face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: return Plane(face, surf, f_id) elif surf_type == GeomAbs_Cylinder: return Cylinder(face, surf, f_id) elif surf_type == GeomAbs_Cone: return Cone(face, surf, f_id) elif surf_type == GeomAbs_Sphere: return Sphere(face, surf, f_id) elif surf_type == GeomAbs_Torus: return Torus(face, surf, f_id)
def compute_halfway_on_shared_edge(sv0, sv1): def get_shared_edge(sv0, sv1): for sv0_edge_with_p in sv0.edges_with_p: sv0_edge, sv0_p = sv0_edge_with_p for sv1_edge_with_p in sv1.edges_with_p: sv1_edge, sv1_p = sv1_edge_with_p if sv0_edge == sv1_edge: u0 = min(sv0_p, sv1_p) u1 = max(sv0_p, sv1_p) return sv0_edge, u0, u1 return None, -1, -1 assert sv0.face_id == sv1.face_id assert not sv0.edges_with_p is None assert not sv1.edges_with_p is None shared_edge, u0, u1 = get_shared_edge(sv0, sv1) if shared_edge is None: raise Exception( 'compute_halfway_on_shared_edge() error - no shared edge') curve = BRepAdaptor_Curve2d(shared_edge, sv0.face) u01_length = GCPnts_AbscissaPoint.Length(curve, u0, u1) abscissa_point = GCPnts_AbscissaPoint(curve, u01_length / 2, u0) assert abscissa_point.IsDone() p = abscissa_point.Parameter() uv = curve.Value(p) xyz = BRepAdaptor_Surface(sv0.face).Value(uv.X(), uv.Y()) sv_halfway = SuperVertex(x=xyz.X(), y=xyz.Y(), z=xyz.Z(), u=uv.X(), v=uv.Y()) sv_halfway.face_id = sv0.face_id sv_halfway.face = sv0.face sv_halfway.edges_with_p = [(shared_edge, p)] if sv0.face.Orientation() == TopAbs_REVERSED: sv_halfway.reverse_u() return sv_halfway
def adaptor(self): if self._adaptor is not None and not self.is_dirty: pass else: self._adaptor = BRepAdaptor_Surface(self) self._adaptor_handle = BRepAdaptor_HSurface() self._adaptor_handle.Set(self._adaptor) return self._adaptor
def collect_interface(edge, face): surface = BRepAdaptor_Surface(face) curve2d = BRepAdaptor_Curve2d(edge, face) fp = curve2d.FirstParameter() lp = curve2d.LastParameter() return surface, curve2d, fp, lp
def recognize_face(a_face): """ Takes a TopoDS shape and tries to identify its nature whether it is a plane a cylinder a torus etc. if a plane, returns the normal if a cylinder, returns the radius """ if not type(a_face) is TopoDS_Face: print("Please hit the 'G' key to switch to face selection mode") return False surf = BRepAdaptor_Surface(a_face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: print("Identified Plane Geometry") # look for the properties of the plane # first get the related gp_Pln gp_pln = surf.Plane() location = gp_pln.Location() # a point of the plane normal = gp_pln.Axis().Direction() # the plane normal # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Normal (global coordinates)", normal.X(), normal.Y(), normal.Z()) elif surf_type == GeomAbs_Cylinder: print("Identified Cylinder Geometry") # look for the properties of the cylinder # first get the related gp_Cyl gp_cyl = surf.Cylinder() location = gp_cyl.Location() # a point of the axis axis = gp_cyl.Axis().Direction() # the cylinder axis # then export location and normal to the console output print("--> Location (global coordinates)", location.X(), location.Y(), location.Z()) print("--> Axis (global coordinates)", axis.X(), axis.Y(), axis.Z()) elif surf_type == GeomAbs_BSplineSurface: print("Identified BSplineSurface Geometry") #gp_bsrf = surf.Surface() #degree = gp_bsrf.NbUKnots() # TODO use a model that provided BSplineSurfaces, as1_pe_203.stp only contains # planes and cylinders else: # TODO there are plenty other type that can be checked # see documentation for the BRepAdaptor class # https://www.opencascade.com/doc/occt-6.9.1/refman/html/class_b_rep_adaptor___surface.html print(surf_type, "recognition not implemented")
def _unify_faces_array(input): ret = [] fset = {} for i in input: surface = BRep_Tool.Surface(i.Face()) adaptor_surface = BRepAdaptor_Surface(i.Face()) surface_type = adaptor_surface.GetType() if surface_type == GeomAbs_Plane: pln = Geom_Plane.DownCast(surface) pln0 = pln.Pln() found = False for key, arr in fset.items(): pnt = gp_Pnt() key.D0(0, 0, pnt) pln1 = key.Pln() dir0 = pln0.Axis().Direction() dir1 = pln1.Axis().Direction() if (dir0.IsEqual(dir1, 0.00001) and abs(pln0.Distance(pln1.Axis().Location())) < 0.0000001 and abs(pln1.Distance( pln0.Axis().Location())) < 0.0000001): found = True arr.append(i) break if found == False: fset[pln] = [i] else: ret.append(i) continue for key, arr in fset.items(): farr = _union(arr) ret.append(_unify_face(farr)) return ret
def pln_on_face(self, face=TopoDS_Face()): face_adaptor = BRepAdaptor_Surface(face) face_trf = face_adaptor.Trsf() face_pln = face_adaptor.Plane() #face_dir = face_adaptor.Direction() face_umin = face_adaptor.FirstUParameter() face_vmin = face_adaptor.FirstVParameter() face_umax = face_adaptor.LastUParameter() face_vmax = face_adaptor.LastVParameter() face_u = (face_umax + face_umin) / 2 face_v = (face_vmax + face_vmin) / 2 face_pnt = face_adaptor.Value(face_u, face_v) return face_pln
def __extract_faceType(self, a_face): surf = BRepAdaptor_Surface(a_face, True) surf_type = surf.GetType() if surf_type == GeomAbs_Plane: return {'plane': a_face} elif surf_type == GeomAbs_Cylinder: return {'cylinder': a_face} elif surf_type == GeomAbs_Cone: return {'cone': a_face} elif surf_type == GeomAbs_Torus: return {'torus': a_face} elif surf_type == GeomAbs_SurfaceOfExtrusion: return {'surfaceOfExtrusion': a_face} elif surf_type == GeomAbs_SurfaceOfRevolution: return {'surfaceOfRevolution': a_face} elif surf_type == GeomAbs_BSplineSurface: return {'BSplineSurface': a_face} else: print('face type not yet implemented !!!!!!') return {'else': a_face}
def filter_all_step_files(event=None): inputFiles = glob.glob(os.path.join('../resources/step', '*.step')) for inputFile in inputFiles: compound = read_step_file(inputFile) index = 0 for face in TopologyExplorer(compound).faces(): if BRepAdaptor_Surface(face).GetType() == FILTER_TYPE: fileName = os.path.join(OUTPUT_DIR, str(index) + OUTPUT_EXTENSION) os.makedirs(OUTPUT_DIR, exist_ok=True) write_step_file(face, fileName) index += 1
def collect_interface(edge, face): surface = BRepAdaptor_Surface(face) curve2d = BRepAdaptor_Curve2d(edge, face) curve3d = BRepAdaptor_Curve(edge) fp = curve2d.FirstParameter() lp = curve2d.LastParameter() assert fp == curve3d.FirstParameter() assert lp == curve3d.LastParameter() p_length = lp - fp return surface, curve2d, curve3d, fp, lp, p_length
def by_face(cls, face, restrict=True): """ Create by a face. :param afem.topology.entities.Face face: The face. :param bool restrict: Option to restruct the uv-domain of the surface to the boundary of the face. :return: The adaptor surface. :rtype: afem.adaptor.entities.FaceAdaptorSurface """ adp_srf = BRepAdaptor_Surface(face.object, restrict) return cls(adp_srf)
def find_faces(solid): # search the solid for the bottom-most horizontal planes result = defaultdict(list) # downward-facing XY plane d = gp.DZ().Reversed() # loop over all faces (only faces) for f in TopologyExplorer(solid).faces(): surf = BRepAdaptor_Surface(f, True) # skip non-planar faces if surf.GetType() != GeomAbs_Plane: continue # get surface attributes pln = surf.Plane() location = pln.Location() normal = pln.Axis().Direction() # if face is reversed, reverse the surface normal if f.Orientation() == TopAbs_REVERSED: normal.Reverse() # add face if it's parallel (opposite) and coincident with a slicing plane if d.IsEqual(normal, 0.1): result[location.Z()].append(f) # display the face # display.DisplayShape(f, update=True) # display the face normal # display.DisplayVector(gp_Vec(normal), location, update=True) # sort the dict by keys (z-height), and return the lowest lowest = sorted(result.keys())[0] for f in result[lowest]: print( f'z: {lowest}, orientation: {"FORWARD" if f.Orientation() == TopAbs_FORWARD else "REVERSED"}' ) # return all faces associated with the lowest value print(f'number of faces: {len(result[lowest])}') return result[lowest]
def run_beam_face(self, beam0=gp_Ax3(), shpe=TopoDS_Shape(), tr=0): v0 = dir_to_vec(beam0.Direction()) v1 = dir_to_vec(beam0.XDirection()) p0 = beam0.Location() lin = gp_Lin(beam0.Axis()) api = BRepIntCurveSurface_Inter() api.Init(shpe, lin, 1.0E-9) dst = np.inf num = 0 sxy = p0 uvw = [0, 0, 0] fce = None while api.More(): p1 = api.Pnt() dst1 = p0.Distance(p1) if dst1 < dst and api.W() > 1.0E-6: dst = dst1 uvw = [api.U(), api.V(), api.W()] sxy = api.Pnt() fce = api.Face() api.Next() else: api.Next() print(*uvw) u, v, w = uvw surf = BRepAdaptor_Surface(fce) prop = BRepLProp_SLProps(surf, u, v, 2, 1.0E-9) p1, vx, vy = prop.Value(), prop.D1U(), prop.D1V() vz = vx.Crossed(vy) if vz.Dot(v0) > 0: vz.Reverse() vx.Normalize() vy.Normalize() vz.Normalize() beam1 = gp_Ax3(p1, vec_to_dir(v0.Reversed()), vec_to_dir(v1.Reversed())) norm1 = gp_Ax3(p1, vec_to_dir(vz), vec_to_dir(vx)) if tr == 0: beam1.Mirror(norm1.Ax2()) if beam1.Direction().Dot(norm1.Direction()) < 0: beam1.ZReverse() elif tr == 1: beam1.ZReverse() return beam1
def sample_point(face): # randomly choose a point from F u_min, u_max, v_min, v_max = breptools_UVBounds(face) u = random.uniform(u_min, u_max) v = random.uniform(v_min, v_max) itool = IntTools_FClass2d(face, 1e-6) while itool.Perform(gp_Pnt2d(u,v)) != 0: print('outside') u = random.uniform(u_min, u_max) v = random.uniform(v_min, v_max) P = BRepAdaptor_Surface(face).Value(u, v) # the normal surf = BRep_Tool_Surface(face) D = GeomLProp_SLProps(surf,u,v,1,0.01).Normal() if face.Orientation() == TopAbs_REVERSED: D.Reverse() return P, D
def generate_TCP(): global tool_tcp_pnts, tool_tcp_vxs, tool_tcp_vys, tool_tcp_vzs tool_tcp_pnts = [] tool_tcp_vxs = [] tool_tcp_vys = [] tool_tcp_vzs = [] numperface = 1 num1 = round(abs(math.sqrt(numperface))) num2 = round(abs(math.sqrt(numperface))) numofrots = 8 for sur in surf: umin, umax, vmin, vmax = shapeanalysis_GetFaceUVBounds(sur) bsur = BRepAdaptor_Surface(sur, True) for i in range(0, num1 + 1): for j in range(0, num2 + 1): u = umin + i * (umax - umin) / num1 v = vmin + j * (vmax - vmin) / num2 point, Vx, Vy, Vz = get_point(bsur, u, v) flag = 0 for apoint in tool_tcp_pnts: if abs(point.Distance(apoint)) < 0.1: flag = 1 break if flag == 0: for k in range(0, numofrots): ang = 2 * math.pi / numofrots tool_tcp_pnts.append(point) Vx = Vx.Rotated(gp_Ax1(point, gp_Dir(Vz)), ang) tool_tcp_vxs.append(Vx) Vy = Vy.Rotated(gp_Ax1(point, gp_Dir(Vz)), ang) tool_tcp_vys.append(Vy) tool_tcp_vzs.append(Vz) display_coord(tool_tcp_pnts, tool_tcp_vxs, tool_tcp_vys, tool_tcp_vzs) display.DisplayMessage(gp_Pnt(100, 100, 100), 'TCP #:' + str(len(tool_tcp_pnts)), height=None, message_color=(1, 1, 1), update=True)
def selected_shape_info(self): if self.selectMode == 'Face': print(self.shape_selected) surf = BRepAdaptor_Surface(self.shape_selected, True) if surf.GetType() == GeomAbs_Plane: gp_pln = surf.Plane() normal = gp_pln.Axis().Direction() print('plane normal: (%.3f, %.3f, %.3f)' % (normal.X(), normal.Y(), normal.Z())) elif surf.GetType() == GeomAbs_Cylinder: gp_cyl = surf.Cylinder() axis = gp_cyl.Axis().Direction() location = gp_cyl.Location() print('cylinder axis direction: (%.3f, %.3f, %.3f)' % (axis.X(), axis.Y(), axis.Z())) print('cylinder axis location: (%.3f, %.3f, %.3f)' % (location.X(), location.Y(), location.Z())) else: typeList = ['Plane', 'Cylinder', 'Cone', 'Sphere', 'Torus', 'BezierSurface', 'BSplineSurface', 'SurfaceOfRevolution', 'SurfaceOfExtrusion', 'OffsetSurface', 'OtherSurface'] print('This surface type "%s" is not implemented !!' % typeList[surf.GetType()]) elif self.selectMode == 'Edge': print(self.shape_selected) edge = BRepAdaptor_Curve(self.shape_selected) curveType = edge.GetType() if curveType == GeomAbs_Line: gp_lin = edge.Line() direction = gp_lin.Direction() print('Line direction: (%.3f, %.3f, %.3f)' % (direction.X(), direction.Y(), direction.Z())) elif curveType == GeomAbs_Circle: gp_circ = edge.Circle() center = gp_circ.Location() print('Center of circle: (%.3f, %.3f, %.3f)' % (center.X(), center.Y(), center.Z())) print('Radius of circle:', gp_circ.Radius()) else: typeList = ['Line', 'Circle', 'Ellipse', 'Parabola', 'BezierCurve', 'BSplineCurve', 'OffsetCurve or OtherCurve?', 'OtherCurve'] print('This edge type is not implemented !!') print('This surface type "%s" is not implemented !!' % typeList[surf.GetType()])
def sample_interior(face_mesh): vertices, _, _, face = face_mesh additional_vertices = [] surface = BRepAdaptor_Surface(face) FU = surface.FirstUParameter() LU = surface.LastUParameter() FV = surface.FirstVParameter() LV = surface.LastVParameter() U_LENGTH = LU - FU V_LENGTH = LV - FV if INTERIOR_SAMPLING_METHOD == INTERIOR_GRID: for u_index in range(1, GRID_U_SAMPLES + 1): for v_index in range(1, GRID_V_SAMPLES + 1): u_offset = U_OFFSET_FACTOR / (GRID_U_SAMPLES + 1) v_offset = V_OFFSET_FACTOR / (GRID_V_SAMPLES + 1) u = FU + ((u_index / (GRID_U_SAMPLES + 1)) + u_offset) * U_LENGTH v = FV + ((v_index / (GRID_V_SAMPLES + 1)) + v_offset) * V_LENGTH sv_add = SuperVertex(u=u, v=v, same_as=vertices[0]) sv_add.project_to_XYZ() additional_vertices.append(sv_add) elif INTERIOR_SAMPLING_METHOD == INTERIOR_RANDOM: for i in range(RANDOM_SAMPLES): rand0 = random.randint( 1, RANDOM_RESOLUTION - 1) / RANDOM_RESOLUTION rand1 = random.randint( 1, RANDOM_RESOLUTION - 1) / RANDOM_RESOLUTION u = FU + rand0 * U_LENGTH v = FV + rand1 * V_LENGTH sv_add = SuperVertex(u=u, v=v, same_as=vertices[0]) sv_add.project_to_XYZ() additional_vertices.append(sv_add) else: raise Exception( 'sample_interior() error - INTERIOR_SAMPLING_METHOD unknown') return additional_vertices
def makeHelixOnCyl(self): bas = BRepAdaptor_Surface(self.face) cyl = bas.Cylinder() delta_v = bas.LastVParameter() - bas.FirstVParameter() v_final = bas.LastVParameter() dv_du = self.pitch / (2*pi) l = delta_v / sin(atan(dv_du)) aLine2d = gp_Lin2d(gp_Pnt2d(bas.FirstUParameter(),bas.FirstVParameter()), gp_Dir2d(1,dv_du)) if not self.reverse_helix: aSegment = GCE2d_MakeSegment(aLine2d, 0.0, l) else: aSegment = GCE2d_MakeSegment(aLine2d, l, 0.0) helix_edge = BRepBuilderAPI_MakeEdge(aSegment.Value(), Geom_CylindricalSurface(cyl)).Edge() #self.aLine2d = aLine2d #self.aSegment = aSegment self.helix_edge = helix_edge return helix_edge
def geom_plane_from_face(aFace): """ Returns the geometric plane entity from a planar surface """ return BRepAdaptor_Surface(aFace, True).Plane()
def AdaptorSurface(self): assert(self.is_face()) return BRepAdaptor_Surface(self.Face())
def get_face_type(self, index): _, _, _, face = self.face_meshes[index] return SURFACE_TYPE_STRINGS[BRepAdaptor_Surface(face).GetType()]
def reverse_u(u, face): last_u_parameter = BRepAdaptor_Surface(face).LastUParameter() return last_u_parameter - u