geo_coder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +12 -0
- data/Gemfile.lock +32 -0
- data/History.txt +6 -0
- data/Makefile +13 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +197 -0
- data/Rakefile +53 -0
- data/TODO.txt +8 -0
- data/VERSION +1 -0
- data/bin/build_indexes +8 -0
- data/bin/rebuild_cluster +22 -0
- data/bin/rebuild_metaphones +23 -0
- data/bin/tiger_import +59 -0
- data/demos/demo/app/ext/geocodewrap.rb +84 -0
- data/demos/demo/app/views/index.builder +13 -0
- data/demos/demo/app/views/index.erb +71 -0
- data/demos/demo/config.ru +12 -0
- data/demos/demo/config/bootstraps.rb +130 -0
- data/demos/demo/config/geoenvironment.rb +25 -0
- data/demos/demo/geocoder_helper.rb +12 -0
- data/demos/demo/geocom_geocode.rb +10 -0
- data/demos/demo/main.rb +3 -0
- data/demos/demo/rakefile.rb +17 -0
- data/demos/demo/tmp/restart.txt +0 -0
- data/demos/simpledemo/views/index.builder +13 -0
- data/demos/simpledemo/views/index.erb +69 -0
- data/demos/simpledemo/ws.rb +83 -0
- data/doc/Makefile +7 -0
- data/doc/html4css1.css +279 -0
- data/doc/lookup.rst +193 -0
- data/doc/parsing.rst +125 -0
- data/doc/voidspace.css +147 -0
- data/geo_coder.gemspec +172 -0
- data/lib/geocoder/us.rb +21 -0
- data/lib/geocoder/us/address.rb +290 -0
- data/lib/geocoder/us/constants.rb +670 -0
- data/lib/geocoder/us/database.rb +745 -0
- data/lib/geocoder/us/import.rb +181 -0
- data/lib/geocoder/us/import/tiger.rb +13 -0
- data/lib/geocoder/us/numbers.rb +58 -0
- data/navteq/README +4 -0
- data/navteq/convert.sql +37 -0
- data/navteq/navteq_import +39 -0
- data/navteq/prepare.sql +92 -0
- data/sql/cluster.sql +16 -0
- data/sql/convert.sql +80 -0
- data/sql/create.sql +37 -0
- data/sql/index.sql +12 -0
- data/sql/place.csv +104944 -0
- data/sql/place.sql +104948 -0
- data/sql/setup.sql +78 -0
- data/src/Makefile +13 -0
- data/src/README +14 -0
- data/src/liblwgeom/Makefile +75 -0
- data/src/liblwgeom/box2d.c +54 -0
- data/src/liblwgeom/lex.yy.c +4799 -0
- data/src/liblwgeom/liblwgeom.h +1405 -0
- data/src/liblwgeom/lwalgorithm.c +946 -0
- data/src/liblwgeom/lwalgorithm.h +52 -0
- data/src/liblwgeom/lwcircstring.c +759 -0
- data/src/liblwgeom/lwcollection.c +541 -0
- data/src/liblwgeom/lwcompound.c +118 -0
- data/src/liblwgeom/lwcurvepoly.c +86 -0
- data/src/liblwgeom/lwgeom.c +886 -0
- data/src/liblwgeom/lwgeom_api.c +2201 -0
- data/src/liblwgeom/lwgparse.c +1219 -0
- data/src/liblwgeom/lwgunparse.c +1054 -0
- data/src/liblwgeom/lwline.c +525 -0
- data/src/liblwgeom/lwmcurve.c +125 -0
- data/src/liblwgeom/lwmline.c +137 -0
- data/src/liblwgeom/lwmpoint.c +138 -0
- data/src/liblwgeom/lwmpoly.c +141 -0
- data/src/liblwgeom/lwmsurface.c +129 -0
- data/src/liblwgeom/lwpoint.c +439 -0
- data/src/liblwgeom/lwpoly.c +579 -0
- data/src/liblwgeom/lwsegmentize.c +1047 -0
- data/src/liblwgeom/lwutil.c +369 -0
- data/src/liblwgeom/measures.c +861 -0
- data/src/liblwgeom/postgis_config.h +93 -0
- data/src/liblwgeom/ptarray.c +847 -0
- data/src/liblwgeom/vsprintf.c +179 -0
- data/src/liblwgeom/wktparse.h +126 -0
- data/src/liblwgeom/wktparse.lex +74 -0
- data/src/liblwgeom/wktparse.tab.c +2353 -0
- data/src/liblwgeom/wktparse.tab.h +145 -0
- data/src/liblwgeom/wktparse.y +385 -0
- data/src/libsqlite3_geocoder/Makefile +22 -0
- data/src/libsqlite3_geocoder/Makefile.nix +15 -0
- data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
- data/src/libsqlite3_geocoder/extension.c +121 -0
- data/src/libsqlite3_geocoder/extension.h +13 -0
- data/src/libsqlite3_geocoder/levenshtein.c +42 -0
- data/src/libsqlite3_geocoder/metaphon.c +278 -0
- data/src/libsqlite3_geocoder/util.c +37 -0
- data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
- data/src/metaphone/Makefile +7 -0
- data/src/metaphone/README +49 -0
- data/src/metaphone/extension.c +37 -0
- data/src/metaphone/metaphon.c +251 -0
- data/src/shp2sqlite/Makefile +37 -0
- data/src/shp2sqlite/Makefile.nix +36 -0
- data/src/shp2sqlite/Makefile.redhat +35 -0
- data/src/shp2sqlite/dbfopen.c +1595 -0
- data/src/shp2sqlite/getopt.c +695 -0
- data/src/shp2sqlite/getopt.h +127 -0
- data/src/shp2sqlite/shapefil.h +500 -0
- data/src/shp2sqlite/shp2sqlite.c +1974 -0
- data/src/shp2sqlite/shpopen.c +1894 -0
- data/tests/address.rb +236 -0
- data/tests/benchmark.rb +20 -0
- data/tests/constants.rb +57 -0
- data/tests/data/address-sample.csv +52 -0
- data/tests/data/db-test.csv +57 -0
- data/tests/data/locations.csv +4 -0
- data/tests/database.rb +137 -0
- data/tests/generate.rb +34 -0
- data/tests/numbers.rb +46 -0
- data/tests/run.rb +11 -0
- metadata +237 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* postgis_config.h. Generated from postgis_config.h.in by configure. */
|
|
2
|
+
/* postgis_config.h.in. Generated from configure.ac by autoheader. */
|
|
3
|
+
|
|
4
|
+
/* Define to 1 if you have the <dlfcn.h> header file. */
|
|
5
|
+
#define HAVE_DLFCN_H 1
|
|
6
|
+
|
|
7
|
+
/* Defined if libiconv headers and library are present */
|
|
8
|
+
#define HAVE_ICONV 0
|
|
9
|
+
|
|
10
|
+
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
11
|
+
#define HAVE_INTTYPES_H 1
|
|
12
|
+
|
|
13
|
+
/* Define to 1 if you have the `geos_c' library (-lgeos_c). */
|
|
14
|
+
#define HAVE_LIBGEOS_C 1
|
|
15
|
+
|
|
16
|
+
/* Define to 1 if you have the `pq' library (-lpq). */
|
|
17
|
+
#define HAVE_LIBPQ 0
|
|
18
|
+
|
|
19
|
+
/* Define to 1 if you have the `proj' library (-lproj). */
|
|
20
|
+
#define HAVE_LIBPROJ 0
|
|
21
|
+
|
|
22
|
+
/* Define to 1 if you have the <memory.h> header file. */
|
|
23
|
+
#define HAVE_MEMORY_H 1
|
|
24
|
+
|
|
25
|
+
/* Define to 1 if you have the <stdint.h> header file. */
|
|
26
|
+
#define HAVE_STDINT_H 1
|
|
27
|
+
|
|
28
|
+
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
29
|
+
#define HAVE_STDLIB_H 1
|
|
30
|
+
|
|
31
|
+
/* Define to 1 if you have the <strings.h> header file. */
|
|
32
|
+
#define HAVE_STRINGS_H 1
|
|
33
|
+
|
|
34
|
+
/* Define to 1 if you have the <string.h> header file. */
|
|
35
|
+
#define HAVE_STRING_H 1
|
|
36
|
+
|
|
37
|
+
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
38
|
+
#define HAVE_SYS_STAT_H 1
|
|
39
|
+
|
|
40
|
+
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
41
|
+
#define HAVE_SYS_TYPES_H 1
|
|
42
|
+
|
|
43
|
+
/* Define to 1 if you have the <unistd.h> header file. */
|
|
44
|
+
#define HAVE_UNISTD_H 1
|
|
45
|
+
|
|
46
|
+
/* Enable caching of bounding box within geometries */
|
|
47
|
+
#define POSTGIS_AUTOCACHE_BBOX 0
|
|
48
|
+
|
|
49
|
+
/* PostGIS build date */
|
|
50
|
+
#define POSTGIS_BUILD_DATE "2009-03-09 15:11:36"
|
|
51
|
+
|
|
52
|
+
/* PostGIS library debug level (0=disabled) */
|
|
53
|
+
#define POSTGIS_DEBUG_LEVEL 0
|
|
54
|
+
|
|
55
|
+
/* GEOS library version */
|
|
56
|
+
#define POSTGIS_GEOS_VERSION 30
|
|
57
|
+
|
|
58
|
+
/* PostGIS library version */
|
|
59
|
+
#define POSTGIS_LIB_VERSION "1.4.0SVN"
|
|
60
|
+
|
|
61
|
+
/* PostGIS major version */
|
|
62
|
+
#define POSTGIS_MAJOR_VERSION "1"
|
|
63
|
+
|
|
64
|
+
/* PostGIS micro version */
|
|
65
|
+
#define POSTGIS_MICRO_VERSION "0SVN"
|
|
66
|
+
|
|
67
|
+
/* PostGIS minor version */
|
|
68
|
+
#define POSTGIS_MINOR_VERSION "4"
|
|
69
|
+
|
|
70
|
+
/* PostgreSQL server version */
|
|
71
|
+
#define POSTGIS_PGSQL_VERSION 83
|
|
72
|
+
|
|
73
|
+
/* Enable GEOS profiling (0=disabled) */
|
|
74
|
+
#define POSTGIS_PROFILE 0
|
|
75
|
+
|
|
76
|
+
/* PROJ library version */
|
|
77
|
+
#define POSTGIS_PROJ_VERSION 46
|
|
78
|
+
|
|
79
|
+
/* PostGIS scripts version */
|
|
80
|
+
#define POSTGIS_SCRIPTS_VERSION "1.4.0SVN"
|
|
81
|
+
|
|
82
|
+
/* Enable use of ANALYZE statistics */
|
|
83
|
+
#define POSTGIS_USE_STATS 1
|
|
84
|
+
|
|
85
|
+
/* PostGIS version */
|
|
86
|
+
#define POSTGIS_VERSION "1.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1"
|
|
87
|
+
|
|
88
|
+
/* Define to 1 if you have the ANSI C header files. */
|
|
89
|
+
#define STDC_HEADERS 1
|
|
90
|
+
|
|
91
|
+
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
|
92
|
+
`char[]'. */
|
|
93
|
+
#define YYTEXT_POINTER 1
|
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
* $Id: ptarray.c 3639 2009-02-04 00:28:37Z pramsey $
|
|
3
|
+
*
|
|
4
|
+
* PostGIS - Spatial Types for PostgreSQL
|
|
5
|
+
* http://postgis.refractions.net
|
|
6
|
+
* Copyright 2001-2006 Refractions Research Inc.
|
|
7
|
+
*
|
|
8
|
+
* This is free software; you can redistribute and/or modify it under
|
|
9
|
+
* the terms of the GNU General Public Licence. See the COPYING file.
|
|
10
|
+
*
|
|
11
|
+
**********************************************************************/
|
|
12
|
+
|
|
13
|
+
#include <stdio.h>
|
|
14
|
+
#include <string.h>
|
|
15
|
+
|
|
16
|
+
#include "liblwgeom.h"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
POINTARRAY *
|
|
20
|
+
ptarray_construct(char hasz, char hasm, unsigned int npoints)
|
|
21
|
+
{
|
|
22
|
+
uchar dims = 0;
|
|
23
|
+
size_t size;
|
|
24
|
+
uchar *ptlist;
|
|
25
|
+
POINTARRAY *pa;
|
|
26
|
+
|
|
27
|
+
TYPE_SETZM(dims, hasz?1:0, hasm?1:0);
|
|
28
|
+
size = TYPE_NDIMS(dims)*npoints*sizeof(double);
|
|
29
|
+
|
|
30
|
+
ptlist = (uchar *)lwalloc(size);
|
|
31
|
+
pa = lwalloc(sizeof(POINTARRAY));
|
|
32
|
+
pa->dims = dims;
|
|
33
|
+
pa->serialized_pointlist = ptlist;
|
|
34
|
+
pa->npoints = npoints;
|
|
35
|
+
|
|
36
|
+
return pa;
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void ptarray_free(POINTARRAY *pa)
|
|
41
|
+
{
|
|
42
|
+
/* TODO
|
|
43
|
+
* Turn this on after retrofitting all calls to lwfree_ in /lwgeom
|
|
44
|
+
if( pa->serialized_pointlist )
|
|
45
|
+
lwfree(pa->serialized_pointlist);
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
lwfree(pa);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void
|
|
52
|
+
ptarray_reverse(POINTARRAY *pa)
|
|
53
|
+
{
|
|
54
|
+
POINT4D pbuf;
|
|
55
|
+
uint32 i;
|
|
56
|
+
int ptsize = pointArray_ptsize(pa);
|
|
57
|
+
int last = pa->npoints-1;
|
|
58
|
+
int mid = last/2;
|
|
59
|
+
|
|
60
|
+
for (i=0; i<=mid; i++)
|
|
61
|
+
{
|
|
62
|
+
uchar *from, *to;
|
|
63
|
+
from = getPoint_internal(pa, i);
|
|
64
|
+
to = getPoint_internal(pa, (last-i));
|
|
65
|
+
memcpy((uchar *)&pbuf, to, ptsize);
|
|
66
|
+
memcpy(to, from, ptsize);
|
|
67
|
+
memcpy(from, (uchar *)&pbuf, ptsize);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* calculate the 2d bounding box of a set of points
|
|
74
|
+
* write result to the provided BOX2DFLOAT4
|
|
75
|
+
* Return 0 if bounding box is NULL (empty geom)
|
|
76
|
+
*/
|
|
77
|
+
int
|
|
78
|
+
ptarray_compute_box2d_p(const POINTARRAY *pa, BOX2DFLOAT4 *result)
|
|
79
|
+
{
|
|
80
|
+
int t;
|
|
81
|
+
POINT2D pt;
|
|
82
|
+
BOX3D box;
|
|
83
|
+
|
|
84
|
+
if (pa->npoints == 0) return 0;
|
|
85
|
+
|
|
86
|
+
getPoint2d_p(pa, 0, &pt);
|
|
87
|
+
|
|
88
|
+
box.xmin = pt.x;
|
|
89
|
+
box.xmax = pt.x;
|
|
90
|
+
box.ymin = pt.y;
|
|
91
|
+
box.ymax = pt.y;
|
|
92
|
+
|
|
93
|
+
for (t=1; t<pa->npoints; t++)
|
|
94
|
+
{
|
|
95
|
+
getPoint2d_p(pa, t, &pt);
|
|
96
|
+
if (pt.x < box.xmin) box.xmin = pt.x;
|
|
97
|
+
if (pt.y < box.ymin) box.ymin = pt.y;
|
|
98
|
+
if (pt.x > box.xmax) box.xmax = pt.x;
|
|
99
|
+
if (pt.y > box.ymax) box.ymax = pt.y;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
box3d_to_box2df_p(&box, result);
|
|
103
|
+
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* Calculate the 2d bounding box of a set of points.
|
|
109
|
+
* Return allocated BOX2DFLOAT4 or NULL (for empty array).
|
|
110
|
+
*/
|
|
111
|
+
BOX2DFLOAT4 *
|
|
112
|
+
ptarray_compute_box2d(const POINTARRAY *pa)
|
|
113
|
+
{
|
|
114
|
+
int t;
|
|
115
|
+
POINT2D pt;
|
|
116
|
+
BOX2DFLOAT4 *result;
|
|
117
|
+
|
|
118
|
+
if (pa->npoints == 0) return NULL;
|
|
119
|
+
|
|
120
|
+
result = lwalloc(sizeof(BOX2DFLOAT4));
|
|
121
|
+
|
|
122
|
+
getPoint2d_p(pa, 0, &pt);
|
|
123
|
+
|
|
124
|
+
result->xmin = pt.x;
|
|
125
|
+
result->xmax = pt.x;
|
|
126
|
+
result->ymin = pt.y;
|
|
127
|
+
result->ymax = pt.y;
|
|
128
|
+
|
|
129
|
+
for (t=1;t<pa->npoints;t++)
|
|
130
|
+
{
|
|
131
|
+
getPoint2d_p(pa, t, &pt);
|
|
132
|
+
if (pt.x < result->xmin) result->xmin = pt.x;
|
|
133
|
+
if (pt.y < result->ymin) result->ymin = pt.y;
|
|
134
|
+
if (pt.x > result->xmax) result->xmax = pt.x;
|
|
135
|
+
if (pt.y > result->ymax) result->ymax = pt.y;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* Returns a modified POINTARRAY so that no segment is
|
|
143
|
+
* longer then the given distance (computed using 2d).
|
|
144
|
+
* Every input point is kept.
|
|
145
|
+
* Z and M values for added points (if needed) are set to 0.
|
|
146
|
+
*/
|
|
147
|
+
POINTARRAY *
|
|
148
|
+
ptarray_segmentize2d(POINTARRAY *ipa, double dist)
|
|
149
|
+
{
|
|
150
|
+
double segdist;
|
|
151
|
+
POINT4D p1, p2;
|
|
152
|
+
void *ip, *op;
|
|
153
|
+
POINT4D pbuf;
|
|
154
|
+
POINTARRAY *opa;
|
|
155
|
+
int maxpoints = ipa->npoints;
|
|
156
|
+
int ptsize = pointArray_ptsize(ipa);
|
|
157
|
+
int ipoff=0; /* input point offset */
|
|
158
|
+
|
|
159
|
+
pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
|
|
160
|
+
|
|
161
|
+
/* Initial storage */
|
|
162
|
+
opa = (POINTARRAY *)lwalloc(ptsize * maxpoints);
|
|
163
|
+
opa->dims = ipa->dims;
|
|
164
|
+
opa->npoints = 0;
|
|
165
|
+
opa->serialized_pointlist = (uchar *)lwalloc(maxpoints*ptsize);
|
|
166
|
+
|
|
167
|
+
/* Add first point */
|
|
168
|
+
opa->npoints++;
|
|
169
|
+
getPoint4d_p(ipa, ipoff, &p1);
|
|
170
|
+
op = getPoint_internal(opa, opa->npoints-1);
|
|
171
|
+
memcpy(op, &p1, ptsize);
|
|
172
|
+
ipoff++;
|
|
173
|
+
|
|
174
|
+
while (ipoff<ipa->npoints)
|
|
175
|
+
{
|
|
176
|
+
/*
|
|
177
|
+
* We use these pointers to avoid
|
|
178
|
+
* "strict-aliasing rules break" warning raised
|
|
179
|
+
* by gcc (3.3 and up).
|
|
180
|
+
*
|
|
181
|
+
* It looks that casting a variable address (also
|
|
182
|
+
* referred to as "type-punned pointer")
|
|
183
|
+
* breaks those "strict" rules.
|
|
184
|
+
*
|
|
185
|
+
*/
|
|
186
|
+
POINT4D *p1ptr=&p1, *p2ptr=&p2;
|
|
187
|
+
|
|
188
|
+
getPoint4d_p(ipa, ipoff, &p2);
|
|
189
|
+
|
|
190
|
+
segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
|
|
191
|
+
|
|
192
|
+
if (segdist > dist) /* add an intermediate point */
|
|
193
|
+
{
|
|
194
|
+
pbuf.x = p1.x + (p2.x-p1.x)/segdist * dist;
|
|
195
|
+
pbuf.y = p1.y + (p2.y-p1.y)/segdist * dist;
|
|
196
|
+
/* might also compute z and m if available... */
|
|
197
|
+
ip = &pbuf;
|
|
198
|
+
memcpy(&p1, ip, ptsize);
|
|
199
|
+
}
|
|
200
|
+
else /* copy second point */
|
|
201
|
+
{
|
|
202
|
+
ip = &p2;
|
|
203
|
+
p1 = p2;
|
|
204
|
+
ipoff++;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Add point */
|
|
208
|
+
if ( ++(opa->npoints) > maxpoints ) {
|
|
209
|
+
maxpoints *= 1.5;
|
|
210
|
+
opa->serialized_pointlist = (uchar *)lwrealloc(
|
|
211
|
+
opa->serialized_pointlist,
|
|
212
|
+
maxpoints*ptsize
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
op = getPoint_internal(opa, opa->npoints-1);
|
|
216
|
+
memcpy(op, ip, ptsize);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return opa;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
char
|
|
223
|
+
ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
|
|
224
|
+
{
|
|
225
|
+
unsigned int i;
|
|
226
|
+
size_t ptsize;
|
|
227
|
+
|
|
228
|
+
if ( TYPE_GETZM(pa1->dims) != TYPE_GETZM(pa2->dims) ) return 0;
|
|
229
|
+
|
|
230
|
+
if ( pa1->npoints != pa2->npoints ) return 0;
|
|
231
|
+
|
|
232
|
+
ptsize = pointArray_ptsize(pa1);
|
|
233
|
+
|
|
234
|
+
for (i=0; i<pa1->npoints; i++)
|
|
235
|
+
{
|
|
236
|
+
if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), ptsize) )
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return 1;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/*
|
|
244
|
+
* Add a point in a pointarray.
|
|
245
|
+
* 'where' is the offset (starting at 0)
|
|
246
|
+
* if 'where' == -1 append is required.
|
|
247
|
+
*/
|
|
248
|
+
POINTARRAY *
|
|
249
|
+
ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims, unsigned int where)
|
|
250
|
+
{
|
|
251
|
+
POINTARRAY *ret;
|
|
252
|
+
POINT4D pbuf;
|
|
253
|
+
size_t ptsize = pointArray_ptsize(pa);
|
|
254
|
+
|
|
255
|
+
LWDEBUGF(3, "pa %x p %x size %d where %d",
|
|
256
|
+
pa, p, pdims, where);
|
|
257
|
+
|
|
258
|
+
if ( pdims < 2 || pdims > 4 )
|
|
259
|
+
{
|
|
260
|
+
lwerror("ptarray_addPoint: point dimension out of range (%d)",
|
|
261
|
+
pdims);
|
|
262
|
+
return NULL;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if ( where > pa->npoints )
|
|
266
|
+
{
|
|
267
|
+
lwerror("ptarray_addPoint: offset out of range (%d)",
|
|
268
|
+
where);
|
|
269
|
+
return NULL;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
LWDEBUG(3, "called with a %dD point");
|
|
273
|
+
|
|
274
|
+
pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;
|
|
275
|
+
memcpy((uchar *)&pbuf, p, pdims*sizeof(double));
|
|
276
|
+
|
|
277
|
+
LWDEBUG(3, "initialized point buffer");
|
|
278
|
+
|
|
279
|
+
ret = ptarray_construct(TYPE_HASZ(pa->dims),
|
|
280
|
+
TYPE_HASM(pa->dims), pa->npoints+1);
|
|
281
|
+
|
|
282
|
+
if ( where == -1 ) where = pa->npoints;
|
|
283
|
+
|
|
284
|
+
if ( where )
|
|
285
|
+
{
|
|
286
|
+
memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
memcpy(getPoint_internal(ret, where), (uchar *)&pbuf, ptsize);
|
|
290
|
+
|
|
291
|
+
if ( where+1 != ret->npoints )
|
|
292
|
+
{
|
|
293
|
+
memcpy(getPoint_internal(ret, where+1),
|
|
294
|
+
getPoint_internal(pa, where),
|
|
295
|
+
ptsize*(pa->npoints-where));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return ret;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
* Remove a point from a pointarray.
|
|
303
|
+
* 'which' is the offset (starting at 0)
|
|
304
|
+
* Returned pointarray is newly allocated
|
|
305
|
+
*/
|
|
306
|
+
POINTARRAY *
|
|
307
|
+
ptarray_removePoint(POINTARRAY *pa, unsigned int which)
|
|
308
|
+
{
|
|
309
|
+
POINTARRAY *ret;
|
|
310
|
+
size_t ptsize = pointArray_ptsize(pa);
|
|
311
|
+
|
|
312
|
+
LWDEBUGF(3, "pa %x which %d", pa, which);
|
|
313
|
+
|
|
314
|
+
#if PARANOIA_LEVEL > 0
|
|
315
|
+
if ( which > pa->npoints-1 )
|
|
316
|
+
{
|
|
317
|
+
lwerror("ptarray_removePoint: offset (%d) out of range (%d..%d)",
|
|
318
|
+
which, 0, pa->npoints-1);
|
|
319
|
+
return NULL;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if ( pa->npoints < 3 )
|
|
323
|
+
{
|
|
324
|
+
lwerror("ptarray_removePointe: can't remove a point from a 2-vertex POINTARRAY");
|
|
325
|
+
}
|
|
326
|
+
#endif
|
|
327
|
+
|
|
328
|
+
ret = ptarray_construct(TYPE_HASZ(pa->dims),
|
|
329
|
+
TYPE_HASM(pa->dims), pa->npoints-1);
|
|
330
|
+
|
|
331
|
+
/* copy initial part */
|
|
332
|
+
if ( which )
|
|
333
|
+
{
|
|
334
|
+
memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* copy final part */
|
|
338
|
+
if ( which < pa->npoints-1 )
|
|
339
|
+
{
|
|
340
|
+
memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
|
|
341
|
+
ptsize*(pa->npoints-which-1));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return ret;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/*
|
|
348
|
+
* Clone a pointarray
|
|
349
|
+
*/
|
|
350
|
+
POINTARRAY *
|
|
351
|
+
ptarray_clone(const POINTARRAY *in)
|
|
352
|
+
{
|
|
353
|
+
POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
|
|
354
|
+
size_t size;
|
|
355
|
+
|
|
356
|
+
LWDEBUG(3, "ptarray_clone called.");
|
|
357
|
+
|
|
358
|
+
out->dims = in->dims;
|
|
359
|
+
out->npoints = in->npoints;
|
|
360
|
+
|
|
361
|
+
size = in->npoints*sizeof(double)*TYPE_NDIMS(in->dims);
|
|
362
|
+
out->serialized_pointlist = lwalloc(size);
|
|
363
|
+
memcpy(out->serialized_pointlist, in->serialized_pointlist, size);
|
|
364
|
+
|
|
365
|
+
return out;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
int
|
|
369
|
+
ptarray_isclosed2d(const POINTARRAY *in)
|
|
370
|
+
{
|
|
371
|
+
if ( memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D)) ) return 0;
|
|
372
|
+
return 1;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/*
|
|
376
|
+
* calculate the BOX3D bounding box of a set of points
|
|
377
|
+
* returns a lwalloced BOX3D, or NULL on empty array.
|
|
378
|
+
* zmin/zmax values are set to NO_Z_VALUE if not available.
|
|
379
|
+
*/
|
|
380
|
+
BOX3D *
|
|
381
|
+
ptarray_compute_box3d(const POINTARRAY *pa)
|
|
382
|
+
{
|
|
383
|
+
BOX3D *result = lwalloc(sizeof(BOX3D));
|
|
384
|
+
|
|
385
|
+
if ( ! ptarray_compute_box3d_p(pa, result) )
|
|
386
|
+
{
|
|
387
|
+
lwfree(result);
|
|
388
|
+
return NULL;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
* calculate the BOX3D bounding box of a set of points
|
|
396
|
+
* zmin/zmax values are set to NO_Z_VALUE if not available.
|
|
397
|
+
* write result to the provided BOX3D
|
|
398
|
+
* Return 0 if bounding box is NULL (empty geom)
|
|
399
|
+
*/
|
|
400
|
+
int
|
|
401
|
+
ptarray_compute_box3d_p(const POINTARRAY *pa, BOX3D *result)
|
|
402
|
+
{
|
|
403
|
+
int t;
|
|
404
|
+
POINT3DZ pt;
|
|
405
|
+
|
|
406
|
+
LWDEBUGF(3, "ptarray_compute_box3d call (array has %d points)", pa->npoints);
|
|
407
|
+
|
|
408
|
+
if (pa->npoints == 0) return 0;
|
|
409
|
+
|
|
410
|
+
getPoint3dz_p(pa, 0, &pt);
|
|
411
|
+
|
|
412
|
+
LWDEBUG(3, "got point 0");
|
|
413
|
+
|
|
414
|
+
result->xmin = pt.x;
|
|
415
|
+
result->xmax = pt.x;
|
|
416
|
+
result->ymin = pt.y;
|
|
417
|
+
result->ymax = pt.y;
|
|
418
|
+
|
|
419
|
+
if ( TYPE_HASZ(pa->dims) ) {
|
|
420
|
+
result->zmin = pt.z;
|
|
421
|
+
result->zmax = pt.z;
|
|
422
|
+
} else {
|
|
423
|
+
result->zmin = NO_Z_VALUE;
|
|
424
|
+
result->zmax = NO_Z_VALUE;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
LWDEBUGF(3, "scanning other %d points", pa->npoints);
|
|
428
|
+
|
|
429
|
+
for (t=1; t<pa->npoints; t++)
|
|
430
|
+
{
|
|
431
|
+
getPoint3dz_p(pa,t,&pt);
|
|
432
|
+
if (pt.x < result->xmin) result->xmin = pt.x;
|
|
433
|
+
if (pt.y < result->ymin) result->ymin = pt.y;
|
|
434
|
+
if (pt.x > result->xmax) result->xmax = pt.x;
|
|
435
|
+
if (pt.y > result->ymax) result->ymax = pt.y;
|
|
436
|
+
|
|
437
|
+
if ( TYPE_HASZ(pa->dims) ) {
|
|
438
|
+
if (pt.z > result->zmax) result->zmax = pt.z;
|
|
439
|
+
if (pt.z < result->zmin) result->zmin = pt.z;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
LWDEBUG(3, "returning box");
|
|
444
|
+
|
|
445
|
+
return 1;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/*
|
|
449
|
+
* TODO: implement point interpolation
|
|
450
|
+
*/
|
|
451
|
+
POINTARRAY *
|
|
452
|
+
ptarray_substring(POINTARRAY *ipa, double from, double to)
|
|
453
|
+
{
|
|
454
|
+
DYNPTARRAY *dpa;
|
|
455
|
+
POINTARRAY *opa;
|
|
456
|
+
POINT4D pt;
|
|
457
|
+
POINT4D p1, p2;
|
|
458
|
+
POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
|
|
459
|
+
POINT4D *p2ptr=&p2;
|
|
460
|
+
int nsegs, i;
|
|
461
|
+
double length, slength, tlength;
|
|
462
|
+
int state = 0; /* 0=before, 1=inside */
|
|
463
|
+
|
|
464
|
+
/*
|
|
465
|
+
* Create a dynamic pointarray with an initial capacity
|
|
466
|
+
* equal to full copy of input points
|
|
467
|
+
*/
|
|
468
|
+
dpa = dynptarray_create(ipa->npoints, ipa->dims);
|
|
469
|
+
|
|
470
|
+
/* Compute total line length */
|
|
471
|
+
length = lwgeom_pointarray_length2d(ipa);
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
LWDEBUGF(3, "Total length: %g", length);
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
/* Get 'from' and 'to' lengths */
|
|
478
|
+
from = length*from;
|
|
479
|
+
to = length*to;
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
LWDEBUGF(3, "From/To: %g/%g", from, to);
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
tlength = 0;
|
|
486
|
+
getPoint4d_p(ipa, 0, &p1);
|
|
487
|
+
nsegs = ipa->npoints - 1;
|
|
488
|
+
for( i = 0; i < nsegs; i++ )
|
|
489
|
+
{
|
|
490
|
+
double dseg;
|
|
491
|
+
|
|
492
|
+
getPoint4d_p(ipa, i+1, &p2);
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
|
|
496
|
+
i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
/* Find the length of this segment */
|
|
500
|
+
slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
|
|
501
|
+
|
|
502
|
+
/*
|
|
503
|
+
* We are before requested start.
|
|
504
|
+
*/
|
|
505
|
+
if ( state == 0 ) /* before */
|
|
506
|
+
{
|
|
507
|
+
|
|
508
|
+
LWDEBUG(3, " Before start");
|
|
509
|
+
|
|
510
|
+
/*
|
|
511
|
+
* Didn't reach the 'from' point,
|
|
512
|
+
* nothing to do
|
|
513
|
+
*/
|
|
514
|
+
if ( from > tlength + slength ) goto END;
|
|
515
|
+
|
|
516
|
+
else if ( from == tlength + slength )
|
|
517
|
+
{
|
|
518
|
+
|
|
519
|
+
LWDEBUG(3, " Second point is our start");
|
|
520
|
+
|
|
521
|
+
/*
|
|
522
|
+
* Second point is our start
|
|
523
|
+
*/
|
|
524
|
+
dynptarray_addPoint4d(dpa, &p2, 1);
|
|
525
|
+
state=1; /* we're inside now */
|
|
526
|
+
goto END;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
else if ( from == tlength )
|
|
530
|
+
{
|
|
531
|
+
|
|
532
|
+
LWDEBUG(3, " First point is our start");
|
|
533
|
+
|
|
534
|
+
/*
|
|
535
|
+
* First point is our start
|
|
536
|
+
*/
|
|
537
|
+
dynptarray_addPoint4d(dpa, &p1, 1);
|
|
538
|
+
|
|
539
|
+
/*
|
|
540
|
+
* We're inside now, but will check
|
|
541
|
+
* 'to' point as well
|
|
542
|
+
*/
|
|
543
|
+
state=1;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
else /* tlength < from < tlength+slength */
|
|
547
|
+
{
|
|
548
|
+
|
|
549
|
+
LWDEBUG(3, " Seg contains first point");
|
|
550
|
+
|
|
551
|
+
/*
|
|
552
|
+
* Our start is between first and
|
|
553
|
+
* second point
|
|
554
|
+
*/
|
|
555
|
+
dseg = (from - tlength) / slength;
|
|
556
|
+
interpolate_point4d(&p1, &p2, &pt, dseg);
|
|
557
|
+
|
|
558
|
+
dynptarray_addPoint4d(dpa, &pt, 1);
|
|
559
|
+
|
|
560
|
+
/*
|
|
561
|
+
* We're inside now, but will check
|
|
562
|
+
* 'to' point as well
|
|
563
|
+
*/
|
|
564
|
+
state=1;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if ( state == 1 ) /* inside */
|
|
569
|
+
{
|
|
570
|
+
|
|
571
|
+
LWDEBUG(3, " Inside");
|
|
572
|
+
|
|
573
|
+
/*
|
|
574
|
+
* Didn't reach the 'end' point,
|
|
575
|
+
* just copy second point
|
|
576
|
+
*/
|
|
577
|
+
if ( to > tlength + slength )
|
|
578
|
+
{
|
|
579
|
+
dynptarray_addPoint4d(dpa, &p2, 0);
|
|
580
|
+
goto END;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/*
|
|
584
|
+
* 'to' point is our second point.
|
|
585
|
+
*/
|
|
586
|
+
else if ( to == tlength + slength )
|
|
587
|
+
{
|
|
588
|
+
|
|
589
|
+
LWDEBUG(3, " Second point is our end");
|
|
590
|
+
|
|
591
|
+
dynptarray_addPoint4d(dpa, &p2, 0);
|
|
592
|
+
break; /* substring complete */
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/*
|
|
596
|
+
* 'to' point is our first point.
|
|
597
|
+
* (should only happen if 'to' is 0)
|
|
598
|
+
*/
|
|
599
|
+
else if ( to == tlength )
|
|
600
|
+
{
|
|
601
|
+
|
|
602
|
+
LWDEBUG(3, " First point is our end");
|
|
603
|
+
|
|
604
|
+
dynptarray_addPoint4d(dpa, &p1, 0);
|
|
605
|
+
|
|
606
|
+
break; /* substring complete */
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/*
|
|
610
|
+
* 'to' point falls on this segment
|
|
611
|
+
* Interpolate and break.
|
|
612
|
+
*/
|
|
613
|
+
else if ( to < tlength + slength )
|
|
614
|
+
{
|
|
615
|
+
|
|
616
|
+
LWDEBUG(3, " Seg contains our end");
|
|
617
|
+
|
|
618
|
+
dseg = (to - tlength) / slength;
|
|
619
|
+
interpolate_point4d(&p1, &p2, &pt, dseg);
|
|
620
|
+
|
|
621
|
+
dynptarray_addPoint4d(dpa, &pt, 0);
|
|
622
|
+
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
else
|
|
627
|
+
{
|
|
628
|
+
LWDEBUG(3, "Unhandled case");
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
END:
|
|
634
|
+
|
|
635
|
+
tlength += slength;
|
|
636
|
+
memcpy(&p1, &p2, sizeof(POINT4D));
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* Get constructed pointarray and release memory associated
|
|
640
|
+
* with the dynamic pointarray
|
|
641
|
+
*/
|
|
642
|
+
opa = dpa->pa;
|
|
643
|
+
lwfree(dpa);
|
|
644
|
+
|
|
645
|
+
LWDEBUGF(3, "Out of loop, ptarray has %d points", opa->npoints);
|
|
646
|
+
|
|
647
|
+
return opa;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/*
|
|
651
|
+
* Write into the *ret argument coordinates of the closes point on
|
|
652
|
+
* the given segment to the reference input point.
|
|
653
|
+
*/
|
|
654
|
+
void
|
|
655
|
+
closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)
|
|
656
|
+
{
|
|
657
|
+
double r;
|
|
658
|
+
|
|
659
|
+
if ( ( A->x == B->x) && (A->y == B->y) )
|
|
660
|
+
{
|
|
661
|
+
*ret = *A;
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/*
|
|
666
|
+
* We use comp.graphics.algorithms Frequently Asked Questions method
|
|
667
|
+
*
|
|
668
|
+
* (1) AC dot AB
|
|
669
|
+
* r = ----------
|
|
670
|
+
* ||AB||^2
|
|
671
|
+
* r has the following meaning:
|
|
672
|
+
* r=0 P = A
|
|
673
|
+
* r=1 P = B
|
|
674
|
+
* r<0 P is on the backward extension of AB
|
|
675
|
+
* r>1 P is on the forward extension of AB
|
|
676
|
+
* 0<r<1 P is interior to AB
|
|
677
|
+
*
|
|
678
|
+
*/
|
|
679
|
+
r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
|
|
680
|
+
|
|
681
|
+
if (r<0) {
|
|
682
|
+
*ret = *A; return;
|
|
683
|
+
}
|
|
684
|
+
if (r>1) {
|
|
685
|
+
*ret = *B;
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
ret->x = A->x + ( (B->x - A->x) * r );
|
|
690
|
+
ret->y = A->y + ( (B->y - A->y) * r );
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/*
|
|
694
|
+
* Given a point, returns the location of closest point on pointarray
|
|
695
|
+
*/
|
|
696
|
+
double
|
|
697
|
+
ptarray_locate_point(POINTARRAY *pa, POINT2D *p)
|
|
698
|
+
{
|
|
699
|
+
double mindist=-1;
|
|
700
|
+
double tlen, plen;
|
|
701
|
+
int t, seg=-1;
|
|
702
|
+
POINT2D start, end;
|
|
703
|
+
POINT2D proj;
|
|
704
|
+
|
|
705
|
+
getPoint2d_p(pa, 0, &start);
|
|
706
|
+
for (t=1; t<pa->npoints; t++)
|
|
707
|
+
{
|
|
708
|
+
double dist;
|
|
709
|
+
getPoint2d_p(pa, t, &end);
|
|
710
|
+
dist = distance2d_pt_seg(p, &start, &end);
|
|
711
|
+
|
|
712
|
+
if (t==1 || dist < mindist ) {
|
|
713
|
+
mindist = dist;
|
|
714
|
+
seg=t-1;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if ( mindist == 0 ) break;
|
|
718
|
+
|
|
719
|
+
start = end;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
LWDEBUGF(3, "Closest segment: %d", seg);
|
|
723
|
+
|
|
724
|
+
/*
|
|
725
|
+
* If mindist is not 0 we need to project the
|
|
726
|
+
* point on the closest segment.
|
|
727
|
+
*/
|
|
728
|
+
if ( mindist > 0 )
|
|
729
|
+
{
|
|
730
|
+
getPoint2d_p(pa, seg, &start);
|
|
731
|
+
getPoint2d_p(pa, seg+1, &end);
|
|
732
|
+
closest_point_on_segment(p, &start, &end, &proj);
|
|
733
|
+
} else {
|
|
734
|
+
proj = *p;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
|
|
738
|
+
|
|
739
|
+
tlen = lwgeom_pointarray_length2d(pa);
|
|
740
|
+
|
|
741
|
+
LWDEBUGF(3, "tlen %g", tlen);
|
|
742
|
+
|
|
743
|
+
plen=0;
|
|
744
|
+
getPoint2d_p(pa, 0, &start);
|
|
745
|
+
for (t=0; t<seg; t++, start=end)
|
|
746
|
+
{
|
|
747
|
+
getPoint2d_p(pa, t+1, &end);
|
|
748
|
+
plen += distance2d_pt_pt(&start, &end);
|
|
749
|
+
|
|
750
|
+
LWDEBUGF(4, "Segment %d made plen %g", t, plen);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
plen+=distance2d_pt_pt(&proj, &start);
|
|
754
|
+
|
|
755
|
+
LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);
|
|
756
|
+
LWDEBUGF(3, "mindist: %g", mindist);
|
|
757
|
+
|
|
758
|
+
return plen/tlen;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/*
|
|
762
|
+
* Longitude shift for a pointarray.
|
|
763
|
+
* Y remains the same
|
|
764
|
+
* X is converted:
|
|
765
|
+
* from -180..180 to 0..360
|
|
766
|
+
* from 0..360 to -180..180
|
|
767
|
+
* X < 0 becomes X + 360
|
|
768
|
+
* X > 180 becomes X - 360
|
|
769
|
+
*/
|
|
770
|
+
void
|
|
771
|
+
ptarray_longitude_shift(POINTARRAY *pa)
|
|
772
|
+
{
|
|
773
|
+
int i;
|
|
774
|
+
double x;
|
|
775
|
+
|
|
776
|
+
for (i=0; i<pa->npoints; i++) {
|
|
777
|
+
memcpy(&x, getPoint_internal(pa, i), sizeof(double));
|
|
778
|
+
if ( x < 0 ) x+= 360;
|
|
779
|
+
else if ( x > 180 ) x -= 360;
|
|
780
|
+
memcpy(getPoint_internal(pa, i), &x, sizeof(double));
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
DYNPTARRAY *
|
|
785
|
+
dynptarray_create(size_t initial_capacity, int dims)
|
|
786
|
+
{
|
|
787
|
+
DYNPTARRAY *ret=lwalloc(sizeof(DYNPTARRAY));
|
|
788
|
+
|
|
789
|
+
LWDEBUGF(3, "dynptarray_create called, dims=%d.", dims);
|
|
790
|
+
|
|
791
|
+
if ( initial_capacity < 1 ) initial_capacity=1;
|
|
792
|
+
|
|
793
|
+
ret->pa=lwalloc(sizeof(POINTARRAY));
|
|
794
|
+
ret->pa->dims=dims;
|
|
795
|
+
ret->ptsize=pointArray_ptsize(ret->pa);
|
|
796
|
+
ret->capacity=initial_capacity;
|
|
797
|
+
ret->pa->serialized_pointlist=lwalloc(ret->ptsize*ret->capacity);
|
|
798
|
+
ret->pa->npoints=0;
|
|
799
|
+
|
|
800
|
+
return ret;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/*
|
|
804
|
+
* Add a POINT4D to the dynamic pointarray.
|
|
805
|
+
*
|
|
806
|
+
* The dynamic pointarray may be of any dimension, only
|
|
807
|
+
* accepted dimensions will be copied.
|
|
808
|
+
*
|
|
809
|
+
* If allow_duplicates is set to 0 (false) a check
|
|
810
|
+
* is performed to see if last point in array is equal to the
|
|
811
|
+
* provided one. NOTE that the check is 4d based, with missing
|
|
812
|
+
* ordinates in the pointarray set to NO_Z_VALUE and NO_M_VALUE
|
|
813
|
+
* respectively.
|
|
814
|
+
*/
|
|
815
|
+
int
|
|
816
|
+
dynptarray_addPoint4d(DYNPTARRAY *dpa, POINT4D *p4d, int allow_duplicates)
|
|
817
|
+
{
|
|
818
|
+
POINTARRAY *pa=dpa->pa;
|
|
819
|
+
POINT4D tmp;
|
|
820
|
+
|
|
821
|
+
LWDEBUG(3, "dynptarray_addPoint4d called.");
|
|
822
|
+
|
|
823
|
+
if ( ! allow_duplicates && pa->npoints > 0 )
|
|
824
|
+
{
|
|
825
|
+
getPoint4d_p(pa, pa->npoints-1, &tmp);
|
|
826
|
+
|
|
827
|
+
/*
|
|
828
|
+
* return 0 and do nothing else if previous point in list is
|
|
829
|
+
* equal to this one (4D equality)
|
|
830
|
+
*/
|
|
831
|
+
if (tmp.x == p4d->x && tmp.y == p4d->y && tmp.z == p4d->z && tmp.m == p4d->m) return 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
++pa->npoints;
|
|
835
|
+
if ( pa->npoints > dpa->capacity )
|
|
836
|
+
{
|
|
837
|
+
dpa->capacity*=2;
|
|
838
|
+
pa->serialized_pointlist = lwrealloc(
|
|
839
|
+
pa->serialized_pointlist,
|
|
840
|
+
dpa->capacity*dpa->ptsize);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
setPoint4d(pa, pa->npoints-1, p4d);
|
|
844
|
+
|
|
845
|
+
return 1;
|
|
846
|
+
}
|
|
847
|
+
|