From 4aca949514bf459935f9f3dd47cd09af69ab4228 Mon Sep 17 00:00:00 2001 From: Peter Abeles Date: Wed, 1 Nov 2023 05:51:32 -0700 Subject: [PATCH] AreaIntersectionPolygon2D_F64 - Now recycles memory when possible --- change.txt | 2 + .../AreaIntersectionPolygon2D_F64.java | 116 ++++++++++-------- .../TestAreaIntersectionPolygon_F64.java | 7 +- 3 files changed, 71 insertions(+), 54 deletions(-) diff --git a/change.txt b/change.txt index 45408c67..0c54ab09 100644 --- a/change.txt +++ b/change.txt @@ -6,6 +6,8 @@ Version : 0.26.3 - GeoTuple * Provided setTo() where you can assign it from a lower dimension +- AreaIntersectionPolygon2D_F64 + * Now recycles memory when possible --------------------------------------------- Date : 2023-Sep-24 diff --git a/main/src/georegression/geometry/polygon/AreaIntersectionPolygon2D_F64.java b/main/src/georegression/geometry/polygon/AreaIntersectionPolygon2D_F64.java index 0018f677..bb3da1c8 100644 --- a/main/src/georegression/geometry/polygon/AreaIntersectionPolygon2D_F64.java +++ b/main/src/georegression/geometry/polygon/AreaIntersectionPolygon2D_F64.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Peter Abeles. All Rights Reserved. + * Copyright (C) 2022, Peter Abeles. All Rights Reserved. * * This file is part of Geometric Regression Library (GeoRegression). * @@ -22,14 +22,13 @@ import georegression.struct.point.Point2D_I32; import georegression.struct.shapes.Polygon2D_F64; import georegression.struct.shapes.Rectangle2D_F64; +import org.ddogleg.struct.DogArray; /** *

* Computes the area of intersection between two convex polygons. Port of code found at [1] and Java version by Lagado. *

* - * WARNING: No effort has been made to reduce the number of calls to new internally from original code. - * * [1] http://www.cap-lore.com/MathPhys/IP/ * * @author Peter Abeles @@ -37,66 +36,88 @@ @SuppressWarnings("NullAway.Init") public class AreaIntersectionPolygon2D_F64 { static final double gamut = (double)500000000.0; - static final double mid = gamut / (double)2.0; + static final double mid = gamut/(double)2.0; private long ssss; private double sclx; private double scly; + // Internal workspace + DogArray ipa = new DogArray<>(Vertex::new, Vertex::reset); + DogArray ipb = new DogArray<>(Vertex::new, Vertex::reset); + Rectangle2D_F64 bbox = new Rectangle2D_F64(); + /** - * Computes the area of the intersection between the two polygons. + *

Computes the area of the intersection between the two polygons.

* * Note: the area result has little more accuracy than a float - * This is true even if the polygon is specified with doubles. + * This is true even if the polygon is specified with doubles. * * @param a Polygon A * @param b Polygon B - * @return area of area of intersection. Negative if the order (CW vs CCW) do not match. + * @return area of intersection. Negative if the order (CW vs CCW) do not match. */ - public double computeArea(Polygon2D_F64 a , Polygon2D_F64 b ) { + public double computeArea( Polygon2D_F64 a, Polygon2D_F64 b ) { ssss = 0; sclx = 0; scly = 0; - return inter(a,b); + return inter(a, b); } //-------------------------------------------------------------------------- static class Rng { - int mn; int mx; - Rng(int mn, int mx) { this.mn = mn; this.mx = mx; } + int mn; + int mx; + + Rng( int mn, int mx ) { + this.mn = mn; + this.mx = mx; + } + } + + static class Vertex { + Point2D_I32 ip; + Rng rx; + Rng ry; + int in; + + @SuppressWarnings("NullAway") + public void reset() { + ip = null; + rx = null; + ry = null; + in = 0; + } } - static class Vertex { Point2D_I32 ip; Rng rx; Rng ry; int in; } //-------------------------------------------------------------------------- - private static void range(Polygon2D_F64 points, Rectangle2D_F64 bbox) - { - UtilPolygons2D_F64.bounding(points,bbox); + private static void range( Polygon2D_F64 points, Rectangle2D_F64 bbox ) { + UtilPolygons2D_F64.bounding(points, bbox); } - private static long area(Point2D_I32 a, Point2D_I32 p, Point2D_I32 q) { - return (long)p.x * q.y - (long)p.y * q.x + - (long)a.x * (p.y - q.y) + (long)a.y * (q.x - p.x); + private static long area( Point2D_I32 a, Point2D_I32 p, Point2D_I32 q ) { + return (long)p.x*q.y - (long)p.y*q.x + + (long)a.x*(p.y - q.y) + (long)a.y*(q.x - p.x); } - private static boolean ovl(Rng p, Rng q) { + private static boolean ovl( Rng p, Rng q ) { return p.mn < q.mx && q.mn < p.mx; } - private void cntrib(int f_x, int f_y, int t_x, int t_y, int w) { - ssss += (long)w * (t_x - f_x) * (t_y + f_y) / 2; + private void cntrib( int f_x, int f_y, int t_x, int t_y, int w ) { + ssss += (long)w*(t_x - f_x)*(t_y + f_y)/2; } - private void fit(Polygon2D_F64 x, Vertex[] ix, int fudge, Rectangle2D_F64 B) - { + private void fit( Polygon2D_F64 x, Vertex[] ix, int fudge, Rectangle2D_F64 B ) { int c = x.size(); while (c-- > 0) { ix[c] = new Vertex(); ix[c].ip = new Point2D_I32(); - ix[c].ip.x = ((int)((x.get(c).getX() - B.p0.x) * sclx - mid) & ~7) + ix[c].ip.x = ((int)((x.get(c).getX() - B.p0.x)*sclx - mid) & ~7) | fudge | (c & 1); - ix[c].ip.y = ((int)((x.get(c).getY() - B.p0.y) * scly - mid) & ~7) + ix[c].ip.y = ((int)((x.get(c).getY() - B.p0.y)*scly - mid) & ~7) | fudge; } @@ -115,25 +136,23 @@ private void fit(Polygon2D_F64 x, Vertex[] ix, int fudge, Rectangle2D_F64 B) } } - private void cross(Vertex a, Vertex b, Vertex c, Vertex d, - double a1, double a2, double a3, double a4) - { - double r1 = a1 / ((double) a1 + a2); - double r2 = a3 / ((double) a3 + a4); + private void cross( Vertex a, Vertex b, Vertex c, Vertex d, + double a1, double a2, double a3, double a4 ) { + double r1 = a1/((double) a1 + a2); + double r2 = a3/((double) a3 + a4); - cntrib((int)(a.ip.x + r1 * (b.ip.x - a.ip.x)), - (int)(a.ip.y + r1 * (b.ip.y - a.ip.y)), + cntrib((int)(a.ip.x + r1*(b.ip.x - a.ip.x)), + (int)(a.ip.y + r1*(b.ip.y - a.ip.y)), b.ip.x, b.ip.y, 1); cntrib(d.ip.x, d.ip.y, - (int)(c.ip.x + r2 * (d.ip.x - c.ip.x)), - (int)(c.ip.y + r2 * (d.ip.y - c.ip.y)), + (int)(c.ip.x + r2*(d.ip.x - c.ip.x)), + (int)(c.ip.y + r2*(d.ip.y - c.ip.y)), 1); ++a.in; --c.in; } - private void inness(Vertex[] P, int cP, Vertex[] Q, int cQ) - { + private void inness( Vertex[] P, int cP, Vertex[] Q, int cQ ) { int s = 0; int c = cQ; Point2D_I32 p = P[0].ip; @@ -154,28 +173,27 @@ private void inness(Vertex[] P, int cP, Vertex[] Q, int cQ) //------------------------------------------------------------------------- - private double inter(Polygon2D_F64 a, Polygon2D_F64 b) - { + private double inter( Polygon2D_F64 a, Polygon2D_F64 b ) { if (a.size() < 3 || b.size() < 3) return 0; - // int na = a.size(); -// int nb = b.size(); - Vertex[] ipa = new Vertex[a.size() + 1]; - Vertex[] ipb = new Vertex[b.size()+ 1]; - Rectangle2D_F64 bbox = new Rectangle2D_F64( - Double.MAX_VALUE, Double.MAX_VALUE, - -Double.MAX_VALUE, -Double.MAX_VALUE); + // Recycle / allocate memory + ipa.reset().resize(a.size() + 1); + ipb.reset().resize(b.size() + 1); + Vertex[] ipa = this.ipa.data; + Vertex[] ipb = this.ipb.data; + + bbox.setTo(Double.MAX_VALUE, Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE); range(a, bbox); range(b, bbox); double rngx = bbox.p1.x - bbox.p0.x; - sclx = gamut / rngx; + sclx = gamut/rngx; double rngy = bbox.p1.y - bbox.p0.y; - scly = gamut / rngy; - double ascale = sclx * scly; + scly = gamut/rngy; + double ascale = sclx*scly; fit(a, ipa, 0, bbox); fit(b, ipb, 2, bbox); @@ -206,6 +224,6 @@ private double inter(Polygon2D_F64 a, Polygon2D_F64 b) inness(ipa, a.size(), ipb, b.size()); inness(ipb, b.size(), ipa, a.size()); - return ssss / ascale; + return ssss/ascale; } } diff --git a/main/test/georegression/geometry/polygon/TestAreaIntersectionPolygon_F64.java b/main/test/georegression/geometry/polygon/TestAreaIntersectionPolygon_F64.java index 82c3b42f..db984cc0 100644 --- a/main/test/georegression/geometry/polygon/TestAreaIntersectionPolygon_F64.java +++ b/main/test/georegression/geometry/polygon/TestAreaIntersectionPolygon_F64.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, Peter Abeles. All Rights Reserved. + * Copyright (C) 2022, Peter Abeles. All Rights Reserved. * * This file is part of Geometric Regression Library (GeoRegression). * @@ -25,9 +25,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -/** - * @author Peter Abeles - */ public class TestAreaIntersectionPolygon_F64 { /** * Unit tests provided by the original author @@ -39,7 +36,7 @@ public class TestAreaIntersectionPolygon_F64 { // as good test cases should. // It is not necessary to duplicate the first vertex at the end. - double[][] a2 = {{1,7}, {4,7}, {4, 6}, {2,6}, {2, 3}, {4,3}, {4,2}, {1,2}}; + double[][] a2 = {{1,7}, {4,7}, {4,6}, {2,6}, {2,3}, {4,3}, {4,2}, {1,2}}; double[][] b2 = {{3,1}, {5,1}, {5,4}, {3,4}, {3,5}, {6,5}, {6,0}, {3,0}}; // 0, 9 double[][] a3 = {{1,1}, {1,2}, {2,1}, {2,2}};