Put all `#[test]` in a `mod tests` (#2728)

workspace: put all `#[test]` in a `mod tests`
This commit is contained in:
Firestar99 2025-06-18 11:46:01 +02:00 committed by Keavon Chambers
parent 579bedd9ff
commit 006209c5d0
12 changed files with 748 additions and 696 deletions

View File

@ -91,44 +91,48 @@ pub fn get_current_normalized_pivot(inputs: &[NodeInput]) -> DVec2 {
if let Some(&TaggedValue::DVec2(pivot)) = inputs[5].as_value() { pivot } else { DVec2::splat(0.5) } if let Some(&TaggedValue::DVec2(pivot)) = inputs[5].as_value() { pivot } else { DVec2::splat(0.5) }
} }
/// ![](https://files.keavon.com/-/OptimisticSpotlessTinamou/capture.png) #[cfg(test)]
/// mod tests {
/// Source: use super::*;
/// ```tex /// ![](https://files.keavon.com/-/OptimisticSpotlessTinamou/capture.png)
/// \begin{bmatrix} ///
/// S_{x}\cos(\theta)-S_{y}\sin(\theta)H_{y} & S_{x}\cos(\theta)H_{x}-S_{y}\sin(\theta) & T_{x}\\ /// Source:
/// S_{x}\sin(\theta)+S_{y}\cos(\theta)H_{y} & S_{x}\sin(\theta)H_{x}+S_{y}\cos(\theta) & T_{y}\\ /// ```tex
/// 0 & 0 & 1 /// \begin{bmatrix}
/// \end{bmatrix} /// S_{x}\cos(\theta)-S_{y}\sin(\theta)H_{y} & S_{x}\cos(\theta)H_{x}-S_{y}\sin(\theta) & T_{x}\\
/// ``` /// S_{x}\sin(\theta)+S_{y}\cos(\theta)H_{y} & S_{x}\sin(\theta)H_{x}+S_{y}\cos(\theta) & T_{y}\\
#[test] /// 0 & 0 & 1
fn derive_transform() { /// \end{bmatrix}
for shear_x in -10..=10 { /// ```
let shear_x = (shear_x as f64) / 2.; #[test]
for angle in (0..=360).step_by(15) { fn derive_transform() {
let angle = (angle as f64).to_radians(); for shear_x in -10..=10 {
for scale_x in 1..10 { let shear_x = (shear_x as f64) / 2.;
let scale_x = (scale_x as f64) / 5.; for angle in (0..=360).step_by(15) {
for scale_y in 1..10 { let angle = (angle as f64).to_radians();
let scale_y = (scale_y as f64) / 5.; for scale_x in 1..10 {
let scale_x = (scale_x as f64) / 5.;
for scale_y in 1..10 {
let scale_y = (scale_y as f64) / 5.;
let shear = DVec2::new(shear_x, 0.); let shear = DVec2::new(shear_x, 0.);
let scale = DVec2::new(scale_x, scale_y); let scale = DVec2::new(scale_x, scale_y);
let translate = DVec2::new(5666., 644.); let translate = DVec2::new(5666., 644.);
let original_transform = DAffine2::from_cols( let original_transform = DAffine2::from_cols(
DVec2::new(scale.x * angle.cos() - scale.y * angle.sin() * shear.y, scale.x * angle.sin() + scale.y * angle.cos() * shear.y), DVec2::new(scale.x * angle.cos() - scale.y * angle.sin() * shear.y, scale.x * angle.sin() + scale.y * angle.cos() * shear.y),
DVec2::new(scale.x * angle.cos() * shear.x - scale.y * angle.sin(), scale.x * angle.sin() * shear.x + scale.y * angle.cos()), DVec2::new(scale.x * angle.cos() * shear.x - scale.y * angle.sin(), scale.x * angle.sin() * shear.x + scale.y * angle.cos()),
translate, translate,
); );
let (new_scale, new_angle, new_translation, new_shear) = compute_scale_angle_translation_shear(original_transform); let (new_scale, new_angle, new_translation, new_shear) = compute_scale_angle_translation_shear(original_transform);
let new_transform = DAffine2::from_scale_angle_translation(new_scale, new_angle, new_translation) * DAffine2::from_cols_array(&[1., new_shear.y, new_shear.x, 1., 0., 0.]); let new_transform = DAffine2::from_scale_angle_translation(new_scale, new_angle, new_translation) * DAffine2::from_cols_array(&[1., new_shear.y, new_shear.x, 1., 0., 0.]);
assert!( assert!(
new_transform.abs_diff_eq(original_transform, 1e-10), new_transform.abs_diff_eq(original_transform, 1e-10),
"original_transform {original_transform} new_transform {new_transform} / scale {scale} new_scale {new_scale} / angle {angle} new_angle {new_angle} / shear {shear} / new_shear {new_shear}", "original_transform {original_transform} new_transform {new_transform} / scale {scale} new_scale {new_scale} / angle {angle} new_angle {new_angle} / shear {shear} / new_shear {new_shear}",
); );
}
} }
} }
} }

View File

@ -522,49 +522,53 @@ pub struct NodeRelations {
// Helper functions // Helper functions
// ================ // ================
#[test] #[cfg(test)]
fn test_tree() { mod tests {
let mut metadata = DocumentMetadata::default(); use super::*;
let root = LayerNodeIdentifier::ROOT_PARENT; #[test]
let metadata = &mut metadata; fn test_tree() {
root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(3))); let mut metadata = DocumentMetadata::default();
assert_eq!(root.children(metadata).collect::<Vec<_>>(), vec![LayerNodeIdentifier::new_unchecked(NodeId(3))]); let root = LayerNodeIdentifier::ROOT_PARENT;
root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(6))); let metadata = &mut metadata;
assert_eq!(root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]); root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(3)));
assert_eq!(root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]); assert_eq!(root.children(metadata).collect::<Vec<_>>(), vec![LayerNodeIdentifier::new_unchecked(NodeId(3))]);
LayerNodeIdentifier::new_unchecked(NodeId(3)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(4))); root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(6)));
LayerNodeIdentifier::new_unchecked(NodeId(3)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(2))); assert_eq!(root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]);
LayerNodeIdentifier::new_unchecked(NodeId(6)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(5))); assert_eq!(root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]);
LayerNodeIdentifier::new_unchecked(NodeId(6)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(9))); LayerNodeIdentifier::new_unchecked(NodeId(3)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(4)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(8))); LayerNodeIdentifier::new_unchecked(NodeId(3)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(2)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(7))); LayerNodeIdentifier::new_unchecked(NodeId(6)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(5)));
root.push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(1))); LayerNodeIdentifier::new_unchecked(NodeId(6)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(9)));
assert_eq!( LayerNodeIdentifier::new_unchecked(NodeId(6)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(8)));
root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), LayerNodeIdentifier::new_unchecked(NodeId(6)).push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(7)));
vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(9)] root.push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(1)));
); assert_eq!(
assert_eq!( root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(9)]
vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(7), NodeId(8), NodeId(9)] );
); assert_eq!(
assert_eq!( root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(), vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(7), NodeId(8), NodeId(9)]
vec![NodeId(9), NodeId(8), NodeId(7), NodeId(6), NodeId(5), NodeId(4), NodeId(3), NodeId(2), NodeId(1)] );
); assert_eq!(
assert!(root.children(metadata).all(|child| child.parent(metadata) == Some(root))); root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(),
LayerNodeIdentifier::new_unchecked(NodeId(6)).delete(metadata); vec![NodeId(9), NodeId(8), NodeId(7), NodeId(6), NodeId(5), NodeId(4), NodeId(3), NodeId(2), NodeId(1)]
LayerNodeIdentifier::new_unchecked(NodeId(1)).delete(metadata); );
LayerNodeIdentifier::new_unchecked(NodeId(9)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(10))); assert!(root.children(metadata).all(|child| child.parent(metadata) == Some(root)));
assert_eq!( LayerNodeIdentifier::new_unchecked(NodeId(6)).delete(metadata);
root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), LayerNodeIdentifier::new_unchecked(NodeId(1)).delete(metadata);
vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9)] LayerNodeIdentifier::new_unchecked(NodeId(9)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(10)));
); assert_eq!(
assert_eq!( root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9)]
vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9), NodeId(10)] );
); assert_eq!(
assert_eq!( root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(), vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9), NodeId(10)]
vec![NodeId(10), NodeId(9), NodeId(5), NodeId(4), NodeId(3), NodeId(2)] );
); assert_eq!(
root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(),
vec![NodeId(10), NodeId(9), NodeId(5), NodeId(4), NodeId(3), NodeId(2)]
);
}
} }

