Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Prepare HalfEdgeBuilder for HalfEdge/PartialHalfEdge unification #1662

Merged
merged 43 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b2830a4
Make trait method more convenient to call
hannobraun Mar 9, 2023
37e1689
Update variable names
hannobraun Mar 9, 2023
b936c4f
Return curve from `HalfEdgeBuilder::update_as_arc`
hannobraun Mar 9, 2023
857adb2
Merge variables
hannobraun Mar 9, 2023
73b313c
Remove needless allocation
hannobraun Mar 9, 2023
72b6086
Consolidate redundant code
hannobraun Mar 9, 2023
889f4a5
Simplify `CycleBuilder::add_half_edge`
hannobraun Mar 9, 2023
2c0a7d4
Remove redundant return value
hannobraun Mar 9, 2023
3b84e73
Add `HalfEdgeBuilder::make_circle`
hannobraun Mar 9, 2023
0a68de0
Simplify `PartialHalfEdge` construction
hannobraun Mar 9, 2023
a4d10c2
Update variable name
hannobraun Mar 9, 2023
629bfde
Update variable name
hannobraun Mar 9, 2023
f957f5b
Prepare code for follow-on change
hannobraun Mar 9, 2023
4150187
Add `HalfEdgeBuilder::make_arc`
hannobraun Mar 9, 2023
fcc3412
Update variable name
hannobraun Mar 9, 2023
632f0b4
Refactor
hannobraun Mar 9, 2023
7ceb38f
Move code to prepare for follow-on change
hannobraun Mar 9, 2023
6bb5b6a
Make variable name more accurate
hannobraun Mar 9, 2023
b66c957
Refactor code to simplify it
hannobraun Mar 9, 2023
678dfeb
Remove comment
hannobraun Mar 9, 2023
8c609f8
Update variable names
hannobraun Mar 9, 2023
2a80634
Refactor to prepare for follow-on change
hannobraun Mar 9, 2023
4e89719
Refactor to prepare for follow-on change
hannobraun Mar 9, 2023
460c7d9
Prepare builder method for change to constructor
hannobraun Mar 9, 2023
b60cfa6
Prepare builder method for change to constructor
hannobraun Mar 9, 2023
2ab9121
Simplify trait method arguments
hannobraun Mar 9, 2023
4fa5bc9
Merge variables
hannobraun Mar 9, 2023
af90851
Simplify builder method
hannobraun Mar 9, 2023
5e06c95
Update variable name
hannobraun Mar 9, 2023
037718a
Refactor code to simplify it
hannobraun Mar 9, 2023
fdcde32
Refactor code to simplify it
hannobraun Mar 9, 2023
9b1d0e1
Refactor code to simplify it
hannobraun Mar 9, 2023
5250203
Add `ObjectArguments::map_with_next`
hannobraun Mar 9, 2023
68d7e45
Make trait method more convenient to call
hannobraun Mar 9, 2023
ebfa61c
Simplify builder method
hannobraun Mar 9, 2023
b019e82
Add `HalfEdgeBuilder::make_line_segment`
hannobraun Mar 9, 2023
7f72057
Update variable name
hannobraun Mar 9, 2023
428ab91
Simplify variable name
hannobraun Mar 9, 2023
b421863
Refactor code to simplify it
hannobraun Mar 9, 2023
0a0f971
Make builder method more flexible
hannobraun Mar 9, 2023
f2d6eb9
Make builder method more flexible
hannobraun Mar 9, 2023
356f7d1
Update doc comments
hannobraun Mar 9, 2023
6c2e50d
Add `HalfEdgeBuilder::make_half_edge`
hannobraun Mar 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions crates/fj-kernel/src/algorithms/approx/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,8 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xz_plane();
let half_edge = {
let mut half_edge = PartialHalfEdge::new(&mut services.objects);

half_edge.update_as_circle_from_radius(1.);

half_edge
.build(&mut services.objects)
.insert(&mut services.objects)
};
let half_edge = PartialHalfEdge::make_circle(1., &mut services.objects)
.build(&mut services.objects);

