跳转到内容

linkcad.plugin

插件模块提供创建工具、格式读取器和格式写入器的框架。在脚本和插件中请使用 linkcad.v1.plugin;它完整镜像 linkcad.plugin 的公开命名空间,两者公开完全相同的 API。

from linkcad.v1.plugin import (
tool, Tool, Option, TableColumn,
format_reader, FormatReader, DrawingContext, CellContext, LayerContext, DrawingBuilder,
format_writer, FormatWriter, WriterContext, ShapeInfo, WriterController,
DialogSpec, ChoiceItem,
EventLog, Phase, LayerFlags, SortOrder,
HolesMode, PolygonType, EndCap, FillRule,
PluginError, ParseError, WriteError, ValidationError,
UNIT_IN_METERS,
)

工作单位

DrawingContext(导入)和 WriterContext(导出)都带有 units 属性。设置一次之后,跨越插件边界的每个坐标和宽度都以该单位表示——插件不再需要自带缩放表:

drawing.units = "mm" # in a reader: the numbers you hand in are millimetres
drawing.units = "um" # in a writer: the numbers you get back are microns
可接受的名称别名
nmummilmmcminchmnanometer/nanometremicron/micrometer/micrometremillimeter/millimetrecentimeter/centimetreinmeter/metre

不设置 units(或赋值 None)表示使用原始数据库单位,这与该属性出现之前插件的行为完全一致。名称未知,或图纸未声明其数据库单位时,会抛出 ValidationError

UNIT_IN_METERS 是唯一的换算表,在此导出,使任何插件都不必自带一份——一份可能悄然不一致的第二张表,正是当年把千倍放置误差带进已发布工具的那条路径:

from linkcad.v1.plugin import UNIT_IN_METERS
to_db_units = UNIT_IN_METERS["mm"] * drawing.units # drawing.units is per metre

装饰器

@tool()

把类注册为菜单工具。参见工具装饰器

@tool(name="My Tool", menu="Tools/Custom")
class MyTool(Tool):
def run(self, drawing) -> dict:
# `drawing` is a linkcad.v1.db.Drawing owned by the application.
return {"summary": f"{len(drawing.cells)} cells"}

@format_reader()

把类注册为文件导入格式。参见格式装饰器

@format_reader(name="My Format", extensions=["*.myf"])
class MyReader(FormatReader):
def read(self, path: Path, drawing: DrawingContext) -> None:
...

读取器还可以定义可选的 post_process(phase, drawing, resolution) 钩子,它在解析之后 LinkCAD 运行的每个阶段被调用——与内置原生读取器使用的钩子相同。它在与 read() 相同的实例上运行,因此在那里记录的内容仍然可用。返回 False 会中止导入:

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

FormatReader 还提供 LinkCAD 使用的原生桥接方法 parse_file(filepath, builder, file_size, progress_callback)。在用户插件中请实现 read(),让桥接去调用它。

@format_writer()

把类注册为文件导出格式。参见格式装饰器

@format_writer(name="My Format", extensions=["*.myf"])
class MyWriter(FormatWriter):
def write(self, path: Path, drawing: WriterContext) -> None:
...

FormatWriter 还提供 LinkCAD 使用的原生桥接方法 write_file(filepath, controller, set_entity_sink=None)。在用户插件中请实现 write(),让桥接去调用它。

Option 类

Option 提供用于定义带类型且可持久化选项的工厂方法:

工厂方法结果类型UI 控件
Option.integer(label, default, min, max)int微调框
Option.real(label, default, min, max, decimals)float小数微调框
Option.boolean(label, default)bool复选框
Option.string(label, default)str文本框
Option.choice(label, choices, default)str下拉列表
Option.path(label, default, file_filter)str文件选择器
Option.color(label, default)str颜色选择器
Option.table(label, columns, default)list[dict]可编辑网格
Option.cell_choice(label, default)str单元下拉列表

所有工厂方法都接受可选的 tooltipenabled_when 参数,以及一个仅限关键字的 name 参数,用于覆盖自动生成的选项键。

选项键与应用程序自身的设置共享同一命名空间,因此由类属性生成的键是被限定的,而不只是加了前缀:AsciiWriter 上的 flatten 变成 PyPlugin.AsciiWriter.flatten。保留根 PyPlugin 把插件选项挡在应用程序命名空间之外,类名段则把两个都叫 flatten 的插件选项区分开。属性名原样使用,因此键与读取它的 Python 属性拼写一致。

