pythonOCC官方demo:链轮建模

旋转、移动、镜像

官方案例展示

core_modeling_sprocket.py:

import sys
from math import pi as M_PI, sin, cos, atan

from OCC.Core.gp import (
    gp_Pnt2d,
    gp_Ax2d,
    gp_Dir2d,
    gp_Circ2d,
    gp_Origin2d,
    gp_DX2d,
    gp_Ax2,
    gp_OX2d,
    gp_Lin2d,
    gp_Trsf,
    gp_XOY,
    gp_Pnt,
    gp_Vec,
    gp_Ax3,
    gp_Pln,
    gp_Origin,
    gp_DX,
    gp_DY,
    gp_DZ,
    gp_OZ,
)
from OCC.Core.GCE2d import GCE2d_MakeArcOfCircle, GCE2d_MakeCircle, GCE2d_MakeLine
from OCC.Core.Geom2dAPI import Geom2dAPI_InterCurveCurve
from OCC.Core.Geom2d import Geom2d_TrimmedCurve
from OCC.Core.GeomAPI import geomapi_To3d
from OCC.Core.BRepBuilderAPI import (
    BRepBuilderAPI_MakeEdge,
    BRepBuilderAPI_MakeWire,
    BRepBuilderAPI_MakeFace,
    BRepBuilderAPI_Transform,
)
from OCC.Core.BRepPrimAPI import (
    BRepPrimAPI_MakePrism,
    BRepPrimAPI_MakeRevol,
    BRepPrimAPI_MakeCylinder,
    BRepPrimAPI_MakeCone,
)
from OCC.Core.GccAna import GccAna_Circ2d2TanRad
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut, BRepAlgoAPI_Fuse
from OCC.Core.BRepFilletAPI import BRepFilletAPI_MakeFillet2d
from OCC.Core.BRepTools import BRepTools_WireExplorer
from OCC.Display.SimpleGui import init_display

roller_diameter = 10.2
pitch = 15.875
num_teeth = 40
chain_width = 6.35

#  Dimensions derived from the provided inputs
roller_radius = roller_diameter / 2.0
tooth_angle = (2 * M_PI) / num_teeth
pitch_circle_diameter = pitch / sin(tooth_angle / 2.0)
pitch_circle_radius = pitch_circle_diameter / 2.0

roller_contact_angle_min = (M_PI * 120 / 180) - ((M_PI / 2.0) / num_teeth)
roller_contact_angle_max = (M_PI * 140 / 180) - ((M_PI / 2.0) / num_teeth)
roller_contact_angle = (roller_contact_angle_min + roller_contact_angle_max) / 2.0

tooth_radius_min = 0.505 * roller_diameter
tooth_radius_max = tooth_radius_min + (0.069 * pow(roller_diameter, 1.0 / 3.0))
tooth_radius = (tooth_radius_min + tooth_radius_max) / 2.0

profile_radius = 0.12 * roller_diameter * (num_teeth + 2)
top_diameter = (
    pitch_circle_diameter + ((1 - (1.6 / num_teeth)) * pitch) - roller_diameter
)
top_radius = top_diameter / 2.0

thickness = chain_width * 0.95

# Center hole data
center_radius = 125.0 / 2.0

# Mounting hole data
mounting_hole_count = 6
mounting_radius = 153.0 / 2.0
hole_radius = 8.5 / 2.0