View File

@ -382,317 +382,321 @@ impl DistributionSnapper {
} }
} }
#[test]
fn merge_intersecting_test() {
let mut rectangles = vec![Rect::from_square(DVec2::ZERO, 2.), Rect::from_square(DVec2::new(10., 0.), 2.)];
DistributionSnapper::merge_intersecting(&mut rectangles);
assert_eq!(rectangles.len(), 2);
let mut rectangles = vec![
Rect::from_square(DVec2::ZERO, 2.),
Rect::from_square(DVec2::new(1., 0.), 2.),
Rect::from_square(DVec2::new(10., 0.), 2.),
Rect::from_square(DVec2::new(11., 0.), 2.),
];
DistributionSnapper::merge_intersecting(&mut rectangles);
assert_eq!(rectangles.len(), 6);
assert_eq!(rectangles[0], Rect::from_box([DVec2::new(-2., -2.), DVec2::new(3., 2.)]));
assert_eq!(rectangles[3], Rect::from_box([DVec2::new(8., -2.), DVec2::new(13., 2.)]));
}
#[test]
fn dist_simple_2() {
let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 2);
}
#[test]
fn dist_simple_3() {
let rectangles = [10., 20., 30.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 3);
}
#[test]
fn dist_out_of_tolerance() {
let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 0.4, dist_right);
assert_eq!(offset, None);
assert_eq!(rectangles.len(), 1);
}
#[test]
fn dist_with_nonsense() {
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let rectangles = [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 2);
}
#[cfg(test)] #[cfg(test)]
fn assert_boxes_in_order(rectangles: &VecDeque<Rect>, index: usize) { mod tests {
for (&first, &second) in rectangles.iter().zip(rectangles.iter().skip(1)) { use super::*;
assert!(first.max()[index] < second.min()[index], "{first:?} {second:?} {index}") #[test]
fn merge_intersecting_test() {
let mut rectangles = vec![Rect::from_square(DVec2::ZERO, 2.), Rect::from_square(DVec2::new(10., 0.), 2.)];
DistributionSnapper::merge_intersecting(&mut rectangles);
assert_eq!(rectangles.len(), 2);
let mut rectangles = vec![
Rect::from_square(DVec2::ZERO, 2.),
Rect::from_square(DVec2::new(1., 0.), 2.),
Rect::from_square(DVec2::new(10., 0.), 2.),
Rect::from_square(DVec2::new(11., 0.), 2.),
];
DistributionSnapper::merge_intersecting(&mut rectangles);
assert_eq!(rectangles.len(), 6);
assert_eq!(rectangles[0], Rect::from_box([DVec2::new(-2., -2.), DVec2::new(3., 2.)]));
assert_eq!(rectangles[3], Rect::from_box([DVec2::new(8., -2.), DVec2::new(13., 2.)]));
}
#[test]
fn dist_simple_2() {
let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 2);
}
#[test]
fn dist_simple_3() {
let rectangles = [10., 20., 30.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 3);
}
#[test]
fn dist_out_of_tolerance() {
let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 0.4, dist_right);
assert_eq!(offset, None);
assert_eq!(rectangles.len(), 1);
}
#[test]
fn dist_with_nonsense() {
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let rectangles = [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.));
let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right);
assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. }));
assert_eq!(rectangles.len(), 2);
}
#[cfg(test)]
fn assert_boxes_in_order(rectangles: &VecDeque<Rect>, index: usize) {
for (&first, &second) in rectangles.iter().zip(rectangles.iter().skip(1)) {
assert!(first.max()[index] < second.min()[index], "{first:?} {second:?} {index}")
}
}
#[test]
fn dist_snap_point_right() {
let dist_snapper = DistributionSnapper {
right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
left: [-2.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y);
expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[0], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_right_left() {
let dist_snapper = DistributionSnapper {
right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 5);
let mut expected_left1 = dist_snapper.left[1];
let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_center[0].y = expected_center[0].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y);
expected_center[1].y = expected_center[1].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y);
expected_left1[0].y = expected_left1[0].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y);
expected_left1[1].y = expected_left1[1].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_left1);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], expected_center);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_left() {
let dist_snapper = DistributionSnapper {
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_left_right() {
let dist_snapper = DistributionSnapper {
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [2., 10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 4);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_center_x() {
let dist_snapper = DistributionSnapper {
left: [-10., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y);
expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
// ----------------------------------
#[test]
fn dist_snap_point_down() {
let dist_snapper = DistributionSnapper {
down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
up: [-2.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].x = expected_box[0].x.min(dist_snapper.down[0][1].x);
expected_box[1].x = expected_box[1].x.min(dist_snapper.down[0][1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[0], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_down_up() {
let dist_snapper = DistributionSnapper {
down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 5);
let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_center[0].x = expected_center[0].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x);
expected_center[1].x = expected_center[1].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x);
let mut expected_up = Rect::from_square(DVec2::new(0., -10.), 2.);
expected_up[0].x = expected_up[0].x.min(dist_snapper.up[0][1].x).min(expected_center[0].x);
expected_up[1].x = expected_up[1].x.min(dist_snapper.up[0][1].x).min(expected_center[1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_up);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], expected_center);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_up() {
let dist_snapper = DistributionSnapper {
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_up_down() {
let dist_snapper = DistributionSnapper {
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [2., 10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 4);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_center_y() {
let dist_snapper = DistributionSnapper {
up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].x = expected_box[0].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x);
expected_box[1].x = expected_box[1].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_center_xy() {
let dist_snapper = DistributionSnapper {
up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
left: [-12., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [12., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.3, 0.4), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5000000000000001);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(8.));
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert!(snap_results.points[0].distribution_boxes_horizontal[1][0].y <= dist_snapper.left[0][1].y);
assert!(snap_results.points[0].distribution_boxes_horizontal[1][1].y <= dist_snapper.left[0][1].y);
assert!(snap_results.points[0].distribution_boxes_vertical[1][0].x <= dist_snapper.up[0][1].x);
assert!(snap_results.points[0].distribution_boxes_vertical[1][1].x <= dist_snapper.up[0][1].x);
assert_eq!(Rect::from_box(snap_results.points[0].source_bounds.unwrap().bounding_box()), Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
} }
} }
#[test]
fn dist_snap_point_right() {
let dist_snapper = DistributionSnapper {
right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
left: [-2.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y);
expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[0], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_right_left() {
let dist_snapper = DistributionSnapper {
right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 5);
let mut expected_left1 = dist_snapper.left[1];
let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_center[0].y = expected_center[0].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y);
expected_center[1].y = expected_center[1].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y);
expected_left1[0].y = expected_left1[0].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y);
expected_left1[1].y = expected_left1[1].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_left1);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], expected_center);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_left() {
let dist_snapper = DistributionSnapper {
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_left_right() {
let dist_snapper = DistributionSnapper {
left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [2., 10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 4);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
#[test]
fn dist_snap_point_center_x() {
let dist_snapper = DistributionSnapper {
left: [-10., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.5, 0.), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y);
expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
}
// ----------------------------------
#[test]
fn dist_snap_point_down() {
let dist_snapper = DistributionSnapper {
down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
up: [-2.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].x = expected_box[0].x.min(dist_snapper.down[0][1].x);
expected_box[1].x = expected_box[1].x.min(dist_snapper.down[0][1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[0], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_down_up() {
let dist_snapper = DistributionSnapper {
down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 5);
let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_center[0].x = expected_center[0].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x);
expected_center[1].x = expected_center[1].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x);
let mut expected_up = Rect::from_square(DVec2::new(0., -10.), 2.);
expected_up[0].x = expected_up[0].x.min(dist_snapper.up[0][1].x).min(expected_center[0].x);
expected_up[1].x = expected_up[1].x.min(dist_snapper.up[0][1].x).min(expected_center[1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_up);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], expected_center);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_up() {
let dist_snapper = DistributionSnapper {
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_up_down() {
let dist_snapper = DistributionSnapper {
up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [2., 10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 4);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_center_y() {
let dist_snapper = DistributionSnapper {
up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0., 0.5), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5);
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.);
expected_box[0].x = expected_box[0].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x);
expected_box[1].x = expected_box[1].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x);
assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_box);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}
#[test]
fn dist_snap_point_center_xy() {
let dist_snapper = DistributionSnapper {
up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(),
left: [-12., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
right: [12., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(),
..Default::default()
};
let source = Rect::from_square(DVec2::new(0.3, 0.4), 2.);
let snap_results = &mut SnapResults::default();
dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source);
assert_eq!(snap_results.points.len(), 1);
assert_eq!(snap_results.points[0].distance, 0.5000000000000001);
assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(8.));
assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.));
assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3);
assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3);
assert!(snap_results.points[0].distribution_boxes_horizontal[1][0].y <= dist_snapper.left[0][1].y);
assert!(snap_results.points[0].distribution_boxes_horizontal[1][1].y <= dist_snapper.left[0][1].y);
assert!(snap_results.points[0].distribution_boxes_vertical[1][0].x <= dist_snapper.up[0][1].x);
assert!(snap_results.points[0].distribution_boxes_vertical[1][1].x <= dist_snapper.up[0][1].x);
assert_eq!(Rect::from_box(snap_results.points[0].source_bounds.unwrap().bounding_box()), Rect::from_square(DVec2::new(0., 0.), 2.));
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0);
assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1);
}

View File

@ -800,59 +800,64 @@ impl BoundingBoxManager {
} }
} }
#[test] #[cfg(test)]
fn skew_transform_singular() { mod tests {
for edge in [ use super::*;
SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]), #[test]
SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]), fn skew_transform_singular() {
SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]), for edge in [
] { SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
// The determinant is 0. SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
let transform = DAffine2::from_cols_array(&[2.; 6]); SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]),
// This shouldn't panic. We don't really care about the behavior in this test. SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]),
let _ = edge.skew_transform(DVec2::new(1.5, 1.5), transform, false); ] {
} // The determinant is 0.
} let transform = DAffine2::from_cols_array(&[2.; 6]);
// This shouldn't panic. We don't really care about the behavior in this test.
#[test] let _ = edge.skew_transform(DVec2::new(1.5, 1.5), transform, false);
fn skew_transform_correct() { }
for edge in [ }
SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]), #[test]
SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]), fn skew_transform_correct() {
SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]), for edge in [
] { SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
// Random transform with det != 0. SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]),
let to_viewport_transform = DAffine2::from_cols_array(&[2., 1., 0., 1., 2., 3.]); SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]),
// Random mouse position. SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]),
let mouse = DVec2::new(1.5, 1.5); ] {
let final_transform = edge.skew_transform(mouse, to_viewport_transform, false); // Random transform with det != 0.
let to_viewport_transform = DAffine2::from_cols_array(&[2., 1., 0., 1., 2., 3.]);
// This is the current handle that goes under the mouse. // Random mouse position.
let opposite = edge.pivot_from_bounds(edge.bounds[0], edge.bounds[1]); let mouse = DVec2::new(1.5, 1.5);
let dragging_point = edge.pivot_from_bounds(edge.bounds[1], edge.bounds[0]); let final_transform = edge.skew_transform(mouse, to_viewport_transform, false);
let viewport_dragging_point = to_viewport_transform.transform_point2(dragging_point); // This is the current handle that goes under the mouse.
let parallel_to_x = edge.top || edge.bottom; let opposite = edge.pivot_from_bounds(edge.bounds[0], edge.bounds[1]);
let parallel_to_y = !parallel_to_x && (edge.left || edge.right); let dragging_point = edge.pivot_from_bounds(edge.bounds[1], edge.bounds[0]);
let drag_vector = mouse - viewport_dragging_point; let viewport_dragging_point = to_viewport_transform.transform_point2(dragging_point);
let document_drag_vector = to_viewport_transform.inverse().transform_vector2(drag_vector); let parallel_to_x = edge.top || edge.bottom;
let parallel_to_y = !parallel_to_x && (edge.left || edge.right);
let sign = if edge.top || edge.left { -1. } else { 1. };
let scale_factor = (edge.bounds[1] - edge.bounds[0])[parallel_to_x as usize].abs().recip() * sign; let drag_vector = mouse - viewport_dragging_point;
let scaled_document_drag = document_drag_vector * scale_factor; let document_drag_vector = to_viewport_transform.inverse().transform_vector2(drag_vector);
let skew = DAffine2::from_mat2(DMat2::from_cols_array(&[ let sign = if edge.top || edge.left { -1. } else { 1. };
1., let scale_factor = (edge.bounds[1] - edge.bounds[0])[parallel_to_x as usize].abs().recip() * sign;
if parallel_to_y { scaled_document_drag.y } else { 0. }, let scaled_document_drag = document_drag_vector * scale_factor;
if parallel_to_x { scaled_document_drag.x } else { 0. },
1., let skew = DAffine2::from_mat2(DMat2::from_cols_array(&[
])); 1.,
if parallel_to_y { scaled_document_drag.y } else { 0. },
let constructed_transform = DAffine2::from_translation(opposite) * skew * DAffine2::from_translation(-opposite); if parallel_to_x { scaled_document_drag.x } else { 0. },
1.,
assert_eq!(constructed_transform, final_transform); ]));
let constructed_transform = DAffine2::from_translation(opposite) * skew * DAffine2::from_translation(-opposite);
assert_eq!(constructed_transform, final_transform);
}
} }
} }

