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 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-20 16:04:03 +03:00
1 parent 298bfd4803
commit a8aece1909
6 files changed
+161 -219

No files matched your search

+2 -51
View File
@@ -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(),