static void test_lwline_clip_big(void) { POINTARRAY *pa = ptarray_construct(1, 0, 3); LWLINE *line = lwline_construct(SRID_UNKNOWN, NULL, pa); LWCOLLECTION *c; char *ewkt; POINT4D p; p.x = 0.0; p.y = 0.0; p.z = 0.0; ptarray_set_point4d(pa, 0, &p); p.x = 1.0; p.y = 1.0; p.z = 1.0; ptarray_set_point4d(pa, 1, &p); p.x = 2.0; p.y = 2.0; p.z = 2.0; ptarray_set_point4d(pa, 2, &p); c = lwline_clip_to_ordinate_range(line, 'Z', 0.5, 1.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0.5 0.5 0.5,1 1 1,1.5 1.5 1.5))" ); lwfree(ewkt); lwcollection_free(c); lwline_free(line); }
static LWGEOM* circstring_from_pa(const POINTARRAY *pa, int srid, int start, int end) { POINT4D p0, p1, p2; POINTARRAY *pao = ptarray_construct(ptarray_has_z(pa), ptarray_has_m(pa), 3); LWDEBUGF(4, "srid=%d, start=%d, end=%d", srid, start, end); getPoint4d_p(pa, start, &p0); ptarray_set_point4d(pao, 0, &p0); getPoint4d_p(pa, (start+end)/2, &p1); ptarray_set_point4d(pao, 1, &p1); getPoint4d_p(pa, end+1, &p2); ptarray_set_point4d(pao, 2, &p2); return lwcircstring_as_lwgeom(lwcircstring_construct(srid, NULL, pao)); }
/** * Affine transform a pointarray. */ void ptarray_affine(POINTARRAY *pa, const AFFINE *a) { int i; double x,y,z; POINT4D p4d; LWDEBUG(2, "lwgeom_affine_ptarray start"); if ( FLAGS_GET_Z(pa->flags) ) { LWDEBUG(3, " has z"); for (i=0; i<pa->npoints; i++) { getPoint4d_p(pa, i, &p4d); x = p4d.x; y = p4d.y; z = p4d.z; p4d.x = a->afac * x + a->bfac * y + a->cfac * z + a->xoff; p4d.y = a->dfac * x + a->efac * y + a->ffac * z + a->yoff; p4d.z = a->gfac * x + a->hfac * y + a->ifac * z + a->zoff; ptarray_set_point4d(pa, i, &p4d); LWDEBUGF(3, " POINT %g %g %g => %g %g %g", x, y, x, p4d.x, p4d.y, p4d.z); } } else { LWDEBUG(3, " doesn't have z"); for (i=0; i<pa->npoints; i++) { getPoint4d_p(pa, i, &p4d); x = p4d.x; y = p4d.y; p4d.x = a->afac * x + a->bfac * y + a->xoff; p4d.y = a->dfac * x + a->efac * y + a->yoff; ptarray_set_point4d(pa, i, &p4d); LWDEBUGF(3, " POINT %g %g %g => %g %g %g", x, y, x, p4d.x, p4d.y, p4d.z); } } LWDEBUG(3, "lwgeom_affine_ptarray end"); }
/* * Add a point into a pointarray. Only adds as many dimensions as the * pointarray supports. */ int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, int where) { size_t point_size = ptarray_point_size(pa); LWDEBUGF(5,"pa = %p; p = %p; where = %d", pa, p, where); LWDEBUGF(5,"pa->npoints = %d; pa->maxpoints = %d", pa->npoints, pa->maxpoints); if ( FLAGS_GET_READONLY(pa->flags) ) { lwerror("ptarray_insert_point: called on read-only point array"); return LW_FAILURE; } /* Error on invalid offset value */ if ( where > pa->npoints || where < 0) { lwerror("ptarray_insert_point: offset out of range (%d)", where); return LW_FAILURE; } /* If we have no storage, let's allocate some */ if( pa->maxpoints == 0 || ! pa->serialized_pointlist ) { pa->maxpoints = 32; pa->npoints = 0; pa->serialized_pointlist = lwalloc(ptarray_point_size(pa) * pa->maxpoints); } /* Error out if we have a bad situation */ if ( pa->npoints > pa->maxpoints ) { lwerror("npoints (%d) is greated than maxpoints (%d)", pa->npoints, pa->maxpoints); return LW_FAILURE; } /* Check if we have enough storage, add more if necessary */ if( pa->npoints == pa->maxpoints ) { pa->maxpoints *= 2; pa->serialized_pointlist = lwrealloc(pa->serialized_pointlist, ptarray_point_size(pa) * pa->maxpoints); } /* Make space to insert the new point */ if( where < pa->npoints ) { size_t copy_size = point_size * (pa->npoints - where); memmove(getPoint_internal(pa, where+1), getPoint_internal(pa, where), copy_size); LWDEBUGF(5,"copying %d bytes to start vertex %d from start vertex %d", copy_size, where+1, where); } /* We have one more point */ ++pa->npoints; /* Copy the new point into the gap */ ptarray_set_point4d(pa, where, p); LWDEBUGF(5,"copying new point to start vertex %d", point_size, where); return LW_SUCCESS; }
static LWGEOM* linestring_from_pa(const POINTARRAY *pa, int srid, int start, int end) { int i = 0, j = 0; POINT4D p; POINTARRAY *pao = ptarray_construct(ptarray_has_z(pa), ptarray_has_m(pa), end-start+2); LWDEBUGF(4, "srid=%d, start=%d, end=%d", srid, start, end); for( i = start; i < end + 2; i++ ) { getPoint4d_p(pa, i, &p); ptarray_set_point4d(pao, j++, &p); } return lwline_as_lwgeom(lwline_construct(srid, NULL, pao)); }
/** * Transform given POINTARRAY * from inpj projection to outpj projection */ int ptarray_transform(POINTARRAY *pa, projPJ inpj, projPJ outpj) { int i; POINT4D p; for ( i = 0; i < pa->npoints; i++ ) { getPoint4d_p(pa, i, &p); if ( ! point4d_transform(&p, inpj, outpj) ) return LW_FAILURE; ptarray_set_point4d(pa, i, &p); } return LW_SUCCESS; }
/** * Reverse X and Y axis on a given POINTARRAY */ POINTARRAY* ptarray_flip_coordinates(POINTARRAY *pa) { int i; double d; POINT4D p; for (i=0 ; i < pa->npoints ; i++) { getPoint4d_p(pa, i, &p); d = p.y; p.y = p.x; p.x = d; ptarray_set_point4d(pa, i, &p); } return pa; }
/* Return a POINTARRAY from a GEOSCoordSeq */ POINTARRAY * ptarray_from_GEOSCoordSeq(const GEOSCoordSequence *cs, char want3d) { uint32_t dims=2; uint32_t size, i, ptsize; POINTARRAY *pa; POINT4D point; LWDEBUG(2, "ptarray_fromGEOSCoordSeq called"); if ( ! GEOSCoordSeq_getSize(cs, &size) ) lwerror("Exception thrown"); LWDEBUGF(4, " GEOSCoordSeq size: %d", size); if ( want3d ) { if ( ! GEOSCoordSeq_getDimensions(cs, &dims) ) lwerror("Exception thrown"); LWDEBUGF(4, " GEOSCoordSeq dimensions: %d", dims); /* forget higher dimensions (if any) */ if ( dims > 3 ) dims = 3; } LWDEBUGF(4, " output dimensions: %d", dims); ptsize = sizeof(double)*dims; pa = ptarray_construct((dims==3), 0, size); for (i=0; i<size; i++) { GEOSCoordSeq_getX(cs, i, &(point.x)); GEOSCoordSeq_getY(cs, i, &(point.y)); if ( dims >= 3 ) GEOSCoordSeq_getZ(cs, i, &(point.z)); ptarray_set_point4d(pa,i,&point); } return pa; }
/** * Scale a pointarray. */ void ptarray_scale(POINTARRAY *pa, const POINT4D *fact) { int i; POINT4D p4d; LWDEBUG(3, "ptarray_scale start"); for (i=0; i<pa->npoints; ++i) { getPoint4d_p(pa, i, &p4d); p4d.x *= fact->x; p4d.y *= fact->y; p4d.z *= fact->z; p4d.m *= fact->m; ptarray_set_point4d(pa, i, &p4d); } LWDEBUG(3, "ptarray_scale end"); }
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2) { int i; double d, *dp1, *dp2; POINT4D p; #if PARANOIA_LEVEL > 0 assert(o1 < 4); assert(o2 < 4); #endif dp1 = ((double*)&p)+(unsigned)o1; dp2 = ((double*)&p)+(unsigned)o2; for (i=0 ; i < pa->npoints ; i++) { getPoint4d_p(pa, i, &p); d = *dp2; *dp2 = *dp1; *dp1 = d; ptarray_set_point4d(pa, i, &p); } }
/* * Note: input will be changed, make sure you have permissions for this. * */ void lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint) { ptarray_set_point4d(curve->points, index, newpoint); }
/** * Take in a LINESTRING and return a MULTILINESTRING of those portions of the * LINESTRING between the from/to range for the specified ordinate (XYZM) */ LWCOLLECTION* lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to) { POINTARRAY *pa_in = NULL; LWCOLLECTION *lwgeom_out = NULL; POINTARRAY *dp = NULL; int i, rv; int added_last_point = 0; POINT4D *p = NULL, *q = NULL, *r = NULL; double ordinate_value_p = 0.0, ordinate_value_q = 0.0; char hasz = lwgeom_has_z(lwline_as_lwgeom(line)); char hasm = lwgeom_has_m(lwline_as_lwgeom(line)); char dims = FLAGS_NDIMS(line->flags); /* Null input, nothing we can do. */ if ( ! line ) { lwerror("Null input geometry."); return NULL; } /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } LWDEBUGF(4, "from = %g, to = %g, ordinate = %c", from, to, ordinate); LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line)); /* Asking for an ordinate we don't have. Error. */ if ( (ordinate == 'Z' && ! hasz) || (ordinate == 'M' && ! hasm) ) { lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims); return NULL; } /* Prepare our working point objects. */ p = lwalloc(sizeof(POINT4D)); q = lwalloc(sizeof(POINT4D)); r = lwalloc(sizeof(POINT4D)); /* Construct a collection to hold our outputs. */ lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, line->srid, hasz, hasm); /* Get our input point array */ pa_in = line->points; for ( i = 0; i < pa_in->npoints; i++ ) { LWDEBUGF(4, "Point #%d", i); LWDEBUGF(4, "added_last_point %d", added_last_point); if ( i > 0 ) { *q = *p; ordinate_value_q = ordinate_value_p; } rv = getPoint4d_p(pa_in, i, p); ordinate_value_p = lwpoint_get_ordinate(p, ordinate); LWDEBUGF(4, " ordinate_value_p %g (current)", ordinate_value_p); LWDEBUGF(4, " ordinate_value_q %g (previous)", ordinate_value_q); /* Is this point inside the ordinate range? Yes. */ if ( ordinate_value_p >= from && ordinate_value_p <= to ) { LWDEBUGF(4, " inside ordinate range (%g, %g)", from, to); if ( ! added_last_point ) { LWDEBUG(4," new ptarray required"); /* We didn't add the previous point, so this is a new segment. * Make a new point array. */ dp = ptarray_construct_empty(hasz, hasm, 32); /* We're transiting into the range so add an interpolated * point at the range boundary. * If we're on a boundary and crossing from the far side, * we also need an interpolated point. */ if ( i > 0 && ( /* Don't try to interpolate if this is the first point */ ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */ ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */ ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */ { double interpolation_value; (ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, "[0] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } /* Add the current vertex to the point array. */ rv = ptarray_append_point(dp, p, LW_FALSE); if ( ordinate_value_p == from || ordinate_value_p == to ) { added_last_point = 2; /* Added on boundary. */ } else { added_last_point = 1; /* Added inside range. */ } } /* Is this point inside the ordinate range? No. */ else { LWDEBUGF(4, " added_last_point (%d)", added_last_point); if ( added_last_point == 1 ) { /* We're transiting out of the range, so add an interpolated point * to the point array at the range boundary. */ double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [1] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } else if ( added_last_point == 2 ) { /* We're out and the last point was on the boundary. * If the last point was the near boundary, nothing to do. * If it was the far boundary, we need an interpolated point. */ if ( from != to && ( (ordinate_value_q == from && ordinate_value_p > from) || (ordinate_value_q == to && ordinate_value_p < to) ) ) { double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [2] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } else if ( i && ordinate_value_q < from && ordinate_value_p > to ) { /* We just hopped over the whole range, from bottom to top, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 0, r); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 1, r); } else if ( i && ordinate_value_q > to && ordinate_value_p < from ) { /* We just hopped over the whole range, from top to bottom, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 0, r); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 1, r); } /* We have an extant point-array, save it out to a multi-line. */ if ( dp ) { LWDEBUG(4, "saving pointarray to multi-line (1)"); /* Only one point, so we have to make an lwpoint to hold this * and set the overall output type to a generic collection. */ if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } added_last_point = 0; } } /* Still some points left to be saved out. */ if ( dp && dp->npoints > 0 ) { LWDEBUG(4, "saving pointarray to multi-line (2)"); LWDEBUGF(4, "dp->npoints == %d", dp->npoints); LWDEBUGF(4, "lwgeom_out->ngeoms == %d", lwgeom_out->ngeoms); if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } lwfree(p); lwfree(q); lwfree(r); if ( lwgeom_out->ngeoms > 0 ) { lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); } return lwgeom_out; }
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS) { GSERIALIZED *gser = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *result; double distance = PG_GETARG_FLOAT8(1); LWLINE *line; LWGEOM *geom; LWPOINT *point; POINTARRAY *ipa, *opa; POINT4D pt; int nsegs, i; double length, slength, tlength; if ( distance < 0 || distance > 1 ) { elog(ERROR,"line_interpolate_point: 2nd arg isn't within [0,1]"); PG_RETURN_NULL(); } if ( gserialized_get_type(gser) != LINETYPE ) { elog(ERROR,"line_interpolate_point: 1st arg isn't a line"); PG_RETURN_NULL(); } /* Empty.InterpolatePoint == Point Empty */ if ( gserialized_is_empty(gser) ) { point = lwpoint_construct_empty(gserialized_get_srid(gser), gserialized_has_z(gser), gserialized_has_m(gser)); result = geometry_serialize(lwpoint_as_lwgeom(point)); lwpoint_free(point); PG_RETURN_POINTER(result); } geom = lwgeom_from_gserialized(gser); line = lwgeom_as_lwline(geom); ipa = line->points; /* If distance is one of the two extremes, return the point on that * end rather than doing any expensive computations */ if ( distance == 0.0 || distance == 1.0 ) { if ( distance == 0.0 ) getPoint4d_p(ipa, 0, &pt); else getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } /* Interpolate a point on the line */ nsegs = ipa->npoints - 1; length = ptarray_length_2d(ipa); tlength = 0; for ( i = 0; i < nsegs; i++ ) { POINT4D p1, p2; POINT4D *p1ptr=&p1, *p2ptr=&p2; /* don't break * strict-aliasing rules */ getPoint4d_p(ipa, i, &p1); getPoint4d_p(ipa, i+1, &p2); /* Find the relative length of this segment */ slength = distance2d_pt_pt((POINT2D*)p1ptr, (POINT2D*)p2ptr)/length; /* If our target distance is before the total length we've seen * so far. create a new point some distance down the current * segment. */ if ( distance < tlength + slength ) { double dseg = (distance - tlength) / slength; interpolate_point4d(&p1, &p2, &pt, dseg); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } tlength += slength; } /* Return the last point on the line. This shouldn't happen, but * could if there's some floating point rounding errors. */ getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_FREE_IF_COPY(gser, 0); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); }
static void test_lwline_crossing_short_lines(void) { POINT4D p; /* ** Simple test, two two-point lines */ /* Vertical line from 0,0 to 1,1 */ p.x = 0.0; p.y = 0.0; ptarray_set_point4d(pa21, 0, &p); p.y = 1.0; ptarray_set_point4d(pa21, 1, &p); /* Horizontal, crossing mid-segment */ p.x = -0.5; p.y = 0.5; ptarray_set_point4d(pa22, 0, &p); p.x = 0.5; ptarray_set_point4d(pa22, 1, &p); CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT ); /* Horizontal, crossing at top end vertex (end crossings don't count) */ p.x = -0.5; p.y = 1.0; ptarray_set_point4d(pa22, 0, &p); p.x = 0.5; ptarray_set_point4d(pa22, 1, &p); CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); /* Horizontal, crossing at bottom end vertex */ p.x = -0.5; p.y = 0.0; ptarray_set_point4d(pa22, 0, &p); p.x = 0.5; ptarray_set_point4d(pa22, 1, &p); CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT ); /* Horizontal, no crossing */ p.x = -0.5; p.y = 2.0; ptarray_set_point4d(pa22, 0, &p); p.x = 0.5; ptarray_set_point4d(pa22, 1, &p); CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); /* Vertical, no crossing */ p.x = -0.5; p.y = 0.0; ptarray_set_point4d(pa22, 0, &p); p.y = 1.0; ptarray_set_point4d(pa22, 1, &p); CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); }