diff --git a/INTEGRATION_GAPS.md b/INTEGRATION_GAPS.md index b9587d7a7..f77dcec95 100644 --- a/INTEGRATION_GAPS.md +++ b/INTEGRATION_GAPS.md @@ -32,7 +32,7 @@ Legend: ✅ Done · ⚠️ Partial · ❌ Not done | Status | Entity | Ignored Field(s) | Effect | |---|---|---|---| | ✅ | **Arc / Circle / Line / LwPolyline / Polyline2D** | `thickness` | Extrudes along WCS normal — `src/entities/{arc,circle,line,lwpolyline,polyline}.rs` | -| ❌ | **LWPolyline** | `plinegen` flag | Linetype pattern resets at each vertex instead of continuing | +| ✅ | **LWPolyline** | `plinegen` flag | `plinegen=false` → `SegmentedLines` with NaN separators + distance reset in `wire_gpu.rs`; `plinegen=true` → `Contour` (continuous) | --- @@ -49,7 +49,7 @@ Legend: ✅ Done · ⚠️ Partial · ❌ Not done | Status | Entity | Missing | |---|---|---| -| ⚠️ | **Solid3D / Region / Body** | `src/scene/solid3d_tess.rs` exists with MeshModel support; no real mesh from ACIS data | +| ✅ | **Solid3D / Region / Body** | SAT (text) + SAB (binary) both parsed — `SabReader::read` called when `is_binary` — tessellates plane/cone/sphere/torus faces — `src/scene/solid3d_tess.rs` | ### Partial Render @@ -207,13 +207,13 @@ These are fixed in our post-load `fix_dxf_dimension_rotations()` in `src/io/mod. | Status | Count | |---|---| -| ✅ Done | 48 | -| ⚠️ Partial | 2 | +| ✅ Done | 50 | +| ⚠️ Partial | 1 | | ❌ Not done | 0 | -| **Total** | **50** | +| **Total** | **51** | ### Remaining gaps by priority **Medium:** Viewport GPU scissor rect (pixel-level boundary clipping for overlapping viewports) -**Low:** LWPolyline plinegen — GPU shader change needed; current behavior is continuous arc-length across vertices (equivalent to plinegen=true). Segment-restart mode (plinegen=false) requires distance reset logic in the wire shader. +No remaining low-priority gaps. diff --git a/src/app/update.rs b/src/app/update.rs index e9be7b954..a94c54785 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -1366,6 +1366,7 @@ impl H7CAD { tangent_geoms: vec![], key_vertices: vec![], aabb: crate::scene::WireModel::UNBOUNDED_AABB, + plinegen: true, }; previews.push(guide); } diff --git a/src/entities/lwpolyline.rs b/src/entities/lwpolyline.rs index dc41ffce8..d31a428ff 100644 --- a/src/entities/lwpolyline.rs +++ b/src/entities/lwpolyline.rs @@ -184,6 +184,62 @@ fn to_truck(pline: &LwPolyline) -> TruckEntity { return thick_segments(&seg_data, &path, pline.thickness, normal, kv, tgs); } + // plinegen=false: NaN-separated segments so the linetype pattern restarts per vertex. + if !pline.plinegen { + let mut pts: Vec<[f32; 3]> = Vec::new(); + let mut tgs: Vec = Vec::new(); + let mut kv: Vec<[f32; 3]> = Vec::new(); + for i in 0..seg_count { + let va = &verts[i]; + let vb = &verts[(i + 1) % count]; + let (ox0, oy0) = (va.location.x, va.location.y); + let (ox1, oy1) = (vb.location.x, vb.location.y); + let bulge = va.bulge; + let (wx0, wy0, wz0) = to_wcs(ox0, oy0); + let p_start = [wx0 as f32, wy0 as f32, wz0 as f32]; + pts.push(p_start); + if i == 0 { kv.push(p_start); } + if bulge.abs() < 1e-9 { + let (wx1, wy1, wz1) = to_wcs(ox1, oy1); + let p_end = [wx1 as f32, wy1 as f32, wz1 as f32]; + pts.push(p_end); + kv.push(p_end); + tgs.push(TangentGeom::Line { p1: p_start, p2: p_end }); + } else { + let angle = 4.0 * bulge.atan(); + let dx = ox1 - ox0; let dy = oy1 - oy0; + let d = (dx * dx + dy * dy).sqrt().max(1e-12); + let r = (d / 2.0) / (angle / 2.0).sin().abs(); + let mx = (ox0 + ox1) * 0.5; let my = (oy0 + oy1) * 0.5; + let px = -dy / d; let py = dx / d; + let ss = if bulge > 0.0 { 1.0_f64 } else { -1.0_f64 }; + let h = r - (r * r - d * d / 4.0).max(0.0).sqrt(); + let ocx = mx + ss * px * (r - h); let ocy = my + ss * py * (r - h); + let a0 = (oy0 - ocy).atan2(ox0 - ocx); + let mut a1 = (oy1 - ocy).atan2(ox1 - ocx); + if bulge > 0.0 { if a1 < a0 { a1 += TAU; } } else { if a1 > a0 { a1 -= TAU; } } + for j in 1..=16usize { + let a = a0 + (a1 - a0) * (j as f64 / 16.0); + let (wx, wy, wz) = to_wcs(ocx + r * a.cos(), ocy + r * a.sin()); + pts.push([wx as f32, wy as f32, wz as f32]); + } + let (wx1, wy1, wz1) = to_wcs(ox1, oy1); + kv.push([wx1 as f32, wy1 as f32, wz1 as f32]); + let (wcx, wcy, wcz) = to_wcs(ocx, ocy); + tgs.push(TangentGeom::Circle { center: [wcx as f32, wcy as f32, wcz as f32], radius: r as f32 }); + } + if i + 1 < seg_count { + pts.push([f32::NAN; 3]); + } + } + return TruckEntity { + object: TruckObject::SegmentedLines(pts), + snap_pts: vec![], + tangent_geoms: tgs, + key_vertices: kv, + }; + } + for i in 0..seg_count { let v0 = &verts[i]; let v1 = &verts[(i + 1) % count]; diff --git a/src/modules/annotate/aligned_dim.rs b/src/modules/annotate/aligned_dim.rs index b569abae0..9abfd8c6e 100644 --- a/src/modules/annotate/aligned_dim.rs +++ b/src/modules/annotate/aligned_dim.rs @@ -102,6 +102,7 @@ impl CadCommand for AlignedDimensionCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } @@ -136,5 +137,6 @@ fn preview_aligned(p1: Vec3, p2: Vec3, dim_pt: Vec3) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/angular_dim.rs b/src/modules/annotate/angular_dim.rs index bc3ad7932..1c126ea11 100644 --- a/src/modules/annotate/angular_dim.rs +++ b/src/modules/annotate/angular_dim.rs @@ -125,6 +125,7 @@ fn preview_wire(points: Vec) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/diameter_dim.rs b/src/modules/annotate/diameter_dim.rs index 93f530f67..4d9219dce 100644 --- a/src/modules/annotate/diameter_dim.rs +++ b/src/modules/annotate/diameter_dim.rs @@ -101,5 +101,6 @@ fn preview_line(a: Vec3, b: Vec3) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/dim_baseline.rs b/src/modules/annotate/dim_baseline.rs index 3f7ab1712..8ab8f58a5 100644 --- a/src/modules/annotate/dim_baseline.rs +++ b/src/modules/annotate/dim_baseline.rs @@ -143,6 +143,7 @@ impl CadCommand for DimBaselineCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/annotate/dim_continue.rs b/src/modules/annotate/dim_continue.rs index eb560a604..8b90b4d67 100644 --- a/src/modules/annotate/dim_continue.rs +++ b/src/modules/annotate/dim_continue.rs @@ -140,6 +140,7 @@ impl CadCommand for DimContinueCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/annotate/dimjogline.rs b/src/modules/annotate/dimjogline.rs index 89b265d82..11807be3d 100644 --- a/src/modules/annotate/dimjogline.rs +++ b/src/modules/annotate/dimjogline.rs @@ -94,6 +94,7 @@ impl CadCommand for DimJogLineCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/annotate/dimtedit.rs b/src/modules/annotate/dimtedit.rs index 6a2efc36d..1fedee8a7 100644 --- a/src/modules/annotate/dimtedit.rs +++ b/src/modules/annotate/dimtedit.rs @@ -102,6 +102,7 @@ impl CadCommand for DimTeditCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } diff --git a/src/modules/annotate/leader_cmd.rs b/src/modules/annotate/leader_cmd.rs index 3e799c435..42ebd82e2 100644 --- a/src/modules/annotate/leader_cmd.rs +++ b/src/modules/annotate/leader_cmd.rs @@ -202,6 +202,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/linear_dim.rs b/src/modules/annotate/linear_dim.rs index 188150711..ae0cd49c4 100644 --- a/src/modules/annotate/linear_dim.rs +++ b/src/modules/annotate/linear_dim.rs @@ -113,6 +113,7 @@ fn preview_wire(points: Vec) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/mleader_cmd.rs b/src/modules/annotate/mleader_cmd.rs index 9ae9c1822..808d43364 100644 --- a/src/modules/annotate/mleader_cmd.rs +++ b/src/modules/annotate/mleader_cmd.rs @@ -155,6 +155,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/mleader_edit.rs b/src/modules/annotate/mleader_edit.rs index 8302a4fd7..866c7446e 100644 --- a/src/modules/annotate/mleader_edit.rs +++ b/src/modules/annotate/mleader_edit.rs @@ -366,6 +366,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/qdim.rs b/src/modules/annotate/qdim.rs index 7e11652fd..6c04f0570 100644 --- a/src/modules/annotate/qdim.rs +++ b/src/modules/annotate/qdim.rs @@ -99,6 +99,7 @@ impl CadCommand for QdimCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/annotate/radius_dim.rs b/src/modules/annotate/radius_dim.rs index 0f0970696..9470a5089 100644 --- a/src/modules/annotate/radius_dim.rs +++ b/src/modules/annotate/radius_dim.rs @@ -112,5 +112,6 @@ fn preview_wire(points: Vec) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/annotate/table_cmd.rs b/src/modules/annotate/table_cmd.rs index e57c9c8f9..db7c3211a 100644 --- a/src/modules/annotate/table_cmd.rs +++ b/src/modules/annotate/table_cmd.rs @@ -145,6 +145,7 @@ impl CadCommand for TableCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } else { None diff --git a/src/modules/annotate/tolerance_cmd.rs b/src/modules/annotate/tolerance_cmd.rs index c33e3541b..3f8c27530 100644 --- a/src/modules/annotate/tolerance_cmd.rs +++ b/src/modules/annotate/tolerance_cmd.rs @@ -98,6 +98,7 @@ impl CadCommand for ToleranceCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/attdef.rs b/src/modules/home/draw/attdef.rs index bf3c254fa..2df8f879c 100644 --- a/src/modules/home/draw/attdef.rs +++ b/src/modules/home/draw/attdef.rs @@ -134,6 +134,7 @@ impl CadCommand for AttdefCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/ellipse.rs b/src/modules/home/draw/ellipse.rs index bd45561bd..c80a31e46 100644 --- a/src/modules/home/draw/ellipse.rs +++ b/src/modules/home/draw/ellipse.rs @@ -527,5 +527,6 @@ fn line_wire(from: Vec3, to: Vec3) -> WireModel { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } diff --git a/src/modules/home/draw/line.rs b/src/modules/home/draw/line.rs index 389c2f65b..07ec2cc2e 100644 --- a/src/modules/home/draw/line.rs +++ b/src/modules/home/draw/line.rs @@ -88,6 +88,7 @@ impl CadCommand for LineCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/mline.rs b/src/modules/home/draw/mline.rs index 31557db85..e1ea3ebb8 100644 --- a/src/modules/home/draw/mline.rs +++ b/src/modules/home/draw/mline.rs @@ -113,6 +113,7 @@ impl CadCommand for MlineCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/raster_image.rs b/src/modules/home/draw/raster_image.rs index 6d8eac633..3b1833455 100644 --- a/src/modules/home/draw/raster_image.rs +++ b/src/modules/home/draw/raster_image.rs @@ -112,6 +112,7 @@ impl CadCommand for ImageCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/ray.rs b/src/modules/home/draw/ray.rs index 7af64eceb..c13cbc3d7 100644 --- a/src/modules/home/draw/ray.rs +++ b/src/modules/home/draw/ray.rs @@ -86,6 +86,7 @@ impl CadCommand for RayCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } @@ -164,6 +165,7 @@ impl CadCommand for XLineCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/revcloud.rs b/src/modules/home/draw/revcloud.rs index ec05c373d..ceb564668 100644 --- a/src/modules/home/draw/revcloud.rs +++ b/src/modules/home/draw/revcloud.rs @@ -83,6 +83,7 @@ impl CadCommand for RevCloudCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/draw/wipeout.rs b/src/modules/home/draw/wipeout.rs index 27344f119..86b2108f0 100644 --- a/src/modules/home/draw/wipeout.rs +++ b/src/modules/home/draw/wipeout.rs @@ -119,6 +119,7 @@ impl CadCommand for WipeoutCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } WipeoutMode::Polygonal => { @@ -140,6 +141,7 @@ impl CadCommand for WipeoutCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/inquiry/area.rs b/src/modules/home/inquiry/area.rs index 00dd7d0e4..2bb3c76b0 100644 --- a/src/modules/home/inquiry/area.rs +++ b/src/modules/home/inquiry/area.rs @@ -76,6 +76,7 @@ impl CadCommand for AreaCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/inquiry/dist.rs b/src/modules/home/inquiry/dist.rs index ec2a23805..3dca411a5 100644 --- a/src/modules/home/inquiry/dist.rs +++ b/src/modules/home/inquiry/dist.rs @@ -71,6 +71,7 @@ impl CadCommand for DistCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/home/modify/stretch.rs b/src/modules/home/modify/stretch.rs index 3df965f6a..14968c99e 100644 --- a/src/modules/home/modify/stretch.rs +++ b/src/modules/home/modify/stretch.rs @@ -134,6 +134,7 @@ impl CadCommand for StretchCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } _ => None, diff --git a/src/modules/layout/mview.rs b/src/modules/layout/mview.rs index 550d46d52..5a76f0875 100644 --- a/src/modules/layout/mview.rs +++ b/src/modules/layout/mview.rs @@ -98,6 +98,7 @@ impl CadCommand for MviewCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/view/plot_window.rs b/src/modules/view/plot_window.rs index 3627facb0..c5e1cbd13 100644 --- a/src/modules/view/plot_window.rs +++ b/src/modules/view/plot_window.rs @@ -63,6 +63,7 @@ impl CadCommand for PlotWindowCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/modules/view/zoom_window.rs b/src/modules/view/zoom_window.rs index a8cfa5377..ef5732079 100644 --- a/src/modules/view/zoom_window.rs +++ b/src/modules/view/zoom_window.rs @@ -69,6 +69,7 @@ impl CadCommand for ZoomWindowCommand { aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) } } diff --git a/src/scene/acad_to_truck.rs b/src/scene/acad_to_truck.rs index b7f05e6e3..6ba326644 100644 --- a/src/scene/acad_to_truck.rs +++ b/src/scene/acad_to_truck.rs @@ -23,6 +23,8 @@ pub enum TruckObject { Text(Vec), /// Pre-computed NaN-separated 3-D point list (leader lines, arrowheads, etc.). Lines(Vec<[f32; 3]>), + /// Like Lines but linetype pattern restarts at each NaN-separated segment (plinegen=false). + SegmentedLines(Vec<[f32; 3]>), Volume(Solid), } diff --git a/src/scene/complex_lt.rs b/src/scene/complex_lt.rs index dc41cbaea..360974ac3 100644 --- a/src/scene/complex_lt.rs +++ b/src/scene/complex_lt.rs @@ -202,6 +202,7 @@ pub fn apply_along( aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }) .collect() } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 0880497de..4067ce922 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -3211,6 +3211,7 @@ fn tessellate_entity( tangent_geoms: vec![], key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }); return wires; } diff --git a/src/scene/pipeline/wire_gpu.rs b/src/scene/pipeline/wire_gpu.rs index 9dc59bb11..0ff064af9 100644 --- a/src/scene/pipeline/wire_gpu.rs +++ b/src/scene/pipeline/wire_gpu.rs @@ -148,7 +148,12 @@ impl WireGpu { let p = wire.points[i - 1]; let q = wire.points[i]; if !p[0].is_finite() || !q[0].is_finite() { - dists[i] = dists[i - 1]; + // plinegen=false: reset to 0 at the first real point after a NaN separator. + dists[i] = if !wire.plinegen && !p[0].is_finite() && q[0].is_finite() { + 0.0 + } else { + dists[i - 1] + }; } else { let dx = q[0] - p[0]; let dy = q[1] - p[1]; @@ -234,10 +239,13 @@ impl WireGpu { for i in 1..n { let p = wire.points[i - 1]; let q = wire.points[i]; - // If either point is non-finite (NaN sentinel or ±inf from overflow), - // keep the same distance — the segment will be skipped anyway. if !p[0].is_finite() || !q[0].is_finite() { - dists[i] = dists[i - 1]; + // plinegen=false: reset to 0 at the first real point after a NaN separator. + dists[i] = if !wire.plinegen && !p[0].is_finite() && q[0].is_finite() { + 0.0 + } else { + dists[i - 1] + }; } else { let dx = q[0] - p[0]; let dy = q[1] - p[1]; diff --git a/src/scene/solid3d_tess.rs b/src/scene/solid3d_tess.rs index 1519b7069..88988d1d8 100644 --- a/src/scene/solid3d_tess.rs +++ b/src/scene/solid3d_tess.rs @@ -14,8 +14,8 @@ use std::collections::HashSet; use std::f64::consts::TAU; use acadrust::entities::acis::{ - SatCoedge, SatConeSurface, SatDocument, SatEdge, SatFace, SatLoop, SatPlaneSurface, SatPoint, - SatPointer, SatSphereSurface, SatTorusSurface, SatVertex, + SabReader, SatCoedge, SatConeSurface, SatDocument, SatEdge, SatFace, SatLoop, + SatPlaneSurface, SatPoint, SatPointer, SatSphereSurface, SatTorusSurface, SatVertex, }; use acadrust::entities::acis::types::Sense; use acadrust::entities::{Body, Region, Solid3D}; @@ -67,16 +67,26 @@ fn tessellate_sat(sat: &SatDocument, name: String, color: [f32; 4]) -> Option Option, is_binary: bool, sab_data: &[u8]) -> Option { + if let Some(doc) = sat_fn() { + return Some(doc); + } + if is_binary && !sab_data.is_empty() { + return SabReader::read(sab_data).ok(); + } + None +} + /// Tessellate a `Region` entity (2D planar ACIS body) into a `MeshModel`. pub fn tessellate_region(region: &Region, color: [f32; 4]) -> Option { - let sat = region.parse_sat()?; + let sat = parse_acis(|| region.parse_sat(), region.acis_data.is_binary, ®ion.acis_data.sab_data)?; let name = region.common.handle.value().to_string(); tessellate_sat(&sat, name, color) } /// Tessellate a `Body` entity (3D ACIS body) into a `MeshModel`. pub fn tessellate_body(body: &Body, color: [f32; 4]) -> Option { - let sat = body.parse_sat()?; + let sat = parse_acis(|| body.parse_sat(), body.acis_data.is_binary, &body.acis_data.sab_data)?; let name = body.common.handle.value().to_string(); tessellate_sat(&sat, name, color) } @@ -86,7 +96,7 @@ pub fn tessellate_body(body: &Body, color: [f32; 4]) -> Option { /// Returns `None` when the entity has no parseable SAT data or produces no /// triangles (e.g. the solid uses only unsupported surface types). pub fn tessellate_solid3d(solid: &Solid3D, color: [f32; 4]) -> Option { - let sat = solid.parse_sat()?; + let sat = parse_acis(|| solid.parse_sat(), solid.acis_data.is_binary, &solid.acis_data.sab_data)?; let name = solid.common.handle.value().to_string(); tessellate_sat(&sat, name, color) } diff --git a/src/scene/tessellate.rs b/src/scene/tessellate.rs index fb841a02f..22dc7d667 100644 --- a/src/scene/tessellate.rs +++ b/src/scene/tessellate.rs @@ -104,6 +104,7 @@ pub fn tessellate( aci: 0, key_vertices: te.key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }; } @@ -132,6 +133,7 @@ pub fn tessellate( aci: 0, key_vertices: te.key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }; } _ => {} @@ -158,6 +160,7 @@ pub fn tessellate( aci: 0, key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }; } } @@ -182,6 +185,7 @@ pub fn tessellate( aci: 0, key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }; } } @@ -212,6 +216,34 @@ pub fn tessellate( aci: 0, key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, + }; + } + + TruckObject::SegmentedLines(points) => { + let [ox, oy, oz] = world_offset; + let local_pts: Vec<[f32; 3]> = points.into_iter().map(|[x, y, z]| { + if x.is_nan() { [x, y, z] } + else { [x - ox as f32, y - oy as f32, z - oz as f32] } + }).collect(); + let snap_pts = offset_snap_pts(te.snap_pts, world_offset); + let key_vertices: Vec<[f32; 3]> = te.key_vertices.into_iter() + .map(|[x, y, z]| [x - ox as f32, y - oy as f32, z - oz as f32]) + .collect(); + return WireModel { + name, + points: local_pts, + color, + selected, + pattern_length, + pattern, + line_weight_px, + snap_pts, + tangent_geoms: te.tangent_geoms, + aci: 0, + key_vertices, + plinegen: false, + aabb: WireModel::UNBOUNDED_AABB, }; } @@ -241,6 +273,7 @@ pub fn tessellate( tangent_geoms, key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, } } @@ -296,6 +329,7 @@ pub fn tessellate_dimension( tangent_geoms: vec![], key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }]; if let Some(text) = dimension_text_entity(dim) { @@ -344,6 +378,7 @@ fn tessellate_leader( aci: 0, key_vertices: vec![], aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }]; } @@ -412,6 +447,7 @@ fn tessellate_leader( tangent_geoms: vec![], key_vertices, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }] } @@ -521,6 +557,7 @@ fn tessellate_multileader( aci: 0, key_vertices: key_verts, aabb: WireModel::UNBOUNDED_AABB, + plinegen: true, }]; // Render text content as MText wire diff --git a/src/scene/wire_model.rs b/src/scene/wire_model.rs index eb354f279..6e7b57186 100644 --- a/src/scene/wire_model.rs +++ b/src/scene/wire_model.rs @@ -60,6 +60,9 @@ pub struct WireModel { /// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected /// by the snap world-space filter. pub aabb: [f32; 4], + /// When false the linetype pattern restarts at each NaN-separated segment + /// (DXF PLINEGEN=0). When true the pattern runs continuously (PLINEGEN=1). + pub plinegen: bool, } impl WireModel { @@ -85,6 +88,7 @@ impl WireModel { tangent_geoms: vec![], key_vertices: vec![], aabb: Self::UNBOUNDED_AABB, + plinegen: true, } } @@ -184,6 +188,7 @@ impl Default for WireModel { tangent_geoms: Vec::new(), key_vertices: Vec::new(), aabb: Self::UNBOUNDED_AABB, + plinegen: true, } } }