Skip to content

Commit

Permalink
#13 fix bug in normalizing project image axes in OMF1 conversion, and…
Browse files Browse the repository at this point in the history
… don't require them to be orthogonal.
  • Loading branch information
Tim Evans committed Oct 21, 2024
1 parent 7817efb commit 0f5de07
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 10 deletions.
4 changes: 3 additions & 1 deletion src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,8 @@ impl Validate for Surface {

impl Validate for GridSurface {
fn validate_inner(&mut self, val: &mut Validator) {
val.enter("GridSurface")
let mut val = val
.enter("GridSurface")
.obj(&mut self.orient)
.obj(&mut self.grid)
.array_opt(self.heights.as_mut(), Constraint::Scalar, "heights")
Expand All @@ -356,6 +357,7 @@ impl Validate for GridSurface {
self.grid.flat_corner_count(),
"heights",
);
self.orient.validate_ortho(&mut val);
}
}

Expand Down
17 changes: 11 additions & 6 deletions src/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,14 @@ const fn k() -> Vector3 {
pub struct Orient2 {
/// Origin point relative to the project origin and coordinate reference.
pub origin: Vector3,
/// The direction of the U axis of the plane. Must be a unit vector perpendicular to `v`.
/// Default [1, 0, 0].
/// The direction of the U axis of the plane. Must be a unit vector. Default [1, 0, 0].
///
/// Must also be perpendicular to the 'v' in grid surfaces.
#[serde(default = "i")]
pub u: Vector3,
/// The direction of the V axis of the plane. Must be a unit vector perpendicular to `u`.
/// Default [0, 1, 0].
/// The direction of the V axis of the plane. Must be a unit vector. Default [0, 1, 0].
///
/// Must also be perpendicular to the 'u' in grid surfaces.
#[serde(default = "j")]
pub v: Vector3,
}
Expand All @@ -191,6 +193,10 @@ impl Orient2 {
pub fn from_origin(origin: Vector3) -> Self {
Self::new(origin, i(), j())
}

pub(crate) fn validate_ortho(&self, val: &mut Validator) {
val.enter("Orient2").vectors_ortho2(self.u, self.v);
}
}

impl Default for Orient2 {
Expand Down Expand Up @@ -291,8 +297,7 @@ impl Validate for Orient2 {
val.enter("Orient2")
.finite_seq(self.origin, "origin")
.unit_vector(self.u, "u")
.unit_vector(self.v, "v")
.vectors_ortho2(self.u, self.v);
.unit_vector(self.v, "v");
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/omf1/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,11 @@ pub(super) fn attribute(
}

fn projection_axis(axis: [f64; 3]) -> ([f64; 3], f64) {
let length: f64 = axis.iter().map(|x| x * x).sum();
if length == 0.0 {
let length_squared: f64 = axis.iter().map(|x| x * x).sum();
if length_squared == 0.0 {
([0.0, 0.0, 0.0], 0.0)
} else {
let length = length_squared.sqrt();
(axis.map(|x| x / length), length)
}
}
29 changes: 28 additions & 1 deletion tests/conversion_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::{fs::read_dir, path::Path, time::Instant};

use omf::{error::Error, file::Reader, omf1::Converter};
use omf::{error::Error, file::Reader, omf1::Converter, AttributeData};

#[test]
fn convert_omf1() {
Expand Down Expand Up @@ -35,6 +35,28 @@ fn convert_omf1() {
));
}

/// Tests that the fix for [#13](https://github.com/gmggroup/omf-rust/issues/13) works.
///
/// The axis vectors of a projected image weren't normalized correctly, and they were
/// wrongly required to be orthogonal.
#[test]
fn convert_omf1_plane_surface() {
let output_path = Path::new(env!("CARGO_TARGET_TMPDIR")).join("plane_surface.2.omf");
let converter = Converter::new();
let warnings = converter
.convert_open("tests/omf1/plane_surface.omf", &output_path)
.unwrap();
let warning_strings: Vec<_> = warnings.into_iter().map(|p| p.to_string()).collect();
assert_eq!(warning_strings, Vec::<String>::new());
let project = Reader::open(&output_path).unwrap().project().unwrap().0;
let image = &project.elements[0].attributes[3];
let AttributeData::ProjectedTexture { orient, .. } = &image.data else {
panic!("wrong type");
};
assert!(vec3_approx_equal(orient.u, [0.9905557, 0.1371108, 0.0]));
assert!(vec3_approx_equal(orient.v, [-0.0957124, 0.9954090, 0.0]));
}

#[ignore = "requires local files"]
#[test]
fn convert_external_files() {
Expand Down Expand Up @@ -82,3 +104,8 @@ fn convert_external_files() {
}
assert!(success);
}

fn vec3_approx_equal(a: [f64; 3], b: [f64; 3]) -> bool {
const THRESHOLD: f64 = 1e-6;
a.into_iter().zip(b).all(|(a, b)| (a - b).abs() < THRESHOLD)
}
Binary file added tests/omf1/plane_surface.omf
Binary file not shown.

0 comments on commit 0f5de07

Please sign in to comment.