Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare SurfaceGeom for the transition to a more flexible geometry representation #2428

Merged
merged 10 commits into from
Jul 26, 2024
16 changes: 8 additions & 8 deletions crates/fj-core/src/algorithms/approx/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ fn approx_curve(
boundary: CurveBoundary<Point<1>>,
tolerance: impl Into<Tolerance>,
) -> CurveApprox {
let points = match (path, surface.u) {
let SurfaceGeom::Basic { u, .. } = surface;
let points = match (path, u) {
(SurfacePath::Circle(_), GlobalPath::Circle(_)) => {
approx_circle_on_curved_surface()
}
Expand Down Expand Up @@ -110,11 +111,10 @@ fn approx_line_on_any_surface(
.map(|point_curve| [line.point_from_line_coords(point_curve).u]),
);

let approx_u = match surface.u {
GlobalPath::Circle(circle) => {
approx_circle(&circle, range_u, tolerance)
}
GlobalPath::Line(line) => approx_line(&line),
let SurfaceGeom::Basic { u, .. } = surface;
let approx_u = match u {
GlobalPath::Circle(circle) => approx_circle(circle, range_u, tolerance),
GlobalPath::Line(line) => approx_line(line),
};

let mut points = Vec::new();
Expand Down Expand Up @@ -216,7 +216,7 @@ mod tests {

#[test]
fn approx_line_on_curved_surface_but_not_along_curve() {
let surface = SurfaceGeom {
let surface = SurfaceGeom::Basic {
u: GlobalPath::circle_from_radius(1.),
v: Vector::from([0., 0., 1.]),
};
Expand All @@ -236,7 +236,7 @@ mod tests {

let circle = Circle::from_center_and_radius(Point::origin(), 1.);
let global_path = GlobalPath::Circle(circle);
let surface_geom = SurfaceGeom {
let surface_geom = SurfaceGeom::Basic {
u: global_path,
v: Vector::from([0., 0., 1.]),
};
Expand Down
9 changes: 5 additions & 4 deletions crates/fj-core/src/algorithms/bounding_volume/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::Deref;
use fj_math::Aabb;

use crate::{
geometry::{Geometry, GlobalPath},
geometry::{Geometry, GlobalPath, SurfaceGeom},
topology::Face,
};

Expand All @@ -14,16 +14,17 @@ impl super::BoundingVolume<3> for &Face {
.map(|aabb2| {
let surface = geometry.of_surface(self.surface());

match surface.u {
let SurfaceGeom::Basic { u, v } = surface;
match u {
GlobalPath::Circle(circle) => {
// This is not the most precise way to calculate the
// AABB, doing it for the whole circle, but it should
// do.

let aabb_bottom = circle.aabb();
let aabb_top = Aabb {
min: aabb_bottom.min + surface.v,
max: aabb_bottom.max + surface.v,
min: aabb_bottom.min + *v,
max: aabb_bottom.max + *v,
};

aabb_bottom.merged(&aabb_top)
Expand Down
6 changes: 3 additions & 3 deletions crates/fj-core/src/geometry/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,21 @@ impl Geometry {

self_.define_surface_inner(
self_.xy_plane.clone(),
SurfaceGeom {
SurfaceGeom::Basic {
u: GlobalPath::x_axis(),
v: Vector::unit_y(),
},
);
self_.define_surface_inner(
self_.xz_plane.clone(),
SurfaceGeom {
SurfaceGeom::Basic {
u: GlobalPath::x_axis(),
v: Vector::unit_z(),
},
);
self_.define_surface_inner(
self_.yz_plane.clone(),
SurfaceGeom {
SurfaceGeom::Basic {
u: GlobalPath::y_axis(),
v: Vector::unit_z(),
},
Expand Down
51 changes: 34 additions & 17 deletions crates/fj-core/src/geometry/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,23 @@ use super::GlobalPath;

/// The geometry that defines a surface
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct SurfaceGeom {
/// The u-axis of the surface
pub u: GlobalPath,

/// The v-axis of the surface
pub v: Vector<3>,
pub enum SurfaceGeom {
/// # Basic definition of surface geometry
///
/// ## Implementation Note
///
/// At the time of writing, this is the sole variant of `SurfaceGeom`.
/// `SurfaceGeom` simply used to be a struct, identical to this variant.
///
/// This was changed as part of a transition to a new, less basic and more
/// flexible, representation of surface geometry.
Basic {
/// The u-axis of the surface
u: GlobalPath,

/// The v-axis of the surface
v: Vector<3>,
},
}

impl SurfaceGeom {
Expand All @@ -21,7 +32,8 @@ impl SurfaceGeom {
point: impl Into<Point<2>>,
) -> Point<3> {
let point = point.into();
self.u.point_from_path_coords([point.u])
let Self::Basic { u, .. } = self;
u.point_from_path_coords([point.u])
+ self.path_to_line().vector_from_line_coords([point.v])
}

Expand All @@ -31,31 +43,36 @@ impl SurfaceGeom {
vector: impl Into<Vector<2>>,
) -> Vector<3> {
let vector = vector.into();
self.u.vector_from_path_coords([vector.u])
let Self::Basic { u, .. } = self;
u.vector_from_path_coords([vector.u])
+ self.path_to_line().vector_from_line_coords([vector.v])
}

fn path_to_line(&self) -> Line<3> {
Line::from_origin_and_direction(self.u.origin(), self.v)
let Self::Basic { u, v } = self;
Line::from_origin_and_direction(u.origin(), *v)
}

/// Project the global point into the surface
pub fn project_global_point(&self, point: impl Into<Point<3>>) -> Point<2> {
let GlobalPath::Line(line) = self.u else {
let Self::Basic { u, v } = self;

let GlobalPath::Line(line) = u else {
todo!("Projecting point into non-plane surface is not supported")
};

let plane =
Plane::from_parametric(line.origin(), line.direction(), self.v);
let plane = Plane::from_parametric(line.origin(), line.direction(), *v);
plane.project_point(point)
}

/// Transform the surface geometry
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
let u = self.u.transform(transform);
let v = transform.transform_vector(&self.v);
Self { u, v }
let Self::Basic { u, v } = self;

let u = u.transform(transform);
let v = transform.transform_vector(&v);
Self::Basic { u, v }
}
}

Expand All @@ -68,7 +85,7 @@ mod tests {

#[test]
fn point_from_surface_coords() {
let surface = SurfaceGeom {
let surface = SurfaceGeom::Basic {
u: GlobalPath::Line(Line::from_origin_and_direction(
Point::from([1., 1., 1.]),
Vector::from([0., 2., 0.]),
Expand All @@ -84,7 +101,7 @@ mod tests {

#[test]
fn vector_from_surface_coords() {
let surface = SurfaceGeom {
let surface = SurfaceGeom::Basic {
u: GlobalPath::Line(Line::from_origin_and_direction(
Point::from([1., 0., 0.]),
Vector::from([0., 2., 0.]),
Expand Down
2 changes: 1 addition & 1 deletion crates/fj-core/src/operations/build/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub trait BuildSurface {
core: &mut Core,
) -> Handle<Surface> {
Self::from_geometry(
SurfaceGeom {
SurfaceGeom::Basic {
u: u.into(),
v: v.into(),
},
Expand Down
3 changes: 2 additions & 1 deletion crates/fj-core/src/operations/sweep/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ impl SweepSurfacePath for SurfacePath {
path: impl Into<Vector<3>>,
core: &mut Core,
) -> Handle<Surface> {
match surface.u {
let SurfaceGeom::Basic { u, .. } = surface;
match u {
GlobalPath::Circle(_) => {
// Sweeping a `Curve` creates a `Surface`. The u-axis of that
// `Surface` is a `GlobalPath`, which we are computing below.
Expand Down
10 changes: 6 additions & 4 deletions crates/fj-core/src/operations/sweep/sketch.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use fj_math::{Scalar, Vector};

use crate::{
geometry::GlobalPath,
geometry::{GlobalPath, SurfaceGeom},
operations::{derive::DeriveFrom, insert::Insert, reverse::Reverse},
storage::Handle,
topology::{Face, Sketch, Solid, Surface},
Expand Down Expand Up @@ -45,17 +45,19 @@ impl SweepSketch for Sketch {
.winding(&core.layers.geometry, self.surface())
.is_ccw());

let SurfaceGeom::Basic { u, v } =
core.layers.geometry.of_surface(&surface);

let is_negative_sweep = {
let u = match core.layers.geometry.of_surface(&surface).u {
let u = match u {
GlobalPath::Circle(_) => todo!(
"Sweeping sketch from a rounded surfaces is not \
supported"
),
GlobalPath::Line(line) => line.direction(),
};
let v = core.layers.geometry.of_surface(&surface).v;

let normal = u.cross(&v);
let normal = u.cross(v);

normal.dot(&path) < Scalar::ZERO
};
Expand Down