/* ** The suite initialization function. ** Create any re-used objects. */ static int init_cg_suite(void) { pa21 = ptarray_construct(0, 0, 2); pa22 = ptarray_construct(0, 0, 2); l21 = lwline_construct(SRID_UNKNOWN, NULL, pa21); l22 = lwline_construct(SRID_UNKNOWN, NULL, pa22); return 0; }
/** * POINTARRAY * Read a dynamically sized point array and advance the parse state forward. * First read the number of points, then read the points. */ static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s) { POINTARRAY *pa = NULL; size_t pa_size; uint32_t ndims = 2; uint32_t npoints = 0; static uint32_t maxpoints = 4294967295 / WKB_DOUBLE_SIZE / 4; /* Calculate the size of this point array. */ npoints = integer_from_wkb_state(s); if (npoints > maxpoints) { lwerror("point array length (%d) is too large"); } LWDEBUGF(4,"Pointarray has %d points", npoints); if( s->has_z ) ndims++; if( s->has_m ) ndims++; pa_size = npoints * ndims * WKB_DOUBLE_SIZE; /* Empty! */ if( npoints == 0 ) return ptarray_construct(s->has_z, s->has_m, npoints); /* 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 < npoints * ndims; i++ ) { dlist[i] = double_from_wkb_state(s); } } return pa; }
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 LWLINE* lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size) { uint8_t *start_ptr = data_ptr; LWLINE *line; uint32_t npoints = 0; assert(data_ptr); line = (LWLINE*)lwalloc(sizeof(LWLINE)); line->srid = SRID_UNKNOWN; /* Default */ line->bbox = NULL; line->type = LINETYPE; line->flags = g_flags; data_ptr += 4; /* Skip past the type. */ npoints = lw_get_uint32_t(data_ptr); /* Zero => empty geometry */ data_ptr += 4; /* Skip past the npoints. */ if ( npoints > 0 ) line->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr); else line->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty linestring */ data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double); if ( g_size ) *g_size = data_ptr - start_ptr; return line; }
static LWPOINT* lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size) { uint8_t *start_ptr = data_ptr; LWPOINT *point; uint32_t npoints = 0; assert(data_ptr); point = (LWPOINT*)lwalloc(sizeof(LWPOINT)); point->srid = SRID_UNKNOWN; /* Default */ point->bbox = NULL; point->type = POINTTYPE; point->flags = g_flags; data_ptr += 4; /* Skip past the type. */ npoints = lw_get_uint32_t(data_ptr); /* Zero => empty geometry */ data_ptr += 4; /* Skip past the npoints. */ if ( npoints > 0 ) point->point = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 1, data_ptr); else point->point = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty point */ data_ptr += npoints * FLAGS_NDIMS(g_flags) * sizeof(double); if ( g_size ) *g_size = data_ptr - start_ptr; return point; }
static LWCIRCSTRING* lwcircstring_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size) { uint8_t *start_ptr = data_ptr; LWCIRCSTRING *circstring; uint32_t npoints = 0; assert(data_ptr); circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING)); circstring->srid = SRID_UNKNOWN; /* Default */ circstring->bbox = NULL; circstring->type = CIRCSTRINGTYPE; circstring->flags = g_flags; data_ptr += 4; /* Skip past the circstringtype. */ npoints = lw_get_uint32_t(data_ptr); /* Zero => empty geometry */ data_ptr += 4; /* Skip past the npoints. */ if ( npoints > 0 ) circstring->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr); else circstring->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty circularstring */ data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double); if ( g_size ) *g_size = data_ptr - start_ptr; return circstring; }
/** * @brief Merge two given POINTARRAY and returns a pointer * on the new aggregate one. * Warning: this function free the two inputs POINTARRAY * @return #POINTARRAY is newly allocated */ POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2) { POINTARRAY *pa; size_t ptsize = ptarray_point_size(pa1); if (FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags)) lwerror("ptarray_cat: Mixed dimension"); pa = ptarray_construct( FLAGS_GET_Z(pa1->flags), FLAGS_GET_M(pa1->flags), pa1->npoints + pa2->npoints); memcpy( getPoint_internal(pa, 0), getPoint_internal(pa1, 0), ptsize*(pa1->npoints)); memcpy( getPoint_internal(pa, pa1->npoints), getPoint_internal(pa2, 0), ptsize*(pa2->npoints)); lwfree(pa1); lwfree(pa2); return pa; }
/** * Re-write the measure ordinate (or add one, if it isn't already there) interpolating * the measure between the supplied start and end values. */ LWLINE* lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end) { int i = 0; int hasm = 0, hasz = 0; int npoints = 0; double length = 0.0; double length_so_far = 0.0; double m_range = m_end - m_start; double m; POINTARRAY *pa = NULL; POINT3DZ p1, p2; if ( TYPE_GETTYPE(lwline->type) != LINETYPE ) { lwerror("lwline_construct_from_lwline: only line types supported"); return NULL; } hasz = TYPE_HASZ(lwline->type); hasm = 1; /* Null points or npoints == 0 will result in empty return geometry */ if ( lwline->points ) { npoints = lwline->points->npoints; length = lwgeom_pointarray_length2d(lwline->points); getPoint3dz_p(lwline->points, 0, &p1); } pa = ptarray_construct(hasz, hasm, npoints); for ( i = 0; i < npoints; i++ ) { POINT4D q; POINT2D a, b; getPoint3dz_p(lwline->points, i, &p2); a.x = p1.x; a.y = p1.y; b.x = p2.x; b.y = p2.y; length_so_far += distance2d_pt_pt(&a, &b); if ( length > 0.0 ) m = m_start + m_range * length_so_far / length; else m = 0.0; q.x = p2.x; q.y = p2.y; q.z = p2.z; q.m = m; setPoint4d(pa, i, &q); p1 = p2; } return lwline_construct(lwline->SRID, NULL, pa); }
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm) { LWPOINT *result = lwalloc(sizeof(LWPOINT)); result->type = POINTTYPE; result->flags = gflags(hasz, hasm, 0); result->srid = srid; result->point = ptarray_construct(hasz, hasm, 0); result->bbox = NULL; return result; }
/** * @brief Add a point in a pointarray. * * @param pa the source POINTARRAY * @param p the point to add * @param pdims number of ordinates in p (2..4) * @param where to insert the point. 0 prepends, pa->npoints appends * * @returns a newly constructed POINTARRAY using a newly allocated buffer * for the actual points, or NULL on error. */ POINTARRAY * ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where) { POINTARRAY *ret; POINT4D pbuf; size_t ptsize = ptarray_point_size(pa); LWDEBUGF(3, "pa %x p %x size %d where %d", pa, p, pdims, where); if ( pdims < 2 || pdims > 4 ) { lwerror("ptarray_addPoint: point dimension out of range (%d)", pdims); return NULL; } if ( where > pa->npoints ) { lwerror("ptarray_addPoint: offset out of range (%d)", where); return NULL; } LWDEBUG(3, "called with a %dD point"); pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0; memcpy((uint8_t *)&pbuf, p, pdims*sizeof(double)); LWDEBUG(3, "initialized point buffer"); ret = ptarray_construct(FLAGS_GET_Z(pa->flags), FLAGS_GET_M(pa->flags), pa->npoints+1); if ( where == -1 ) where = pa->npoints; if ( where ) { memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where); } memcpy(getPoint_internal(ret, where), (uint8_t *)&pbuf, ptsize); if ( where+1 != ret->npoints ) { memcpy(getPoint_internal(ret, where+1), getPoint_internal(pa, where), ptsize*(pa->npoints-where)); } return ret; }
LWPOINT * make_lwpoint2d(int SRID, double x, double y) { POINT2D p; POINTARRAY *pa = ptarray_construct(0, 0, 1); p.x = x; p.y = y; memcpy(getPoint_internal(pa, 0), &p, sizeof(POINT2D)); return lwpoint_construct(SRID, NULL, pa); }
LWPOINT * make_lwpoint3dm(int SRID, double x, double y, double m) { POINTARRAY *pa = ptarray_construct(0, 1, 1); POINT3DM p; p.x = x; p.y = y; p.m = m; memcpy(getPoint_internal(pa, 0), &p, sizeof(POINT3DM)); return lwpoint_construct(SRID, NULL, pa); }
LWPOINT * make_lwpoint3dz(int SRID, double x, double y, double z) { POINT3DZ p; POINTARRAY *pa = ptarray_construct(1, 0, 1); p.x = x; p.y = y; p.z = z; memcpy(getPoint_internal(pa, 0), &p, sizeof(POINT3DZ)); return lwpoint_construct(SRID, NULL, pa); }
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)); }
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)); }
/** * 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); } }
/** * POINTARRAY * Read a dynamically sized point array and advance the parse state forward. */ static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints) { POINTARRAY *pa = NULL; uint32_t ndims = s->ndims; int i; double *dlist; LWDEBUG(2,"Entering ptarray_from_twkb_state"); LWDEBUGF(4,"Pointarray has %d points", npoints); /* Empty! */ if( npoints == 0 ) return ptarray_construct_empty(s->has_z, s->has_m, 0); pa = ptarray_construct(s->has_z, s->has_m, npoints); dlist = (double*)(pa->serialized_pointlist); for( i = 0; i < npoints; i++ ) { int j = 0; /* X */ s->coords[j] += twkb_parse_state_varint(s); dlist[ndims*i + j] = s->coords[j] / s->factor; j++; /* Y */ s->coords[j] += twkb_parse_state_varint(s); dlist[ndims*i + j] = s->coords[j] / s->factor; j++; /* Z */ if ( s->has_z ) { s->coords[j] += twkb_parse_state_varint(s); dlist[ndims*i + j] = s->coords[j] / s->factor_z; j++; } /* M */ if ( s->has_m ) { s->coords[j] += twkb_parse_state_varint(s); dlist[ndims*i + j] = s->coords[j] / s->factor_m; j++; } } return pa; }
/* * 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(POINTARRAY *in) { POINTARRAY* out; size_t ptsize; size_t ipn, opn; LWDEBUG(3, "ptarray_remove_repeated_points called."); /* 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; memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize); LWDEBUGF(3, " first point copied, out points: %d", opn); for (ipn=1; ipn<in->npoints; ++ipn) { if ( (ipn==in->npoints-1 && opn==1) || memcmp(getPoint_internal(in, ipn-1), getPoint_internal(in, ipn), ptsize) ) { /* The point is different from the previous, * we add it to output */ memcpy(getPoint_internal(out, opn++), getPoint_internal(in, ipn), ptsize); LWDEBUGF(3, " Point %d differs from point %d. Out points: %d", ipn, ipn-1, opn); } } LWDEBUGF(3, " in:%d out:%d", out->npoints, opn); out->npoints = opn; return out; }
/* 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; }
/** * @brief Remove a point from a pointarray. * @param which - is the offset (starting at 0) * @return #POINTARRAY is newly allocated */ POINTARRAY * ptarray_removePoint(POINTARRAY *pa, uint32_t which) { POINTARRAY *ret; size_t ptsize = ptarray_point_size(pa); LWDEBUGF(3, "pa %x which %d", pa, which); #if PARANOIA_LEVEL > 0 if ( which > pa->npoints-1 ) { lwerror("ptarray_removePoint: offset (%d) out of range (%d..%d)", which, 0, pa->npoints-1); return NULL; } if ( pa->npoints < 3 ) { lwerror("ptarray_removePointe: can't remove a point from a 2-vertex POINTARRAY"); } #endif ret = ptarray_construct(FLAGS_GET_Z(pa->flags), FLAGS_GET_M(pa->flags), pa->npoints-1); /* copy initial part */ if ( which ) { memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which); } /* copy final part */ if ( which < pa->npoints-1 ) { memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1), ptsize*(pa->npoints-which-1)); } return ret; }
/** * 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))); }
/* * 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; }