编写格式插件
本教程演示如何使用 Python 为 LinkCAD 添加自定义文件格式支持。
格式读取器(导入)
格式读取器把外部文件格式转换为 LinkCAD 的图纸数据库。
示例:简单的坐标文件读取器
from pathlib import Pathfrom 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提供用于创建单元、图层和形状的构建器 APIdrawing.units声明你的坐标所用的单位,因此无需手动缩放drawing.iter_lines()按行读取并自动跟踪进度drawing.iter_binary()读取二进制数据并跟踪进度
工作单位
只要设置一次 drawing.units,你传入的每个坐标和宽度都会按该单位解释。可接受的名称有 nm、um、mil、mm、cm、inch 和 m,以及 micron、millimetre、in 等常见别名。
不设置时坐标即为原始数据库单位,与该属性出现之前的行为完全一致。名称未知,或图纸未声明其数据库单位时,会抛出 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各阶段按以下顺序到达:ParsedFile、ParsedAll、ClosedOpenCells、ResolvedRefs、SelectedMainCell、ResolvedLayersByBlock、AutoNumberedZ。
格式写入器(导出)
格式写入器把 LinkCAD 的几何图形写入文件。
示例:简单的文本写入器
from pathlib import Pathfrom 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_name | str | 图层名 |
cell_name | str | 单元名 |
vertices | list[tuple] | 以工作单位表示的 (x, y) 坐标 |
is_polygon | bool | 多边形为 True,折线为 False |
width | int | 以工作单位表示的折线宽度(多边形为 0) |
is_closed | bool | 形状是否闭合 |
错误处理
使用内置异常类以获得清晰的错误报告:
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")