def build_tooth():
    base_center = gp_Pnt2d(pitch_circle_radius + (tooth_radius - roller_radius), 0)
    base_circle = gp_Circ2d(gp_Ax2d(base_center, gp_Dir2d()), tooth_radius)
    trimmed_base = GCE2d_MakeArcOfCircle(
        base_circle, M_PI - (roller_contact_angle / 2.0), M_PI
    ).Value()
    trimmed_base.Reverse()  # just a trick
    p0 = trimmed_base.StartPoint()
    p1 = trimmed_base.EndPoint()

    # Determine the center of the profile circle
    x_distance = cos(roller_contact_angle / 2.0) * (profile_radius + tooth_radius)
    y_distance = sin(roller_contact_angle / 2.0) * (profile_radius + tooth_radius)
    profile_center = gp_Pnt2d(pitch_circle_radius - x_distance, y_distance)

    # Construct the profile circle gp_Circ2d
    profile_circle = gp_Circ2d(
        gp_Ax2d(profile_center, gp_Dir2d()), profile_center.Distance(p1)
    )
    geom_profile_circle = GCE2d_MakeCircle(profile_circle).Value()

    # Construct the outer circle gp_Circ2d
    outer_circle = gp_Circ2d(gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d()), top_radius)
    geom_outer_circle = GCE2d_MakeCircle(outer_circle).Value()

    inter = Geom2dAPI_InterCurveCurve(geom_profile_circle, geom_outer_circle)
    num_points = inter.NbPoints()
    assert isinstance(p1, gp_Pnt2d)
    if num_points == 2:
        if p1.Distance(inter.Point(1)) < p1.Distance(inter.Point(2)):
            p2 = inter.Point(1)
        else:
            p2 = inter.Point(2)
    elif num_points == 1:
        p2 = inter.Point(1)
    else:
        sys.exit(-1)

    # Trim the profile circle and mirror
    trimmed_profile = GCE2d_MakeArcOfCircle(profile_circle, p1, p2).Value()

    # Calculate the outermost point
    p3 = gp_Pnt2d(
        cos(tooth_angle / 2.0) * top_radius, sin(tooth_angle / 2.0) * top_radius
    )

    # and use it to create the third arc
    trimmed_outer = GCE2d_MakeArcOfCircle(outer_circle, p2, p3).Value()

    # Mirror and reverse the three arcs
    mirror_axis = gp_Ax2d(gp_Origin2d(), gp_DX2d().Rotated(tooth_angle / 2.0))

    mirror_base = Geom2d_TrimmedCurve.DownCast(trimmed_base.Copy())
    mirror_profile = Geom2d_TrimmedCurve.DownCast(trimmed_profile.Copy())
    mirror_outer = Geom2d_TrimmedCurve.DownCast(trimmed_outer.Copy())

    mirror_base.Mirror(mirror_axis)
    mirror_profile.Mirror(mirror_axis)
    mirror_outer.Mirror(mirror_axis)

    mirror_base.Reverse()
    mirror_profile.Reverse()
    mirror_outer.Reverse()

    # Replace the two outer arcs with a single one
    outer_start = trimmed_outer.StartPoint()
    outer_mid = trimmed_outer.EndPoint()
    outer_end = mirror_outer.EndPoint()

    outer_arc = GCE2d_MakeArcOfCircle(outer_start, outer_mid, outer_end).Value()

    # Create an arc for the inside of the wedge
    inner_circle = gp_Circ2d(
        gp_Ax2d(gp_Pnt2d(0, 0), gp_Dir2d()), top_radius - roller_diameter
    )
    inner_start = gp_Pnt2d(top_radius - roller_diameter, 0)
    inner_arc = GCE2d_MakeArcOfCircle(inner_circle, inner_start, tooth_angle).Value()
    inner_arc.Reverse()

    # Convert the 2D arcs and two extra lines to 3D edges
    plane = gp_Pln(gp_Origin(), gp_DZ())
    arc1 = BRepBuilderAPI_MakeEdge(geomapi_To3d(trimmed_base, plane)).Edge()
    arc2 = BRepBuilderAPI_MakeEdge(geomapi_To3d(trimmed_profile, plane)).Edge()
    arc3 = BRepBuilderAPI_MakeEdge(geomapi_To3d(outer_arc, plane)).Edge()
    arc4 = BRepBuilderAPI_MakeEdge(geomapi_To3d(mirror_profile, plane)).Edge()
    arc5 = BRepBuilderAPI_MakeEdge(geomapi_To3d(mirror_base, plane)).Edge()

    p4 = mirror_base.EndPoint()
    p5 = inner_arc.StartPoint()

    lin1 = BRepBuilderAPI_MakeEdge(
        gp_Pnt(p4.X(), p4.Y(), 0), gp_Pnt(p5.X(), p5.Y(), 0)
    ).Edge()
    arc6 = BRepBuilderAPI_MakeEdge(geomapi_To3d(inner_arc, plane)).Edge()

    p6 = inner_arc.EndPoint()
    lin2 = BRepBuilderAPI_MakeEdge(
        gp_Pnt(p6.X(), p6.Y(), 0), gp_Pnt(p0.X(), p0.Y(), 0)
    ).Edge()

    wire = BRepBuilderAPI_MakeWire(arc1)
    wire.Add(arc2)
    wire.Add(arc3)
    wire.Add(arc4)
    wire.Add(arc5)
    wire.Add(lin1)
    wire.Add(arc6)
    wire.Add(lin2)

    face = BRepBuilderAPI_MakeFace(wire.Wire())

    wedge = BRepPrimAPI_MakePrism(face.Shape(), gp_Vec(0.0, 0.0, thickness))

    return wedge.Shape()


