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;
}
Exemple #2
0
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;
    }
}
Exemple #5
0
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);

}
Exemple #6
0
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);
}