forked from 1b-agent/opencadstudio-upstream
Cargo: codec aad7053, kernel 1a52eaf, graph 263de59; honour viewport clipping
Brings codec PRs #84 (cross-version visual styles, table styles, subentity managers), #88 (viewport clipping flag, DXF boundary handle), #89 (DXF viewport snap/twist in degrees) and #92 (field format codes, event updates). With #88 a viewport keeps a stored boundary whether or not clipping is on, so a linked boundary alone no longer means "clipped": rendering, paper picking, VPCLIP and the Clipped property check the clipping flag too, and VPCLIP / MVIEW Object and Polygon set it. Before, OCS never set the flag, so its clipped viewports opened rectangular elsewhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2dfa9f3f2a
commit
81bb8d48cf
12 files changed
+32
-19
No files matched your search
Generated
+4
-4
@@ -4205,7 +4205,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opencadcodec"
|
name = "opencadcodec"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=1ca7d33#1ca7d3360a34384b59297ffe8aa18b157d2701d9"
|
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=aad7053#aad70533211bd9192545729f7eb3bccb827bcf30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
@@ -4228,7 +4228,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opencadgraph"
|
name = "opencadgraph"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=d7908a8#d7908a8d24a42896b03f7f83b3a1c0187692043a"
|
source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=263de59#263de5924e3fffcbb78377db5ed1117f50620666"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"opencadkernel",
|
"opencadkernel",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -4237,7 +4237,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opencadkernel"
|
name = "opencadkernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=7fb0abb#7fb0abb4ee8e4266a770eb673ac7757c71321513"
|
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=1a52eaf#1a52eaf237949a4492a7b56907922218ab2d1ea9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cavalier_contours",
|
"cavalier_contours",
|
||||||
"opencadcodec",
|
"opencadcodec",
|
||||||
@@ -4248,7 +4248,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opencadkernel-constraints"
|
name = "opencadkernel-constraints"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=7fb0abb#7fb0abb4ee8e4266a770eb673ac7757c71321513"
|
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=1a52eaf#1a52eaf237949a4492a7b56907922218ab2d1ea9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
]
|
]
|
||||||
|
|||||||
+4
-4
@@ -34,10 +34,10 @@ rfd = "0.17"
|
|||||||
clap = { version = "4", features = ["derive", "string"] }
|
clap = { version = "4", features = ["derive", "string"] }
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "1ca7d33", features = ["serde"] }
|
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "aad7053", features = ["serde"] }
|
||||||
kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "7fb0abb", features = ["acis", "offset"] }
|
kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "1a52eaf", features = ["acis", "offset"] }
|
||||||
kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "7fb0abb" }
|
kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "1a52eaf" }
|
||||||
graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "d7908a8" }
|
graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "263de59" }
|
||||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true }
|
|||||||
# Pulled in only by the `host` feature, which adds the `opencadcodec`-typed
|
# Pulled in only by the `host` feature, which adds the `opencadcodec`-typed
|
||||||
# `HostApi` runtime surface. The default crate stays dependency-free so engine
|
# `HostApi` runtime surface. The default crate stays dependency-free so engine
|
||||||
# crates and external tooling can depend on the manifest/ribbon contract cheaply.
|
# crates and external tooling can depend on the manifest/ribbon contract cheaply.
|
||||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "1ca7d33", optional = true, features = ["serde"] }
|
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "aad7053", optional = true, features = ["serde"] }
|
||||||
|
|
||||||
# Runtime IPC and serialization (host feature only).
|
# Runtime IPC and serialization (host feature only).
|
||||||
interprocess = { version = "2", optional = true }
|
interprocess = { version = "2", optional = true }
|
||||||
@@ -39,7 +39,7 @@ serde_json = "1"
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
cargo-lock = "11"
|
cargo-lock = "11"
|
||||||
# opencadcodec is scanned at build time to generate the embedded type registry.
|
# opencadcodec is scanned at build time to generate the embedded type registry.
|
||||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "1ca7d33", features = ["serde"] }
|
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "aad7053", features = ["serde"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
@@ -8,7 +8,7 @@ publish = false
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "1ca7d33", features = ["serde"] }
|
codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "aad7053", features = ["serde"] }
|
||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
|
|||||||
Generated
+1
-1
@@ -1264,7 +1264,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opencadcodec"
|
name = "opencadcodec"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=1ca7d33#1ca7d3360a34384b59297ffe8aa18b157d2701d9"
|
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=aad7053#aad70533211bd9192545729f7eb3bccb827bcf30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ impl OpenCADStudio {
|
|||||||
let mut vp = vp;
|
let mut vp = vp;
|
||||||
if clip.is_null() {
|
if clip.is_null() {
|
||||||
vp.clip_boundary_handle = Handle::NULL;
|
vp.clip_boundary_handle = Handle::NULL;
|
||||||
|
vp.status.non_rectangular_clipping = false;
|
||||||
} else {
|
} else {
|
||||||
let (lo, hi) = clip_boundary_extents(scene, clip)
|
let (lo, hi) = clip_boundary_extents(scene, clip)
|
||||||
.map(|(lo, hi)| (glam::DVec2::from(lo), glam::DVec2::from(hi)))
|
.map(|(lo, hi)| (glam::DVec2::from(lo), glam::DVec2::from(hi)))
|
||||||
@@ -117,6 +118,7 @@ impl OpenCADStudio {
|
|||||||
vp.height = hi.y - lo.y;
|
vp.height = hi.y - lo.y;
|
||||||
vp.view_height = vp.height * scale;
|
vp.view_height = vp.height * scale;
|
||||||
vp.clip_boundary_handle = clip;
|
vp.clip_boundary_handle = clip;
|
||||||
|
vp.status.non_rectangular_clipping = true;
|
||||||
if let Some(entity) = scene.document.get_entity_mut(clip) {
|
if let Some(entity) = scene.document.get_entity_mut(clip) {
|
||||||
let common = entity.common_mut();
|
let common = entity.common_mut();
|
||||||
if !common.reactors.contains(&viewport) {
|
if !common.reactors.contains(&viewport) {
|
||||||
@@ -228,6 +230,7 @@ impl OpenCADStudio {
|
|||||||
viewport.height = max_y - min_y;
|
viewport.height = max_y - min_y;
|
||||||
viewport.id = 2;
|
viewport.id = 2;
|
||||||
viewport.clip_boundary_handle = clip_handle;
|
viewport.clip_boundary_handle = clip_handle;
|
||||||
|
viewport.status.non_rectangular_clipping = !clip_handle.is_null();
|
||||||
let viewport_handle = self.commit_entity_handle(codec::EntityType::Viewport(viewport));
|
let viewport_handle = self.commit_entity_handle(codec::EntityType::Viewport(viewport));
|
||||||
if let Some(viewport_handle) = viewport_handle {
|
if let Some(viewport_handle) = viewport_handle {
|
||||||
if !created_boundary {
|
if !created_boundary {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ fn viewport_dimension_curved_clip_includes_the_exact_boundary() {
|
|||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
vp.clip_boundary_handle = clip;
|
vp.clip_boundary_handle = clip;
|
||||||
|
vp.status.non_rectangular_clipping = true;
|
||||||
assert!(scene
|
assert!(scene
|
||||||
.viewport_displays_paper_point(frame.viewport, glam::DVec2::new(boundary.x, boundary.y)));
|
.viewport_displays_paper_point(frame.viewport, glam::DVec2::new(boundary.x, boundary.y)));
|
||||||
assert!(!scene.viewport_displays_paper_point(frame.viewport, glam::DVec2::new(60.01, 50.0)));
|
assert!(!scene.viewport_displays_paper_point(frame.viewport, glam::DVec2::new(60.01, 50.0)));
|
||||||
@@ -463,6 +464,7 @@ fn viewport_dimension_eligibility_is_shared_and_uses_clipping() {
|
|||||||
let clip = scene.add_entity(EntityType::LwPolyline(clip));
|
let clip = scene.add_entity(EntityType::LwPolyline(clip));
|
||||||
if let Some(EntityType::Viewport(vp)) = scene.document.get_entity_mut(top) {
|
if let Some(EntityType::Viewport(vp)) = scene.document.get_entity_mut(top) {
|
||||||
vp.clip_boundary_handle = clip;
|
vp.clip_boundary_handle = clip;
|
||||||
|
vp.status.non_rectangular_clipping = true;
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scene
|
scene
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ fn properties(vp: &Viewport) -> Vec<PropSection> {
|
|||||||
ro(
|
ro(
|
||||||
"Clipped",
|
"Clipped",
|
||||||
"vp_clipped",
|
"vp_clipped",
|
||||||
if vp.clip_boundary_handle.is_null() { "No" } else { "Yes" },
|
if is_clipped(vp) { "Yes" } else { "No" },
|
||||||
),
|
),
|
||||||
Property {
|
Property {
|
||||||
label: "Display locked".into(),
|
label: "Display locked".into(),
|
||||||
@@ -342,6 +342,13 @@ fn apply_grip(vp: &mut Viewport, grip_id: usize, apply: GripApply) {
|
|||||||
|
|
||||||
/// Stretch a rectangular paper-space viewport by the corners captured by a
|
/// Stretch a rectangular paper-space viewport by the corners captured by a
|
||||||
/// crossing window. Bounds that have no captured corner stay anchored.
|
/// crossing window. Bounds that have no captured corner stay anchored.
|
||||||
|
/// A viewport clipped by its boundary object: the boundary is linked and
|
||||||
|
/// non-rectangular clipping is on. A stored boundary with clipping off draws
|
||||||
|
/// the rectangular viewport.
|
||||||
|
pub(crate) fn is_clipped(vp: &Viewport) -> bool {
|
||||||
|
!vp.clip_boundary_handle.is_null() && vp.status.non_rectangular_clipping
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stretch(
|
pub fn stretch(
|
||||||
vp: &mut Viewport,
|
vp: &mut Viewport,
|
||||||
win_min: glam::DVec3,
|
win_min: glam::DVec3,
|
||||||
@@ -435,7 +442,7 @@ impl crate::entities::traits::FallbackTess for Viewport {
|
|||||||
// A clipped viewport uses its linked boundary entity as its visible
|
// A clipped viewport uses its linked boundary entity as its visible
|
||||||
// frame. Drawing the viewport's rectangular extents as well leaves an
|
// frame. Drawing the viewport's rectangular extents as well leaves an
|
||||||
// incorrect box around polygonal/Object MVIEW results.
|
// incorrect box around polygonal/Object MVIEW results.
|
||||||
if !self.clip_boundary_handle.is_null() {
|
if is_clipped(self) {
|
||||||
return (vec![], vec![], vec![], vec![]);
|
return (vec![], vec![], vec![], vec![]);
|
||||||
}
|
}
|
||||||
let cx = self.center.x;
|
let cx = self.center.x;
|
||||||
|
|||||||
@@ -497,7 +497,7 @@ impl CadCommand for ClipCommand {
|
|||||||
}
|
}
|
||||||
// The layout's own paper-space viewport (id 1) is not clippable.
|
// The layout's own paper-space viewport (id 1) is not clippable.
|
||||||
Some(EntityType::Viewport(vp)) if vp.id != 1 => {
|
Some(EntityType::Viewport(vp)) if vp.id != 1 => {
|
||||||
let clipped = !vp.clip_boundary_handle.is_null();
|
let clipped = crate::entities::viewport::is_clipped(&vp);
|
||||||
self.inner = Some(Box::new(MviewCommand::vpclip(handle, clipped)));
|
self.inner = Some(Box::new(MviewCommand::vpclip(handle, clipped)));
|
||||||
CmdResult::NeedPoint
|
CmdResult::NeedPoint
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -799,7 +799,7 @@ impl CadCommand for MviewCommand {
|
|||||||
if self.step == Step::ClipSelect {
|
if self.step == Step::ClipSelect {
|
||||||
return match self.picked.take() {
|
return match self.picked.take() {
|
||||||
Some(EntityType::Viewport(vp)) if vp.id != 1 => {
|
Some(EntityType::Viewport(vp)) if vp.id != 1 => {
|
||||||
self.clip = Some((handle, !vp.clip_boundary_handle.is_null()));
|
self.clip = Some((handle, crate::entities::viewport::is_clipped(&vp)));
|
||||||
self.step = Step::ClipChoice;
|
self.step = Step::ClipChoice;
|
||||||
CmdResult::NeedPoint
|
CmdResult::NeedPoint
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -189,7 +189,7 @@ impl Scene {
|
|||||||
if (paper.x - vp.center.x).abs() > hw || (paper.y - vp.center.y).abs() > hh {
|
if (paper.x - vp.center.x).abs() > hw || (paper.y - vp.center.y).abs() > hh {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if vp.clip_boundary_handle.is_null() {
|
if !crate::entities::viewport::is_clipped(vp) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let Some(boundary) = self.document.get_entity(vp.clip_boundary_handle)
|
let Some(boundary) = self.document.get_entity(vp.clip_boundary_handle)
|
||||||
@@ -321,6 +321,7 @@ mod clip_tests {
|
|||||||
viewport.width = 20.0;
|
viewport.width = 20.0;
|
||||||
viewport.height = 20.0;
|
viewport.height = 20.0;
|
||||||
viewport.clip_boundary_handle = clip;
|
viewport.clip_boundary_handle = clip;
|
||||||
|
viewport.status.non_rectangular_clipping = true;
|
||||||
let viewport = scene.add_entity(EntityType::Viewport(viewport));
|
let viewport = scene.add_entity(EntityType::Viewport(viewport));
|
||||||
for (x, y, inside) in [
|
for (x, y, inside) in [
|
||||||
(2.0, 2.0, true), (8.0, 2.0, true), (8.0, 8.0, false),
|
(2.0, 2.0, true), (8.0, 2.0, true), (8.0, 8.0, false),
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ impl Scene {
|
|||||||
[xmin as f64, ymin as f64], [xmax as f64, ymin as f64],
|
[xmin as f64, ymin as f64], [xmax as f64, ymin as f64],
|
||||||
[xmax as f64, ymax as f64], [xmin as f64, ymax as f64],
|
[xmax as f64, ymax as f64], [xmin as f64, ymax as f64],
|
||||||
]];
|
]];
|
||||||
if !self.images.is_empty() && !viewport.clip_boundary_handle.is_null() {
|
if !self.images.is_empty() && crate::entities::viewport::is_clipped(viewport) {
|
||||||
let boundary = self.clip_boundary_polygon(
|
let boundary = self.clip_boundary_polygon(
|
||||||
viewport.clip_boundary_handle, viewport.center.z as f32);
|
viewport.clip_boundary_handle, viewport.center.z as f32);
|
||||||
if boundary.len() >= 3 {
|
if boundary.len() >= 3 {
|
||||||
@@ -663,7 +663,7 @@ impl Scene {
|
|||||||
if hw.abs() < 1e-6 || hh.abs() < 1e-6 {
|
if hw.abs() < 1e-6 || hh.abs() < 1e-6 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let poly = if vp.clip_boundary_handle.is_null() {
|
let poly = if !crate::entities::viewport::is_clipped(vp) {
|
||||||
// Rectangular viewport → its own four corners (paper coords). These
|
// Rectangular viewport → its own four corners (paper coords). These
|
||||||
// map to full-rect NDC [-1, 1], a no-op mask over a render target
|
// map to full-rect NDC [-1, 1], a no-op mask over a render target
|
||||||
// that already clips to the rectangle, but it keeps rect and
|
// that already clips to the rectangle, but it keeps rect and
|
||||||
|
|||||||
Reference in new issue
Block a user