| 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 | }}} |