wiki:occt

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 v klicanju metod.

Primer kocke, ki je lahko poženemo v urejevalniku pycharm na strežiku viz.hpc.fs.uni-lj.si.

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:

from OCC.TodoDS import topods_Edge

Med tem ko v PythonOCCT so statične funkcije znotraj razredov in imajo na koncu še podčrtaj

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

handle_geom = line.Copy()
new_line = Handle_Geom_Line.Downcast(handle_geom).GetObject()

V PythonOCCT

new_line = line.Copy()

To naredi stvari precej pitonične, saj lahko direktno ugotovimo tip geometrije z uporabo python metode isinstance:

# 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
# 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 MakeBottleCAD(C++). Za vizualizacijo se uporablja SALOME-8.5.0, ki se ga požene z ukayom smiter

Prikaz geometrije BottleCAD

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

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.

Last modified 15 months ago Last modified on Nov 23, 2018, 9:12:00 AM

Attachments (1)

Download all attachments as: .zip