int geography_tree_distance(const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, double* distance) { CIRC_NODE* circ_tree1 = NULL; CIRC_NODE* circ_tree2 = NULL; LWGEOM* lwgeom1 = NULL; LWGEOM* lwgeom2 = NULL; POINT4D pt1, pt2; lwgeom1 = lwgeom_from_gserialized(g1); lwgeom2 = lwgeom_from_gserialized(g2); circ_tree1 = lwgeom_calculate_circ_tree(lwgeom1); circ_tree2 = lwgeom_calculate_circ_tree(lwgeom2); lwgeom_startpoint(lwgeom1, &pt1); lwgeom_startpoint(lwgeom2, &pt2); if ( CircTreePIP(circ_tree1, g1, &pt2) || CircTreePIP(circ_tree2, g2, &pt1) ) { *distance = 0.0; } else { /* Calculate tree/tree distance */ *distance = circ_tree_distance_tree(circ_tree1, circ_tree2, s, tolerance); } circ_tree_free(circ_tree1); circ_tree_free(circ_tree2); lwgeom_free(lwgeom1); lwgeom_free(lwgeom2); return LW_SUCCESS; }
static CIRC_NODE* lwcollection_calculate_circ_tree(const LWCOLLECTION* lwcol) { int i = 0, j = 0; CIRC_NODE** nodes; CIRC_NODE* node; /* One geometry? Done! */ if ( lwcol->ngeoms == 1 ) return lwgeom_calculate_circ_tree(lwcol->geoms[0]); /* Calculate a tree for each sub-geometry*/ nodes = lwalloc(lwcol->ngeoms * sizeof(CIRC_NODE*)); for ( i = 0; i < lwcol->ngeoms; i++ ) { node = lwgeom_calculate_circ_tree(lwcol->geoms[i]); if ( node ) nodes[j++] = node; } /* Put the trees into a spatially correlated order */ circ_nodes_sort(nodes, j); /* Merge the trees pairwise up to a parent node and return */ node = circ_nodes_merge(nodes, j); /* Don't need the working list any more */ lwfree(nodes); return node; }
/** * Builder, freeer and public accessor for cached CIRC_NODE trees */ static int CircTreeBuilder(const LWGEOM* lwgeom, GeomCache* cache) { CircTreeGeomCache* circ_cache = (CircTreeGeomCache*)cache; CIRC_NODE* tree = lwgeom_calculate_circ_tree(lwgeom); if ( circ_cache->index ) { circ_tree_free(circ_cache->index); circ_cache->index = 0; } if ( ! tree ) return LW_FAILURE; circ_cache->index = tree; return LW_SUCCESS; }
static int geography_distance_cache_tolerance(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, double* distance) { CircTreeGeomCache* tree_cache = NULL; int type1 = gserialized_get_type(g1); int type2 = gserialized_get_type(g2); Assert(distance); /* Two points? Get outa here... */ if ( type1 == POINTTYPE && type2 == POINTTYPE ) return LW_FAILURE; /* Fetch/build our cache, if appropriate, etc... */ tree_cache = GetCircTreeGeomCache(fcinfo, g1, g2); /* OK, we have an index at the ready! Use it for the one tree argument and */ /* fill in the other tree argument */ if ( tree_cache && tree_cache->argnum && tree_cache->index ) { CIRC_NODE* circtree_cached = tree_cache->index; CIRC_NODE* circtree = NULL; const GSERIALIZED* g_cached; const GSERIALIZED* g; LWGEOM* lwgeom = NULL; int geomtype_cached; int geomtype; POINT4D p4d; /* We need to dynamically build a tree for the uncached side of the function call */ if ( tree_cache->argnum == 1 ) { g_cached = g1; g = g2; geomtype_cached = type1; geomtype = type2; } else if ( tree_cache->argnum == 2 ) { g_cached = g2; g = g1; geomtype_cached = type2; geomtype = type1; } else { lwpgerror("geography_distance_cache this cannot happen!"); return LW_FAILURE; } lwgeom = lwgeom_from_gserialized(g); if ( geomtype_cached == POLYGONTYPE || geomtype_cached == MULTIPOLYGONTYPE ) { lwgeom_startpoint(lwgeom, &p4d); if ( CircTreePIP(circtree_cached, g_cached, &p4d) ) { *distance = 0.0; lwgeom_free(lwgeom); return LW_SUCCESS; } } circtree = lwgeom_calculate_circ_tree(lwgeom); if ( geomtype == POLYGONTYPE || geomtype == MULTIPOLYGONTYPE ) { POINT2D p2d; circ_tree_get_point(circtree_cached, &p2d); p4d.x = p2d.x; p4d.y = p2d.y; if ( CircTreePIP(circtree, g, &p4d) ) { *distance = 0.0; circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } } *distance = circ_tree_distance_tree(circtree_cached, circtree, s, tolerance); circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } else { return LW_FAILURE; } }
static void test_tree_circ_distance(void) { LWGEOM *lwg1, *lwg2; CIRC_NODE *c1, *c2; SPHEROID s; double d1, d2, d3, d4; double threshold = 0.0; spheroid_init(&s, 1.0, 1.0); /* Ticket #1958 */ lwg1 = lwgeom_from_wkt("LINESTRING(22.88333 41.96667,21.32667 42.13667)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POLYGON((22.94472 41.34667,22.87528 41.99028,22.87389 41.98472,22.87472 41.98333,22.94472 41.34667))", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("d1 = %g d2 = %g\n", d1 * WGS84_RADIUS, d2 * WGS84_RADIUS); // printf("line\n"); // circ_tree_print(c1, 0); // printf("poly\n"); // circ_tree_print(c2, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.0000001); /* Ticket #1951 */ lwg1 = lwgeom_from_wkt("LINESTRING(0 0, 0 0)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(0.1 0.1)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(-2 0)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(2 2)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(1 1)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(1 0.5)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("distance_tree %g\n", distance_tree); // printf("distance_geom %g\n", distance_geom); // circ_tree_print(cline, 0); // circ_tree_print(cpoint, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); /* Ticket #2351 */ lwg1 = lwgeom_from_wkt("LINESTRING(149.386990599235 -26.3567415843982,149.386990599247 -26.3567415843965)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(149.386990599235 -26.3567415843982)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("d1 = %g d2 = %g\n", d1 * WGS84_RADIUS, d2 * WGS84_RADIUS); // printf("line\n"); // circ_tree_print(c1, 0); // printf("point\n"); // circ_tree_print(c2, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.0000001); /* Ticket #2634 */ lwg1 = lwgeom_from_wkt("MULTIPOINT (-10 40,-10 65,10 40,10 65,30 40,30 65,50 40,50 65)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POLYGON((-9.1111111 40,-9.14954053919354 39.6098193559677,-9.26335203497743 39.2346331352698,-9.44817187539491 38.8888595339608,-9.6968975376269 38.5857864376269,-9.99997063396079 38.3370607753949,-10.3457442352698 38.1522409349774,-10.7209304559677 38.0384294391935,-11.1111111 38,-11.5012917440323 38.0384294391935,-11.8764779647302 38.1522409349774,-12.2222515660392 38.3370607753949,-12.5253246623731 38.5857864376269,-12.7740503246051 38.8888595339608,-12.9588701650226 39.2346331352698,-13.0726816608065 39.6098193559677,-13.1111111 40,-13.0726816608065 40.3901806440322,-12.9588701650226 40.7653668647302,-12.7740503246051 41.1111404660392,-12.5253246623731 41.4142135623731,-12.2222515660392 41.6629392246051,-11.8764779647302 41.8477590650226,-11.5012917440323 41.9615705608065,-11.1111111 42,-10.7209304559678 41.9615705608065,-10.3457442352698 41.8477590650226,-9.9999706339608 41.6629392246051,-9.69689753762691 41.4142135623731,-9.44817187539491 41.1111404660392,-9.26335203497743 40.7653668647302,-9.14954053919354 40.3901806440323,-9.1111111 40))", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("d1 = %g d2 = %g\n", d1 * WGS84_RADIUS, d2 * WGS84_RADIUS); // printf("multipoint\n"); // circ_tree_print(c1, 0); // printf("polygon\n"); // circ_tree_print(c2, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.0000001); /* Ticket #2634 */ lwg1 = lwgeom_from_wkt("MULTIPOINT Z (-10 40 1,-10 65 1,10 40 1,10 65 1,30 40 1,30 65 1,50 40 1,50 65 1,-10 40 2,-10 65 2,10 40 2,10 65 2,30 40 2,30 65 2,50 40 2,50 65 2,-10 40 3,-10 65 3,10 40 3,10 65 3,30 40 3,30 65 3,50 40 3,50 65 3)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("MULTIPOLYGON(((-9.1111111 40,-9.14954053919354 39.6098193559677,-9.26335203497743 39.2346331352698,-9.44817187539491 38.8888595339608,-9.6968975376269 38.5857864376269,-9.99997063396079 38.3370607753949,-10.3457442352698 38.1522409349774,-10.7209304559677 38.0384294391935,-11.1111111 38,-11.5012917440323 38.0384294391935,-11.8764779647302 38.1522409349774,-12.2222515660392 38.3370607753949,-12.5253246623731 38.5857864376269,-12.7740503246051 38.8888595339608,-12.9588701650226 39.2346331352698,-13.0726816608065 39.6098193559677,-13.1111111 40,-13.0726816608065 40.3901806440322,-12.9588701650226 40.7653668647302,-12.7740503246051 41.1111404660392,-12.5253246623731 41.4142135623731,-12.2222515660392 41.6629392246051,-11.8764779647302 41.8477590650226,-11.5012917440323 41.9615705608065,-11.1111111 42,-10.7209304559678 41.9615705608065,-10.3457442352698 41.8477590650226,-9.9999706339608 41.6629392246051,-9.69689753762691 41.4142135623731,-9.44817187539491 41.1111404660392,-9.26335203497743 40.7653668647302,-9.14954053919354 40.3901806440323,-9.1111111 40)))", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); // printf("\n"); // circ_tree_print(c1, 0); // printf("\n"); // circ_tree_print(c2, 0); // printf("\n"); d1 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); d2 = circ_tree_distance_tree(c1, c2, &s, threshold); d3 = circ_tree_distance_tree(c1, c2, &s, threshold); d4 = circ_tree_distance_tree(c1, c2, &s, threshold); // printf("\n d1-no-tree %20.20g\n d2 %20.20g\n d3 %20.20g\n d4 %20.20g\n", d1, d2, d3, d4); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00000001); CU_ASSERT_DOUBLE_EQUAL(d1, d3, 0.00000001); CU_ASSERT_DOUBLE_EQUAL(d1, d4, 0.00000001); }
static void test_tree_circ_distance(void) { LWGEOM *lwg1, *lwg2; CIRC_NODE *c1, *c2; SPHEROID s; double d1, d2; double threshold = 0.0; spheroid_init(&s, 1.0, 1.0); /* Ticket #1958 */ lwg1 = lwgeom_from_wkt("LINESTRING(22.88333 41.96667,21.32667 42.13667)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POLYGON((22.94472 41.34667,22.87528 41.99028,22.87389 41.98472,22.87472 41.98333,22.94472 41.34667))", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("d1 = %g d2 = %g\n", d1 * WGS84_RADIUS, d2 * WGS84_RADIUS); // printf("line\n"); // circ_tree_print(c1, 0); // printf("poly\n"); // circ_tree_print(c2, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.0000001); /* Ticket #1951 */ lwg1 = lwgeom_from_wkt("LINESTRING(0 0, 0 0)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(0.1 0.1)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(-2 0)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(2 2)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(1 1)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); lwg1 = lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE); lwg2 = lwgeom_from_wkt("POINT(1 0.5)", LW_PARSER_CHECK_NONE); c1 = lwgeom_calculate_circ_tree(lwg1); c2 = lwgeom_calculate_circ_tree(lwg2); d1 = circ_tree_distance_tree(c1, c2, &s, threshold); d2 = lwgeom_distance_spheroid(lwg1, lwg2, &s, threshold); // printf("distance_tree %g\n", distance_tree); // printf("distance_geom %g\n", distance_geom); // circ_tree_print(cline, 0); // circ_tree_print(cpoint, 0); circ_tree_free(c1); circ_tree_free(c2); lwgeom_free(lwg1); lwgeom_free(lwg2); CU_ASSERT_DOUBLE_EQUAL(d1, d2, 0.00001); }