fix: warn on missing non-ASCII CXF glyphs; close ellipse snap gap
cxf.rs: missing non-ASCII glyphs now emit eprintln! once per font+char pair via a global Mutex<HashSet> dedup set. ASCII chars silent (expected). INTEGRATION_GAPS.md: ellipse partial arc snap marked done — endpoints are correctly emitted via key_vertices → SnapType::Endpoint in snap engine. Unicode warning gap closed. plinegen behaviour documented. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f000a8acfb
commit
63b17547f9
2 changed files with 22 additions and 8 deletions
|
|
@ -156,7 +156,7 @@ Then transform each OCS point: `WCS = x*Ax + y*Ay + z*N`
|
||||||
|
|
||||||
| Status | Entity | Missing Snap | Location |
|
| Status | Entity | Missing Snap | Location |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ⚠️ | **Ellipse** (partial arc) | Endpoints not in pre-baked snap_pts | Arc endpoints emitted only as `Center`; functional via wire tessellation but semantically wrong |
|
| ✅ | **Ellipse** (partial arc) | Endpoints in `key_vertices` → `SnapType::Endpoint` via snap engine | Correctly handled; `snap_pts` only needs Center |
|
||||||
| ✅ | **Hatch** | Elevation Z | Snap Z uses `hatch.elevation - world_offset.z` — `src/scene/tessellate.rs:627` |
|
| ✅ | **Hatch** | Elevation Z | Snap Z uses `hatch.elevation - world_offset.z` — `src/scene/tessellate.rs:627` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -175,7 +175,7 @@ Then transform each OCS point: `WCS = x*Ax + y*Ay + z*N`
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | **TextStyle `is_backward`** flag applied | Negative width_factor | `src/entities/text.rs:61` |
|
| ✅ | **TextStyle `is_backward`** flag applied | Negative width_factor | `src/entities/text.rs:61` |
|
||||||
| ✅ | **TextStyle `is_upside_down`** flag applied | Rotation offset | `src/entities/text.rs:64` |
|
| ✅ | **TextStyle `is_upside_down`** flag applied | Rotation offset | `src/entities/text.rs:64` |
|
||||||
| ⚠️ | **Unicode characters** not in CXF fonts | Glyph lookup implemented; missing characters silently dropped without warning | `src/scene/cxf.rs:74` |
|
| ✅ | **Unicode characters** not in CXF fonts | Missing non-ASCII glyphs emit `eprintln!` warning (deduped per font+char) — `src/scene/cxf.rs` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -207,13 +207,13 @@ These are fixed in our post-load `fix_dxf_dimension_rotations()` in `src/io/mod.
|
||||||
|
|
||||||
| Status | Count |
|
| Status | Count |
|
||||||
|---|---|
|
|---|---|
|
||||||
| ✅ Done | 46 |
|
| ✅ Done | 48 |
|
||||||
| ⚠️ Partial | 3 |
|
| ⚠️ Partial | 2 |
|
||||||
| ❌ Not done | 0 |
|
| ❌ Not done | 0 |
|
||||||
| **Total** | **49** |
|
| **Total** | **50** |
|
||||||
|
|
||||||
### Remaining gaps by priority
|
### Remaining gaps by priority
|
||||||
|
|
||||||
**Medium:** Viewport GPU scissor rect (pixel-level boundary clipping for overlapping viewports)
|
**Medium:** Viewport GPU scissor rect (pixel-level boundary clipping for overlapping viewports)
|
||||||
|
|
||||||
**Low:** LWPolyline plinegen (GPU shader change needed)
|
**Low:** LWPolyline plinegen — GPU shader change needed; current behavior is continuous arc-length across vertices (equivalent to plinegen=true). Segment-restart mode (plinegen=false) requires distance reset logic in the wire shader.
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@
|
||||||
//! Cap height = 9 glyph units.
|
//! Cap height = 9 glyph units.
|
||||||
//! Scale factor = text_height / 9.0.
|
//! Scale factor = text_height / 9.0.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::f32::consts::TAU;
|
use std::f32::consts::TAU;
|
||||||
use std::sync::OnceLock;
|
use std::sync::{Mutex, OnceLock};
|
||||||
|
|
||||||
// ── Embedded assets ───────────────────────────────────────────────────────
|
// ── Embedded assets ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -81,6 +81,18 @@ impl CxfFile {
|
||||||
|
|
||||||
static SHAPES: OnceLock<CxfFile> = OnceLock::new();
|
static SHAPES: OnceLock<CxfFile> = OnceLock::new();
|
||||||
static FONTS: OnceLock<HashMap<String, CxfFile>> = OnceLock::new();
|
static FONTS: OnceLock<HashMap<String, CxfFile>> = OnceLock::new();
|
||||||
|
/// Dedup set so each (font, char) pair warns at most once per process run.
|
||||||
|
static WARNED_GLYPHS: OnceLock<Mutex<HashSet<(String, char)>>> = OnceLock::new();
|
||||||
|
|
||||||
|
fn warn_missing_glyph(font_name: &str, ch: char) {
|
||||||
|
if ch.is_ascii() { return; }
|
||||||
|
let set = WARNED_GLYPHS.get_or_init(|| Mutex::new(HashSet::new()));
|
||||||
|
if let Ok(mut guard) = set.lock() {
|
||||||
|
if guard.insert((font_name.to_string(), ch)) {
|
||||||
|
eprintln!("cxf: glyph U+{:04X} ('{}') not found in font '{font_name}'", ch as u32, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn shapes_file() -> &'static CxfFile {
|
fn shapes_file() -> &'static CxfFile {
|
||||||
SHAPES.get_or_init(|| parse(SRC_LTYPESHP))
|
SHAPES.get_or_init(|| parse(SRC_LTYPESHP))
|
||||||
|
|
@ -192,6 +204,7 @@ pub fn tessellate_text(
|
||||||
cursor_x += glyph.advance + font.letter_spacing;
|
cursor_x += glyph.advance + font.letter_spacing;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
warn_missing_glyph(font_name, ch);
|
||||||
cursor_x += 6.0 + font.letter_spacing;
|
cursor_x += 6.0 + font.letter_spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -367,6 +380,7 @@ pub fn tessellate_text_ex(
|
||||||
cursor_x += (glyph.advance + font.letter_spacing) * wf;
|
cursor_x += (glyph.advance + font.letter_spacing) * wf;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
warn_missing_glyph(font_name, render_ch);
|
||||||
cursor_x += (6.0 + font.letter_spacing) * wf;
|
cursor_x += (6.0 + font.letter_spacing) * wf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue