mirror of https://github.com/hannobraun/Fornjot
Merge pull request #1331 from hannobraun/partial
Integrate `Face` into partial object API
This commit is contained in:
commit
d9bef00c12
|
@ -150,7 +150,7 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::CurveBuilder,
|
builder::{CurveBuilder, FaceBuilder},
|
||||||
objects::{Curve, Face, Objects},
|
objects::{Curve, Face, Objects},
|
||||||
partial::HasPartial,
|
partial::HasPartial,
|
||||||
};
|
};
|
||||||
|
@ -183,11 +183,11 @@ mod tests {
|
||||||
[ 1., -1.],
|
[ 1., -1.],
|
||||||
];
|
];
|
||||||
|
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points(exterior)
|
.with_exterior_polygon_from_points(exterior)
|
||||||
.with_interior_polygon_from_points(interior)
|
.with_interior_polygon_from_points(interior)
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
let expected =
|
let expected =
|
||||||
CurveFaceIntersection::from_intervals([[[1.], [2.]], [[4.], [5.]]]);
|
CurveFaceIntersection::from_intervals([[[1.], [2.]], [[4.], [5.]]]);
|
||||||
|
|
|
@ -67,7 +67,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::intersect::CurveFaceIntersection,
|
algorithms::intersect::CurveFaceIntersection,
|
||||||
builder::CurveBuilder,
|
builder::{CurveBuilder, FaceBuilder},
|
||||||
objects::{Curve, Face, Objects},
|
objects::{Curve, Face, Objects},
|
||||||
partial::HasPartial,
|
partial::HasPartial,
|
||||||
};
|
};
|
||||||
|
@ -86,12 +86,12 @@ mod tests {
|
||||||
[1., 2.],
|
[1., 2.],
|
||||||
];
|
];
|
||||||
let [a, b] = [objects.surfaces.xy_plane(), objects.surfaces.xz_plane()]
|
let [a, b] = [objects.surfaces.xy_plane(), objects.surfaces.xz_plane()]
|
||||||
.map(|surface| {
|
.try_map_ext(|surface| {
|
||||||
Face::builder(&objects)
|
Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points(points)
|
.with_exterior_polygon_from_points(points)
|
||||||
.build()
|
.build(&objects)
|
||||||
});
|
})?;
|
||||||
|
|
||||||
let intersection = FaceFaceIntersection::compute([&a, &b], &objects)?;
|
let intersection = FaceFaceIntersection::compute([&a, &b], &objects)?;
|
||||||
|
|
||||||
|
@ -113,12 +113,12 @@ mod tests {
|
||||||
];
|
];
|
||||||
let surfaces =
|
let surfaces =
|
||||||
[objects.surfaces.xy_plane(), objects.surfaces.xz_plane()];
|
[objects.surfaces.xy_plane(), objects.surfaces.xz_plane()];
|
||||||
let [a, b] = surfaces.clone().map(|surface| {
|
let [a, b] = surfaces.clone().try_map_ext(|surface| {
|
||||||
Face::builder(&objects)
|
Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points(points)
|
.with_exterior_polygon_from_points(points)
|
||||||
.build()
|
.build(&objects)
|
||||||
});
|
})?;
|
||||||
|
|
||||||
let intersection = FaceFaceIntersection::compute([&a, &b], &objects)?;
|
let intersection = FaceFaceIntersection::compute([&a, &b], &objects)?;
|
||||||
|
|
||||||
|
|
|
@ -136,34 +136,38 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::intersect::{face_point::FacePointIntersection, Intersect},
|
algorithms::intersect::{face_point::FacePointIntersection, Intersect},
|
||||||
|
builder::FaceBuilder,
|
||||||
iter::ObjectIters,
|
iter::ObjectIters,
|
||||||
objects::{Face, Objects},
|
objects::{Face, Objects},
|
||||||
|
partial::HasPartial,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn point_is_outside_face() {
|
fn point_is_outside_face() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [1., 1.], [0., 2.]])
|
.with_exterior_polygon_from_points([[0., 0.], [1., 1.], [0., 2.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([2., 1.]);
|
let point = Point::from([2., 1.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
assert_eq!(intersection, None);
|
assert_eq!(intersection, None);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_hits_vertex_while_passing_outside() {
|
fn ray_hits_vertex_while_passing_outside() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [2., 1.], [0., 2.]])
|
.with_exterior_polygon_from_points([[0., 0.], [2., 1.], [0., 2.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 1.]);
|
let point = Point::from([1., 1.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -171,17 +175,19 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsInsideFace)
|
Some(FacePointIntersection::PointIsInsideFace)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_hits_vertex_at_cycle_seam() {
|
fn ray_hits_vertex_at_cycle_seam() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[4., 2.], [0., 4.], [0., 0.]])
|
.with_exterior_polygon_from_points([[4., 2.], [0., 4.], [0., 0.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 2.]);
|
let point = Point::from([1., 2.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -189,14 +195,16 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsInsideFace)
|
Some(FacePointIntersection::PointIsInsideFace)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_hits_vertex_while_staying_inside() {
|
fn ray_hits_vertex_while_staying_inside() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[0., 0.],
|
[0., 0.],
|
||||||
|
@ -204,7 +212,7 @@ mod tests {
|
||||||
[3., 0.],
|
[3., 0.],
|
||||||
[3., 4.],
|
[3., 4.],
|
||||||
])
|
])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 1.]);
|
let point = Point::from([1., 1.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -212,14 +220,17 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsInsideFace)
|
Some(FacePointIntersection::PointIsInsideFace)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_hits_parallel_edge_and_leaves_face_at_vertex() {
|
fn ray_hits_parallel_edge_and_leaves_face_at_vertex() -> anyhow::Result<()>
|
||||||
|
{
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[0., 0.],
|
[0., 0.],
|
||||||
|
@ -227,7 +238,7 @@ mod tests {
|
||||||
[3., 1.],
|
[3., 1.],
|
||||||
[0., 2.],
|
[0., 2.],
|
||||||
])
|
])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 1.]);
|
let point = Point::from([1., 1.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -235,14 +246,17 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsInsideFace)
|
Some(FacePointIntersection::PointIsInsideFace)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_hits_parallel_edge_and_does_not_leave_face_there() {
|
fn ray_hits_parallel_edge_and_does_not_leave_face_there(
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[0., 0.],
|
[0., 0.],
|
||||||
|
@ -251,7 +265,7 @@ mod tests {
|
||||||
[4., 0.],
|
[4., 0.],
|
||||||
[4., 5.],
|
[4., 5.],
|
||||||
])
|
])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 1.]);
|
let point = Point::from([1., 1.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -259,17 +273,19 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsInsideFace)
|
Some(FacePointIntersection::PointIsInsideFace)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn point_is_coincident_with_edge() {
|
fn point_is_coincident_with_edge() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [2., 0.], [0., 1.]])
|
.with_exterior_polygon_from_points([[0., 0.], [2., 0.], [0., 1.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 0.]);
|
let point = Point::from([1., 0.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -286,17 +302,19 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsOnEdge(edge.clone()))
|
Some(FacePointIntersection::PointIsOnEdge(edge.clone()))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn point_is_coincident_with_vertex() {
|
fn point_is_coincident_with_vertex() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let point = Point::from([1., 0.]);
|
let point = Point::from([1., 0.]);
|
||||||
|
|
||||||
let intersection = (&face, &point).intersect();
|
let intersection = (&face, &point).intersect();
|
||||||
|
@ -311,5 +329,7 @@ mod tests {
|
||||||
intersection,
|
intersection,
|
||||||
Some(FacePointIntersection::PointIsOnVertex(vertex.clone()))
|
Some(FacePointIntersection::PointIsOnVertex(vertex.clone()))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,8 +152,10 @@ mod tests {
|
||||||
},
|
},
|
||||||
transform::TransformObject,
|
transform::TransformObject,
|
||||||
},
|
},
|
||||||
|
builder::FaceBuilder,
|
||||||
iter::ObjectIters,
|
iter::ObjectIters,
|
||||||
objects::{Face, Objects},
|
objects::{Face, Objects},
|
||||||
|
partial::HasPartial,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -163,7 +165,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.yz_plane();
|
let surface = objects.surfaces.yz_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -171,7 +173,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([-1., 0., 0.], &objects)?;
|
.translate([-1., 0., 0.], &objects)?;
|
||||||
|
|
||||||
assert_eq!((&ray, &face).intersect(), None);
|
assert_eq!((&ray, &face).intersect(), None);
|
||||||
|
@ -185,7 +187,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.yz_plane();
|
let surface = objects.surfaces.yz_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -193,7 +195,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([1., 0., 0.], &objects)?;
|
.translate([1., 0., 0.], &objects)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -210,7 +212,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.yz_plane();
|
let surface = objects.surfaces.yz_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -218,7 +220,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([0., 0., 2.], &objects)?;
|
.translate([0., 0., 2.], &objects)?;
|
||||||
|
|
||||||
assert_eq!((&ray, &face).intersect(), None);
|
assert_eq!((&ray, &face).intersect(), None);
|
||||||
|
@ -232,7 +234,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.yz_plane();
|
let surface = objects.surfaces.yz_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -240,7 +242,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([1., 1., 0.], &objects)?;
|
.translate([1., 1., 0.], &objects)?;
|
||||||
|
|
||||||
let edge = face
|
let edge = face
|
||||||
|
@ -265,7 +267,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.yz_plane();
|
let surface = objects.surfaces.yz_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -273,7 +275,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([1., 1., 1.], &objects)?;
|
.translate([1., 1., 1.], &objects)?;
|
||||||
|
|
||||||
let vertex = face
|
let vertex = face
|
||||||
|
@ -290,13 +292,13 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_is_parallel_to_surface_and_hits() {
|
fn ray_is_parallel_to_surface_and_hits() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -304,12 +306,14 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(&ray, &face).intersect(),
|
(&ray, &face).intersect(),
|
||||||
Some(RayFaceIntersection::RayHitsFaceAndAreParallel)
|
Some(RayFaceIntersection::RayHitsFaceAndAreParallel)
|
||||||
)
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -319,7 +323,7 @@ mod tests {
|
||||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-1., -1.],
|
[-1., -1.],
|
||||||
|
@ -327,7 +331,7 @@ mod tests {
|
||||||
[1., 1.],
|
[1., 1.],
|
||||||
[-1., 1.],
|
[-1., 1.],
|
||||||
])
|
])
|
||||||
.build()
|
.build(&objects)?
|
||||||
.translate([0., 0., 1.], &objects)?;
|
.translate([0., 0., 1.], &objects)?;
|
||||||
|
|
||||||
assert_eq!((&ray, &face).intersect(), None);
|
assert_eq!((&ray, &face).intersect(), None);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Face, Objects},
|
objects::{Face, Objects},
|
||||||
|
partial::HasPartial,
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
validate::ValidationError,
|
validate::ValidationError,
|
||||||
};
|
};
|
||||||
|
@ -14,10 +15,10 @@ impl Reverse for Handle<Face> {
|
||||||
.map(|cycle| cycle.clone().reverse(objects))
|
.map(|cycle| cycle.clone().reverse(objects))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Ok(Face::builder(objects)
|
Face::partial()
|
||||||
.with_exterior(exterior)
|
.with_exterior(exterior)
|
||||||
.with_interiors(interiors)
|
.with_interiors(interiors)
|
||||||
.with_color(self.color())
|
.with_color(self.color())
|
||||||
.build())
|
.build(objects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
Curve, Cycle, Face, GlobalEdge, HalfEdge, Objects, SurfaceVertex,
|
Curve, Cycle, Face, GlobalEdge, HalfEdge, Objects, SurfaceVertex,
|
||||||
Vertex,
|
Vertex,
|
||||||
},
|
},
|
||||||
|
partial::HasPartial,
|
||||||
path::SurfacePath,
|
path::SurfacePath,
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
validate::ValidationError,
|
validate::ValidationError,
|
||||||
|
@ -175,10 +176,10 @@ impl Sweep for (Handle<HalfEdge>, Color) {
|
||||||
objects.cycles.insert(Cycle::new(edges))?
|
objects.cycles.insert(Cycle::new(edges))?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Face::builder(objects)
|
Face::partial()
|
||||||
.with_exterior(cycle)
|
.with_exterior(cycle)
|
||||||
.with_color(color)
|
.with_color(color)
|
||||||
.build())
|
.build(objects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +257,7 @@ mod tests {
|
||||||
.cycles
|
.cycles
|
||||||
.insert(Cycle::new([bottom, side_up, top, side_down]))?;
|
.insert(Cycle::new([bottom, side_up, top, side_down]))?;
|
||||||
|
|
||||||
Face::builder(&objects).with_exterior(cycle).build()
|
Face::partial().with_exterior(cycle).build(&objects)?
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(face, expected_face);
|
assert_eq!(face, expected_face);
|
||||||
|
|
|
@ -84,7 +84,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::{reverse::Reverse, transform::TransformObject},
|
algorithms::{reverse::Reverse, transform::TransformObject},
|
||||||
builder::HalfEdgeBuilder,
|
builder::{FaceBuilder, HalfEdgeBuilder},
|
||||||
objects::{Face, HalfEdge, Objects, Sketch},
|
objects::{Face, HalfEdge, Objects, Sketch},
|
||||||
partial::HasPartial,
|
partial::HasPartial,
|
||||||
};
|
};
|
||||||
|
@ -107,15 +107,15 @@ mod tests {
|
||||||
.build()
|
.build()
|
||||||
.sweep(UP, &objects)?;
|
.sweep(UP, &objects)?;
|
||||||
|
|
||||||
let bottom = Face::builder(&objects)
|
let bottom = Face::partial()
|
||||||
.with_surface(surface.clone())
|
.with_surface(surface.clone())
|
||||||
.with_exterior_polygon_from_points(TRIANGLE)
|
.with_exterior_polygon_from_points(TRIANGLE)
|
||||||
.build()
|
.build(&objects)?
|
||||||
.reverse(&objects)?;
|
.reverse(&objects)?;
|
||||||
let top = Face::builder(&objects)
|
let top = Face::partial()
|
||||||
.with_surface(surface.translate(UP, &objects)?)
|
.with_surface(surface.translate(UP, &objects)?)
|
||||||
.with_exterior_polygon_from_points(TRIANGLE)
|
.with_exterior_polygon_from_points(TRIANGLE)
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
assert!(solid.find_face(&bottom).is_some());
|
assert!(solid.find_face(&bottom).is_some());
|
||||||
assert!(solid.find_face(&top).is_some());
|
assert!(solid.find_face(&top).is_some());
|
||||||
|
@ -151,15 +151,15 @@ mod tests {
|
||||||
.build()
|
.build()
|
||||||
.sweep(DOWN, &objects)?;
|
.sweep(DOWN, &objects)?;
|
||||||
|
|
||||||
let bottom = Face::builder(&objects)
|
let bottom = Face::partial()
|
||||||
.with_surface(surface.clone().translate(DOWN, &objects)?)
|
.with_surface(surface.clone().translate(DOWN, &objects)?)
|
||||||
.with_exterior_polygon_from_points(TRIANGLE)
|
.with_exterior_polygon_from_points(TRIANGLE)
|
||||||
.build()
|
.build(&objects)?
|
||||||
.reverse(&objects)?;
|
.reverse(&objects)?;
|
||||||
let top = Face::builder(&objects)
|
let top = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points(TRIANGLE)
|
.with_exterior_polygon_from_points(TRIANGLE)
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
assert!(solid.find_face(&bottom).is_some());
|
assert!(solid.find_face(&bottom).is_some());
|
||||||
assert!(solid.find_face(&top).is_some());
|
assert!(solid.find_face(&top).is_some());
|
||||||
|
|
|
@ -2,44 +2,51 @@ use fj_math::Transform;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Face, FaceSet, Objects},
|
objects::{Face, FaceSet, Objects},
|
||||||
partial::HasPartial,
|
partial::{HasPartial, PartialFace},
|
||||||
storage::Handle,
|
|
||||||
validate::ValidationError,
|
validate::ValidationError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::TransformObject;
|
use super::TransformObject;
|
||||||
|
|
||||||
impl TransformObject for Handle<Face> {
|
impl TransformObject for PartialFace {
|
||||||
fn transform(
|
fn transform(
|
||||||
self,
|
self,
|
||||||
transform: &Transform,
|
transform: &Transform,
|
||||||
objects: &Objects,
|
objects: &Objects,
|
||||||
) -> Result<Self, ValidationError> {
|
) -> Result<Self, ValidationError> {
|
||||||
let surface = self.surface().clone().transform(transform, objects)?;
|
let surface = self
|
||||||
|
.surface()
|
||||||
|
.map(|surface| surface.transform(transform, objects))
|
||||||
|
.transpose()?;
|
||||||
let exterior = self
|
let exterior = self
|
||||||
.exterior()
|
.exterior()
|
||||||
.to_partial()
|
.into_partial()
|
||||||
.transform(transform, objects)?
|
.transform(transform, objects)?
|
||||||
.with_surface(Some(surface.clone()))
|
.with_surface(surface.clone());
|
||||||
.build(objects)?;
|
|
||||||
let interiors = self
|
let interiors = self
|
||||||
.interiors()
|
.interiors()
|
||||||
.map(|cycle| -> Result<_, ValidationError> {
|
.map(|cycle| -> Result<_, ValidationError> {
|
||||||
cycle
|
cycle
|
||||||
.to_partial()
|
.into_partial()
|
||||||
.transform(transform, objects)?
|
.transform(transform, objects)?
|
||||||
.with_surface(Some(surface.clone()))
|
.with_surface(surface.clone())
|
||||||
.build(objects)
|
.build(objects)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let color = self.color();
|
let color = self.color();
|
||||||
|
|
||||||
Ok(Face::builder(objects)
|
let mut face = Face::partial()
|
||||||
.with_exterior(exterior)
|
.with_exterior(exterior)
|
||||||
.with_interiors(interiors)
|
.with_interiors(interiors);
|
||||||
.with_color(color)
|
if let Some(surface) = surface {
|
||||||
.build())
|
face = face.with_surface(surface);
|
||||||
|
}
|
||||||
|
if let Some(color) = color {
|
||||||
|
face = face.with_color(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(face)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,9 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::approx::{Approx, Tolerance},
|
algorithms::approx::{Approx, Tolerance},
|
||||||
|
builder::FaceBuilder,
|
||||||
objects::{Face, Objects},
|
objects::{Face, Objects},
|
||||||
|
partial::HasPartial,
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,10 +102,10 @@ mod tests {
|
||||||
let d = [0., 1.];
|
let d = [0., 1.];
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([a, b, c, d])
|
.with_exterior_polygon_from_points([a, b, c, d])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
let a = Point::from(a).to_xyz();
|
let a = Point::from(a).to_xyz();
|
||||||
let b = Point::from(b).to_xyz();
|
let b = Point::from(b).to_xyz();
|
||||||
|
@ -135,11 +137,11 @@ mod tests {
|
||||||
let h = [3., 1.];
|
let h = [3., 1.];
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface.clone())
|
.with_surface(surface.clone())
|
||||||
.with_exterior_polygon_from_points([a, b, c, d])
|
.with_exterior_polygon_from_points([a, b, c, d])
|
||||||
.with_interior_polygon_from_points([e, f, g, h])
|
.with_interior_polygon_from_points([e, f, g, h])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
let triangles = triangulate(face)?;
|
let triangles = triangulate(face)?;
|
||||||
|
|
||||||
|
@ -196,10 +198,10 @@ mod tests {
|
||||||
let e = [0., 0.8];
|
let e = [0., 0.8];
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface.clone())
|
.with_surface(surface.clone())
|
||||||
.with_exterior_polygon_from_points([a, b, c, d, e])
|
.with_exterior_polygon_from_points([a, b, c, d, e])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
|
|
||||||
let triangles = triangulate(face)?;
|
let triangles = triangulate(face)?;
|
||||||
|
|
||||||
|
|
|
@ -1,115 +1,49 @@
|
||||||
use fj_interop::mesh::Color;
|
|
||||||
use fj_math::Point;
|
use fj_math::Point;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Cycle, Face, Objects, Surface},
|
objects::Cycle,
|
||||||
partial::HasPartial,
|
partial::{HasPartial, PartialFace},
|
||||||
storage::Handle,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::CycleBuilder;
|
use super::CycleBuilder;
|
||||||
|
|
||||||
/// API for building a [`Face`]
|
/// Builder API for [`PartialFace`]
|
||||||
///
|
pub trait FaceBuilder {
|
||||||
/// Also see [`Face::builder`].
|
/// Update the [`PartialFace`] with an exterior polygon
|
||||||
pub struct FaceBuilder<'a> {
|
fn with_exterior_polygon_from_points(
|
||||||
/// The stores that the created objects are put in
|
self,
|
||||||
pub objects: &'a Objects,
|
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||||
|
) -> Self;
|
||||||
|
|
||||||
/// The surface that the [`Face`] is defined in
|
/// Update the [`PartialFace`] with an interior polygon
|
||||||
pub surface: Option<Handle<Surface>>,
|
fn with_interior_polygon_from_points(
|
||||||
|
self,
|
||||||
/// The exterior cycle that bounds the [`Face`] on the outside
|
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||||
///
|
) -> Self;
|
||||||
/// Must be provided by the caller, directly or using one of the `with_`
|
|
||||||
/// methods, before [`FaceBuilder::build`] is called.
|
|
||||||
pub exterior: Option<Handle<Cycle>>,
|
|
||||||
|
|
||||||
/// The interior cycles that form holes in the [`Face`]
|
|
||||||
pub interiors: Vec<Handle<Cycle>>,
|
|
||||||
|
|
||||||
/// The color of the [`Face`]
|
|
||||||
pub color: Option<Color>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FaceBuilder<'a> {
|
impl FaceBuilder for PartialFace {
|
||||||
/// Build the [`Face`] with the provided surface
|
fn with_exterior_polygon_from_points(
|
||||||
pub fn with_surface(mut self, surface: Handle<Surface>) -> Self {
|
self,
|
||||||
self.surface = Some(surface);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build the [`Face`] with the provided exterior
|
|
||||||
pub fn with_exterior(mut self, exterior: Handle<Cycle>) -> Self {
|
|
||||||
self.exterior = Some(exterior);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build the [`Face`] with an exterior polygon from the provided points
|
|
||||||
pub fn with_exterior_polygon_from_points(
|
|
||||||
mut self,
|
|
||||||
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let surface = self
|
let surface = self.surface().expect("Need surface to create polygon");
|
||||||
.surface
|
|
||||||
.as_ref()
|
|
||||||
.expect("Need surface to create polygon");
|
|
||||||
|
|
||||||
self.exterior = Some(
|
self.with_exterior(
|
||||||
Cycle::partial()
|
Cycle::partial()
|
||||||
.with_poly_chain_from_points(surface.clone(), points)
|
.with_poly_chain_from_points(surface, points)
|
||||||
.close_with_line_segment()
|
.close_with_line_segment(),
|
||||||
.build(self.objects)
|
)
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the [`Face`] with the provided interior polygons
|
fn with_interior_polygon_from_points(
|
||||||
pub fn with_interiors(
|
self,
|
||||||
mut self,
|
|
||||||
interiors: impl IntoIterator<Item = Handle<Cycle>>,
|
|
||||||
) -> Self {
|
|
||||||
self.interiors.extend(interiors);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build the [`Face`] with an interior polygon from the provided points
|
|
||||||
pub fn with_interior_polygon_from_points(
|
|
||||||
mut self,
|
|
||||||
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let surface = self
|
let surface = self.surface().expect("Need surface to build polygon.");
|
||||||
.surface
|
|
||||||
.as_ref()
|
|
||||||
.expect("Need surface to build polygon.");
|
|
||||||
|
|
||||||
self.interiors.push(
|
self.with_interiors([Cycle::partial()
|
||||||
Cycle::partial()
|
.with_poly_chain_from_points(surface, points)
|
||||||
.with_poly_chain_from_points(surface.clone(), points)
|
.close_with_line_segment()])
|
||||||
.close_with_line_segment()
|
|
||||||
.build(self.objects)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build the [`Face`] with the provided color
|
|
||||||
pub fn with_color(mut self, color: Color) -> Self {
|
|
||||||
self.color = Some(color);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a polygon from a list of points
|
|
||||||
pub fn build(self) -> Handle<Face> {
|
|
||||||
let exterior = self
|
|
||||||
.exterior
|
|
||||||
.expect("Can't build `Face` without exterior cycle");
|
|
||||||
let color = self.color.unwrap_or_default();
|
|
||||||
|
|
||||||
self.objects
|
|
||||||
.faces
|
|
||||||
.insert(Face::new(exterior, self.interiors, color))
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
// These are the old-style builders that need to be transferred to the partial
|
// These are the old-style builders that need to be transferred to the partial
|
||||||
// object API. Issue:
|
// object API. Issue:
|
||||||
// https://github.com/hannobraun/Fornjot/issues/1147
|
// https://github.com/hannobraun/Fornjot/issues/1147
|
||||||
mod face;
|
|
||||||
mod shell;
|
mod shell;
|
||||||
mod sketch;
|
mod sketch;
|
||||||
mod solid;
|
mod solid;
|
||||||
|
@ -12,6 +11,7 @@ mod solid;
|
||||||
mod curve;
|
mod curve;
|
||||||
mod cycle;
|
mod cycle;
|
||||||
mod edge;
|
mod edge;
|
||||||
|
mod face;
|
||||||
mod vertex;
|
mod vertex;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
|
|
@ -5,7 +5,7 @@ use fj_math::Scalar;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::transform::TransformObject,
|
algorithms::transform::TransformObject,
|
||||||
builder::HalfEdgeBuilder,
|
builder::{FaceBuilder, HalfEdgeBuilder},
|
||||||
objects::{
|
objects::{
|
||||||
Curve, Cycle, Face, FaceSet, HalfEdge, Objects, Shell, Surface,
|
Curve, Cycle, Face, FaceSet, HalfEdge, Objects, Shell, Surface,
|
||||||
SurfaceVertex, Vertex,
|
SurfaceVertex, Vertex,
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> ShellBuilder<'a> {
|
||||||
.translate([Z, Z, -h], self.objects)
|
.translate([Z, Z, -h], self.objects)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Face::builder(self.objects)
|
Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([
|
.with_exterior_polygon_from_points([
|
||||||
[-h, -h],
|
[-h, -h],
|
||||||
|
@ -62,7 +62,8 @@ impl<'a> ShellBuilder<'a> {
|
||||||
[h, h],
|
[h, h],
|
||||||
[-h, h],
|
[-h, h],
|
||||||
])
|
])
|
||||||
.build()
|
.build(self.objects)
|
||||||
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let (sides, top_edges) = {
|
let (sides, top_edges) = {
|
||||||
|
@ -193,7 +194,10 @@ impl<'a> ShellBuilder<'a> {
|
||||||
.build(self.objects)
|
.build(self.objects)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Face::builder(self.objects).with_exterior(cycle).build()
|
Face::partial()
|
||||||
|
.with_exterior(cycle)
|
||||||
|
.build(self.objects)
|
||||||
|
.unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
(sides, tops)
|
(sides, tops)
|
||||||
|
@ -259,11 +263,12 @@ impl<'a> ShellBuilder<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Face::builder(self.objects)
|
Face::partial()
|
||||||
.with_exterior(
|
.with_exterior(
|
||||||
self.objects.cycles.insert(Cycle::new(edges)).unwrap(),
|
self.objects.cycles.insert(Cycle::new(edges)).unwrap(),
|
||||||
)
|
)
|
||||||
.build()
|
.build(self.objects)
|
||||||
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.faces.extend([bottom]);
|
self.faces.extend([bottom]);
|
||||||
|
|
|
@ -2,9 +2,12 @@ use fj_math::Point;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Face, FaceSet, Objects, Sketch, Surface},
|
objects::{Face, FaceSet, Objects, Sketch, Surface},
|
||||||
|
partial::HasPartial,
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::FaceBuilder;
|
||||||
|
|
||||||
/// API for building a [`Sketch`]
|
/// API for building a [`Sketch`]
|
||||||
///
|
///
|
||||||
/// Also see [`Sketch::builder`].
|
/// Also see [`Sketch::builder`].
|
||||||
|
@ -44,10 +47,11 @@ impl<'a> SketchBuilder<'a> {
|
||||||
.surface
|
.surface
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("Can't build `Sketch` without `Surface`");
|
.expect("Can't build `Sketch` without `Surface`");
|
||||||
self.faces.extend([Face::builder(self.objects)
|
self.faces.extend([Face::partial()
|
||||||
.with_surface(surface.clone())
|
.with_surface(surface.clone())
|
||||||
.with_exterior_polygon_from_points(points)
|
.with_exterior_polygon_from_points(points)
|
||||||
.build()]);
|
.build(self.objects)
|
||||||
|
.unwrap()]);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -360,7 +360,7 @@ impl<T> Iterator for Iter<T> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{CurveBuilder, CycleBuilder, HalfEdgeBuilder},
|
builder::{CurveBuilder, CycleBuilder, FaceBuilder, HalfEdgeBuilder},
|
||||||
objects::{
|
objects::{
|
||||||
Curve, Cycle, Face, GlobalCurve, GlobalVertex, HalfEdge, Objects,
|
Curve, Cycle, Face, GlobalCurve, GlobalVertex, HalfEdge, Objects,
|
||||||
Shell, Sketch, Solid, SurfaceVertex, Vertex,
|
Shell, Sketch, Solid, SurfaceVertex, Vertex,
|
||||||
|
@ -424,10 +424,10 @@ mod tests {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let object = Face::builder(&objects)
|
let object = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
||||||
.build();
|
.build(&objects);
|
||||||
|
|
||||||
assert_eq!(3, object.curve_iter().count());
|
assert_eq!(3, object.curve_iter().count());
|
||||||
assert_eq!(1, object.cycle_iter().count());
|
assert_eq!(1, object.cycle_iter().count());
|
||||||
|
@ -528,14 +528,14 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sketch() {
|
fn sketch() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let surface = objects.surfaces.xy_plane();
|
let surface = objects.surfaces.xy_plane();
|
||||||
let face = Face::builder(&objects)
|
let face = Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
.with_exterior_polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let object = Sketch::builder(&objects).with_faces([face]).build();
|
let object = Sketch::builder(&objects).with_faces([face]).build();
|
||||||
|
|
||||||
assert_eq!(3, object.curve_iter().count());
|
assert_eq!(3, object.curve_iter().count());
|
||||||
|
@ -549,6 +549,8 @@ mod tests {
|
||||||
assert_eq!(0, object.solid_iter().count());
|
assert_eq!(0, object.solid_iter().count());
|
||||||
assert_eq!(1, object.surface_iter().count());
|
assert_eq!(1, object.surface_iter().count());
|
||||||
assert_eq!(6, object.vertex_iter().count());
|
assert_eq!(6, object.vertex_iter().count());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::collections::{btree_set, BTreeSet};
|
||||||
use fj_interop::mesh::Color;
|
use fj_interop::mesh::Color;
|
||||||
use fj_math::Winding;
|
use fj_math::Winding;
|
||||||
|
|
||||||
use crate::{builder::FaceBuilder, storage::Handle};
|
use crate::storage::Handle;
|
||||||
|
|
||||||
use super::{Cycle, Objects, Surface};
|
use super::{Cycle, Surface};
|
||||||
|
|
||||||
/// A face of a shape
|
/// A face of a shape
|
||||||
///
|
///
|
||||||
|
@ -39,17 +39,6 @@ pub struct Face {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Face {
|
impl Face {
|
||||||
/// Build a `Face` using [`FaceBuilder`]
|
|
||||||
pub fn builder(objects: &Objects) -> FaceBuilder {
|
|
||||||
FaceBuilder {
|
|
||||||
objects,
|
|
||||||
surface: None,
|
|
||||||
exterior: None,
|
|
||||||
interiors: Vec::new(),
|
|
||||||
color: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a new instance of `Face`
|
/// Construct a new instance of `Face`
|
||||||
pub fn new(
|
pub fn new(
|
||||||
exterior: Handle<Cycle>,
|
exterior: Handle<Cycle>,
|
||||||
|
|
|
@ -45,6 +45,7 @@ pub use self::{
|
||||||
curve::{PartialCurve, PartialGlobalCurve},
|
curve::{PartialCurve, PartialGlobalCurve},
|
||||||
cycle::PartialCycle,
|
cycle::PartialCycle,
|
||||||
edge::{PartialGlobalEdge, PartialHalfEdge},
|
edge::{PartialGlobalEdge, PartialHalfEdge},
|
||||||
|
face::PartialFace,
|
||||||
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
|
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
|
||||||
},
|
},
|
||||||
traits::{HasPartial, Partial},
|
traits::{HasPartial, Partial},
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
use fj_interop::mesh::Color;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
objects::{Cycle, Face, Objects, Surface},
|
||||||
|
partial::{util::merge_options, MaybePartial},
|
||||||
|
storage::Handle,
|
||||||
|
validate::ValidationError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A partial [`Face`]
|
||||||
|
///
|
||||||
|
/// See [`crate::partial`] for more information.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct PartialFace {
|
||||||
|
surface: Option<Handle<Surface>>,
|
||||||
|
exterior: MaybePartial<Cycle>,
|
||||||
|
interiors: Vec<MaybePartial<Cycle>>,
|
||||||
|
color: Option<Color>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialFace {
|
||||||
|
/// Access th surface that the [`Face`] is defined in
|
||||||
|
pub fn surface(&self) -> Option<Handle<Surface>> {
|
||||||
|
self.surface.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the [`Face`]'s exterior cycle
|
||||||
|
pub fn exterior(&self) -> MaybePartial<Cycle> {
|
||||||
|
self.exterior.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the [`Face`]'s interior cycles
|
||||||
|
pub fn interiors(&self) -> impl Iterator<Item = MaybePartial<Cycle>> + '_ {
|
||||||
|
self.interiors.iter().cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the color of the [`Face`]
|
||||||
|
pub fn color(&self) -> Option<Color> {
|
||||||
|
self.color
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the [`Face`] with the provided surface
|
||||||
|
pub fn with_surface(mut self, surface: Handle<Surface>) -> Self {
|
||||||
|
self.surface = Some(surface);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the [`Face`] with the provided exterior
|
||||||
|
pub fn with_exterior(
|
||||||
|
mut self,
|
||||||
|
exterior: impl Into<MaybePartial<Cycle>>,
|
||||||
|
) -> Self {
|
||||||
|
self.exterior = exterior.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the [`Face`] with the provided interior polygons
|
||||||
|
pub fn with_interiors(
|
||||||
|
mut self,
|
||||||
|
interiors: impl IntoIterator<Item = impl Into<MaybePartial<Cycle>>>,
|
||||||
|
) -> Self {
|
||||||
|
let interiors = interiors.into_iter().map(Into::into);
|
||||||
|
self.interiors.extend(interiors);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the [`Face`] with the provided color
|
||||||
|
pub fn with_color(mut self, color: Color) -> Self {
|
||||||
|
self.color = Some(color);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge this partial object with another
|
||||||
|
pub fn merge_with(self, other: Self) -> Self {
|
||||||
|
let mut interiors = self.interiors;
|
||||||
|
interiors.extend(other.interiors);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
surface: merge_options(self.surface, other.surface),
|
||||||
|
exterior: self.exterior.merge_with(other.exterior),
|
||||||
|
interiors,
|
||||||
|
color: merge_options(self.color, other.color),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a polygon from a list of points
|
||||||
|
pub fn build(
|
||||||
|
self,
|
||||||
|
objects: &Objects,
|
||||||
|
) -> Result<Handle<Face>, ValidationError> {
|
||||||
|
let exterior = self.exterior.into_full(objects)?;
|
||||||
|
let interiors = self
|
||||||
|
.interiors
|
||||||
|
.into_iter()
|
||||||
|
.map(|cycle| cycle.into_full(objects))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
let color = self.color.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(objects
|
||||||
|
.faces
|
||||||
|
.insert(Face::new(exterior, interiors, color))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Face> for PartialFace {
|
||||||
|
fn from(face: &Face) -> Self {
|
||||||
|
Self {
|
||||||
|
surface: Some(face.surface().clone()),
|
||||||
|
exterior: face.exterior().clone().into(),
|
||||||
|
interiors: face.interiors().cloned().map(Into::into).collect(),
|
||||||
|
color: Some(face.color()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,19 @@
|
||||||
pub mod curve;
|
pub mod curve;
|
||||||
pub mod cycle;
|
pub mod cycle;
|
||||||
pub mod edge;
|
pub mod edge;
|
||||||
|
pub mod face;
|
||||||
pub mod vertex;
|
pub mod vertex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
Curve, Cycle, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects,
|
Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge,
|
||||||
SurfaceVertex, Vertex,
|
Objects, SurfaceVertex, Vertex,
|
||||||
},
|
},
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
HasPartial, MaybePartial, Partial, PartialCurve, PartialCycle,
|
HasPartial, MaybePartial, Partial, PartialCurve, PartialCycle, PartialFace,
|
||||||
PartialGlobalCurve, PartialGlobalEdge, PartialGlobalVertex,
|
PartialGlobalCurve, PartialGlobalEdge, PartialGlobalVertex,
|
||||||
PartialHalfEdge, PartialSurfaceVertex, PartialVertex,
|
PartialHalfEdge, PartialSurfaceVertex, PartialVertex,
|
||||||
};
|
};
|
||||||
|
@ -53,6 +54,7 @@ macro_rules! impl_traits {
|
||||||
impl_traits!(
|
impl_traits!(
|
||||||
Curve, PartialCurve;
|
Curve, PartialCurve;
|
||||||
Cycle, PartialCycle;
|
Cycle, PartialCycle;
|
||||||
|
Face, PartialFace;
|
||||||
GlobalCurve, PartialGlobalCurve;
|
GlobalCurve, PartialGlobalCurve;
|
||||||
GlobalEdge, PartialGlobalEdge;
|
GlobalEdge, PartialGlobalEdge;
|
||||||
GlobalVertex, PartialGlobalVertex;
|
GlobalVertex, PartialGlobalVertex;
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl FaceValidationError {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::reverse::Reverse,
|
algorithms::reverse::Reverse,
|
||||||
builder::CycleBuilder,
|
builder::{CycleBuilder, FaceBuilder},
|
||||||
objects::{Cycle, Face, Objects},
|
objects::{Cycle, Face, Objects},
|
||||||
partial::HasPartial,
|
partial::HasPartial,
|
||||||
validate::Validate,
|
validate::Validate,
|
||||||
|
@ -115,11 +115,11 @@ mod tests {
|
||||||
fn face_surface_mismatch() -> anyhow::Result<()> {
|
fn face_surface_mismatch() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let valid = Face::builder(&objects)
|
let valid = Face::partial()
|
||||||
.with_surface(objects.surfaces.xy_plane())
|
.with_surface(objects.surfaces.xy_plane())
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [3., 0.], [0., 3.]])
|
.with_exterior_polygon_from_points([[0., 0.], [3., 0.], [0., 3.]])
|
||||||
.with_interior_polygon_from_points([[1., 1.], [1., 2.], [2., 1.]])
|
.with_interior_polygon_from_points([[1., 1.], [1., 2.], [2., 1.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let invalid = {
|
let invalid = {
|
||||||
let interiors = [Cycle::partial()
|
let interiors = [Cycle::partial()
|
||||||
.with_poly_chain_from_points(
|
.with_poly_chain_from_points(
|
||||||
|
@ -142,11 +142,11 @@ mod tests {
|
||||||
fn face_invalid_interior_winding() -> anyhow::Result<()> {
|
fn face_invalid_interior_winding() -> anyhow::Result<()> {
|
||||||
let objects = Objects::new();
|
let objects = Objects::new();
|
||||||
|
|
||||||
let valid = Face::builder(&objects)
|
let valid = Face::partial()
|
||||||
.with_surface(objects.surfaces.xy_plane())
|
.with_surface(objects.surfaces.xy_plane())
|
||||||
.with_exterior_polygon_from_points([[0., 0.], [3., 0.], [0., 3.]])
|
.with_exterior_polygon_from_points([[0., 0.], [3., 0.], [0., 3.]])
|
||||||
.with_interior_polygon_from_points([[1., 1.], [1., 2.], [2., 1.]])
|
.with_interior_polygon_from_points([[1., 1.], [1., 2.], [2., 1.]])
|
||||||
.build();
|
.build(&objects)?;
|
||||||
let invalid = {
|
let invalid = {
|
||||||
let interiors = valid
|
let interiors = valid
|
||||||
.interiors()
|
.interiors()
|
||||||
|
|
|
@ -5,6 +5,7 @@ use fj_kernel::{
|
||||||
algorithms::reverse::Reverse,
|
algorithms::reverse::Reverse,
|
||||||
iter::ObjectIters,
|
iter::ObjectIters,
|
||||||
objects::{Face, Objects, Sketch},
|
objects::{Face, Objects, Sketch},
|
||||||
|
partial::HasPartial,
|
||||||
validate::ValidationError,
|
validate::ValidationError,
|
||||||
};
|
};
|
||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
@ -78,11 +79,11 @@ impl Shape for fj::Difference2d {
|
||||||
);
|
);
|
||||||
|
|
||||||
faces.push(
|
faces.push(
|
||||||
Face::builder(objects)
|
Face::partial()
|
||||||
.with_exterior(exterior)
|
.with_exterior(exterior)
|
||||||
.with_interiors(interiors)
|
.with_interiors(interiors)
|
||||||
.with_color(Color(self.color()))
|
.with_color(Color(self.color()))
|
||||||
.build(),
|
.build(objects)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::ops::Deref;
|
||||||
|
|
||||||
use fj_interop::{debug::DebugInfo, mesh::Color};
|
use fj_interop::{debug::DebugInfo, mesh::Color};
|
||||||
use fj_kernel::{
|
use fj_kernel::{
|
||||||
builder::HalfEdgeBuilder,
|
builder::{FaceBuilder, HalfEdgeBuilder},
|
||||||
objects::{Cycle, Face, HalfEdge, Objects, Sketch},
|
objects::{Cycle, Face, HalfEdge, Objects, Sketch},
|
||||||
partial::HasPartial,
|
partial::HasPartial,
|
||||||
validate::ValidationError,
|
validate::ValidationError,
|
||||||
|
@ -32,20 +32,20 @@ impl Shape for fj::Sketch {
|
||||||
.build(objects)?;
|
.build(objects)?;
|
||||||
let cycle = objects.cycles.insert(Cycle::new([half_edge]))?;
|
let cycle = objects.cycles.insert(Cycle::new([half_edge]))?;
|
||||||
|
|
||||||
Face::builder(objects)
|
Face::partial()
|
||||||
.with_exterior(cycle)
|
.with_exterior(cycle)
|
||||||
.with_color(Color(self.color()))
|
.with_color(Color(self.color()))
|
||||||
.build()
|
.build(objects)?
|
||||||
}
|
}
|
||||||
fj::Chain::PolyChain(poly_chain) => {
|
fj::Chain::PolyChain(poly_chain) => {
|
||||||
let points =
|
let points =
|
||||||
poly_chain.to_points().into_iter().map(Point::from);
|
poly_chain.to_points().into_iter().map(Point::from);
|
||||||
|
|
||||||
Face::builder(objects)
|
Face::partial()
|
||||||
.with_surface(surface)
|
.with_surface(surface)
|
||||||
.with_exterior_polygon_from_points(points)
|
.with_exterior_polygon_from_points(points)
|
||||||
.with_color(Color(self.color()))
|
.with_color(Color(self.color()))
|
||||||
.build()
|
.build(objects)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue