Don't structure fills around the even-odd rule.
Improves self-intersecting paths under the winding rule.
This commit is contained in:
parent
4ac11e9010
commit
a126e1248e
|
@ -188,9 +188,7 @@ impl<'a> Partitioner<'a> {
|
||||||
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
|
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
|
||||||
|
|
||||||
let endpoint = &self.endpoints[endpoint_index as usize];
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
||||||
if self.should_fill_above_active_edge(next_active_edge_index) {
|
self.emit_b_quad(next_active_edge_index, endpoint.position.x);
|
||||||
self.emit_b_quad_above(next_active_edge_index, endpoint.position.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index);
|
self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index);
|
||||||
|
|
||||||
|
@ -208,12 +206,8 @@ impl<'a> Partitioner<'a> {
|
||||||
debug!("... REGULAR point: active edge {}", active_edge_index);
|
debug!("... REGULAR point: active edge {}", active_edge_index);
|
||||||
|
|
||||||
let endpoint = &self.endpoints[endpoint_index as usize];
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
||||||
let bottom = self.should_fill_above_active_edge(active_edge_index);
|
let bottom = self.emit_b_quad(active_edge_index, endpoint.position.x) ==
|
||||||
if !bottom {
|
BQuadEmissionResult::BQuadEmittedAbove;
|
||||||
self.emit_b_quad_below(active_edge_index, endpoint.position.x)
|
|
||||||
} else {
|
|
||||||
self.emit_b_quad_above(active_edge_index, endpoint.position.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
||||||
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
|
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
|
||||||
|
@ -281,15 +275,8 @@ impl<'a> Partitioner<'a> {
|
||||||
|
|
||||||
let endpoint = &self.endpoints[endpoint_index as usize];
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
||||||
|
|
||||||
if self.should_fill_above_active_edge(active_edge_indices[0]) {
|
self.emit_b_quad(active_edge_indices[0], endpoint.position.x);
|
||||||
self.emit_b_quad_above(active_edge_indices[0], endpoint.position.x)
|
self.emit_b_quad(active_edge_indices[1], endpoint.position.x);
|
||||||
}
|
|
||||||
if self.should_fill_above_active_edge(active_edge_indices[1]) {
|
|
||||||
self.emit_b_quad_above(active_edge_indices[1], endpoint.position.x)
|
|
||||||
}
|
|
||||||
if self.should_fill_below_active_edge(active_edge_indices[1]) {
|
|
||||||
self.emit_b_quad_below(active_edge_indices[1], endpoint.position.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.heap.pop();
|
self.heap.pop();
|
||||||
|
|
||||||
|
@ -312,15 +299,10 @@ impl<'a> Partitioner<'a> {
|
||||||
|
|
||||||
if let Some(crossing_point) =
|
if let Some(crossing_point) =
|
||||||
self.crossing_point_for_active_edge(upper_active_edge_index) {
|
self.crossing_point_for_active_edge(upper_active_edge_index) {
|
||||||
if self.should_fill_above_active_edge(upper_active_edge_index) {
|
debug!("found SELF-INTERSECTION point for active edges {} & {}",
|
||||||
self.emit_b_quad_above(upper_active_edge_index, crossing_point.x)
|
upper_active_edge_index,
|
||||||
}
|
lower_active_edge_index);
|
||||||
if self.should_fill_above_active_edge(lower_active_edge_index) {
|
self.emit_b_quad(lower_active_edge_index, crossing_point.x);
|
||||||
self.emit_b_quad_above(lower_active_edge_index, crossing_point.x)
|
|
||||||
}
|
|
||||||
if self.should_fill_above_active_edge(lower_active_edge_index + 1) {
|
|
||||||
self.emit_b_quad_below(lower_active_edge_index, crossing_point.x)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active_edges.swap(upper_active_edge_index as usize,
|
self.active_edges.swap(upper_active_edge_index as usize,
|
||||||
|
@ -476,83 +458,73 @@ impl<'a> Partitioner<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_fill_below_active_edge(&self, active_edge_index: u32) -> bool {
|
fn bounding_active_edges_for_fill(&self, active_edge_index: u32) -> (u32, u32) {
|
||||||
if (active_edge_index as usize) + 1 == self.active_edges.len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.fill_rule {
|
match self.fill_rule {
|
||||||
FillRule::EvenOdd => active_edge_index % 2 == 0,
|
FillRule::EvenOdd if active_edge_index % 2 == 1 => {
|
||||||
FillRule::Winding => self.winding_number_below_active_edge(active_edge_index) != 0,
|
(active_edge_index - 1, active_edge_index)
|
||||||
|
}
|
||||||
|
FillRule::EvenOdd if (active_edge_index as usize) + 1 == self.active_edges.len() => {
|
||||||
|
(active_edge_index, active_edge_index)
|
||||||
|
}
|
||||||
|
FillRule::EvenOdd => (active_edge_index, active_edge_index + 1),
|
||||||
|
|
||||||
|
FillRule::Winding => {
|
||||||
|
let (mut winding_number, mut upper_active_edge_index) = (0, 0);
|
||||||
|
for (active_edge_index, active_edge) in
|
||||||
|
self.active_edges[0..active_edge_index as usize].iter().enumerate() {
|
||||||
|
if winding_number == 0 {
|
||||||
|
upper_active_edge_index = active_edge_index as u32
|
||||||
|
}
|
||||||
|
winding_number += active_edge.winding_number()
|
||||||
|
}
|
||||||
|
if winding_number == 0 {
|
||||||
|
upper_active_edge_index = active_edge_index as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lower_active_edge_index = active_edge_index;
|
||||||
|
for (active_edge_index, active_edge) in
|
||||||
|
self.active_edges.iter().enumerate().skip(active_edge_index as usize) {
|
||||||
|
winding_number += active_edge.winding_number();
|
||||||
|
if winding_number == 0 {
|
||||||
|
lower_active_edge_index = active_edge_index as u32;
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_fill_above_active_edge(&self, active_edge_index: u32) -> bool {
|
(upper_active_edge_index, lower_active_edge_index)
|
||||||
active_edge_index > 0 && self.should_fill_below_active_edge(active_edge_index - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn winding_number_above_active_edge(&self, active_edge_index: u32) -> i32 {
|
|
||||||
if active_edge_index == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
self.winding_number_below_active_edge(active_edge_index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn winding_number_below_active_edge(&self, active_edge_index: u32) -> i32 {
|
|
||||||
let mut winding_number = 0;
|
|
||||||
for active_edge_index in 0..(active_edge_index as usize + 1) {
|
|
||||||
if self.active_edges[active_edge_index].left_to_right {
|
|
||||||
winding_number += 1
|
|
||||||
} else {
|
|
||||||
winding_number -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
winding_number
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_b_quad_below(&mut self, upper_active_edge_index: u32, right_x: f32) {
|
|
||||||
let mut lower_active_edge_index = upper_active_edge_index + 1;
|
|
||||||
|
|
||||||
if self.fill_rule == FillRule::Winding {
|
|
||||||
let active_edge_count = self.active_edges.len() as u32;
|
|
||||||
let mut winding_number =
|
|
||||||
self.winding_number_below_active_edge(lower_active_edge_index);
|
|
||||||
while lower_active_edge_index + 1 < active_edge_count && winding_number != 0 {
|
|
||||||
lower_active_edge_index += 1;
|
|
||||||
if self.active_edges[lower_active_edge_index as usize].left_to_right {
|
|
||||||
winding_number += 1
|
|
||||||
} else {
|
|
||||||
winding_number -= 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_b_quad_above(lower_active_edge_index, right_x)
|
fn emit_b_quad(&mut self, active_edge_index: u32, right_x: f32) -> BQuadEmissionResult {
|
||||||
|
if (active_edge_index as usize) >= self.active_edges.len() {
|
||||||
|
return BQuadEmissionResult::NoBQuadEmitted
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_b_quad_above(&mut self, lower_active_edge_index: u32, right_x: f32) {
|
|
||||||
// TODO(pcwalton): Assert that the green X position is the same on both edges.
|
// TODO(pcwalton): Assert that the green X position is the same on both edges.
|
||||||
debug_assert!(lower_active_edge_index > 0,
|
let (upper_active_edge_index, lower_active_edge_index) =
|
||||||
"Can't emit b_quads above the top active edge");
|
self.bounding_active_edges_for_fill(active_edge_index);
|
||||||
|
debug!("... bounding active edges for fill = [{},{}] around {}",
|
||||||
|
upper_active_edge_index,
|
||||||
|
lower_active_edge_index,
|
||||||
|
active_edge_index);
|
||||||
|
|
||||||
let mut upper_active_edge_index = lower_active_edge_index - 1;
|
let emission_result = BQuadEmissionResult::new(active_edge_index,
|
||||||
|
upper_active_edge_index,
|
||||||
if self.fill_rule == FillRule::Winding {
|
lower_active_edge_index);
|
||||||
let mut winding_number =
|
if emission_result == BQuadEmissionResult::NoBQuadEmitted {
|
||||||
self.winding_number_above_active_edge(upper_active_edge_index);
|
return emission_result
|
||||||
while upper_active_edge_index > 0 && winding_number != 0 {
|
|
||||||
upper_active_edge_index -= 1;
|
|
||||||
if self.active_edges[upper_active_edge_index as usize].left_to_right {
|
|
||||||
winding_number -= 1
|
|
||||||
} else {
|
|
||||||
winding_number += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let upper_curve = self.subdivide_active_edge_at(upper_active_edge_index, right_x);
|
let upper_curve = self.subdivide_active_edge_at(upper_active_edge_index,
|
||||||
let lower_curve = self.subdivide_active_edge_at(lower_active_edge_index, right_x);
|
right_x,
|
||||||
|
SubdivisionType::Upper);
|
||||||
|
for active_edge_index in (upper_active_edge_index + 1)..lower_active_edge_index {
|
||||||
|
self.subdivide_active_edge_at(active_edge_index, right_x, SubdivisionType::Inside);
|
||||||
|
}
|
||||||
|
let lower_curve = self.subdivide_active_edge_at(lower_active_edge_index,
|
||||||
|
right_x,
|
||||||
|
SubdivisionType::Lower);
|
||||||
|
|
||||||
let upper_shape = upper_curve.shape(&self.b_vertex_loop_blinn_data);
|
let upper_shape = upper_curve.shape(&self.b_vertex_loop_blinn_data);
|
||||||
let lower_shape = lower_curve.shape(&self.b_vertex_loop_blinn_data);
|
let lower_shape = lower_curve.shape(&self.b_vertex_loop_blinn_data);
|
||||||
|
@ -706,7 +678,9 @@ impl<'a> Partitioner<'a> {
|
||||||
upper_curve.middle_point,
|
upper_curve.middle_point,
|
||||||
lower_curve.left_curve_left,
|
lower_curve.left_curve_left,
|
||||||
lower_curve.left_curve_control_point,
|
lower_curve.left_curve_control_point,
|
||||||
lower_curve.middle_point))
|
lower_curve.middle_point));
|
||||||
|
|
||||||
|
emission_result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn already_visited_point(&self, point: &Point) -> bool {
|
fn already_visited_point(&self, point: &Point) -> bool {
|
||||||
|
@ -875,11 +849,14 @@ impl<'a> Partitioner<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subdivide_active_edge_at(&mut self, active_edge_index: u32, x: f32)
|
fn subdivide_active_edge_at(&mut self,
|
||||||
|
active_edge_index: u32,
|
||||||
|
x: f32,
|
||||||
|
subdivision_type: SubdivisionType)
|
||||||
-> SubdividedActiveEdge {
|
-> SubdividedActiveEdge {
|
||||||
let t = self.solve_active_edge_t_for_x(x, &self.active_edges[active_edge_index as usize]);
|
let t = self.solve_active_edge_t_for_x(x, &self.active_edges[active_edge_index as usize]);
|
||||||
|
|
||||||
let bottom = self.should_fill_above_active_edge(active_edge_index);
|
let bottom = subdivision_type == SubdivisionType::Lower;
|
||||||
|
|
||||||
let active_edge = &mut self.active_edges[active_edge_index as usize];
|
let active_edge = &mut self.active_edges[active_edge_index as usize];
|
||||||
let left_curve_left = active_edge.left_vertex_index;
|
let left_curve_left = active_edge.left_vertex_index;
|
||||||
|
@ -1135,6 +1112,15 @@ impl ActiveEdge {
|
||||||
BVertexKind::Endpoint1
|
BVertexKind::Endpoint1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn winding_number(&self) -> i32 {
|
||||||
|
if self.left_to_right {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -1176,3 +1162,33 @@ enum Shape {
|
||||||
Convex,
|
Convex,
|
||||||
Concave,
|
Concave,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
enum BQuadEmissionResult {
|
||||||
|
NoBQuadEmitted,
|
||||||
|
BQuadEmittedBelow,
|
||||||
|
BQuadEmittedAbove,
|
||||||
|
BQuadEmittedAround,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BQuadEmissionResult {
|
||||||
|
fn new(active_edge_index: u32, upper_active_edge_index: u32, lower_active_edge_index: u32)
|
||||||
|
-> BQuadEmissionResult {
|
||||||
|
if upper_active_edge_index == lower_active_edge_index {
|
||||||
|
BQuadEmissionResult::NoBQuadEmitted
|
||||||
|
} else if upper_active_edge_index == active_edge_index {
|
||||||
|
BQuadEmissionResult::BQuadEmittedBelow
|
||||||
|
} else if lower_active_edge_index == active_edge_index {
|
||||||
|
BQuadEmissionResult::BQuadEmittedAbove
|
||||||
|
} else {
|
||||||
|
BQuadEmissionResult::BQuadEmittedAround
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
enum SubdivisionType {
|
||||||
|
Upper,
|
||||||
|
Inside,
|
||||||
|
Lower,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue