feat(points): point style commands + DDPTYPE dialog, viewport-aware size

Points could only render as a 1px dot — no way to change PDMODE/PDSIZE.

- PDMODE / PDSIZE commands set the header value and rebuild the glyphs.
- DDPTYPE opens a Point Style dialog: a 5x4 grid of rendered glyphs
  (shape x enclosure), a size field, and relative/absolute radios.
- Relative (<=0) PDSIZE now sizes from the current world-per-pixel so the
  marker stays a roughly constant on-screen size across zoom, rebuilding
  on zoom via the existing camera-generation cache key. Absolute (>0)
  scales with the world as before. Switching to absolute with a zero size
  seeds a positive value from the on-screen size so it stays representable.

Part of the #100 extensibility epic (point style surfaced in #106).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-17 11:13:12 +03:00
1 parent a3b8acb59e
commit 96ec672d5b
14 files changed
+456 -45

No files matched your search

+1 -1
View File
@@ -450,7 +450,7 @@ fn tessellate_sub_local(
// top-level MTEXT outside blocks the colour split is preserved via the
// hot path in `tessellate_entity`.
let mut wires_out = tessellate::tessellate(
doc, h, sub, false, sub_color, pat_len, pat, lw_px, local_offset, anno_scale,
doc, h, sub, false, sub_color, pat_len, pat, lw_px, local_offset, anno_scale, None,
);
if wires_out.is_empty() {
return None;
+6 -1
View File
@@ -42,6 +42,7 @@ pub fn tessellate(
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
world_per_pixel: Option<f32>,
) -> Vec<WireModel> {
let color = if selected {
WireModel::SELECTED
@@ -87,7 +88,11 @@ pub fn tessellate(
}
// ── Try the truck path first ───────────────────────────────────────────
if let Some(te) = convert(entity, document) {
// Relative-PDSIZE points size their glyph from the current zoom so they
// stay a roughly constant on-screen size; otherwise the header-driven path.
let te = crate::entities::point::relative_truck(entity, document, world_per_pixel)
.or_else(|| convert(entity, document));
if let Some(te) = te {
match te.object {
// ── Text / MText: pre-tessellated glyph strokes ───────────────
//
+3
View File
@@ -7109,6 +7109,7 @@ fn tessellate_entity(
1.5,
world_offset,
1.0,
world_per_pixel,
);
let ab = entity_aabb(e, world_offset);
for w in &mut wires {
@@ -7423,6 +7424,7 @@ fn tessellate_entity(
sub_line_weight_px,
world_offset,
anno_scale,
world_per_pixel,
);
for w in &mut wires {
w.name = h.value().to_string();
@@ -7584,6 +7586,7 @@ fn tessellate_entity(
line_weight_px,
world_offset,
anno_scale,
world_per_pixel,
);
for b in &mut bases {
b.aci = aci;