View File

@ -570,28 +570,33 @@ pub fn solve_spline_first_handle_closed(points: &[DVec2]) -> Vec<DVec2> {
x x
} }
#[test] #[cfg(test)]
fn closed_spline() { mod tests {
// These points are just chosen arbitrary use super::*;
let points = [DVec2::new(0., 0.), DVec2::new(0., 0.), DVec2::new(6., 5.), DVec2::new(7., 9.), DVec2::new(2., 3.)];
let out_handles = solve_spline_first_handle_closed(&points); #[test]
fn closed_spline() {
// These points are just chosen arbitrary
let points = [DVec2::new(0., 0.), DVec2::new(0., 0.), DVec2::new(6., 5.), DVec2::new(7., 9.), DVec2::new(2., 3.)];
// Construct the Subpath let out_handles = solve_spline_first_handle_closed(&points);
let mut manipulator_groups = Vec::new();
for i in 0..out_handles.len() {
manipulator_groups.push(ManipulatorGroup::<EmptyId>::new(points[i], Some(2. * points[i] - out_handles[i]), Some(out_handles[i])));
}
let subpath = Subpath::new(manipulator_groups, true);
// For each pair of bézier curves, ensure that the second derivative is continuous // Construct the Subpath
for (bézier_a, bézier_b) in subpath.iter().zip(subpath.iter().skip(1).chain(subpath.iter().take(1))) { let mut manipulator_groups = Vec::new();
let derivative2_end_a = bézier_a.derivative().unwrap().derivative().unwrap().evaluate(crate::TValue::Parametric(1.)); for i in 0..out_handles.len() {
let derivative2_start_b = bézier_b.derivative().unwrap().derivative().unwrap().evaluate(crate::TValue::Parametric(0.)); manipulator_groups.push(ManipulatorGroup::<EmptyId>::new(points[i], Some(2. * points[i] - out_handles[i]), Some(out_handles[i])));
}
let subpath = Subpath::new(manipulator_groups, true);
assert!( // For each pair of bézier curves, ensure that the second derivative is continuous
derivative2_end_a.abs_diff_eq(derivative2_start_b, 1e-10), for (bézier_a, bézier_b) in subpath.iter().zip(subpath.iter().skip(1).chain(subpath.iter().take(1))) {
"second derivative at the end of a {derivative2_end_a} is equal to the second derivative at the start of b {derivative2_start_b}" let derivative2_end_a = bézier_a.derivative().unwrap().derivative().unwrap().evaluate(crate::TValue::Parametric(1.));
); let derivative2_start_b = bézier_b.derivative().unwrap().derivative().unwrap().evaluate(crate::TValue::Parametric(0.));
assert!(
derivative2_end_a.abs_diff_eq(derivative2_start_b, 1e-10),
"second derivative at the end of a {derivative2_end_a} is equal to the second derivative at the start of b {derivative2_start_b}"
);
}
} }
} }

View File

@ -150,43 +150,48 @@ impl core::ops::Mul<Quad> for DAffine2 {
Quad(rhs.0.map(|point| self.transform_point2(point))) Quad(rhs.0.map(|point| self.transform_point2(point)))
} }
} }
#[test]
fn offset_quad() { #[cfg(test)]
fn eq(a: Quad, b: Quad) -> bool { mod tests {
a.0.iter().zip(b.0).all(|(a, b)| a.abs_diff_eq(b, 0.0001)) use super::*;
#[test]
fn offset_quad() {
fn eq(a: Quad, b: Quad) -> bool {
a.0.iter().zip(b.0).all(|(a, b)| a.abs_diff_eq(b, 0.0001))
}
assert!(eq(Quad::from_box([DVec2::ZERO, DVec2::ONE]).inflate(0.5), Quad::from_box([DVec2::splat(-0.5), DVec2::splat(1.5)])));
assert!(eq(Quad::from_box([DVec2::ONE, DVec2::ZERO]).inflate(0.5), Quad::from_box([DVec2::splat(1.5), DVec2::splat(-0.5)])));
assert!(eq(
(DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).inflate(0.5),
DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::splat(-0.5), DVec2::splat(1.5)])
));
}
#[test]
fn quad_contains() {
assert!(Quad::from_box([DVec2::ZERO, DVec2::ONE]).contains(DVec2::splat(0.5)));
assert!(Quad::from_box([DVec2::ONE, DVec2::ZERO]).contains(DVec2::splat(0.5)));
assert!(Quad::from_box([DVec2::splat(300.), DVec2::splat(500.)]).contains(DVec2::splat(350.)));
assert!((DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).contains(DVec2::new(-0.5, 0.5)));
assert!(!Quad::from_box([DVec2::ZERO, DVec2::ONE]).contains(DVec2::new(1., 1.1)));
assert!(!Quad::from_box([DVec2::ONE, DVec2::ZERO]).contains(DVec2::new(0.5, -0.01)));
assert!(!(DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).contains(DVec2::splat(0.5)));
} }
assert!(eq(Quad::from_box([DVec2::ZERO, DVec2::ONE]).inflate(0.5), Quad::from_box([DVec2::splat(-0.5), DVec2::splat(1.5)]))); #[test]
assert!(eq(Quad::from_box([DVec2::ONE, DVec2::ZERO]).inflate(0.5), Quad::from_box([DVec2::splat(1.5), DVec2::splat(-0.5)]))); fn intersect_lines() {
assert!(eq( assert_eq!(
(DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).inflate(0.5), Quad::intersect_lines(DVec2::new(-5., 5.), DVec2::new(5., 5.), DVec2::new(2., 7.), DVec2::new(2., 3.)),
DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::splat(-0.5), DVec2::splat(1.5)]) Some(DVec2::new(2., 5.))
)); );
} assert_eq!(Quad::intersect_lines(DVec2::new(4., 6.), DVec2::new(4., 5.), DVec2::new(2., 7.), DVec2::new(2., 3.)), None);
#[test] assert_eq!(Quad::intersect_lines(DVec2::new(-5., 5.), DVec2::new(5., 5.), DVec2::new(2., 7.), DVec2::new(2., 9.)), None);
fn quad_contains() { }
assert!(Quad::from_box([DVec2::ZERO, DVec2::ONE]).contains(DVec2::splat(0.5))); #[test]
assert!(Quad::from_box([DVec2::ONE, DVec2::ZERO]).contains(DVec2::splat(0.5))); fn intersect_quad() {
assert!(Quad::from_box([DVec2::splat(300.), DVec2::splat(500.)]).contains(DVec2::splat(350.))); assert!(Quad::from_box([DVec2::ZERO, DVec2::splat(5.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(7.)])));
assert!((DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).contains(DVec2::new(-0.5, 0.5))); assert!(Quad::from_box([DVec2::ZERO, DVec2::splat(5.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(4.2)])));
assert!(!Quad::from_box([DVec2::ZERO, DVec2::splat(3.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(4.2)])));
assert!(!Quad::from_box([DVec2::ZERO, DVec2::ONE]).contains(DVec2::new(1., 1.1))); }
assert!(!Quad::from_box([DVec2::ONE, DVec2::ZERO]).contains(DVec2::new(0.5, -0.01)));
assert!(!(DAffine2::from_scale(DVec2::new(-1., 1.)) * Quad::from_box([DVec2::ZERO, DVec2::ONE])).contains(DVec2::splat(0.5)));
}
#[test]
fn intersect_lines() {
assert_eq!(
Quad::intersect_lines(DVec2::new(-5., 5.), DVec2::new(5., 5.), DVec2::new(2., 7.), DVec2::new(2., 3.)),
Some(DVec2::new(2., 5.))
);
assert_eq!(Quad::intersect_lines(DVec2::new(4., 6.), DVec2::new(4., 5.), DVec2::new(2., 7.), DVec2::new(2., 3.)), None);
assert_eq!(Quad::intersect_lines(DVec2::new(-5., 5.), DVec2::new(5., 5.), DVec2::new(2., 7.), DVec2::new(2., 9.)), None);
}
#[test]
fn intersect_quad() {
assert!(Quad::from_box([DVec2::ZERO, DVec2::splat(5.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(7.)])));
assert!(Quad::from_box([DVec2::ZERO, DVec2::splat(5.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(4.2)])));
assert!(!Quad::from_box([DVec2::ZERO, DVec2::splat(3.)]).intersects(Quad::from_box([DVec2::splat(4.), DVec2::splat(4.2)])));
} }

