Merge pull request #1596 from hannobraun/surface

Move reference to `Surface` from `Curve` to `HalfEdge`
This commit is contained in:
Hanno Braun 2023-02-17 12:29:49 +01:00 committed by GitHub
commit abef26ea52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 117 additions and 159 deletions

View File

@ -13,13 +13,13 @@ use std::collections::BTreeMap;
use crate::{ use crate::{
geometry::path::{GlobalPath, SurfacePath}, geometry::path::{GlobalPath, SurfacePath},
objects::{Curve, GlobalCurve}, objects::{Curve, GlobalCurve, Surface},
storage::{Handle, ObjectId}, storage::{Handle, ObjectId},
}; };
use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance}; use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance};
impl Approx for (&Handle<Curve>, RangeOnPath) { impl Approx for (&Handle<Curve>, &Surface, RangeOnPath) {
type Approximation = CurveApprox; type Approximation = CurveApprox;
type Cache = CurveCache; type Cache = CurveCache;
@ -28,13 +28,14 @@ impl Approx for (&Handle<Curve>, RangeOnPath) {
tolerance: impl Into<Tolerance>, tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache, cache: &mut Self::Cache,
) -> Self::Approximation { ) -> Self::Approximation {
let (curve, range) = self; let (curve, surface, range) = self;
let global_curve = curve.global_form().clone(); let global_curve = curve.global_form().clone();
let global_curve_approx = match cache.get(global_curve.clone(), range) { let global_curve_approx = match cache.get(global_curve.clone(), range) {
Some(approx) => approx, Some(approx) => approx,
None => { None => {
let approx = approx_global_curve(curve, range, tolerance); let approx =
approx_global_curve(curve, surface, range, tolerance);
cache.insert(global_curve, range, approx) cache.insert(global_curve, range, approx)
} }
}; };
@ -53,6 +54,7 @@ impl Approx for (&Handle<Curve>, RangeOnPath) {
fn approx_global_curve( fn approx_global_curve(
curve: &Curve, curve: &Curve,
surface: &Surface,
range: RangeOnPath, range: RangeOnPath,
tolerance: impl Into<Tolerance>, tolerance: impl Into<Tolerance>,
) -> GlobalCurveApprox { ) -> GlobalCurveApprox {
@ -62,7 +64,7 @@ fn approx_global_curve(
// This will probably all be unified eventually, as `SurfacePath` and // This will probably all be unified eventually, as `SurfacePath` and
// `GlobalPath` grow APIs that are better suited to implementing this code // `GlobalPath` grow APIs that are better suited to implementing this code
// in a more abstract way. // in a more abstract way.
let points = match (curve.path(), curve.surface().geometry().u) { let points = match (curve.path(), surface.geometry().u) {
(SurfacePath::Circle(_), GlobalPath::Circle(_)) => { (SurfacePath::Circle(_), GlobalPath::Circle(_)) => {
todo!( todo!(
"Approximating a circle on a curved surface not supported yet." "Approximating a circle on a curved surface not supported yet."
@ -88,8 +90,7 @@ fn approx_global_curve(
// surface point available, so it needs to be computed // surface point available, so it needs to be computed
// later anyway, in the general case. // later anyway, in the general case.
let point_global = curve let point_global = surface
.surface()
.geometry() .geometry()
.point_from_surface_coords(point_surface); .point_from_surface_coords(point_surface);
(point_curve, point_global) (point_curve, point_global)
@ -102,17 +103,15 @@ fn approx_global_curve(
[curve.path().point_from_path_coords(point_curve).u] [curve.path().point_from_path_coords(point_curve).u]
})); }));
let approx_u = (curve.surface().geometry().u, range_u) let approx_u = (surface.geometry().u, range_u)
.approx_with_cache(tolerance, &mut ()); .approx_with_cache(tolerance, &mut ());
let mut points = Vec::new(); let mut points = Vec::new();
for (u, _) in approx_u { for (u, _) in approx_u {
let t = (u.t - line.origin().u) / line.direction().u; let t = (u.t - line.origin().u) / line.direction().u;
let point_surface = curve.path().point_from_path_coords([t]); let point_surface = curve.path().point_from_path_coords([t]);
let point_global = curve let point_global =
.surface() surface.geometry().point_from_surface_coords(point_surface);
.geometry()
.point_from_surface_coords(point_surface);
points.push((u, point_global)); points.push((u, point_global));
} }
@ -211,7 +210,7 @@ impl GlobalCurveApprox {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::f64::consts::TAU; use std::{f64::consts::TAU, ops::Deref};
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
@ -220,7 +219,7 @@ mod tests {
builder::{CurveBuilder, SurfaceBuilder}, builder::{CurveBuilder, SurfaceBuilder},
geometry::path::GlobalPath, geometry::path::GlobalPath,
insert::Insert, insert::Insert,
partial::{Partial, PartialCurve, PartialObject, PartialSurface}, partial::{PartialCurve, PartialObject, PartialSurface},
services::Services, services::Services,
}; };
@ -231,17 +230,14 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = services.objects.surfaces.xz_plane(); let surface = services.objects.surfaces.xz_plane();
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: Partial::from(surface),
..Default::default()
};
curve.update_as_line_from_points([[1., 1.], [2., 1.]]); curve.update_as_line_from_points([[1., 1.], [2., 1.]]);
let curve = curve let curve = curve
.build(&mut services.objects) .build(&mut services.objects)
.insert(&mut services.objects); .insert(&mut services.objects);
let range = RangeOnPath::from([[0.], [1.]]); let range = RangeOnPath::from([[0.], [1.]]);
let approx = (&curve, range).approx(1.); let approx = (&curve, surface.deref(), range).approx(1.);
assert_eq!(approx, CurveApprox::empty()); assert_eq!(approx, CurveApprox::empty());
} }
@ -256,17 +252,14 @@ mod tests {
) )
.build(&mut services.objects) .build(&mut services.objects)
.insert(&mut services.objects); .insert(&mut services.objects);
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: Partial::from(surface),
..Default::default()
};
curve.update_as_line_from_points([[1., 1.], [1., 2.]]); curve.update_as_line_from_points([[1., 1.], [1., 2.]]);
let curve = curve let curve = curve
.build(&mut services.objects) .build(&mut services.objects)
.insert(&mut services.objects); .insert(&mut services.objects);
let range = RangeOnPath::from([[0.], [1.]]); let range = RangeOnPath::from([[0.], [1.]]);
let approx = (&curve, range).approx(1.); let approx = (&curve, surface.deref(), range).approx(1.);
assert_eq!(approx, CurveApprox::empty()); assert_eq!(approx, CurveApprox::empty());
} }
@ -279,10 +272,7 @@ mod tests {
let surface = PartialSurface::from_axes(path, [0., 0., 1.]) let surface = PartialSurface::from_axes(path, [0., 0., 1.])
.build(&mut services.objects) .build(&mut services.objects)
.insert(&mut services.objects); .insert(&mut services.objects);
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: Partial::from(surface.clone()),
..Default::default()
};
curve.update_as_line_from_points([[0., 1.], [1., 1.]]); curve.update_as_line_from_points([[0., 1.], [1., 1.]]);
let curve = curve let curve = curve
.build(&mut services.objects) .build(&mut services.objects)
@ -291,7 +281,7 @@ mod tests {
let range = RangeOnPath::from([[0.], [TAU]]); let range = RangeOnPath::from([[0.], [TAU]]);
let tolerance = 1.; let tolerance = 1.;
let approx = (&curve, range).approx(tolerance); let approx = (&curve, surface.deref(), range).approx(tolerance);
let expected_approx = (path, range) let expected_approx = (path, range)
.approx(tolerance) .approx(tolerance)
@ -312,10 +302,7 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = services.objects.surfaces.xz_plane(); let surface = services.objects.surfaces.xz_plane();
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: Partial::from(surface),
..Default::default()
};
curve.update_as_circle_from_radius(1.); curve.update_as_circle_from_radius(1.);
let curve = curve let curve = curve
.build(&mut services.objects) .build(&mut services.objects)
@ -323,16 +310,14 @@ mod tests {
let range = RangeOnPath::from([[0.], [TAU]]); let range = RangeOnPath::from([[0.], [TAU]]);
let tolerance = 1.; let tolerance = 1.;
let approx = (&curve, range).approx(tolerance); let approx = (&curve, surface.deref(), range).approx(tolerance);
let expected_approx = (curve.path(), range) let expected_approx = (curve.path(), range)
.approx(tolerance) .approx(tolerance)
.into_iter() .into_iter()
.map(|(_, point_surface)| { .map(|(_, point_surface)| {
let point_global = curve let point_global =
.surface() surface.geometry().point_from_surface_coords(point_surface);
.geometry()
.point_from_surface_coords(point_surface);
ApproxPoint::new(point_surface, point_global) ApproxPoint::new(point_surface, point_global)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -5,6 +5,8 @@
//! approximations are usually used to build cycle approximations, and this way, //! approximations are usually used to build cycle approximations, and this way,
//! the caller doesn't have to call with duplicate vertices. //! the caller doesn't have to call with duplicate vertices.
use std::ops::Deref;
use crate::{objects::HalfEdge, storage::Handle}; use crate::{objects::HalfEdge, storage::Handle};
use super::{ use super::{
@ -30,8 +32,8 @@ impl Approx for &Handle<HalfEdge> {
self.start_vertex().global_form().position(), self.start_vertex().global_form().position(),
) )
.with_source((self.clone(), self.boundary()[0])); .with_source((self.clone(), self.boundary()[0]));
let curve_approx = let curve_approx = (self.curve(), self.surface().deref(), range)
(self.curve(), range).approx_with_cache(tolerance, cache); .approx_with_cache(tolerance, cache);
HalfEdgeApprox { HalfEdgeApprox {
first, first,

View File

@ -87,10 +87,7 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = Partial::from(services.objects.surfaces.xy_plane()); let surface = Partial::from(services.objects.surfaces.xy_plane());
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: surface.clone(),
..Default::default()
};
curve.update_as_u_axis(); curve.update_as_u_axis();
let curve = curve.build(&mut services.objects); let curve = curve.build(&mut services.objects);
let half_edge = { let half_edge = {
@ -118,10 +115,7 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = Partial::from(services.objects.surfaces.xy_plane()); let surface = Partial::from(services.objects.surfaces.xy_plane());
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: surface.clone(),
..Default::default()
};
curve.update_as_u_axis(); curve.update_as_u_axis();
let curve = curve.build(&mut services.objects); let curve = curve.build(&mut services.objects);
let half_edge = { let half_edge = {
@ -149,10 +143,7 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = Partial::from(services.objects.surfaces.xy_plane()); let surface = Partial::from(services.objects.surfaces.xy_plane());
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: surface.clone(),
..Default::default()
};
curve.update_as_u_axis(); curve.update_as_u_axis();
let curve = curve.build(&mut services.objects); let curve = curve.build(&mut services.objects);
let half_edge = { let half_edge = {
@ -175,10 +166,7 @@ mod tests {
let mut services = Services::new(); let mut services = Services::new();
let surface = Partial::from(services.objects.surfaces.xy_plane()); let surface = Partial::from(services.objects.surfaces.xy_plane());
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: surface.clone(),
..Default::default()
};
curve.update_as_u_axis(); curve.update_as_u_axis();
let curve = curve.build(&mut services.objects); let curve = curve.build(&mut services.objects);
let half_edge = { let half_edge = {

View File

@ -163,10 +163,7 @@ mod tests {
let surface = Partial::from(services.objects.surfaces.xy_plane()); let surface = Partial::from(services.objects.surfaces.xy_plane());
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: surface.clone(),
..Default::default()
};
curve.update_as_line_from_points([[-3., 0.], [-2., 0.]]); curve.update_as_line_from_points([[-3., 0.], [-2., 0.]]);
let curve = curve.build(&mut services.objects); let curve = curve.build(&mut services.objects);

View File

@ -132,11 +132,8 @@ mod tests {
let intersection = let intersection =
FaceFaceIntersection::compute([&a, &b], &mut services.objects); FaceFaceIntersection::compute([&a, &b], &mut services.objects);
let expected_curves = surfaces.map(|surface| { let expected_curves = surfaces.map(|_| {
let mut curve = PartialCurve { let mut curve = PartialCurve::default();
surface: Partial::from(surface),
..Default::default()
};
curve.update_as_line_from_points([[0., 0.], [1., 0.]]); curve.update_as_line_from_points([[0., 0.], [1., 0.]]);
curve curve
.build(&mut services.objects) .build(&mut services.objects)

View File

@ -27,14 +27,10 @@ impl SurfaceSurfaceIntersection {
// Adaptations were made to get the intersection curves in local // Adaptations were made to get the intersection curves in local
// coordinates for each surface. // coordinates for each surface.
let surfaces_and_planes = surfaces.map(|surface| { let planes = surfaces.map(|surface| plane_from_surface(&surface));
let plane = plane_from_surface(&surface);
(surface, plane)
});
let [a, b] = surfaces_and_planes.clone().map(|(_, plane)| plane);
let (a_distance, a_normal) = a.constant_normal_form(); let [(a_distance, a_normal), (b_distance, b_normal)] =
let (b_distance, b_normal) = b.constant_normal_form(); planes.map(|plane| plane.constant_normal_form());
let direction = a_normal.cross(&b_normal); let direction = a_normal.cross(&b_normal);
@ -57,11 +53,11 @@ impl SurfaceSurfaceIntersection {
let line = Line::from_origin_and_direction(origin, direction); let line = Line::from_origin_and_direction(origin, direction);
let curves = surfaces_and_planes.map(|(surface, plane)| { let curves = planes.map(|plane| {
let path = SurfacePath::Line(plane.project_line(&line)); let path = SurfacePath::Line(plane.project_line(&line));
let global_form = GlobalCurve.insert(objects); let global_form = GlobalCurve.insert(objects);
Curve::new(surface, path, global_form).insert(objects) Curve::new(path, global_form).insert(objects)
}); });
Some(Self { Some(Self {
@ -92,7 +88,7 @@ mod tests {
algorithms::transform::TransformObject, algorithms::transform::TransformObject,
builder::CurveBuilder, builder::CurveBuilder,
insert::Insert, insert::Insert,
partial::{Partial, PartialCurve, PartialObject}, partial::{PartialCurve, PartialObject},
services::Services, services::Services,
}; };
@ -120,18 +116,13 @@ mod tests {
None, None,
); );
let mut expected_xy = PartialCurve { let mut expected_xy = PartialCurve::default();
surface: Partial::from(xy.clone()),
..Default::default()
};
expected_xy.update_as_u_axis(); expected_xy.update_as_u_axis();
let expected_xy = expected_xy let expected_xy = expected_xy
.build(&mut services.objects) .build(&mut services.objects)
.insert(&mut services.objects); .insert(&mut services.objects);
let mut expected_xz = PartialCurve {
surface: Partial::from(xz.clone()), let mut expected_xz = PartialCurve::default();
..Default::default()
};
expected_xz.update_as_u_axis(); expected_xz.update_as_u_axis();
let expected_xz = expected_xz let expected_xz = expected_xz
.build(&mut services.objects) .build(&mut services.objects)

View File

@ -19,6 +19,7 @@ impl Reverse for Handle<HalfEdge> {
}; };
HalfEdge::new( HalfEdge::new(
self.surface().clone(),
self.curve().clone(), self.curve().clone(),
vertices, vertices,
self.global_form().clone(), self.global_form().clone(),

View File

@ -12,7 +12,7 @@ use crate::{
use super::{Sweep, SweepCache}; use super::{Sweep, SweepCache};
impl Sweep for Handle<Curve> { impl Sweep for (Handle<Curve>, &Surface) {
type Swept = Handle<Surface>; type Swept = Handle<Surface>;
fn sweep_with_cache( fn sweep_with_cache(
@ -21,7 +21,9 @@ impl Sweep for Handle<Curve> {
_: &mut SweepCache, _: &mut SweepCache,
objects: &mut Service<Objects>, objects: &mut Service<Objects>,
) -> Self::Swept { ) -> Self::Swept {
match self.surface().geometry().u { let (curve, surface) = self;
match surface.geometry().u {
GlobalPath::Circle(_) => { GlobalPath::Circle(_) => {
// Sweeping a `Curve` creates a `Surface`. The u-axis of that // Sweeping a `Curve` creates a `Surface`. The u-axis of that
// `Surface` is a `GlobalPath`, which we are computing below. // `Surface` is a `GlobalPath`, which we are computing below.
@ -45,32 +47,24 @@ impl Sweep for Handle<Curve> {
} }
} }
let u = match self.path() { let u = match curve.path() {
SurfacePath::Circle(circle) => { SurfacePath::Circle(circle) => {
let center = self let center = surface
.surface()
.geometry() .geometry()
.point_from_surface_coords(circle.center()); .point_from_surface_coords(circle.center());
let a = self let a =
.surface() surface.geometry().vector_from_surface_coords(circle.a());
.geometry() let b =
.vector_from_surface_coords(circle.a()); surface.geometry().vector_from_surface_coords(circle.b());
let b = self
.surface()
.geometry()
.vector_from_surface_coords(circle.b());
let circle = Circle::new(center, a, b); let circle = Circle::new(center, a, b);
GlobalPath::Circle(circle) GlobalPath::Circle(circle)
} }
SurfacePath::Line(line) => { SurfacePath::Line(line) => {
let origin = self let origin =
.surface() surface.geometry().point_from_surface_coords(line.origin());
.geometry() let direction = surface
.point_from_surface_coords(line.origin());
let direction = self
.surface()
.geometry() .geometry()
.vector_from_surface_coords(line.direction()); .vector_from_surface_coords(line.direction());

View File

@ -1,3 +1,5 @@
use std::ops::Deref;
use fj_interop::{ext::ArrayExt, mesh::Color}; use fj_interop::{ext::ArrayExt, mesh::Color};
use fj_math::{Point, Scalar, Vector}; use fj_math::{Point, Scalar, Vector};
@ -34,7 +36,8 @@ impl Sweep for (Handle<HalfEdge>, Color) {
// be created by sweeping a curve, so let's sweep the curve of the edge // be created by sweeping a curve, so let's sweep the curve of the edge
// we're sweeping. // we're sweeping.
face.exterior.write().surface = Partial::from( face.exterior.write().surface = Partial::from(
edge.curve().clone().sweep_with_cache(path, cache, objects), (edge.curve().clone(), edge.surface().deref())
.sweep_with_cache(path, cache, objects),
); );
// Now we're ready to create the edges. // Now we're ready to create the edges.
@ -194,7 +197,7 @@ mod tests {
}; };
let side_up = { let side_up = {
let mut side_up = PartialHalfEdge::default(); let mut side_up = PartialHalfEdge::default();
side_up.curve.write().surface = surface.clone(); side_up.replace_surface(surface.clone());
{ {
let [back, front] = side_up let [back, front] = side_up
@ -206,7 +209,6 @@ mod tests {
let mut front = front.write(); let mut front = front.write();
front.position = Some([1., 1.].into()); front.position = Some([1., 1.].into());
front.surface = surface.clone();
} }
side_up.infer_global_form(); side_up.infer_global_form();
@ -216,7 +218,7 @@ mod tests {
}; };
let top = { let top = {
let mut top = PartialHalfEdge::default(); let mut top = PartialHalfEdge::default();
top.curve.write().surface = surface.clone(); top.replace_surface(surface.clone());
{ {
let [(back, back_surface), (front, front_surface)] = let [(back, back_surface), (front, front_surface)] =
@ -228,7 +230,6 @@ mod tests {
*front = Some(Point::from([0.])); *front = Some(Point::from([0.]));
let mut front_surface = front_surface.write(); let mut front_surface = front_surface.write();
front_surface.position = Some([0., 1.].into()); front_surface.position = Some([0., 1.].into());
front_surface.surface = surface.clone();
} }
top.infer_global_form(); top.infer_global_form();
@ -243,7 +244,7 @@ mod tests {
}; };
let side_down = { let side_down = {
let mut side_down = PartialHalfEdge::default(); let mut side_down = PartialHalfEdge::default();
side_down.curve.write().surface = surface; side_down.replace_surface(surface);
let [(back, back_surface), (front, front_surface)] = let [(back, back_surface), (front, front_surface)] =
side_down.vertices.each_mut_ext(); side_down.vertices.each_mut_ext();

View File

@ -18,16 +18,12 @@ impl TransformObject for Curve {
// coordinates, and thus transforming `surface` takes care of it. // coordinates, and thus transforming `surface` takes care of it.
let path = self.path(); let path = self.path();
let surface = self
.surface()
.clone()
.transform_with_cache(transform, objects, cache);
let global_form = self let global_form = self
.global_form() .global_form()
.clone() .clone()
.transform_with_cache(transform, objects, cache); .transform_with_cache(transform, objects, cache);
Self::new(surface, path, global_form) Self::new(path, global_form)
} }
} }

View File

@ -15,6 +15,10 @@ impl TransformObject for HalfEdge {
objects: &mut Service<Objects>, objects: &mut Service<Objects>,
cache: &mut TransformCache, cache: &mut TransformCache,
) -> Self { ) -> Self {
let surface = self
.surface()
.clone()
.transform_with_cache(transform, objects, cache);
let curve = self let curve = self
.curve() .curve()
.clone() .clone()
@ -32,7 +36,7 @@ impl TransformObject for HalfEdge {
.clone() .clone()
.transform_with_cache(transform, objects, cache); .transform_with_cache(transform, objects, cache);
Self::new(curve, boundary, global_form) Self::new(surface, curve, boundary, global_form)
} }
} }

View File

@ -64,7 +64,7 @@ impl HalfEdgeBuilder for PartialHalfEdge {
fn replace_surface(&mut self, surface: impl Into<Partial<Surface>>) { fn replace_surface(&mut self, surface: impl Into<Partial<Surface>>) {
let surface = surface.into(); let surface = surface.into();
self.curve.write().surface = surface.clone(); self.surface = surface.clone();
for vertex in &mut self.vertices { for vertex in &mut self.vertices {
vertex.1.write().surface = surface.clone(); vertex.1.write().surface = surface.clone();
@ -134,14 +134,11 @@ impl HalfEdgeBuilder for PartialHalfEdge {
surface: impl Into<Partial<Surface>>, surface: impl Into<Partial<Surface>>,
points: [impl Into<Point<2>>; 2], points: [impl Into<Point<2>>; 2],
) { ) {
let surface = surface.into(); self.replace_surface(surface.into());
self.curve.write().surface = surface.clone();
for (vertex, point) in self.vertices.each_mut_ext().zip_ext(points) { for (vertex, point) in self.vertices.each_mut_ext().zip_ext(points) {
let mut surface_form = vertex.1.write(); let mut surface_form = vertex.1.write();
surface_form.position = Some(point.into()); surface_form.position = Some(point.into());
surface_form.surface = surface.clone();
} }
self.update_as_line_segment() self.update_as_line_segment()
@ -196,7 +193,7 @@ impl HalfEdgeBuilder for PartialHalfEdge {
self.curve.write().path = self.curve.write().path =
other.read().curve.read().path.as_ref().and_then(|path| { other.read().curve.read().path.as_ref().and_then(|path| {
match other.read().curve.read().surface.read().geometry { match other.read().surface.read().geometry {
Some(surface) => { Some(surface) => {
// We have information about the other edge's surface // We have information about the other edge's surface
// available. We need to use that to interpret what the // available. We need to use that to interpret what the

View File

@ -1,6 +1,5 @@
use crate::{ use crate::{
geometry::path::SurfacePath, geometry::path::SurfacePath,
objects::Surface,
storage::{Handle, HandleWrapper}, storage::{Handle, HandleWrapper},
}; };
@ -8,19 +7,16 @@ use crate::{
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Curve { pub struct Curve {
path: SurfacePath, path: SurfacePath,
surface: Handle<Surface>,
global_form: HandleWrapper<GlobalCurve>, global_form: HandleWrapper<GlobalCurve>,
} }
impl Curve { impl Curve {
/// Construct a new instance of `Curve` /// Construct a new instance of `Curve`
pub fn new( pub fn new(
surface: Handle<Surface>,
path: SurfacePath, path: SurfacePath,
global_form: impl Into<HandleWrapper<GlobalCurve>>, global_form: impl Into<HandleWrapper<GlobalCurve>>,
) -> Self { ) -> Self {
Self { Self {
surface,
path, path,
global_form: global_form.into(), global_form: global_form.into(),
} }
@ -31,11 +27,6 @@ impl Curve {
self.path self.path
} }
/// Access the surface that the curve is defined in
pub fn surface(&self) -> &Handle<Surface> {
&self.surface
}
/// Access the global form of the curve /// Access the global form of the curve
pub fn global_form(&self) -> &Handle<GlobalCurve> { pub fn global_form(&self) -> &Handle<GlobalCurve> {
&self.global_form &self.global_form

View File

@ -39,7 +39,7 @@ impl Cycle {
/// Access the surface that the cycle is in /// Access the surface that the cycle is in
pub fn surface(&self) -> &Handle<Surface> { pub fn surface(&self) -> &Handle<Surface> {
if let Some(half_edge) = self.half_edges.first() { if let Some(half_edge) = self.half_edges.first() {
return half_edge.curve().surface(); return half_edge.surface();
} }
unreachable!( unreachable!(

View File

@ -4,13 +4,14 @@ use fj_interop::ext::ArrayExt;
use fj_math::Point; use fj_math::Point;
use crate::{ use crate::{
objects::{Curve, GlobalCurve, GlobalVertex, SurfaceVertex}, objects::{Curve, GlobalCurve, GlobalVertex, Surface, SurfaceVertex},
storage::{Handle, HandleWrapper}, storage::{Handle, HandleWrapper},
}; };
/// A half-edge /// A half-edge
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct HalfEdge { pub struct HalfEdge {
surface: Handle<Surface>,
curve: Handle<Curve>, curve: Handle<Curve>,
boundary: [(Point<1>, Handle<SurfaceVertex>); 2], boundary: [(Point<1>, Handle<SurfaceVertex>); 2],
global_form: Handle<GlobalEdge>, global_form: Handle<GlobalEdge>,
@ -19,17 +20,24 @@ pub struct HalfEdge {
impl HalfEdge { impl HalfEdge {
/// Create an instance of `HalfEdge` /// Create an instance of `HalfEdge`
pub fn new( pub fn new(
surface: Handle<Surface>,
curve: Handle<Curve>, curve: Handle<Curve>,
boundary: [(Point<1>, Handle<SurfaceVertex>); 2], boundary: [(Point<1>, Handle<SurfaceVertex>); 2],
global_form: Handle<GlobalEdge>, global_form: Handle<GlobalEdge>,
) -> Self { ) -> Self {
Self { Self {
surface,
curve, curve,
boundary, boundary,
global_form, global_form,
} }
} }
/// Access the surface that the half-edge is defined in
pub fn surface(&self) -> &Handle<Surface> {
&self.surface
}
/// Access the curve that defines the half-edge's geometry /// Access the curve that defines the half-edge's geometry
pub fn curve(&self) -> &Handle<Curve> { pub fn curve(&self) -> &Handle<Curve> {
&self.curve &self.curve

View File

@ -2,7 +2,7 @@ use fj_math::Scalar;
use crate::{ use crate::{
geometry::path::SurfacePath, geometry::path::SurfacePath,
objects::{Curve, GlobalCurve, Objects, Surface}, objects::{Curve, GlobalCurve, Objects},
partial::{FullToPartialCache, Partial, PartialObject}, partial::{FullToPartialCache, Partial, PartialObject},
services::Service, services::Service,
}; };
@ -13,9 +13,6 @@ pub struct PartialCurve {
/// The path that defines the curve /// The path that defines the curve
pub path: Option<MaybeSurfacePath>, pub path: Option<MaybeSurfacePath>,
/// The surface the curve is defined in
pub surface: Partial<Surface>,
/// The global form of the curve /// The global form of the curve
pub global_form: Partial<GlobalCurve>, pub global_form: Partial<GlobalCurve>,
} }
@ -26,7 +23,6 @@ impl PartialObject for PartialCurve {
fn from_full(curve: &Self::Full, cache: &mut FullToPartialCache) -> Self { fn from_full(curve: &Self::Full, cache: &mut FullToPartialCache) -> Self {
Self { Self {
path: Some(curve.path().into()), path: Some(curve.path().into()),
surface: Partial::from_full(curve.surface().clone(), cache),
global_form: Partial::from_full(curve.global_form().clone(), cache), global_form: Partial::from_full(curve.global_form().clone(), cache),
} }
} }
@ -40,10 +36,9 @@ impl PartialObject for PartialCurve {
) )
} }
}; };
let surface = self.surface.build(objects);
let global_form = self.global_form.build(objects); let global_form = self.global_form.build(objects);
Curve::new(surface, path, global_form) Curve::new(path, global_form)
} }
} }

View File

@ -6,7 +6,7 @@ use fj_math::Point;
use crate::{ use crate::{
objects::{ objects::{
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects,
SurfaceVertex, Surface, SurfaceVertex,
}, },
partial::{ partial::{
FullToPartialCache, Partial, PartialObject, PartialSurfaceVertex, FullToPartialCache, Partial, PartialObject, PartialSurfaceVertex,
@ -17,6 +17,9 @@ use crate::{
/// A partial [`HalfEdge`] /// A partial [`HalfEdge`]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PartialHalfEdge { pub struct PartialHalfEdge {
/// The surface that the half-edge is defined in
pub surface: Partial<Surface>,
/// The curve that the half-edge is defined in /// The curve that the half-edge is defined in
pub curve: Partial<Curve>, pub curve: Partial<Curve>,
@ -35,6 +38,7 @@ impl PartialObject for PartialHalfEdge {
cache: &mut FullToPartialCache, cache: &mut FullToPartialCache,
) -> Self { ) -> Self {
Self { Self {
surface: Partial::from_full(half_edge.surface().clone(), cache),
curve: Partial::from_full(half_edge.curve().clone(), cache), curve: Partial::from_full(half_edge.curve().clone(), cache),
vertices: half_edge vertices: half_edge
.boundary() .boundary()
@ -53,6 +57,7 @@ impl PartialObject for PartialHalfEdge {
} }
fn build(self, objects: &mut Service<Objects>) -> Self::Full { fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let surface = self.surface.build(objects);
let curve = self.curve.build(objects); let curve = self.curve.build(objects);
let vertices = self.vertices.map(|mut vertex| { let vertices = self.vertices.map(|mut vertex| {
let position_surface = vertex.1.read().position; let position_surface = vertex.1.read().position;
@ -76,10 +81,9 @@ impl PartialObject for PartialHalfEdge {
// Infer global position, if not available. // Infer global position, if not available.
let position_global = vertex.1.read().global_form.read().position; let position_global = vertex.1.read().global_form.read().position;
if position_global.is_none() { if position_global.is_none() {
let surface = curve.surface().geometry(); let position_global = surface
.geometry()
let position_global = .point_from_surface_coords(position_surface);
surface.point_from_surface_coords(position_surface);
vertex.1.write().global_form.write().position = vertex.1.write().global_form.write().position =
Some(position_global); Some(position_global);
} }
@ -92,18 +96,18 @@ impl PartialObject for PartialHalfEdge {
}); });
let global_form = self.global_form.build(objects); let global_form = self.global_form.build(objects);
HalfEdge::new(curve, vertices, global_form) HalfEdge::new(surface, curve, vertices, global_form)
} }
} }
impl Default for PartialHalfEdge { impl Default for PartialHalfEdge {
fn default() -> Self { fn default() -> Self {
let surface = Partial::new();
let curve = Partial::<Curve>::new(); let curve = Partial::<Curve>::new();
let vertices = array::from_fn(|_| { let vertices = array::from_fn(|_| {
let surface = Partial::new();
let surface_form = Partial::from_partial(PartialSurfaceVertex { let surface_form = Partial::from_partial(PartialSurfaceVertex {
surface, surface: surface.clone(),
..Default::default() ..Default::default()
}); });
@ -125,6 +129,7 @@ impl Default for PartialHalfEdge {
}); });
Self { Self {
surface,
curve, curve,
vertices, vertices,
global_form, global_form,

View File

@ -165,13 +165,13 @@ impl HalfEdgeValidationError {
half_edge: &HalfEdge, half_edge: &HalfEdge,
errors: &mut Vec<ValidationError>, errors: &mut Vec<ValidationError>,
) { ) {
let curve_surface = half_edge.curve().surface(); let surface = half_edge.surface();
let surface_form_surface = half_edge.start_vertex().surface(); let surface_form_surface = half_edge.start_vertex().surface();
if curve_surface.id() != surface_form_surface.id() { if surface.id() != surface_form_surface.id() {
errors.push( errors.push(
Box::new(Self::SurfaceMismatch { Box::new(Self::SurfaceMismatch {
curve_surface: curve_surface.clone(), curve_surface: surface.clone(),
surface_form_surface: surface_form_surface.clone(), surface_form_surface: surface_form_surface.clone(),
}) })
.into(), .into(),
@ -240,7 +240,12 @@ mod tests {
.boundary() .boundary()
.zip_ext(valid.surface_vertices().map(Clone::clone)); .zip_ext(valid.surface_vertices().map(Clone::clone));
HalfEdge::new(valid.curve().clone(), vertices, global_form) HalfEdge::new(
valid.surface().clone(),
valid.curve().clone(),
vertices,
global_form,
)
}; };
valid.validate_and_return_first_error()?; valid.validate_and_return_first_error()?;
@ -282,7 +287,12 @@ mod tests {
.boundary() .boundary()
.zip_ext(valid.surface_vertices().map(Clone::clone)); .zip_ext(valid.surface_vertices().map(Clone::clone));
HalfEdge::new(valid.curve().clone(), vertices, global_form) HalfEdge::new(
valid.surface().clone(),
valid.curve().clone(),
vertices,
global_form,
)
}; };
valid.validate_and_return_first_error()?; valid.validate_and_return_first_error()?;
@ -318,6 +328,7 @@ mod tests {
}); });
HalfEdge::new( HalfEdge::new(
valid.surface().clone(),
valid.curve().clone(), valid.curve().clone(),
vertices, vertices,
valid.global_form().clone(), valid.global_form().clone(),
@ -349,6 +360,7 @@ mod tests {
}); });
HalfEdge::new( HalfEdge::new(
valid.surface().clone(),
valid.curve().clone(), valid.curve().clone(),
vertices, vertices,
valid.global_form().clone(), valid.global_form().clone(),

View File

@ -31,13 +31,7 @@ impl Shape for fj::Sketch {
let surface = Partial::from(surface); let surface = Partial::from(surface);
let mut half_edge = PartialHalfEdge::default(); let mut half_edge = PartialHalfEdge::default();
half_edge.replace_surface(surface);
half_edge.curve.write().surface = surface.clone();
for vertex in &mut half_edge.vertices {
vertex.1.write().surface = surface.clone();
}
half_edge.update_as_circle_from_radius(circle.radius()); half_edge.update_as_circle_from_radius(circle.radius());
Partial::from_partial(half_edge) Partial::from_partial(half_edge)