forked from 1b-agent/opencadstudio-upstream
Fix wipeout rotation and block frame width
This commit is contained in:
1 parent
4a7f08f80e
commit
d07e8cf7d4
4 files changed
+61
-8
No files matched your search
@@ -722,14 +722,22 @@ impl PropertyEditable for Wipeout {
|
||||
let u = glam::DVec3::new(self.u_vector.x, self.u_vector.y, self.u_vector.z);
|
||||
let v = glam::DVec3::new(self.v_vector.x, self.v_vector.y, self.v_vector.z);
|
||||
let normal = u.cross(v).normalize_or_zero();
|
||||
if normal.length_squared() <= 1e-18 {
|
||||
if normal.length_squared() <= 1e-18 || normal.z.abs() <= 1e-12 {
|
||||
return;
|
||||
}
|
||||
let current_radians = u.y.atan2(u.x);
|
||||
let rotation = glam::DQuat::from_axis_angle(
|
||||
normal,
|
||||
target_degrees.to_radians() - current_radians,
|
||||
);
|
||||
let target_radians = target_degrees.to_radians();
|
||||
let horizontal = glam::DVec3::new(target_radians.cos(), target_radians.sin(), 0.0);
|
||||
let target = (normal.z * horizontal - normal.dot(horizontal) * glam::DVec3::Z)
|
||||
* normal.z.signum();
|
||||
let direction = u.normalize_or_zero();
|
||||
let target = target.normalize_or_zero();
|
||||
if direction == glam::DVec3::ZERO || target == glam::DVec3::ZERO {
|
||||
return;
|
||||
}
|
||||
let angle = normal
|
||||
.dot(direction.cross(target))
|
||||
.atan2(direction.dot(target));
|
||||
let rotation = glam::DQuat::from_axis_angle(normal, angle);
|
||||
let u = rotation * u;
|
||||
let v = rotation * v;
|
||||
self.u_vector = acadrust::types::Vector3::new(u.x, u.y, u.z);
|
||||
@@ -786,3 +794,33 @@ impl Transformable for Wipeout {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod wipeout_property_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn rotation_reaches_the_requested_angle_for_mirrored_and_tilted_frames() {
|
||||
for (u, v, target) in [
|
||||
([1.0, 0.0, 0.0], [0.0, -1.0, 0.0], 90.0),
|
||||
([1.0, 0.0, 1.0], [0.0, 1.0, 0.0], 45.0),
|
||||
] {
|
||||
let mut wipeout = Wipeout::new();
|
||||
wipeout.u_vector = acadrust::types::Vector3::new(u[0], u[1], u[2]);
|
||||
wipeout.v_vector = acadrust::types::Vector3::new(v[0], v[1], v[2]);
|
||||
let lengths = (wipeout.u_vector.length(), wipeout.v_vector.length());
|
||||
|
||||
wipeout.apply_geom_prop("wo_rotation", &target.to_string());
|
||||
|
||||
let angle = wipeout
|
||||
.u_vector
|
||||
.y
|
||||
.atan2(wipeout.u_vector.x)
|
||||
.to_degrees()
|
||||
.rem_euclid(360.0);
|
||||
assert!((angle - target).abs() < 1e-9, "target={target} actual={angle}");
|
||||
assert!((wipeout.u_vector.length() - lengths.0).abs() < 1e-12);
|
||||
assert!((wipeout.v_vector.length() - lengths.1).abs() < 1e-12);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1495,6 +1495,19 @@ mod block_wire_storage_tests {
|
||||
assert_eq!(names(&packed), names(&storage));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_block_wire_shaders_honor_fixed_screen_width() {
|
||||
for source in [
|
||||
include_str!("../../shaders/block_wire.wgsl"),
|
||||
include_str!("../../shaders/block_wire_storage.wgsl"),
|
||||
] {
|
||||
assert!(source.contains("if world_hw < 0.0"));
|
||||
assert!(source.contains(
|
||||
"resolve_hw(0.0, wire_const.world_half_width, wire_const.half_width)"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wire_shader_validates_with_naga() {
|
||||
let source = include_str!("../../shaders/wire.wgsl");
|
||||
|
||||
@@ -69,6 +69,7 @@ fn resolve_hw(taper_ratio: f32, world_hw: f32, px_hw: f32) -> f32 {
|
||||
if world_hw > 0.0 {
|
||||
return max(world_hw / u.world_per_pixel, 0.5);
|
||||
}
|
||||
if world_hw < 0.0 { return max(-world_hw, 0.5); }
|
||||
var display_hw = max(px_hw * u.lineweight_scale, 0.5);
|
||||
if u.lineweight_scale < 0.0 {
|
||||
let scale = -u.lineweight_scale;
|
||||
@@ -185,7 +186,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
|
||||
let perpendicular = vec2<f32>(-direction.y, direction.x);
|
||||
let clip_position = mix(clip_a, clip_b, which_end);
|
||||
|
||||
let half_width = resolve_hw(0.0, 0.0, wire_const.half_width);
|
||||
let half_width = resolve_hw(0.0, wire_const.world_half_width, wire_const.half_width);
|
||||
let extension = which_end * 2.0 - 1.0;
|
||||
let offset_px = perpendicular * half_width * side
|
||||
+ direction * half_width * extension;
|
||||
|
||||
@@ -93,6 +93,7 @@ fn resolve_hw(taper_ratio: f32, world_hw: f32, px_hw: f32) -> f32 {
|
||||
if world_hw > 0.0 {
|
||||
return max(world_hw / u.world_per_pixel, 0.5);
|
||||
}
|
||||
if world_hw < 0.0 { return max(-world_hw, 0.5); }
|
||||
var display_hw = max(px_hw * u.lineweight_scale, 0.5);
|
||||
if u.lineweight_scale < 0.0 {
|
||||
let scale = -u.lineweight_scale;
|
||||
@@ -216,7 +217,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
|
||||
let perpendicular = vec2<f32>(-direction.y, direction.x);
|
||||
let clip_position = mix(clip_a, clip_b, which_end);
|
||||
|
||||
let half_width = resolve_hw(0.0, 0.0, wire_const.half_width);
|
||||
let half_width = resolve_hw(0.0, wire_const.world_half_width, wire_const.half_width);
|
||||
let extension = which_end * 2.0 - 1.0;
|
||||
let offset_px = perpendicular * half_width * side
|
||||
+ direction * half_width * extension;
|
||||
|
||||
Reference in new issue
Block a user