def round_tooth(wedge):
    round_x = 2.6
    round_z = 0.06 * pitch
    round_radius = pitch

    # Determine where the circle used for rounding has to start and stop
    p2d_1 = gp_Pnt2d(top_radius - round_x, 0)
    p2d_2 = gp_Pnt2d(top_radius, round_z)

    # Construct the rounding circle
    round_circle = GccAna_Circ2d2TanRad(p2d_1, p2d_2, round_radius, 0.01)
    if round_circle.NbSolutions() != 2:
        sys.exit(-2)

    round_circle_2d_1 = round_circle.ThisSolution(1)
    round_circle_2d_2 = round_circle.ThisSolution(2)

    if round_circle_2d_1.Position().Location().Coord()[1] >= 0:
        round_circle_2d = round_circle_2d_1
    else:
        round_circle_2d = round_circle_2d_2

    # Remove the arc used for rounding
    trimmed_circle = GCE2d_MakeArcOfCircle(round_circle_2d, p2d_1, p2d_2).Value()

    # Calculate extra points used to construct lines
    p1 = gp_Pnt(p2d_1.X(), 0, p2d_1.Y())
    p2 = gp_Pnt(p2d_2.X(), 0, p2d_2.Y())
    p3 = gp_Pnt(p2d_2.X() + 1, 0, p2d_2.Y())
    p4 = gp_Pnt(p2d_2.X() + 1, 0, p2d_1.Y() - 1)
    p5 = gp_Pnt(p2d_1.X(), 0, p2d_1.Y() - 1)

    # Convert the arc and four extra lines into 3D edges
    plane = gp_Pln(gp_Ax3(gp_Origin(), gp_DY().Reversed(), gp_DX()))
    arc1 = BRepBuilderAPI_MakeEdge(geomapi_To3d(trimmed_circle, plane)).Edge()
    lin1 = BRepBuilderAPI_MakeEdge(p2, p3).Edge()
    lin2 = BRepBuilderAPI_MakeEdge(p3, p4).Edge()
    lin3 = BRepBuilderAPI_MakeEdge(p4, p5).Edge()
    lin4 = BRepBuilderAPI_MakeEdge(p5, p1).Edge()

    # Make a wire composed of the edges
    round_wire = BRepBuilderAPI_MakeWire(arc1)
    round_wire.Add(lin1)
    round_wire.Add(lin2)
    round_wire.Add(lin3)
    round_wire.Add(lin4)

    # Turn the wire into a face
    round_face = BRepBuilderAPI_MakeFace(round_wire.Wire()).Shape()

    # Revolve the face around the Z axis over the tooth angle
    rounding_cut_1 = BRepPrimAPI_MakeRevol(round_face, gp_OZ(), tooth_angle).Shape()

    # Construct a mirrored copy of the first cutting shape
    mirror = gp_Trsf()
    mirror.SetMirror(gp_XOY())
    mirrored_cut_1 = BRepBuilderAPI_Transform(rounding_cut_1, mirror, True).Shape()

    # and translate it so that it ends up on the other side of the wedge
    translate = gp_Trsf()
    translate.SetTranslation(gp_Vec(0, 0, thickness))
    rounding_cut_2 = BRepBuilderAPI_Transform(mirrored_cut_1, translate, False).Shape()

    # Cut the wedge using the first and second cutting shape
    cut_1 = BRepAlgoAPI_Cut(wedge, rounding_cut_1).Shape()
    cut_2 = BRepAlgoAPI_Cut(cut_1, rounding_cut_2).Shape()

    return cut_2


