예제 #1
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/**
* Returns the area in cartesian units. Area is negative if ring is oriented CCW, 
* positive if it is oriented CW and zero if the ring is degenerate or flat.
* http://en.wikipedia.org/wiki/Shoelace_formula
*/
double
ptarray_signed_area(const POINTARRAY *pa)
{
	const POINT2D *P1;
	const POINT2D *P2;
	const POINT2D *P3;
	double sum = 0.0;
	double x0, x, y1, y2;
	int i;
	
	if (! pa || pa->npoints < 3 )
		return 0.0;
		
	P1 = getPoint2d_cp(pa, 0);
	P2 = getPoint2d_cp(pa, 1);
	x0 = P1->x;
	for ( i = 1; i < pa->npoints - 1; i++ )
	{
		P3 = getPoint2d_cp(pa, i+1);
		x = P2->x - x0;
		y1 = P3->y;
		y2 = P1->y;
		sum += x * (y2-y1);
		
		/* Move forwards! */
		P1 = P2;
		P2 = P3;
	}
	return sum / 2.0;	
}
예제 #2
0
int
pt_in_ring_2d(const POINT2D *p, const POINTARRAY *ring)
{
	int cn = 0;    /* the crossing number counter */
	int i;
	const POINT2D *v1, *v2;
	const POINT2D *first, *last;

	first = getPoint2d_cp(ring, 0);
	last = getPoint2d_cp(ring, ring->npoints-1);
	if ( memcmp(first, last, sizeof(POINT2D)) )
	{
		lwerror("pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)",
		        first->x, first->y, last->x, last->y);
		return LW_FALSE;

	}

	LWDEBUGF(2, "pt_in_ring_2d called with point: %g %g", p->x, p->y);
	/* printPA(ring); */

	/* loop through all edges of the polygon */
	v1 = getPoint2d_cp(ring, 0);
	for (i=0; i<ring->npoints-1; i++)
	{
		double vt;
		v2 = getPoint2d_cp(ring, i+1);

		/* edge from vertex i to vertex i+1 */
		if
		(
		    /* an upward crossing */
		    ((v1->y <= p->y) && (v2->y > p->y))
		    /* a downward crossing */
		    || ((v1->y > p->y) && (v2->y <= p->y))
		)
		{

			vt = (double)(p->y - v1->y) / (v2->y - v1->y);

			/* P->x <intersect */
			if (p->x < v1->x + vt * (v2->x - v1->x))
			{
				/* a valid crossing of y=p->y right of p->x */
				++cn;
			}
		}
		v1 = v2;
	}

	LWDEBUGF(3, "pt_in_ring_2d returning %d", cn&1);

	return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
}
예제 #3
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
static void
ptarray_dp_findsplit(POINTARRAY *pts, int p1, int p2, int *split, double *dist)
{
	int k;
	const POINT2D *pk, *pa, *pb;
	double tmp, d;

	LWDEBUG(4, "function called");

	*split = p1;
	d = -1;

	if (p1 + 1 < p2)
	{

		pa = getPoint2d_cp(pts, p1);
		pb = getPoint2d_cp(pts, p2);

		LWDEBUGF(4, "P%d(%f,%f) to P%d(%f,%f)",
		         p1, pa->x, pa->y, p2, pb->x, pb->y);

		for (k=p1+1; k<p2; k++)
		{
			pk = getPoint2d_cp(pts, k);

			LWDEBUGF(4, "P%d(%f,%f)", k, pk->x, pk->y);

			/* distance computation */
			tmp = distance2d_sqr_pt_seg(pk, pa, pb);

			if (tmp > d)
			{
				d = tmp;	/* record the maximum */
				*split = k;

				LWDEBUGF(4, "P%d is farthest (%g)", k, d);
			}
		}
		*dist = d;

	} /* length---should be redone if can == 0 */
	else
	{
		LWDEBUG(3, "segment too short, no split/no dist");
		*dist = -1;
	}

}
예제 #4
0
static size_t
pointArray_to_geojson(POINTARRAY *pa, char *output, int precision)
{
	int i;
	char *ptr;
#define BUFSIZE OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION
	char x[BUFSIZE+1];
	char y[BUFSIZE+1];
	char z[BUFSIZE+1];

	assert ( precision <= OUT_MAX_DOUBLE_PRECISION );

  /* Ensure a terminating NULL at the end of buffers
   * so that we don't need to check for truncation
   * inprint_double */
  x[BUFSIZE] = '\0';
  y[BUFSIZE] = '\0';
  z[BUFSIZE] = '\0';

	ptr = output;

  /* TODO: rewrite this loop to be simpler and possibly quicker */
	if (!FLAGS_GET_Z(pa->flags))
	{
		for (i=0; i<pa->npoints; i++)
		{
			const POINT2D *pt;
			pt = getPoint2d_cp(pa, i);

			lwprint_double(pt->x, precision, x, BUFSIZE);
			trim_trailing_zeros(x);
			lwprint_double(pt->y, precision, y, BUFSIZE);
			trim_trailing_zeros(y);

			if ( i ) ptr += sprintf(ptr, ",");
			ptr += sprintf(ptr, "[%s,%s]", x, y);
		}
	}
	else
	{
		for (i=0; i<pa->npoints; i++)
		{
			const POINT3DZ *pt;
			pt = getPoint3dz_cp(pa, i);

			lwprint_double(pt->x, precision, x, BUFSIZE);
			trim_trailing_zeros(x);
			lwprint_double(pt->y, precision, y, BUFSIZE);
			trim_trailing_zeros(y);
			lwprint_double(pt->z, precision, z, BUFSIZE);
			trim_trailing_zeros(z);

			if ( i ) ptr += sprintf(ptr, ",");
			ptr += sprintf(ptr, "[%s,%s,%s]", x, y, z);
		}
	}

	return (ptr-output);
}
예제 #5
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
int 
ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
{
	const POINT2D *pt;
	int n = 0;
	int i;
	for ( i = 0; i < pa->npoints; i++ )
	{
		pt = getPoint2d_cp(pa, i);
		if ( gbox_contains_point2d(gbox, pt) )
			n++;
	}
	return n;
}
예제 #6
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/**
* Find the 2d length of the given #POINTARRAY (even if it's 3d)
*/
double
ptarray_length_2d(const POINTARRAY *pts)
{
	double dist = 0.0;
	int i;
	const POINT2D *frm;
	const POINT2D *to;

	if ( pts->npoints < 2 ) return 0.0;

	frm = getPoint2d_cp(pts, 0);
	
	for ( i=1; i < pts->npoints; i++ )
	{
		to = getPoint2d_cp(pts, i);

		dist += sqrt( ((frm->x - to->x)*(frm->x - to->x))  +
		              ((frm->y - to->y)*(frm->y - to->y)) );
		
		frm = to;
	}
	return dist;
}
예제 #7
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/**
* Find the 2d length of the given #POINTARRAY, using circular
* arc interpolation between each coordinate triple.
* Length(A1, A2, A3, A4, A5) = Length(A1, A2, A3)+Length(A3, A4, A5)
*/
double
ptarray_arc_length_2d(const POINTARRAY *pts)
{
	double dist = 0.0;
	int i;
	const POINT2D *a1;
	const POINT2D *a2;
	const POINT2D *a3;

	if ( pts->npoints % 2 != 1 )
        lwerror("arc point array with even number of points");
        
	a1 = getPoint2d_cp(pts, 0);
	
	for ( i=2; i < pts->npoints; i += 2 )
	{
    	a2 = getPoint2d_cp(pts, i-1);
		a3 = getPoint2d_cp(pts, i);
		dist += lw_arc_length(a1, a2, a3);
		a1 = a3;
	}
	return dist;
}
예제 #8
0
/**
* POINT
* Read a WKB point, starting just after the endian byte,
* type number and optional srid number.
* Advance the parse state forward appropriately.
* WKB point has just a set of doubles, with the quantity depending on the
* dimension of the point, so this looks like a special case of the above
* with only one point.
*/
static LWPOINT* lwpoint_from_wkb_state(wkb_parse_state *s)
{
	static uint32_t npoints = 1;
	POINTARRAY *pa = NULL;
	size_t pa_size;
	uint32_t ndims = 2;
	const POINT2D *pt;

	/* Count the dimensions. */
	if( s->has_z ) ndims++;
	if( s->has_m ) ndims++;
	pa_size = ndims * WKB_DOUBLE_SIZE;

	/* Does the data we want to read exist? */
	wkb_parse_state_check(s, pa_size);

	/* If we're in a native endianness, we can just copy the data directly! */
	if( ! s->swap_bytes )
	{
		pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos);
		s->pos += pa_size;
	}
	/* Otherwise we have to read each double, separately */
	else
	{
		int i = 0;
		double *dlist;
		pa = ptarray_construct(s->has_z, s->has_m, npoints);
		dlist = (double*)(pa->serialized_pointlist);
		for( i = 0; i < ndims; i++ )
		{
			dlist[i] = double_from_wkb_state(s);
		}
	}

	/* Check for POINT(NaN NaN) ==> POINT EMPTY */
	pt = getPoint2d_cp(pa, 0);
	if ( isnan(pt->x) && isnan(pt->y) )
	{
		ptarray_free(pa);
		return lwpoint_construct_empty(s->srid, s->has_z, s->has_m);
	}
	else
	{
		return lwpoint_construct(s->srid, NULL, pa);
	}
}
예제 #9
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
int 
ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
{
	int wn = 0;
	int i, side;
	const POINT2D *seg1;
	const POINT2D *seg2;
	const POINT2D *seg3;
	GBOX gbox;

	/* Check for not an arc ring (always have odd # of points) */
	if ( (pa->npoints % 2) == 0 )
	{
		lwerror("ptarrayarc_contains_point called with even number of points");
		return LW_OUTSIDE;
	}

	/* Check for not an arc ring (always have >= 3 points) */
	if ( pa->npoints < 3 )
	{
		lwerror("ptarrayarc_contains_point called too-short pointarray");
		return LW_OUTSIDE;
	}

	/* Check for unclosed case */
	seg1 = getPoint2d_cp(pa, 0);
	seg3 = getPoint2d_cp(pa, pa->npoints-1);
	if ( check_closed && ! p2d_same(seg1, seg3) )
	{
		lwerror("ptarrayarc_contains_point called on unclosed ring");
		return LW_OUTSIDE;
	} 
	/* OK, it's closed. Is it just one circle? */
	else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
	{
		double radius, d;
		POINT2D c;
		seg2 = getPoint2d_cp(pa, 1);
		
		/* Wait, it's just a point, so it can't contain anything */
		if ( lw_arc_is_pt(seg1, seg2, seg3) )
			return LW_OUTSIDE;
			
		/* See if the point is within the circle radius */
		radius = lw_arc_center(seg1, seg2, seg3, &c);
		d = distance2d_pt_pt(pt, &c);
		if ( FP_EQUALS(d, radius) )
			return LW_BOUNDARY; /* Boundary of circle */
		else if ( d < radius ) 
			return LW_INSIDE; /* Inside circle */
		else 
			return LW_OUTSIDE; /* Outside circle */
	} 
	else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
	{
		return LW_BOUNDARY; /* Boundary case */
	}

	/* Start on the ring */
	seg1 = getPoint2d_cp(pa, 0);
	for ( i=1; i < pa->npoints; i += 2 )
	{
		seg2 = getPoint2d_cp(pa, i);
		seg3 = getPoint2d_cp(pa, i+1);
		
		/* Catch an easy boundary case */
		if( p2d_same(seg3, pt) )
			return LW_BOUNDARY;
		
		/* Skip arcs that have no size */
		if ( lw_arc_is_pt(seg1, seg2, seg3) )
		{
			seg1 = seg3;
			continue;
		}
		
		/* Only test segments in our vertical range */
		lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
		if ( pt->y > gbox.ymax || pt->y < gbox.ymin ) 
		{
			seg1 = seg3;
			continue;
		}

		/* Outside of horizontal range, and not between end points we also skip */
		if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) && 
			 (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) ) 
		{
			seg1 = seg3;
			continue;
		}		
		
		side = lw_arc_side(seg1, seg2, seg3, pt);
		
		/* On the boundary */
		if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
		{
			return LW_BOUNDARY;
		}
		
		/* Going "up"! Point to left of arc. */
		if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
		{
			wn++;
		}

		/* Going "down"! */
		if ( side > 0 && (seg2->y <= pt->y) && (pt->y < seg1->y) )
		{
			wn--;
		}
		
		/* Inside the arc! */
		if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin ) 
		{
			POINT2D C;
			double radius = lw_arc_center(seg1, seg2, seg3, &C);
			double d = distance2d_pt_pt(pt, &C);

			/* On the boundary! */
			if ( d == radius )
				return LW_BOUNDARY;
			
			/* Within the arc! */
			if ( d  < radius )
			{
				/* Left side, increment winding number */
				if ( side < 0 )
					wn++;
				/* Right side, decrement winding number */
				if ( side > 0 ) 
					wn--;
			}
		}

		seg1 = seg3;
	}

	/* Sent out the winding number for calls that are building on this as a primitive */
	if ( winding_number )
		*winding_number = wn;

	/* Outside */
	if (wn == 0)
	{
		return LW_OUTSIDE;
	}
	
	/* Inside */
	return LW_INSIDE;
}
예제 #10
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
int 
ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
{
	int wn = 0;
	int i;
	double side;
	const POINT2D *seg1;
	const POINT2D *seg2;
	double ymin, ymax;

	seg1 = getPoint2d_cp(pa, 0);
	seg2 = getPoint2d_cp(pa, pa->npoints-1);
	if ( check_closed && ! p2d_same(seg1, seg2) )
		lwerror("ptarray_contains_point called on unclosed ring");
	
	for ( i=1; i < pa->npoints; i++ )
	{
		seg2 = getPoint2d_cp(pa, i);
		
		/* Zero length segments are ignored. */
		if ( seg1->x == seg2->x && seg1->y == seg2->y )
		{
			seg1 = seg2;
			continue;
		}
			
		ymin = FP_MIN(seg1->y, seg2->y);
		ymax = FP_MAX(seg1->y, seg2->y);
		
		/* Only test segments in our vertical range */
		if ( pt->y > ymax || pt->y < ymin ) 
		{
			seg1 = seg2;
			continue;
		}

		side = lw_segment_side(seg1, seg2, pt);

		/* 
		* A point on the boundary of a ring is not contained. 
		* WAS: if (fabs(side) < 1e-12), see #852 
		*/
		if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) )
		{
			return LW_BOUNDARY;
		}

		/*
		* If the point is to the left of the line, and it's rising,
		* then the line is to the right of the point and
		* circling counter-clockwise, so incremement.
		*/
		if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) )
		{
			wn++;
		}
		
		/*
		* If the point is to the right of the line, and it's falling,
		* then the line is to the right of the point and circling
		* clockwise, so decrement.
		*/
		else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
		{
			wn--;
		}
		
		seg1 = seg2;
	}

	/* Sent out the winding number for calls that are building on this as a primitive */
	if ( winding_number )
		*winding_number = wn;

	/* Outside */
	if (wn == 0)
	{
		return LW_OUTSIDE;
	}
	
	/* Inside */
	return LW_INSIDE;
}
예제 #11
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/*
 * Returns a POINTARRAY with consecutive equal points
 * removed. Equality test on all dimensions of input.
 *
 * Always returns a newly allocated object.
 *
 */
