Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@
- `examples/site-plan.ts` is the sheet an agent copies, so it must read as a model: the site
in model space at its true size, with the annotation that is read in the plan sized by the
view it names, and everything that belongs to the paper inside `d.layout`, in paper units.
Its border and title block are one block whose fields are attributes. Never draw a sheet
in model space there.
Its layout is on its standard's sheet format and laid out by its zones, and its border and
title block are the standard's, placed by `sheet.titleBlock()`. Never draw a sheet in model
space there.
- A view is drawn only where it can be seen. The clip of a view, the hidden rectangle and
the cull all use one rectangle: the viewport, cut to the paper, cut to the picture `toSVG`
is drawing (its `viewBox`), with every number as it will be written. If that rectangle has
Expand Down Expand Up @@ -175,6 +176,18 @@
through `src/standard/made.ts` and never imports `define.ts`, which draws the plain title
block with the builder as it loads. A drawing without a standard is built as it was before
standards.
- Under a standard, a top-level conditional on the standard's type parameter `Z` whose branches
mention `Z`, such as `Z extends Standard ? A<Z> : B` as a parameter's type, makes
`DrawingBuilder<…, undefined>` not assignable to `DrawingBuilder<…, Standard | undefined>`,
which a helper typed with `ReturnType<typeof createDrawing>` needs. A conditional inside a
field's type, a conditional whose branches do not mention `Z`, and a conditional that is one
member of a union are fine. In a rest tuple, an element whose type is that conditional alone
makes `DrawingBuilder<…, S>` for a standard `S` not assignable to `DrawingBuilder<…, Standard>`,
and so do overloads; `layout()` keeps it one member of a union with `| undefined`.
- Under a standard, a title block's block, the blocks it inserts and their text styles enter the
drawing under their own names when `sheet.titleBlock()` first places it, and one the drawing
has with another definition is refused: never rename one, since its handles come from its
name. The builder fills a title block's scale when the layout's `draw` returns.
- Under a standard, a role's text style and a dimension style of the standard enter the drawing
on first use, under `capitals` of the id, and in model space with the view's scale id after a
dimension style's: `DIMS-1in-10ft`. A view's id is taken when `view()` declares it, and the
Expand Down
13 changes: 11 additions & 2 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ keeping `drafting.ts` in a `lib` folder beside it. Change two import strings to
`"../src/index.ts"` in `site-plan.ts`, and `"../../src/index.ts"` in `lib/drafting.ts`.

Its parameters come first and every position is worked out from them. Its columns and line
breaks are laid out with `measureText`. Its symbols are blocks, and so is its title block.
breaks are laid out with `measureText`. Its symbols are blocks.

