forked from 1b-agent/opencadstudio-upstream
refactor(modify): take plane geometry from cadkernel
TRIM, FILLET and EXPLODE each carried their own copy of the same plane maths. The copies had already drifted apart: `ll` differed only in parameter names between trim.rs and fillet.rs, `arc_pts` only in which angle helper it called, and `norm` meant angle normalisation in trim.rs and explode.rs while meaning vector normalisation in two other files. The implementations now live in cadkernel's geom2d. A new local `geom` module adapts the call shapes — the kernel takes `[f64; 2]` points and returns `[f64; 3]`, while these commands pass loose scalars and feed `WireModel::points`, which is `[f32; 3]`. Narrowing stays on this side because only the caller knows whether it is a preview wire, which leaves `points_low` empty and accepts the loss, or resident geometry, which splits the f64 into a high/low pair instead. Call sites are untouched: the kernel functions are imported under the old local names, so the signatures they were written against still hold. This also fixes ELLIPSE trim and extend previews. `ellipse_pts` wrote its components as [x, z, y] while `arc_pts` — reached from the same match in `entity_pts`, feeding the same `[f32; 3]` — wrote [x, y, z], and `WireModel::points` is documented as world-space positions. Ellipse previews were collapsing onto y = 0 and displacing along Z. The kernel's `ellipse_arc` orders them correctly, so delegating corrects it. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
051272ad71
commit
d0cc3284d2
6 files changed
+152
-272
No files matched your search
Generated
+1
-1
@@ -946,7 +946,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
[[package]]
|
||||
name = "cadkernel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#53e15eccfb5c476a04c49cbea2809c5c4e13b691"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#0e4b23845de75242e00f016feed9fc2341b4a85a"
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
// Unsupported entity types are skipped silently.
|
||||
|
||||
use std::f64::consts::TAU;
|
||||
use super::geom::normalize_angle as norm_angle;
|
||||
|
||||
use acadrust::entities::EntityCommon;
|
||||
use acadrust::entities::{
|
||||
@@ -260,10 +260,6 @@ fn bulge_to_arc(
|
||||
Some(EntityType::Arc(arc))
|
||||
}
|
||||
|
||||
fn norm_angle(a: f64) -> f64 {
|
||||
((a % TAU) + TAU) % TAU
|
||||
}
|
||||
|
||||
fn explode_mline(ml: &MLine) -> Vec<EntityType> {
|
||||
let n = ml.vertices.len();
|
||||
if n < 2 {
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
// Finds intersection, backs off dist1 along line 1 and dist2 along line 2.
|
||||
|
||||
use acadrust::entities::{Arc as ArcEnt, Line as LineEnt, LwPolyline};
|
||||
|
||||
// Shared plane geometry, from cadkernel via the local adapters.
|
||||
use super::geom;
|
||||
use super::geom::{arc_points as arc_pts, line_line as ll, normalize_angle as norm_angle};
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::DVec3;
|
||||
@@ -46,26 +50,6 @@ pub const DROPDOWN_ITEMS: &[(&str, &str, IconKind)] = &[
|
||||
// Geometry
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Intersect two infinite lines. Returns (t on L1, u on L2).
|
||||
fn ll(
|
||||
ax: f64,
|
||||
ay: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
cx: f64,
|
||||
cy: f64,
|
||||
ex: f64,
|
||||
ey: f64,
|
||||
) -> Option<(f64, f64)> {
|
||||
let det = dx * ey - dy * ex;
|
||||
if det.abs() < 1e-10 {
|
||||
return None;
|
||||
}
|
||||
let t = ((cx - ax) * ey - (cy - ay) * ex) / det;
|
||||
let u = ((cx - ax) * dy - (cy - ay) * dx) / det;
|
||||
Some((t, u))
|
||||
}
|
||||
|
||||
/// Extract coords and unit direction for a Line entity.
|
||||
fn line_geom(l: &LineEnt) -> ([f64; 2], [f64; 2], [f64; 2], f64) {
|
||||
let p1 = [l.start.x, l.start.y];
|
||||
@@ -229,32 +213,10 @@ fn trim_to_xy(
|
||||
// ── Point-generation helpers ──────────────────────────────────────────────
|
||||
|
||||
fn line_pts(l: &LineEnt) -> Vec<[f32; 3]> {
|
||||
vec![
|
||||
[l.start.x as f32, l.start.y as f32, l.start.z as f32],
|
||||
[l.end.x as f32, l.end.y as f32, l.end.z as f32],
|
||||
]
|
||||
}
|
||||
|
||||
fn arc_pts(cx: f64, cy: f64, r: f64, a0: f64, a1: f64, z: f64) -> Vec<[f32; 3]> {
|
||||
let span = {
|
||||
let s = norm_angle(a1) - norm_angle(a0);
|
||||
if s <= 0.0 {
|
||||
s + TAU
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let steps = (span.abs() * 20.0).ceil().max(4.0) as usize;
|
||||
(0..=steps)
|
||||
.map(|i| {
|
||||
let ang = norm_angle(a0) + span * (i as f64 / steps as f64);
|
||||
[
|
||||
(cx + r * ang.cos()) as f32,
|
||||
(cy + r * ang.sin()) as f32,
|
||||
z as f32,
|
||||
]
|
||||
})
|
||||
.collect()
|
||||
geom::line_points(
|
||||
[l.start.x, l.start.y, l.start.z],
|
||||
[l.end.x, l.end.y, l.end.z],
|
||||
)
|
||||
}
|
||||
|
||||
fn entity_pts(e: &EntityType) -> Vec<[f32; 3]> {
|
||||
@@ -286,11 +248,6 @@ fn arc_geom(a: &ArcEnt) -> ([f64; 2], f64, f64, f64, f64) {
|
||||
)
|
||||
}
|
||||
|
||||
/// Normalize angle to [0, 2π).
|
||||
fn norm_angle(a: f64) -> f64 {
|
||||
((a % TAU) + TAU) % TAU
|
||||
}
|
||||
|
||||
/// Return the CCW angular span from `start` to `end`.
|
||||
fn arc_span(start: f64, end: f64) -> f64 {
|
||||
let s = (end - start).rem_euclid(TAU);
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
//! Adapters between the editing commands and `cadkernel`'s plane geometry.
|
||||
//!
|
||||
//! The kernel takes points as `[f64; 2]` and hands tessellation back as
|
||||
//! `[f64; 3]`. The commands here grew up passing loose `x, y` scalars and
|
||||
//! feeding [`WireModel::points`](crate::scene::model::wire_model::WireModel),
|
||||
//! which is `[f32; 3]`. These wrappers absorb that difference in one place so
|
||||
//! the maths itself lives once, in the kernel.
|
||||
//!
|
||||
//! Narrowing to `f32` happens here rather than in the kernel deliberately:
|
||||
//! preview wires leave `points_low` empty, so they accept the loss, while the
|
||||
//! resident render path splits the `f64` into a high/low pair instead. Only a
|
||||
//! caller knows which of the two it is.
|
||||
|
||||
use acadrust::kernel::geom2d::{self, Ellipse};
|
||||
|
||||
/// Re-exported unchanged: these already speak in plain `f64`, so there is no
|
||||
/// call-shape difference for this module to absorb.
|
||||
pub use acadrust::kernel::geom2d::{angle_within_arc, arc_parameter, lerp, normalize_angle};
|
||||
|
||||
/// Preview geometry keeps the density the commands have always used.
|
||||
const SEGMENTS_PER_RADIAN: f64 = geom2d::DEFAULT_SEGMENTS_PER_RADIAN;
|
||||
|
||||
fn narrow(points: Vec<[f64; 3]>) -> Vec<[f32; 3]> {
|
||||
points
|
||||
.into_iter()
|
||||
.map(|p| [p[0] as f32, p[1] as f32, p[2] as f32])
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Where two infinite lines cross, as `(t, u)`; `None` when parallel.
|
||||
///
|
||||
/// Both parameters are unbounded, so EXTEND can use a crossing that lies past
|
||||
/// the end of either line.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn line_line(
|
||||
px: f64,
|
||||
py: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
qx: f64,
|
||||
qy: f64,
|
||||
ex: f64,
|
||||
ey: f64,
|
||||
) -> Option<(f64, f64)> {
|
||||
geom2d::line_line([px, py], [dx, dy], [qx, qy], [ex, ey])
|
||||
}
|
||||
|
||||
/// Line parameters where `p + t·d` meets a circle: none, one when tangent, or
|
||||
/// two ordered by increasing `t`.
|
||||
pub fn line_circle(px: f64, py: f64, dx: f64, dy: f64, cx: f64, cy: f64, r: f64) -> Vec<f64> {
|
||||
geom2d::line_circle([px, py], [dx, dy], [cx, cy], r)
|
||||
}
|
||||
|
||||
/// Angles **on the first circle** where two circles meet.
|
||||
pub fn circle_circle_angles(cx1: f64, cy1: f64, r1: f64, cx2: f64, cy2: f64, r2: f64) -> Vec<f64> {
|
||||
geom2d::circle_circle_angles([cx1, cy1], r1, [cx2, cy2], r2)
|
||||
}
|
||||
|
||||
/// `(s_on_line, t_on_ellipse)` pairs where a line meets an ellipse.
|
||||
///
|
||||
/// `nx, ny` is the unit major axis.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn line_ellipse(
|
||||
px: f64,
|
||||
py: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
cx: f64,
|
||||
cy: f64,
|
||||
a: f64,
|
||||
b: f64,
|
||||
nx: f64,
|
||||
ny: f64,
|
||||
) -> Vec<(f64, f64)> {
|
||||
geom2d::line_ellipse(
|
||||
[px, py],
|
||||
[dx, dy],
|
||||
&Ellipse {
|
||||
centre: [cx, cy],
|
||||
major_radius: a,
|
||||
minor_radius: b,
|
||||
major_axis: [nx, ny],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// The two endpoints of a straight segment, as render vertices.
|
||||
pub fn line_points(start: [f64; 3], end: [f64; 3]) -> Vec<[f32; 3]> {
|
||||
narrow(vec![start, end])
|
||||
}
|
||||
|
||||
/// A circular arc sampled counter-clockwise, as render vertices.
|
||||
pub fn arc_points(cx: f64, cy: f64, r: f64, a0: f64, a1: f64, z: f64) -> Vec<[f32; 3]> {
|
||||
narrow(geom2d::arc([cx, cy], r, a0, a1, z, SEGMENTS_PER_RADIAN))
|
||||
}
|
||||
|
||||
/// An elliptical arc sampled between two of the ellipse's own parameters, as
|
||||
/// render vertices.
|
||||
///
|
||||
/// Components come back as `[x, y, z]`. The hand-rolled version this replaces
|
||||
/// wrote them as `[x, z, y]`, which flattened ELLIPSE trim previews onto
|
||||
/// `y = 0` and displaced them along Z.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn ellipse_points(
|
||||
cx: f64,
|
||||
cy: f64,
|
||||
a: f64,
|
||||
b: f64,
|
||||
nx: f64,
|
||||
ny: f64,
|
||||
t0: f64,
|
||||
t1: f64,
|
||||
z: f64,
|
||||
) -> Vec<[f32; 3]> {
|
||||
let ellipse = Ellipse {
|
||||
centre: [cx, cy],
|
||||
major_radius: a,
|
||||
minor_radius: b,
|
||||
major_axis: [nx, ny],
|
||||
};
|
||||
narrow(geom2d::ellipse_arc(
|
||||
&ellipse,
|
||||
t0,
|
||||
t1,
|
||||
z,
|
||||
SEGMENTS_PER_RADIAN,
|
||||
))
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub mod delete;
|
||||
mod entity_index;
|
||||
pub mod explode;
|
||||
pub mod fillet;
|
||||
pub mod geom;
|
||||
pub mod join;
|
||||
pub mod lengthen;
|
||||
pub mod mirror;
|
||||
|
||||
+13
-215
@@ -10,6 +10,15 @@
|
||||
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
// The plane geometry these commands run on lives in cadkernel; `geom` adapts
|
||||
// its call shapes to the loose scalars and f32 render vertices used here.
|
||||
use super::geom;
|
||||
use super::geom::{
|
||||
angle_within_arc as in_arc, arc_parameter as arc_t, arc_points as arc_pts,
|
||||
circle_circle_angles as cc_angles, ellipse_points as ellipse_pts, lerp as lerp2,
|
||||
line_circle as lc, line_ellipse as le, line_line as ll, normalize_angle as norm,
|
||||
};
|
||||
|
||||
use crate::modules::draw::fence::{crossing_box_preview, FencePick};
|
||||
|
||||
use acadrust::entities::{
|
||||
@@ -54,163 +63,6 @@ pub const DROPDOWN_ITEMS: &[(&str, &str, IconKind)] = &[
|
||||
// Geometry helpers
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Normalize angle to [0, 2π).
|
||||
fn norm(a: f64) -> f64 {
|
||||
((a % TAU) + TAU) % TAU
|
||||
}
|
||||
|
||||
/// Is angle `a` within the arc from `s` to `e` (CCW, radians)?
|
||||
fn in_arc(a: f64, s: f64, e: f64) -> bool {
|
||||
let (a, s, e) = (norm(a), norm(s), norm(e));
|
||||
if (e - s).abs() < 1e-9 || (e - s - TAU).abs() < 1e-9 {
|
||||
return true;
|
||||
}
|
||||
if s <= e {
|
||||
a >= s - 1e-9 && a <= e + 1e-9
|
||||
} else {
|
||||
a >= s - 1e-9 || a <= e + 1e-9
|
||||
}
|
||||
}
|
||||
|
||||
/// Parametric t ∈ [0,1] on arc (a0→a1 CCW) for angle `a`.
|
||||
fn arc_t(a: f64, a0: f64, a1: f64) -> f64 {
|
||||
let span = {
|
||||
let s = norm(a1) - norm(a0);
|
||||
if s <= 0.0 {
|
||||
s + TAU
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let da = {
|
||||
let d = norm(a) - norm(a0);
|
||||
if d < 0.0 {
|
||||
d + TAU
|
||||
} else {
|
||||
d
|
||||
}
|
||||
};
|
||||
(da / span).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
/// Intersect infinite lines (p+t·d) and (q+u·e). Returns (t, u).
|
||||
fn ll(
|
||||
px: f64,
|
||||
py: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
qx: f64,
|
||||
qy: f64,
|
||||
ex: f64,
|
||||
ey: f64,
|
||||
) -> Option<(f64, f64)> {
|
||||
let det = dx * ey - dy * ex;
|
||||
if det.abs() < 1e-10 {
|
||||
return None;
|
||||
}
|
||||
let t = ((qx - px) * ey - (qy - py) * ex) / det;
|
||||
let u = ((qx - px) * dy - (qy - py) * dx) / det;
|
||||
Some((t, u))
|
||||
}
|
||||
|
||||
/// Intersect infinite line (p+t·d) with circle (cx,cy,r). Returns t values.
|
||||
fn lc(px: f64, py: f64, dx: f64, dy: f64, cx: f64, cy: f64, r: f64) -> Vec<f64> {
|
||||
let fx = px - cx;
|
||||
let fy = py - cy;
|
||||
let a = dx * dx + dy * dy;
|
||||
let b = 2.0 * (fx * dx + fy * dy);
|
||||
let c = fx * fx + fy * fy - r * r;
|
||||
let disc = b * b - 4.0 * a * c;
|
||||
if disc < 0.0 {
|
||||
return vec![];
|
||||
}
|
||||
let sq = disc.sqrt();
|
||||
if disc < 1e-14 {
|
||||
vec![(-b) / (2.0 * a)]
|
||||
} else {
|
||||
vec![(-b - sq) / (2.0 * a), (-b + sq) / (2.0 * a)]
|
||||
}
|
||||
}
|
||||
|
||||
/// Circle-circle intersection: angles on circle 1 where they meet.
|
||||
fn cc_angles(cx1: f64, cy1: f64, r1: f64, cx2: f64, cy2: f64, r2: f64) -> Vec<f64> {
|
||||
let d = ((cx2 - cx1).powi(2) + (cy2 - cy1).powi(2)).sqrt();
|
||||
if d < 1e-9 || d > r1 + r2 + 1e-9 || d < (r1 - r2).abs() - 1e-9 {
|
||||
return vec![];
|
||||
}
|
||||
let a = (r1 * r1 - r2 * r2 + d * d) / (2.0 * d);
|
||||
let h2 = r1 * r1 - a * a;
|
||||
if h2 < 0.0 {
|
||||
return vec![];
|
||||
}
|
||||
let h = h2.sqrt();
|
||||
let mx = cx1 + a * (cx2 - cx1) / d;
|
||||
let my = cy1 + a * (cy2 - cy1) / d;
|
||||
let px = h * (cy2 - cy1) / d;
|
||||
let py = -h * (cx2 - cx1) / d;
|
||||
let a1 = ((my + py) - cy1).atan2((mx + px) - cx1);
|
||||
let a2 = ((my - py) - cy1).atan2((mx - px) - cx1);
|
||||
if h < 1e-9 {
|
||||
vec![a1]
|
||||
} else {
|
||||
vec![a1, a2]
|
||||
}
|
||||
}
|
||||
|
||||
/// Line (px+s·d) vs ellipse (cx,cy,a,b,nx,ny). Returns (s_on_line, t_on_ellipse) pairs.
|
||||
/// nx,ny: unit major-axis; perp = (-ny, nx). Parametric ellipse: P(t) = center + a·cos(t)·n + b·sin(t)·v.
|
||||
fn le(
|
||||
px: f64,
|
||||
py: f64,
|
||||
dpx: f64,
|
||||
dpy: f64,
|
||||
cx: f64,
|
||||
cy: f64,
|
||||
a: f64,
|
||||
b: f64,
|
||||
nx: f64,
|
||||
ny: f64,
|
||||
) -> Vec<(f64, f64)> {
|
||||
// Transform line origin to ellipse local frame
|
||||
let rx = px - cx;
|
||||
let ry = py - cy;
|
||||
// Project onto major/minor axes
|
||||
let xl0 = rx * nx + ry * ny;
|
||||
let yl0 = -rx * ny + ry * nx;
|
||||
let dxl = dpx * nx + dpy * ny;
|
||||
let dyl = -dpx * ny + dpy * nx;
|
||||
// Scale by 1/a, 1/b → circle equation
|
||||
let xa = xl0 / a;
|
||||
let xda = dxl / a;
|
||||
let yb = yl0 / b;
|
||||
let ydb = dyl / b;
|
||||
let big_a = xda * xda + ydb * ydb;
|
||||
if big_a < 1e-20 {
|
||||
return vec![];
|
||||
}
|
||||
let big_b = 2.0 * (xa * xda + yb * ydb);
|
||||
let big_c = xa * xa + yb * yb - 1.0;
|
||||
let disc = big_b * big_b - 4.0 * big_a * big_c;
|
||||
if disc < 0.0 {
|
||||
return vec![];
|
||||
}
|
||||
let sq = disc.sqrt();
|
||||
let s_vals: Vec<f64> = if disc < 1e-14 {
|
||||
vec![(-big_b) / (2.0 * big_a)]
|
||||
} else {
|
||||
vec![(-big_b - sq) / (2.0 * big_a), (-big_b + sq) / (2.0 * big_a)]
|
||||
};
|
||||
s_vals
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
let xl = xl0 + s * dxl;
|
||||
let yl = yl0 + s * dyl;
|
||||
let t = yl.atan2(xl); // ≡ atan2(yl/b, xl/a) but faster since sign is preserved
|
||||
(s, t)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ── Boundary geometry ─────────────────────────────────────────────────────
|
||||
|
||||
/// Virtual extent used to represent infinite ends of Ray / XLine.
|
||||
@@ -1051,34 +903,6 @@ fn extend_ellipse(orig: &EllipseEnt, t_click: f64, geos: &[Geo]) -> Option<Entit
|
||||
Some(EntityType::Ellipse(e))
|
||||
}
|
||||
|
||||
/// Generate preview points for an ellipse arc.
|
||||
fn ellipse_pts(
|
||||
cx: f64,
|
||||
cy: f64,
|
||||
a: f64,
|
||||
b: f64,
|
||||
nx: f64,
|
||||
ny: f64,
|
||||
t0: f64,
|
||||
t1: f64,
|
||||
z: f64,
|
||||
) -> Vec<[f32; 3]> {
|
||||
let span = t1 - t0;
|
||||
let steps = (span.abs() * 20.0).ceil().max(4.0) as usize;
|
||||
(0..=steps)
|
||||
.map(|i| {
|
||||
let t = t0 + span * (i as f64 / steps as f64);
|
||||
let lx = a * t.cos();
|
||||
let ly = b * t.sin();
|
||||
[
|
||||
(cx + lx * nx - ly * ny) as f32,
|
||||
z as f32,
|
||||
(cy + lx * ny + ly * nx) as f32,
|
||||
]
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ── Spline trim / extend ──────────────────────────────────────────────────
|
||||
|
||||
/// Find normalised t-params ∈ [0,1] where a Spline intersects boundary geos.
|
||||
@@ -1221,10 +1045,6 @@ fn trim_intervals(ts: &[f64], t_click: f64) -> Vec<(f64, f64)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn lerp2(p1: [f64; 2], p2: [f64; 2], t: f64) -> [f64; 2] {
|
||||
[p1[0] + t * (p2[0] - p1[0]), p1[1] + t * (p2[1] - p1[1])]
|
||||
}
|
||||
|
||||
/// Trim a Line entity. Returns the surviving line segments.
|
||||
fn trim_line(orig: &LineEnt, ts: &[f64], t_click: f64) -> Vec<EntityType> {
|
||||
let p1 = [orig.start.x, orig.start.y];
|
||||
@@ -2004,32 +1824,10 @@ fn trim_xline(orig: &XLineEnt, ts: &[f64], t_click: f64) -> Vec<EntityType> {
|
||||
const DIM_RED: [f32; 4] = [1.0, 0.3, 0.3, 0.6];
|
||||
|
||||
fn line_pts(l: &LineEnt) -> Vec<[f32; 3]> {
|
||||
vec![
|
||||
[l.start.x as f32, l.start.y as f32, l.start.z as f32],
|
||||
[l.end.x as f32, l.end.y as f32, l.end.z as f32],
|
||||
]
|
||||
}
|
||||
|
||||
fn arc_pts(cx: f64, cy: f64, r: f64, a0: f64, a1: f64, z: f64) -> Vec<[f32; 3]> {
|
||||
let span = {
|
||||
let s = norm(a1) - norm(a0);
|
||||
if s <= 0.0 {
|
||||
s + TAU
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let steps = (span.abs() * 20.0).ceil().max(4.0) as usize;
|
||||
(0..=steps)
|
||||
.map(|i| {
|
||||
let ang = norm(a0) + span * (i as f64 / steps as f64);
|
||||
[
|
||||
(cx + r * ang.cos()) as f32,
|
||||
(cy + r * ang.sin()) as f32,
|
||||
z as f32,
|
||||
]
|
||||
})
|
||||
.collect()
|
||||
geom::line_points(
|
||||
[l.start.x, l.start.y, l.start.z],
|
||||
[l.end.x, l.end.y, l.end.z],
|
||||
)
|
||||
}
|
||||
|
||||
fn entity_pts(e: &EntityType) -> Vec<[f32; 3]> {
|
||||
|
||||
Reference in new issue
Block a user