POINTARRAY *
ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
{
	POINTARRAY* out;
	size_t ptsize;
	size_t ipn, opn;
	const POINT2D *last_point, *this_point;
	double tolsq = tolerance * tolerance;

	if ( minpoints < 1 ) minpoints = 1;

	LWDEBUGF(3, "%s called", __func__);

	/* Single or zero point arrays can't have duplicates */
	if ( in->npoints < 3 ) return ptarray_clone_deep(in);

	ptsize = ptarray_point_size(in);

	LWDEBUGF(3, " ptsize: %d", ptsize);

	/* Allocate enough space for all points */
	out = ptarray_construct(FLAGS_GET_Z(in->flags),
	                        FLAGS_GET_M(in->flags), in->npoints);

	/* Now fill up the actual points (NOTE: could be optimized) */

	opn=1;
	/* Keep the first point */
	memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize);
	last_point = getPoint2d_cp(in, 0);
	LWDEBUGF(3, " first point copied, out points: %d", opn);
	for ( ipn = 1; ipn < in->npoints; ++ipn)
	{
		this_point = getPoint2d_cp(in, ipn);
		if ( ipn < in->npoints-minpoints+1 || opn >= minpoints ) /* need extra points to hit minponts */
		{
			if (
				(tolerance == 0 && memcmp(getPoint_internal(in, ipn-1), getPoint_internal(in, ipn), ptsize) == 0) || /* exact dupe */
				(tolerance > 0.0 && distance2d_sqr_pt_pt(last_point, this_point) <= tolsq) /* within the removal tolerance */
			) continue;
		}

		/*
		 * The point is different (see above) from the previous,
		 * so we add it to output
		 */
		memcpy(getPoint_internal(out, opn++), getPoint_internal(in, ipn), ptsize);
		last_point = this_point;
		LWDEBUGF(3, " Point %d differs from point %d. Out points: %d", ipn, ipn-1, opn);
	}
	/* Keep the last point */
	if ( memcmp(last_point, getPoint_internal(in, ipn-1), ptsize) != 0 )
	{
		memcpy(getPoint_internal(out, opn-1), getPoint_internal(in, ipn-1), ptsize);
	}

	LWDEBUGF(3, " in:%d out:%d", out->npoints, opn);
	out->npoints = opn;

	return out;
}
예제 #12
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/*
 * Given a point, returns the location of closest point on pointarray
 * and, optionally, it's actual distance from the point array.
 */