View File

@ -1058,37 +1058,41 @@ impl Color {
} }
} }
#[test] #[cfg(test)]
fn hsl_roundtrip() { mod tests {
for (red, green, blue) in [ use super::*;
(24, 98, 118), #[test]
(69, 11, 89), fn hsl_roundtrip() {
(54, 82, 38), for (red, green, blue) in [
(47, 76, 50), (24, 98, 118),
(25, 15, 73), (69, 11, 89),
(62, 57, 33), (54, 82, 38),
(55, 2, 18), (47, 76, 50),
(12, 3, 82), (25, 15, 73),
(91, 16, 98), (62, 57, 33),
(91, 39, 82), (55, 2, 18),
(97, 53, 32), (12, 3, 82),
(76, 8, 91), (91, 16, 98),
(54, 87, 19), (91, 39, 82),
(56, 24, 88), (97, 53, 32),
(14, 82, 34), (76, 8, 91),
(61, 86, 31), (54, 87, 19),
(73, 60, 75), (56, 24, 88),
(95, 79, 88), (14, 82, 34),
(13, 34, 4), (61, 86, 31),
(82, 84, 84), (73, 60, 75),
(255, 255, 178), (95, 79, 88),
] { (13, 34, 4),
let col = Color::from_rgb8_srgb(red, green, blue); (82, 84, 84),
let [hue, saturation, lightness, alpha] = col.to_hsla(); (255, 255, 178),
let result = Color::from_hsla(hue, saturation, lightness, alpha); ] {
assert!((col.r() - result.r()) < f32::EPSILON * 100.); let col = Color::from_rgb8_srgb(red, green, blue);
assert!((col.g() - result.g()) < f32::EPSILON * 100.); let [hue, saturation, lightness, alpha] = col.to_hsla();
assert!((col.b() - result.b()) < f32::EPSILON * 100.); let result = Color::from_hsla(hue, saturation, lightness, alpha);
assert!((col.a() - result.a()) < f32::EPSILON * 100.); assert!((col.r() - result.r()) < f32::EPSILON * 100.);
assert!((col.g() - result.g()) < f32::EPSILON * 100.);
assert!((col.b() - result.b()) < f32::EPSILON * 100.);
assert!((col.a() - result.a()) < f32::EPSILON * 100.);
}
} }
} }

