forked from 1b-agent/opencadstudio-upstream
Add Graphic Attributes fill and line controls
This commit is contained in:
1 parent
65bd8e1b4c
commit
abef285cc6
16 files changed
+2112
-891
No files matched your search
+14
-5
@@ -1269,10 +1269,12 @@ impl Scene {
|
||||
style.0 = crate::scene::view::render::adapt_to_bg(style.0, hatch_bg);
|
||||
m.aci = style.4;
|
||||
m.line_weight_px = style.3;
|
||||
// A gradient's colour is its first stop (already baked into
|
||||
// the cached model); only solid / pattern fills take the
|
||||
// entity's resolved colour.
|
||||
if !matches!(m.pattern, model::hatch_model::HatchPattern::Gradient { .. }) {
|
||||
// Gradient RGB comes from its own colour stops, while
|
||||
// transparency remains an entity property shared by both
|
||||
// stops. Solid/pattern fills take the complete style.
|
||||
if matches!(m.pattern, model::hatch_model::HatchPattern::Gradient { .. }) {
|
||||
m.set_alpha(style.0[3]);
|
||||
} else {
|
||||
m.color = style.0;
|
||||
}
|
||||
if let EntityType::Hatch(dxf) = e {
|
||||
@@ -2055,7 +2057,14 @@ impl Scene {
|
||||
.colors
|
||||
.get(i)
|
||||
.and_then(|e| e.color.rgb())
|
||||
.map(|(r, g, b)| [r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0])
|
||||
.map(|(r, g, b)| {
|
||||
[
|
||||
r as f32 / 255.0,
|
||||
g as f32 / 255.0,
|
||||
b as f32 / 255.0,
|
||||
color[3],
|
||||
]
|
||||
})
|
||||
};
|
||||
gradient_color1 = stop(0);
|
||||
let color1 = gradient_color1.unwrap_or(color);
|
||||
|
||||
@@ -4,6 +4,43 @@ use acadrust::types::{Vector2, Vector3};
|
||||
use cadkernel::geom2d::{refine_spline_boundary, triangulate_rings, Curve, NurbsCurve};
|
||||
use cadkernel::tessellation::DEFAULT_ANGLE;
|
||||
|
||||
#[test]
|
||||
fn gradient_stops_keep_entity_transparency() {
|
||||
let mut hatch = Hatch::new();
|
||||
hatch.is_solid = true;
|
||||
hatch
|
||||
.paths
|
||||
.push(rectangle([0.0, 0.0], [10.0, 10.0], [0.0; 2]));
|
||||
hatch.gradient_color.enabled = true;
|
||||
hatch.gradient_color.name = "LINEAR".into();
|
||||
hatch.gradient_color.colors = vec![
|
||||
acadrust::entities::hatch::GradientColorEntry {
|
||||
value: 0.0,
|
||||
color: acadrust::types::Color::Rgb { r: 255, g: 0, b: 0 },
|
||||
},
|
||||
acadrust::entities::hatch::GradientColorEntry {
|
||||
value: 1.0,
|
||||
color: acadrust::types::Color::Rgb { r: 0, g: 0, b: 255 },
|
||||
},
|
||||
];
|
||||
|
||||
let mut model = Scene::hatch_model_from_dxf(&hatch, [0.2, 0.3, 0.4, 0.35]).unwrap();
|
||||
assert!((model.color[3] - 0.35).abs() < f32::EPSILON);
|
||||
let crate::scene::model::hatch_model::HatchPattern::Gradient { color2, .. } = &model.pattern
|
||||
else {
|
||||
panic!("gradient hatch must produce a gradient render pattern");
|
||||
};
|
||||
assert!((color2[3] - 0.35).abs() < f32::EPSILON);
|
||||
|
||||
model.set_alpha(0.6);
|
||||
assert!((model.color[3] - 0.6).abs() < f32::EPSILON);
|
||||
let crate::scene::model::hatch_model::HatchPattern::Gradient { color2, .. } = &model.pattern
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
assert!((color2[3] - 0.6).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
fn narrow(clearance: f64, offset: [f64; 2]) -> NurbsCurve {
|
||||
let line = |a: [f64; 2], b: [f64; 2]| {
|
||||
[
|
||||
@@ -184,8 +221,7 @@ fn valid_samples_are_unchanged_and_invalid_samples_stay_rejected() {
|
||||
|p| p
|
||||
)
|
||||
.is_none());
|
||||
assert!(refine_spline_boundary(
|
||||
&vec![[0.0; 2]; 513],
|
||||
assert!(refine_spline_boundary(&vec![[0.0; 2]; 513],
|
||||
|| panic!("size cap ignored"),
|
||||
|p| p
|
||||
)
|
||||
|
||||
@@ -272,6 +272,18 @@ pub struct HatchModel {
|
||||
pub draw_depth: f32,
|
||||
}
|
||||
|
||||
impl HatchModel {
|
||||
/// Apply an entity's resolved opacity to every colour stop. Gradient stop
|
||||
/// colours come from the HATCH payload, but transparency remains a common
|
||||
/// entity property and must affect both ends equally.
|
||||
pub(crate) fn set_alpha(&mut self, alpha: f32) {
|
||||
self.color[3] = alpha;
|
||||
if let HatchPattern::Gradient { color2, .. } = &mut self.pattern {
|
||||
color2[3] = alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HatchModel {
|
||||
pub(crate) fn gradient_frame(
|
||||
&self,
|
||||
@@ -350,9 +362,8 @@ impl HatchModel {
|
||||
self.pattern_segments_with_dot_length(Some(0.0))
|
||||
}
|
||||
|
||||
fn pattern_segments_with_dot_length(
|
||||
&self,
|
||||
plot_dot_length: Option<f64>,
|
||||
fn pattern_segments_with_dot_length(&self,
|
||||
plot_dot_length: Option<f64>
|
||||
) -> Vec<[[f64; 2]; 2]> {
|
||||
let HatchPattern::Pattern(families) = &self.pattern else {
|
||||
return Vec::new();
|
||||
|
||||
+28
-22
@@ -2,8 +2,7 @@
|
||||
use super::*;
|
||||
|
||||
impl Scene {
|
||||
pub(super) fn paper_viewport_handles(
|
||||
&self,
|
||||
pub(super) fn paper_viewport_handles(&self
|
||||
) -> (Handle, Handle, Arc<Vec<Handle>>) {
|
||||
{
|
||||
let cache = self.paper_viewport_cache.borrow();
|
||||
@@ -12,7 +11,7 @@ impl Scene {
|
||||
return (
|
||||
cache.layout_block,
|
||||
cache.sheet,
|
||||
Arc::clone(&cache.content),
|
||||
Arc::clone(&cache.content)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -123,7 +122,8 @@ impl Scene {
|
||||
) -> Vec<ViewportInstance> {
|
||||
if self.current_layout == "Model" {
|
||||
let tiles = self.model_tiles.borrow();
|
||||
let active = self.active_model_tile.get().min(tiles.len().saturating_sub(1));
|
||||
let active = self.active_model_tile.get()
|
||||
.min(tiles.len().saturating_sub(1));
|
||||
return tiles
|
||||
.iter()
|
||||
.enumerate()
|
||||
@@ -298,9 +298,7 @@ impl Scene {
|
||||
hatches.push(sheet);
|
||||
}
|
||||
hatches.extend(
|
||||
self.paper_canvas_hatches(tint_selected)
|
||||
.iter()
|
||||
.cloned(),
|
||||
self.paper_canvas_hatches(tint_selected).iter().cloned()
|
||||
);
|
||||
let hatches = Arc::new(hatches);
|
||||
let wipeouts = self.paper_canvas_wipeouts();
|
||||
@@ -377,9 +375,8 @@ impl Scene {
|
||||
|
||||
/// Physical sheet bounds in canvas pixels. Uses the same forced top-down
|
||||
/// paper transform as the GPU sheet viewport, ignoring stored camera twist.
|
||||
pub fn paper_sheet_screen_rect(
|
||||
&self,
|
||||
canvas_px: (f32, f32),
|
||||
pub fn paper_sheet_screen_rect(&self,
|
||||
canvas_px: (f32, f32)
|
||||
) -> Option<iced::Rectangle> {
|
||||
let ((x0, y0), (x1, y1)) = self.paper_limits()?;
|
||||
let (canvas_w, canvas_h) = canvas_px;
|
||||
@@ -477,13 +474,17 @@ impl Scene {
|
||||
)
|
||||
.is_some() =>
|
||||
{
|
||||
Self::hatch_model_from_dxf(dxf, model.color)
|
||||
.unwrap_or_else(|| model.clone())
|
||||
Self::hatch_model_from_dxf(dxf, model.color).unwrap_or_else(|| model.clone())
|
||||
}
|
||||
_ => model.clone(),
|
||||
};
|
||||
let style = self.render_style(entity);
|
||||
m.color = style.0;
|
||||
if matches!(
|
||||
m.pattern, model::hatch_model::HatchPattern::Gradient { .. }) {
|
||||
m.set_alpha(style.0[3]);
|
||||
} else {
|
||||
m.color = style.0;
|
||||
}
|
||||
m.aci = style.4;
|
||||
m.line_weight_px = style.3;
|
||||
if let EntityType::Hatch(dxf) = entity {
|
||||
@@ -600,13 +601,19 @@ impl Scene {
|
||||
)
|
||||
.is_some() =>
|
||||
{
|
||||
Self::hatch_model_from_dxf(dxf, model.color)
|
||||
.unwrap_or_else(|| model.clone())
|
||||
Self::hatch_model_from_dxf(dxf, model.color).unwrap_or_else(|| model.clone())
|
||||
}
|
||||
_ => model.clone(),
|
||||
};
|
||||
let style = self.render_style(entity);
|
||||
hatch.color = style.0;
|
||||
if matches!(
|
||||
hatch.pattern,
|
||||
model::hatch_model::HatchPattern::Gradient { .. }
|
||||
) {
|
||||
hatch.set_alpha(style.0[3]);
|
||||
} else {
|
||||
hatch.color = style.0;
|
||||
}
|
||||
hatch.aci = style.4;
|
||||
hatch.line_weight_px = style.3;
|
||||
if let EntityType::Hatch(dxf) = entity {
|
||||
@@ -715,9 +722,9 @@ impl Scene {
|
||||
// from a big symbol library) has viewports legitimately aimed at that
|
||||
// second cluster; testing only the dense one wrongly auto-fits them onto
|
||||
// the library. Fall back to the cluster box when no extents are known.
|
||||
let full_bounds = self.model_space_extents().map(|(mn, mx)| {
|
||||
(mn.x as f64, mn.y as f64, mx.x as f64, mx.y as f64)
|
||||
});
|
||||
let full_bounds = self.model_space_extents()
|
||||
.map(|(mn, mx)|
|
||||
(mn.x as f64, mn.y as f64, mx.x as f64, mx.y as f64));
|
||||
// Absolute drawing centre. Geometry now reaches the scene at absolute
|
||||
// (UTM) coordinates — the old code centred the overlap test and the
|
||||
// auto-fit on the origin, which was right only while world_offset
|
||||
@@ -734,9 +741,8 @@ impl Scene {
|
||||
(self.local_center[0], self.local_center[1])
|
||||
} else {
|
||||
self.model_space_extents()
|
||||
.map(|(mn, mx)| {
|
||||
(((mn.x + mx.x) * 0.5) as f64, ((mn.y + mx.y) * 0.5) as f64)
|
||||
})
|
||||
.map(|(mn, mx)|
|
||||
(((mn.x + mx.x) * 0.5) as f64, ((mn.y + mx.y) * 0.5) as f64))
|
||||
.unwrap_or((0.0, 0.0))
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user