forked from 1b-agent/opencadstudio-upstream
SHX: fractional arcs span their octants (#1638)
The end angle subtracted a whole octant less the end offset, so the arc in the ISOCP 9 stopped about 45 degrees short and the glyph shrank to 0.68 of the cap height; clockwise arcs and n = 0 (a full circle) drew nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ec603f1c8f
commit
c70a217e3f
1 file changed
+40
-6
+40
-6
@@ -617,13 +617,21 @@ fn interpret(
|
|||||||
if n_oct == 0.0 {
|
if n_oct == 0.0 {
|
||||||
n_oct = 8.0;
|
n_oct = 8.0;
|
||||||
}
|
}
|
||||||
|
// The arc spans `n_oct` octants from `start_oct`, starting
|
||||||
|
// `so`/256 of an octant into the first one and ending `eo`/256
|
||||||
|
// into the last (0 = on its far boundary) (#1638).
|
||||||
let q = std::f64::consts::FRAC_PI_4;
|
let q = std::f64::consts::FRAC_PI_4;
|
||||||
let start = start_oct * q + so * q / 256.0 * if cw { -1.0 } else { 1.0 };
|
let dir = if cw { -1.0 } else { 1.0 };
|
||||||
let total = n_oct * q;
|
let start = (start_oct + dir * so / 256.0) * q;
|
||||||
let sweep_mag = total - so * q / 256.0 - (255.0 - eo) * q / 256.0
|
let end = if eo == 0.0 {
|
||||||
+ if eo == 0.0 { 0.0 } else { 0.0 };
|
(start_oct + dir * n_oct) * q
|
||||||
let sweep = sweep_mag.max(0.0) * if cw { -1.0 } else { 1.0 };
|
} else {
|
||||||
emit_arc(st, cur, out, radius, start, sweep);
|
(start_oct + dir * (n_oct - 1.0 + eo / 256.0)) * q
|
||||||
|
};
|
||||||
|
let sweep = end - start;
|
||||||
|
if sweep * dir > 0.0 {
|
||||||
|
emit_arc(st, cur, out, radius, start, sweep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xC => {
|
0xC => {
|
||||||
@@ -754,4 +762,30 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert!(font_glyph(&path, 'B' as u16).is_none());
|
assert!(font_glyph(&path, 'B' as u16).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `9` program of the ISOCP fonts: a fractional arc into the stem,
|
||||||
|
/// then octant arcs. Its ink spans 36 font units, the cap height; the
|
||||||
|
/// fractional arc used to end short and drop the glyph to ~0.68 (#1638).
|
||||||
|
#[test]
|
||||||
|
fn fractional_arc_spans_its_octants() {
|
||||||
|
const NINE: [u8; 25] = [
|
||||||
|
0x02, 0x08, 0x0a, 0x02, 0x01, 0x0b, 0x6c, 0x00, 0x00, 0x12, 0x62, 0xb4, 0x0a, 0x08,
|
||||||
|
0x04, 0x4c, 0x0a, 0x08, 0x42, 0x80, 0x02, 0x08, 0x06, 0xee, 0x00,
|
||||||
|
];
|
||||||
|
let mut b = b"AutoCAD-86 unifont 1.0\r\n\x1a".to_vec();
|
||||||
|
b.extend_from_slice(&2u32.to_le_bytes());
|
||||||
|
let head: Vec<u8> = [b"UNI\x00".as_slice(), &[36u8, 8, 2, 0, 0, 0]].concat();
|
||||||
|
b.extend_from_slice(&(head.len() as u16).to_le_bytes());
|
||||||
|
b.extend_from_slice(&head);
|
||||||
|
let glyph: Vec<u8> = [b"\x00".as_slice(), &NINE].concat();
|
||||||
|
b.extend_from_slice(&('9' as u16).to_le_bytes());
|
||||||
|
b.extend_from_slice(&(glyph.len() as u16).to_le_bytes());
|
||||||
|
b.extend_from_slice(&glyph);
|
||||||
|
let path = tmp("nine.shx", &b);
|
||||||
|
let g = font_glyph(&path, '9' as u16).expect("glyph for 9");
|
||||||
|
let ys = g.strokes.iter().flatten().map(|p| p[1]);
|
||||||
|
let (lo, hi) = ys.fold((f32::MAX, f32::MIN), |(lo, hi), y| (lo.min(y), hi.max(y)));
|
||||||
|
// 36 font units at above = 36 → the 9-unit cap height.
|
||||||
|
assert!(((hi - lo) - 9.0).abs() < 0.05, "ink height {}", hi - lo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user