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.
Files changed (119) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +32 -0
  3. data/History.txt +6 -0
  4. data/Makefile +13 -0
  5. data/Manifest.txt +18 -0
  6. data/README.rdoc +197 -0
  7. data/Rakefile +53 -0
  8. data/TODO.txt +8 -0
  9. data/VERSION +1 -0
  10. data/bin/build_indexes +8 -0
  11. data/bin/rebuild_cluster +22 -0
  12. data/bin/rebuild_metaphones +23 -0
  13. data/bin/tiger_import +59 -0
  14. data/demos/demo/app/ext/geocodewrap.rb +84 -0
  15. data/demos/demo/app/views/index.builder +13 -0
  16. data/demos/demo/app/views/index.erb +71 -0
  17. data/demos/demo/config.ru +12 -0
  18. data/demos/demo/config/bootstraps.rb +130 -0
  19. data/demos/demo/config/geoenvironment.rb +25 -0
  20. data/demos/demo/geocoder_helper.rb +12 -0
  21. data/demos/demo/geocom_geocode.rb +10 -0
  22. data/demos/demo/main.rb +3 -0
  23. data/demos/demo/rakefile.rb +17 -0
  24. data/demos/demo/tmp/restart.txt +0 -0
  25. data/demos/simpledemo/views/index.builder +13 -0
  26. data/demos/simpledemo/views/index.erb +69 -0
  27. data/demos/simpledemo/ws.rb +83 -0
  28. data/doc/Makefile +7 -0
  29. data/doc/html4css1.css +279 -0
  30. data/doc/lookup.rst +193 -0
  31. data/doc/parsing.rst +125 -0
  32. data/doc/voidspace.css +147 -0
  33. data/geo_coder.gemspec +172 -0
  34. data/lib/geocoder/us.rb +21 -0
  35. data/lib/geocoder/us/address.rb +290 -0
  36. data/lib/geocoder/us/constants.rb +670 -0
  37. data/lib/geocoder/us/database.rb +745 -0
  38. data/lib/geocoder/us/import.rb +181 -0
  39. data/lib/geocoder/us/import/tiger.rb +13 -0
  40. data/lib/geocoder/us/numbers.rb +58 -0
  41. data/navteq/README +4 -0
  42. data/navteq/convert.sql +37 -0
  43. data/navteq/navteq_import +39 -0
  44. data/navteq/prepare.sql +92 -0
  45. data/sql/cluster.sql +16 -0
  46. data/sql/convert.sql +80 -0
  47. data/sql/create.sql +37 -0
  48. data/sql/index.sql +12 -0
  49. data/sql/place.csv +104944 -0
  50. data/sql/place.sql +104948 -0
  51. data/sql/setup.sql +78 -0
  52. data/src/Makefile +13 -0
  53. data/src/README +14 -0
  54. data/src/liblwgeom/Makefile +75 -0
  55. data/src/liblwgeom/box2d.c +54 -0
  56. data/src/liblwgeom/lex.yy.c +4799 -0
  57. data/src/liblwgeom/liblwgeom.h +1405 -0
  58. data/src/liblwgeom/lwalgorithm.c +946 -0
  59. data/src/liblwgeom/lwalgorithm.h +52 -0
  60. data/src/liblwgeom/lwcircstring.c +759 -0
  61. data/src/liblwgeom/lwcollection.c +541 -0
  62. data/src/liblwgeom/lwcompound.c +118 -0
  63. data/src/liblwgeom/lwcurvepoly.c +86 -0
  64. data/src/liblwgeom/lwgeom.c +886 -0
  65. data/src/liblwgeom/lwgeom_api.c +2201 -0
  66. data/src/liblwgeom/lwgparse.c +1219 -0
  67. data/src/liblwgeom/lwgunparse.c +1054 -0
  68. data/src/liblwgeom/lwline.c +525 -0
  69. data/src/liblwgeom/lwmcurve.c +125 -0
  70. data/src/liblwgeom/lwmline.c +137 -0
  71. data/src/liblwgeom/lwmpoint.c +138 -0
  72. data/src/liblwgeom/lwmpoly.c +141 -0
  73. data/src/liblwgeom/lwmsurface.c +129 -0
  74. data/src/liblwgeom/lwpoint.c +439 -0
  75. data/src/liblwgeom/lwpoly.c +579 -0
  76. data/src/liblwgeom/lwsegmentize.c +1047 -0
  77. data/src/liblwgeom/lwutil.c +369 -0
  78. data/src/liblwgeom/measures.c +861 -0
  79. data/src/liblwgeom/postgis_config.h +93 -0
  80. data/src/liblwgeom/ptarray.c +847 -0
  81. data/src/liblwgeom/vsprintf.c +179 -0
  82. data/src/liblwgeom/wktparse.h +126 -0
  83. data/src/liblwgeom/wktparse.lex +74 -0
  84. data/src/liblwgeom/wktparse.tab.c +2353 -0
  85. data/src/liblwgeom/wktparse.tab.h +145 -0
  86. data/src/liblwgeom/wktparse.y +385 -0
  87. data/src/libsqlite3_geocoder/Makefile +22 -0
  88. data/src/libsqlite3_geocoder/Makefile.nix +15 -0
  89. data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
  90. data/src/libsqlite3_geocoder/extension.c +121 -0
  91. data/src/libsqlite3_geocoder/extension.h +13 -0
  92. data/src/libsqlite3_geocoder/levenshtein.c +42 -0
  93. data/src/libsqlite3_geocoder/metaphon.c +278 -0
  94. data/src/libsqlite3_geocoder/util.c +37 -0
  95. data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
  96. data/src/metaphone/Makefile +7 -0
  97. data/src/metaphone/README +49 -0
  98. data/src/metaphone/extension.c +37 -0
  99. data/src/metaphone/metaphon.c +251 -0
  100. data/src/shp2sqlite/Makefile +37 -0
  101. data/src/shp2sqlite/Makefile.nix +36 -0
  102. data/src/shp2sqlite/Makefile.redhat +35 -0
  103. data/src/shp2sqlite/dbfopen.c +1595 -0
  104. data/src/shp2sqlite/getopt.c +695 -0
  105. data/src/shp2sqlite/getopt.h +127 -0
  106. data/src/shp2sqlite/shapefil.h +500 -0
  107. data/src/shp2sqlite/shp2sqlite.c +1974 -0
  108. data/src/shp2sqlite/shpopen.c +1894 -0
  109. data/tests/address.rb +236 -0
  110. data/tests/benchmark.rb +20 -0
  111. data/tests/constants.rb +57 -0
  112. data/tests/data/address-sample.csv +52 -0
  113. data/tests/data/db-test.csv +57 -0
  114. data/tests/data/locations.csv +4 -0
  115. data/tests/database.rb +137 -0
  116. data/tests/generate.rb +34 -0
  117. data/tests/numbers.rb +46 -0
  118. data/tests/run.rb +11 -0
  119. metadata +237 -0
