mirror of https://github.com/hannobraun/Fornjot
Merge pull request #1340 from hannobraun/surface
Clean up surface-related code; prepare for deeper integration into partial object API
This commit is contained in:
commit
35a02544ad
|
@ -12,8 +12,8 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{
|
||||
geometry::path::{GlobalPath, SurfacePath},
|
||||
objects::{Curve, GlobalCurve},
|
||||
path::{GlobalPath, SurfacePath},
|
||||
storage::{Handle, ObjectId},
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,7 @@ fn approx_global_curve(
|
|||
// This will probably all be unified eventually, as `SurfacePath` and
|
||||
// `GlobalPath` grow APIs that are better suited to implementing this code
|
||||
// in a more abstract way.
|
||||
let points = match (curve.path(), curve.surface().u()) {
|
||||
let points = match (curve.path(), curve.surface().geometry().u) {
|
||||
(SurfacePath::Circle(_), GlobalPath::Circle(_)) => {
|
||||
todo!(
|
||||
"Approximating a circle on a curved surface not supported yet."
|
||||
|
@ -90,6 +90,7 @@ fn approx_global_curve(
|
|||
|
||||
let point_global = curve
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(point_surface);
|
||||
(point_curve, point_global)
|
||||
})
|
||||
|
@ -101,15 +102,17 @@ fn approx_global_curve(
|
|||
[curve.path().point_from_path_coords(point_curve).u]
|
||||
}));
|
||||
|
||||
let approx_u = (curve.surface().u(), range_u)
|
||||
let approx_u = (curve.surface().geometry().u, range_u)
|
||||
.approx_with_cache(tolerance, &mut ());
|
||||
|
||||
let mut points = Vec::new();
|
||||
for (u, _) in approx_u {
|
||||
let t = (u.t - line.origin().u) / line.direction().u;
|
||||
let point_surface = curve.path().point_from_path_coords([t]);
|
||||
let point_global =
|
||||
curve.surface().point_from_surface_coords(point_surface);
|
||||
let point_global = curve
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(point_surface);
|
||||
points.push((u, point_global));
|
||||
}
|
||||
|
||||
|
@ -197,11 +200,11 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint},
|
||||
builder::CurveBuilder,
|
||||
builder::{CurveBuilder, SurfaceBuilder},
|
||||
geometry::path::GlobalPath,
|
||||
insert::Insert,
|
||||
objects::{Objects, Surface},
|
||||
partial::PartialCurve,
|
||||
path::GlobalPath,
|
||||
objects::Objects,
|
||||
partial::{PartialCurve, PartialSurface},
|
||||
};
|
||||
|
||||
use super::CurveApprox;
|
||||
|
@ -210,9 +213,10 @@ mod tests {
|
|||
fn approx_line_on_flat_surface() -> anyhow::Result<()> {
|
||||
let objects = Objects::new();
|
||||
|
||||
let surface = objects
|
||||
.surfaces
|
||||
.insert(Surface::new(GlobalPath::x_axis(), [0., 0., 1.]))?;
|
||||
let surface =
|
||||
PartialSurface::from_axes(GlobalPath::x_axis(), [0., 0., 1.])
|
||||
.build(&objects)?
|
||||
.insert(&objects)?;
|
||||
let mut curve = PartialCurve {
|
||||
surface: Some(surface),
|
||||
..Default::default()
|
||||
|
@ -232,10 +236,12 @@ mod tests {
|
|||
{
|
||||
let objects = Objects::new();
|
||||
|
||||
let surface = objects.surfaces.insert(Surface::new(
|
||||
let surface = PartialSurface::from_axes(
|
||||
GlobalPath::circle_from_radius(1.),
|
||||
[0., 0., 1.],
|
||||
))?;
|
||||
)
|
||||
.build(&objects)?
|
||||
.insert(&objects)?;
|
||||
let mut curve = PartialCurve {
|
||||
surface: Some(surface),
|
||||
..Default::default()
|
||||
|
@ -255,8 +261,9 @@ mod tests {
|
|||
let objects = Objects::new();
|
||||
|
||||
let path = GlobalPath::circle_from_radius(1.);
|
||||
let surface =
|
||||
objects.surfaces.insert(Surface::new(path, [0., 0., 1.]))?;
|
||||
let surface = PartialSurface::from_axes(path, [0., 0., 1.])
|
||||
.build(&objects)?
|
||||
.insert(&objects)?;
|
||||
let mut curve = PartialCurve {
|
||||
surface: Some(surface.clone()),
|
||||
..Default::default()
|
||||
|
@ -276,7 +283,7 @@ mod tests {
|
|||
let point_surface =
|
||||
curve.path().point_from_path_coords(point_local);
|
||||
let point_global =
|
||||
surface.point_from_surface_coords(point_surface);
|
||||
surface.geometry().point_from_surface_coords(point_surface);
|
||||
ApproxPoint::new(point_surface, point_global)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -288,9 +295,10 @@ mod tests {
|
|||
fn approx_circle_on_flat_surface() -> anyhow::Result<()> {
|
||||
let objects = Objects::new();
|
||||
|
||||
let surface = objects
|
||||
.surfaces
|
||||
.insert(Surface::new(GlobalPath::x_axis(), [0., 0., 1.]))?;
|
||||
let surface =
|
||||
PartialSurface::from_axes(GlobalPath::x_axis(), [0., 0., 1.])
|
||||
.build(&objects)?
|
||||
.insert(&objects)?;
|
||||
let mut curve = PartialCurve {
|
||||
surface: Some(surface),
|
||||
..Default::default()
|
||||
|
@ -306,8 +314,10 @@ mod tests {
|
|||
.approx(tolerance)
|
||||
.into_iter()
|
||||
.map(|(_, point_surface)| {
|
||||
let point_global =
|
||||
curve.surface().point_from_surface_coords(point_surface);
|
||||
let point_global = curve
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(point_surface);
|
||||
ApproxPoint::new(point_surface, point_global)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
|
|
@ -32,7 +32,7 @@ use std::iter;
|
|||
|
||||
use fj_math::{Circle, Point, Scalar, Sign};
|
||||
|
||||
use crate::path::{GlobalPath, SurfacePath};
|
||||
use crate::geometry::path::{GlobalPath, SurfacePath};
|
||||
|
||||
use super::{Approx, Tolerance};
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use fj_math::{Point, Segment};
|
||||
|
||||
use crate::{
|
||||
geometry::path::SurfacePath,
|
||||
objects::{Curve, HalfEdge},
|
||||
path::SurfacePath,
|
||||
};
|
||||
|
||||
use super::LineSegmentIntersection;
|
||||
|
|
|
@ -4,8 +4,8 @@ use fj_math::Segment;
|
|||
|
||||
use crate::{
|
||||
algorithms::intersect::{HorizontalRayToTheRight, Intersect},
|
||||
geometry::path::SurfacePath,
|
||||
objects::HalfEdge,
|
||||
path::SurfacePath,
|
||||
storage::Handle,
|
||||
};
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ use fj_math::{Plane, Point, Scalar};
|
|||
|
||||
use crate::{
|
||||
algorithms::intersect::face_point::FacePointIntersection,
|
||||
geometry::path::GlobalPath,
|
||||
objects::{Face, HalfEdge, Vertex},
|
||||
path::GlobalPath,
|
||||
storage::Handle,
|
||||
};
|
||||
|
||||
|
@ -17,14 +17,14 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Handle<Face>) {
|
|||
fn intersect(self) -> Option<Self::Intersection> {
|
||||
let (ray, face) = self;
|
||||
|
||||
let plane = match face.surface().u() {
|
||||
let plane = match face.surface().geometry().u {
|
||||
GlobalPath::Circle(_) => todo!(
|
||||
"Casting a ray against a swept circle is not supported yet"
|
||||
),
|
||||
GlobalPath::Line(line) => Plane::from_parametric(
|
||||
line.origin(),
|
||||
line.direction(),
|
||||
face.surface().v(),
|
||||
face.surface().geometry().v,
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ use fj_interop::ext::ArrayExt;
|
|||
use fj_math::{Line, Plane, Point, Scalar};
|
||||
|
||||
use crate::{
|
||||
geometry::path::{GlobalPath, SurfacePath},
|
||||
objects::{Curve, GlobalCurve, Objects, Surface},
|
||||
path::{GlobalPath, SurfacePath},
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
@ -74,12 +74,12 @@ impl SurfaceSurfaceIntersection {
|
|||
|
||||
fn plane_from_surface(surface: &Surface) -> Plane {
|
||||
let (line, path) = {
|
||||
let line = match surface.u() {
|
||||
let line = match surface.geometry().u {
|
||||
GlobalPath::Line(line) => line,
|
||||
_ => todo!("Only plane-plane intersection is currently supported."),
|
||||
};
|
||||
|
||||
(line, surface.v())
|
||||
(line, surface.geometry().v)
|
||||
};
|
||||
|
||||
Plane::from_parametric(line.origin(), line.direction(), path)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use fj_math::{Circle, Line, Vector};
|
||||
|
||||
use crate::{
|
||||
builder::SurfaceBuilder,
|
||||
geometry::path::{GlobalPath, SurfacePath},
|
||||
insert::Insert,
|
||||
objects::{Curve, Objects, Surface},
|
||||
path::{GlobalPath, SurfacePath},
|
||||
partial::PartialSurface,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
@ -18,7 +21,7 @@ impl Sweep for Handle<Curve> {
|
|||
_: &mut SweepCache,
|
||||
objects: &Objects,
|
||||
) -> Result<Self::Swept, ValidationError> {
|
||||
match self.surface().u() {
|
||||
match self.surface().geometry().u {
|
||||
GlobalPath::Circle(_) => {
|
||||
// Sweeping a `Curve` creates a `Surface`. The u-axis of that
|
||||
// `Surface` is a `GlobalPath`, which we are computing below.
|
||||
|
@ -44,20 +47,32 @@ impl Sweep for Handle<Curve> {
|
|||
|
||||
let u = match self.path() {
|
||||
SurfacePath::Circle(circle) => {
|
||||
let center =
|
||||
self.surface().point_from_surface_coords(circle.center());
|
||||
let a = self.surface().vector_from_surface_coords(circle.a());
|
||||
let b = self.surface().vector_from_surface_coords(circle.b());
|
||||
let center = self
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(circle.center());
|
||||
let a = self
|
||||
.surface()
|
||||
.geometry()
|
||||
.vector_from_surface_coords(circle.a());
|
||||
let b = self
|
||||
.surface()
|
||||
.geometry()
|
||||
.vector_from_surface_coords(circle.b());
|
||||
|
||||
let circle = Circle::new(center, a, b);
|
||||
|
||||
GlobalPath::Circle(circle)
|
||||
}
|
||||
SurfacePath::Line(line) => {
|
||||
let origin =
|
||||
self.surface().point_from_surface_coords(line.origin());
|
||||
let direction =
|
||||
self.surface().vector_from_surface_coords(line.direction());
|
||||
let origin = self
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(line.origin());
|
||||
let direction = self
|
||||
.surface()
|
||||
.geometry()
|
||||
.vector_from_surface_coords(line.direction());
|
||||
|
||||
let line = Line::from_origin_and_direction(origin, direction);
|
||||
|
||||
|
@ -65,6 +80,9 @@ impl Sweep for Handle<Curve> {
|
|||
}
|
||||
};
|
||||
|
||||
Ok(objects.surfaces.insert(Surface::new(u, path))?)
|
||||
let surface = PartialSurface::from_axes(u, path)
|
||||
.build(objects)?
|
||||
.insert(objects)?;
|
||||
Ok(surface)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ use iter_fixed::IntoIteratorFixed;
|
|||
|
||||
use crate::{
|
||||
algorithms::{reverse::Reverse, transform::TransformObject},
|
||||
geometry::path::SurfacePath,
|
||||
insert::Insert,
|
||||
objects::{
|
||||
Curve, Cycle, Face, GlobalEdge, HalfEdge, Objects, SurfaceVertex,
|
||||
Vertex,
|
||||
},
|
||||
partial::HasPartial,
|
||||
path::SurfacePath,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
|
|
@ -2,8 +2,8 @@ use fj_math::{Scalar, Vector};
|
|||
|
||||
use crate::{
|
||||
algorithms::{reverse::Reverse, transform::TransformObject},
|
||||
geometry::path::GlobalPath,
|
||||
objects::{Face, Objects, Shell},
|
||||
path::GlobalPath,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
@ -24,14 +24,14 @@ impl Sweep for Handle<Face> {
|
|||
let mut faces = Vec::new();
|
||||
|
||||
let is_negative_sweep = {
|
||||
let u = match self.surface().u() {
|
||||
let u = match self.surface().geometry().u {
|
||||
GlobalPath::Circle(_) => todo!(
|
||||
"Sweeping from faces defined in round surfaces is not \
|
||||
supported"
|
||||
),
|
||||
GlobalPath::Line(line) => line.direction(),
|
||||
};
|
||||
let v = self.surface().v();
|
||||
let v = self.surface().geometry().v;
|
||||
|
||||
let normal = u.cross(&v);
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@ use fj_math::{Line, Point, Scalar, Vector};
|
|||
use try_insert_ext::EntryInsertExt;
|
||||
|
||||
use crate::{
|
||||
geometry::path::SurfacePath,
|
||||
objects::{
|
||||
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects,
|
||||
Surface, SurfaceVertex, Vertex,
|
||||
},
|
||||
path::SurfacePath,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
@ -56,7 +56,7 @@ impl Sweep for (Handle<Vertex>, Handle<Surface>) {
|
|||
// not, we have no way of knowing the surface coordinates of the input
|
||||
// `Vertex` on the `Surface`, and we're going to need to do that further
|
||||
// down. There's no way to check for that, unfortunately.
|
||||
assert_eq!(path, surface.v());
|
||||
assert_eq!(path, surface.geometry().v);
|
||||
|
||||
// With that out of the way, let's start by creating the `GlobalEdge`,
|
||||
// as that is the most straight-forward part of this operations, and
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
use fj_math::Transform;
|
||||
|
||||
use crate::{
|
||||
objects::{Objects, Surface},
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
geometry::surface::SurfaceGeometry, objects::Objects,
|
||||
partial::PartialSurface, validate::ValidationError,
|
||||
};
|
||||
|
||||
use super::TransformObject;
|
||||
|
||||
impl TransformObject for Handle<Surface> {
|
||||
impl TransformObject for PartialSurface {
|
||||
fn transform(
|
||||
self,
|
||||
transform: &Transform,
|
||||
objects: &Objects,
|
||||
_: &Objects,
|
||||
) -> Result<Self, ValidationError> {
|
||||
Ok(objects.surfaces.insert(Surface::new(
|
||||
self.u().transform(transform),
|
||||
transform.transform_vector(&self.v()),
|
||||
))?)
|
||||
let geometry = self.geometry.map(|geometry| {
|
||||
let u = geometry.u.transform(transform);
|
||||
let v = transform.transform_vector(&geometry.v);
|
||||
|
||||
SurfaceGeometry { u, v }
|
||||
});
|
||||
|
||||
Ok(Self { geometry })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,12 +148,12 @@ mod tests {
|
|||
|
||||
let triangles = triangulate(face)?;
|
||||
|
||||
let a = surface.point_from_surface_coords(a);
|
||||
let b = surface.point_from_surface_coords(b);
|
||||
let e = surface.point_from_surface_coords(e);
|
||||
let f = surface.point_from_surface_coords(f);
|
||||
let g = surface.point_from_surface_coords(g);
|
||||
let h = surface.point_from_surface_coords(h);
|
||||
let a = surface.geometry().point_from_surface_coords(a);
|
||||
let b = surface.geometry().point_from_surface_coords(b);
|
||||
let e = surface.geometry().point_from_surface_coords(e);
|
||||
let f = surface.geometry().point_from_surface_coords(f);
|
||||
let g = surface.geometry().point_from_surface_coords(g);
|
||||
let h = surface.geometry().point_from_surface_coords(h);
|
||||
|
||||
// Let's test that some correct triangles are present. We don't need to
|
||||
// test them all.
|
||||
|
@ -209,11 +209,11 @@ mod tests {
|
|||
|
||||
let triangles = triangulate(face)?;
|
||||
|
||||
let a3 = surface.point_from_surface_coords(a);
|
||||
let b3 = surface.point_from_surface_coords(b);
|
||||
let c3 = surface.point_from_surface_coords(c);
|
||||
let d3 = surface.point_from_surface_coords(d);
|
||||
let e3 = surface.point_from_surface_coords(e);
|
||||
let a3 = surface.geometry().point_from_surface_coords(a);
|
||||
let b3 = surface.geometry().point_from_surface_coords(b);
|
||||
let c3 = surface.geometry().point_from_surface_coords(c);
|
||||
let d3 = surface.geometry().point_from_surface_coords(d);
|
||||
let e3 = surface.geometry().point_from_surface_coords(e);
|
||||
|
||||
assert!(triangles.contains_triangle([a3, b3, d3]));
|
||||
assert!(triangles.contains_triangle([b3, c3, d3]));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use fj_math::{Point, Scalar, Vector};
|
||||
|
||||
use crate::{partial::PartialCurve, path::SurfacePath};
|
||||
use crate::{geometry::path::SurfacePath, partial::PartialCurve};
|
||||
|
||||
/// Builder API for [`PartialCurve`]
|
||||
pub trait CurveBuilder {
|
||||
|
|
|
@ -5,8 +5,9 @@ use crate::{
|
|||
insert::Insert,
|
||||
objects::{Curve, Objects, Surface, Vertex, VerticesInNormalizedOrder},
|
||||
partial::{
|
||||
MaybePartial, PartialCurve, PartialGlobalEdge, PartialGlobalVertex,
|
||||
PartialHalfEdge, PartialSurfaceVertex, PartialVertex,
|
||||
MaybePartial, MergeWith, PartialCurve, PartialGlobalEdge,
|
||||
PartialGlobalVertex, PartialHalfEdge, PartialSurfaceVertex,
|
||||
PartialVertex,
|
||||
},
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
|
@ -135,8 +136,8 @@ impl HalfEdgeBuilder for PartialHalfEdge {
|
|||
let surface = self
|
||||
.curve()
|
||||
.surface()
|
||||
.or_else(|| from_surface.surface())
|
||||
.or_else(|| to_surface.surface())
|
||||
.merge_with(from_surface.surface())
|
||||
.merge_with(to_surface.surface())
|
||||
.expect("Can't infer line segment without a surface");
|
||||
let points = [&from_surface, &to_surface].map(|vertex| {
|
||||
vertex
|
||||
|
|
|
@ -12,6 +12,7 @@ mod curve;
|
|||
mod cycle;
|
||||
mod edge;
|
||||
mod face;
|
||||
mod surface;
|
||||
mod vertex;
|
||||
|
||||
pub use self::{
|
||||
|
@ -22,5 +23,6 @@ pub use self::{
|
|||
shell::ShellBuilder,
|
||||
sketch::SketchBuilder,
|
||||
solid::SolidBuilder,
|
||||
surface::SurfaceBuilder,
|
||||
vertex::{GlobalVertexBuilder, SurfaceVertexBuilder, VertexBuilder},
|
||||
};
|
||||
|
|
|
@ -6,10 +6,13 @@ use iter_fixed::IntoIteratorFixed;
|
|||
|
||||
use crate::{
|
||||
algorithms::transform::TransformObject,
|
||||
builder::{FaceBuilder, HalfEdgeBuilder},
|
||||
builder::{FaceBuilder, HalfEdgeBuilder, SurfaceBuilder},
|
||||
insert::Insert,
|
||||
objects::{Cycle, Face, FaceSet, HalfEdge, Objects, Shell, Surface},
|
||||
partial::{HasPartial, PartialCurve, PartialSurfaceVertex, PartialVertex},
|
||||
objects::{Cycle, Face, FaceSet, HalfEdge, Objects, Shell},
|
||||
partial::{
|
||||
HasPartial, PartialCurve, PartialSurface, PartialSurfaceVertex,
|
||||
PartialVertex,
|
||||
},
|
||||
storage::Handle,
|
||||
};
|
||||
|
||||
|
@ -78,9 +81,10 @@ impl<'a> ShellBuilder<'a> {
|
|||
.map(|vertex| vertex.global_form().position());
|
||||
let c = a + [Z, Z, edge_length];
|
||||
|
||||
self.objects
|
||||
.surfaces
|
||||
.insert(Surface::plane_from_points([a, b, c]))
|
||||
PartialSurface::plane_from_points([a, b, c])
|
||||
.build(self.objects)
|
||||
.unwrap()
|
||||
.insert(self.objects)
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
use fj_math::{Line, Point, Vector};
|
||||
|
||||
use crate::{
|
||||
geometry::{path::GlobalPath, surface::SurfaceGeometry},
|
||||
partial::PartialSurface,
|
||||
};
|
||||
|
||||
/// Builder API for [`PartialSurface`]
|
||||
pub trait SurfaceBuilder {
|
||||
/// Build a surface from its two axes
|
||||
fn from_axes(u: GlobalPath, v: impl Into<Vector<3>>) -> Self;
|
||||
|
||||
/// Construct a plane from 3 points
|
||||
fn plane_from_points(points: [impl Into<Point<3>>; 3]) -> Self;
|
||||
}
|
||||
|
||||
impl SurfaceBuilder for PartialSurface {
|
||||
fn from_axes(u: GlobalPath, v: impl Into<Vector<3>>) -> Self {
|
||||
let v = v.into();
|
||||
|
||||
Self {
|
||||
geometry: Some(SurfaceGeometry { u, v }),
|
||||
}
|
||||
}
|
||||
|
||||
fn plane_from_points(points: [impl Into<Point<3>>; 3]) -> Self {
|
||||
let [a, b, c] = points.map(Into::into);
|
||||
|
||||
let u = GlobalPath::Line(Line::from_points([a, b]));
|
||||
let v = c - a;
|
||||
|
||||
Self {
|
||||
geometry: Some(SurfaceGeometry { u, v }),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
objects::{Curve, GlobalVertex, Surface},
|
||||
geometry::surface::SurfaceGeometry,
|
||||
objects::{Curve, GlobalVertex},
|
||||
partial::{
|
||||
HasPartial, MaybePartial, PartialGlobalVertex, PartialSurfaceVertex,
|
||||
PartialVertex,
|
||||
|
@ -44,7 +45,7 @@ pub trait GlobalVertexBuilder {
|
|||
|
||||
/// Update partial global vertex from the given surface and position on it
|
||||
fn from_surface_and_position(
|
||||
surface: &Surface,
|
||||
surface: &SurfaceGeometry,
|
||||
position: impl Into<Point<2>>,
|
||||
) -> Self;
|
||||
}
|
||||
|
@ -59,9 +60,12 @@ impl GlobalVertexBuilder for PartialGlobalVertex {
|
|||
let path = curve.path.expect(
|
||||
"Need path to create `GlobalVertex` from curve and position",
|
||||
);
|
||||
let surface = curve.surface.expect(
|
||||
"Need surface to create `GlobalVertex` from curve and position",
|
||||
);
|
||||
let surface = curve
|
||||
.surface
|
||||
.expect(
|
||||
"Need surface to create `GlobalVertex` from curve and position",
|
||||
)
|
||||
.geometry();
|
||||
|
||||
let position_surface = path.point_from_path_coords(position);
|
||||
|
||||
|
@ -69,7 +73,7 @@ impl GlobalVertexBuilder for PartialGlobalVertex {
|
|||
}
|
||||
|
||||
fn from_surface_and_position(
|
||||
surface: &Surface,
|
||||
surface: &SurfaceGeometry,
|
||||
position: impl Into<Point<2>>,
|
||||
) -> Self {
|
||||
PartialGlobalVertex {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
//! Types that are tied to objects, but aren't objects themselves
|
||||
|
||||
pub mod path;
|
||||
pub mod surface;
|
|
@ -0,0 +1,81 @@
|
|||
//! The geometry that defines a surface
|
||||
|
||||
use fj_math::{Line, Point, Vector};
|
||||
|
||||
use super::path::GlobalPath;
|
||||
|
||||
/// The geometry that defines a surface
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct SurfaceGeometry {
|
||||
/// The u-axis of the surface
|
||||
pub u: GlobalPath,
|
||||
|
||||
/// The v-axis of the surface
|
||||
pub v: Vector<3>,
|
||||
}
|
||||
|
||||
impl SurfaceGeometry {
|
||||
/// Convert a point in surface coordinates to model coordinates
|
||||
pub fn point_from_surface_coords(
|
||||
&self,
|
||||
point: impl Into<Point<2>>,
|
||||
) -> Point<3> {
|
||||
let point = point.into();
|
||||
self.u.point_from_path_coords([point.u])
|
||||
+ self.path_to_line().vector_from_line_coords([point.v])
|
||||
}
|
||||
|
||||
/// Convert a vector in surface coordinates to model coordinates
|
||||
pub fn vector_from_surface_coords(
|
||||
&self,
|
||||
vector: impl Into<Vector<2>>,
|
||||
) -> Vector<3> {
|
||||
let vector = vector.into();
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fj_math::{Line, Point, Vector};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::geometry::{path::GlobalPath, surface::SurfaceGeometry};
|
||||
|
||||
#[test]
|
||||
fn point_from_surface_coords() {
|
||||
let surface = SurfaceGeometry {
|
||||
u: GlobalPath::Line(Line::from_origin_and_direction(
|
||||
Point::from([1., 1., 1.]),
|
||||
Vector::from([0., 2., 0.]),
|
||||
)),
|
||||
v: Vector::from([0., 0., 2.]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
surface.point_from_surface_coords([2., 4.]),
|
||||
Point::from([1., 5., 9.]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector_from_surface_coords() {
|
||||
let surface = SurfaceGeometry {
|
||||
u: GlobalPath::Line(Line::from_origin_and_direction(
|
||||
Point::from([1., 0., 0.]),
|
||||
Vector::from([0., 2., 0.]),
|
||||
)),
|
||||
v: Vector::from([0., 0., 2.]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
surface.vector_from_surface_coords([2., 4.]),
|
||||
Vector::from([0., 4., 8.]),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -89,10 +89,10 @@
|
|||
|
||||
pub mod algorithms;
|
||||
pub mod builder;
|
||||
pub mod geometry;
|
||||
pub mod insert;
|
||||
pub mod iter;
|
||||
pub mod objects;
|
||||
pub mod partial;
|
||||
pub mod path;
|
||||
pub mod storage;
|
||||
pub mod validate;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
path::SurfacePath,
|
||||
geometry::path::SurfacePath,
|
||||
storage::{Handle, HandleWrapper},
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::slice;
|
|||
use fj_interop::ext::SliceExt;
|
||||
use fj_math::{Scalar, Winding};
|
||||
|
||||
use crate::{path::SurfacePath, storage::Handle};
|
||||
use crate::{geometry::path::SurfacePath, storage::Handle};
|
||||
|
||||
use super::{HalfEdge, Surface};
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ use std::convert::Infallible;
|
|||
use fj_math::Vector;
|
||||
|
||||
use crate::{
|
||||
path::GlobalPath,
|
||||
geometry::{path::GlobalPath, surface::SurfaceGeometry},
|
||||
storage::{Handle, Store},
|
||||
validate::{
|
||||
CycleValidationError, FaceValidationError, HalfEdgeValidationError,
|
||||
|
@ -380,12 +380,18 @@ impl Default for Surfaces {
|
|||
fn default() -> Self {
|
||||
let store = Store::new();
|
||||
|
||||
let xy_plane =
|
||||
store.insert(Surface::new(GlobalPath::x_axis(), Vector::unit_y()));
|
||||
let xz_plane =
|
||||
store.insert(Surface::new(GlobalPath::x_axis(), Vector::unit_z()));
|
||||
let yz_plane =
|
||||
store.insert(Surface::new(GlobalPath::y_axis(), Vector::unit_z()));
|
||||
let xy_plane = store.insert(Surface::new(SurfaceGeometry {
|
||||
u: GlobalPath::x_axis(),
|
||||
v: Vector::unit_y(),
|
||||
}));
|
||||
let xz_plane = store.insert(Surface::new(SurfaceGeometry {
|
||||
u: GlobalPath::x_axis(),
|
||||
v: Vector::unit_z(),
|
||||
}));
|
||||
let yz_plane = store.insert(Surface::new(SurfaceGeometry {
|
||||
u: GlobalPath::y_axis(),
|
||||
v: Vector::unit_z(),
|
||||
}));
|
||||
|
||||
Self {
|
||||
store,
|
||||
|
|
|
@ -1,104 +1,19 @@
|
|||
use fj_math::{Line, Point, Vector};
|
||||
|
||||
use crate::path::GlobalPath;
|
||||
use crate::geometry::surface::SurfaceGeometry;
|
||||
|
||||
/// A two-dimensional shape
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct Surface {
|
||||
u: GlobalPath,
|
||||
v: Vector<3>,
|
||||
geometry: SurfaceGeometry,
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
/// Construct a `Surface` from two paths that define its coordinate system
|
||||
pub fn new(u: GlobalPath, v: impl Into<Vector<3>>) -> Self {
|
||||
let v = v.into();
|
||||
Self { u, v }
|
||||
pub fn new(geometry: SurfaceGeometry) -> Self {
|
||||
Self { geometry }
|
||||
}
|
||||
|
||||
/// Construct a plane from 3 points
|
||||
pub fn plane_from_points(points: [impl Into<Point<3>>; 3]) -> Self {
|
||||
let [a, b, c] = points.map(Into::into);
|
||||
|
||||
let u = GlobalPath::Line(Line::from_points([a, b]));
|
||||
let v = c - a;
|
||||
|
||||
Self { u, v }
|
||||
}
|
||||
|
||||
/// Access the path that defines the u-coordinate of this surface
|
||||
pub fn u(&self) -> GlobalPath {
|
||||
self.u
|
||||
}
|
||||
|
||||
/// Access the path that defines the v-coordinate of this surface
|
||||
pub fn v(&self) -> Vector<3> {
|
||||
self.v
|
||||
}
|
||||
|
||||
/// Convert a point in surface coordinates to model coordinates
|
||||
pub fn point_from_surface_coords(
|
||||
&self,
|
||||
point: impl Into<Point<2>>,
|
||||
) -> Point<3> {
|
||||
let point = point.into();
|
||||
self.u.point_from_path_coords([point.u])
|
||||
+ self.path_to_line().vector_from_line_coords([point.v])
|
||||
}
|
||||
|
||||
/// Convert a vector in surface coordinates to model coordinates
|
||||
pub fn vector_from_surface_coords(
|
||||
&self,
|
||||
vector: impl Into<Vector<2>>,
|
||||
) -> Vector<3> {
|
||||
let vector = vector.into();
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fj_math::{Line, Point, Vector};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::path::GlobalPath;
|
||||
|
||||
use super::Surface;
|
||||
|
||||
#[test]
|
||||
fn point_from_surface_coords() {
|
||||
let swept = Surface {
|
||||
u: GlobalPath::Line(Line::from_origin_and_direction(
|
||||
Point::from([1., 1., 1.]),
|
||||
Vector::from([0., 2., 0.]),
|
||||
)),
|
||||
v: Vector::from([0., 0., 2.]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
swept.point_from_surface_coords([2., 4.]),
|
||||
Point::from([1., 5., 9.]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector_from_surface_coords() {
|
||||
let swept = Surface {
|
||||
u: GlobalPath::Line(Line::from_origin_and_direction(
|
||||
Point::from([1., 0., 0.]),
|
||||
Vector::from([0., 2., 0.]),
|
||||
)),
|
||||
v: Vector::from([0., 0., 2.]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
swept.vector_from_surface_coords([2., 4.]),
|
||||
Vector::from([0., 4., 8.]),
|
||||
);
|
||||
/// Access the surface's geometry
|
||||
pub fn geometry(&self) -> SurfaceGeometry {
|
||||
self.geometry
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
geometry::{path::SurfacePath, surface::SurfaceGeometry},
|
||||
insert::Insert,
|
||||
objects::{
|
||||
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects,
|
||||
Surface, SurfaceVertex, Vertex,
|
||||
},
|
||||
path::SurfacePath,
|
||||
storage::Handle,
|
||||
validate::{Validate, ValidationError},
|
||||
};
|
||||
|
@ -212,6 +212,16 @@ impl MaybePartial<HalfEdge> {
|
|||
}
|
||||
}
|
||||
|
||||
impl MaybePartial<Surface> {
|
||||
/// Access the geometry
|
||||
pub fn geometry(&self) -> Option<SurfaceGeometry> {
|
||||
match self {
|
||||
Self::Full(full) => Some(full.geometry()),
|
||||
Self::Partial(partial) => partial.geometry,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybePartial<SurfaceVertex> {
|
||||
/// Access the position
|
||||
pub fn position(&self) -> Option<Point<2>> {
|
||||
|
|
|
@ -47,6 +47,7 @@ pub use self::{
|
|||
cycle::PartialCycle,
|
||||
edge::{PartialGlobalEdge, PartialHalfEdge},
|
||||
face::PartialFace,
|
||||
surface::PartialSurface,
|
||||
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
|
||||
},
|
||||
traits::{HasPartial, Partial},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
geometry::path::SurfacePath,
|
||||
objects::{Curve, GlobalCurve, Objects, Surface},
|
||||
partial::{MaybePartial, MergeWith, Mergeable},
|
||||
path::SurfacePath,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
|
|
@ -2,17 +2,18 @@ pub mod curve;
|
|||
pub mod cycle;
|
||||
pub mod edge;
|
||||
pub mod face;
|
||||
pub mod surface;
|
||||
pub mod vertex;
|
||||
|
||||
use crate::objects::{
|
||||
Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge,
|
||||
Objects, SurfaceVertex, Vertex,
|
||||
Objects, Surface, SurfaceVertex, Vertex,
|
||||
};
|
||||
|
||||
use super::{
|
||||
HasPartial, MaybePartial, Partial, PartialCurve, PartialCycle, PartialFace,
|
||||
PartialGlobalCurve, PartialGlobalEdge, PartialGlobalVertex,
|
||||
PartialHalfEdge, PartialSurfaceVertex, PartialVertex,
|
||||
PartialHalfEdge, PartialSurface, PartialSurfaceVertex, PartialVertex,
|
||||
};
|
||||
|
||||
macro_rules! impl_traits {
|
||||
|
@ -52,6 +53,7 @@ impl_traits!(
|
|||
GlobalEdge, PartialGlobalEdge;
|
||||
GlobalVertex, PartialGlobalVertex;
|
||||
HalfEdge, PartialHalfEdge;
|
||||
Surface, PartialSurface;
|
||||
SurfaceVertex, PartialSurfaceVertex;
|
||||
Vertex, PartialVertex;
|
||||
);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
use crate::{
|
||||
geometry::surface::SurfaceGeometry,
|
||||
objects::{Objects, Surface},
|
||||
partial::MergeWith,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
||||
/// A partial [`Surface`]
|
||||
///
|
||||
/// See [`crate::partial`] for more information
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PartialSurface {
|
||||
/// The geometry that defines the [`Surface`]
|
||||
pub geometry: Option<SurfaceGeometry>,
|
||||
}
|
||||
|
||||
impl PartialSurface {
|
||||
/// Build a full [`Surface`] from the partial surface
|
||||
pub fn build(self, _: &Objects) -> Result<Surface, ValidationError> {
|
||||
let geometry = self
|
||||
.geometry
|
||||
.expect("Can't build `Surface` without geometry");
|
||||
|
||||
Ok(Surface::new(geometry))
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeWith for PartialSurface {
|
||||
fn merge_with(self, other: impl Into<Self>) -> Self {
|
||||
let other = other.into();
|
||||
|
||||
Self {
|
||||
geometry: self.geometry.merge_with(other.geometry),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Surface> for PartialSurface {
|
||||
fn from(surface: &Surface) -> Self {
|
||||
Self {
|
||||
geometry: Some(surface.geometry()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ impl From<&Vertex> for PartialVertex {
|
|||
/// A partial [`SurfaceVertex`]
|
||||
///
|
||||
/// See [`crate::partial`] for more information.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PartialSurfaceVertex {
|
||||
/// The position of the [`SurfaceVertex`]
|
||||
pub position: Option<Point<2>>,
|
||||
|
@ -108,7 +108,8 @@ impl PartialSurfaceVertex {
|
|||
let global_form = self
|
||||
.global_form
|
||||
.merge_with(PartialGlobalVertex::from_surface_and_position(
|
||||
&surface, position,
|
||||
&surface.geometry(),
|
||||
position,
|
||||
))
|
||||
.into_full(objects)?;
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ impl SurfaceVertexValidationError {
|
|||
) -> Result<(), Self> {
|
||||
let surface_position_as_global = surface_vertex
|
||||
.surface()
|
||||
.geometry()
|
||||
.point_from_surface_coords(surface_vertex.position());
|
||||
let global_position = surface_vertex.global_form().position();
|
||||
|
||||
|
|
Loading…
Reference in New Issue