mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 10:56:51 -06:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
567f9b96f5 | ||
|
|
e6368ff496 |
@@ -119,7 +119,7 @@ fn style(s: &Session) -> String {
|
||||
s.doc().map(|d| d.header.str("DIMSTYLE", "Standard")).unwrap_or_else(|_| "Standard".into())
|
||||
}
|
||||
|
||||
fn dim(s: &Session, kind: DimKind, defpt: Vec2, p13: Vec2, p14: Vec2, p15: Vec2, p16: Vec2, text: &str) -> EntityKind {
|
||||
fn dim(s: &Session, kind: DimKind, defpt: Vec2, p13: Vec2, p14: Vec2, p15: Vec2, text: &str) -> EntityKind {
|
||||
EntityKind::Dimension(Dimension {
|
||||
kind,
|
||||
defpt: v3(defpt),
|
||||
@@ -127,7 +127,7 @@ fn dim(s: &Session, kind: DimKind, defpt: Vec2, p13: Vec2, p14: Vec2, p15: Vec2,
|
||||
p13: v3(p13),
|
||||
p14: v3(p14),
|
||||
p15: v3(p15),
|
||||
p16: v3(p16),
|
||||
p16: v3(Vec2::ZERO),
|
||||
text: text.into(),
|
||||
style: style(s),
|
||||
measurement: 0.0,
|
||||
@@ -204,7 +204,10 @@ fn angular_from_lines(s: &Session, h1: Handle, h2: Handle, at: Vec2) -> Option<E
|
||||
// The picked leg end goes last in each pair, so the renderer measures between p14 and p15.
|
||||
let (o1, t1) = if s1 == AssocSnap::Start { (a2, AssocSnap::End) } else { (a1, AssocSnap::Start) };
|
||||
let (o2, t2) = if s2 == AssocSnap::Start { (b2, AssocSnap::End) } else { (b1, AssocSnap::Start) };
|
||||
let k = dim(s, DimKind::Angular, o2, o1, p1, p2, at, "");
|
||||
let mut k = dim(s, DimKind::Angular, o2, o1, p1, p2, "");
|
||||
if let EntityKind::Dimension(d) = &mut k {
|
||||
d.p16 = v3(at);
|
||||
}
|
||||
let mut assoc = Vec::new();
|
||||
if assoc_enabled(s) {
|
||||
assoc = vec![
|
||||
@@ -224,7 +227,7 @@ fn run_linear(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
};
|
||||
let at = point_req("dimlinear", p, "at")?;
|
||||
let rot = p.get("rotation").and_then(Value::as_f64).map(f64::to_radians);
|
||||
let k = dim(s, linear_kind(a, b, at, rot, false), at, a, b, Vec2::ZERO, Vec2::ZERO, str_param(p, "text").unwrap_or(""));
|
||||
let k = dim(s, linear_kind(a, b, at, rot, false), at, a, b, Vec2::ZERO, str_param(p, "text").unwrap_or(""));
|
||||
Ok(json!({ "handle": add_dim(s, k)?.hex() }))
|
||||
}
|
||||
|
||||
@@ -232,7 +235,7 @@ fn run_aligned(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let a = point_req("dimaligned", p, "p1")?;
|
||||
let b = point_req("dimaligned", p, "p2")?;
|
||||
let at = point_req("dimaligned", p, "at")?;
|
||||
let k = dim(s, DimKind::Aligned, at, a, b, Vec2::ZERO, Vec2::ZERO, str_param(p, "text").unwrap_or(""));
|
||||
let k = dim(s, DimKind::Aligned, at, a, b, Vec2::ZERO, str_param(p, "text").unwrap_or(""));
|
||||
Ok(json!({ "handle": add_dim(s, k)?.hex() }))
|
||||
}
|
||||
|
||||
@@ -260,9 +263,9 @@ fn radial(s: &mut Session, p: &Value, diameter: bool) -> Result<Value> {
|
||||
return Err(bad(id, "`point` must differ from `center`"));
|
||||
}
|
||||
let k = if diameter {
|
||||
dim(s, DimKind::Diameter, c + (c - pt), Vec2::ZERO, Vec2::ZERO, pt, Vec2::ZERO, "")
|
||||
dim(s, DimKind::Diameter, c + (c - pt), Vec2::ZERO, Vec2::ZERO, pt, "")
|
||||
} else {
|
||||
dim(s, DimKind::Radius, c, Vec2::ZERO, Vec2::ZERO, pt, Vec2::ZERO, "")
|
||||
dim(s, DimKind::Radius, c, Vec2::ZERO, Vec2::ZERO, pt, "")
|
||||
};
|
||||
let k = match at {
|
||||
Some(at) => text_at(k, at),
|
||||
@@ -307,7 +310,7 @@ fn run_angular(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
_ => return Err(bad("dimangular", "object is not an arc")),
|
||||
};
|
||||
let g = cadcraft_geom::Arc::new(a.center.xy(), a.radius, a.start, a.end);
|
||||
let k = dim(s, DimKind::Angular3P, at, g.start_point(), g.end_point(), g.center, Vec2::ZERO, "");
|
||||
let k = dim(s, DimKind::Angular3P, at, g.start_point(), g.end_point(), g.center, "");
|
||||
return Ok(json!({ "handle": add_dim(s, k)?.hex() }));
|
||||
}
|
||||
let v = point_req("dimangular", p, "vertex")?;
|
||||
@@ -317,7 +320,7 @@ fn run_angular(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if v.near(a, 1e-12) || v.near(b, 1e-12) {
|
||||
return Err(bad("dimangular", "`p1` and `p2` must differ from `vertex`"));
|
||||
}
|
||||
let k = dim(s, DimKind::Angular3P, at, a, b, v, Vec2::ZERO, "");
|
||||
let k = dim(s, DimKind::Angular3P, at, a, b, v, "");
|
||||
Ok(json!({ "handle": add_dim(s, k)?.hex() }))
|
||||
}
|
||||
|
||||
@@ -329,7 +332,7 @@ fn run_arclen(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
_ => return Err(bad("dimarc", "object is not an arc")),
|
||||
};
|
||||
let ga = cadcraft_geom::Arc::new(a.center.xy(), a.radius, a.start, a.end);
|
||||
let k = dim(s, DimKind::ArcLength, at, ga.start_point(), ga.end_point(), ga.center, Vec2::ZERO, "");
|
||||
let k = dim(s, DimKind::ArcLength, at, ga.start_point(), ga.end_point(), ga.center, "");
|
||||
Ok(json!({ "handle": add_dim(s, k)?.hex() }))
|
||||
}
|
||||
|
||||
@@ -337,7 +340,7 @@ fn run_ordinate(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let f = point_req("dimordinate", p, "feature")?;
|
||||
let l = point_req("dimordinate", p, "leader")?;
|
||||
let xtype = p.get("xtype").and_then(Value::as_bool).unwrap_or((l - f).y.abs() > (l - f).x.abs());
|
||||
let k = dim(s, DimKind::Ordinate { x_type: xtype }, Vec2::ZERO, f, l, Vec2::ZERO, Vec2::ZERO, "");
|
||||
let k = dim(s, DimKind::Ordinate { x_type: xtype }, Vec2::ZERO, f, l, Vec2::ZERO, "");
|
||||
Ok(json!({ "handle": add_dim(s, k)?.hex() }))
|
||||
}
|
||||
|
||||
@@ -1059,7 +1062,7 @@ impl Interactive for LinearM {
|
||||
}
|
||||
(_, Input::Point(at)) => {
|
||||
let (Some(&a), Some(&b)) = (self.pts.first(), self.pts.get(1)) else { return Ok(Step::Continue) };
|
||||
let k = self.text.apply(dim(s, linear_kind(a, b, at, self.rotation, self.aligned), at, a, b, Vec2::ZERO, Vec2::ZERO, ""));
|
||||
let k = self.text.apply(dim(s, linear_kind(a, b, at, self.rotation, self.aligned), at, a, b, Vec2::ZERO, ""));
|
||||
add_dim(s, k)?;
|
||||
if let Some(EntityKind::Dimension(d)) = s.last_dim.and_then(|h| s.doc().ok()?.entity(h).map(|e| e.kind.clone())) {
|
||||
let st = s.doc()?.dim_style(&d.style).cloned().unwrap_or_default();
|
||||
@@ -1086,7 +1089,7 @@ impl Interactive for LinearM {
|
||||
fn preview(&self, s: &Session, c: Vec2) -> Vec<EntityKind> {
|
||||
match self.pts.as_slice() {
|
||||
[a] => vec![super::helpers::line(*a, c)],
|
||||
[a, b] => vec![self.text.apply(dim(s, linear_kind(*a, *b, c, self.rotation, self.aligned), c, *a, *b, Vec2::ZERO, Vec2::ZERO, ""))],
|
||||
[a, b] => vec![self.text.apply(dim(s, linear_kind(*a, *b, c, self.rotation, self.aligned), c, *a, *b, Vec2::ZERO, ""))],
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -1105,9 +1108,9 @@ impl RadialM {
|
||||
fn kind(&self, s: &Session, c: Vec2, r: f64, at: Vec2) -> EntityKind {
|
||||
let pt = c + (at - c).normalized() * r;
|
||||
let k = self.text.apply(if self.diameter {
|
||||
dim(s, DimKind::Diameter, c + (c - pt), Vec2::ZERO, Vec2::ZERO, pt, Vec2::ZERO, "")
|
||||
dim(s, DimKind::Diameter, c + (c - pt), Vec2::ZERO, Vec2::ZERO, pt, "")
|
||||
} else {
|
||||
dim(s, DimKind::Radius, c, Vec2::ZERO, Vec2::ZERO, pt, Vec2::ZERO, "")
|
||||
dim(s, DimKind::Radius, c, Vec2::ZERO, Vec2::ZERO, pt, "")
|
||||
});
|
||||
text_at(k, at)
|
||||
}
|
||||
@@ -1240,7 +1243,7 @@ impl Interactive for AngularM {
|
||||
([h1, h2], None) => angular_from_lines(s, *h1, *h2, at),
|
||||
_ => None,
|
||||
};
|
||||
let k = k.unwrap_or_else(|| dim(s, DimKind::Angular3P, at, a, b, v, Vec2::ZERO, ""));
|
||||
let k = k.unwrap_or_else(|| dim(s, DimKind::Angular3P, at, a, b, v, ""));
|
||||
add_dim(s, self.text.apply(k))?;
|
||||
Ok(Step::Done)
|
||||
}
|
||||
@@ -1306,9 +1309,7 @@ impl Interactive for AngularM {
|
||||
}
|
||||
}
|
||||
fn preview(&self, s: &Session, c: Vec2) -> Vec<EntityKind> {
|
||||
self.geometry()
|
||||
.map(|(v, a, b)| vec![self.text.apply(dim(s, DimKind::Angular3P, self.located(v, c), a, b, v, Vec2::ZERO, ""))])
|
||||
.unwrap_or_default()
|
||||
self.geometry().map(|(v, a, b)| vec![self.text.apply(dim(s, DimKind::Angular3P, self.located(v, c), a, b, v, ""))]).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1384,7 +1385,7 @@ impl Interactive for ArcLenM {
|
||||
Ok(Step::Continue)
|
||||
}
|
||||
(Some(g), Input::Point(at)) => {
|
||||
add_dim(s, self.text.apply(dim(s, DimKind::ArcLength, at, g.start_point(), g.end_point(), g.center, Vec2::ZERO, "")))?;
|
||||
add_dim(s, self.text.apply(dim(s, DimKind::ArcLength, at, g.start_point(), g.end_point(), g.center, "")))?;
|
||||
Ok(Step::Done)
|
||||
}
|
||||
(Some(_), Input::Keyword(k)) => {
|
||||
@@ -1403,9 +1404,7 @@ impl Interactive for ArcLenM {
|
||||
if self.partial.is_some() {
|
||||
return Vec::new();
|
||||
}
|
||||
self.arc
|
||||
.map(|g| vec![self.text.apply(dim(s, DimKind::ArcLength, c, g.start_point(), g.end_point(), g.center, Vec2::ZERO, ""))])
|
||||
.unwrap_or_default()
|
||||
self.arc.map(|g| vec![self.text.apply(dim(s, DimKind::ArcLength, c, g.start_point(), g.end_point(), g.center, ""))]).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1420,7 +1419,7 @@ struct OrdinateM {
|
||||
impl OrdinateM {
|
||||
fn kind(&self, s: &Session, f: Vec2, l: Vec2) -> EntityKind {
|
||||
let x = self.xtype.unwrap_or((l - f).y.abs() > (l - f).x.abs());
|
||||
self.text.apply(dim(s, DimKind::Ordinate { x_type: x }, Vec2::ZERO, f, l, Vec2::ZERO, Vec2::ZERO, ""))
|
||||
self.text.apply(dim(s, DimKind::Ordinate { x_type: x }, Vec2::ZERO, f, l, Vec2::ZERO, ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1570,7 +1570,7 @@ impl Interactive for XlineM2 {
|
||||
// RECTANG with Area / Dimensions / Rotation / Width / Elevation / Thickness
|
||||
// =====================================================================================
|
||||
|
||||
fn rect_kind(first: Vec2, w: f64, h: f64, rot: f64, fillet: f64, chamfer: (f64, f64), width: f64, elevation: f64) -> EntityKind {
|
||||
fn rect_kind(first: Vec2, (w, h): (f64, f64), rot: f64, fillet: f64, chamfer: (f64, f64), width: f64, elevation: f64) -> EntityKind {
|
||||
let local = rect_with_corners(Vec2::ZERO, Vec2::new(w, h), fillet, chamfer);
|
||||
let vs = local.into_iter().map(|v| PolyVertex { p: first + v.p.rotate(rot), ..v }).collect();
|
||||
let mut k = lwpoly(vs, true);
|
||||
@@ -1629,7 +1629,7 @@ pub(crate) fn run_rectang2(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
return Err(bad("rectang", "rectangle has no area"));
|
||||
}
|
||||
let first = if centered { a - Vec2::new(w / 2.0, h / 2.0).rotate(rot) } else { a };
|
||||
let k = rect_kind(first, w, h, rot, fillet, ch, width, f64_or(p, "elevation", 0.0));
|
||||
let k = rect_kind(first, (w, h), rot, fillet, ch, width, f64_or(p, "elevation", 0.0));
|
||||
let hd = s.add_entity(k)?;
|
||||
let th = f64_or(p, "thickness", 0.0);
|
||||
if th != 0.0 {
|
||||
@@ -1682,7 +1682,7 @@ impl RectM2 {
|
||||
return Err(other("The rectangle has no area."));
|
||||
}
|
||||
let first = self.origin(w, h).unwrap_or(a);
|
||||
let hd = s.add_entity(rect_kind(first, w, h, self.rotation, self.fillet, self.chamfer, self.width, self.elevation))?;
|
||||
let hd = s.add_entity(rect_kind(first, (w, h), self.rotation, self.fillet, self.chamfer, self.width, self.elevation))?;
|
||||
if self.thickness != 0.0 {
|
||||
let t = self.thickness;
|
||||
s.doc_mut()?.modify_entity(hd, |e| e.common.thickness = t)?;
|
||||
@@ -1862,7 +1862,7 @@ impl Interactive for RectM2 {
|
||||
}
|
||||
match self.other_corner(c).and_then(|(w, h)| self.origin(w, h).map(|a| (a, w, h))) {
|
||||
Some((a, w, h)) if w.abs() > 1e-12 && h.abs() > 1e-12 => {
|
||||
vec![rect_kind(a, w, h, self.rotation, self.fillet, self.chamfer, self.width, self.elevation)]
|
||||
vec![rect_kind(a, (w, h), self.rotation, self.fillet, self.chamfer, self.width, self.elevation)]
|
||||
}
|
||||
_ => Vec::new(),
|
||||
}
|
||||
|
||||
@@ -280,11 +280,9 @@ impl Unused {
|
||||
fn item_json(
|
||||
c: Category,
|
||||
name: &str,
|
||||
entities: usize,
|
||||
block_entities: usize,
|
||||
(entities, block_entities): (usize, usize),
|
||||
references: usize,
|
||||
used: bool,
|
||||
empty: bool,
|
||||
(used, empty): (bool, bool),
|
||||
current: Option<bool>,
|
||||
unused: &Unused,
|
||||
) -> Value {
|
||||
@@ -314,13 +312,13 @@ fn items(scan: &Scan, unused: &Unused, d: &Drawing) -> Vec<Value> {
|
||||
let (e, b) = scan.layers.get(&l.name.to_ascii_lowercase()).copied().unwrap_or_default();
|
||||
let uses = e.saturating_add(b);
|
||||
let cur = l.name.eq_ignore_ascii_case(¤t_layer);
|
||||
out.push(item_json(Category::Layer, &l.name, e, b, 0, uses > 0, uses == 0, Some(cur), unused));
|
||||
out.push(item_json(Category::Layer, &l.name, (e, b), 0, (uses > 0, uses == 0), Some(cur), unused));
|
||||
}
|
||||
for b in d.blocks.values() {
|
||||
let (e, n) = scan.blocks.get(&b.name.to_ascii_lowercase()).copied().unwrap_or_default();
|
||||
// A definition is used when a reference to it is reachable, as PURGE counts it.
|
||||
let used = scan.used_blocks.contains(&b.name.to_ascii_uppercase());
|
||||
out.push(item_json(Category::Block, &b.name, e, n, 0, used, e.saturating_add(n) == 0, None, unused));
|
||||
out.push(item_json(Category::Block, &b.name, (e, n), 0, (used, e.saturating_add(n) == 0), None, unused));
|
||||
}
|
||||
let current_style = d.header.str("TEXTSTYLE", "Standard");
|
||||
for t in &d.text_styles {
|
||||
@@ -328,7 +326,7 @@ fn items(scan: &Scan, unused: &Unused, d: &Drawing) -> Vec<Value> {
|
||||
let r = scan.style_refs.get(&t.name.to_ascii_lowercase()).copied().unwrap_or(0);
|
||||
let uses = e.saturating_add(b).saturating_add(r);
|
||||
let cur = t.name.eq_ignore_ascii_case(¤t_style);
|
||||
out.push(item_json(Category::TextStyle, &t.name, e, b, r, uses > 0, uses == 0, Some(cur), unused));
|
||||
out.push(item_json(Category::TextStyle, &t.name, (e, b), r, (uses > 0, uses == 0), Some(cur), unused));
|
||||
}
|
||||
let current_linetype = d.header.str("CELTYPE", "ByLayer");
|
||||
for t in &d.linetypes {
|
||||
@@ -336,7 +334,7 @@ fn items(scan: &Scan, unused: &Unused, d: &Drawing) -> Vec<Value> {
|
||||
let r = scan.linetype_refs.get(&t.name.to_ascii_lowercase()).copied().unwrap_or(0);
|
||||
let uses = e.saturating_add(b).saturating_add(r);
|
||||
let cur = t.name.eq_ignore_ascii_case(¤t_linetype);
|
||||
out.push(item_json(Category::Linetype, &t.name, e, b, r, uses > 0, uses == 0, Some(cur), unused));
|
||||
out.push(item_json(Category::Linetype, &t.name, (e, b), r, (uses > 0, uses == 0), Some(cur), unused));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
@@ -80,8 +80,7 @@ fn same_polyline(
|
||||
s: &mut Session,
|
||||
h: Handle,
|
||||
pl: &LwPolyline,
|
||||
p1: Vec2,
|
||||
p2: Vec2,
|
||||
(p1, p2): (Vec2, Vec2),
|
||||
r: f64,
|
||||
chamfer: Option<ChamferDistances>,
|
||||
trim: bool,
|
||||
@@ -223,7 +222,7 @@ pub(crate) fn fillet_pline(
|
||||
_ => None,
|
||||
};
|
||||
let made = match (&e1.kind, &e2.kind) {
|
||||
(EntityKind::LwPolyline(pl), _) if h1 == h2 => same_polyline(s, h1, pl, p1, p2, r, chamfer, trim)?,
|
||||
(EntityKind::LwPolyline(pl), _) if h1 == h2 => same_polyline(s, h1, pl, (p1, p2), r, chamfer, trim)?,
|
||||
(EntityKind::LwPolyline(pl), k) if as_line(k).is_some() => {
|
||||
let ln = as_line(k).ok_or_else(|| other("Select a line."))?;
|
||||
polyline_and_line(s, (h1, pl, p1), (h2, ln, p2), true, r, chamfer, trim)?
|
||||
|
||||
@@ -528,14 +528,14 @@ impl Family<'_> {
|
||||
if solid_line {
|
||||
out.push(vec![self.to_world(Vec2::new(x0, y)), self.to_world(Vec2::new(x1, y))]);
|
||||
} else {
|
||||
self.dash(x0, x1, y, offset, pat_len, out, work);
|
||||
self.dash((x0, x1), y, offset, pat_len, out, work);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The dashes and dots of the span `x0..x1` of the line at `y`, phase anchored at x = `offset`.
|
||||
fn dash(&self, x0: f64, x1: f64, y: f64, offset: f64, pat_len: f64, out: &mut Vec<Vec<Vec2>>, work: &mut u64) {
|
||||
fn dash(&self, (x0, x1): (f64, f64), y: f64, offset: f64, pat_len: f64, out: &mut Vec<Vec<Vec2>>, work: &mut u64) {
|
||||
let start_rep = ((x0 - offset) / pat_len).floor();
|
||||
let mut x = offset + start_rep * pat_len;
|
||||
let mut guard = 0;
|
||||
|
||||
Reference in New Issue
Block a user