double
ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
{
	double mindist=-1;
	double tlen, plen;
	int t, seg=-1;
	POINT4D	start4d, end4d, projtmp;
	POINT2D proj, p;
	const POINT2D *start = NULL, *end = NULL;

	/* Initialize our 2D copy of the input parameter */
	p.x = p4d->x;
	p.y = p4d->y;
	
	if ( ! proj4d ) proj4d = &projtmp;
	
	start = getPoint2d_cp(pa, 0);
	
	/* If the pointarray has only one point, the nearest point is */
	/* just that point */
	if ( pa->npoints == 1 )
	{
		getPoint4d_p(pa, 0, proj4d);
		if ( mindistout )
			*mindistout = distance2d_pt_pt(&p, start);
		return 0.0;
	}
	
	/* Loop through pointarray looking for nearest segment */
	for (t=1; t<pa->npoints; t++)
	{
		double dist;
		end = getPoint2d_cp(pa, t);
		dist = distance2d_pt_seg(&p, start, end);

		if (t==1 || dist < mindist )
		{
			mindist = dist;
			seg=t-1;
		}

		if ( mindist == 0 )
		{
			LWDEBUG(3, "Breaking on mindist=0");
			break;
		}

		start = end;
	}

	if ( mindistout ) *mindistout = mindist;

	LWDEBUGF(3, "Closest segment: %d", seg);
	LWDEBUGF(3, "mindist: %g", mindist);

	/*
	 * We need to project the
	 * point on the closest segment.
	 */
	getPoint4d_p(pa, seg, &start4d);
	getPoint4d_p(pa, seg+1, &end4d);
	closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
	
	/* Copy 4D values into 2D holder */
	proj.x = proj4d->x;
	proj.y = proj4d->y;

	LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);

	/* For robustness, force 1 when closest point == endpoint */
	if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, end) )
	{
		return 1.0;
	}

	LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);

	tlen = ptarray_length_2d(pa);

	LWDEBUGF(3, "tlen %g", tlen);

	/* Location of any point on a zero-length line is 0 */
	/* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
	if ( tlen == 0 ) return 0;

	plen=0;
	start = getPoint2d_cp(pa, 0);
	for (t=0; t<seg; t++, start=end)
	{
		end = getPoint2d_cp(pa, t+1);
		plen += distance2d_pt_pt(start, end);

		LWDEBUGF(4, "Segment %d made plen %g", t, plen);
	}

	plen+=distance2d_pt_pt(&proj, start);

	LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);

	return plen/tlen;
}
예제 #13
0
int *
lwgeom_cluster_2d_kmeans(const LWGEOM **geoms, int ngeoms, int k)
{
	int i;
	int num_centroids = 0;
	LWGEOM **centroids;
	POINT2D *centers_raw;
	const POINT2D *cp;
	POINT2D min = { DBL_MAX,   DBL_MAX };
	POINT2D max = { -DBL_MAX, -DBL_MAX };
	double dx, dy;
	kmeans_config config;
	kmeans_result result;
	int *seen;
	int sidx = 0;

	assert(k>0);
	assert(ngeoms>0);
	assert(geoms);

    /* Initialize our static structs */
    memset(&config, 0, sizeof(kmeans_config));
    memset(&result, 0, sizeof(kmeans_result));

	if (ngeoms<k)
	{
		lwerror("%s: number of geometries is less than the number of clusters requested", __func__);
	}

	/* We'll hold the temporary centroid objects here */
	centroids = lwalloc(sizeof(LWGEOM*) * ngeoms);
	memset(centroids, 0, sizeof(LWGEOM*) * ngeoms);

	/* The vector of cluster means. We have to allocate a */
	/* chunk of memory for these because we'll be mutating them */
	/* in the kmeans algorithm */
	centers_raw = lwalloc(sizeof(POINT2D) * k);
	memset(centers_raw, 0, sizeof(POINT2D) * k);

	/* K-means configuration setup */
	config.objs = lwalloc(sizeof(Pointer) * ngeoms);
	config.num_objs = ngeoms;
	config.clusters = lwalloc(sizeof(int) * ngeoms);
	config.centers = lwalloc(sizeof(Pointer) * k);
	config.k = k;
	config.max_iterations = 0;
	config.distance_method = lwkmeans_pt_distance;
	config.centroid_method = lwkmeans_pt_centroid;

	/* Clean the memory */
	memset(config.objs, 0, sizeof(Pointer) * ngeoms);
	memset(config.clusters, 0, sizeof(int) * ngeoms);
	memset(config.centers, 0, sizeof(Pointer) * k);

	/* Prepare the list of object pointers for K-means */
	for (i = 0; i < ngeoms; i++)
	{
		const LWGEOM *geom = geoms[i];
		LWPOINT *lwpoint;

		/* Null/empty geometries get a NULL pointer */
		if ((!geom) || lwgeom_is_empty(geom))
		{
			config.objs[i] = NULL;
			continue;
		}

		/* If the input is a point, use its coordinates */
		/* If its not a point, convert it to one via centroid */
		if (lwgeom_get_type(geom) != POINTTYPE)
		{
			LWGEOM *centroid = lwgeom_centroid(geom);
			if ((!centroid) || lwgeom_is_empty(centroid))
			{
				config.objs[i] = NULL;
				continue;
			}
			centroids[num_centroids++] = centroid;
			lwpoint = lwgeom_as_lwpoint(centroid);
		}
		else
		{
			lwpoint = lwgeom_as_lwpoint(geom);
		}

		/* Store a pointer to the POINT2D we are interested in */
		cp = getPoint2d_cp(lwpoint->point, 0);
		config.objs[i] = (Pointer)cp;

		/* Since we're already here, let's calculate the extrema of the set */
		if (cp->x < min.x) min.x = cp->x;
		if (cp->y < min.y) min.y = cp->y;
		if (cp->x > max.x) max.x = cp->x;
		if (cp->y > max.y) max.y = cp->y;
	}

	/*
	* We map a uniform assignment of points in the area covered by the set
	* onto actual points in the set
	*/
	dx = (max.x - min.x)/k;
	dy = (max.y - min.y)/k;
	seen = lwalloc(sizeof(int)*config.k);
	memset(seen, 0, sizeof(int)*config.k);
	for (i = 0; i < k; i++)
	{
		int closest;
		POINT2D p;
		int j;

		/* Calculate a point in the range */
		p.x = min.x + dx * (i + 0.5);
		p.y = min.y + dy * (i + 0.5);

		/* Find the data point closest to the calculated point */
		closest = lwkmeans_pt_closest(config.objs, config.num_objs, &p);

		/* If something is terrible wrong w/ data, cannot find a closest */
		if (closest < 0)
			lwerror("unable to calculate cluster seed points, too many NULLs or empties?");

		/* Ensure we aren't already using that point as a seed */
		j = 0;
		while(j < sidx)
		{
			if (seen[j] == closest)
			{
				closest = (closest + 1) % config.num_objs;
				j = 0;
			}
			else
			{
				j++;
			}
		}
		seen[sidx++] = closest;

		/* Copy the point coordinates into the initial centers array */
		/* This is ugly, but the centers array is an array of */
		/* pointers to points, not an array of points */
		centers_raw[i] = *((POINT2D*)config.objs[closest]);
		config.centers[i] = &(centers_raw[i]);
	}

	result = kmeans(&config);

	/* Before error handling, might as well clean up all the inputs */
	lwfree(config.objs);
	lwfree(config.centers);
	lwfree(centers_raw);
	lwfree(centroids);
	lwfree(seen);

	/* Good result */
	if (result == KMEANS_OK)
		return config.clusters;

	/* Bad result, not going to need the answer */
	lwfree(config.clusters);
	if (result == KMEANS_EXCEEDED_MAX_ITERATIONS)
	{
		lwerror("%s did not converge after %d iterations", __func__, config.max_iterations);
		return NULL;
	}

	/* Unknown error */
	return NULL;
}
예제 #14
0
/**
** @brief lwline_crossing_direction: returns the kind of #CG_LINE_CROSS_TYPE behavior  of 2 linestrings
** @param l1 first line string
** @param l2 second line string
** @return a #CG_LINE_CROSS_TYPE
**   LINE_NO_CROSS = 0
**   LINE_CROSS_LEFT = -1
**   LINE_CROSS_RIGHT = 1
**   LINE_MULTICROSS_END_LEFT = -2
**   LINE_MULTICROSS_END_RIGHT = 2
**   LINE_MULTICROSS_END_SAME_FIRST_LEFT = -3
**   LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3
**
*/
int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2)
{
	int i = 0, j = 0;
	const POINT2D *p1, *p2, *q1, *q2;
	POINTARRAY *pa1 = NULL, *pa2 = NULL;
	int cross_left = 0;
	int cross_right = 0;
	int first_cross = 0;
	int this_cross = 0;

	pa1 = (POINTARRAY*)l1->points;
	pa2 = (POINTARRAY*)l2->points;

	/* One-point lines can't intersect (and shouldn't exist). */
	if ( pa1->npoints < 2 || pa2->npoints < 2 )
		return LINE_NO_CROSS;

	LWDEBUGF(4, "l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1));
	LWDEBUGF(4, "l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2));

	/* Initialize first point of q */
	q1 = getPoint2d_cp(pa2, 0);

	for ( i = 1; i < pa2->npoints; i++ )
	{

		/* Update second point of q to next value */
		q2 = getPoint2d_cp(pa2, i);

		/* Initialize first point of p */
		p1 = getPoint2d_cp(pa1, 0);

		for ( j = 1; j < pa1->npoints; j++ )
		{

			/* Update second point of p to next value */
			p2 = getPoint2d_cp(pa1, j);

			this_cross = lw_segment_intersects(p1, p2, q1, q2);

			LWDEBUGF(4, "i=%d, j=%d (%.8g %.8g, %.8g %.8g)", this_cross, i, j, p1->x, p1->y, p2->x, p2->y);

			if ( this_cross == SEG_CROSS_LEFT )
			{
				LWDEBUG(4,"this_cross == SEG_CROSS_LEFT");
				cross_left++;
				if ( ! first_cross )
					first_cross = SEG_CROSS_LEFT;
			}

			if ( this_cross == SEG_CROSS_RIGHT )
			{
				LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT");
				cross_right++;
				if ( ! first_cross )
					first_cross = SEG_CROSS_LEFT;
			}

			/*
			** Crossing at a co-linearity can be turned handled by extending
			** segment to next vertext and seeing if the end points straddle
			** the co-linear segment.
			*/
			if ( this_cross == SEG_COLINEAR )
			{
				LWDEBUG(4,"this_cross == SEG_COLINEAR");
				/* TODO: Add logic here and in segment_intersects()
				continue;
				*/
			}

			LWDEBUG(4,"this_cross == SEG_NO_INTERSECTION");

			/* Turn second point of p into first point */
			p1 = p2;

		}

		/* Turn second point of q into first point */
		q1 = q2;

	}

	LWDEBUGF(4, "first_cross=%d, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right);

	if ( !cross_left && !cross_right )
		return LINE_NO_CROSS;

	if ( !cross_left && cross_right == 1 )
		return LINE_CROSS_RIGHT;

	if ( !cross_right && cross_left == 1 )
		return LINE_CROSS_LEFT;

	if ( cross_left - cross_right == 1 )
		return LINE_MULTICROSS_END_LEFT;

	if ( cross_left - cross_right == -1 )
		return LINE_MULTICROSS_END_RIGHT;

	if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT )
		return LINE_MULTICROSS_END_SAME_FIRST_LEFT;

	if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT )
		return LINE_MULTICROSS_END_SAME_FIRST_RIGHT;

	return LINE_NO_CROSS;

}