2004-03-10 01:15:06 +00:00
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "access/gist.h"
|
|
|
|
#include "access/itup.h"
|
|
|
|
#include "access/rtree.h"
|
|
|
|
|
|
|
|
#include "fmgr.h"
|
|
|
|
#include "utils/elog.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "lwgeom.h"
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
#define DEBUG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
extern char *wkb_to_lwgeom(char *wkb, int SRID,int *size);
|
|
|
|
extern char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian);
|
|
|
|
extern void swap_char(char *a,char *b);
|
|
|
|
extern void flip_endian_double(char *d);
|
|
|
|
extern void flip_endian_int32(char *i);
|
|
|
|
extern char wkb_dims(uint32 type);
|
|
|
|
extern char wkb_simpletype (uint32 type);
|
|
|
|
extern uint32 constructWKBType(int simple_type, char dims);
|
|
|
|
extern bool requiresflip(char WKBendianflag);
|
|
|
|
extern void flipPoints(char *pts, int npoints, char dims);
|
|
|
|
extern uint32 constructWKBType(int simple_type, char dims);
|
|
|
|
|
|
|
|
extern LWPOINT *wkb_point_to_lwpoint(char *wkb,int SRID);
|
|
|
|
extern LWLINE *wkb_line_to_lwline(char *wkb,int SRID);
|
|
|
|
extern LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID);
|
|
|
|
|
|
|
|
extern char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize);
|
|
|
|
extern char *lwpoint_to_wkb(LWPOINT *point, char desiredWKBEndian, int *wkbsize);
|
|
|
|
extern char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
extern unsigned char parse_hex(char *str);
|
|
|
|
extern void deparse_hex(unsigned char str, unsigned char *result);
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
// 3d or 4d. There is NOT a (x,y,m) point type!!!
|
|
|
|
#define WKB3DOFFSET 0x80000000
|
|
|
|
#define WKB4DOFFSET 0x40000000
|
|
|
|
|
|
|
|
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS);
|
|
|
|
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
Datum LWGEOM_in(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_out(PG_FUNCTION_ARGS);
|
|
|
|
|
|
|
|
|
|
|
|
// WKB structure -- exactly the same as TEXT
|
|
|
|
typedef struct Well_known_bin {
|
|
|
|
int32 size; // total size of this structure
|
|
|
|
unsigned char data[1]; //THIS HOLD VARIABLE LENGTH DATA
|
|
|
|
} WellKnownBinary;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_in);
|
|
|
|
Datum LWGEOM_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
WellKnownBinary *wkb;
|
|
|
|
char *result,*lwgeom;
|
|
|
|
int size;
|
|
|
|
int t;
|
|
|
|
int input_str_len;
|
|
|
|
|
|
|
|
int SRID = -1; //default (change)
|
|
|
|
|
|
|
|
input_str_len = strlen(str);
|
|
|
|
|
|
|
|
if ( ( ( (int)(input_str_len/2.0) ) *2.0) != input_str_len)
|
|
|
|
{
|
|
|
|
elog(ERROR,"LWGEOM_in parser - should be even number of characters!");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strspn(str,"0123456789ABCDEF") != strlen(str) )
|
|
|
|
{
|
|
|
|
elog(ERROR,"WKB_in parser - input contains bad characters. Should only have '0123456789ABCDEF'!");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
size = (input_str_len/2) + 4;
|
|
|
|
wkb = (WellKnownBinary *) palloc(size);
|
|
|
|
wkb->size = size;
|
|
|
|
|
|
|
|
for (t=0;t<input_str_len/2;t++)
|
|
|
|
{
|
|
|
|
((unsigned char *)wkb)[t+4] = parse_hex( &str[t*2]) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
//have WKB string (and we can safely modify it)
|
|
|
|
lwgeom = wkb_to_lwgeom(((char *) wkb)+4, SRID,&size);
|
|
|
|
|
|
|
|
pfree(wkb); // no longer referenced!
|
|
|
|
|
|
|
|
result = palloc(size+4);
|
|
|
|
|
|
|
|
memcpy(result+4, lwgeom, size);
|
|
|
|
size+=4;
|
|
|
|
memcpy(result, &size, 4);
|
|
|
|
|
|
|
|
pfree(lwgeom);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_out);
|
|
|
|
Datum LWGEOM_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
char *result;
|
|
|
|
int size_result;
|
|
|
|
int t;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
char *wkb = lwgeom_to_wkb(lwgeom+4,&size,1); // 0=XDR, 1=NDR
|
|
|
|
|
|
|
|
size_result = size *2 +1; //+1 for null char
|
|
|
|
result = palloc (size_result);
|
|
|
|
result[size_result-1] = 0; //null terminate
|
|
|
|
|
|
|
|
for (t=0; t< size; t++)
|
|
|
|
{
|
|
|
|
deparse_hex( ((unsigned char *) wkb)[t], &result[t*2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(wkb);
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
// LWGEOMFromWKB(wkb, [SRID] )
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOMFromWKB);
|
|
|
|
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *wkb_input = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-03-11 00:54:37 +00:00
|
|
|
int SRID = -1;
|
2004-03-10 01:15:06 +00:00
|
|
|
int size;
|
|
|
|
char *lwgeom;
|
|
|
|
char * result;
|
2004-03-11 00:54:37 +00:00
|
|
|
char *wkb_copy;
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) ))
|
2004-03-10 01:15:06 +00:00
|
|
|
SRID = PG_GETARG_INT32(1);
|
|
|
|
else
|
|
|
|
SRID = -1;
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"LWGEOMFromWKB: entry with SRID=%i",SRID);
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// need to do this because there might be a bunch of endian flips!
|
|
|
|
wkb_copy = palloc( *((int32 *) wkb_input));
|
|
|
|
memcpy(wkb_copy, wkb_input+4, *((int32 *) wkb_input) -4);
|
|
|
|
|
|
|
|
lwgeom = wkb_to_lwgeom(wkb_copy, SRID,&size);
|
|
|
|
|
|
|
|
pfree(wkb_copy); // no longer referenced!
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
result = palloc(size+4);
|
|
|
|
|
|
|
|
memcpy(result+4, lwgeom, size);
|
|
|
|
size+=4;
|
|
|
|
memcpy(result, &size, 4);
|
|
|
|
|
|
|
|
pfree(lwgeom);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// WKBFromLWGEOM(wkb)
|
|
|
|
PG_FUNCTION_INFO_V1(WKBFromLWGEOM);
|
|
|
|
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *lwgeom_input = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
int size;
|
|
|
|
char *wkb = lwgeom_to_wkb(lwgeom_input+4,&size,1); // 0=XDR, 1=NDR
|
|
|
|
|
|
|
|
char *result = palloc(size+4);
|
|
|
|
|
|
|
|
memcpy(result+4, wkb, size);
|
|
|
|
size+=4;
|
|
|
|
memcpy(result, &size, 4);
|
|
|
|
pfree(wkb);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//given a wkb (with 3d and 4d extension)
|
|
|
|
// create the serialized form of an equivelent LWGEOM
|
|
|
|
// size of the lwgeom form is also returned
|
|
|
|
//
|
|
|
|
// note - to actually serialize, you should put the first 4
|
|
|
|
// bytes as size (size +4), then the results of this function.
|
|
|
|
//
|
|
|
|
// because this function modifies the wkb (to make it the
|
|
|
|
// server's endian), you should give it a copy of the wkb.
|
|
|
|
// The underlying LWGEOM will point into this WKB, so
|
|
|
|
// be extreamly careful when you free it!
|
|
|
|
//
|
|
|
|
// also, wkb should point to the 1st wkb character; NOT
|
|
|
|
// the postgresql length int32.
|
|
|
|
char *wkb_to_lwgeom(char *wkb, int SRID,int *size)
|
|
|
|
{
|
|
|
|
uint32 wkbtype;
|
|
|
|
char dims;
|
|
|
|
bool need_flip = requiresflip( wkb[0] );
|
|
|
|
|
|
|
|
LWPOINT *pt;
|
|
|
|
LWLINE *line;
|
|
|
|
LWPOLY *poly;
|
|
|
|
char *multigeom = NULL;
|
|
|
|
char *result = NULL;
|
|
|
|
int simpletype;
|
|
|
|
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+1);
|
|
|
|
|
|
|
|
wkbtype = get_uint32(wkb+1);
|
|
|
|
dims = wkb_dims(wkbtype);
|
|
|
|
simpletype = wkb_simpletype(wkbtype);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"wkb_to_lwgeom: entry with SRID=%i, dims=%i, simpletype=%i",SRID,(int) dims, (int) simpletype);
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
switch (simpletype)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
pt = wkb_point_to_lwpoint(wkb, SRID);
|
|
|
|
result = lwpoint_serialize(pt);
|
|
|
|
*size = lwpoint_findlength(result);
|
|
|
|
pfree_point(pt);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
line = wkb_line_to_lwline(wkb, SRID);
|
2004-03-11 01:27:43 +00:00
|
|
|
//printLWLINE(line);
|
2004-03-10 01:15:06 +00:00
|
|
|
result = lwline_serialize(line);
|
2004-03-11 01:27:43 +00:00
|
|
|
// elog(NOTICE,"line serialized");
|
2004-03-10 01:15:06 +00:00
|
|
|
*size = lwline_findlength(result);
|
|
|
|
pfree_line(line);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
poly = wkb_poly_to_lwpoly(wkb, SRID);
|
2004-03-11 01:27:43 +00:00
|
|
|
// printLWPOLY(poly);
|
2004-03-10 01:15:06 +00:00
|
|
|
result = lwpoly_serialize(poly);
|
|
|
|
*size = lwpoly_findlength(result);
|
|
|
|
pfree_polygon(poly);
|
|
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
result = multigeom;
|
|
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
break;
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
break;
|
|
|
|
}
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE,"wkb_to_lwgeom:returning");
|
|
|
|
#endif
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//NOTE: THIS CHANGES THE ENDIAN OF THE WKB!!
|
|
|
|
// we make sure the point is correctly endianed
|
|
|
|
// and make a LWPOINT that points into it.
|
|
|
|
// wkb --> point to the endian definition of the wkb point
|
|
|
|
LWPOINT *wkb_point_to_lwpoint(char *wkb,int SRID)
|
|
|
|
{
|
|
|
|
uint32 wkbtype;
|
|
|
|
char dims;
|
|
|
|
char simpletype;
|
|
|
|
POINTARRAY *pa;
|
|
|
|
|
|
|
|
bool need_flip = requiresflip( wkb[0] );
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+1);
|
|
|
|
|
|
|
|
wkbtype = get_uint32(wkb+1);
|
|
|
|
dims = wkb_dims(wkbtype);
|
|
|
|
simpletype = wkb_simpletype(wkbtype);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"wkb_point_to_lwpoint: entry with SRID=%i, dims=%i, simpletype=%i",SRID,(int) dims, (int) simpletype);
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
if (simpletype != POINTTYPE)
|
|
|
|
elog(ERROR,"WKB::point parser - go wrong type");
|
|
|
|
|
|
|
|
pa = pointArray_construct(wkb+5, dims, 1);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
return lwpoint_construct(dims, SRID, pa);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWLINE *wkb_line_to_lwline(char *wkb,int SRID)
|
|
|
|
{
|
|
|
|
uint32 wkbtype;
|
|
|
|
char dims;
|
|
|
|
char simpletype;
|
|
|
|
POINTARRAY *pa;
|
|
|
|
int npoints;
|
|
|
|
|
|
|
|
bool need_flip = requiresflip( wkb[0] );
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+1); // type
|
|
|
|
|
|
|
|
wkbtype = get_uint32(wkb+1);
|
|
|
|
dims = wkb_dims(wkbtype);
|
|
|
|
simpletype = wkb_simpletype(wkbtype);
|
|
|
|
|
|
|
|
if (simpletype != LINETYPE)
|
|
|
|
elog(ERROR,"WKB::line parser - go wrong type");
|
|
|
|
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+5); // npoints
|
|
|
|
|
|
|
|
npoints = get_uint32(wkb+5);
|
|
|
|
|
|
|
|
if (need_flip)
|
|
|
|
flipPoints(wkb+9,npoints,dims);
|
|
|
|
|
|
|
|
pa = pointArray_construct(wkb+9, dims, npoints);
|
|
|
|
return lwline_construct(dims, SRID, pa);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID)
|
|
|
|
{
|
|
|
|
uint32 wkbtype;
|
|
|
|
char dims;
|
|
|
|
char simpletype;
|
|
|
|
POINTARRAY *pa;
|
|
|
|
int npoints;
|
|
|
|
POINTARRAY **rings;
|
|
|
|
int nrings;
|
|
|
|
int t;
|
|
|
|
char *loc;
|
|
|
|
int ptsize =16;
|
|
|
|
|
|
|
|
bool need_flip = requiresflip( wkb[0] );
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+1); // type
|
|
|
|
|
|
|
|
wkbtype = get_uint32(wkb+1);
|
|
|
|
dims = wkb_dims(wkbtype);
|
|
|
|
simpletype = wkb_simpletype(wkbtype);
|
|
|
|
|
|
|
|
if (simpletype != POLYGONTYPE)
|
|
|
|
elog(ERROR,"WKB::polygon parser - go wrong type");
|
|
|
|
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(wkb+5); // nrings
|
|
|
|
|
|
|
|
nrings = get_uint32(wkb+5);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
loc = wkb+9;
|
2004-03-10 01:15:06 +00:00
|
|
|
|
|
|
|
//point size
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
ptsize =16;
|
2004-03-10 01:15:06 +00:00
|
|
|
if (dims == FOURDIMS)
|
|
|
|
{
|
|
|
|
ptsize = 32;
|
|
|
|
}
|
|
|
|
if (dims == THREEDIMS)
|
|
|
|
{
|
|
|
|
ptsize = 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rings = (POINTARRAY **) palloc(sizeof(POINTARRAY*) * nrings);
|
|
|
|
|
|
|
|
for (t=0;t<nrings;t++)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(loc); // npoints
|
|
|
|
|
|
|
|
npoints = get_uint32(loc);
|
|
|
|
|
|
|
|
// read a ring
|
|
|
|
if (need_flip)
|
|
|
|
flipPoints(loc+4,npoints,dims);
|
|
|
|
pa = pointArray_construct(loc+4, dims, npoints);
|
|
|
|
|
|
|
|
loc += 4;
|
|
|
|
loc += npoints * ptsize;
|
|
|
|
rings[t] = pa;
|
|
|
|
}
|
|
|
|
return lwpoly_construct(dims, SRID, nrings,rings);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// takes a lwgeom and converts it to an appropriate wkb
|
|
|
|
//
|
|
|
|
// length of the wkb is returned in wkblength (this doesnt
|
|
|
|
// include the 4 bytes needed for the postgresql int32 length)
|
|
|
|
//
|
|
|
|
char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian)
|
|
|
|
{
|
|
|
|
char simple_type = lwgeom_getType(serialized_form[0]);
|
|
|
|
char *result = NULL;
|
|
|
|
LWPOINT *pt;
|
|
|
|
LWLINE *line;
|
|
|
|
LWPOLY *poly;
|
|
|
|
char *multigeom = NULL;
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"lwgeom_to_wkb: entry with simpletype=%i, dims=%i",(int) simple_type,(int) lwgeom_is3d( serialized_form[0]) );
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
|
|
|
|
switch (simple_type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
pt = lwpoint_deserialize(serialized_form);
|
|
|
|
result = lwpoint_to_wkb(pt, desiredWKBEndian, wkblength);
|
|
|
|
pfree_point(pt);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
line = lwline_deserialize(serialized_form);
|
|
|
|
result = lwline_to_wkb(line, desiredWKBEndian, wkblength);
|
|
|
|
pfree_line(line);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
poly = lwpoly_deserialize(serialized_form);
|
2004-03-11 01:27:43 +00:00
|
|
|
// printLWPOLY(poly);
|
2004-03-10 01:15:06 +00:00
|
|
|
result = lwpoly_to_wkb(poly, desiredWKBEndian, wkblength);
|
|
|
|
pfree_polygon(poly );
|
|
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
result = multigeom;
|
|
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
break;
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *lwpoint_to_wkb(LWPOINT *pt, char desiredWKBEndian, int *wkbsize)
|
|
|
|
{
|
|
|
|
int ptsize = pointArray_ptsize(pt->point);
|
|
|
|
char * result;
|
|
|
|
uint32 wkbtype ;
|
|
|
|
bool need_flip = requiresflip( desiredWKBEndian );
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"lwpoint_to_wkb: pa dims = %i", (int)pt->point->is3d );
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
|
|
|
|
*wkbsize = 1+ 4+ ptsize; //endian, type, point
|
|
|
|
|
|
|
|
result = palloc(*wkbsize);
|
|
|
|
|
|
|
|
result[0] = desiredWKBEndian; //endian flag
|
|
|
|
|
|
|
|
wkbtype = constructWKBType(POINTTYPE, pt->point->is3d);
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-03-11 01:27:43 +00:00
|
|
|
elog(NOTICE,"lwpoint_to_wkb: entry with wkbtype=%i, pa dims = %i",wkbtype, (int)pt->point->is3d );
|
2004-03-11 00:54:37 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-10 01:15:06 +00:00
|
|
|
memcpy(result+1, &wkbtype, 4);
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(result+1);
|
|
|
|
|
|
|
|
memcpy(result+5, pt->point->serialized_pointlist, pointArray_ptsize(pt->point) );
|
|
|
|
if (need_flip)
|
|
|
|
flipPoints(result+5, 1, pt->point->is3d);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize)
|
|
|
|
{
|
|
|
|
int ptsize = pointArray_ptsize(line->points);
|
|
|
|
char * result;
|
|
|
|
uint32 wkbtype ;
|
|
|
|
bool need_flip = requiresflip( desiredWKBEndian );
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
*wkbsize = 1+ 4+4+ line->points->npoints * ptsize; //endian, type, npoints, points
|
2004-03-10 01:15:06 +00:00
|
|
|
|
|
|
|
result = palloc(*wkbsize);
|
|
|
|
|
|
|
|
result[0] = desiredWKBEndian; //endian flag
|
|
|
|
|
|
|
|
wkbtype = constructWKBType(LINETYPE, line->points->is3d);
|
|
|
|
memcpy(result+1, &wkbtype, 4);
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(result+1);
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
memcpy(result+5, &line->points->npoints, 4);
|
2004-03-10 01:15:06 +00:00
|
|
|
if (need_flip)
|
2004-03-11 00:54:37 +00:00
|
|
|
flip_endian_int32(result+5);
|
|
|
|
|
|
|
|
memcpy(result+9, line->points->serialized_pointlist, ptsize * line->points->npoints);
|
|
|
|
if (need_flip)
|
|
|
|
flipPoints(result+9, line->points->npoints, line->points->is3d);
|
2004-03-10 01:15:06 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize)
|
|
|
|
{
|
|
|
|
int ptsize = pointArray_ptsize(poly->rings[0]);
|
|
|
|
char * result;
|
|
|
|
uint32 wkbtype ;
|
|
|
|
bool need_flip = requiresflip( desiredWKBEndian );
|
|
|
|
int total_points =0;
|
|
|
|
char *loc;
|
|
|
|
int t;
|
|
|
|
|
|
|
|
|
|
|
|
for (t=0;t<poly->nrings;t++)
|
|
|
|
{
|
|
|
|
total_points += poly->rings[t]->npoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
*wkbsize = 1+ 4+ total_points * ptsize + 4* poly->nrings; //endian, type, all points, ring lengths
|
|
|
|
|
|
|
|
result = palloc(*wkbsize);
|
|
|
|
|
|
|
|
result[0] = desiredWKBEndian; //endian flag
|
|
|
|
|
|
|
|
wkbtype = constructWKBType(POLYGONTYPE, poly->is3d);
|
|
|
|
memcpy(result+1, &wkbtype, 4); // type
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(result+1);
|
|
|
|
|
|
|
|
memcpy(result+5, &poly->nrings, 4); // nrings
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(result+5);
|
|
|
|
|
|
|
|
loc = result+9;
|
|
|
|
|
|
|
|
for (t=0;t<poly->nrings;t++)
|
|
|
|
{
|
|
|
|
int npoints =poly->rings[t]->npoints;
|
|
|
|
memcpy( loc, &npoints, 4); // npoints
|
|
|
|
if (need_flip)
|
|
|
|
flip_endian_int32(loc);
|
|
|
|
memcpy(loc+4, poly->rings[t]->serialized_pointlist, ptsize * npoints);
|
|
|
|
if (need_flip)
|
|
|
|
flipPoints(loc+4, npoints, poly->is3d);
|
|
|
|
loc += 4+ ptsize * npoints;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool requiresflip(char WKBendianflag)
|
|
|
|
{
|
|
|
|
if (WKBendianflag == 1) // NDR
|
|
|
|
return ( BYTE_ORDER != LITTLE_ENDIAN );
|
|
|
|
if (WKBendianflag == 0) // xDR
|
|
|
|
return ( BYTE_ORDER != BIG_ENDIAN );
|
|
|
|
elog(ERROR,"WKB: endian flag isnt a 0 or 1. WKB screwed?");
|
|
|
|
return 0; //shouldnt get here
|
|
|
|
}
|
|
|
|
|
|
|
|
void swap_char(char *a,char *b)
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
|
|
|
|
c = *a;
|
|
|
|
*a=*b;
|
|
|
|
*b=c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void flip_endian_double(char *d)
|
|
|
|
{
|
|
|
|
swap_char(d+7, d);
|
|
|
|
swap_char(d+6, d+1);
|
|
|
|
swap_char(d+5, d+2);
|
|
|
|
swap_char(d+4, d+3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void flip_endian_int32(char *i)
|
|
|
|
{
|
|
|
|
swap_char (i+3,i);
|
|
|
|
swap_char (i+2,i+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// given a wkb type
|
|
|
|
// return twoDims, threeDims, or fourDims
|
|
|
|
char wkb_dims(uint32 type)
|
|
|
|
{
|
|
|
|
if (type & 0x80000000)
|
|
|
|
return THREEDIMS;
|
|
|
|
if (type & 0x40000000)
|
|
|
|
return FOURDIMS;
|
|
|
|
return TWODIMS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char wkb_simpletype (uint32 type)
|
|
|
|
{
|
|
|
|
return type & 0x0F;
|
|
|
|
}
|
|
|
|
|
|
|
|
void flipPoints(char *pts, int npoints, char dims)
|
|
|
|
{
|
|
|
|
int t;
|
|
|
|
char *loc = pts;
|
|
|
|
int size =16;
|
|
|
|
|
|
|
|
if (dims == FOURDIMS)
|
|
|
|
{
|
|
|
|
size = 32;
|
|
|
|
}
|
|
|
|
if (dims == THREEDIMS)
|
|
|
|
{
|
|
|
|
size = 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (t=0;t<npoints;t++)
|
|
|
|
{
|
|
|
|
flip_endian_double(loc);
|
|
|
|
flip_endian_double(loc+8);
|
|
|
|
if ( (dims == THREEDIMS) || (dims == FOURDIMS) )
|
|
|
|
{
|
|
|
|
flip_endian_double(loc+16);
|
|
|
|
}
|
|
|
|
if (dims == FOURDIMS)
|
|
|
|
{
|
|
|
|
flip_endian_double(loc+24);
|
|
|
|
}
|
|
|
|
loc += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 constructWKBType(int simple_type, char dims)
|
|
|
|
{
|
|
|
|
if (dims == TWODIMS)
|
|
|
|
return simple_type;
|
|
|
|
if (dims == THREEDIMS)
|
|
|
|
return simple_type | 0x80000000;
|
|
|
|
|
|
|
|
return simple_type | 0x40000000;
|
|
|
|
}
|
|
|
|
|
2004-03-11 00:54:37 +00:00
|
|
|
|
|
|
|
//given one byte, populate result with two byte representing
|
|
|
|
// the hex number
|
|
|
|
// ie deparse_hex( 255, mystr)
|
|
|
|
// -> mystr[0] = 'F' and mystr[1] = 'F'
|
|
|
|
// no error checking done
|
|
|
|
void deparse_hex(unsigned char str, unsigned char *result)
|
|
|
|
{
|
|
|
|
int input_high;
|
|
|
|
int input_low;
|
|
|
|
|
|
|
|
input_high = (str>>4);
|
|
|
|
input_low = (str & 0x0F);
|
|
|
|
|
|
|
|
switch (input_high)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
result[0] = '0';
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result[0] = '1';
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
result[0] = '2';
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
result[0] = '3';
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
result[0] = '4';
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
result[0] = '5';
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
result[0] = '6';
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
result[0] = '7';
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
result[0] = '8';
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
result[0] = '9';
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
result[0] = 'A';
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
result[0] = 'B';
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
result[0] = 'C';
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
result[0] = 'D';
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
result[0] = 'E';
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
result[0] = 'F';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (input_low)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
result[1] = '0';
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result[1] = '1';
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
result[1] = '2';
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
result[1] = '3';
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
result[1] = '4';
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
result[1] = '5';
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
result[1] = '6';
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
result[1] = '7';
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
result[1] = '8';
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
result[1] = '9';
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
result[1] = 'A';
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
result[1] = 'B';
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
result[1] = 'C';
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
result[1] = 'D';
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
result[1] = 'E';
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
result[1] = 'F';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//given a string with at least 2 chars in it, convert them to
|
|
|
|
// a byte value. No error checking done!
|
|
|
|
unsigned char parse_hex(char *str)
|
|
|
|
{
|
|
|
|
//do this a little brute force to make it faster
|
|
|
|
|
|
|
|
unsigned char result_high = 0;
|
|
|
|
unsigned char result_low = 0;
|
|
|
|
|
|
|
|
switch (str[0])
|
|
|
|
{
|
|
|
|
case '0' :
|
|
|
|
result_high = 0;
|
|
|
|
break;
|
|
|
|
case '1' :
|
|
|
|
result_high = 1;
|
|
|
|
break;
|
|
|
|
case '2' :
|
|
|
|
result_high = 2;
|
|
|
|
break;
|
|
|
|
case '3' :
|
|
|
|
result_high = 3;
|
|
|
|
break;
|
|
|
|
case '4' :
|
|
|
|
result_high = 4;
|
|
|
|
break;
|
|
|
|
case '5' :
|
|
|
|
result_high = 5;
|
|
|
|
break;
|
|
|
|
case '6' :
|
|
|
|
result_high = 6;
|
|
|
|
break;
|
|
|
|
case '7' :
|
|
|
|
result_high = 7;
|
|
|
|
break;
|
|
|
|
case '8' :
|
|
|
|
result_high = 8;
|
|
|
|
break;
|
|
|
|
case '9' :
|
|
|
|
result_high = 9;
|
|
|
|
break;
|
|
|
|
case 'A' :
|
|
|
|
result_high = 10;
|
|
|
|
break;
|
|
|
|
case 'B' :
|
|
|
|
result_high = 11;
|
|
|
|
break;
|
|
|
|
case 'C' :
|
|
|
|
result_high = 12;
|
|
|
|
break;
|
|
|
|
case 'D' :
|
|
|
|
result_high = 13;
|
|
|
|
break;
|
|
|
|
case 'E' :
|
|
|
|
result_high = 14;
|
|
|
|
break;
|
|
|
|
case 'F' :
|
|
|
|
result_high = 15;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (str[1])
|
|
|
|
{
|
|
|
|
case '0' :
|
|
|
|
result_low = 0;
|
|
|
|
break;
|
|
|
|
case '1' :
|
|
|
|
result_low = 1;
|
|
|
|
break;
|
|
|
|
case '2' :
|
|
|
|
result_low = 2;
|
|
|
|
break;
|
|
|
|
case '3' :
|
|
|
|
result_low = 3;
|
|
|
|
break;
|
|
|
|
case '4' :
|
|
|
|
result_low = 4;
|
|
|
|
break;
|
|
|
|
case '5' :
|
|
|
|
result_low = 5;
|
|
|
|
break;
|
|
|
|
case '6' :
|
|
|
|
result_low = 6;
|
|
|
|
break;
|
|
|
|
case '7' :
|
|
|
|
result_low = 7;
|
|
|
|
break;
|
|
|
|
case '8' :
|
|
|
|
result_low = 8;
|
|
|
|
break;
|
|
|
|
case '9' :
|
|
|
|
result_low = 9;
|
|
|
|
break;
|
|
|
|
case 'A' :
|
|
|
|
result_low = 10;
|
|
|
|
break;
|
|
|
|
case 'B' :
|
|
|
|
result_low = 11;
|
|
|
|
break;
|
|
|
|
case 'C' :
|
|
|
|
result_low = 12;
|
|
|
|
break;
|
|
|
|
case 'D' :
|
|
|
|
result_low = 13;
|
|
|
|
break;
|
|
|
|
case 'E' :
|
|
|
|
result_low = 14;
|
|
|
|
break;
|
|
|
|
case 'F' :
|
|
|
|
result_low = 15;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (unsigned char) ((result_high<<4) + result_low);
|
|
|
|
}
|
|
|
|
|