View File

@ -239,11 +239,15 @@ impl<'a> Iterator for SplitWordsIncludingSpaces<'a> {
} }
} }
#[test] #[cfg(test)]
fn split_words_including_spaces() { mod tests {
let mut split_words = SplitWordsIncludingSpaces::new("hello world ."); use super::*;
assert_eq!(split_words.next(), Some("hello ")); #[test]
assert_eq!(split_words.next(), Some("world ")); fn split_words_including_spaces() {
assert_eq!(split_words.next(), Some(".")); let mut split_words = SplitWordsIncludingSpaces::new("hello world .");
assert_eq!(split_words.next(), None); assert_eq!(split_words.next(), Some("hello "));
assert_eq!(split_words.next(), Some("world "));
assert_eq!(split_words.next(), Some("."));
assert_eq!(split_words.next(), None);
}
} }

View File

@ -136,43 +136,47 @@ pub fn solve_spline_first_handle_closed(points: &[DVec2]) -> Vec<DVec2> {
x x
} }
#[test] #[cfg(test)]
fn closed_spline() { mod tests {
use crate::vector::misc::{dvec2_to_point, point_to_dvec2}; use super::*;
use kurbo::{BezPath, ParamCurve, ParamCurveDeriv}; #[test]
fn closed_spline() {
use crate::vector::misc::{dvec2_to_point, point_to_dvec2};
use kurbo::{BezPath, ParamCurve, ParamCurveDeriv};
// These points are just chosen arbitrary // These points are just chosen arbitrary
let points = [DVec2::new(0., 0.), DVec2::new(0., 0.), DVec2::new(6., 5.), DVec2::new(7., 9.), DVec2::new(2., 3.)]; let points = [DVec2::new(0., 0.), DVec2::new(0., 0.), DVec2::new(6., 5.), DVec2::new(7., 9.), DVec2::new(2., 3.)];
// List of first handle or second point in a cubic bezier curve. // List of first handle or second point in a cubic bezier curve.
let first_handles = solve_spline_first_handle_closed(&points); let first_handles = solve_spline_first_handle_closed(&points);
// Construct the Subpath // Construct the Subpath
let mut bezpath = BezPath::new(); let mut bezpath = BezPath::new();
bezpath.move_to(dvec2_to_point(points[0])); bezpath.move_to(dvec2_to_point(points[0]));
for i in 0..first_handles.len() { for i in 0..first_handles.len() {
let next_i = i + 1; let next_i = i + 1;
let next_i = if next_i == first_handles.len() { 0 } else { next_i }; let next_i = if next_i == first_handles.len() { 0 } else { next_i };
// First handle or second point of a cubic Bezier curve. // First handle or second point of a cubic Bezier curve.
let p1 = dvec2_to_point(first_handles[i]); let p1 = dvec2_to_point(first_handles[i]);
// Second handle or third point of a cubic Bezier curve. // Second handle or third point of a cubic Bezier curve.
let p2 = dvec2_to_point(2. * points[next_i] - first_handles[next_i]); let p2 = dvec2_to_point(2. * points[next_i] - first_handles[next_i]);
// Endpoint or fourth point of a cubic Bezier curve. // Endpoint or fourth point of a cubic Bezier curve.
let p3 = dvec2_to_point(points[next_i]); let p3 = dvec2_to_point(points[next_i]);
bezpath.curve_to(p1, p2, p3); bezpath.curve_to(p1, p2, p3);
} }
// For each pair of bézier curves, ensure that the second derivative is continuous // For each pair of bézier curves, ensure that the second derivative is continuous
for (bézier_a, bézier_b) in bezpath.segments().zip(bezpath.segments().skip(1).chain(bezpath.segments().take(1))) { for (bézier_a, bézier_b) in bezpath.segments().zip(bezpath.segments().skip(1).chain(bezpath.segments().take(1))) {
let derivative2_end_a = point_to_dvec2(bézier_a.to_cubic().deriv().eval(1.)); let derivative2_end_a = point_to_dvec2(bézier_a.to_cubic().deriv().eval(1.));
let derivative2_start_b = point_to_dvec2(bézier_b.to_cubic().deriv().eval(0.)); let derivative2_start_b = point_to_dvec2(bézier_b.to_cubic().deriv().eval(0.));
assert!( assert!(
derivative2_end_a.abs_diff_eq(derivative2_start_b, 1e-10), derivative2_end_a.abs_diff_eq(derivative2_start_b, 1e-10),
"second derivative at the end of a {derivative2_end_a} is equal to the second derivative at the start of b {derivative2_start_b}" "second derivative at the end of a {derivative2_end_a} is equal to the second derivative at the start of b {derivative2_start_b}"
); );
}
} }
} }

