0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

言葉でつくるCAD

OpenSCADのPython版、PythonSCADと、Cadqueryから派生したbuild123dを合わせて、コード作成と、画面viewer確認ができます。3D CADをPythonで行う新しいアプローチです。これまで、PythonSCADからbuild123dのコードを呼び出し、サンプルをまとめてみました。実際に実行してみてください。
検証したサンプルを紹介します。

線 (Edge/Wire/Curve)をつかった、circleを三つ繋げたサンプル

線の描画は、円が一番分かりやすい確認になります。2種類用意しました。

平面上で3つの円をつなぐ(Builder モード)

from b123dview import *

with BuildLine() as line:
    for i in range(3):
        CenterArc(center=(i * 30, 0), radius=20, start_angle=0, arc_size=360)
    Line((0, 20), (60, 20))       # 上端を1本で結ぶ
    Line((0, -20), (60, -20))     # 下端

show(line)                        # line.line でも可

スクリーンショット 2026-08-30 192718.png

BuildLine では円は Circle ではなく CenterArc(..., arc_size=360) で描きます(Circle は BuildSketch 用の「面」です)。半径 20 を 30 間隔で並べているので互いに重なり、上下を直線でつないでいます。

直交する3平面に円を置く(代数モード)

from b123dview import *

c1 = Plane.XY * Edge.make_circle(20)
c2 = Plane.XZ * Edge.make_circle(20)
c3 = Plane.YZ * Edge.make_circle(20)

show(c1, c2, c3)                  # 複数渡せる

スクリーンショット 2026-08-30 193112.png

ジャイロのような形になり、線が 3D 空間の任意の向きでも描けていることが一目で分かります。

見た目の調整は、線の太さが wire_r、曲線の分割数が segs です。

show(line, wire_r=0.5, segs=32)

スクリーンショット 2026-08-30 193420.png

show(c1, c2, c3,wire_r=0.75, segs=50)      # 複数渡せる

円1つが segs 個のカプセルになるので、segs=32 で円3つなら 96 個の hull が走ります。プレビューが重く感じたら segs を下げてください。直線(GeomType.LINE)は分割せず1本のカプセルで済むよう分岐してあります。

build123dでの回転体作成

PythonSCADの2D表示は、厚みがなく、renderすると赤い線がでて
2Dとわかるようにしていましたが、build123dからの変換で、ポリゴンで
渡しているのですね。
PythonSCADの回転体作成は、+xy平面で、2D描画、-x領域はエラーになる。
rotate_extrudeでしたが、build123dでも同じ考え方でしょうか。

1. 2D の扱い

今の b123dview は Sketch を薄く押し出した 3D polyhedron として渡しています。PythonSCAD から見ると本物の 2D ではないので、赤い線の表示にはならず、linear_extruderotate_extrude にも掛けられません。

XY 平面上のスケッチに限れば、頂点を拾って PythonSCAD の polygon() に変換すれば、本物の 2D にできます。穴は paths で渡します。

def _loop(wire, segs):
    pts = []
    for e in wire.order_edges():
        n = 1 if e.geom_type == GeomType.LINE else segs
        seg = [e @ (i / n) for i in range(n + 1)]
        if pts and (pts[-1] - seg[0]).length > (pts[-1] - seg[-1]).length:
            seg.reverse()                     # 辺の向きをそろえる
        pts += seg[:-1]                       # 終点は次の辺の始点と重なるので落とす
    return [[p.X, p.Y] for p in pts]

def to_polygon(obj, segs=16):
    """XY 平面上の Face / Sketch を PythonSCAD の 2D polygon にする"""
    if isinstance(obj, Builder):
        obj = obj._obj
    polys = []
    for f in obj.faces():
        pts, paths = [], []
        for w in [f.outer_wire(), *f.inner_wires()]:
            loop = _loop(w, segs)
            paths.append(list(range(len(pts), len(pts) + len(loop))))
            pts += loop
        polys.append(polygon(pts, paths))
    return union(polys) if len(polys) > 1 else polys[0]

これで show(to_polygon(sketch)) は赤線付きの 2D として出ますし、to_polygon(sketch).rotate_extrude() のように PythonSCAD 側の押し出しにも渡せます。from pythonscad import polygon の追加が必要です。傾いたスケッチは Z を捨てているので正しく出ません。

2. 回転体の考え方は少し違います

OpenSCAD の rotate_extrude は「XY の 2D 図形を暗黙に XZ に立てて、X を半径として Z 軸回りに回す」ので、−X 側があるとエラーになります。

build123d の revolve は「描いた平面のまま、明示した軸の回りに回す」です。なので断面は最初から Plane.XZ に描き、axis=Axis.Z で回します。断面が軸をまたいではいけない点は同じです(自己交差になるためエラーになります)。

from b123dview import *

with BuildPart() as vase:
    with BuildSketch(Plane.XZ):              # ローカル x = X(半径), ローカル y = Z(高さ)
        with BuildLine():
            Polyline((5, 0), (20, 0), (15, 30), (8, 40), (5, 40), close=True)
        make_face()
    revolve(axis=Axis.Z, revolution_arc=360)

show(vase)

image.png

違いを整理すると、OpenSCAD は「+X 側の XY 図形を Z 軸で回す」一択なのに対し、build123d は断面をどの平面に置くか、どの軸で回すか(Axis.X や任意の Axis)、何度回すか(revolution_arc)を全部明示します。授業では「build123d は暗黙のルールが少ない代わりに、平面と軸を自分で言葉にする」という対比で説明できると思います。

描画したpolylineを安全のために、マイナス部分をカット、または+部分とintersectionする方法

make_face() のあとに +x 側だけを覆う矩形を Mode.INTERSECT で重ねる方法です。BuildSketch 内はローカル座標(x が半径方向)で書けるので、Plane.XZ に置いても考え方は変わりません。

from b123dview import *

with BuildPart() as vase:
    with BuildSketch(Plane.XZ):
        with BuildLine():
            Polyline((-5, 0), (20, 0), (15, 30), (8, 40), (-5, 40), close=True)  # わざと −x にはみ出す
        make_face()
        Rectangle(1000, 1000, align=(Align.MIN, Align.CENTER), mode=Mode.INTERSECT)  # x ≥ 0 だけ残す
    revolve(axis=Axis.Z)

show(vase)

スクリーンショット 2026-08-30 201033.png

align=(Align.MIN, Align.CENTER) で矩形の左端を x=0 に置き、上下は中央揃えなので ±500 をカバーします。断面が軸にちょうど接する形になりますが、軸上の辺は許されるので(花瓶の底のような中実部分になります)revolve は通ります。

代数モードなら、split で平面の片側を残す書き方もあります。

from b123dview import *

prof = make_face(Polyline((-5, 0), (20, 0), (15, 30), (8, 40), (-5, 40), close=True))
prof = split(prof, bisect_by=Plane.YZ, keep=Keep.TOP)   # Plane.YZ の法線 +X 側を残す
vase = revolve(Plane.XZ * prof, axis=Axis.Z)

show(vase)

スクリーンショット 2026-08-30 201254.png

Plane.YZ の法線は +X なので Keep.TOP が +X 側です。Builder の中で split を使う場合はローカル座標との対応を意識する必要があるので、生徒向けには矩形の INTERSECT のほうが「+x 側を切り抜く」という意図がそのまま読めて説明しやすいと思います。

いずれも build123d の中で完結するので、変換前に断面が保証され、revolve のエラーで止まることがなくなります。教材なら「断面を描く → 安全のために +x で切り抜く → 回す」を定型にしておくとよいですね。

  • PythonSCADのGUIでbuild123dを動かす

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?