| | 1 | == Uporaba modula PythonOCCT == |
| | 2 | |
| | 3 | Projekt **PythonOCCT** je še ena priredba knjižnice OpenCASCADE 7.2.0 za programiranje v jeziku Python. |
| | 4 | Od PythonOCC-ja se razlikuje v verziji OpenCASCADE in v klicanju metod. |
| | 5 | |
| | 6 | Statične funkcije se v **PythonOCC** uvozijo kar na modularnem nivoju: |
| | 7 | |
| | 8 | {{{#!python |
| | 9 | from OCC.TodoDS import topods_Edge |
| | 10 | }}} |
| | 11 | |
| | 12 | Med tem ko v PythonOCCT so statične funkcije znotraj razredov in imajo na koncu še podčrtaj |
| | 13 | |
| | 14 | {{{#!python |
| | 15 | from OCCT.TopoDS import TopoDS |
| | 16 | edge = TopoDS.Edge_(shape) |
| | 17 | }}} |
| | 18 | |
| | 19 | Prav tako se v PythonOCCT ne uporablja več metod **GetHandle**, **Downcast** in **GetObject**, ker se že v kodi PythonOCCT vse avtomatsko to naredi: |
| | 20 | |
| | 21 | V **PythonOCC** |
| | 22 | {{{#!python |
| | 23 | handle_geom = line.Copy() |
| | 24 | new_line = Handle_Geom_Line.Downcast(handle_geom).GetObject() |
| | 25 | }}} |
| | 26 | |
| | 27 | V **PythonOCCT** |
| | 28 | {{{#!python |
| | 29 | new_line = line.Copy() |
| | 30 | }}} |
| | 31 | |
| | 32 | To naredi stvari precej pitonične, saj lahko direktno ugotovimo tip geometrije z uporabo python metode **isinstance**: |
| | 33 | |
| | 34 | {{{#!python |
| | 35 | # S pomočjo PythonOCC-ja preverimo če je TopoDS_Shape Geom_Plane. |
| | 36 | hs = BRep_Tool_Surface(face) |
| | 37 | downcast_result = Geom_Plane.DownCast(hs) |
| | 38 | # Če je downcast_result tipa None, spremenljivka face ni Geom_Plane. |
| | 39 | if downcast_result is None: |
| | 40 | return False |
| | 41 | else: |
| | 42 | return True |
| | 43 | }}} |
| | 44 | |
| | 45 | |
| | 46 | {{{#!python |
| | 47 | # S pomočjo PythonOCCT-ja preverimo če je TopoDS_Shape Geom_Plane. |
| | 48 | hs = BRep_Tool_Surface(face) |
| | 49 | if isinstance(hs, Geom_Plane): |
| | 50 | return True |
| | 51 | else: |
| | 52 | return False |
| | 53 | }}} |
| | 54 | |
| | 55 | === Izdelava primera Bottle z uporabo programskega jezika Python in knjižnice OCCT === |
| | 56 | 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 |
| | 57 | |
| | 58 | [[Image(bottle.png, width=480px, right)]] |
| | 59 | {{{ |
| | 60 | #!python |
| | 61 | ##Uredil in posodobil 2018 Gregor Simič (gregor.simic@lecad.fs.uni-lj.si) |
| | 62 | import math |
| | 63 | |
| | 64 | # from OCCT.gp import gp_Pnt, gp_OX, gp_Vec, gp_Trsf, gp_DZ, gp_Ax2, gp_Ax3, gp_Pnt2d, gp_Dir2d, gp_Ax2d |
| | 65 | from OCCT.gp import gp_Pnt, gp, gp_Vec, gp_Trsf, gp_Ax2, gp_Ax3, gp_Pnt2d, gp_Dir2d, gp_Ax2d |
| | 66 | # Classes gp_OX, gp_DZ are statical methods and in OCCT stored inside |
| | 67 | # OCCT.gp.gp as OX_ and DZ_ respectively. |
| | 68 | |
| | 69 | from OCCT.GC import GC_MakeArcOfCircle, GC_MakeSegment |
| | 70 | from OCCT.GCE2d import GCE2d_MakeSegment |
| | 71 | from OCCT.Geom import Geom_Plane, Geom_CylindricalSurface, Geom_Surface |
| | 72 | from OCCT.Geom2d import Geom2d_Ellipse, Geom2d_TrimmedCurve, Geom2d_Ellipse, Geom2d_Curve |
| | 73 | from OCCT.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace, \ |
| | 74 | BRepBuilderAPI_Transform |
| | 75 | from OCCT.BRepPrimAPI import BRepPrimAPI_MakePrism, BRepPrimAPI_MakeCylinder |
| | 76 | from OCCT.BRepFilletAPI import BRepFilletAPI_MakeFillet |
| | 77 | from OCCT.BRepAlgoAPI import BRepAlgoAPI_Fuse |
| | 78 | from OCCT.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid, BRepOffsetAPI_ThruSections |
| | 79 | |
| | 80 | # from OCC.Core.BRepLib import breplib |
| | 81 | # In OCCT the modules preserve the case. |
| | 82 | from OCCT.BRepLib import BRepLib |
| | 83 | |
| | 84 | # from OCC.Core.BRep import BRep_Tool_Surface, BRep_Builder |
| | 85 | from OCCT.BRep import BRep_Tool, BRep_Builder |
| | 86 | # OCCT does not have OCCT.Core but rather all modules are accessed directly |
| | 87 | # from OCCT. Again BRep_Tool_Surface from OCC is a static method to create |
| | 88 | # a Surface, hence in OCCT it is called from BRep_Tools as Surface_ |
| | 89 | |
| | 90 | from OCCT.TopoDS import TopoDS, TopoDS_Edge, TopoDS_Compound |
| | 91 | from OCCT.TopExp import TopExp_Explorer |
| | 92 | from OCCT.TopAbs import TopAbs_EDGE, TopAbs_FACE |
| | 93 | from OCCT.TopTools import TopTools_ListOfShape |
| | 94 | |
| | 95 | def face_is_plane(face): |
| | 96 | """ |
| | 97 | Returns True if the TopoDS_Shape is a Geom_Plane, False otherwise. |
| | 98 | """ |
| | 99 | hs = BRep_Tool.Surface_(face) |
| | 100 | # downcast_result = Geom_Plane.DownCast(hs) |
| | 101 | # OCCT 7.2.0 does not have the DownCast function anymore, in this case |
| | 102 | # we use we simply use the isinstance method to check if the shape |
| | 103 | # is a Geom_Plane. |
| | 104 | if isinstance(hs, Geom_Plane): |
| | 105 | return True |
| | 106 | else: |
| | 107 | # Othe cases when it returns false are, Geom_CylindricalSurface, |
| | 108 | # Geom_ToroidalSurface, Geom_SphericalSurface |
| | 109 | return False |
| | 110 | |
| | 111 | |
| | 112 | def geom_plane_from_face(aFace): |
| | 113 | """ |
| | 114 | Returns the geometric plane entity from a planar surface |
| | 115 | """ |
| | 116 | # return Geom_Plane.DownCast(BRep_Tool.Surface_(aFace)) |
| | 117 | return BRep_Tool.Surface_(aFace).Pln() |
| | 118 | |
| | 119 | |
| | 120 | height = 70 |
| | 121 | width = 50 |
| | 122 | thickness = 30 |
| | 123 | |
| | 124 | print("creating bottle") |
| | 125 | # The points we'll use to create the profile of the bottle's body |
| | 126 | aPnt1 = gp_Pnt(-width / 2.0, 0, 0) |
| | 127 | aPnt2 = gp_Pnt(-width / 2.0, -thickness / 4.0, 0) |
| | 128 | aPnt3 = gp_Pnt(0, -thickness / 2.0, 0) |
| | 129 | aPnt4 = gp_Pnt(width / 2.0, -thickness / 4.0, 0) |
| | 130 | aPnt5 = gp_Pnt(width / 2.0, 0, 0) |
| | 131 | |
| | 132 | aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4) |
| | 133 | aSegment1 = GC_MakeSegment(aPnt1, aPnt2) |
| | 134 | aSegment2 = GC_MakeSegment(aPnt4, aPnt5) |
| | 135 | |
| | 136 | # Could also construct the line edges directly using the points instead of the resulting line |
| | 137 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value()) |
| | 138 | aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value()) |
| | 139 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value()) |
| | 140 | |
| | 141 | # Create a wire out of the edges |
| | 142 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge()) |
| | 143 | |
| | 144 | # Quick way to specify the X axis |
| | 145 | # xAxis = gp_OX() # From OCC |
| | 146 | xAxis = gp.OX_() |
| | 147 | |
| | 148 | # Set up the mirror |
| | 149 | aTrsf = gp_Trsf() |
| | 150 | aTrsf.SetMirror(xAxis) |
| | 151 | |
| | 152 | # Apply the mirror transformation |
| | 153 | aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf) |
| | 154 | |
| | 155 | # Get the mirrored shape back out of the transformation and convert back to a wire |
| | 156 | aMirroredShape = aBRespTrsf.Shape() |
| | 157 | |
| | 158 | # A wire instead of a generic shape now |
| | 159 | # aMirroredWire = topods.Wire(aMirroredShape) # From OCC |
| | 160 | aMirroredWire = TopoDS.Wire_(aMirroredShape) |
| | 161 | |
| | 162 | # Combine the two constituent wires |
| | 163 | mkWire = BRepBuilderAPI_MakeWire() |
| | 164 | mkWire.Add(aWire.Wire()) |
| | 165 | mkWire.Add(aMirroredWire) |
| | 166 | myWireProfile = mkWire.Wire() |
| | 167 | |
| | 168 | # The face that we'll sweep to make the prism |
| | 169 | myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile) |
| | 170 | |
| | 171 | # We want to sweep the face along the Z axis to the height |
| | 172 | aPrismVec = gp_Vec(0, 0, height) |
| | 173 | myBody = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec) |
| | 174 | |
| | 175 | # Add fillets to all edges through the explorer |
| | 176 | mkFillet = BRepFilletAPI_MakeFillet(myBody.Shape()) |
| | 177 | anEdgeExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_EDGE) |
| | 178 | |
| | 179 | while anEdgeExplorer.More(): |
| | 180 | anEdge = TopoDS.Edge_(anEdgeExplorer.Current()) |
| | 181 | mkFillet.Add(thickness / 12.0, anEdge) |
| | 182 | |
| | 183 | anEdgeExplorer.Next() |
| | 184 | |
| | 185 | myBody = mkFillet |
| | 186 | |
| | 187 | # Create the neck of the bottle |
| | 188 | neckLocation = gp_Pnt(0, 0, height) |
| | 189 | # neckAxis = gp_DZ() # From OCC |
| | 190 | neckAxis = gp.DZ_() |
| | 191 | neckAx2 = gp_Ax2(neckLocation, neckAxis) |
| | 192 | |
| | 193 | myNeckRadius = thickness / 4.0 |
| | 194 | myNeckHeight = height / 10.0 |
| | 195 | |
| | 196 | mkCylinder = BRepPrimAPI_MakeCylinder(neckAx2, myNeckRadius, myNeckHeight) |
| | 197 | |
| | 198 | myBody = BRepAlgoAPI_Fuse(myBody.Shape(), mkCylinder.Shape()) |
| | 199 | |
| | 200 | # Our goal is to find the highest Z face and remove it |
| | 201 | faceToRemove = None |
| | 202 | zMax = -1 |
| | 203 | |
| | 204 | # We have to work our way through all the faces to find the highest Z face so we can remove it for the shell |
| | 205 | aFaceExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_FACE) |
| | 206 | while aFaceExplorer.More(): |
| | 207 | # aFace = topods.Face(aFaceExplorer.Current()) # From OCC |
| | 208 | aFace = TopoDS.Face_(aFaceExplorer.Current()) |
| | 209 | |
| | 210 | if face_is_plane(aFace): |
| | 211 | aPlane = geom_plane_from_face(aFace) |
| | 212 | |
| | 213 | # We want the highest Z face, so compare this to the previous faces |
| | 214 | aPnt = aPlane.Location() |
| | 215 | aZ = aPnt.Z() |
| | 216 | if aZ > zMax: |
| | 217 | zMax = aZ |
| | 218 | faceToRemove = aFace |
| | 219 | |
| | 220 | aFaceExplorer.Next() |
| | 221 | |
| | 222 | facesToRemove = TopTools_ListOfShape() |
| | 223 | facesToRemove.Append(faceToRemove) |
| | 224 | |
| | 225 | myBody = BRepOffsetAPI_MakeThickSolid(myBody.Shape(), facesToRemove, -thickness / 50.0, 0.001) |
| | 226 | |
| | 227 | # Set up our surfaces for the threading on the neck |
| | 228 | neckAx2_Ax3 = gp_Ax3(neckLocation, gp.DZ_()) |
| | 229 | aCyl1 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 0.99) |
| | 230 | aCyl2 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 1.05) |
| | 231 | |
| | 232 | # Set up the curves for the threads on the bottle's neck |
| | 233 | aPnt = gp_Pnt2d(2.0 * math.pi, myNeckHeight / 2.0) |
| | 234 | aDir = gp_Dir2d(2.0 * math.pi, myNeckHeight / 4.0) |
| | 235 | anAx2d = gp_Ax2d(aPnt, aDir) |
| | 236 | |
| | 237 | aMajor = 2.0 * math.pi |
| | 238 | aMinor = myNeckHeight / 10.0 |
| | 239 | |
| | 240 | anEllipse1 = Geom2d_Ellipse(anAx2d, aMajor, aMinor) |
| | 241 | anEllipse2 = Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4.0) |
| | 242 | |
| | 243 | anArc1 = Geom2d_TrimmedCurve(anEllipse1, 0, math.pi) |
| | 244 | anArc2 = Geom2d_TrimmedCurve(anEllipse2, 0, math.pi) |
| | 245 | |
| | 246 | anEllipsePnt1 = anEllipse1.Value(0) |
| | 247 | anEllipsePnt2 = anEllipse1.Value(math.pi) |
| | 248 | |
| | 249 | aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2) |
| | 250 | |
| | 251 | # Build edges and wires for threading |
| | 252 | anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1) |
| | 253 | anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl1) |
| | 254 | anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2) |
| | 255 | anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl2) |
| | 256 | |
| | 257 | threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1.Edge(), anEdge2OnSurf1.Edge()) |
| | 258 | threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2.Edge(), anEdge2OnSurf2.Edge()) |
| | 259 | |
| | 260 | # Compute the 3D representations of the edges/wires |
| | 261 | # breplib.BuildCurves3d(threadingWire1.Shape()) # From OCC |
| | 262 | # breplib.BuildCurves3d(threadingWire2.Shape()) # From OCC |
| | 263 | BRepLib.BuildCurves3d_(threadingWire1.Shape()) |
| | 264 | BRepLib.BuildCurves3d_(threadingWire2.Shape()) |
| | 265 | |
| | 266 | # Create the surfaces of the threading |
| | 267 | aTool = BRepOffsetAPI_ThruSections(True) |
| | 268 | aTool.AddWire(threadingWire1.Wire()) |
| | 269 | aTool.AddWire(threadingWire2.Wire()) |
| | 270 | aTool.CheckCompatibility(False) |
| | 271 | myThreading = aTool.Shape() |
| | 272 | |
| | 273 | # Build the resulting compound |
| | 274 | bottle = TopoDS_Compound() |
| | 275 | aBuilder = BRep_Builder() |
| | 276 | aBuilder.MakeCompound(bottle) |
| | 277 | aBuilder.Add(bottle, myBody.Shape()) |
| | 278 | aBuilder.Add(bottle, myThreading) |
| | 279 | print("bottle finished") |
| | 280 | |
| | 281 | # if __name__ == "__main__": |
| | 282 | # from OCC.Display.SimpleGui import init_display |
| | 283 | # display, start_display, add_menu, add_function_to_menu = init_display() |
| | 284 | # display.DisplayColoredShape(bottle, update=True) |
| | 285 | # start_display() |
| | 286 | |
| | 287 | # Display in GEOM |
| | 288 | from GEOM_OCCT import fromPythonOCCT |
| | 289 | fromPythonOCCT(bottle, 'bottle') |
| | 290 | }}} |