Skip to content

Commit

Permalink
Merge pull request #910 from hannobraun/line
Browse files Browse the repository at this point in the history
Validate `Line` on construction
  • Loading branch information
hannobraun authored Aug 3, 2022
2 parents e7d0a75 + 439ff8f commit c901659
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 100 deletions.
34 changes: 12 additions & 22 deletions crates/fj-kernel/src/algorithms/intersection/line_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl LineSegmentIntersection {
Vector::from([ab.v, ab.u])
};

let n_dot_origin = n.dot(&(b - line.origin));
let n_dot_direction = n.dot(&line.direction);
let n_dot_origin = n.dot(&(b - line.origin()));
let n_dot_direction = n.dot(&line.direction());

if n_dot_direction == Scalar::ZERO {
// `line` and `segment` are parallel
Expand Down Expand Up @@ -72,10 +72,8 @@ mod tests {

#[test]
fn compute_one_hit() {
let line = Line {
origin: Point::origin(),
direction: Vector::unit_u(),
};
let line =
Line::from_origin_and_direction(Point::origin(), Vector::unit_u());

assert_eq!(
LineSegmentIntersection::compute(
Expand All @@ -90,10 +88,8 @@ mod tests {

#[test]
fn compute_coincident() {
let line = Line {
origin: Point::origin(),
direction: Vector::unit_u(),
};
let line =
Line::from_origin_and_direction(Point::origin(), Vector::unit_u());

assert_eq!(
LineSegmentIntersection::compute(
Expand All @@ -108,10 +104,8 @@ mod tests {

#[test]
fn compute_no_hit_above() {
let line = Line {
origin: Point::origin(),
direction: Vector::unit_u(),
};
let line =
Line::from_origin_and_direction(Point::origin(), Vector::unit_u());

assert_eq!(
LineSegmentIntersection::compute(
Expand All @@ -124,10 +118,8 @@ mod tests {

#[test]
fn compute_no_hit_below() {
let line = Line {
origin: Point::origin(),
direction: Vector::unit_u(),
};
let line =
Line::from_origin_and_direction(Point::origin(), Vector::unit_u());

assert_eq!(
LineSegmentIntersection::compute(
Expand All @@ -140,10 +132,8 @@ mod tests {

#[test]
fn compute_no_hit_parallel() {
let line = Line {
origin: Point::origin(),
direction: Vector::unit_u(),
};
let line =
Line::from_origin_and_direction(Point::origin(), Vector::unit_u());

assert_eq!(
LineSegmentIntersection::compute(
Expand Down
24 changes: 13 additions & 11 deletions crates/fj-kernel/src/algorithms/intersection/surface_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ impl SurfaceSurfaceIntersection {
/ denom;
let origin = Point { coords: origin };

let line = Line { origin, direction };
let line = Line::from_origin_and_direction(origin, direction);

let curves = planes_parametric.map(|plane| {
let local = project_line_into_plane(&line, &plane);
let global = CurveKind::Line(Line { origin, direction });
let global = CurveKind::Line(Line::from_origin_and_direction(
origin, direction,
));

Curve::new(local, GlobalCurve::from_kind(global))
});
Expand Down Expand Up @@ -74,8 +76,8 @@ impl PlaneParametric {
};

Self {
origin: line.origin,
u: line.direction,
origin: line.origin(),
u: line.direction(),
v: surface.path,
}
}
Expand Down Expand Up @@ -111,7 +113,7 @@ fn project_line_into_plane(
line: &Line<3>,
plane: &PlaneParametric,
) -> CurveKind<2> {
let line_origin_relative_to_plane = line.origin - plane.origin;
let line_origin_relative_to_plane = line.origin() - plane.origin;
let line_origin_in_plane = Vector::from([
plane
.u
Expand All @@ -122,16 +124,16 @@ fn project_line_into_plane(
]);

let line_direction_in_plane = Vector::from([
plane.u.scalar_projection_onto(&line.direction),
plane.v.scalar_projection_onto(&line.direction),
plane.u.scalar_projection_onto(&line.direction()),
plane.v.scalar_projection_onto(&line.direction()),
]);

let line = Line {
origin: Point {
let line = Line::from_origin_and_direction(
Point {
coords: line_origin_in_plane,
},
direction: line_direction_in_plane,
};
line_direction_in_plane,
);

CurveKind::Line(line)
}
Expand Down
17 changes: 11 additions & 6 deletions crates/fj-kernel/src/algorithms/reverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ fn reverse_local_coordinates_in_cycle<'r>(

CurveKind::Circle(Circle { center, a, b })
}
CurveKind::Line(Line { origin, direction }) => {
let origin = Point::from([origin.u, -origin.v]);
let direction =
Vector::from([direction.u, -direction.v]);

CurveKind::Line(Line { origin, direction })
CurveKind::Line(line) => {
let origin =
Point::from([line.origin().u, -line.origin().v]);
let direction = Vector::from([
line.direction().u,
-line.direction().v,
]);

CurveKind::Line(Line::from_origin_and_direction(
origin, direction,
))
}
};

Expand Down
26 changes: 13 additions & 13 deletions crates/fj-kernel/src/objects/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl<const D: usize> CurveKind<D> {
pub fn origin(&self) -> Point<D> {
match self {
Self::Circle(curve) => curve.center,
Self::Line(curve) => curve.origin,
Self::Line(curve) => curve.origin(),
}
}

Expand Down Expand Up @@ -127,26 +127,26 @@ impl<const D: usize> CurveKind<D> {
impl CurveKind<3> {
/// Construct a `Curve` that represents the x-axis
pub fn x_axis() -> Self {
Self::Line(Line {
origin: Point::origin(),
direction: Vector::unit_x(),
})
Self::Line(Line::from_origin_and_direction(
Point::origin(),
Vector::unit_x(),
))
}

/// Construct a `Curve` that represents the y-axis
pub fn y_axis() -> Self {
Self::Line(Line {
origin: Point::origin(),
direction: Vector::unit_y(),
})
Self::Line(Line::from_origin_and_direction(
Point::origin(),
Vector::unit_y(),
))
}

/// Construct a `Curve` that represents the z-axis
pub fn z_axis() -> Self {
Self::Line(Line {
origin: Point::origin(),
direction: Vector::unit_z(),
})
Self::Line(Line::from_origin_and_direction(
Point::origin(),
Vector::unit_z(),
))
}

/// Transform the surface
Expand Down
37 changes: 17 additions & 20 deletions crates/fj-kernel/src/objects/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,7 @@ impl SweptCurve {
}

fn path_to_line(&self) -> Line<3> {
Line {
origin: self.curve.origin(),
direction: self.path,
}
Line::from_origin_and_direction(self.curve.origin(), self.path)
}
}

Expand All @@ -143,20 +140,20 @@ mod tests {
#[test]
fn reverse() {
let original = SweptCurve {
curve: CurveKind::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
}),
curve: CurveKind::Line(Line::from_origin_and_direction(
Point::from([1., 0., 0.]),
Vector::from([0., 2., 0.]),
)),
path: Vector::from([0., 0., 3.]),
};

let reversed = original.reverse();

let expected = SweptCurve {
curve: CurveKind::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
}),
curve: CurveKind::Line(Line::from_origin_and_direction(
Point::from([1., 0., 0.]),
Vector::from([0., 2., 0.]),
)),
path: Vector::from([0., 0., -3.]),
};
assert_eq!(expected, reversed);
Expand All @@ -165,10 +162,10 @@ mod tests {
#[test]
fn point_from_surface_coords() {
let swept = SweptCurve {
curve: CurveKind::Line(Line {
origin: Point::from([1., 1., 1.]),
direction: Vector::from([0., 2., 0.]),
}),
curve: CurveKind::Line(Line::from_origin_and_direction(
Point::from([1., 1., 1.]),
Vector::from([0., 2., 0.]),
)),
path: Vector::from([0., 0., 2.]),
};

Expand All @@ -181,10 +178,10 @@ mod tests {
#[test]
fn vector_from_surface_coords() {
let swept = SweptCurve {
curve: CurveKind::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
}),
curve: CurveKind::Line(Line::from_origin_and_direction(
Point::from([1., 0., 0.]),
Vector::from([0., 2., 0.]),
)),
path: Vector::from([0., 0., 2.]),
};

Expand Down
59 changes: 43 additions & 16 deletions crates/fj-math/src/line.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Point, Triangle, Vector};
use crate::{Point, Scalar, Triangle, Vector};

/// An n-dimensional line, defined by an origin and a direction
///
Expand All @@ -7,30 +7,57 @@ use crate::{Point, Triangle, Vector};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct Line<const D: usize> {
/// The origin of the line
origin: Point<D>,
direction: Vector<D>,
}

impl<const D: usize> Line<D> {
/// Create a line from a point and a vector
///
/// # Panics
///
/// Panics, if `direction` has a length of zero.
pub fn from_origin_and_direction(
origin: Point<D>,
direction: Vector<D>,
) -> Self {
if direction.magnitude() == Scalar::ZERO {
panic!(
"Can't construct `Line`. Direction is zero: {:?}",
direction
);
}

Self { origin, direction }
}

/// Create a line from two points
///
/// # Panics
///
/// Panics, if the points are coincident.
pub fn from_points(points: [impl Into<Point<D>>; 2]) -> Self {
let [a, b] = points.map(Into::into);

Self::from_origin_and_direction(a, b - a)
}

/// Access the origin of the line
///
/// The origin is a point on the line which, together with the `direction`
/// field, defines the line fully. The origin also defines the origin of the
/// line's 1-dimensional coordinate system.
pub origin: Point<D>,
pub fn origin(&self) -> Point<D> {
self.origin
}

/// The direction of the line
/// Access the direction of the line
///
/// The length of this vector defines the unit of the line's curve
/// coordinate system. The coordinate `1.` is always were the direction
/// vector points, from `origin`.
pub direction: Vector<D>,
}

impl<const D: usize> Line<D> {
/// Create a line from two points
pub fn from_points(points: [impl Into<Point<D>>; 2]) -> Self {
let [a, b] = points.map(Into::into);

Self {
origin: a,
direction: b - a,
}
pub fn direction(&self) -> Vector<D> {
self.direction
}

/// Determine if this line is coincident with another line
Expand Down
Loading

0 comments on commit c901659

Please sign in to comment.