每个插件选项也都可以用该键从命令行设置:

linkcad --PyPlugin.AsciiWriter.precision=5 ...

上下文类

DrawingContext

面向格式读取器的 Python 风格构建器接口。

  • units — 你的坐标所用的单位;参见工作单位
  • cell(name, main=False) — 返回 CellContext 的上下文管理器
  • iter_lines(path, encoding="utf-8") — 带进度的行迭代器
  • iter_binary(path, chunk_size=8192) — 带进度的二进制迭代器
  • progress — 读取/设置 0.01.0 的进度

CellContext

DrawingContext.cell() 返回。

  • layer(name) — 返回 LayerContext 的上下文管理器

LayerContext

CellContext.layer() 返回。坐标以图纸的工作单位表示。

  • polygon(vertices) — 从 (x, y) 元组创建闭合多边形
  • polyline(width, vertices, closed=False) — 创建折线
  • circle(center, diameter) — 创建圆
def read(self, path: Path, drawing: DrawingContext) -> None:
drawing.units = "um"
with drawing.cell(path.stem, main=True) as cell:
with cell.layer("METAL1") as layer:
layer.polygon([(0, 0), (100, 0), (100, 100), (0, 100)]) # a 100 µm square
layer.polyline(2.5, [(0, 0), (200, 200)])
layer.circle((500, 500), 50)

WriterContext

面向格式写入器的 Python 风格读取接口。

  • units — 你收到的几何图形所用的单位;参见工作单位
  • 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.01.0 的进度

shapes() 及其两个分组形式外,其余都是名词,因而都是属性。cells()layers() 生成器已被移除:它们产出的字符串正是 cell_nameslayer_names 已经持有的内容,而同一个列表有两种写法是一个没有正确答案的选择。

无论是否展平,shapes() 都是遍历几何图形的唯一入口。flatten = False 时它遍历每个单元自身的形状,把引用留给你处理。flatten = True 时它通过宿主控制器渲染层次结构,宿主在下降时应用变换栈并沿途细分曲线——因此圆弧、圆、圆环和 NURBS 只有在启用展平时才会以多边形和折线的形式到达写入器。

def write(self, path: Path, drawing: WriterContext) -> None:
drawing.units = "mm"
drawing.flatten = True
with open(path, "w") as f:
for shape in drawing.shapes():
for x, y in shape.vertices: # millimetres
f.write(f"{x:.4f} {y:.4f}\n")
f.write("\n")

展平遍历需要宿主写入器,因此只能在 FormatWriter.write() 内部使用。手工构造的 WriterContext 只能使用 flatten = False

ShapeInfo

WriterContext.shapes() 产出的数据类:

  • layer_name: str — 图层名
  • cell_name: str — 单元名
  • vertices: list[tuple] — 以工作单位表示的 (x, y) 坐标
  • is_polygon: bool — 多边形还是类折线输出
  • width: int — 以工作单位表示的折线宽度
  • is_closed: bool — 形状是否闭合

原生格式接口

DrawingContextWriterContext 覆盖了大多数格式插件的需求。对于需要与 LinkCAD 底层格式 API 完全对等的插件,还公开了原生的 DrawingBuilderWriterController 接口。

DrawingBuilder

DrawingBuilder 由 LinkCAD 运行时提供给导入插件,用户代码不会直接创建它。

属性说明
builder.resolution曲线细分设置
builder.cell当前单元,或 None
builder.layer当前图层,或 None
builder.cell_object最近创建的单元对象,或 None
builder.drawing正在构建的图纸
方法分组方法
图纸元数据set_drawing_name(name)set_drawing_modif_time(time)set_drawing_access_time(time)set_progress(percent)
单元open_cell(name_or_number, is_main_cell=False, reopen=False)close_cell()delete_cell()set_cell_name(name)set_cell_modif_time(time)set_cell_access_time(time)find_cell(name)
图层select_layer(name_or_number)select_layer(major, minor)set_layer_comment(comment)set_layer_color(rgba)set_layer_enabled(enabled)set_layer_z(z)set_layer_polarity_positive(positive=True)set_layer_polarity_group(group_name)set_layer_polarity_sequence(sequence)
形状create_polygon(vertices, make_simple=False)create_polygon_with_bulges(vertices, bulges)create_rectangle(corner1, corner2)create_polyline(width, vertices, closed=False, end_cap=EndCap.Round)create_circle(center, diameter, donut=False)create_arc(center, radius, width, start_angle=0.0, end_angle=360.0, end_cap=EndCap.Round)create_donut(center, mean_diameter, width)create_nurbs(width, degree, knots, control_points, periodic=False)create_nurbs_weighted(width, degree, knots, control_points, weights, periodic=False)
文本create_text()set_text_position(position)set_text_height(height)set_text_stroke_width(width)set_text_style(flags, mask=TextStyleMask.None_)set_formatted_text(text)set_unformatted_text(text)set_text_font(font_name)set_text_width_factor(factor)set_text_obliquing_angle(angle_degrees)set_text_mirrored_x(mirror=True)set_text_mirrored_y(mirror=True)set_text_rotation(angle_degrees, absolute=False)set_text_box_width(width)set_text_line_spacing(spacing)
引用create_ref(cell_name_or_number)scale_ref(scale, absolute=False)mirror_ref_x(negate=True)mirror_ref_y(negate=True)rotate_ref(angle_degrees, absolute=False)translate_ref(position)set_ref_array_spacing(dx, dy)set_ref_array_size(cols, rows)
上下文save_context()enter_context(handle)leave_context()
日志log_info(message)log_warning(message)log_error(message)
属性与样式set_entity_layer_style(flags)set_current_cell_object_real_property(name, value)set_current_cell_object_bool_property(name, value)
字体DrawingBuilder.register_odb_fonts(fonts_dir)
from linkcad.v1.db import EndCap, TextStyle, TextStyleMask
from linkcad.v1.geom import Point
builder.open_cell("TOP", is_main_cell=True)
builder.select_layer("metal1")
builder.create_arc(Point(0, 0), radius=10_000, width=500, end_cap=EndCap.Round)
builder.create_text()
builder.set_text_position(Point(0, 12_000))
builder.set_text_height(1_000)
builder.set_text_style(TextStyle.AlignHCenter, TextStyleMask.AlignH)
builder.set_unformatted_text("TOP")
builder.close_cell()

WriterController

WriterController 由 LinkCAD 运行时提供给导出插件,用户代码不会直接创建它。

属性说明
controller.file_name输出文件路径
controller.resolution曲线细分设置
controller.drawing正在导出的图纸
controller.main_cell主单元
controller.units_per_meter每米对应的数据库单位数;图纸未声明时为 0
controller.layers全部已启用图层,按常规顺序
controller.layer_names全部已启用图层的名称
controller.layer_count已启用图层的数量
controller.cells全部子单元,子级优先(不含主单元)
controller.cell_names全部单元的名称,含主单元
controller.cell_count单元数量,含主单元
controller.fonts图纸中使用的全部字体
controller.object_count当前已处理的对象数
controller.total_object_count待导出对象总数
controller.fill_rule当前的 FillRule
controller.transformation坐标变换栈的当前栈顶
方法分组方法
日志与进度log_info(message)log_warning(message)log_error(message)set_progress(percent)init_progress_counter(force_flattened=False)set_object_count(count)set_total_object_count(count)
导出配置set_polygon_mode(holes_mode, polygon_type)
带筛选的访问器filtered_layers(sort_order=SortOrder.Regular)filtered_cells(layer=None)
逐步枚举start_enum_layers(sort_order=SortOrder.Regular)next_layer()start_enum_cells()next_cell(layer=None)start_enum_fonts()next_font()
变换transform_point(point)transform_distance(distance)

layerscells 覆盖常见情形;filtered_layers(sort_order)filtered_cells(layer) 暴露这些属性隐藏起来的参数——与 cell.shapes / cell.filtered_shapes 是同一组搭配。

from linkcad.v1.plugin import SortOrder
for layer in controller.filtered_layers(SortOrder.Reverse):
for cell in controller.filtered_cells(layer):
...

推送一侧属于框架

LinkCAD 以两种方式导出几何图形:插件把形状出来,或者控制器把渲染好的实体给写入器。只有推送方向能够展平,因为只有控制器持有沿引用下降时建立的变换栈——手工驱动推送一侧的插件,得到的是没有放置信息的形状,而且不会有任何错误提示。

