Commit Graph
6 Commits
Author SHA1 Message Date
Chris YehandClaude Opus 5 4826cd7989 fix(pdf): Flate-compress the exported PDF streams
printpdf 0.9's `PdfSaveOptions::optimize` is a no-op — its `doc.compress()`
call is commented out — so every page's content stream (megabytes of vector
operators for a CAD sheet) was written uncompressed: a 16-sheet drawing set
exported as 280 MB. Serialise through `printpdf::to_lopdf_doc` and run
lopdf's `compress()` before writing; the same export is now 49 MB and
readers see ordinary FlateDecode streams.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 22:02:13 +08:00
Chris YehandClaude Opus 5 876513d009 fix(mtext): wrap between ideographs; paragraph indents and tabs in text-height units
Two layout defects that together broke every numbered note in a Chinese
drawing:

- Words were split on whitespace only, so a Chinese sentence — which has no
  spaces — was one unbreakable word. When it did not fit after "7.<tab>" the
  whole sentence dropped to the next line and still ran past the column.
  Ideographic text may break between any two characters except before a
  closing mark or after an opening one (the basic kinsoku rule); the atom
  splitter now emits those break opportunities.

- `\pxi…,l…,r…,t…;` paragraph indents and tab stops are multiples of the
  text height, and the first-line indent is relative to the left indent
  (a hanging list is `i-1.5,l1.5`). They were applied as raw drawing units,
  i.e. a fraction of a unit, so wrapped lines snapped back to the margin
  and the number/tab column collapsed. Scale them by the entity height and
  resolve the first line from the left indent.

Adds a layout test: a 40-ideograph paragraph in a 30-unit column wraps into
several lines, none wider than the column.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 22:02:13 +08:00
Chris YehandClaude Opus 5 24f8e124d5 fix(text): re-lay-out cached glyph quads after the SDF atlas grows
Glyph quads bake the atlas UV of their tile. `grow_height` rescales every
cached entry's V and bumps the atlas generation, and the tessellation memo
folds that generation in — but the caches that hold finished wires do not:
the resident wire set is keyed by geometry epoch, block definitions by
block epoch, and a full build can grow the atlas part-way through (a CJK
sheet set bakes thousands of tiles on first sight). Text tessellated before
the growth then samples the wrong tiles for as long as those caches live,
which on a big drawing is forever: whole tables of scrambled glyphs, and
the block contents stayed scrambled even after a REGEN.

- `resident_wires_for` rebuilds (dropping the block definition cache) until
  the atlas generation is stable across the pass.
- `Scene::update` compares the live generation with the one the scene's
  caches were built against and bumps geometry once when it moved, so a
  later growth (opening a layout, editing text) re-lays-out everything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 21:01:05 +08:00
Chris YehandClaude Opus 5 ff4981ffe6 feat(text): read unifont and big-font .shx files; pair a style's big font
`shx.rs` only accepted the classic `AutoCAD-86 shapes 1.x` container, so
every modern Autodesk font (`txt.shx`, `simplex.shx`, `romans.shx`, … are
`unifont 1.0`) and every Asian big font (`chineset.shx`, `hztxt.shx`,
`bigfont.shx` — `bigfont 1.0`) was rejected and text fell back to the LFF
substitutes and TrueType fallback glyphs. Drawings authored with SHX big
fonts (the norm for Chinese / Japanese / Korean sheets) never showed their
real glyphs.

- Parse all three containers. Unifont glyphs are keyed by Unicode; big-font
  glyphs by their double-byte code from a sparse hash table of
  (code, length, offset) entries. Big fonts reference subshapes with a
  two-byte `7, 0, hi, lo`.
- `bigfont_glyph` encodes a character with encoding_rs (Big5 / GBK /
  Shift_JIS / EUC-KR, most likely first for the file name) and takes the
  first code the font has.
- `Face::WithBig` pairs a style's big font with its primary face: full-width
  characters come from the big font, everything else from the primary —
  how a STYLE with a "Big Font" behaves in AutoCAD. `resolve_text_style`
  resolves `big_font_file` like the primary (next to the drawing, then the
  user fonts folder) and rides it along in the font name.
- The missing-fonts dialog lists unresolvable big fonts too.

Unit tests cover a synthetic big font (Big5 lookup, cap-height scaling, no
aliasing of unknown codes), a synthetic unifont, and the pairing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 21:01:05 +08:00
Chris YehandClaude Opus 5 0b522ceb86 fix(text): size TrueType fallback ideographs by the em box, like a big font
When a text style's SHX / stroke font lacks a character, the glyph comes
from a system TrueType font through `ttf_glyph::fallback_glyph`. That
substitute was normalised to the Latin cap height (9 units = text height),
which is right for Latin, Greek or Cyrillic stand-ins but wrong for CJK:
an ideograph fills the whole em square, and 1 em is 1.3–1.5 cap heights in
every common CJK font (DFKai-SB has no OS/2 cap height at all, so it fell
to the 0.7 em guess). Every substituted Chinese character therefore came
out ~40 % taller and wider than the big font (`chineset.shx`, `hztxt.shx`,
…) the drawing was authored with, and whole lines of notes ran past their
frames.

A big font draws an ideograph one text height tall and one text height
wide, so size full-width / ideographic fallback glyphs by their em box
instead. Other scripts keep the cap-height normalisation. Real TrueType
styles (`Face::Ttf`, shaped runs) are unchanged.

Adds a unit test that a fallback `中` advances by about one text height and
its ink fits the text height (skipped on machines without a CJK font).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 18:14:26 +08:00
Chris YehandClaude Opus 5 52d766b488 fix(plot): scale wide polyline band width into paper units through viewports
`viewport_content_wires` projects model-space wires into paper coordinates
for plotting: the points and the linetype stations are multiplied by the
viewport scale, but `world_width` (the band width of a wide polyline) was
copied unchanged. The PDF / print exporter strokes that band at
`world_width` in paper millimetres, so a 15-unit-wide bus bar seen through
a 1:100 viewport came out as a ~21 mm black blob instead of 0.15 mm, and
every single-line diagram sheet plotted as solid black shapes.

Scale `world_width` by the viewport scale alongside the points, and keep
the per-point taper widths in step (or drop them when clipping changed the
vertex count, so they cannot misalign). Negative (fixed pixel) and zero
(lineweight) widths are left untouched.

Adds a regression test that plots a 15-unit-wide polyline through a 1:10
viewport and expects a 1.5-unit band in the projected plot wires.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 17:28:09 +08:00