[librsvg: 2/6] bbox: factor out a rect module
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/6] bbox: factor out a rect module
- Date: Tue, 15 May 2018 15:08:42 +0000 (UTC)
commit 5ab459252158690a9c59bd5aca50e453e3822032
Author: Paolo Borelli <pborelli gnome org>
Date: Sun May 13 18:45:53 2018 +0200
bbox: factor out a rect module
Module for generic cairo::Rectangle utils
Makefile.am | 1 +
rsvg_internals/src/bbox.rs | 117 ++++--------------------------------
rsvg_internals/src/lib.rs | 1 +
rsvg_internals/src/rect.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 162 insertions(+), 104 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 6da52d82..5dcd8865 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -107,6 +107,7 @@ RUST_SRC = \
rsvg_internals/src/pattern.rs \
rsvg_internals/src/property_bag.rs \
rsvg_internals/src/property_macros.rs \
+ rsvg_internals/src/rect.rs \
rsvg_internals/src/shapes.rs \
rsvg_internals/src/space.rs \
rsvg_internals/src/state.rs \
diff --git a/rsvg_internals/src/bbox.rs b/rsvg_internals/src/bbox.rs
index fe63b0f7..abc2df82 100644
--- a/rsvg_internals/src/bbox.rs
+++ b/rsvg_internals/src/bbox.rs
@@ -6,6 +6,8 @@ use glib::translate::*;
use float_eq_cairo::ApproxEqCairo;
+use rect;
+
// Keep this in sync with ../../rsvg-private.h:RsvgBbox
#[repr(C)]
#[derive(Copy, Clone)]
@@ -49,61 +51,19 @@ impl RsvgBbox {
return;
}
- let (mut xmin, mut ymin, mut xmax, mut ymax) = if !self.is_virgin() {
- (
- self.rect.x,
- self.rect.y,
- (self.rect.x + self.rect.width),
- (self.rect.y + self.rect.height),
- )
- } else {
- (0.0, 0.0, 0.0, 0.0)
- };
-
let mut affine = self.affine;
// this will panic!() if it's not invertible... should we check on our own?
affine.invert();
affine = cairo::Matrix::multiply(&src.affine, &affine);
- // This is a trick. We want to transform each of the corners of
- // the rectangle defined by src.rect with the affine
- // transformation, and get the bounding box of all the four
- // resulting points. The modulus and division accomplish this by
- // running through all the combinations of adding or not adding
- // the width/height to the first point src.rect.(x, y).
- for i in 0..4 {
- let rx: f64 = src.rect.x + src.rect.width * f64::from(i % 2);
- let ry: f64 = src.rect.y + src.rect.height * f64::from(i / 2);
- let x: f64 = affine.xx * rx + affine.xy * ry + affine.x0;
- let y: f64 = affine.yx * rx + affine.yy * ry + affine.y0;
-
- if self.is_virgin() {
- xmin = x;
- xmax = x;
- ymin = y;
- ymax = y;
- self.virgin = false.to_glib();
- } else {
- if x < xmin {
- xmin = x;
- }
- if x > xmax {
- xmax = x;
- }
- if y < ymin {
- ymin = y;
- }
- if y > ymax {
- ymax = y;
- }
- }
- }
+ let rect = rect::transform(&affine, &src.rect);
- self.rect.x = xmin;
- self.rect.y = ymin;
- self.rect.width = xmax - xmin;
- self.rect.height = ymax - ymin;
+ if self.is_virgin() {
+ self.set_rect(&rect);
+ } else {
+ self.rect = rect::union(&rect, &self.rect);
+ }
}
pub fn clip(&mut self, src: &RsvgBbox) {
@@ -111,69 +71,18 @@ impl RsvgBbox {
return;
}
- let (mut xmin, mut ymin, mut xmax, mut ymax) = if !self.is_virgin() {
- (
- (self.rect.x + self.rect.width),
- (self.rect.y + self.rect.height),
- self.rect.x,
- self.rect.y,
- )
- } else {
- (0.0, 0.0, 0.0, 0.0)
- };
-
let mut affine = self.affine;
affine.invert();
affine = cairo::Matrix::multiply(&src.affine, &affine);
- // This is a trick. See rsvg_bbox_insert() for a description of how it works.
- for i in 0..4 {
- let rx: f64 = src.rect.x + src.rect.width * f64::from(i % 2);
- let ry: f64 = src.rect.y + src.rect.height * f64::from(i / 2);
- let x = affine.xx * rx + affine.xy * ry + affine.x0;
- let y = affine.yx * rx + affine.yy * ry + affine.y0;
-
- if self.is_virgin() {
- xmin = x;
- xmax = x;
- ymin = y;
- ymax = y;
- self.virgin = false.to_glib();
- } else {
- if x < xmin {
- xmin = x;
- }
- if x > xmax {
- xmax = x;
- }
- if y < ymin {
- ymin = y;
- }
- if y > ymax {
- ymax = y;
- }
- }
- }
-
- if xmin < self.rect.x {
- xmin = self.rect.x;
- }
- if ymin < self.rect.y {
- ymin = self.rect.y;
- }
+ let rect = rect::transform(&affine, &src.rect);
- if xmax > self.rect.x + self.rect.width {
- xmax = self.rect.x + self.rect.width;
- }
- if ymax > self.rect.y + self.rect.height {
- ymax = self.rect.y + self.rect.height;
+ if self.is_virgin() {
+ self.set_rect(&rect);
+ } else {
+ self.rect = rect::intersect(&rect, &self.rect);
}
-
- self.rect.x = xmin;
- self.rect.width = xmax - xmin;
- self.rect.y = ymin;
- self.rect.height = ymax - ymin;
}
}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 85194dcc..5aa731a9 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -189,6 +189,7 @@ mod space;
mod state;
mod stop;
mod structure;
+mod rect;
mod text;
mod transform;
mod unitinterval;
diff --git a/rsvg_internals/src/rect.rs b/rsvg_internals/src/rect.rs
new file mode 100644
index 00000000..06209f6c
--- /dev/null
+++ b/rsvg_internals/src/rect.rs
@@ -0,0 +1,147 @@
+use cairo;
+use cairo::MatrixTrait;
+
+pub fn intersect(r1: &cairo::Rectangle, r2: &cairo::Rectangle) -> cairo::Rectangle {
+ let (x1, y1, x2, y2) = (
+ r1.x.max(r2.x),
+ r1.y.max(r2.y),
+ (r1.x + r1.width).min(r2.x + r2.width),
+ (r1.y + r1.height).min(r2.y + r2.height),
+ );
+
+ cairo::Rectangle {
+ x: x1,
+ y: y1,
+ width: x2 - x1,
+ height: y2 - y1,
+ }
+}
+
+pub fn union(r1: &cairo::Rectangle, r2: &cairo::Rectangle) -> cairo::Rectangle {
+ let (x1, y1, x2, y2) = (
+ r1.x.min(r2.x),
+ r1.y.min(r2.y),
+ (r1.x + r1.width).max(r2.x + r2.width),
+ (r1.y + r1.height).max(r2.y + r2.height),
+ );
+
+ cairo::Rectangle {
+ x: x1,
+ y: y1,
+ width: x2 - x1,
+ height: y2 - y1,
+ }
+}
+
+pub fn transform(affine: &cairo::Matrix, rect: &cairo::Rectangle) -> cairo::Rectangle {
+ let points = vec![
+ affine.transform_point(rect.x, rect.y),
+ affine.transform_point(rect.x + rect.width, rect.y),
+ affine.transform_point(rect.x, rect.y + rect.height),
+ affine.transform_point(rect.x + rect.width, rect.y + rect.height),
+ ];
+
+ let (mut xmin, mut ymin, mut xmax, mut ymax) = {
+ let (x, y) = points[0];
+
+ (x, y, x, y)
+ };
+
+ for i in 1..4 {
+ let (x, y) = points[i];
+
+ if x < xmin {
+ xmin = x;
+ }
+
+ if x > xmax {
+ xmax = x;
+ }
+
+ if y < ymin {
+ ymin = y;
+ }
+
+ if y > ymax {
+ ymax = y;
+ }
+ }
+
+ cairo::Rectangle {
+ x: xmin,
+ y: ymin,
+ width: xmax - xmin,
+ height: ymax - ymin,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use float_eq_cairo::ApproxEqCairo;
+
+ #[test]
+ fn intersect_rects() {
+ let r1 = cairo::Rectangle {
+ x: 0.42,
+ y: 0.42,
+ width: 4.14,
+ height: 4.14,
+ };
+ let r2 = cairo::Rectangle {
+ x: 0.22,
+ y: 0.22,
+ width: 3.14,
+ height: 3.14,
+ };
+
+ let r = intersect(&r1, &r2);
+ assert_approx_eq_cairo!(0.42_f64, r.x);
+ assert_approx_eq_cairo!(0.42_f64, r.y);
+ assert_approx_eq_cairo!(2.94_f64, r.width);
+ assert_approx_eq_cairo!(2.94_f64, r.height);
+ }
+
+ #[test]
+ fn union_rects() {
+ let r1 = cairo::Rectangle {
+ x: 0.42,
+ y: 0.42,
+ width: 4.14,
+ height: 4.14,
+ };
+ let r2 = cairo::Rectangle {
+ x: 0.22,
+ y: 0.22,
+ width: 3.14,
+ height: 3.14,
+ };
+
+ let r = union(&r1, &r2);
+ assert_approx_eq_cairo!(0.22_f64, r.x);
+ assert_approx_eq_cairo!(0.22_f64, r.y);
+ assert_approx_eq_cairo!(4.34_f64, r.width);
+ assert_approx_eq_cairo!(4.34_f64, r.height);
+ }
+
+ #[test]
+ fn transform_rect() {
+ let r = cairo::Rectangle {
+ x: 0.42,
+ y: 0.42,
+ width: 3.14,
+ height: 3.14,
+ };
+
+ let m = cairo::Matrix::identity();
+ let tr = transform(&m, &r);
+ assert_eq!(tr, r);
+
+ let m = cairo::Matrix::new(2.0, 0.0, 0.0, 2.0, 1.5, 1.5);
+ let tr = transform(&m, &r);
+ assert_approx_eq_cairo!(2.34_f64, tr.x);
+ assert_approx_eq_cairo!(2.34_f64, tr.y);
+ assert_approx_eq_cairo!(6.28_f64, tr.width);
+ assert_approx_eq_cairo!(6.28_f64, tr.height);
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]