@@ -0,0 +1,369 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <stdarg.h>
4
+ #include <string.h>
5
+
6
+
7
+ /* Global variables */
8
+ #include "liblwgeom.h"
9
+
10
+ void *init_allocator(size_t size);
11
+ void init_freeor(void *mem);
12
+ void *init_reallocator(void *mem, size_t size);
13
+ void init_noticereporter(const char *fmt, va_list ap);
14
+ void init_errorreporter(const char *fmt, va_list ap);
15
+
16
+ lwallocator lwalloc_var = init_allocator;
17
+ lwreallocator lwrealloc_var = init_reallocator;
18
+ lwfreeor lwfree_var = init_freeor;
19
+ lwreporter lwnotice_var = init_noticereporter;
20
+ lwreporter lwerror_var = init_errorreporter;
21
+
22
+ static char *lwgeomTypeName[] = {
23
+ "Unknown",
24
+ "Point",
25
+ "Line",
26
+ "Polygon",
27
+ "MultiPoint",
28
+ "MultiLine",
29
+ "MultiPolygon",
30
+ "GeometryCollection",
31
+ "CircularString",
32
+ "CompoundString",
33
+ "Invalid Type", /* POINTTYPEI */
34
+ "Invalid Type", /* LINETYPEI */
35
+ "Invalid Type", /* POLYTYPEI */
36
+ "CurvePolygon",
37
+ "MultiCurve",
38
+ "MultiSurface"
39
+ };
40
+
41
+
42
+ /*
43
+ * lwnotice/lwerror handlers
44
+ *
45
+ * Since variadic functions cannot pass their parameters directly, we need
46
+ * wrappers for these functions to convert the arguments into a va_list
47
+ * structure.
48
+ */
49
+
50
+ void
51
+ lwnotice(const char *fmt, ...)
52
+ {
53
+ va_list ap;
54
+
55
+ va_start(ap, fmt);
56
+
57
+ /* Call the supplied function */
58
+ (*lwnotice_var)(fmt, ap);
59
+
60
+ va_end(ap);
61
+ }
62
+
63
+ void
64
+ lwerror(const char *fmt, ...)
65
+ {
66
+ va_list ap;
67
+
68
+ va_start(ap, fmt);
69
+
70
+ /* Call the supplied function */
71
+ (*lwerror_var)(fmt, ap);
72
+
73
+ va_end(ap);
74
+ }
75
+
76
+ /*
77
+ * Initialisation allocators
78
+ *
79
+ * These are used the first time any of the allocators are called
80
+ * to enable executables/libraries that link into liblwgeom to
81
+ * be able to set up their own allocators. This is mainly useful
82
+ * for older PostgreSQL versions that don't have functions that
83
+ * are called upon startup.
84
+ */
85
+
86
+ void *
87
+ init_allocator(size_t size)
88
+ {
89
+ lwgeom_init_allocators();
90
+
91
+ return lwalloc_var(size);
92
+ }
93
+
94
+ void
95
+ init_freeor(void *mem)
96
+ {
97
+ lwgeom_init_allocators();
98
+
99
+ lwfree_var(mem);
100
+ }
101
+
102
+ void *
103
+ init_reallocator(void *mem, size_t size)
104
+ {
105
+ lwgeom_init_allocators();
106
+
107
+ return lwrealloc_var(mem, size);
108
+ }
109
+
110
+ void
111
+ init_noticereporter(const char *fmt, va_list ap)
112
+ {
113
+ lwgeom_init_allocators();
114
+
115
+ (*lwnotice_var)(fmt, ap);
116
+ }
117
+
118
+ void
119
+ init_errorreporter(const char *fmt, va_list ap)
120
+ {
121
+ lwgeom_init_allocators();
122
+
123
+ (*lwerror_var)(fmt, ap);
124
+ }
125
+
126
+
127
+ /*
128
+ * Default allocators
129
+ *
130
+ * We include some default allocators that use malloc/free/realloc
131
+ * along with stdout/stderr since this is the most common use case
132
+ *
133
+ */
134
+
135
+ void *
136
+ default_allocator(size_t size)
137
+ {
138
+ void *mem = malloc(size);
139
+ return mem;
140
+ }
141
+
142
+ void
143
+ default_freeor(void *mem)
144
+ {
145
+ free(mem);
146
+ }
147
+
148
+ void *
149
+ default_reallocator(void *mem, size_t size)
150
+ {
151
+ void *ret = realloc(mem, size);
152
+ return ret;
153
+ }
154
+
155
+ void
156
+ default_noticereporter(const char *fmt, va_list ap)
157
+ {
158
+ char *msg;
159
+
160
+ /*
161
+ * This is a GNU extension.
162
+ * Dunno how to handle errors here.
163
+ */
164
+ if (!lw_vasprintf (&msg, fmt, ap))
165
+ {
166
+ va_end (ap);
167
+ return;
168
+ }
169
+ printf("%s\n", msg);
170
+ free(msg);
171
+ }
172
+
173
+ void
174
+ default_errorreporter(const char *fmt, va_list ap)
175
+ {
176
+ char *msg;
177
+
178
+ /*
179
+ * This is a GNU extension.
180
+ * Dunno how to handle errors here.
181
+ */
182
+ if (!lw_vasprintf (&msg, fmt, ap))
183
+ {
184
+ va_end (ap);
185
+ return;
186
+ }
187
+ fprintf(stderr, "%s\n", msg);
188
+ free(msg);
189
+ exit(1);
190
+ }
191
+
192
+
193
+ /*
194
+ * This function should be called from lwgeom_init_allocators() by programs
195
+ * which wish to use the default allocators above
196
+ */
197
+
198
+ void lwgeom_install_default_allocators(void)
199
+ {
200
+ lwalloc_var = default_allocator;
201
+ lwrealloc_var = default_reallocator;
202
+ lwfree_var = default_freeor;
203
+ lwerror_var = default_errorreporter;
204
+ lwnotice_var = default_noticereporter;
205
+ }
206
+
207
+
208
+ const char *
209
+ lwgeom_typename(int type)
210
+ {
211
+ /* something went wrong somewhere */
212
+ if ( type < 0 || type > 15 ) {
213
+ /* assert(0); */
214
+ return "Invalid type";
215
+ }
216
+ return lwgeomTypeName[type];
217
+ }
218
+
219
+ void *
220
+ lwalloc(size_t size)
221
+ {
222
+ void *mem = lwalloc_var(size);
223
+ LWDEBUGF(5, "lwalloc: %d@%p", size, mem);
224
+ return mem;
225
+ }
226
+
227
+ void *
228
+ lwrealloc(void *mem, size_t size)
229
+ {
230
+ LWDEBUGF(5, "lwrealloc: %d@%p", size, mem);
231
+ return lwrealloc_var(mem, size);
232
+ }
233
+
234
+ void
235
+ lwfree(void *mem)
236
+ {
237
+ lwfree_var(mem);
238
+ }
239
+
240
+ /*
241
+ * Removes trailing zeros and dot for a %f formatted number.
242
+ * Modifies input.
243
+ */
244
+ void
245
+ trim_trailing_zeros(char *str)
246
+ {
247
+ char *ptr, *totrim=NULL;
248
+ int len;
249
+ int i;
250
+
251
+ LWDEBUGF(3, "input: %s", str);
252
+
253
+ ptr = strchr(str, '.');
254
+ if ( ! ptr ) return; /* no dot, no decimal digits */
255
+
256
+ LWDEBUGF(3, "ptr: %s", ptr);
257
+
258
+ len = strlen(ptr);
259
+ for (i=len-1; i; i--)
260
+ {
261
+ if ( ptr[i] != '0' ) break;
262
+ totrim=&ptr[i];
263
+ }
264
+ if ( totrim )
265
+ {
266
+ if ( ptr == totrim-1 ) *ptr = '\0';
267
+ else *totrim = '\0';
268
+ }
269
+
270
+ LWDEBUGF(3, "output: %s", str);
271
+ }
272
+
273
+
274
+ /*
275
+ * Returns a new string which contains a maximum of maxlength characters starting
276
+ * from startpos and finishing at endpos (0-based indexing). If the string is
277
+ * truncated then the first or last characters are replaced by "..." as
278
+ * appropriate.
279
+ *
280
+ * The caller should specify start or end truncation by setting the truncdirection
281
+ * parameter as follows:
282
+ * 0 - start truncation (i.e. characters are removed from the beginning)
283
+ * 1 - end trunctation (i.e. characters are removed from the end)
284
+ */
285
+
286
+ char *lwmessage_truncate(char *str, int startpos, int endpos, int maxlength, int truncdirection)
287
+ {
288
+ char *output;
289
+ char *outstart;
290
+
291
+ /* Allocate space for new string */
292
+ output = lwalloc(maxlength + 4);
293
+ output[0] = '\0';
294
+
295
+ /* Start truncation */
296
+ if (truncdirection == 0)
297
+ {
298
+ /* Calculate the start position */
299
+ if (endpos - startpos < maxlength)
300
+ {
301
+ outstart = str + startpos;
302
+ strncat(output, outstart, endpos - startpos + 1);
303
+ }
304
+ else
305
+ {
306
+ if (maxlength >= 3)
307
+ {
308
+ /* Add "..." prefix */
309
+ outstart = str + endpos + 1 - maxlength + 3;
310
+ strncat(output, "...", 3);
311
+ strncat(output, outstart, maxlength - 3);
312
+ }
313
+ else
314
+ {
315
+ /* maxlength is too small; just output "..." */
316
+ strncat(output, "...", 3);
317
+ }
318
+ }
319
+ }
320
+
321
+ /* End truncation */
322
+ if (truncdirection == 1)
323
+ {
324
+ /* Calculate the end position */
325
+ if (endpos - startpos < maxlength)
326
+ {
327
+ outstart = str + startpos;
328
+ strncat(output, outstart, endpos - startpos + 1);
329
+ }
330
+ else
331
+ {
332
+ if (maxlength >= 3)
333
+ {
334
+ /* Add "..." suffix */
335
+ outstart = str + startpos;
336
+ strncat(output, outstart, maxlength - 3);
337
+ strncat(output, "...", 3);
338
+ }
339
+ else
340
+ {
341
+ /* maxlength is too small; just output "..." */
342
+ strncat(output, "...", 3);
343
+ }
344
+ }
345
+ }
346
+
347
+ return output;
348
+ }
349
+
350
+
351
+ char
352
+ getMachineEndian(void)
353
+ {
354
+ static int endian_check_int = 1; /* dont modify this!!! */
355
+
356
+ return *((char *) &endian_check_int); /* 0 = big endian | xdr,
357
+ * 1 = little endian | ndr
358
+ */
359
+ }
360
+
361
+
362
+ void
363
+ errorIfSRIDMismatch(int srid1, int srid2)
364
+ {
365
+ if ( srid1 != srid2 )
366
+ {
367
+ lwerror("Operation on mixed SRID geometries");
368
+ }
369
+ }
@@ -0,0 +1,861 @@
1
+ /**********************************************************************
2
+ * $Id: measures.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 <math.h>
14
+ #include <string.h>
15
+
16
+ #include "liblwgeom.h"
17
+
18
+
19
+ /*
20
+ * pt_in_ring_2d(): crossing number test for a point in a polygon
21
+ * input: p = a point,
22
+ * pa = vertex points of a ring V[n+1] with V[n]=V[0]
23
+ * returns: 0 = outside, 1 = inside
24
+ *
25
+ * Our polygons have first and last point the same,
26
+ *
27
+ */
28
+ int pt_in_ring_2d(POINT2D *p, POINTARRAY *ring)
29
+ {
30
+ int cn = 0; /* the crossing number counter */
31
+ int i;
32
+ POINT2D v1, v2;
33
+
34
+ #if INTEGRITY_CHECKS
35
+ POINT2D first, last;
36
+
37
+ getPoint2d_p(ring, 0, &first);
38
+ getPoint2d_p(ring, ring->npoints-1, &last);
39
+ if ( memcmp(&first, &last, sizeof(POINT2D)) )
40
+ {
41
+ lwerror("pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)",
42
+ first.x, first.y, last.x, last.y);
43
+
44
+ }
45
+ #endif
46
+
47
+ LWDEBUGF(2, "pt_in_ring_2d called with point: %g %g", p->x, p->y);
48
+ /* printPA(ring); */
49
+
50
+ /* loop through all edges of the polygon */
51
+ getPoint2d_p(ring, 0, &v1);
52
+ for (i=0; i<ring->npoints-1; i++)
53
+ {
54
+ double vt;
55
+ getPoint2d_p(ring, i+1, &v2);
56
+
57
+ /* edge from vertex i to vertex i+1 */
58
+ if
59
+ (
60
+ /* an upward crossing */
61
+ ((v1.y <= p->y) && (v2.y > p->y))
62
+ /* a downward crossing */
63
+ || ((v1.y > p->y) && (v2.y <= p->y))
64
+ )
65
+ {
66
+
67
+ vt = (double)(p->y - v1.y) / (v2.y - v1.y);
68
+
69
+ /* P.x <intersect */
70
+ if (p->x < v1.x + vt * (v2.x - v1.x))
71
+ {
72
+ /* a valid crossing of y=p.y right of p.x */
73
+ ++cn;
74
+ }
75
+ }
76
+ v1 = v2;
77
+ }
78
+
79
+ LWDEBUGF(3, "pt_in_ring_2d returning %d", cn&1);
80
+
81
+ return (cn&1); /* 0 if even (out), and 1 if odd (in) */
82
+ }
83
+
84
+ double distance2d_pt_pt(POINT2D *p1, POINT2D *p2)
85
+ {
86
+ double hside = p2->x - p1->x;
87
+ double vside = p2->y - p1->y;
88
+
89
+ return sqrt ( hside*hside + vside*vside );
90
+
91
+ /* the above is more readable
92
+ return sqrt(
93
+ (p2->x-p1->x) * (p2->x-p1->x) + (p2->y-p1->y) * (p2->y-p1->y)
94
+ ); */
95
+ }
96
+
97
+ /*distance2d from p to line A->B */
98
+ double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B)
99
+ {
100
+ double r,s;
101
+
102
+ /*if start==end, then use pt distance */
103
+ if ( ( A->x == B->x) && (A->y == B->y) )
104
+ return distance2d_pt_pt(p,A);
105
+
106
+ /*
107
+ * otherwise, we use comp.graphics.algorithms
108
+ * Frequently Asked Questions method
109
+ *
110
+ * (1) AC dot AB
111
+ * r = ---------
112
+ * ||AB||^2
113
+ * r has the following meaning:
114
+ * r=0 P = A
115
+ * r=1 P = B
116
+ * r<0 P is on the backward extension of AB
117
+ * r>1 P is on the forward extension of AB
118
+ * 0<r<1 P is interior to AB
119
+ */
120
+
121
+ 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) );
122
+
123
+ if (r<0) return distance2d_pt_pt(p,A);
124
+ if (r>1) return distance2d_pt_pt(p,B);
125
+
126
+
127
+ /*
128
+ * (2)
129
+ * (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
130
+ * s = -----------------------------
131
+ * L^2
132
+ *
133
+ * Then the distance from C to P = |s|*L.
134
+ *
135
+ */
136
+
137
+ s = ( (A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) ) /
138
+ ( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
139
+
140
+ return LW_ABS(s) * sqrt(
141
+ (B->x-A->x)*(B->x-A->x) + (B->y-A->y)*(B->y-A->y)
142
+ );
143
+ }
144
+
145
+ /* find the minimum 2d distance from AB to CD */
146
+ double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D)
147
+ {
148
+
149
+ double s_top, s_bot,s;
150
+ double r_top, r_bot,r;
151
+
152
+ LWDEBUGF(2, "distance2d_seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g]",
153
+ A->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y);
154
+
155
+
156
+ /*A and B are the same point */
157
+ if ( ( A->x == B->x) && (A->y == B->y) )
158
+ return distance2d_pt_seg(A,C,D);
159
+
160
+ /*U and V are the same point */
161
+
162
+ if ( ( C->x == D->x) && (C->y == D->y) )
163
+ return distance2d_pt_seg(D,A,B);
164
+
165
+ /* AB and CD are line segments */
166
+ /* from comp.graphics.algo
167
+
168
+ Solving the above for r and s yields
169
+ (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
170
+ r = ----------------------------- (eqn 1)
171
+ (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
172
+
173
+ (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
174
+ s = ----------------------------- (eqn 2)
175
+ (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
176
+ Let P be the position vector of the intersection point, then
177
+ P=A+r(B-A) or
178
+ Px=Ax+r(Bx-Ax)
179
+ Py=Ay+r(By-Ay)
180
+ By examining the values of r & s, you can also determine some other limiting conditions:
181
+ If 0<=r<=1 & 0<=s<=1, intersection exists
182
+ r<0 or r>1 or s<0 or s>1 line segments do not intersect
183
+ If the denominator in eqn 1 is zero, AB & CD are parallel
184
+ If the numerator in eqn 1 is also zero, AB & CD are collinear.
185
+
186
+ */
187
+ r_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ;
188
+ r_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x) ;
189
+
190
+ s_top = (A->y-C->y)*(B->x-A->x) - (A->x-C->x)*(B->y-A->y);
191
+ s_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x);
192
+
193
+ if ( (r_bot==0) || (s_bot == 0) )
194
+ {
195
+ return (
196
+ LW_MIN(distance2d_pt_seg(A,C,D),
197
+ LW_MIN(distance2d_pt_seg(B,C,D),
198
+ LW_MIN(distance2d_pt_seg(C,A,B),
199
+ distance2d_pt_seg(D,A,B))
200
+ )
201
+ )
202
+ );
203
+ }
204
+ s = s_top/s_bot;
205
+ r= r_top/r_bot;
206
+
207
+ if ((r<0) || (r>1) || (s<0) || (s>1) )
208
+ {
209
+ /*no intersection */
210
+ return (
211
+ LW_MIN(distance2d_pt_seg(A,C,D),
212
+ LW_MIN(distance2d_pt_seg(B,C,D),
213
+ LW_MIN(distance2d_pt_seg(C,A,B),
214
+ distance2d_pt_seg(D,A,B))
215
+ )
216
+ )
217
+ );
218
+
219
+ }
220
+ else
221
+ return -0; /*intersection exists */
222
+
223
+ }
224
+
225
+ /*
226
+ * search all the segments of pointarray to see which one is closest to p1
227
+ * Returns minimum distance between point and pointarray
228
+ */
229
+ double distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa)
230
+ {
231
+ double result = 0;
232
+ int t;
233
+ POINT2D start, end;
234
+
235
+ getPoint2d_p(pa, 0, &start);
236
+
237
+ for (t=1; t<pa->npoints; t++)
238
+ {
239
+ double dist;
240
+ getPoint2d_p(pa, t, &end);
241
+ dist = distance2d_pt_seg(p, &start, &end);
242
+ if (t==1) result = dist;
243
+ else result = LW_MIN(result, dist);
244
+
245
+ if ( result == 0 ) return 0;
246
+
247
+ start = end;
248
+ }
249
+
250
+ return result;
251
+ }
252
+
253
+ /* test each segment of l1 against each segment of l2. Return min */
254
+ double distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2)
255
+ {
256
+ double result = 99999999999.9;
257
+ char result_okay = 0; /*result is a valid min */
258
+ int t,u;
259
+ POINT2D start, end;
260
+ POINT2D start2, end2;
261
+
262
+ LWDEBUGF(2, "distance2d_ptarray_ptarray called (points: %d-%d)",
263
+ l1->npoints, l2->npoints);
264
+
265
+ getPoint2d_p(l1, 0, &start);
266
+ for (t=1; t<l1->npoints; t++) /*for each segment in L1 */
267
+ {
268
+ getPoint2d_p(l1, t, &end);
269
+
270
+ getPoint2d_p(l2, 0, &start2);
271
+ for (u=1; u<l2->npoints; u++) /*for each segment in L2 */
272
+ {
273
+ double dist;
274
+
275
+ getPoint2d_p(l2, u, &end2);
276
+
277
+ dist = distance2d_seg_seg(&start, &end, &start2, &end2);
278
+
279
+ LWDEBUGF(4, "line_line; seg %i * seg %i, dist = %g\n",t,u,dist);
280
+
281
+ if (result_okay)
282
+ result = LW_MIN(result,dist);
283
+ else
284
+ {
285
+ result_okay = 1;
286
+ result = dist;
287
+ }
288
+
289
+ LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f",
290
+ t, u, dist, result);
291
+
292
+ if (result <= 0) return 0; /*intersection */
293
+
294
+ start2 = end2;
295
+ }
296
+ start = end;
297
+ }
298
+
299
+ return result;
300
+ }
301
+
302
+ /* true if point is in poly (and not in its holes) */
303
+ int pt_in_poly_2d(POINT2D *p, LWPOLY *poly)
304
+ {
305
+ int i;
306
+
307
+ /* Not in outer ring */
308
+ if ( ! pt_in_ring_2d(p, poly->rings[0]) ) return 0;
309
+
310
+ /* Check holes */
311
+ for (i=1; i<poly->nrings; i++)
312
+ {
313
+ /* Inside a hole */
314
+ if ( pt_in_ring_2d(p, poly->rings[i]) ) return 0;
315
+ }
316
+
317
+ return 1; /* In outer ring, not in holes */
318
+ }
319
+
320
+ /*
321
+ * Brute force.
322
+ * Test line-ring distance against each ring.
323
+ * If there's an intersection (distance==0) then return 0 (crosses boundary).
324
+ * Otherwise, test to see if any point is inside outer rings of polygon,
325
+ * but not in inner rings.
326
+ * If so, return 0 (line inside polygon),
327
+ * otherwise return min distance to a ring (could be outside
328
+ * polygon or inside a hole)
329
+ */
330
+ double distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly)
331
+ {
332
+ POINT2D pt;
333
+ int i;
334
+ double mindist = 0;
335
+
336
+ LWDEBUGF(2, "distance2d_ptarray_poly called (%d rings)", poly->nrings);
337
+
338
+ for (i=0; i<poly->nrings; i++)
339
+ {
340
+ double dist = distance2d_ptarray_ptarray(pa, poly->rings[i]);
341
+ if (i) mindist = LW_MIN(mindist, dist);
342
+ else mindist = dist;
343
+
344
+ LWDEBUGF(3, " distance from ring %d: %f, mindist: %f",
345
+ i, dist, mindist);
346
+
347
+ if ( mindist <= 0 ) return 0.0; /* intersection */
348
+ }
349
+
350
+ /*
351
+ * No intersection, have to check if a point is
352
+ * inside polygon
353
+ */
354
+ getPoint2d_p(pa, 0, &pt);
355
+
356
+ /*
357
+ * Outside outer ring, so min distance to a ring
358
+ * is the actual min distance
359
+ */
360
+ if ( ! pt_in_ring_2d(&pt, poly->rings[0]) ) return mindist;
361
+
362
+
363
+ /*
364
+ * Its in the outer ring.
365
+ * Have to check if its inside a hole
366
+ */
367
+ for (i=1; i<poly->nrings; i++)
368
+ {
369
+ if ( pt_in_ring_2d(&pt, poly->rings[i]) )
370
+ {
371
+ /*
372
+ * Its inside a hole, then the actual
373
+ * distance is the min ring distance
374
+ */
375
+ return mindist;
376
+ }
377
+ }
378
+
379
+ return 0.0; /* Not in hole, so inside polygon */
380
+ }
381
+
382
+ double distance2d_point_point(LWPOINT *point1, LWPOINT *point2)
383
+ {
384
+ POINT2D p1;
385
+ POINT2D p2;
386
+
387
+ getPoint2d_p(point1->point, 0, &p1);
388
+ getPoint2d_p(point2->point, 0, &p2);
389
+
390
+ return distance2d_pt_pt(&p1, &p2);
391
+ }
392
+
393
+ double distance2d_point_line(LWPOINT *point, LWLINE *line)
394
+ {
395
+ POINT2D p;
396
+ POINTARRAY *pa = line->points;
397
+ getPoint2d_p(point->point, 0, &p);
398
+ return distance2d_pt_ptarray(&p, pa);
399
+ }
400
+
401
+ double distance2d_line_line(LWLINE *line1, LWLINE *line2)
402
+ {
403
+ POINTARRAY *pa1 = line1->points;
404
+ POINTARRAY *pa2 = line2->points;
405
+ return distance2d_ptarray_ptarray(pa1, pa2);
406
+ }
407
+
408
+ /*
409
+ * 1. see if pt in outer boundary. if no, then treat the outer ring like a line
410
+ * 2. if in the boundary, test to see if its in a hole.
411
+ * if so, then return dist to hole, else return 0 (point in polygon)
412
+ */
413
+ double distance2d_point_poly(LWPOINT *point, LWPOLY *poly)
414
+ {
415
+ POINT2D p;
416
+ int i;
417
+
418
+ getPoint2d_p(point->point, 0, &p);
419
+
420
+ LWDEBUG(2, "distance2d_point_poly called");
421
+
422
+ /* Return distance to outer ring if not inside it */
423
+ if ( ! pt_in_ring_2d(&p, poly->rings[0]) )
424
+ {
425
+ LWDEBUG(3, " not inside outer-ring");
426
+
427
+ return distance2d_pt_ptarray(&p, poly->rings[0]);
428
+ }
429
+
430
+ /*
431
+ * Inside the outer ring.
432
+ * Scan though each of the inner rings looking to
433
+ * see if its inside. If not, distance==0.
434
+ * Otherwise, distance = pt to ring distance
435
+ */
436
+ for (i=1; i<poly->nrings; i++)
437
+ {
438
+ /* Inside a hole. Distance = pt -> ring */
439
+ if ( pt_in_ring_2d(&p, poly->rings[i]) )
440
+ {
441
+ LWDEBUG(3, " inside an hole");
442
+
443
+ return distance2d_pt_ptarray(&p, poly->rings[i]);
444
+ }
445
+ }
446
+
447
+ LWDEBUG(3, " inside the polygon");
448
+
449
+ return 0.0; /* Is inside the polygon */
450
+ }
451
+
452
+ /*
453
+ * Brute force.
454
+ * Test to see if any rings intersect.
455
+ * If yes, dist=0.
456
+ * Test to see if one inside the other and if they are inside holes.
457
+ * Find min distance ring-to-ring.
458
+ */
459
+ double distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2)
460
+ {
461
+ POINT2D pt;
462
+ double mindist = -1;
463
+ int i;
464
+
465
+ LWDEBUG(2, "distance2d_poly_poly called");
466
+
467
+ /* if poly1 inside poly2 return 0 */
468
+ getPoint2d_p(poly1->rings[0], 0, &pt);
469
+ if ( pt_in_poly_2d(&pt, poly2) ) return 0.0;
470
+
471
+ /* if poly2 inside poly1 return 0 */
472
+ getPoint2d_p(poly2->rings[0], 0, &pt);
473
+ if ( pt_in_poly_2d(&pt, poly1) ) return 0.0;
474
+
475
+ LWDEBUG(3, " polys not inside each other");
476
+
477
+ /*
478
+ * foreach ring in Poly1
479
+ * foreach ring in Poly2
480
+ * if intersect, return 0
481
+ */
482
+ for (i=0; i<poly1->nrings; i++)
483
+ {
484
+ int j;
485
+ for (j=0; j<poly2->nrings; j++)
486
+ {
487
+ double d = distance2d_ptarray_ptarray(poly1->rings[i],
488
+ poly2->rings[j]);
489
+ if ( d <= 0 ) return 0.0;
490
+
491
+ /* mindist is -1 when not yet set */
492
+ if (mindist > -1) mindist = LW_MIN(mindist, d);
493
+ else mindist = d;
494
+
495
+ LWDEBUGF(3, " ring%i-%i dist: %f, mindist: %f", i, j, d, mindist);
496
+ }
497
+
498
+ }
499
+
500
+ /* otherwise return closest approach of rings (no intersection) */
501
+ return mindist;
502
+
503
+ }
504
+
505
+ double distance2d_line_poly(LWLINE *line, LWPOLY *poly)
506
+ {
507
+ return distance2d_ptarray_poly(line->points, poly);
508
+ }
509
+
510
+
511
+ /*find the 2d length of the given POINTARRAY (even if it's 3d) */
512
+ double lwgeom_pointarray_length2d(POINTARRAY *pts)
513
+ {
514
+ double dist = 0.0;
515
+ int i;
516
+ POINT2D frm;
517
+ POINT2D to;
518
+
519
+ if ( pts->npoints < 2 ) return 0.0;
520
+ for (i=0; i<pts->npoints-1;i++)
521
+ {
522
+ getPoint2d_p(pts, i, &frm);
523
+ getPoint2d_p(pts, i+1, &to);
524
+ dist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) ) +
525
+ ((frm.y - to.y)*(frm.y - to.y) ) );
526
+ }
527
+ return dist;
528
+ }
529
+
530
+ /*
531
+ * Find the 3d/2d length of the given POINTARRAY
532
+ * (depending on its dimensions)
533
+ */
534
+ double
535
+ lwgeom_pointarray_length(POINTARRAY *pts)
536
+ {
537
+ double dist = 0.0;
538
+ int i;
539
+ POINT3DZ frm;
540
+ POINT3DZ to;
541
+
542
+ if ( pts->npoints < 2 ) return 0.0;
543
+
544
+ /* compute 2d length if 3d is not available */
545
+ if ( ! TYPE_HASZ(pts->dims) ) return lwgeom_pointarray_length2d(pts);
546
+
547
+ for (i=0; i<pts->npoints-1;i++)
548
+ {
549
+ getPoint3dz_p(pts, i, &frm);
550
+ getPoint3dz_p(pts, i+1, &to);
551
+ dist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) ) +
552
+ ((frm.y - to.y)*(frm.y - to.y) ) +
553
+ ((frm.z - to.z)*(frm.z - to.z) ) );
554
+ }
555
+
556
+ return dist;
557
+ }
558
+
559
+ /*
560
+ * This should be rewritten to make use of the curve itself.
561
+ */
562
+ double
563
+ lwgeom_curvepolygon_area(LWCURVEPOLY *curvepoly)
564
+ {
565
+ LWPOLY *poly = (LWPOLY *)lwgeom_segmentize((LWGEOM *)curvepoly, 32);
566
+ return lwgeom_polygon_area(poly);
567
+ }
568
+
569
+ /*
570
+ * Find the area of the outer ring - sum (area of inner rings).
571
+ * Could use a more numerically stable calculator...
572
+ */
573
+ double
574
+ lwgeom_polygon_area(LWPOLY *poly)
575
+ {
576
+ double poly_area=0.0;
577
+ int i;
578
+ POINT2D p1;
579
+ POINT2D p2;
580
+
581
+ LWDEBUGF(2, "in lwgeom_polygon_area (%d rings)", poly->nrings);
582
+
583
+ for (i=0; i<poly->nrings; i++)
584
+ {
585
+ int j;
586
+ POINTARRAY *ring = poly->rings[i];
587
+ double ringarea = 0.0;
588
+
589
+ LWDEBUGF(4, " rings %d has %d points", i, ring->npoints);
590
+
591
+ for (j=0; j<ring->npoints-1; j++)
592
+ {
593
+ getPoint2d_p(ring, j, &p1);
594
+ getPoint2d_p(ring, j+1, &p2);
595
+ ringarea += ( p1.x * p2.y ) - ( p1.y * p2.x );
596
+ }
597
+
598
+ ringarea /= 2.0;
599
+
600
+ LWDEBUGF(4, " ring 1 has area %lf",ringarea);
601
+
602
+ ringarea = fabs(ringarea);
603
+ if (i != 0) /*outer */
604
+ ringarea = -1.0*ringarea ; /* its a hole */
605
+
606
+ poly_area += ringarea;
607
+ }
608
+
609
+ return poly_area;
610
+ }
611
+
612
+ /*
613
+ * Compute the sum of polygon rings length.
614
+ * Could use a more numerically stable calculator...
615
+ */
616
+ double lwgeom_polygon_perimeter(LWPOLY *poly)
617
+ {
618
+ double result=0.0;
619
+ int i;
620
+
621
+ LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
622
+
623
+ for (i=0; i<poly->nrings; i++)
624
+ result += lwgeom_pointarray_length(poly->rings[i]);
625
+
626
+ return result;
627
+ }
628
+
629
+ /*
630
+ * Compute the sum of polygon rings length (forcing 2d computation).
631
+ * Could use a more numerically stable calculator...
632
+ */
633
+ double lwgeom_polygon_perimeter2d(LWPOLY *poly)
634
+ {
635
+ double result=0.0;
636
+ int i;
637
+
638
+ LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
639
+
640
+ for (i=0; i<poly->nrings; i++)
641
+ result += lwgeom_pointarray_length2d(poly->rings[i]);
642
+
643
+ return result;
644
+ }
645
+
646
+ double
647
+ lwgeom_mindistance2d_recursive(uchar *lw1, uchar *lw2)
648
+ {
649
+ return lwgeom_mindistance2d_recursive_tolerance( lw1, lw2, 0.0 );
650
+ }
651
+
652
+ double
653
+ lwgeom_mindistance2d_recursive_tolerance(uchar *lw1, uchar *lw2, double tolerance)
654
+ {
655
+ LWGEOM_INSPECTED *in1, *in2;
656
+ int i, j;
657
+ double mindist = -1;
658
+
659
+ in1 = lwgeom_inspect(lw1);
660
+ in2 = lwgeom_inspect(lw2);
661
+
662
+ for (i=0; i<in1->ngeometries; i++)
663
+ {
664
+ uchar *g1 = lwgeom_getsubgeometry_inspected(in1, i);
665
+ int t1 = lwgeom_getType(g1[0]);
666
+ double dist=tolerance;
667
+
668
+ /* it's a multitype... recurse */
669
+ if ( lwgeom_contains_subgeoms(t1) )
670
+ {
671
+ dist = lwgeom_mindistance2d_recursive_tolerance(g1, lw2, tolerance);
672
+ if ( dist <= tolerance ) return tolerance; /* can't be closer */
673
+ if ( mindist == -1 ) mindist = dist;
674
+ else mindist = LW_MIN(dist, mindist);
675
+ continue;
676
+ }
677
+
678
+ for (j=0; j<in2->ngeometries; j++)
679
+ {
680
+ uchar *g2 = lwgeom_getsubgeometry_inspected(in2, j);
681
+ int t2 = lwgeom_getType(g2[0]);
682
+
683
+ if ( t1 == POINTTYPE )
684
+ {
685
+ if ( t2 == POINTTYPE )
686
+ {
687
+ dist = distance2d_point_point(
688
+ lwpoint_deserialize(g1),
689
+ lwpoint_deserialize(g2)
690
+ );
691
+ }
692
+ else if ( t2 == LINETYPE )
693
+ {
694
+ dist = distance2d_point_line(
695
+ lwpoint_deserialize(g1),
696
+ lwline_deserialize(g2)
697
+ );
698
+ }
699
+ else if ( t2 == POLYGONTYPE )
700
+ {
701
+ dist = distance2d_point_poly(
702
+ lwpoint_deserialize(g1),
703
+ lwpoly_deserialize(g2)
704
+ );
705
+ }
706
+ else
707
+ {
708
+ lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
709
+ }
710
+ }
711
+ else if ( t1 == LINETYPE )
712
+ {
713
+ if ( t2 == POINTTYPE )
714
+ {
715
+ dist = distance2d_point_line(
716
+ lwpoint_deserialize(g2),
717
+ lwline_deserialize(g1)
718
+ );
719
+ }
720
+ else if ( t2 == LINETYPE )
721
+ {
722
+ dist = distance2d_line_line(
723
+ lwline_deserialize(g1),
724
+ lwline_deserialize(g2)
725
+ );
726
+ }
727
+ else if ( t2 == POLYGONTYPE )
728
+ {
729
+ dist = distance2d_line_poly(
730
+ lwline_deserialize(g1),
731
+ lwpoly_deserialize(g2)
732
+ );
733
+ }
734
+ else
735
+ {
736
+ lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
737
+ }
738
+ }
739
+ else if ( t1 == POLYGONTYPE )
740
+ {
741
+ if ( t2 == POLYGONTYPE )
742
+ {
743
+ dist = distance2d_poly_poly(
744
+ lwpoly_deserialize(g2),
745
+ lwpoly_deserialize(g1)
746
+ );
747
+ }
748
+ else if ( t2 == POINTTYPE )
749
+ {
750
+ dist = distance2d_point_poly(
751
+ lwpoint_deserialize(g2),
752
+ lwpoly_deserialize(g1)
753
+ );
754
+ }
755
+ else if ( t2 == LINETYPE )
756
+ {
757
+ dist = distance2d_line_poly(
758
+ lwline_deserialize(g2),
759
+ lwpoly_deserialize(g1)
760
+ );
761
+ }
762
+ else
763
+ {
764
+ lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
765
+ }
766
+ }
767
+ else if (lwgeom_contains_subgeoms(t1)) /* it's a multitype... recurse */
768
+ {
769
+ dist = lwgeom_mindistance2d_recursive_tolerance(g1, g2, tolerance);
770
+ }
771
+ else
772
+ {
773
+ lwerror("Unsupported geometry type: %s", lwgeom_typename(t1));
774
+ }
775
+
776
+ if (mindist == -1 ) mindist = dist;
777
+ else mindist = LW_MIN(dist, mindist);
778
+
779
+ LWDEBUGF(3, "dist %d-%d: %f - mindist: %f",
780
+ i, j, dist, mindist);
781
+
782
+
783
+ if (mindist <= tolerance) return tolerance; /* can't be closer */
784
+
785
+ }
786
+
787
+ }
788
+
789
+ if (mindist<0) mindist = 0;
790
+
791
+ return mindist;
792
+ }
793
+
794
+
795
+
796
+ int
797
+ lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad)
798
+ {
799
+ POINT2D center;
800
+
801
+ center.x = cx;
802
+ center.y = cy;
803
+
804
+ if ( distance2d_pt_pt(p, &center) < rad ) return 1;
805
+ else return 0;
806
+
807
+ }
808
+
809
+ /*
810
+ * Compute the azimuth of segment AB in radians.
811
+ * Return 0 on exception (same point), 1 otherwise.
812
+ */
813
+ int
814
+ azimuth_pt_pt(POINT2D *A, POINT2D *B, double *d)
815
+ {
816
+ if ( A->x == B->x )
817
+ {
818
+ if ( A->y < B->y ) *d=0.0;
819
+ else if ( A->y > B->y ) *d=M_PI;
820
+ else return 0;
821
+ return 1;
822
+ }
823
+
824
+ if ( A->y == B->y )
825
+ {
826
+ if ( A->x < B->x ) *d=M_PI/2;
827
+ else if ( A->x > B->x ) *d=M_PI+(M_PI/2);
828
+ else return 0;
829
+ return 1;
830
+ }
831
+
832
+ if ( A->x < B->x )
833
+ {
834
+ if ( A->y < B->y )
835
+ {
836
+ *d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) );
837
+ }
838
+ else /* ( A->y > B->y ) - equality case handled above */
839
+ {
840
+ *d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )
841
+ + (M_PI/2);
842
+ }
843
+ }
844
+
845
+ else /* ( A->x > B->x ) - equality case handled above */
846
+ {
847
+ if ( A->y > B->y )
848
+ {
849
+ *d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) )
850
+ + M_PI;
851
+ }
852
+ else /* ( A->y < B->y ) - equality case handled above */
853
+ {
854
+ *d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )
855
+ + (M_PI+(M_PI/2));
856
+ }
857
+ }
858
+
859
+ return 1;
860
+ }
861
+