/**********************************************************************
*
* PostGIS - Spatial Types for PostgreSQL
* http://postgis.net
*
* PostGIS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* PostGIS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PostGIS. If not, see .
*
**********************************************************************
*
* Copyright (C) 2001-2006 Refractions Research Inc.
*
**********************************************************************/
/* basic LWCIRCSTRING functions */
#include
#include
#include
#include "liblwgeom_internal.h"
#include "lwgeom_log.h"
void printLWCIRCSTRING(LWCIRCSTRING *curve);
void lwcircstring_release(LWCIRCSTRING *lwcirc);
char lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you);
LWCIRCSTRING *lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, LWPOINT **points);
LWCIRCSTRING *lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint);
LWCIRCSTRING *lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where);
LWCIRCSTRING *lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index);
void lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint);
/*
* Construct a new LWCIRCSTRING. points will *NOT* be copied
* use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
*/
LWCIRCSTRING *
lwcircstring_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
{
LWCIRCSTRING *result;
/*
* The first arc requires three points. Each additional
* arc requires two more points. Thus the minimum point count
* is three, and the count must be odd.
*/
if (points->npoints % 2 != 1 || points->npoints < 3)
{
lwnotice("lwcircstring_construct: invalid point count %d", points->npoints);
}
result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));
result->type = CIRCSTRINGTYPE;
result->flags = points->flags;
FLAGS_SET_BBOX(result->flags, bbox?1:0);
result->srid = srid;
result->points = points;
result->bbox = bbox;
return result;
}
LWCIRCSTRING *
lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
{
LWCIRCSTRING *result = lwalloc(sizeof(LWCIRCSTRING));
result->type = CIRCSTRINGTYPE;
result->flags = lwflags(hasz,hasm,0);
result->srid = srid;
result->points = ptarray_construct_empty(hasz, hasm, 1);
result->bbox = NULL;
return result;
}
void
lwcircstring_release(LWCIRCSTRING *lwcirc)
{
lwgeom_release(lwcircstring_as_lwgeom(lwcirc));
}
void lwcircstring_free(LWCIRCSTRING *curve)
{
if ( ! curve ) return;
if ( curve->bbox )
lwfree(curve->bbox);
if ( curve->points )
ptarray_free(curve->points);
lwfree(curve);
}
void printLWCIRCSTRING(LWCIRCSTRING *curve)
{
lwnotice("LWCIRCSTRING {");
lwnotice(" ndims = %i", (int)FLAGS_NDIMS(curve->flags));
lwnotice(" srid = %i", (int)curve->srid);
printPA(curve->points);
lwnotice("}");
}
/* @brief Clone LWCIRCSTRING object. Serialized point lists are not copied.
*
* @see ptarray_clone
*/
LWCIRCSTRING *
lwcircstring_clone(const LWCIRCSTRING *g)
{
return (LWCIRCSTRING *)lwline_clone((LWLINE *)g);
}
/* check coordinate equality */
char
lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you)
{
return ptarray_same(me->points, you->points);
}
/*
* Construct a LWCIRCSTRING from an array of LWPOINTs
* LWCIRCSTRING dimensions are large enough to host all input dimensions.
*/
LWCIRCSTRING *
lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, LWPOINT **points)
{
int zmflag=0;
uint32_t i;
POINTARRAY *pa;
uint8_t *newpoints, *ptr;
size_t ptsize, size;
/*
* Find output dimensions, check integrity
*/
for (i = 0; i < npoints; i++)
{
if (points[i]->type != POINTTYPE)
{
lwerror("lwcurve_from_lwpointarray: invalid input type: %s",
lwtype_name(points[i]->type));
return NULL;
}
if (FLAGS_GET_Z(points[i]->flags)) zmflag |= 2;
if (FLAGS_GET_M(points[i]->flags)) zmflag |= 1;
if (zmflag == 3) break;
}
if (zmflag == 0) ptsize = 2 * sizeof(double);
else if (zmflag == 3) ptsize = 4 * sizeof(double);
else ptsize = 3 * sizeof(double);
/*
* Allocate output points array
*/
size = ptsize * npoints;
newpoints = lwalloc(size);
memset(newpoints, 0, size);
ptr = newpoints;
for (i = 0; i < npoints; i++)
{
size = ptarray_point_size(points[i]->point);
memcpy(ptr, getPoint_internal(points[i]->point, 0), size);
ptr += ptsize;
}
pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, npoints, newpoints);
return lwcircstring_construct(srid, NULL, pa);
}
/*
* Construct a LWCIRCSTRING from a LWMPOINT
*/
LWCIRCSTRING *
lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint)
{
uint32_t i;
POINTARRAY *pa;
char zmflag = FLAGS_GET_ZM(mpoint->flags);
size_t ptsize, size;
uint8_t *newpoints, *ptr;
if (zmflag == 0) ptsize = 2 * sizeof(double);
else if (zmflag == 3) ptsize = 4 * sizeof(double);
else ptsize = 3 * sizeof(double);
/* Allocate space for output points */
size = ptsize * mpoint->ngeoms;
newpoints = lwalloc(size);
memset(newpoints, 0, size);
ptr = newpoints;
for (i = 0; i < mpoint->ngeoms; i++)
{
memcpy(ptr,
getPoint_internal(mpoint->geoms[i]->point, 0),
ptsize);
ptr += ptsize;
}
pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, mpoint->ngeoms, newpoints);
LWDEBUGF(3, "lwcurve_from_lwmpoint: constructed pointarray for %d points, %d zmflag", mpoint->ngeoms, zmflag);
return lwcircstring_construct(srid, NULL, pa);
}
LWCIRCSTRING *
lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where)
{
POINTARRAY *newpa;
LWCIRCSTRING *ret;
newpa = ptarray_addPoint(curve->points,
getPoint_internal(point->point, 0),
FLAGS_NDIMS(point->flags), where);
ret = lwcircstring_construct(curve->srid, NULL, newpa);
return ret;
}
LWCIRCSTRING *
lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index)
{
POINTARRAY *newpa;
LWCIRCSTRING *ret;
newpa = ptarray_removePoint(curve->points, index);
ret = lwcircstring_construct(curve->srid, NULL, newpa);
return ret;
}
/*
* 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);
}
int
lwcircstring_is_closed(const LWCIRCSTRING *curve)
{
if (lwgeom_has_z((LWGEOM*)curve))
return ptarray_is_closed_3d(curve->points);
return ptarray_is_closed_2d(curve->points);
}
double lwcircstring_length(const LWCIRCSTRING *circ)
{
return lwcircstring_length_2d(circ);
}
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
{
if ( lwcircstring_is_empty(circ) )
return 0.0;
return ptarray_arc_length_2d(circ->points);
}
/*
* Returns freshly allocated #LWPOINT that corresponds to the index where.
* Returns NULL if the geometry is empty or the index invalid.
*/
LWPOINT* lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where) {
POINT4D pt;
LWPOINT *lwpoint;
POINTARRAY *pa;
if ( lwcircstring_is_empty(circ) || where >= circ->points->npoints )
return NULL;
pa = ptarray_construct_empty(FLAGS_GET_Z(circ->flags), FLAGS_GET_M(circ->flags), 1);
pt = getPoint4d(circ->points, where);
ptarray_append_point(pa, &pt, LW_TRUE);
lwpoint = lwpoint_construct(circ->srid, NULL, pa);
return lwpoint;
}