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)
|
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::rect::RectF32;
|
||||||
use crate::basic::transform2d::Transform2DF32;
|
use crate::basic::transform2d::Transform2DF32;
|
||||||
use crate::basic::transform3d::Perspective;
|
use crate::basic::transform3d::Perspective;
|
||||||
use crate::clip::{ContourPolygonClipper, ContourRectClipper};
|
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
|
||||||
use crate::dilation::ContourDilator;
|
use crate::dilation::ContourDilator;
|
||||||
use crate::orientation::Orientation;
|
use crate::orientation::Orientation;
|
||||||
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||||
|
@ -138,7 +138,20 @@ impl Outline {
|
||||||
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
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]) {
|
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;
|
let mut new_bounds = None;
|
||||||
for contour in mem::replace(&mut self.contours, vec![]) {
|
for contour in mem::replace(&mut self.contours, vec![]) {
|
||||||
let contour = ContourPolygonClipper::new(clip_polygon, contour).clip();
|
let contour = ContourPolygonClipper::new(clip_polygon, contour).clip();
|
||||||
|
|
|
@ -104,19 +104,27 @@ impl Scene {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_render_options(&self, outline: &Outline, options: &PreparedRenderOptions) -> Outline {
|
fn apply_render_options(&self, original_outline: &Outline, options: &PreparedRenderOptions)
|
||||||
// FIXME(pcwalton): Don't clone?
|
-> Outline {
|
||||||
let mut outline = (*outline).clone();
|
let mut outline;
|
||||||
match options.transform {
|
match options.transform {
|
||||||
PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon } => {
|
PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon } => {
|
||||||
|
if original_outline.is_outside_polygon(clip_polygon) {
|
||||||
|
outline = Outline::new();
|
||||||
|
} else {
|
||||||
|
outline = (*original_outline).clone();
|
||||||
outline.clip_against_polygon(clip_polygon);
|
outline.clip_against_polygon(clip_polygon);
|
||||||
outline.apply_perspective(perspective);
|
outline.apply_perspective(perspective);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
PreparedRenderTransform::Transform2D(ref transform) => {
|
PreparedRenderTransform::Transform2D(ref transform) => {
|
||||||
|
// TODO(pcwalton): Short circuit.
|
||||||
|
outline = (*original_outline).clone();
|
||||||
outline.transform(transform);
|
outline.transform(transform);
|
||||||
outline.clip_against_rect(self.view_box);
|
outline.clip_against_rect(self.view_box);
|
||||||
}
|
}
|
||||||
PreparedRenderTransform::None => {
|
PreparedRenderTransform::None => {
|
||||||
|
outline = (*original_outline).clone();
|
||||||
outline.clip_against_rect(self.view_box);
|
outline.clip_against_rect(self.view_box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue