跳转到内容

编写格式插件

本教程演示如何使用 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")

后续步骤