let tolerance = 1.;
let approx = (&half_edge, surface.deref()).approx(tolerance);
Expand Down
96 changes: 35 additions & 61 deletions crates/fj-kernel/src/algorithms/sweep/edge.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use fj_interop::{ext::ArrayExt, mesh::Color};
use fj_math::{Point, Scalar, Vector};
use itertools::Itertools;

use crate::{
builder::{CycleBuilder, HalfEdgeBuilder},
insert::Insert,
objects::{Face, HalfEdge, Objects, Surface, Vertex},
partial::{PartialFace, PartialObject},
partial::{PartialFace, PartialHalfEdge, PartialObject},
services::Service,
storage::Handle,
};
Expand Down Expand Up @@ -36,30 +35,27 @@ impl Sweep for (Handle<HalfEdge>, &Handle<Vertex>, &Surface, Color) {
(edge.curve(), surface).sweep_with_cache(path, cache, objects),
);

// Now we're ready to create the edges.
let mut edge_bottom = face.exterior.write().add_half_edge(objects);
let mut edge_up = face.exterior.write().add_half_edge(objects);
let mut edge_top = face.exterior.write().add_half_edge(objects);
let mut edge_down = face.exterior.write().add_half_edge(objects);

// Those edges aren't fully defined yet. We'll do that shortly, but
// first we have to figure a few things out.
//
// Let's start with the global vertices and edges.
let (global_vertices, global_edges) = {
// Next, we need to define the boundaries of the face. Let's start with
// the global vertices and edges.
let (vertices, global_edges) = {
let [a, b] = [edge.start_vertex(), next_vertex].map(Clone::clone);
let (edge_right, [_, c]) =
let (edge_up, [_, c]) =
b.clone().sweep_with_cache(path, cache, objects);
let (edge_left, [_, d]) =
let (edge_down, [_, d]) =
a.clone().sweep_with_cache(path, cache, objects);

(
[a, b, c, d],
[edge.global_form().clone(), edge_right, edge_left],
[
Some(edge.global_form().clone()),
Some(edge_up),
Some(edge_down),
None,
],
)
};

// Next, let's figure out the surface coordinates of the edge vertices.
// Let's figure out the surface coordinates of the edge vertices.
let surface_points = {
let [a, b] = edge.boundary();

Expand All @@ -71,6 +67,11 @@ impl Sweep for (Handle<HalfEdge>, &Handle<Vertex>, &Surface, Color) {
]
.map(Point::from)
};
let surface_points_next = {
let mut points = surface_points;
points.rotate_left(1);
points
};

// Now, the boundaries of each edge.
let boundaries = {
Expand All @@ -80,51 +81,24 @@ impl Sweep for (Handle<HalfEdge>, &Handle<Vertex>, &Surface, Color) {
[[a, b], [c, d], [b, a], [d, c]]
};

// Armed with all of that, we can set the edge's vertices.
[
edge_bottom.write(),
edge_up.write(),
edge_top.write(),
edge_down.write(),
]
.zip_ext(boundaries)
.zip_ext(global_vertices)
.map(|((mut half_edge, boundary), global_vertex)| {
for (a, b) in half_edge.boundary.each_mut_ext().zip_ext(boundary) {
*a = Some(b);
}

// Writing to the start vertices is enough. Neighboring half-
// edges share surface vertices, so writing the start vertex of
// each half-edge writes to all vertices.
half_edge.start_vertex = global_vertex;
});

// With the vertices set, we can now update the curves.
//
// Those are all line segments. For the bottom and top curve, because
// even if the original edge was a circle, it's still going to be a line
// when projected into the new surface. For the side edges, because
// we're sweeping along a straight path.
for ((mut half_edge, start), (_, end)) in [
edge_bottom.clone(),
edge_up.clone(),
edge_top.clone(),
edge_down.clone(),
]
.zip_ext(surface_points)
.into_iter()
.circular_tuple_windows()
{
half_edge.write().update_as_line_segment(start, end);
}

// Finally, we can make sure that all edges refer to the correct global
// edges.
[edge_bottom.write(), edge_up.write(), edge_down.write()]
// Armed with all of that, we're ready to create the edges.
let [_edge_bottom, _edge_up, edge_top, _edge_down] = boundaries
.zip_ext(surface_points)
.zip_ext(surface_points_next)
.zip_ext(vertices)
.zip_ext(global_edges)
.map(|(mut half_edge, global_edge)| {
half_edge.global_form = global_edge;
.map(|((((boundary, start), end), start_vertex), global_edge)| {
let half_edge = PartialHalfEdge::make_line_segment(
[start, end],
Some(boundary),
Some(start_vertex),
global_edge,
objects,
);

face.exterior.write().add_half_edge(half_edge.clone());

half_edge
});

// And we're done creating the face! All that's left to do is build our
Expand Down
50 changes: 21 additions & 29 deletions crates/fj-kernel/src/builder/cycle.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use fj_math::Point;
use itertools::Itertools;

use crate::{
objects::{HalfEdge, Objects},
partial::{Partial, PartialCycle},
partial::{Partial, PartialCycle, PartialHalfEdge},
services::Service,
};

Expand All @@ -20,10 +19,7 @@ pub trait CycleBuilder {
///
/// If this is the first half-edge being added, it is connected to itself,
/// meaning its front and back vertices are the same.
fn add_half_edge(
&mut self,
objects: &mut Service<Objects>,
) -> Partial<HalfEdge>;
fn add_half_edge(&mut self, half_edge: Partial<HalfEdge>);

/// Update cycle as a polygon from the provided points
fn update_as_polygon_from_points<O, P>(
Expand All @@ -33,7 +29,7 @@ pub trait CycleBuilder {
) -> O::SameSize<Partial<HalfEdge>>
where
O: ObjectArgument<P>,
P: Into<Point<2>>;
P: Clone + Into<Point<2>>;

/// Connect the cycles to the provided half-edges
///
Expand All @@ -51,13 +47,8 @@ pub trait CycleBuilder {
}

impl CycleBuilder for PartialCycle {
fn add_half_edge(
&mut self,
objects: &mut Service<Objects>,
) -> Partial<HalfEdge> {
let half_edge = Partial::new(objects);
self.half_edges.push(half_edge.clone());
half_edge
fn add_half_edge(&mut self, half_edge: Partial<HalfEdge>) {
self.half_edges.push(half_edge);
}

fn update_as_polygon_from_points<O, P>(
Expand All @@ -67,23 +58,21 @@ impl CycleBuilder for PartialCycle {
) -> O::SameSize<Partial<HalfEdge>>
where
O: ObjectArgument<P>,
P: Into<Point<2>>,
P: Clone + Into<Point<2>>,
{
let mut start_positions = Vec::new();
let half_edges = points.map(|point| {
start_positions.push(point.into());
self.add_half_edge(objects)
});
points.map_with_next(|start, end| {
let half_edge = PartialHalfEdge::make_line_segment(
[start, end],
None,
None,
None,
objects,
);

for ((start, end), half_edge) in start_positions
.into_iter()
.circular_tuple_windows()
.zip(&mut self.half_edges)
{
half_edge.write().update_as_line_segment(start, end);
}
self.add_half_edge(half_edge.clone());

half_edges
half_edge
})
}

fn connect_to_edges<O>(
Expand All @@ -95,8 +84,11 @@ impl CycleBuilder for PartialCycle {
O: ObjectArgument<Partial<HalfEdge>>,
{
edges.map_with_prev(|_, prev| {
let mut edge = self.add_half_edge(objects);
let mut edge: Partial<HalfEdge> = Partial::new(objects);
edge.write().start_vertex = prev.read().start_vertex.clone();

self.add_half_edge(edge.clone());

edge
})
}
Expand Down
Loading