== Uporaba modula PythonOCCT == Projekt **PythonOCCT** je še ena priredba knjižnice OpenCASCADE 7.2.0 za programiranje v jeziku Python in je na voljo na strani https://github.com/LaughlinResearch/pyOCCT Od PythonOCC-ja se razlikuje v verziji OpenCASCADE in [https://pyocct.readthedocs.io/en/latest/dev.html v klicanju metod]. Primer kocke, ki je lahko poženemo v urejevalniku {{{pycharm}}} na strežiku viz.hpc.fs.uni-lj.si. {{{ #!python from OCCT.Visualization import BasicViewer from OCCT.BRepPrimAPI import BRepPrimAPI_MakeBox from OCCT.Graphic3d import Graphic3d_NOM_ALUMINIUM v = BasicViewer() v.set_white_background() shape = BRepPrimAPI_MakeBox(10, 20, 30).Shape() v.display_shape(shape, rgb=(0.8, 0.8, 0.5), material=Graphic3d_NOM_ALUMINIUM) v.start() }}} Statične funkcije se v **PythonOCC** uvozijo kar na modularnem nivoju: {{{#!python from OCC.TodoDS import topods_Edge }}} Med tem ko v PythonOCCT so statične funkcije znotraj razredov in imajo na koncu še podčrtaj {{{#!python from OCCT.TopoDS import TopoDS edge = TopoDS.Edge_(shape) }}} Prav tako se v PythonOCCT ne uporablja več metod **GetHandle**, **Downcast** in **GetObject**, ker se že v kodi PythonOCCT vse avtomatsko to naredi: V **PythonOCC** {{{#!python handle_geom = line.Copy() new_line = Handle_Geom_Line.Downcast(handle_geom).GetObject() }}} V **PythonOCCT** {{{#!python new_line = line.Copy() }}} To naredi stvari precej pitonične, saj lahko direktno ugotovimo tip geometrije z uporabo python metode **isinstance**: {{{#!python # S pomočjo PythonOCC-ja preverimo če je TopoDS_Shape Geom_Plane. hs = BRep_Tool_Surface(face) downcast_result = Geom_Plane.DownCast(hs) # Če je downcast_result tipa None, spremenljivka face ni Geom_Plane. if downcast_result is None: return False else: return True }}} {{{#!python # S pomočjo PythonOCCT-ja preverimo če je TopoDS_Shape Geom_Plane. hs = BRep_Tool_Surface(face) if isinstance(hs, Geom_Plane): return True else: return False }}} === Izdelava primera Bottle z uporabo programskega jezika Python in knjižnice OCCT === Naslednji primer prikazuje izdelavo primera BottleCAD. Podrobnejši razdelek posameznih delov programske kode dobimo na [[http://trac.lecad.si/vaje/wiki/OpenCascade|MakeBottleCAD(C++)]]. Za vizualizacijo se uporablja SALOME-8.5.0, ki se ga požene z ukayom {{{smiter}}} [[Image(bottle.png, right)]] {{{ #!python ##Uredil in posodobil 2018 Gregor Simic (gregor.simic@lecad.fs.uni-lj.si) import math # from OCCT.gp import gp_Pnt, gp_OX, gp_Vec, gp_Trsf, gp_DZ, gp_Ax2, gp_Ax3, gp_Pnt2d, gp_Dir2d, gp_Ax2d from OCCT.gp import gp_Pnt, gp, gp_Vec, gp_Trsf, gp_Ax2, gp_Ax3, gp_Pnt2d, gp_Dir2d, gp_Ax2d # Classes gp_OX, gp_DZ are statical methods and in OCCT stored inside # OCCT.gp.gp as OX_ and DZ_ respectively. from OCCT.GC import GC_MakeArcOfCircle, GC_MakeSegment from OCCT.GCE2d import GCE2d_MakeSegment from OCCT.Geom import Geom_Plane, Geom_CylindricalSurface, Geom_Surface from OCCT.Geom2d import Geom2d_Ellipse, Geom2d_TrimmedCurve, Geom2d_Ellipse, Geom2d_Curve from OCCT.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace, \ BRepBuilderAPI_Transform from OCCT.BRepPrimAPI import BRepPrimAPI_MakePrism, BRepPrimAPI_MakeCylinder from OCCT.BRepFilletAPI import BRepFilletAPI_MakeFillet from OCCT.BRepAlgoAPI import BRepAlgoAPI_Fuse from OCCT.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid, BRepOffsetAPI_ThruSections # from OCC.Core.BRepLib import breplib # In OCCT the modules preserve the case. from OCCT.BRepLib import BRepLib # from OCC.Core.BRep import BRep_Tool_Surface, BRep_Builder from OCCT.BRep import BRep_Tool, BRep_Builder # OCCT does not have OCCT.Core but rather all modules are accessed directly # from OCCT. Again BRep_Tool_Surface from OCC is a static method to create # a Surface, hence in OCCT it is called from BRep_Tools as Surface_ from OCCT.TopoDS import TopoDS, TopoDS_Edge, TopoDS_Compound from OCCT.TopExp import TopExp_Explorer from OCCT.TopAbs import TopAbs_EDGE, TopAbs_FACE from OCCT.TopTools import TopTools_ListOfShape def face_is_plane(face): """ Returns True if the TopoDS_Shape is a Geom_Plane, False otherwise. """ hs = BRep_Tool.Surface_(face) # downcast_result = Geom_Plane.DownCast(hs) # OCCT 7.2.0 does not have the DownCast function anymore, in this case # we use we simply use the isinstance method to check if the shape # is a Geom_Plane. if isinstance(hs, Geom_Plane): return True else: # Othe cases when it returns false are, Geom_CylindricalSurface, # Geom_ToroidalSurface, Geom_SphericalSurface return False def geom_plane_from_face(aFace): """ Returns the geometric plane entity from a planar surface """ # return Geom_Plane.DownCast(BRep_Tool.Surface_(aFace)) return BRep_Tool.Surface_(aFace).Pln() height = 70 width = 50 thickness = 30 print("creating bottle") # The points we'll use to create the profile of the bottle's body aPnt1 = gp_Pnt(-width / 2.0, 0, 0) aPnt2 = gp_Pnt(-width / 2.0, -thickness / 4.0, 0) aPnt3 = gp_Pnt(0, -thickness / 2.0, 0) aPnt4 = gp_Pnt(width / 2.0, -thickness / 4.0, 0) aPnt5 = gp_Pnt(width / 2.0, 0, 0) aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4) aSegment1 = GC_MakeSegment(aPnt1, aPnt2) aSegment2 = GC_MakeSegment(aPnt4, aPnt5) # Could also construct the line edges directly using the points instead of the resulting line aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value()) aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value()) aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value()) # Create a wire out of the edges aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge()) # Quick way to specify the X axis # xAxis = gp_OX() # From OCC xAxis = gp.OX_() # Set up the mirror aTrsf = gp_Trsf() aTrsf.SetMirror(xAxis) # Apply the mirror transformation aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf) # Get the mirrored shape back out of the transformation and convert back to a wire aMirroredShape = aBRespTrsf.Shape() # A wire instead of a generic shape now # aMirroredWire = topods.Wire(aMirroredShape) # From OCC aMirroredWire = TopoDS.Wire_(aMirroredShape) # Combine the two constituent wires mkWire = BRepBuilderAPI_MakeWire() mkWire.Add(aWire.Wire()) mkWire.Add(aMirroredWire) myWireProfile = mkWire.Wire() # The face that we'll sweep to make the prism myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile) # We want to sweep the face along the Z axis to the height aPrismVec = gp_Vec(0, 0, height) myBody = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec) # Add fillets to all edges through the explorer mkFillet = BRepFilletAPI_MakeFillet(myBody.Shape()) anEdgeExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_EDGE) while anEdgeExplorer.More(): anEdge = TopoDS.Edge_(anEdgeExplorer.Current()) mkFillet.Add(thickness / 12.0, anEdge) anEdgeExplorer.Next() myBody = mkFillet # Create the neck of the bottle neckLocation = gp_Pnt(0, 0, height) # neckAxis = gp_DZ() # From OCC neckAxis = gp.DZ_() neckAx2 = gp_Ax2(neckLocation, neckAxis) myNeckRadius = thickness / 4.0 myNeckHeight = height / 10.0 mkCylinder = BRepPrimAPI_MakeCylinder(neckAx2, myNeckRadius, myNeckHeight) myBody = BRepAlgoAPI_Fuse(myBody.Shape(), mkCylinder.Shape()) # Our goal is to find the highest Z face and remove it faceToRemove = None zMax = -1 # We have to work our way through all the faces to find the highest Z face so we can remove it for the shell aFaceExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_FACE) while aFaceExplorer.More(): # aFace = topods.Face(aFaceExplorer.Current()) # From OCC aFace = TopoDS.Face_(aFaceExplorer.Current()) if face_is_plane(aFace): aPlane = geom_plane_from_face(aFace) # We want the highest Z face, so compare this to the previous faces aPnt = aPlane.Location() aZ = aPnt.Z() if aZ > zMax: zMax = aZ faceToRemove = aFace aFaceExplorer.Next() facesToRemove = TopTools_ListOfShape() facesToRemove.Append(faceToRemove) myBody = BRepOffsetAPI_MakeThickSolid(myBody.Shape(), facesToRemove, -thickness / 50.0, 0.001) # Set up our surfaces for the threading on the neck neckAx2_Ax3 = gp_Ax3(neckLocation, gp.DZ_()) aCyl1 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 0.99) aCyl2 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 1.05) # Set up the curves for the threads on the bottle's neck aPnt = gp_Pnt2d(2.0 * math.pi, myNeckHeight / 2.0) aDir = gp_Dir2d(2.0 * math.pi, myNeckHeight / 4.0) anAx2d = gp_Ax2d(aPnt, aDir) aMajor = 2.0 * math.pi aMinor = myNeckHeight / 10.0 anEllipse1 = Geom2d_Ellipse(anAx2d, aMajor, aMinor) anEllipse2 = Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4.0) anArc1 = Geom2d_TrimmedCurve(anEllipse1, 0, math.pi) anArc2 = Geom2d_TrimmedCurve(anEllipse2, 0, math.pi) anEllipsePnt1 = anEllipse1.Value(0) anEllipsePnt2 = anEllipse1.Value(math.pi) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2) # Build edges and wires for threading anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1) anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl1) anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2) anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl2) threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1.Edge(), anEdge2OnSurf1.Edge()) threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2.Edge(), anEdge2OnSurf2.Edge()) # Compute the 3D representations of the edges/wires # breplib.BuildCurves3d(threadingWire1.Shape()) # From OCC # breplib.BuildCurves3d(threadingWire2.Shape()) # From OCC BRepLib.BuildCurves3d_(threadingWire1.Shape()) BRepLib.BuildCurves3d_(threadingWire2.Shape()) # Create the surfaces of the threading aTool = BRepOffsetAPI_ThruSections(True) aTool.AddWire(threadingWire1.Wire()) aTool.AddWire(threadingWire2.Wire()) aTool.CheckCompatibility(False) myThreading = aTool.Shape() # Build the resulting compound bottle = TopoDS_Compound() aBuilder = BRep_Builder() aBuilder.MakeCompound(bottle) aBuilder.Add(bottle, myBody.Shape()) aBuilder.Add(bottle, myThreading) print("bottle finished") # if __name__ == "__main__": # from OCC.Display.SimpleGui import init_display # display, start_display, add_menu, add_function_to_menu = init_display() # display.DisplayColoredShape(bottle, update=True) # start_display() # Display in GEOM from GEOM_OCCT import fromPythonOCCT fromPythonOCCT(bottle, 'bottle') }}} Zadnji dve vrstici preneseta geometrijski model v Geometry modul okolja SALOME. Funkcije GEOM_OCCT so razvite v LECAD-u in so del paketa SMITER. Če v Python konzoli okolja SALOME odtipkate {{{ #!python import GEOM_OCCT help(GEOM_OCCT) }}} dobite celotno pomoč in razlago komplementarne funkcije {{{toPythonOCCT}}}, ki se uporablja za prenos modela iz module Geometry v OCCT. Python konzola s pritiskom tipke TAB tudi pokaže pomoč. Okolje SALOME ima tudi vgrajen urejevalnik Python skript, ki ga dobite z tipko Alt+Y. Skripto poženete iz menija File ali tipko Ctrl+T ter ponovite ukaz s gornjo smerno tipko v Python konzoli.