def clone_tooth(base_shape):
    clone = gp_Trsf()
    grouped_shape = base_shape

    # Find a divisor, between 1 and 8, for the number_of teeth
    multiplier = 1
    max_multiplier = 1
    for i in range(0, 8):
        if num_teeth % multiplier == 0:
            max_multiplier = i + 1

    multiplier = max_multiplier
    for i in range(1, multiplier):
        clone.SetRotation(gp_OZ(), -i * tooth_angle)
        rotated_shape = BRepBuilderAPI_Transform(base_shape, clone, True).Shape()
        grouped_shape = BRepAlgoAPI_Fuse(grouped_shape, rotated_shape).Shape()

    # Rotate the basic tooth and fuse together
    aggregated_shape = grouped_shape
    for i in range(1, int(num_teeth / multiplier)):
        clone.SetRotation(gp_OZ(), -i * multiplier * tooth_angle)
        rotated_shape = BRepBuilderAPI_Transform(grouped_shape, clone, True).Shape()
        aggregated_shape = BRepAlgoAPI_Fuse(aggregated_shape, rotated_shape).Shape()

    cylinder = BRepPrimAPI_MakeCylinder(
        gp_XOY(), top_radius - roller_diameter, thickness
    )
    aggregated_shape = BRepAlgoAPI_Fuse(aggregated_shape, cylinder.Shape()).Shape()

    return aggregated_shape


def center_hole(base):
    cylinder = BRepPrimAPI_MakeCylinder(center_radius, thickness).Shape()
    cut = BRepAlgoAPI_Cut(base, cylinder)
    return cut.Shape()


def mounting_holes(base):
    result = base
    for i in range(0, mounting_hole_count):
        center = gp_Pnt(
            cos(i * M_PI / 3) * mounting_radius,
            sin(i * M_PI / 3) * mounting_radius,
            0.0,
        )
        center_axis = gp_Ax2(center, gp_DZ())

        cylinder = BRepPrimAPI_MakeCylinder(center_axis, hole_radius, thickness).Shape()
        result = BRepAlgoAPI_Cut(result, cylinder).Shape()

        cone = BRepPrimAPI_MakeCone(
            center_axis, hole_radius + thickness / 2.0, hole_radius, thickness / 2.0
        )
        result = BRepAlgoAPI_Cut(result, cone.Shape()).Shape()

    return result


def cut_out(base):
    outer = gp_Circ2d(gp_OX2d(), top_radius - 1.75 * roller_diameter)
    inner = gp_Circ2d(gp_OX2d(), center_radius + 0.75 * roller_diameter)

    geom_outer = GCE2d_MakeCircle(outer).Value()
    geom_inner = GCE2d_MakeCircle(inner).Value()
    geom_inner.Reverse()

    base_angle = (2.0 * M_PI) / mounting_hole_count
    hole_angle = atan(hole_radius / mounting_radius)
    correction_angle = 3 * hole_angle

    left = gp_Lin2d(gp_Origin2d(), gp_DX2d())
    right = gp_Lin2d(gp_Origin2d(), gp_DX2d())
    left.Rotate(gp_Origin2d(), correction_angle)
    right.Rotate(gp_Origin2d(), base_angle - correction_angle)

    geom_left = GCE2d_MakeLine(left).Value()
    geom_right = GCE2d_MakeLine(right).Value()

    inter_1 = Geom2dAPI_InterCurveCurve(geom_outer, geom_left)
    inter_2 = Geom2dAPI_InterCurveCurve(geom_outer, geom_right)
    inter_3 = Geom2dAPI_InterCurveCurve(geom_inner, geom_right)
    inter_4 = Geom2dAPI_InterCurveCurve(geom_inner, geom_left)

    if inter_1.Point(1).X() > 0:
        p1 = inter_1.Point(1)
    else:
        p1 = inter_1.Point(2)

    if inter_2.Point(1).X() > 0:
        p2 = inter_2.Point(1)
    else:
        p2 = inter_2.Point(2)

    if inter_3.Point(1).X() > 0:
        p3 = inter_3.Point(1)
    else:
        p3 = inter_3.Point(2)

    if inter_4.Point(1).X() > 0:
        p4 = inter_4.Point(1)
    else:
        p4 = inter_4.Point(2)

    trimmed_outer = GCE2d_MakeArcOfCircle(outer, p1, p2).Value()
    trimmed_inner = GCE2d_MakeArcOfCircle(inner, p4, p3).Value()

    plane = gp_Pln(gp_Origin(), gp_DZ())

    arc1 = BRepBuilderAPI_MakeEdge(geomapi_To3d(trimmed_outer, plane)).Edge()

    lin1 = BRepBuilderAPI_MakeEdge(
        gp_Pnt(p2.X(), p2.Y(), 0), gp_Pnt(p3.X(), p3.Y(), 0)
    ).Edge()

    arc2 = BRepBuilderAPI_MakeEdge(geomapi_To3d(trimmed_inner, plane)).Edge()

    lin2 = BRepBuilderAPI_MakeEdge(
        gp_Pnt(p4.X(), p4.Y(), 0), gp_Pnt(p1.X(), p1.Y(), 0)
    ).Edge()

    cutout_wire = BRepBuilderAPI_MakeWire(arc1)
    cutout_wire.Add(lin1)
    cutout_wire.Add(arc2)
    cutout_wire.Add(lin2)

    # Turn the wire into a face
    cutout_face = BRepBuilderAPI_MakeFace(cutout_wire.Wire())
    filleted_face = BRepFilletAPI_MakeFillet2d(cutout_face.Face())

    explorer = BRepTools_WireExplorer(cutout_wire.Wire())
    while explorer.More():
        vertex = explorer.CurrentVertex()
        filleted_face.AddFillet(vertex, roller_radius)
        explorer.Next()

    cutout = BRepPrimAPI_MakePrism(
        filleted_face.Shape(), gp_Vec(0.0, 0.0, thickness)
    ).Shape()

    result = base
    rotate = gp_Trsf()
    for i in range(0, mounting_hole_count):
        rotate.SetRotation(gp_OZ(), i * 2.0 * M_PI / mounting_hole_count)
        rotated_cutout = BRepBuilderAPI_Transform(cutout, rotate, True)

        result = BRepAlgoAPI_Cut(result, rotated_cutout.Shape()).Shape()

    return result


