Skip to content

Writing a Format Plugin

This tutorial shows how to add custom file format support to LinkCAD using Python.

Format Reader (Import)

A format reader converts an external file format into LinkCAD’s drawing database.

Example: Simple Coordinate File Reader

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):
scale = Option.integer("Scale factor", default=1000, min=1, max=1000000)
layer_name = Option.string("Layer name", default="imported")
def read(self, path: Path, drawing: DrawingContext) -> None:
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()
x = float(parts[0]) * self.scale
y = float(parts[1]) * self.scale
vertices.append((x, y))
# Don't forget the last polygon
if vertices:
layer.polygon(vertices)

Key Concepts

  • @format_reader() registers the class as an import format
  • extensions determines which files the reader handles
  • DrawingContext provides a builder API for creating cells, layers, and shapes
  • drawing.iter_lines() reads lines with automatic progress tracking
  • drawing.iter_binary() reads binary data with progress tracking

DrawingContext API

MethodDescription
cell(name, main=False)Context manager — creates/opens a cell
iter_lines(path)Iterate text file lines with progress
iter_binary(path, chunk_size)Iterate binary chunks with progress
progressGet/set progress (0.0 to 1.0)

CellContext API

MethodDescription
layer(name)Context manager — selects a layer

LayerContext API

MethodDescription
polygon(vertices)Create a polygon from (x, y) tuples
polyline(width, vertices, closed)Create a polyline
circle(center, diameter)Create a circle

Format Writer (Export)

A format writer exports LinkCAD geometry to a file.

Example: Simple Text Writer

from pathlib import Path
from linkcad.v1.plugin import format_writer, FormatWriter, Option, WriterContext
@format_writer(
name="Simple Text",
extensions=["*.stxt"],
)
class SimpleWriter(FormatWriter):
separator = Option.choice(
"Separator",
choices=["Space", "Comma", "Tab"],
default="Space",
)
precision = Option.integer("Decimal places", default=3, min=0, max=10)
def write(self, path: Path, drawing: WriterContext) -> None:
sep = {"Space": " ", "Comma": ", ", "Tab": "\t"}[self.separator]
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")

WriterContext API

MethodDescription
shapes(cell, layer)Iterate all shapes (optional cell/layer filter)
shapes_by_layer(cell)Iterate shapes grouped by layer
shapes_by_cell(layer)Iterate shapes grouped by cell
cells()Iterate cell names
layers()Iterate layer names
cell_count()Number of cells
shape_count()Total number of shapes
main_cell_name()Name of the top cell
layer_names()List of all layer names
flattenGet/set hierarchy flattening
progressGet/set progress (0.0 to 1.0)

ShapeInfo Properties

PropertyTypeDescription
layer_namestrLayer name
cell_namestrCell name
verticeslist[tuple]List of (x, y) coordinates
is_polygonboolTrue for polygons, False for polylines
widthintPolyline width (0 for polygons)
is_closedboolWhether the shape is closed

Error Handling

Use the built-in exception classes for clear error reporting:

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")

Next Steps