コード例 #1
0
ファイル: lwgeodetic_tree.c プロジェクト: ahinz/postgis
/**
* Create a new leaf node, storing pointers back to the end points for later.
*/
static CIRC_NODE* 
circ_node_leaf_new(const POINTARRAY* pa, int i)
{
	POINT2D *p1, *p2;
	POINT3D q1, q2, c;
	GEOGRAPHIC_POINT g1, g2, gc;
	CIRC_NODE *node;
	double diameter;

	p1 = (POINT2D*)getPoint_internal(pa, i);
	p2 = (POINT2D*)getPoint_internal(pa, i+1);
	geographic_point_init(p1->x, p1->y, &g1);
	geographic_point_init(p2->x, p2->y, &g2);

	LWDEBUGF(3,"edge #%d (%g %g, %g %g)", i, p1->x, p1->y, p2->x, p2->y);
	
	diameter = sphere_distance(&g1, &g2);

	/* Zero length edge, doesn't get a node */
	if ( FP_EQUALS(diameter, 0.0) )
		return NULL;

	/* Allocate */
	node = lwalloc(sizeof(CIRC_NODE));
	node->p1 = p1;
	node->p2 = p2;
	
	/* Convert ends to X/Y/Z, sum, and normalize to get mid-point */
	geog2cart(&g1, &q1);
	geog2cart(&g2, &q2);
	vector_sum(&q1, &q2, &c);
	normalize(&c);
	cart2geog(&c, &gc);
	node->center = gc;
	node->radius = diameter / 2.0;

	LWDEBUGF(3,"edge #%d CENTER(%g %g) RADIUS=%g", i, gc.lon, gc.lat, node->radius);

	/* Leaf has no children */
	node->num_nodes = 0;
	node->nodes = NULL;
	node->edge_num = i;
	
	return node;
}
コード例 #2
0
static int
CircTreePIP(const CIRC_NODE* tree1, const GSERIALIZED* g1, const POINT4D* in_point)
{
    int tree1_type = gserialized_get_type(g1);
    GBOX gbox1;
    GEOGRAPHIC_POINT in_gpoint;
    POINT3D in_point3d;

    POSTGIS_DEBUGF(3, "tree1_type=%d", tree1_type);

    /* If the tree'ed argument is a polygon, do the P-i-P using the tree-based P-i-P */
    if ( tree1_type == POLYGONTYPE || tree1_type == MULTIPOLYGONTYPE )
    {
        POSTGIS_DEBUG(3, "tree is a polygon, using tree PiP");
        /* Need a gbox to calculate an outside point */
        if ( LW_FAILURE == gserialized_get_gbox_p(g1, &gbox1) )
        {
            LWGEOM* lwgeom1 = lwgeom_from_gserialized(g1);
            POSTGIS_DEBUG(3, "unable to read gbox from gserialized, calculating from scratch");
            lwgeom_calculate_gbox_geodetic(lwgeom1, &gbox1);
            lwgeom_free(lwgeom1);
        }

        /* Flip the candidate point into geographics */
        geographic_point_init(in_point->x, in_point->y, &in_gpoint);
        geog2cart(&in_gpoint, &in_point3d);

        /* If the candidate isn't in the tree box, it's not in the tree area */
        if ( ! gbox_contains_point3d(&gbox1, &in_point3d) )
        {
            POSTGIS_DEBUG(3, "in_point3d is not inside the tree gbox, CircTreePIP returning FALSE");
            return LW_FALSE;
        }
        /* The candidate point is in the box, so it *might* be inside the tree */
        else
        {
            POINT2D pt2d_outside; /* latlon */
            POINT2D pt2d_inside;
            pt2d_inside.x = in_point->x;
            pt2d_inside.y = in_point->y;
            /* Calculate a definitive outside point */
            gbox_pt_outside(&gbox1, &pt2d_outside);
            POSTGIS_DEBUGF(3, "p2d_inside=POINT(%g %g) p2d_outside=POINT(%g %g)", pt2d_inside.x, pt2d_inside.y, pt2d_outside.x, pt2d_outside.y);
            /* Test the candidate point for strict containment */
            POSTGIS_DEBUG(3, "calling circ_tree_contains_point for PiP test");
            return circ_tree_contains_point(tree1, &pt2d_inside, &pt2d_outside, NULL);
        }
    }
    else
    {
        POSTGIS_DEBUG(3, "tree1 not polygonal, so CircTreePIP returning FALSE");
        return LW_FALSE;
    }
}
コード例 #3
0
ファイル: lwgeodetic_tree.c プロジェクト: ahinz/postgis
/**
* Return a point node (zero radius, referencing one point)
*/
static CIRC_NODE* 
circ_node_leaf_point_new(const POINTARRAY* pa)
{
	CIRC_NODE* tree = lwalloc(sizeof(CIRC_NODE));
	tree->p1 = tree->p2 = (POINT2D*)getPoint_internal(pa, 0);
	geographic_point_init(tree->p1->x, tree->p1->y, &(tree->center));
	tree->radius = 0.0;
	tree->nodes = NULL;
	tree->num_nodes = 0;
	tree->edge_num = 0;
	return tree;
}
コード例 #4
0
ファイル: lwspheroid.c プロジェクト: Vlczech/vtapi
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid)
{
	GEOGRAPHIC_POINT a, b;
	POINT2D p;
	int i;
	double area = 0.0;
	GBOX gbox2d;
	int in_south = LW_FALSE;
	double delta_lon_tolerance;
	double latitude_min;

	gbox2d.flags = gflags(0, 0, 0);

	/* Return zero on non-sensical inputs */
	if ( ! pa || pa->npoints < 4 )
		return 0.0;

	/* Get the raw min/max values for the latitudes */
	ptarray_calculate_gbox(pa, &gbox2d);

	if ( signum(gbox2d.ymin) != signum(gbox2d.ymax) )
		lwerror("ptarray_area_spheroid: cannot handle ptarray that crosses equator");

	/* Geodetic bbox < 0.0 implies geometry is entirely in southern hemisphere */
	if ( gbox2d.ymax < 0.0 )
		in_south = LW_TRUE;

	LWDEBUGF(4, "gbox2d.ymax %.12g", gbox2d.ymax);

	/* Tolerance for strip area calculation */
	if ( in_south )
	{
		delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymin) / 8.0) - 2.0) / 10000.0;
		latitude_min = deg2rad(fabs(gbox2d.ymax));
	}
	else
	{
		delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymax) / 8.0) - 2.0) / 10000.0;
		latitude_min = deg2rad(gbox2d.ymin);
	}

	/* Initialize first point */
	getPoint2d_p(pa, 0, &p);
	geographic_point_init(p.x, p.y, &a);

	for ( i = 1; i < pa->npoints; i++ )
	{
		GEOGRAPHIC_POINT a1, b1;
		double strip_area = 0.0;
		double delta_lon = 0.0;
		LWDEBUGF(4, "edge #%d", i);

		getPoint2d_p(pa, i, &p);
		geographic_point_init(p.x, p.y, &b);

		a1 = a;
		b1 = b;

		/* Flip into north if in south */
		if ( in_south )
		{
			a1.lat = -1.0 * a1.lat;
			b1.lat = -1.0 * b1.lat;
		}

		LWDEBUGF(4, "in_south %d", in_south);

		LWDEBUGF(4, "crosses_dateline(a, b) %d", crosses_dateline(&a, &b) );

		if ( crosses_dateline(&a, &b) )
		{
			double shift;

			if ( a1.lon > 0.0 )
				shift = (M_PI - a1.lon) + 0.088; /* About 5deg more */
			else
				shift = (M_PI - b1.lon) + 0.088; /* About 5deg more */

			LWDEBUGF(4, "shift: %.8g", shift);
			LWDEBUGF(4, "before shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon);
			point_shift(&a1, shift);
			point_shift(&b1, shift);
			LWDEBUGF(4, "after shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon);
			
		}


		delta_lon = fabs(b1.lon - a1.lon);

		LWDEBUGF(4, "a1(%.18g %.18g) b1(%.18g %.18g)", a1.lat, a1.lon, b1.lat, b1.lon);
		LWDEBUGF(4, "delta_lon %.18g", delta_lon);
		LWDEBUGF(4, "delta_lon_tolerance %.18g", delta_lon_tolerance);

		if ( delta_lon > 0.0 )
		{
			if ( delta_lon < delta_lon_tolerance )
			{
				strip_area = spheroid_striparea(&a1, &b1, latitude_min, spheroid);
				LWDEBUGF(4, "strip_area %.12g", strip_area);
				area += strip_area;
			}
			else
			{
				GEOGRAPHIC_POINT p, q;
				double step = floor(delta_lon / delta_lon_tolerance);
				double distance = spheroid_distance(&a1, &b1, spheroid);
				double pDistance = 0.0;
				int j = 0;
				LWDEBUGF(4, "step %.18g", step);
				LWDEBUGF(4, "distance %.18g", distance);
				step = distance / step;
				LWDEBUGF(4, "step %.18g", step);
				p = a1;
				while (pDistance < (distance - step * 1.01))
				{
					double azimuth = spheroid_direction(&p, &b1, spheroid);
					j++;
					LWDEBUGF(4, "  iteration %d", j);
					LWDEBUGF(4, "  azimuth %.12g", azimuth);
					pDistance = pDistance + step;
					LWDEBUGF(4, "  pDistance %.12g", pDistance);
					spheroid_project(&p, spheroid, step, azimuth, &q);
					strip_area = spheroid_striparea(&p, &q, latitude_min, spheroid);
					LWDEBUGF(4, "  strip_area %.12g", strip_area);
					area += strip_area;
					LWDEBUGF(4, "  area %.12g", area);
					p.lat = q.lat;
					p.lon = q.lon;
				}
				strip_area = spheroid_striparea(&p, &b1, latitude_min, spheroid);
				area += strip_area;
			}
		}

		/* B gets incremented in the next loop, so we save the value here */
		a = b;
	}
	return fabs(area);
}
コード例 #5
0
ファイル: lwgeodetic_tree.c プロジェクト: ahinz/postgis
static double 
circ_tree_distance_tree_internal(const CIRC_NODE* n1, const CIRC_NODE* n2, double threshold, double* min_dist, double* max_dist, GEOGRAPHIC_POINT* closest1, GEOGRAPHIC_POINT* closest2)
{	
	double max;
	double d, d_min;
	int i;
	
	LWDEBUGF(4, "entered, min_dist %.8g max_dist %.8g", *min_dist, *max_dist);
//	circ_tree_print(n1, 0);
//	circ_tree_print(n2, 0);
	
	/* Short circuit if we've already hit the minimum */
	if( FP_LT(*min_dist, threshold) )
		return *min_dist;
	
	/* If your minimum is greater than anyone's maximum, you can't hold the winner */
	if( circ_node_min_distance(n1, n2) > *max_dist )
	{
		LWDEBUGF(4, "pruning pair %p, %p", n1, n2);		
		return MAXFLOAT;
	}
	
	/* If your maximum is a new low, we'll use that as our new global tolerance */
	max = circ_node_max_distance(n1, n2);
	LWDEBUGF(5, "max %.8g", max);
	if( max < *max_dist )
		*max_dist = max;

	/* Both leaf nodes, do a real distance calculation */
	if( circ_node_is_leaf(n1) )
	{
		if( circ_node_is_leaf(n2) )
		{
			double d;
			GEOGRAPHIC_POINT close1, close2;
			LWDEBUGF(4, "testing leaf pair [%d], [%d]", n1->edge_num, n2->edge_num);		
			/* One of the nodes is a point */
			if ( n1->p1 == n1->p2 || n2->p1 == n2->p2 )
			{
				GEOGRAPHIC_EDGE e;
				GEOGRAPHIC_POINT gp1, gp2;

				/* Both nodes are points! */
				if ( n1->p1 == n1->p2 && n2->p1 == n2->p2 )
				{
					geographic_point_init(n1->p1->x, n1->p1->y, &gp1);
					geographic_point_init(n2->p1->x, n2->p1->y, &gp2);
					close1 = gp1; close2 = gp2;
					d = sphere_distance(&gp1, &gp2);
				}				
				/* Node 1 is a point */
				else if ( n1->p1 == n1->p2 )
				{
					geographic_point_init(n1->p1->x, n1->p1->y, &gp1);
					geographic_point_init(n2->p1->x, n2->p1->y, &(e.start));
					geographic_point_init(n2->p2->x, n2->p2->y, &(e.end));
					close1 = gp1;
					d = edge_distance_to_point(&e, &gp1, &close2);
				}
				/* Node 2 is a point */
				else
				{
					geographic_point_init(n2->p1->x, n2->p1->y, &gp1);
					geographic_point_init(n1->p1->x, n1->p1->y, &(e.start));
					geographic_point_init(n1->p2->x, n1->p2->y, &(e.end));
					close1 = gp1;
					d = edge_distance_to_point(&e, &gp1, &close2);
				}
				LWDEBUGF(4, "  got distance %g", d);		
			}
			/* Both nodes are edges */
			else
			{
				GEOGRAPHIC_EDGE e1, e2;
				GEOGRAPHIC_POINT g;
				POINT3D A1, A2, B1, B2;
				geographic_point_init(n1->p1->x, n1->p1->y, &(e1.start));
				geographic_point_init(n1->p2->x, n1->p2->y, &(e1.end));
				geographic_point_init(n2->p1->x, n2->p1->y, &(e2.start));
				geographic_point_init(n2->p2->x, n2->p2->y, &(e2.end));
				geog2cart(&(e1.start), &A1);
				geog2cart(&(e1.end), &A2);
				geog2cart(&(e2.start), &B1);
				geog2cart(&(e2.end), &B2);
				if ( edge_intersects(&A1, &A2, &B1, &B2) )
				{
					d = 0.0;
					edge_intersection(&e1, &e2, &g);
					close1 = close2 = g;
				}
				else
				{
					d = edge_distance_to_edge(&e1, &e2, &close1, &close2);
				}
				LWDEBUGF(4, "edge_distance_to_edge returned %g", d);		
			}
			if ( d < *min_dist )
			{
				*min_dist = d;
				*closest1 = close1;
				*closest2 = close2;
			}
			return d;
		}
		else
		{
			d_min = MAXFLOAT;
			for ( i = 0; i < n2->num_nodes; i++ )
			{
				d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2);
				d_min = FP_MIN(d_min, d);
			}
			return d_min;
		}
	}
	else
	{
		d_min = MAXFLOAT;
		for ( i = 0; i < n1->num_nodes; i++ )
		{
			d = circ_tree_distance_tree_internal(n2, n1->nodes[i], threshold, min_dist, max_dist, closest1, closest2);
			d_min = FP_MIN(d_min, d);
		}
		return d_min;
	}
}
コード例 #6
0
ファイル: lwgeodetic_tree.c プロジェクト: ahinz/postgis
/**
* Walk the tree and count intersections between the stab line and the edges.
* odd => containment, even => no containment.
* KNOWN PROBLEM: Grazings (think of a sharp point, just touching the
*   stabline) will be counted for one, which will throw off the count.
*/
int circ_tree_contains_point(const CIRC_NODE* node, const POINT2D* pt, const POINT2D* pt_outside, int* on_boundary)
{
	GEOGRAPHIC_POINT closest;
	GEOGRAPHIC_EDGE stab_edge, edge;
	POINT3D S1, S2, E1, E2;
	double d;
	int i, c;
	
	/* Construct a stabline edge from our "inside" to our known outside point */
	geographic_point_init(pt->x, pt->y, &(stab_edge.start));
	geographic_point_init(pt_outside->x, pt_outside->y, &(stab_edge.end));
	geog2cart(&(stab_edge.start), &S1);
	geog2cart(&(stab_edge.end), &S2);
	
	LWDEBUG(3, "entered");
	
	/* 
	* If the stabline doesn't cross within the radius of a node, there's no 
	* way it can cross.
	*/
		
	LWDEBUGF(3, "working on node %p, edge_num %d, radius %g, center POINT(%g %g)", node, node->edge_num, node->radius, rad2deg(node->center.lon), rad2deg(node->center.lat));
	d = edge_distance_to_point(&stab_edge, &(node->center), &closest);
	LWDEBUGF(3, "edge_distance_to_point=%g, node_radius=%g", d, node->radius);
	if ( FP_LTEQ(d, node->radius) )
	{
		LWDEBUGF(3,"entering this branch (%p)", node);
		
		/* Return the crossing number of this leaf */
		if ( circ_node_is_leaf(node) )
		{
			int inter;
			LWDEBUGF(3, "leaf node calculation (edge %d)", node->edge_num);
			geographic_point_init(node->p1->x, node->p1->y, &(edge.start));
			geographic_point_init(node->p2->x, node->p2->y, &(edge.end));
			geog2cart(&(edge.start), &E1);
			geog2cart(&(edge.end), &E2);
			
			inter = edge_intersects(&S1, &S2, &E1, &E2);
			
			if ( inter & PIR_INTERSECTS )
			{
				LWDEBUG(3," got stab line edge_intersection with this edge!");
				/* To avoid double counting crossings-at-a-vertex, */
				/* always ignore crossings at "lower" ends of edges*/

				if ( inter & PIR_B_TOUCH_RIGHT || inter & PIR_COLINEAR )
				{
					LWDEBUG(3,"  rejecting stab line grazing by left-side edge");
					return 0;
				}
				else
				{
					LWDEBUG(3,"  accepting stab line intersection");
					return 1;
				}
			}
		}
		/* Or, add up the crossing numbers of all children of this node. */
		else
		{
			c = 0;
			for ( i = 0; i < node->num_nodes; i++ )
			{
				LWDEBUG(3,"internal node calculation");
				LWDEBUGF(3," calling circ_tree_contains_point on child %d!", i);
				c += circ_tree_contains_point(node->nodes[i], pt, pt_outside, on_boundary);
			}
			return c % 2;
		}
	}
	else
	{
		LWDEBUGF(3,"skipping this branch (%p)", node);
	}
	
	return 0;
}