def build_sprocket():
    # create the sprocket model
    wedge = build_tooth()
    rounded_wedge = round_tooth(wedge)
    basic_disk = clone_tooth(rounded_wedge)
    cut_disc = center_hole(basic_disk)
    mountable_disc = mounting_holes(cut_disc)
    sprocket = cut_out(mountable_disc)
    return sprocket


sprocket_model = build_sprocket()
# display the sprocket
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(sprocket_model, update=True)
display.FitAll()
start_display()

运行结果

链轮

重点摘要

这个案例代码主要分为以下几个部分:

  • 导入模块
  • 定义常量以及计算衍生尺寸
    设置了链轮的基本参数,如滚子直径、节距、齿数和链宽等。根据输入参数计算出其他必要的尺寸,如滚子半径、齿角、节圆直径等。
  • build_tooth 函数
    定义一个函数来创建链轮的一个齿。它首先创建了齿的基础轮廓,然后通过一系列的2D几何操作构建了齿的外形,并最终将其转换为3D边缘和面。
  • round_tooth 函数
    定义一个函数来为链轮齿添加圆角。这涉及到创建一个用于圆角的2D圆,并将其转换为3D形状,然后通过布尔运算在齿上切出圆角。
  • clone_tooth 函数
    定义一个函数来复制单个齿形以形成整个链轮的齿。通过旋转和融合多个齿形来实现。
    #创建一个gp_Trsf对象,即几何变换(Transformation)对象。gp_Trsf是OCC中用于存储几何变换(如平移、旋转、缩放等)的类。
    clone = gp_Trsf() 
    
    #SetRotation是gp_Trsf类的一个方法,用于设置一个旋转变换。这里,它被用来设置绕Z轴(由gp_OZ()指定,代表通过原点且方向沿着Z轴的轴对象)的旋转。
    ##第一个参数gp_OZ()定义了旋转的轴。
    ##第二个参数-i * tooth_angle定义了旋转的角度,其中i是一个循环变量,表示当前是第几个齿(在clone_tooth函数中定义),tooth_angle是每个齿之间的角度。
    clone.SetRotation(gp_OZ(), -i * tooth_angle) 
    
    #BRepBuilderAPI_Transform是OCC中的一个方法,用于对边界表示(BRep)对象应用一个几何变换。
    ##第一个参数base_shape是要被变换的形状。
    ##第二个参数clone是我们刚刚创建的包含旋转信息的gp_Trsf对象。
    ##第三个参数True表示应用变换后要更新base_shape的形状(在某些情况下,如果设置为False,则不会更新原对象,而是创建一个新的变换后的对象)
    rotated_shape = BRepBuilderAPI_Transform(base_shape, clone, True).Shape()
    
  • center_hole 函数
    定义了一个函数来在链轮中心创建一个孔。
  • mounting_holes 函数
    定义一个函数在链轮的周边创建安装孔。
  • cut_out 函数
    定义一个函数在链轮上创建凹槽。
  • build_sprocket 函数
    主函数,调用上述所有函数来创建完整的链轮模型。
  • 显示模型
    最后,使用OCC的SimpleGui模块来显示生成的链轮模型。

该内容持续修改······

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值