It is drawn to a standard of its own, which extends `BUILT_IN_STANDARD` with the layer
`V-TREE`. `d.layer(name, draw)` names a layer of the standard, which gives its color, linetype,
Expand All @@ -263,7 +263,16 @@ The plan is a view at one of the standard's scales, `const plan = d.view("plan",
plan })` in the standard's dimension style. The viewport shows the view, as
`sheet.viewport(corner, width, height, { view: plan, center })`, and `plan.paper(inches)`
turns a gap on paper into drawing units. On the sheet and in a block, a text with a role is at
the role's height and names no view. `sitePlan("1in-20ft")` draws the sheet at 1" = 20'.
the role's height and names no view. Under a standard every text names a role: a `height`, a
`style` and `textStyle()` are refused. `sitePlan("1in-20ft")` draws the sheet at 1" = 20'.

Its layout is on a sheet format of the standard, `d.layout("C-101", { sheetFormat: "arch-d" },
(sheet) => …)`, which gives the paper, the title block and the zones the sheet is laid out by:
`sheet.zone("views")` is the box the viewport fills, as `{ left, bottom, right, top, width,
height }`. `sheet.titleBlock({ title: "SITE PLAN" })` places the border and the title block
and fills its fields: the project, the date and who drew and checked it come from
`createDrawing({ standard, fields: { project, date, drawnBy, checkedBy } })`, the number is the
layout's name and the scale is the viewport's.

## Checking intent

Expand Down
7 changes: 7 additions & 0 deletions docs/layouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ puts entities on a layer as it does anywhere.
belongs to the drawing.
- `draw` is given the sheet: `sheet.name`, `sheet.paper`, `sheet.units`, `sheet.width` and
`sheet.height`, so that what is drawn can be placed from the paper's size.
- Drawn to a standard, a layout is on a sheet format of the standard, which gives its paper and
its plot style table: `d.layout(name, { sheetFormat }, draw)`, or `d.layout(name, draw)` on the
standard's `defaultSheetFormat`. The sheet then has `sheet.drawingArea`, `sheet.zone(name)` and
`sheet.titleBlock()`, which [Title blocks](title-blocks.md#the-title-block-of-a-standard)
describes. A second layout whose name AutoCAD's `AUDIT` takes for another's, such as `STRAßE`
beside `STRASSE`, is refused there. AutoCAD keeps both layouts, and a drawing drawn to a
standard holds its layouts' names to `AUDIT`'s comparison.

### Paper

Expand Down
107 changes: 105 additions & 2 deletions docs/title-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ toSVG(drawing, { layout: "C-101" }); // the sheet, with its fields filled
- A tag names one field of the whole drawing where it can: a second block with a tag `TITLE`
is told from the first only by its block's name.

[`examples/site-plan.ts`](../examples/site-plan.ts) has a fuller one: `titleBlock` there draws
a border and a title block with seven fields, a table for revisions and an area for a seal.
The built-in standard's title block `plain` is a fuller one: a border and a title block with
seven fields, a table for revisions and an area for a seal, which
[`examples/site-plan.ts`](../examples/site-plan.ts) places from its standard, as the next
section but one says.

### The edge of the paper

Expand Down Expand Up @@ -185,6 +187,107 @@ The border has to be a DWG file, by a path from the folder of the sheet's file:
value, and the drawing keeps it when it is saved. The next export from the code writes the
code's values again.

## The title block of a standard

A standard names its title blocks, and its sheet formats, each of which gives a sheet its paper,
its plot style table, its title block and its zones. Drawn to a standard, a layout is on a sheet
format, and `sheet.titleBlock()` places the title block and fills its fields:

```ts
import { BUILT_IN_STANDARD, createDrawing } from "tsdraft";

const d = createDrawing({
units: "ft",
standard: BUILT_IN_STANDARD,
fields: { project: "RESIDENCE AT LOT 12", date: "2026-11-13", drawnBy: "AB", checkedBy: "CD" },
});
const plan = d.view("plan", { scale: "1in-10ft" });
d.layer("C-PROP", () => d.rect([0, 0], 100, 140));

d.layout("C-101", { sheetFormat: "arch-d" }, (sheet) => {
sheet.titleBlock({ title: "SITE PLAN" });
const views = sheet.zone("views");
d.layer("G-ANNO-NPLT", () =>
sheet.viewport([views.left, views.bottom], views.width, views.height, {
view: plan,
center: [50, 70],
}),
);
});
```

- `layout(name, { sheetFormat }, draw)` names the sheet format, and `layout(name, draw)` is on
the standard's `defaultSheetFormat`. A layout of a standard takes no `paper` and no
`plotStyle`: the sheet format gives them.
- `sheet.drawingArea` is the part of the paper inside the border, and `sheet.zone(name)` a box of
it that the sheet format names, such as `views`, each as `{ left, bottom, right, top, width,
height }` in paper units.
- `sheet.titleBlock(fields)` places the title block once on its layout, on the title block's
layer. A title block that tsdraft draws is a block, inserted at `[0, 0]`. A firm's own is its
drawing as an xref, inserted at its point, and the block of the sheet's fields goes over it
when the title block has one. The block's insert has the id `<layout name>.title-block` and
the xref's `<layout name>.border`, when that is a valid id, and none otherwise.
- A field is filled from `fields` given to `titleBlock()`, then from `createDrawing`'s `fields`,
then by the builder: the number is the layout's name, as below, and the scale is the label of
the one scale the layout's viewports show, or `AS NOTED` when they show more than one. The
builder writes the scale when the layout's `draw` returns, so a title block placed before the
viewports gets it. A key of `fields` is what a field fills, such as `title` or `drawnBy`, or the
tag of a field that fills none of them.
- The title block's block, every block it inserts and every text style they use enter the
drawing under their own names, once however many layouts place it. A drawing that has a block
or a text style of one of those names with another definition is refused, and so is a later
`block()` of the name. The builder renames none: a block's handles come from its name, and a
renamed block would move the handles that a drawing referencing this one holds. When one of
them is refused none of them enters, and a refused `titleBlock()` places nothing on the layout.
- What the block draws is on layer `0`, which draws as the insert's layer does, or on layers of
the standard, with the standard's properties.

A field's `source` says where its value comes from: an attribute of the block, which tsdraft
writes, or a field of the firm's drawing that AutoCAD fills in the sheet, from the sheet's file
name, its layout's name, or the date it opens or plots the sheet. tsdraft writes nothing for
the last three.

### One drawing, or a file per sheet

A standard's `sheetFiles` says how a firm keeps its sheets.

**`"one-drawing"`**, the default, keeps a set's sheets as the layouts of one drawing.

- A sheet's number is its layout's name, which is unique in the drawing, and the builder writes it
in the field that fills `number`. `createDrawing`'s `fields` give no number, which would be every
sheet's, and a number given to `titleBlock()` is the layout's name.
- No field reads the file's name or the layout's name: each field the sheet fills is an attribute,
which the builder writes over the firm's drawing. One drawing has one file name, which such a
field would show on every sheet. A field that reads `CTAB`, the layout's name, plots each
layout's own name, with `-PLOT` and with `-PUBLISH`, since AutoCAD works it out as it plots each
one. But under one drawing the layouts' names are the sheets' numbers, so such a field in the
title's place would plot the number there.

**`"sheet-per-file"`** keeps each sheet as a drawing of its own, with one layout, which
references the firm's title block and the model drawings as xrefs.

- A drawing has one layout, a sheet, or none, a model drawing. A second layout is refused.
- A sheet has a number, from `createDrawing`'s `fields` or from `titleBlock()`. It names the
sheet's file, so it has 1 to 64 characters, none of `< > : " / \ | ? *`, no control character
and nothing above U+FFFF, no space or dot at its end, and is not a name Windows keeps for a
device: `CON`, `PRN`, `AUX`, `NUL`, `COM1` to `COM9` or `LPT1` to `LPT9`, in any case and with
any extension. Windows names no file with such a character, drops a space or a dot from the end
of a name, and opens the device for a file of a device's name.
- Save a sheet as `<number>.dwg`, or `<number>.dxf`. AutoCAD fills a field that reads the file's
name from the name the file has, so a sheet saved under another name shows that name as its
number, and AutoCAD says nothing.
- A field that reads the layout's name shows the layout's name, and `titleBlock()` refuses
another value for it. A field of the date AutoCAD opens or plots the sheet takes no value.

### A firm's title block as an xref

