fix(polyline): render fill mode boundaries

Use kernel-produced band outlines when FILLMODE is off. Preserve centerline linetype stations through inserts, clipping, projection, and PDF export.
This commit is contained in:
Hakan Seven committed 2026-08-24 22:18:44 +03:00
commit 4209c35ba3
60 files changed
+1620 -575

No files matched your search

+49 -1
View File
@@ -935,6 +935,8 @@ impl OpenCADStudio {
| "SKETCHINC"
| "SKPOLY"
| "SKTOLERANCE"
| "DONUTID"
| "DONUTOD"
| "CENTEREXE"
| "CENTERLAYER"
| "CENTERLTYPE"
@@ -965,7 +967,7 @@ impl OpenCADStudio {
let value = it.next().map(|s| s.trim().to_string());
if name.is_empty() || name == "?" {
self.command_line.push_info(
"SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG ATTREQ ATTDIA DIMASSOC ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE | CLAYER CELTYPE TEXTSTYLE (read-only)",
"SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG ATTREQ ATTDIA DIMASSOC ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE DONUTID DONUTOD CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE | CLAYER CELTYPE TEXTSTYLE (read-only)",
);
} else {
let frame_kind = crate::scene::frame::kind_for_name(&name);
@@ -1081,6 +1083,49 @@ impl OpenCADStudio {
}
return Some(self.finish_dispatch(cmd));
}
if matches!(name.as_str(), "DONUTID" | "DONUTOD") {
let current = if name == "DONUTID" {
crate::modules::draw::defaults::get_donut_inner_diameter()
} else {
crate::modules::draw::defaults::get_donut_outer_diameter()
};
if let Some(value) = &value {
let parsed = value
.trim()
.replace(',', ".")
.parse::<f64>()
.ok()
.filter(|number| number.is_finite());
let valid = parsed.filter(|number| {
if name == "DONUTID" {
*number >= 0.0
} else {
*number > 0.0
}
});
if let Some(number) = valid {
if name == "DONUTID" {
crate::modules::draw::defaults::set_donut_inner_diameter(number);
} else {
crate::modules::draw::defaults::set_donut_outer_diameter(number);
}
self.command_line
.push_output(&format!("{name} = {number}"));
} else {
self.command_line.push_error(if name == "DONUTID" {
"SETVAR: DONUTID requires a finite value greater than or equal to zero."
} else {
"SETVAR: DONUTOD requires a finite value greater than zero."
});
}
} else {
self.command_line.push_output(crate::tf!(
"Enter new value for {name} <{current}>:"
).as_ref());
self.pending_setvar = Some(name.clone());
}
return Some(self.finish_dispatch(cmd));
}
// Parse a boolean given as 0/1 or ON/OFF.
let parse_bool = |s: &str| match s.to_uppercase().as_str() {
"1" | "ON" | "TRUE" => Some(true),
@@ -1849,6 +1894,9 @@ impl OpenCADStudio {
} else {
self.tabs[i].dirty = true;
}
if name == "FILLMODE" {
self.tabs[i].scene.bump_geometry();
}
self.command_line.push_output(&msg);
} else {
// Queried with no value (`changed == false`):
+25
View File
@@ -671,6 +671,31 @@ impl OpenCADStudio {
entity,
));
{
use crate::entities::common::ro_prop;
let xd = &source_entity.common().extended_data;
if !xd.is_empty() {
let mut xd_props = Vec::new();
for rec in xd.records() {
let value_text = rec
.values
.iter()
.map(|value| format!("{value:?}"))
.collect::<Vec<_>>()
.join(", ");
xd_props.push(ro_prop(
t!("Application").as_ref(),
"xdata_value",
format!("{}: {value_text}", rec.application_name),
));
}
sections.push(crate::scene::model::object::PropSection {
title: t!("Extended Data").into_owned(),
props: xd_props,
});
}
}
// Uniform-scale checkbox for block references (#427):
// while the three scale factors are equal (and the user
// hasn't opted into per-axis editing) the panel shows one
+1
View File
@@ -2242,6 +2242,7 @@ impl OpenCADStudio {
let guide = crate::scene::WireModel {
point_marker: None,
taper_widths: Vec::new(),
pattern_stations: Vec::new(),
world_width: 0.0,
depth_override: None,
display_visible: true,