[postgis-tickets] r14425 - Fix to arc center calculation, from tiipponen, #3099
Paul Ramsey
pramsey at cleverelephant.ca
Wed Nov 25 12:10:09 PST 2015
Author: pramsey
Date: 2015-11-25 12:10:09 -0800 (Wed, 25 Nov 2015)
New Revision: 14425
Modified:
trunk/liblwgeom/cunit/cu_algorithm.c
trunk/liblwgeom/lwalgorithm.c
Log:
Fix to arc center calculation, from tiipponen, #3099
Modified: trunk/liblwgeom/cunit/cu_algorithm.c
===================================================================
--- trunk/liblwgeom/cunit/cu_algorithm.c 2015-11-25 18:33:54 UTC (rev 14424)
+++ trunk/liblwgeom/cunit/cu_algorithm.c 2015-11-25 20:10:09 UTC (rev 14425)
@@ -90,6 +90,29 @@
}
+static void test_lw_arc_center(void)
+{
+/* double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result); */
+ POINT2D c1;
+ double d1;
+ POINT2D p1, p2, p3;
+
+ p1.x = 2047538.600;
+ p1.y = 7268770.435;
+ p2.x = 2047538.598;
+ p2.y = 7268770.435;
+ p3.x = 2047538.596;
+ p3.y = 7268770.436;
+
+ d1 = lw_arc_center(&p1, &p2, &p3, &c1);
+
+ CU_ASSERT_DOUBLE_EQUAL(d1, 0.0046097720751, 0.0001);
+ CU_ASSERT_DOUBLE_EQUAL(c1.x, 2047538.599, 0.001);
+ CU_ASSERT_DOUBLE_EQUAL(c1.y, 7268770.4395, 0.001);
+
+ // printf("lw_arc_center: (%12.12g, %12.12g) %12.12g\n", c1.x, c1.y, d1);
+}
+
/*
** Test crossings side.
*/
@@ -983,4 +1006,5 @@
PG_ADD_TEST(suite,test_geohash_point_as_int);
PG_ADD_TEST(suite,test_isclosed);
PG_ADD_TEST(suite,test_lwgeom_simplify);
+ PG_ADD_TEST(suite,test_lw_arc_center);
}
Modified: trunk/liblwgeom/lwalgorithm.c
===================================================================
--- trunk/liblwgeom/lwalgorithm.c 2015-11-25 18:33:54 UTC (rev 14424)
+++ trunk/liblwgeom/lwalgorithm.c 2015-11-25 20:10:09 UTC (rev 14425)
@@ -224,13 +224,13 @@
* point is coincident with either end point, they are taken as colinear.
*/
double
-lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
+lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
{
POINT2D c;
double cx, cy, cr;
- double temp, bc, cd, det;
+ double dx21, dy21, dx31, dy31, h21, h31, d;
- c.x = c.y = 0.0;
+ c.x = c.y = 0.0;
LWDEBUGF(2, "lw_arc_center called (%.16f,%.16f), (%.16f,%.16f), (%.16f,%.16f).", p1->x, p1->y, p2->x, p2->y, p3->x, p3->y);
@@ -247,30 +247,35 @@
return cr;
}
- temp = p2->x*p2->x + p2->y*p2->y;
- bc = (p1->x*p1->x + p1->y*p1->y - temp) / 2.0;
- cd = (temp - p3->x*p3->x - p3->y*p3->y) / 2.0;
- det = (p1->x - p2->x)*(p2->y - p3->y)-(p2->x - p3->x)*(p1->y - p2->y);
+ /* Using cartesian eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle */
+ dx21 = p2->x - p1->x;
+ dy21 = p2->y - p1->y;
+ dx31 = p3->x - p1->x;
+ dy31 = p3->y - p1->y;
- /* Check colinearity */
- if (fabs(det) < EPSILON_SQLMM)
+ h21 = pow(dx21, 2.0) + pow(dy21, 2.0);
+ h31 = pow(dx31, 2.0) + pow(dy31, 2.0);
+
+ /* 2 * |Cross product|, d<0 means clockwise and d>0 counterclockwise sweeping angle */
+ d = 2 * (dx21 * dy31 - dx31 * dy21);
+
+ /* Check colinearity, |Cross product| = 0 */
+ if (fabs(d) < EPSILON_SQLMM)
return -1.0;
-
- det = 1.0 / det;
- cx = (bc*(p2->y - p3->y)-cd*(p1->y - p2->y))*det;
- cy = ((p1->x - p2->x)*cd-(p2->x - p3->x)*bc)*det;
+ /* Calculate centroid coordinates and radius */
+ cx = p1->x + (h21 * dy31 - h31 * dy21) / d;
+ cy = p1->y - (h21 * dx31 - h31 * dx21) / d;
c.x = cx;
c.y = cy;
*result = c;
- cr = sqrt((cx-p1->x)*(cx-p1->x)+(cy-p1->y)*(cy-p1->y));
-
+ cr = sqrt(pow(cx - p1->x, 2) + pow(cy - p1->y, 2));
+
LWDEBUGF(2, "lw_arc_center center is (%.16f,%.16f)", result->x, result->y);
-
+
return cr;
}
-
int
pt_in_ring_2d(const POINT2D *p, const POINTARRAY *ring)
{
More information about the postgis-tickets
mailing list