A title block of the xref form names the firm's drawing by a path from each sheet's file, as
`d.xref` takes one. Its file holds to the rules of
[What the border's file may hold](#what-the-borders-file-may-hold). Its `preview`, a `Drawing`
that stands for the file, is what the pictures draw in its place: give it to `toSVG` as the
drawing of the xref, `toSVG(drawing, { layout, xrefs: { BORDER: titleBlock.preview } })`, and to
the command in the drawing file's `xrefs` export.

## The preview

`toSVG(drawing, { layout })` draws an insert on a sheet with its attributes, each with the
Expand Down
45 changes: 23 additions & 22 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,25 @@ AutoCAD sizes dashes on the paper in a viewport and on the sheet alike. The
street and the adjoining lot lines are part of the site: they run to the sides
of what the viewport shows, where it cuts them off.

The sheet is laid out from its parameters, in inches: the border half an inch
inside the paper, the viewport in the left 27 inches of the drawing area above
a strip for the view's title, a column 7 inches wide for the notes, and the
title block at its foot, 6 1/2 by 3 inches in the lower right corner. The
paper is full bleed, and the border is still inside it: AutoCAD plots a line
on the left, bottom or right edge of the paper with half its width off the
page, and does not plot a line on the top edge.

The border and the title block are one block, `TITLE BLOCK`, which the
function `titleBlock` draws for the sheet's size. Its fields are attributes:
the project, the sheet's title and number, the date, the scale, and who drew
and checked it. It also has a table for revisions and an area for a seal. The
insert on the layout gives each field its value, and in CAD each stays an
attribute. `titleBlock` reads its arguments and the constant `TITLE_BLOCK`
beside it, so the two can be copied by themselves. The view title's
attributes have tags of their own, `VIEW_TITLE` and `VIEW_SCALE`, so no tag
names two fields. [Title blocks](../docs/title-blocks.md)
has more, and the way to use a firm's own border.
The layout is on the standard's sheet format `arch-d`, which gives its paper,
its title block and the zones it is laid out by, in inches: the border half an
inch inside the paper, the zone `views` for the viewport in the left 27 inches
of the drawing area above the zone `viewTitles` for the view's title, and the
zone `notes`, a column 7 inches wide, above the title block, 6 1/2 by 3 inches
in the lower right corner. The paper is full bleed, and the border is still
inside it: AutoCAD plots a line on the left, bottom or right edge of the paper
with half its width off the page, and does not plot a line on the top edge.

The border and the title block are the standard's, one block, `TITLE BLOCK`,
which `sheet.titleBlock()` places. Its fields are attributes: the project, the
sheet's title and number, the date, the scale, and who drew and checked it. It
also has a table for revisions and an area for a seal. The title comes from the
call, the project, the date and who drew and checked it from `createDrawing`'s
`fields`, the number from the layout's name and the scale from the viewport,
and in CAD each stays an attribute. The view title's attributes have tags of
their own, `VIEW_TITLE` and `VIEW_SCALE`, so no tag names two fields.
[Title blocks](../docs/title-blocks.md) has more, and the way to use a firm's
own border.

The trees, the property corners, the north arrow and the view title are blocks
too. The tree and the property corner are in the plan and in the legend, so
Expand All @@ -93,10 +94,10 @@ radius in the plan and at 3/16 inch in the legend.

The sheet is drawn to a standard of its own, `standard`, which extends
`BUILT_IN_STANDARD` with the layer `V-TREE`. Each layer is named, and its color,
linetype, pen and plot flag are the standard's. The border names the standard's
heavy pen. The standard's linetype scale is a length of paper, 1/2. Each text
names a role of the standard, which gives its text style and the height it
plots at; the title block's texts are in a text style of its own, `NOTES`. The
linetype, pen and plot flag are the standard's. The standard's linetype scale
is a length of paper, 1/2. Each text names a role of the standard, which gives
its text style and the height it plots at; the title block's texts are in a
text style of its own, `TITLE BLOCK`. The
view `plan` is at a scale of the standard, `1in-10ft`. Draw it at `1in-20ft`
and nothing on the sheet moves: the plan is half as large in its viewport, and
its text keeps its plotted height. The sheet holds the plan at 1" = 10' and at
Expand Down
7 changes: 5 additions & 2 deletions examples/lib/drafting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,11 @@ export function leader(
});
}

/** A slim closed arrowhead with its tip at `tip`, pointing away from `from`. */
export function arrowhead(d: Pen, tip: Point, from: Point, length: number): void {
/**
* A slim closed arrowhead with its tip at `tip`, pointing away from `from`. It draws no text, so
* a drawing whose texts name roles of a standard can be given.
*/
export function arrowhead(d: Pick<Pen, "polyline">, tip: Point, from: Point, length: number): void {
const dx = tip[0] - from[0];
const dy = tip[1] - from[1];
const size = Math.hypot(dx, dy);
Expand Down
Loading
Loading