Files
OneCAD/crates/io/src/sketch2d.rs
T
bherbruckandClaude Opus 5.5 296683229d Rename SolveCraft to SolidCraft everywhere, with compatibility shims (#389)
* WIP deep rename (not for push)

* WIP2

* WIP3

* WIP4 wxs fix

* rustfmt

* Rename the remaining identifiers in merged crash-report code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:17:01 -04:00

71 lines
2.1 KiB
Rust

//! 2D drawing exchange for sketches: DXF (ASCII, read and write) and SVG (read). Readers produce
//! plain 2D geometry in millimetres; the engine turns it into sketch curves.
use solidcraft_geom::Vec2;
/// One imported 2D entity (millimetres, y up).
#[derive(Clone, Debug, PartialEq)]
pub enum Geom2 {
Point(Vec2),
Line(Vec2, Vec2),
Circle(Vec2, f64),
/// Counter-clockwise arc around `c` from `a` to `b`.
Arc {
c: Vec2,
a: Vec2,
b: Vec2,
},
/// Full ellipse: centre, end of the major axis, minor radius.
Ellipse {
c: Vec2,
major: Vec2,
minor: f64,
},
/// Spline through (`control == false`) or over (`control`) the points.
Spline {
pts: Vec<Vec2>,
control: bool,
degree: u8,
},
/// Quadratic Bézier / conic.
Conic {
a: Vec2,
apex: Vec2,
b: Vec2,
rho: f64,
},
Text {
text: String,
at: Vec2,
height: f64,
angle: f64,
},
}
/// Most entities one file may produce.
pub const MAX_ENTITIES: usize = 200_000;
/// Largest drawing file we read.
pub const MAX_DRAWING_BYTES: usize = 64 << 20;
/// Counter-clockwise arc from `p0` to `p1` with DXF bulge `b` (tan of a quarter of the
/// included angle, negative = clockwise).
pub(crate) fn bulge_arc(p0: Vec2, p1: Vec2, b: f64) -> Option<Geom2> {
if b.abs() < 1e-12 || !b.is_finite() {
return Some(Geom2::Line(p0, p1));
}
let chord = p1 - p0;
let l = chord.len();
if l < 1e-12 {
return None;
}
let theta = 4.0 * b.atan();
let r = l / (2.0 * (theta / 2.0).sin()).abs();
// Centre on the perpendicular bisector, to the left for counter-clockwise bulges.
let mid = (p0 + p1) * 0.5;
let h = r * (theta / 2.0).cos().abs();
let left = chord.perp() / l;
let sign = if theta.abs() > std::f64::consts::PI { -1.0 } else { 1.0 };
let c = if b > 0.0 { mid + left * (h * sign) } else { mid - left * (h * sign) };
Some(if b > 0.0 { Geom2::Arc { c, a: p0, b: p1 } } else { Geom2::Arc { c, a: p1, b: p0 } })
}