View File

@ -245,35 +245,39 @@ fn grid<T: GridSpacing>(
VectorDataTable::new(vector_data) VectorDataTable::new(vector_data)
} }
#[test] #[cfg(test)]
fn isometric_grid_test() { mod tests {
// Doesn't crash with weird angles use super::*;
grid((), (), GridType::Isometric, 0., (0., 0.).into(), 5, 5); #[test]
grid((), (), GridType::Isometric, 90., (90., 90.).into(), 5, 5); fn isometric_grid_test() {
// Doesn't crash with weird angles
grid((), (), GridType::Isometric, 0., (0., 0.).into(), 5, 5);
grid((), (), GridType::Isometric, 90., (90., 90.).into(), 5, 5);
// Works properly // Works properly
let grid = grid((), (), GridType::Isometric, 10., (30., 30.).into(), 5, 5); let grid = grid((), (), GridType::Isometric, 10., (30., 30.).into(), 5, 5);
assert_eq!(grid.instance_ref_iter().next().unwrap().instance.point_domain.ids().len(), 5 * 5); assert_eq!(grid.instance_ref_iter().next().unwrap().instance.point_domain.ids().len(), 5 * 5);
assert_eq!(grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter().count(), 4 * 5 + 4 * 9); assert_eq!(grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter().count(), 4 * 5 + 4 * 9);
for (_, bezier, _, _) in grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter() { for (_, bezier, _, _) in grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter() {
assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear); assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear);
assert!( assert!(
((bezier.start - bezier.end).length() - 10.).abs() < 1e-5, ((bezier.start - bezier.end).length() - 10.).abs() < 1e-5,
"Length of {} should be 10", "Length of {} should be 10",
(bezier.start - bezier.end).length() (bezier.start - bezier.end).length()
); );
} }
} }
#[test] #[test]
fn skew_isometric_grid_test() { fn skew_isometric_grid_test() {
let grid = grid((), (), GridType::Isometric, 10., (40., 30.).into(), 5, 5); let grid = grid((), (), GridType::Isometric, 10., (40., 30.).into(), 5, 5);
assert_eq!(grid.instance_ref_iter().next().unwrap().instance.point_domain.ids().len(), 5 * 5); assert_eq!(grid.instance_ref_iter().next().unwrap().instance.point_domain.ids().len(), 5 * 5);
assert_eq!(grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter().count(), 4 * 5 + 4 * 9); assert_eq!(grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter().count(), 4 * 5 + 4 * 9);
for (_, bezier, _, _) in grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter() { for (_, bezier, _, _) in grid.instance_ref_iter().next().unwrap().instance.segment_bezier_iter() {
assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear); assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear);
let vector = bezier.start - bezier.end; let vector = bezier.start - bezier.end;
let angle = (vector.angle_to(DVec2::X).to_degrees() + 180.) % 180.; let angle = (vector.angle_to(DVec2::X).to_degrees() + 180.) % 180.;
assert!([90., 150., 40.].into_iter().any(|target| (target - angle).abs() < 1e-10), "unexpected angle of {}", angle) assert!([90., 150., 40.].into_iter().any(|target| (target - angle).abs() < 1e-10), "unexpected angle of {}", angle)
}
} }
} }

View File

@ -676,45 +676,49 @@ fn assert_subpath_eq(generated: &[bezier_rs::Subpath<PointId>], expected: &[bezi
} }
} }
#[test] #[cfg(test)]
fn construct_closed_subpath() { mod tests {
let circle = bezier_rs::Subpath::new_ellipse(DVec2::NEG_ONE, DVec2::ONE); use super::*;
let vector_data = VectorData::from_subpath(&circle); #[test]
assert_eq!(vector_data.point_domain.ids().len(), 4); fn construct_closed_subpath() {
let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>(); let circle = bezier_rs::Subpath::new_ellipse(DVec2::NEG_ONE, DVec2::ONE);
assert_eq!(bezier_paths.len(), 4); let vector_data = VectorData::from_subpath(&circle);
assert!(bezier_paths.iter().all(|&bezier| circle.iter().any(|original_bezier| original_bezier == bezier))); assert_eq!(vector_data.point_domain.ids().len(), 4);
let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>();
assert_eq!(bezier_paths.len(), 4);
assert!(bezier_paths.iter().all(|&bezier| circle.iter().any(|original_bezier| original_bezier == bezier)));
let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>(); let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>();
assert_subpath_eq(&generated, &[circle]); assert_subpath_eq(&generated, &[circle]);
} }
#[test] #[test]
fn construct_open_subpath() { fn construct_open_subpath() {
let bezier = bezier_rs::Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::NEG_ONE, DVec2::ONE, DVec2::X); let bezier = bezier_rs::Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::NEG_ONE, DVec2::ONE, DVec2::X);
let subpath = bezier_rs::Subpath::from_bezier(&bezier); let subpath = bezier_rs::Subpath::from_bezier(&bezier);
let vector_data = VectorData::from_subpath(&subpath); let vector_data = VectorData::from_subpath(&subpath);
assert_eq!(vector_data.point_domain.ids().len(), 2); assert_eq!(vector_data.point_domain.ids().len(), 2);
let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>(); let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>();
assert_eq!(bezier_paths, vec![bezier]); assert_eq!(bezier_paths, vec![bezier]);
let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>(); let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>();
assert_subpath_eq(&generated, &[subpath]); assert_subpath_eq(&generated, &[subpath]);
} }
#[test] #[test]
fn construct_many_subpath() { fn construct_many_subpath() {
let curve = bezier_rs::Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::NEG_ONE, DVec2::ONE, DVec2::X); let curve = bezier_rs::Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::NEG_ONE, DVec2::ONE, DVec2::X);
let curve = bezier_rs::Subpath::from_bezier(&curve); let curve = bezier_rs::Subpath::from_bezier(&curve);
let circle = bezier_rs::Subpath::new_ellipse(DVec2::NEG_ONE, DVec2::ONE); let circle = bezier_rs::Subpath::new_ellipse(DVec2::NEG_ONE, DVec2::ONE);
let vector_data = VectorData::from_subpaths([&curve, &circle], false); let vector_data = VectorData::from_subpaths([&curve, &circle], false);
assert_eq!(vector_data.point_domain.ids().len(), 6); assert_eq!(vector_data.point_domain.ids().len(), 6);
let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>(); let bezier_paths = vector_data.segment_bezier_iter().map(|(_, bezier, _, _)| bezier).collect::<Vec<_>>();
assert_eq!(bezier_paths.len(), 5); assert_eq!(bezier_paths.len(), 5);
assert!(bezier_paths.iter().all(|&bezier| circle.iter().chain(curve.iter()).any(|original_bezier| original_bezier == bezier))); assert!(bezier_paths.iter().all(|&bezier| circle.iter().chain(curve.iter()).any(|original_bezier| original_bezier == bezier)));
let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>(); let generated = vector_data.stroke_bezier_paths().collect::<Vec<_>>();
assert_subpath_eq(&generated, &[curve, circle]); assert_subpath_eq(&generated, &[curve, circle]);
}
} }

