Add a quick check to skip clipping when an outline is entirely inside or
outside the clip area
This commit is contained in:
parent
92421943fc
commit
f04c000cae
|
@ -541,3 +541,67 @@ impl Edge3D {
|
|||
prev.lerp(next, alpha as f32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Coarse collision detection
|
||||
|
||||
// Separating axis theorem. Requires that the polygon be convex.
|
||||
pub(crate) fn rect_is_outside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool {
|
||||
let mut outcode = Outcode::all();
|
||||
for point in polygon_points {
|
||||
if point.x() > rect.min_x() { outcode.remove(Outcode::LEFT); }
|
||||
if point.x() < rect.max_x() { outcode.remove(Outcode::RIGHT); }
|
||||
if point.y() > rect.min_y() { outcode.remove(Outcode::TOP); }
|
||||
if point.y() < rect.max_y() { outcode.remove(Outcode::BOTTOM); }
|
||||
}
|
||||
if !outcode.is_empty() {
|
||||
return true
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Check winding!
|
||||
let rect_points = [rect.origin(), rect.upper_right(), rect.lower_left(), rect.lower_right()];
|
||||
for (next_point_index, &next) in polygon_points.iter().enumerate() {
|
||||
let prev_point_index = if next_point_index == 0 {
|
||||
polygon_points.len() - 1
|
||||
} else {
|
||||
next_point_index - 1
|
||||
};
|
||||
let prev = polygon_points[prev_point_index];
|
||||
let polygon_edge_vector = next - prev;
|
||||
if rect_points.iter().all(|&rect_point| polygon_edge_vector.det(rect_point - prev) < 0.0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
// Edge equation method. Requires that the polygon be convex.
|
||||
pub(crate) fn rect_is_inside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool {
|
||||
// FIXME(pcwalton): Check winding!
|
||||
let rect_points = [rect.origin(), rect.upper_right(), rect.lower_left(), rect.lower_right()];
|
||||
for (next_point_index, &next) in polygon_points.iter().enumerate() {
|
||||
let prev_point_index = if next_point_index == 0 {
|
||||
polygon_points.len() - 1
|
||||
} else {
|
||||
next_point_index - 1
|
||||
};
|
||||
let prev = polygon_points[prev_point_index];
|
||||
let polygon_edge_vector = next - prev;
|
||||
for &rect_point in &rect_points {
|
||||
if polygon_edge_vector.det(rect_point - prev) < 0.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct Outcode: u8 {
|
||||
const LEFT = 0x01;
|
||||
const RIGHT = 0x02;
|
||||
const TOP = 0x04;
|
||||
const BOTTOM = 0x08;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::basic::point::Point2DF32;
|
|||
use crate::basic::rect::RectF32;
|
||||
use crate::basic::transform2d::Transform2DF32;
|
||||
use crate::basic::transform3d::Perspective;
|
||||
use crate::clip::{ContourPolygonClipper, ContourRectClipper};
|
||||
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
|
||||
use crate::dilation::ContourDilator;
|
||||
use crate::orientation::Orientation;
|
||||
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||
|
@ -138,7 +138,20 @@ impl Outline {
|
|||
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
||||
}
|
||||
|
||||
pub fn is_outside_polygon(&self, clip_polygon: &[Point2DF32]) -> bool {
|
||||
clip::rect_is_outside_polygon(self.bounds, clip_polygon)
|
||||
}
|
||||
|
||||
fn is_inside_polygon(&self, clip_polygon: &[Point2DF32]) -> bool {
|
||||
clip::rect_is_inside_polygon(self.bounds, clip_polygon)
|
||||
}
|
||||
|
||||
pub fn clip_against_polygon(&mut self, clip_polygon: &[Point2DF32]) {
|
||||
// Quick check.
|
||||
if self.is_inside_polygon(clip_polygon) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut new_bounds = None;
|
||||
for contour in mem::replace(&mut self.contours, vec![]) {
|
||||
let contour = ContourPolygonClipper::new(clip_polygon, contour).clip();
|
||||
|
|
|
@ -104,19 +104,27 @@ impl Scene {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn apply_render_options(&self, outline: &Outline, options: &PreparedRenderOptions) -> Outline {
|
||||
// FIXME(pcwalton): Don't clone?
|
||||
let mut outline = (*outline).clone();
|
||||
fn apply_render_options(&self, original_outline: &Outline, options: &PreparedRenderOptions)
|
||||
-> Outline {
|
||||
let mut outline;
|
||||
match options.transform {
|
||||
PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon } => {
|
||||
outline.clip_against_polygon(clip_polygon);
|
||||
outline.apply_perspective(perspective);
|
||||
if original_outline.is_outside_polygon(clip_polygon) {
|
||||
outline = Outline::new();
|
||||
} else {
|
||||
outline = (*original_outline).clone();
|
||||
outline.clip_against_polygon(clip_polygon);
|
||||
outline.apply_perspective(perspective);
|
||||
}
|
||||
}
|
||||
PreparedRenderTransform::Transform2D(ref transform) => {
|
||||
// TODO(pcwalton): Short circuit.
|
||||
outline = (*original_outline).clone();
|
||||
outline.transform(transform);
|
||||
outline.clip_against_rect(self.view_box);
|
||||
}
|
||||
PreparedRenderTransform::None => {
|
||||
outline = (*original_outline).clone();
|
||||
outline.clip_against_rect(self.view_box);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue