forked from 1b-agent/opencadstudio-upstream
feat(polyline): Polyline2D width band + tube, and block-instance shader bands
Extends the wide-polyline shader band to the two cases the first pass left on the hatch pipeline. Polyline2D: - A flat wide Polyline2D now draws its band from the centre-line wire (`world_width`), same as LwPolyline (`polyline_band_width` handles both). - A thickened wide Polyline2D extrudes a solid 3-D tube. `thick_wide_band`'s body moves to a shared `common::thick_band_tube(origin, fills, thickness, normal, to_wcs)`; LwPolyline delegates to it and Polyline2D calls it from its thickness path. Tube edges read black for both kinds. - The model-space wide-band hatch loop is deleted (both kinds now wire/tube). Blocks: - Block-internal wide polylines draw the shader band too. `LocalWire` carries `world_width`; `emit_wire` scales it by the insert transform (average of the X/Y axis image lengths) so the band tracks a scaled insert, and the scaled width joins the batch `style_key`. `push_block_wide_fills` (the block hatch band) is removed. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
298bfd4803
commit
a8aece1909
6 files changed
+161
-219
No files matched your search
@@ -334,6 +334,64 @@ pub(crate) fn wide_band_tris(origin: [f64; 2], fills: &[Vec<[f32; 2]>]) -> Vec<[
|
||||
out
|
||||
}
|
||||
|
||||
/// Extrude a wide-polyline band (from `wide_fills`) into a solid tube for a DXF
|
||||
/// thickness (code 39): a vertical wall between every band-boundary point and
|
||||
/// its `thickness`-along-`normal` copy, plus triangulated bottom and top caps.
|
||||
/// Returns `(fill_tris, edge_lines)` as flat WCS f64 lists — the caller wraps
|
||||
/// them in a `TruckEntity` (object = `Lines(edge_lines)`, `fill_tris`, and
|
||||
/// `pick_tris = fill_tris`). Shared by LwPolyline and Polyline2D so both wide
|
||||
/// polyline kinds extrude the same solid instead of just their centre-line.
|
||||
///
|
||||
/// `polyline_segment_fill` emits each band loop as the outer boundary forward
|
||||
/// then the inner boundary back, so its two transition edges (`half-1 → half`
|
||||
/// and `n-1 → 0`) are radial cap ends inside the band — no wall is drawn there.
|
||||
pub(crate) fn thick_band_tube(
|
||||
origin: [f64; 2],
|
||||
fills: &[Vec<[f32; 2]>],
|
||||
thickness: f64,
|
||||
normal: (f64, f64, f64),
|
||||
to_wcs: &dyn Fn(f64, f64) -> (f64, f64, f64),
|
||||
) -> (Vec<[f64; 3]>, Vec<[f64; 3]>) {
|
||||
let (nx, ny, nz) = normal;
|
||||
let t = thickness;
|
||||
let off = |p: [f64; 3]| -> [f64; 3] { [p[0] + t * nx, p[1] + t * ny, p[2] + t * nz] };
|
||||
let push_seg = |lines: &mut Vec<[f64; 3]>, a: [f64; 3], b: [f64; 3]| {
|
||||
lines.push(a);
|
||||
lines.push(b);
|
||||
lines.push([f64::NAN; 3]);
|
||||
};
|
||||
let mut lines: Vec<[f64; 3]> = Vec::new();
|
||||
let mut fill_tris: Vec<[f64; 3]> = Vec::new();
|
||||
for poly in fills {
|
||||
let n = poly.len();
|
||||
if n < 4 {
|
||||
continue;
|
||||
}
|
||||
let half = n / 2;
|
||||
let bot: Vec<[f64; 3]> = poly
|
||||
.iter()
|
||||
.map(|&[x, y]| {
|
||||
let (wx, wy, wz) = to_wcs(origin[0] + x as f64, origin[1] + y as f64);
|
||||
[wx, wy, wz]
|
||||
})
|
||||
.collect();
|
||||
let top: Vec<[f64; 3]> = bot.iter().map(|&p| off(p)).collect();
|
||||
for k in 0..n {
|
||||
push_seg(&mut lines, bot[k], top[k]);
|
||||
if k == half - 1 || k == n - 1 {
|
||||
continue;
|
||||
}
|
||||
let kn = (k + 1) % n;
|
||||
push_seg(&mut lines, bot[k], bot[kn]);
|
||||
push_seg(&mut lines, top[k], top[kn]);
|
||||
fill_tris.extend_from_slice(&[bot[k], bot[kn], top[kn], bot[k], top[kn], top[k]]);
|
||||
}
|
||||
fill_tris.extend(crate::entities::mesh::triangulate_planar(&bot));
|
||||
fill_tris.extend(crate::entities::mesh::triangulate_planar(&top));
|
||||
}
|
||||
(fill_tris, lines)
|
||||
}
|
||||
|
||||
/// Compute the filled boundary polygon for one polyline segment.
|
||||
/// For straight segments: a rectangle/trapezoid.
|
||||
/// For arc segments: an arc band (outer arc + reversed inner arc).
|
||||
|
||||
@@ -115,57 +115,8 @@ fn thick_wide_band(
|
||||
tangents: Vec<TangentGeom>,
|
||||
) -> TruckEntity {
|
||||
let (origin, fills) = wide_fills(pl);
|
||||
let (nx, ny, nz) = normal;
|
||||
let t = thickness;
|
||||
let off = |p: [f64; 3]| -> [f64; 3] { [p[0] + t * nx, p[1] + t * ny, p[2] + t * nz] };
|
||||
let push_seg = |lines: &mut Vec<[f64; 3]>, a: [f64; 3], b: [f64; 3]| {
|
||||
lines.push(a);
|
||||
lines.push(b);
|
||||
lines.push([f64::NAN; 3]);
|
||||
};
|
||||
|
||||
let mut lines: Vec<[f64; 3]> = Vec::new();
|
||||
// Shaded surfaces: the vertical walls plus the top cap. The flat bottom cap
|
||||
// is already drawn by the wide-fill hatch path, so it is not repeated here.
|
||||
let mut fill_tris: Vec<[f64; 3]> = Vec::new();
|
||||
for poly in &fills {
|
||||
let n = poly.len();
|
||||
if n < 4 {
|
||||
continue;
|
||||
}
|
||||
// `polyline_segment_fill` returns the band loop as the outer boundary
|
||||
// forward then the inner boundary back, so the two transition edges
|
||||
// (half-1 → half and n-1 → 0) are the radial segment ends.
|
||||
let half = n / 2;
|
||||
let bot: Vec<[f64; 3]> = poly
|
||||
.iter()
|
||||
.map(|&[x, y]| {
|
||||
let (wx, wy, wz) = to_wcs(origin[0] + x as f64, origin[1] + y as f64);
|
||||
[wx, wy, wz]
|
||||
})
|
||||
.collect();
|
||||
let top: Vec<[f64; 3]> = bot.iter().map(|&p| off(p)).collect();
|
||||
for k in 0..n {
|
||||
// Vertical at every boundary point.
|
||||
push_seg(&mut lines, bot[k], top[k]);
|
||||
// Skip the two radial cap edges — they stay inside the band.
|
||||
if k == half - 1 || k == n - 1 {
|
||||
continue;
|
||||
}
|
||||
let kn = (k + 1) % n;
|
||||
push_seg(&mut lines, bot[k], bot[kn]); // bottom boundary
|
||||
push_seg(&mut lines, top[k], top[kn]); // top boundary
|
||||
// Wall quad (two triangles).
|
||||
fill_tris.extend_from_slice(&[
|
||||
bot[k], bot[kn], top[kn], bot[k], top[kn], top[k],
|
||||
]);
|
||||
}
|
||||
// Bottom + top caps — the band ring triangulated at each plane. The
|
||||
// bottom cap is a real 3-D surface (with depth) so the walls occlude it
|
||||
// correctly; the flat 2-D band fill is skipped for thickened polylines.
|
||||
fill_tris.extend(crate::entities::mesh::triangulate_planar(&bot));
|
||||
fill_tris.extend(crate::entities::mesh::triangulate_planar(&top));
|
||||
}
|
||||
let (fill_tris, lines) =
|
||||
crate::entities::common::thick_band_tube(origin, &fills, thickness, normal, to_wcs);
|
||||
|
||||
TruckEntity {
|
||||
pick_tris: fill_tris.clone(),
|
||||
|
||||
@@ -238,6 +238,28 @@ fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
|
||||
let (wbx, wby, wbz) = to_wcs(ox1, oy1);
|
||||
kv.push([wbx, wby, wbz]);
|
||||
}
|
||||
// A wide Polyline2D extrudes its whole band into a solid tube (walls +
|
||||
// caps), same as a thickened LwPolyline; a zero-width one falls through
|
||||
// to the centre-line extrusion below.
|
||||
let is_wide = pl.start_width > 1e-9
|
||||
|| pl.end_width > 1e-9
|
||||
|| pl
|
||||
.vertices
|
||||
.iter()
|
||||
.any(|v| v.start_width > 1e-9 || v.end_width > 1e-9);
|
||||
if is_wide {
|
||||
let (origin, fills) = wide_fills(pl);
|
||||
let (fill_tris, lines) =
|
||||
crate::entities::common::thick_band_tube(origin, &fills, t, normal, &to_wcs);
|
||||
return TruckEntity {
|
||||
pick_tris: fill_tris.clone(),
|
||||
object: TruckObject::Lines(lines),
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: tgs,
|
||||
key_vertices: kv,
|
||||
fill_tris,
|
||||
};
|
||||
}
|
||||
let mut pts: Vec<[f64; 3]> = Vec::with_capacity(path.len() * 2 + kv.len() * 3 + 4);
|
||||
pts.extend_from_slice(&path);
|
||||
pts.push([f64::NAN; 3]);
|
||||
|
||||
Vendored
+36
-7
@@ -61,6 +61,10 @@ pub struct LocalWire {
|
||||
pub pattern_length: f32,
|
||||
pub pattern: [f32; 8],
|
||||
pub line_weight_px: f32,
|
||||
/// World-space band width for a wide polyline (see `WireModel.world_width`).
|
||||
/// Block-local; the expand-time transform scales it by the insert so the
|
||||
/// shader band grows with a scaled insert. `0.0` = a normal wire.
|
||||
pub world_width: f32,
|
||||
pub plinegen: bool,
|
||||
/// Set at construction; used to discriminate fill-only GPU batches from
|
||||
/// stroke batches in [`StyleKey`]. Derived from
|
||||
@@ -325,12 +329,10 @@ fn build_defn(
|
||||
subs.push(LocalSub::Nested(build_nested_ref(nested_ins, doc, bg_color)));
|
||||
}
|
||||
_ => {
|
||||
// A wide polyline inside a block keeps its thin centre-line
|
||||
// here (`LocalWire` carries no `world_width`, and `finalize`
|
||||
// rebuilds every block wire with `world_width: 0.0`); its band
|
||||
// is drawn by the hatch pipeline (`push_block_wide_fills`),
|
||||
// which transforms with the block instance so the band scales
|
||||
// correctly. The shader band is a top-level-entity path only.
|
||||
// A wide polyline inside a block carries its `world_width` on
|
||||
// the LocalWire; `emit_wire` scales it by the insert transform
|
||||
// so the shader band matches the scaled geometry (same band the
|
||||
// top-level path draws — depth-tested + linetype-dashed).
|
||||
for lw in tessellate_sub_local(doc, entity, anno_scale, bg_color) {
|
||||
subs.push(LocalSub::Wire(lw));
|
||||
}
|
||||
@@ -493,6 +495,7 @@ fn tessellate_sub_local(
|
||||
pattern_length: pat_len,
|
||||
pattern: pat,
|
||||
line_weight_px: lw_px,
|
||||
world_width: wire.world_width,
|
||||
plinegen: wire.plinegen,
|
||||
is_fill_only,
|
||||
color_is_byblock: color_is_byblock && wire_on_base_color,
|
||||
@@ -744,6 +747,10 @@ struct StyleKey {
|
||||
pattern_length: u32,
|
||||
pattern: [u32; 8],
|
||||
line_weight_px: u32,
|
||||
/// Wide-polyline band width (bit-cast). Keeps bands of different widths — and
|
||||
/// bands vs thin wires of the same colour/style — in separate batches so the
|
||||
/// finalized WireModel carries one correct `world_width`.
|
||||
world_width: u32,
|
||||
aci: u8,
|
||||
plinegen: bool,
|
||||
/// Marks batches that emit only `fill_tris` with no wire `points`. The
|
||||
@@ -759,6 +766,7 @@ struct BatchEntry {
|
||||
pattern_length: f32,
|
||||
pattern: [f32; 8],
|
||||
line_weight_px: f32,
|
||||
world_width: f32,
|
||||
aci: u8,
|
||||
plinegen: bool,
|
||||
points: Vec<[f32; 3]>,
|
||||
@@ -809,6 +817,7 @@ impl BatchEntry {
|
||||
pat_len: f32,
|
||||
pat: [f32; 8],
|
||||
lw_px: f32,
|
||||
world_width: f32,
|
||||
aci: u8,
|
||||
plinegen: bool,
|
||||
_is_fill_only: bool,
|
||||
@@ -823,6 +832,7 @@ impl BatchEntry {
|
||||
pattern_length: pat_len,
|
||||
pattern: pat,
|
||||
line_weight_px: lw_px,
|
||||
world_width,
|
||||
aci,
|
||||
plinegen,
|
||||
min_x: f32::INFINITY,
|
||||
@@ -854,7 +864,7 @@ impl Batches {
|
||||
// the cached defn.
|
||||
let color = crate::scene::view::render::adapt_to_bg(b.color, bg_color);
|
||||
WireModel {
|
||||
world_width: 0.0,
|
||||
world_width: b.world_width,
|
||||
fill_is_3d: false,
|
||||
pick_tris: b.pick_tris,
|
||||
pick_tris_low: b.pick_tris_low,
|
||||
@@ -896,6 +906,7 @@ fn style_key(
|
||||
pat_len: f32,
|
||||
pat: [f32; 8],
|
||||
lw_px: f32,
|
||||
world_width: f32,
|
||||
aci: u8,
|
||||
plinegen: bool,
|
||||
is_fill_only: bool,
|
||||
@@ -919,6 +930,7 @@ fn style_key(
|
||||
pat[7].to_bits(),
|
||||
],
|
||||
line_weight_px: lw_px.to_bits(),
|
||||
world_width: world_width.to_bits(),
|
||||
aci,
|
||||
plinegen,
|
||||
is_fill_only,
|
||||
@@ -1145,11 +1157,27 @@ fn emit_wire(
|
||||
let final_pat_len = final_pat_len * ctx.pslt_factor;
|
||||
let final_pat = final_pat.map(|v| v * ctx.pslt_factor);
|
||||
|
||||
// A wide polyline's band width is baked in block-local units; scale it by
|
||||
// the insert transform so the shader band matches the scaled geometry.
|
||||
// Average the X and Y axis image lengths — exact for a uniform insert, a
|
||||
// sensible mean for a non-uniform one (the band carries one width).
|
||||
let final_world_width = if lw.world_width > 0.0 {
|
||||
let o = accum_xform.apply(Vector3::new(0.0, 0.0, 0.0));
|
||||
let ax = accum_xform.apply(Vector3::new(1.0, 0.0, 0.0));
|
||||
let ay = accum_xform.apply(Vector3::new(0.0, 1.0, 0.0));
|
||||
let sx = ((ax.x - o.x).powi(2) + (ax.y - o.y).powi(2) + (ax.z - o.z).powi(2)).sqrt();
|
||||
let sy = ((ay.x - o.x).powi(2) + (ay.y - o.y).powi(2) + (ay.z - o.z).powi(2)).sqrt();
|
||||
lw.world_width * ((sx + sy) * 0.5) as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let key = style_key(
|
||||
final_color,
|
||||
final_pat_len,
|
||||
final_pat,
|
||||
final_lw_px,
|
||||
final_world_width,
|
||||
lw.aci,
|
||||
lw.plinegen,
|
||||
lw.is_fill_only,
|
||||
@@ -1170,6 +1198,7 @@ fn emit_wire(
|
||||
final_pat_len,
|
||||
final_pat,
|
||||
final_lw_px,
|
||||
final_world_width,
|
||||
lw.aci,
|
||||
lw.plinegen,
|
||||
lw.is_fill_only,
|
||||
|
||||
@@ -1068,7 +1068,7 @@ pub fn tessellate(
|
||||
// linetype dashes it); the band also backs pick.
|
||||
let (pick_tris, pick_tris_low) = points_to_ds(te.pick_tris);
|
||||
return vec![WireModel {
|
||||
world_width: lwpolyline_band_width(entity),
|
||||
world_width: polyline_band_width(entity),
|
||||
fill_is_3d: false,
|
||||
pick_tris,
|
||||
pick_tris_low,
|
||||
@@ -1130,13 +1130,18 @@ pub fn tessellate(
|
||||
let mut out = Vec::new();
|
||||
let mut is_first = true;
|
||||
|
||||
// A thickened wide polyline's extrusion — its corner / cap edges
|
||||
// A thickened polyline's extrusion — its corner / cap edges
|
||||
// frame the solid tube and read black (like solid-with-edges
|
||||
// outlines), while the tube fill keeps the entity colour.
|
||||
let edge_color = if matches!(
|
||||
// outlines), while the tube fill keeps the entity colour. Both
|
||||
// wide polyline kinds (LwPolyline + Polyline2D) extrude tubes.
|
||||
let is_thick_extrusion = matches!(
|
||||
entity,
|
||||
EntityType::LwPolyline(p) if p.thickness.abs() > 1e-10
|
||||
) {
|
||||
) || matches!(
|
||||
entity,
|
||||
EntityType::Polyline2D(p) if p.thickness.abs() > 1e-10
|
||||
);
|
||||
let edge_color = if is_thick_extrusion {
|
||||
[0.0, 0.0, 0.0, 1.0]
|
||||
} else {
|
||||
color
|
||||
@@ -1260,7 +1265,7 @@ pub fn tessellate(
|
||||
// treatment as the Contour arm, restarting the dash per segment.
|
||||
let (pick_tris, pick_tris_low) = points_to_ds(te.pick_tris);
|
||||
return vec![WireModel {
|
||||
world_width: lwpolyline_band_width(entity),
|
||||
world_width: polyline_band_width(entity),
|
||||
fill_is_3d: false,
|
||||
pick_tris,
|
||||
pick_tris_low,
|
||||
@@ -1509,26 +1514,35 @@ pub(crate) fn entity_z(entity: &EntityType) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Band width (drawing units) of a wide LwPolyline whose flat band is drawn by
|
||||
/// expanding its centre-line wire in the shader. `0.0` = a zero-width polyline
|
||||
/// or a non-LwPolyline (a normal screen-pixel wire). A thickness-extruded
|
||||
/// polyline is excluded: its band becomes a 3-D tube (`thick_wide_band`), not a
|
||||
/// flat shader band. A tapering polyline (per-vertex start/end widths) collapses
|
||||
/// to its widest edge — the shader carries one width per wire.
|
||||
fn lwpolyline_band_width(entity: &EntityType) -> f32 {
|
||||
match entity {
|
||||
/// Band width (drawing units) of a wide polyline whose flat band is drawn by
|
||||
/// expanding its centre-line wire in the shader. `0.0` = a zero-width polyline,
|
||||
/// a non-polyline (a normal screen-pixel wire), or a thickness-extruded one — an
|
||||
/// LwPolyline thickens into a 3-D tube (`thick_wide_band`) and a Polyline2D
|
||||
/// keeps its hatch band (only its centre-line extrudes; no tube yet), so neither
|
||||
/// takes the flat shader band. A tapering polyline (per-vertex start/end widths)
|
||||
/// collapses to its widest edge — the shader carries one width per wire.
|
||||
fn polyline_band_width(entity: &EntityType) -> f32 {
|
||||
let w = match entity {
|
||||
EntityType::LwPolyline(p) if p.thickness.abs() <= 1e-10 => {
|
||||
let mut w = p.constant_width;
|
||||
for v in &p.vertices {
|
||||
w = w.max(v.start_width).max(v.end_width);
|
||||
}
|
||||
if w > 1e-9 {
|
||||
w as f32
|
||||
} else {
|
||||
0.0
|
||||
w
|
||||
}
|
||||
EntityType::Polyline2D(p) if p.thickness.abs() <= 1e-10 => {
|
||||
let mut w = p.start_width.max(p.end_width);
|
||||
for v in &p.vertices {
|
||||
w = w.max(v.start_width).max(v.end_width);
|
||||
}
|
||||
w
|
||||
}
|
||||
_ => 0.0,
|
||||
};
|
||||
if w > 1e-9 {
|
||||
w as f32
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-143
@@ -688,53 +688,12 @@ impl Scene {
|
||||
// true applies the screen selection highlight.)
|
||||
models.extend(self.exploded_insert_hatch_models(layout_block, hatch_bg, true));
|
||||
|
||||
// Wide LWPolyline and Polyline2D fills
|
||||
for entity in self.document.entities() {
|
||||
let (common, fill_origin, fills) = match entity {
|
||||
// A wide LwPolyline no longer draws its band here: the shader
|
||||
// expands the centre-line wire to `world_width` (a real
|
||||
// depth-tested band that also carries the linetype dash), so a
|
||||
// second flat 2-D band with only draw-order depth would double
|
||||
// it and show through 3-D geometry. A thickened one is likewise
|
||||
// a 3-D tube built by the tessellator. Its band still backs pick
|
||||
// (`pick_tris`), just not this fill.
|
||||
EntityType::LwPolyline(_) => continue,
|
||||
EntityType::Polyline2D(pl) => {
|
||||
let (o, f) = crate::entities::polyline::wide_fills(pl);
|
||||
(&pl.common, o, f)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
if fills.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if common.invisible || layer_hidden(&common.layer) {
|
||||
continue;
|
||||
}
|
||||
if !self.belongs_to_visible_block(common.handle, common.owner_handle, layout_block) {
|
||||
continue;
|
||||
}
|
||||
let base_color = self.render_style(entity).0;
|
||||
let selected = self.selected.contains(&common.handle);
|
||||
let color = if selected {
|
||||
[0.15, 0.55, 1.00, 1.0]
|
||||
} else {
|
||||
base_color
|
||||
};
|
||||
for boundary in fills {
|
||||
models.push(HatchModel {
|
||||
boundary: Arc::new(boundary),
|
||||
boundary_wcs: None,
|
||||
pattern: model::hatch_model::HatchPattern::Solid,
|
||||
name: "SOLID".into(),
|
||||
color,
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: fill_origin,
|
||||
draw_depth: depth_map.get(&common.handle.value()).copied().unwrap_or(0.0),
|
||||
});
|
||||
}
|
||||
}
|
||||
// Wide LwPolyline / Polyline2D bands are no longer hatch fills at
|
||||
// model level: a flat band is drawn by expanding its centre-line wire
|
||||
// to `world_width` in the shader (depth-tested, linetype-dashed), and a
|
||||
// thickened one is extruded into a 3-D tube by the tessellator. Only
|
||||
// block-internal wide polylines still band via the hatch path (see
|
||||
// `push_block_wide_fills`), where it scales with the insert transform.
|
||||
|
||||
models
|
||||
}
|
||||
@@ -907,45 +866,11 @@ impl Scene {
|
||||
models.push(model);
|
||||
}
|
||||
}
|
||||
// Wide LwPolyline / Polyline2D inside a block: materialize its
|
||||
// width bands at world position, same as a block-internal
|
||||
// hatch. Without this a wide polyline in a block drew at zero
|
||||
// width (its centreline came from the wire path, the band
|
||||
// fill only from the model-space loop that skips blocks). (#222)
|
||||
EntityType::LwPolyline(pl) => {
|
||||
if pl.common.invisible || layer_hidden(&pl.common.layer) {
|
||||
continue;
|
||||
}
|
||||
let (origin, fills) =
|
||||
crate::entities::lwpolyline::wide_fills(&pl);
|
||||
self.push_block_wide_fills(
|
||||
&mut models,
|
||||
&EntityType::LwPolyline(pl),
|
||||
origin,
|
||||
fills,
|
||||
sub_ins_color,
|
||||
sub_l0,
|
||||
&clip_poly,
|
||||
selected,
|
||||
);
|
||||
}
|
||||
EntityType::Polyline2D(pl) => {
|
||||
if pl.common.invisible || layer_hidden(&pl.common.layer) {
|
||||
continue;
|
||||
}
|
||||
let (origin, fills) =
|
||||
crate::entities::polyline::wide_fills(&pl);
|
||||
self.push_block_wide_fills(
|
||||
&mut models,
|
||||
&EntityType::Polyline2D(pl),
|
||||
origin,
|
||||
fills,
|
||||
sub_ins_color,
|
||||
sub_l0,
|
||||
&clip_poly,
|
||||
selected,
|
||||
);
|
||||
}
|
||||
// Wide LwPolyline / Polyline2D bands inside a block are drawn
|
||||
// by the shader wire path — block_cache carries each centre-
|
||||
// line's `world_width` and scales it by the insert transform
|
||||
// (`emit_wire`) — not as hatch fills here. Same depth-tested,
|
||||
// linetype-dashed band as at model level. (#222)
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -953,63 +878,6 @@ impl Scene {
|
||||
models
|
||||
}
|
||||
|
||||
/// Materialize a block-exploded wide polyline's width bands (from
|
||||
/// `wide_fills`, already in world coords) as solid `HatchModel`s: resolve the
|
||||
/// block-child colour inheritance (NO background adaptation — a width band is
|
||||
/// the polyline's own colour, not a hatch) and apply any XCLIP. Shared by the
|
||||
/// LwPolyline / Polyline2D arms of the block-explode fill walk. (#222)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn push_block_wide_fills(
|
||||
&self,
|
||||
models: &mut Vec<HatchModel>,
|
||||
sub_entity: &EntityType,
|
||||
origin: [f64; 2],
|
||||
fills: Vec<Vec<[f32; 2]>>,
|
||||
sub_ins_color: [f32; 4],
|
||||
sub_l0: crate::scene::view::render::InheritStyle,
|
||||
clip_poly: &Option<Vec<[f32; 2]>>,
|
||||
selected: bool,
|
||||
) {
|
||||
if fills.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut color = crate::scene::view::render::render_style_for_block_sub(
|
||||
&self.document,
|
||||
sub_entity,
|
||||
sub_ins_color,
|
||||
0.0,
|
||||
[0.0; 8],
|
||||
0.0,
|
||||
sub_l0,
|
||||
)
|
||||
.0;
|
||||
if selected {
|
||||
color = [0.15, 0.55, 1.00, color[3]];
|
||||
}
|
||||
for boundary in fills {
|
||||
let ring = if let Some(poly) = clip_poly {
|
||||
let clipped = pick::xclip::clip_hatch_boundary(&boundary, origin, poly);
|
||||
if clipped.is_empty() {
|
||||
continue;
|
||||
}
|
||||
clipped
|
||||
} else {
|
||||
boundary
|
||||
};
|
||||
models.push(HatchModel {
|
||||
boundary: Arc::new(ring),
|
||||
boundary_wcs: None,
|
||||
pattern: model::hatch_model::HatchPattern::Solid,
|
||||
name: "SOLID".into(),
|
||||
color,
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: origin,
|
||||
draw_depth: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Wipeout fill models — rendered in a separate pass AFTER wires so that
|
||||
/// wipeouts correctly mask everything below them in the draw order.
|
||||
pub(crate) fn wipeout_models(&self) -> Vec<HatchModel> {
|
||||
|
||||
Reference in new issue
Block a user