forked from 1b-agent/opencadstudio-upstream
feat: plinegen + SAB parsing for Solid3D/Region/Body
LwPolyline PLINEGEN=0 (DXF default): emit SegmentedLines with NaN separators between vertex-to-vertex segments; wire_gpu resets arc-length to 0 after each NaN so linetype pattern restarts per vertex. PLINEGEN=1: existing Contour path unchanged (continuous pattern). WireModel gains plinegen field propagated through tessellate pipeline. Solid3D/Region/Body: call SabReader::read() when parse_sat() returns None due to binary SAB format (DWG files / newer AutoCAD exports). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
63b17547f9
commit
27aca41dd1
39 files changed
+168
-15
No files matched your search
+6
-6
@@ -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.
|
||||
@@ -1366,6 +1366,7 @@ impl H7CAD {
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
aabb: crate::scene::WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
};
|
||||
previews.push(guide);
|
||||
}
|
||||
|
||||
@@ -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<TangentGeom> = 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];
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -125,6 +125,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,5 +101,6 @@ fn preview_line(a: Vec3, b: Vec3) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,7 @@ impl CadCommand for DimBaselineCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ impl CadCommand for DimContinueCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ impl CadCommand for DimJogLineCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,7 @@ impl CadCommand for DimTeditCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ impl CadCommand for QdimCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,5 +112,6 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
@@ -145,6 +145,7 @@ impl CadCommand for TableCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -98,6 +98,7 @@ impl CadCommand for ToleranceCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,7 @@ impl CadCommand for AttdefCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -527,5 +527,6 @@ fn line_wire(from: Vec3, to: Vec3) -> WireModel {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,7 @@ impl CadCommand for LineCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,7 @@ impl CadCommand for MlineCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ impl CadCommand for ImageCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,7 @@ impl CadCommand for RevCloudCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ impl CadCommand for AreaCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ impl CadCommand for DistCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,7 @@ impl CadCommand for StretchCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
|
||||
@@ -98,6 +98,7 @@ impl CadCommand for MviewCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ impl CadCommand for PlotWindowCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,7 @@ impl CadCommand for ZoomWindowCommand {
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ pub enum TruckObject {
|
||||
Text(Vec<TextStroke>),
|
||||
/// 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),
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ pub fn apply_along(
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -3211,6 +3211,7 @@ fn tessellate_entity(
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
});
|
||||
return wires;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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<Me
|
||||
Some(MeshModel { name, verts, normals, indices, color, selected: false })
|
||||
}
|
||||
|
||||
fn parse_acis(sat_fn: impl FnOnce() -> Option<SatDocument>, is_binary: bool, sab_data: &[u8]) -> Option<SatDocument> {
|
||||
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<MeshModel> {
|
||||
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<MeshModel> {
|
||||
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<MeshModel> {
|
||||
/// 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<MeshModel> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user