View File

@ -436,64 +436,6 @@ async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modificat
vector_data vector_data
} }
#[test]
fn modify_new() {
let vector_data = VectorData::from_subpaths(
[bezier_rs::Subpath::new_ellipse(DVec2::ZERO, DVec2::ONE), bezier_rs::Subpath::new_rect(DVec2::NEG_ONE, DVec2::ZERO)],
false,
);
let modify = VectorModification::create_from_vector(&vector_data);
let mut new = VectorData::default();
modify.apply(&mut new);
assert_eq!(vector_data, new);
}
#[test]
fn modify_existing() {
use bezier_rs::{Bezier, Subpath};
let subpaths = [
Subpath::new_ellipse(DVec2::ZERO, DVec2::ONE),
Subpath::new_rect(DVec2::NEG_ONE, DVec2::ZERO),
Subpath::from_beziers(
&[
Bezier::from_quadratic_dvec2(DVec2::new(0., 0.), DVec2::new(5., 10.), DVec2::new(10., 0.)),
Bezier::from_quadratic_dvec2(DVec2::new(10., 0.), DVec2::new(15., 10.), DVec2::new(20., 0.)),
],
false,
),
];
let mut vector_data = VectorData::from_subpaths(subpaths, false);
let mut modify_new = VectorModification::create_from_vector(&vector_data);
let mut modify_original = VectorModification::default();
for modification in [&mut modify_new, &mut modify_original] {
let point = vector_data.point_domain.ids()[0];
modification.modify(&VectorModificationType::ApplyPointDelta { point, delta: DVec2::X * 0.5 });
let point = vector_data.point_domain.ids()[9];
modification.modify(&VectorModificationType::ApplyPointDelta { point, delta: DVec2::X });
}
let mut new = VectorData::default();
modify_new.apply(&mut new);
modify_original.apply(&mut vector_data);
assert_eq!(vector_data, new);
assert_eq!(vector_data.point_domain.positions()[0], DVec2::X);
assert_eq!(vector_data.point_domain.positions()[9], DVec2::new(11., 0.));
assert_eq!(
vector_data.segment_bezier_iter().nth(8).unwrap().1,
Bezier::from_quadratic_dvec2(DVec2::new(0., 0.), DVec2::new(5., 10.), DVec2::new(11., 0.))
);
assert_eq!(
vector_data.segment_bezier_iter().nth(9).unwrap().1,
Bezier::from_quadratic_dvec2(DVec2::new(11., 0.), DVec2::new(16., 10.), DVec2::new(20., 0.))
);
}
// Do we want to enforce that all serialized/deserialized hashmaps are a vec of tuples? // Do we want to enforce that all serialized/deserialized hashmaps are a vec of tuples?
// TODO: Eventually remove this document upgrade code // TODO: Eventually remove this document upgrade code
use serde::de::{SeqAccess, Visitor}; use serde::de::{SeqAccess, Visitor};
@ -686,3 +628,66 @@ impl<'a> AppendBezpath<'a> {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn modify_new() {
let vector_data = VectorData::from_subpaths(
[bezier_rs::Subpath::new_ellipse(DVec2::ZERO, DVec2::ONE), bezier_rs::Subpath::new_rect(DVec2::NEG_ONE, DVec2::ZERO)],
false,
);
let modify = VectorModification::create_from_vector(&vector_data);
let mut new = VectorData::default();
modify.apply(&mut new);
assert_eq!(vector_data, new);
}
#[test]
fn modify_existing() {
use bezier_rs::{Bezier, Subpath};
let subpaths = [
Subpath::new_ellipse(DVec2::ZERO, DVec2::ONE),
Subpath::new_rect(DVec2::NEG_ONE, DVec2::ZERO),
Subpath::from_beziers(
&[
Bezier::from_quadratic_dvec2(DVec2::new(0., 0.), DVec2::new(5., 10.), DVec2::new(10., 0.)),
Bezier::from_quadratic_dvec2(DVec2::new(10., 0.), DVec2::new(15., 10.), DVec2::new(20., 0.)),
],
false,
),
];
let mut vector_data = VectorData::from_subpaths(subpaths, false);
let mut modify_new = VectorModification::create_from_vector(&vector_data);
let mut modify_original = VectorModification::default();
for modification in [&mut modify_new, &mut modify_original] {
let point = vector_data.point_domain.ids()[0];
modification.modify(&VectorModificationType::ApplyPointDelta { point, delta: DVec2::X * 0.5 });
let point = vector_data.point_domain.ids()[9];
modification.modify(&VectorModificationType::ApplyPointDelta { point, delta: DVec2::X });
}
let mut new = VectorData::default();
modify_new.apply(&mut new);
modify_original.apply(&mut vector_data);
assert_eq!(vector_data, new);
assert_eq!(vector_data.point_domain.positions()[0], DVec2::X);
assert_eq!(vector_data.point_domain.positions()[9], DVec2::new(11., 0.));
assert_eq!(
vector_data.segment_bezier_iter().nth(8).unwrap().1,
Bezier::from_quadratic_dvec2(DVec2::new(0., 0.), DVec2::new(5., 10.), DVec2::new(11., 0.))
);
assert_eq!(
vector_data.segment_bezier_iter().nth(9).unwrap().1,
Bezier::from_quadratic_dvec2(DVec2::new(11., 0.), DVec2::new(16., 10.), DVec2::new(20., 0.))
);
}
}