コンテンツにスキップ

形式プラグインの作成

このチュートリアルでは、Python を使って LinkCAD にカスタムファイル形式のサポートを追加する方法を説明します。

形式リーダー(インポート)

形式リーダーは、外部のファイル形式を LinkCAD の図面データベースに変換します。

例: 単純な座標ファイルリーダー

from pathlib import Path
from linkcad.v1.plugin import format_reader, FormatReader, Option, DrawingContext
@format_reader(
name="Coordinate File",
extensions=["*.xyz", "*.coord"],
description="Simple X Y coordinate files",
)
class CoordReader(FormatReader):
units = Option.choice(
"Units",
choices=["nm", "um", "mil", "mm", "cm", "inch", "m"],
default="um",
tooltip="Physical units of the coordinate values in the file",
)
layer_name = Option.string("Layer name", default="imported")
def read(self, path: Path, drawing: DrawingContext) -> None:
# Name the unit once and LinkCAD converts every coordinate you hand it.
drawing.units = self.units
with drawing.cell(path.stem, main=True) as cell:
with cell.layer(self.layer_name) as layer:
vertices = []
for line in drawing.iter_lines(path):
line = line.strip()
if not line or line.startswith("#"):
# Blank line = end of polygon
if vertices:
layer.polygon(vertices)
vertices = []
continue
parts = line.split()
vertices.append((float(parts[0]), float(parts[1])))
# Don't forget the last polygon
if vertices:
layer.polygon(vertices)

主要な概念

  • @format_reader() はクラスをインポート形式として登録します
  • extensions はリーダーが扱うファイルを決めます
  • DrawingContext はセル、レイヤー、形状を作成するためのビルダー API を提供します
  • drawing.units は座標の単位を宣言するもので、これにより手作業でのスケーリングが不要になります
  • drawing.iter_lines() は進捗表示付きで行を読み込みます
  • drawing.iter_binary() は進捗表示付きでバイナリデータを読み込みます

作業単位

drawing.units を一度設定すれば、渡すすべての座標と幅がその単位として解釈されます。使用できる名前は nmummilmmcminchm と、micronmillimetrein などの別名です。

未設定のままならば座標は生のデータベース単位になり、このプロパティが存在しなかった頃とまったく同じ挙動になります。未知の名前、またはデータベース単位を宣言していない図面の場合は ValidationError が送出されます。

独自のスケール表で座標を乗算しているリーダーは古い書き方です。表を削除し、単位を宣言してください。

DrawingContext API

プロパティ / メソッド説明
units座標の単位。None は生のデータベース単位
cell(name, main=False)コンテキストマネージャー——セルを作成/オープンします
iter_lines(path, encoding="utf-8")進捗表示付きでテキスト行を反復します
iter_binary(path, chunk_size=8192)進捗表示付きでバイナリチャンクを反復します
progress進捗の取得/設定(0.0~1.0)

CellContext API

メソッド説明
layer(name)コンテキストマネージャー——レイヤーを選択します

LayerContext API

座標は図面の作業単位で指定します。

メソッド説明
polygon(vertices)(x, y) タプルから閉じたポリゴンを作成します
polyline(width, vertices, closed=False)ポリラインを作成します
circle(center, diameter)円を作成します

後処理フック

リーダーは任意で post_process() を定義し、LinkCAD が解析後に実行する各フェーズに参加できます——組み込みのネイティブリーダーが使うのと同じフックです。read() と同じインスタンス上で実行されるため、そこで記録した情報はそのまま利用できます。False を返すとインポートを中止します。

from linkcad.v1.plugin import Phase
class CoordReader(FormatReader):
def post_process(self, phase, drawing, resolution) -> bool:
if phase == Phase.ResolvedRefs:
... # every reference now points at a real cell
return True

フェーズは次の順で到達します: ParsedFileParsedAllClosedOpenCellsResolvedRefsSelectedMainCellResolvedLayersByBlockAutoNumberedZ

形式ライター(エクスポート)

形式ライターは LinkCAD のジオメトリをファイルに書き出します。

例: 単純なテキストライター

from pathlib import Path
from linkcad.v1.plugin import format_writer, FormatWriter, Option, WriterContext
@format_writer(
name="Simple Text",
extensions=["*.stxt"],
)
class SimpleWriter(FormatWriter):
units = Option.choice(
"Output units",
choices=["nm", "um", "mil", "mm", "cm", "inch", "m"],
default="um",
)
separator = Option.choice(
"Separator",
choices=["Space", "Comma", "Tab"],
default="Space",
)
precision = Option.integer("Decimal places", default=3, min=0, max=10)
flatten = Option.boolean("Flatten hierarchy", default=False)
def write(self, path: Path, drawing: WriterContext) -> None:
sep = {"Space": " ", "Comma": ", ", "Tab": "\t"}[self.separator]
# Name the unit once and every coordinate arrives already converted.
drawing.units = self.units
drawing.flatten = self.flatten
with open(path, "w") as f:
for layer_name, shapes in drawing.shapes_by_layer():
f.write(f"# Layer: {layer_name}\n")
for shape in shapes:
for x, y in shape.vertices:
f.write(f"{x:.{self.precision}f}{sep}"
f"{y:.{self.precision}f}\n")
f.write("\n")

作業単位とフラット化

drawing.units はリーダーと同じように、ただし逆方向に働きます。設定すれば shapes() から受け取る座標と幅はすべてその単位に変換済みです。独自のスケール表で割っているライターは古い書き方です。

drawing.flatten は走査方法を選びます。反復を始める前に設定してください。

  • flatten = False は各セル自身の形状のみを走査し、セル参照の処理は呼び出し側に委ねます。曲線は頂点を持たずに返されます。曲線のテセレーションにはホストが必要だからです。
  • flatten = True はホストコントローラーを通じて階層をレンダリングします。ホストは降下しながら変換スタックを適用し、途中で曲線をテセレーションします。したがって円弧、円、ドーナツ、NURBS がポリゴンやポリラインとしてライターに届くのはフラット化が有効なときだけです。

いずれの場合も shapes() が唯一の走査手段です。フラット化専用のイテレーターは存在しません。

WriterContext API

プロパティ / メソッド説明
units受け取るジオメトリの単位。None は生のデータベース単位
flatten階層のフラット化の取得/設定。反復前に設定します
shapes(cell=None, layer=None)形状を反復します(セル/レイヤーフィルター任意)
shapes_by_layer(cell=None)レイヤーごとにグループ化して反復します
shapes_by_cell(layer=None)セルごとにグループ化して反復します
cell_names / layer_namesすべてのセル名/レイヤー名のリスト
cell_countセル数
shape_count形状の総数
main_cell_nameトップセルの名前
progress進捗の取得/設定(0.0~1.0)

ShapeInfo のプロパティ

プロパティ説明
layer_namestrレイヤー名
cell_namestrセル名
verticeslist[tuple]作業単位での (x, y) 座標
is_polygonboolポリゴンなら True、ポリラインなら False
widthint作業単位でのポリライン幅(ポリゴンは 0)
is_closedbool形状が閉じているかどうか

エラー処理

明確なエラー報告のために、組み込みの例外クラスを使用してください。

from linkcad.v1.plugin import ParseError, WriteError, ValidationError
# In a reader:
raise ParseError("Invalid coordinate", line=42, path=path)
# In a writer:
raise WriteError("Cannot write to locked file")
# In option validation:
raise ValidationError("Scale must be positive")

次のステップ