因此 _render_cell_render_cell_in_layer_order_flatten_cell_hierarchy_get_shapes 都带下划线前缀:它们属于框架,由 WriterContext 代你驱动。请设置 drawing.flatten = True 并迭代 drawing.shapes(),这是同一次遍历,只是放置信息已经应用好了。

HolesModePolygonType 可从稳定的插件模块获取,供 WriterController.set_polygon_mode() 使用:

from linkcad.v1.plugin import HolesMode, PolygonType
controller.set_polygon_mode(HolesMode.Link, PolygonType.AllowComplex)

DialogSpec

DialogSpec 以声明方式描述格式或工具的选项对话框。它对应 Rust 插件的对话框模型,并序列化为 LinkCAD UI 所消费的 JSON 格式。

from linkcad.v1.plugin import DialogSpec, ChoiceItem
spec = (
DialogSpec("Import Options")
.group("Geometry")
.bool_field("merge", "Merge polygons", True)
.int_field("facets", "Minimum facets", 4, 256, 32)
.combo_field("units", "Units", ["nm", "um", "mm"], "um")
.group_in_row("Layers", row=1)
.single_select_list(
"layer",
"Layer",
[ChoiceItem.with_display("metal1", "Metal 1")],
)
)
json_payload = spec.to_json()
类型用途
DialogSpec(title)顶层对话框描述符
DialogGroup(label, row=None)一组相关字段;row 相同的组可以并排布局
UiWidget(option_name, label, kind)组内的单个 UI 元素
WidgetKind(kind_type, **kwargs)控件类型及其配置
ChoiceItem(value, display, description=None)列表/下拉框的选项条目
构建器方法说明
group(label)开始一个组
group_in_row(label, row)在指定行开始一个组
bool_field(option_name, label, default)复选框
int_field(option_name, label, min, max, default)整数微调框
real_field(option_name, label, min, max, default)小数微调框
string_field(option_name, label, default)文本行
combo_field(option_name, label, choices, default)由字符串构成的下拉框
single_select_list(option_name, label, static_choices=None, inspection_key=None)单选列表
multi_select_list(option_name, label, static_choices=None, inspection_key=None, value_separator=",")多选列表
note(text)仅供显示的说明
separator()水平分隔线
to_json()序列化为 JSON

ChoiceItem 提供 simple(value)with_display(value, display)full(value, display, description) 三个工厂方法。

格式元数据

读取器和写入器装饰器会在插件类上附加一个 FormatInfo 对象。对于更底层的格式约束,请使用 linkcad.v1.conv.FormatFormatAttributes;参见 linkcad.conv

from linkcad.v1.conv import Format, FormatAttributes
fmt = Format()
fmt.attributes = FormatAttributes.LAYER_NAMES | FormatAttributes.CELL_NAMES
fmt.layer_max_length = 32

异常

异常用途
PluginError所有插件错误的基类
ParseError文件解析错误;接受 linepath 关键字参数
WriteError文件写入错误
ValidationError选项验证错误

TableColumn

用于定义表格选项列的数据类:

  • key: str — 字典键
  • label: str — 列标题
  • col_type: strstringintegerrealchoicecell_choice
  • default: Any — 默认值
  • choices: list[str] — 用于 choice
  • decimals: int — 用于 real
  • min_value / max_value — 用于数值列

枚举

枚举取值用途
PhaseParsedFileParsedAllClosedOpenCellsResolvedRefsSelectedMainCellResolvedLayersByBlockAutoNumberedZ读取器后处理的阶段钩子
LayerFlagsNormalByLayerByBlock用于 DrawingBuilder.set_entity_layer_style() 的图层属性继承
SortOrderRegularReverseWriterController 的图层枚举顺序
EndCapRoundSquareExtendedSquareFlat为构建器创建形状而重新导出的 linkcad.v1.db.EndCap
FillRuleNonZeroEvenOdd为写入器填充规则而重新导出的 linkcad.v1.db.FillRule

写入器的多边形模式枚举可从 linkcad.v1.plugin 获取:

枚举取值用途
HolesModeLinkSplitExtractKeep多边形导出时孔的表示方式
PolygonTypeAllowComplexForceSimple渲染出的多边形是否可以是复杂多边形