1 /**********************************************************************
2  *
3  * rttopo - topology library
4  * http://git.osgeo.org/gitea/rttopo/librttopo
5  *
6  * rttopo is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * rttopo is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with rttopo.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
22  *
23  **********************************************************************/
24 
25 
26 
27 #include "rttopo_config.h"
28 #include <ctype.h>
29 
30 #include "librttopo_geom_internal.h"
31 
32 /* Structure for the type array */
33 struct geomtype_struct
34 {
35   char *typename;
36   int type;
37   int z;
38   int m;
39 };
40 
41 /* Type array. Note that the order of this array is important in
42    that any typename in the list must *NOT* occur within an entry
43    before it. Otherwise if we search for "POINT" at the top of the
44    list we would also match MULTIPOINT, for example. */
45 
46 struct geomtype_struct geomtype_struct_array[] =
47 {
48   { "GEOMETRYCOLLECTIONZM", RTCOLLECTIONTYPE, 1, 1 },
49   { "GEOMETRYCOLLECTIONZ", RTCOLLECTIONTYPE, 1, 0 },
50   { "GEOMETRYCOLLECTIONM", RTCOLLECTIONTYPE, 0, 1 },
51   { "GEOMETRYCOLLECTION", RTCOLLECTIONTYPE, 0, 0 },
52 
53   { "GEOMETRYZM", 0, 1, 1 },
54   { "GEOMETRYZ", 0, 1, 0 },
55   { "GEOMETRYM", 0, 0, 1 },
56   { "GEOMETRY", 0, 0, 0 },
57 
58   { "POLYHEDRALSURFACEZM", RTPOLYHEDRALSURFACETYPE, 1, 1 },
59   { "POLYHEDRALSURFACEZ", RTPOLYHEDRALSURFACETYPE, 1, 0 },
60   { "POLYHEDRALSURFACEM", RTPOLYHEDRALSURFACETYPE, 0, 1 },
61   { "POLYHEDRALSURFACE", RTPOLYHEDRALSURFACETYPE, 0, 0 },
62 
63   { "TINZM", RTTINTYPE, 1, 1 },
64   { "TINZ", RTTINTYPE, 1, 0 },
65   { "TINM", RTTINTYPE, 0, 1 },
66   { "TIN", RTTINTYPE, 0, 0 },
67 
68   { "CIRCULARSTRINGZM", RTCIRCSTRINGTYPE, 1, 1 },
69   { "CIRCULARSTRINGZ", RTCIRCSTRINGTYPE, 1, 0 },
70   { "CIRCULARSTRINGM", RTCIRCSTRINGTYPE, 0, 1 },
71   { "CIRCULARSTRING", RTCIRCSTRINGTYPE, 0, 0 },
72 
73   { "COMPOUNDCURVEZM", RTCOMPOUNDTYPE, 1, 1 },
74   { "COMPOUNDCURVEZ", RTCOMPOUNDTYPE, 1, 0 },
75   { "COMPOUNDCURVEM", RTCOMPOUNDTYPE, 0, 1 },
76   { "COMPOUNDCURVE", RTCOMPOUNDTYPE, 0, 0 },
77 
78   { "CURVEPOLYGONZM", RTCURVEPOLYTYPE, 1, 1 },
79   { "CURVEPOLYGONZ", RTCURVEPOLYTYPE, 1, 0 },
80   { "CURVEPOLYGONM", RTCURVEPOLYTYPE, 0, 1 },
81   { "CURVEPOLYGON", RTCURVEPOLYTYPE, 0, 0 },
82 
83   { "MULTICURVEZM", RTMULTICURVETYPE, 1, 1 },
84   { "MULTICURVEZ", RTMULTICURVETYPE, 1, 0 },
85   { "MULTICURVEM", RTMULTICURVETYPE, 0, 1 },
86   { "MULTICURVE", RTMULTICURVETYPE, 0, 0 },
87 
88   { "MULTISURFACEZM", RTMULTISURFACETYPE, 1, 1 },
89   { "MULTISURFACEZ", RTMULTISURFACETYPE, 1, 0 },
90   { "MULTISURFACEM", RTMULTISURFACETYPE, 0, 1 },
91   { "MULTISURFACE", RTMULTISURFACETYPE, 0, 0 },
92 
93   { "MULTILINESTRINGZM", RTMULTILINETYPE, 1, 1 },
94   { "MULTILINESTRINGZ", RTMULTILINETYPE, 1, 0 },
95   { "MULTILINESTRINGM", RTMULTILINETYPE, 0, 1 },
96   { "MULTILINESTRING", RTMULTILINETYPE, 0, 0 },
97 
98   { "MULTIPOLYGONZM", RTMULTIPOLYGONTYPE, 1, 1 },
99   { "MULTIPOLYGONZ", RTMULTIPOLYGONTYPE, 1, 0 },
100   { "MULTIPOLYGONM", RTMULTIPOLYGONTYPE, 0, 1 },
101   { "MULTIPOLYGON", RTMULTIPOLYGONTYPE, 0, 0 },
102 
103   { "MULTIPOINTZM", RTMULTIPOINTTYPE, 1, 1 },
104   { "MULTIPOINTZ", RTMULTIPOINTTYPE, 1, 0 },
105   { "MULTIPOINTM", RTMULTIPOINTTYPE, 0, 1 },
106   { "MULTIPOINT", RTMULTIPOINTTYPE, 0, 0 },
107 
108   { "LINESTRINGZM", RTLINETYPE, 1, 1 },
109   { "LINESTRINGZ", RTLINETYPE, 1, 0 },
110   { "LINESTRINGM", RTLINETYPE, 0, 1 },
111   { "LINESTRING", RTLINETYPE, 0, 0 },
112 
113   { "TRIANGLEZM", RTTRIANGLETYPE, 1, 1 },
114   { "TRIANGLEZ", RTTRIANGLETYPE, 1, 0 },
115   { "TRIANGLEM", RTTRIANGLETYPE, 0, 1 },
116   { "TRIANGLE", RTTRIANGLETYPE, 0, 0 },
117 
118   { "POLYGONZM", RTPOLYGONTYPE, 1, 1 },
119   { "POLYGONZ", RTPOLYGONTYPE, 1, 0 },
120   { "POLYGONM", RTPOLYGONTYPE, 0, 1 },
121   { "POLYGON", RTPOLYGONTYPE, 0, 0 },
122 
123   { "POINTZM", RTPOINTTYPE, 1, 1 },
124   { "POINTZ", RTPOINTTYPE, 1, 0 },
125   { "POINTM", RTPOINTTYPE, 0, 1 },
126   { "POINT", RTPOINTTYPE, 0, 0 }
127 
128 };
129 #define GEOMTYPE_STRUCT_ARRAY_LEN (sizeof geomtype_struct_array/sizeof(struct geomtype_struct))
130 
131 /*
132 * We use a very simple upper case mapper here, because the system toupper() function
133 * is locale dependent and may have trouble mapping lower case strings to the upper
134 * case ones we expect (see, the "Turkisk I", http://www.i18nguy.com/unicode/turkish-i18n.html)
135 * We could also count on PgSQL sending us *lower* case inputs, as it seems to do that
136 * regardless of the case the user provides for the type arguments.
137 */
138 const char dumb_upper_map[128] = "................................................0123456789.......ABCDEFGHIJKLMNOPQRSTUVWXYZ......ABCDEFGHIJKLMNOPQRSTUVWXYZ.....";
139 
dump_toupper(const RTCTX * ctx,int in)140 static char dump_toupper(const RTCTX *ctx, int in)
141 {
142   if ( in < 0 || in > 127 )
143     return '.';
144   return dumb_upper_map[in];
145 }
146 
gflags(const RTCTX * ctx,int hasz,int hasm,int geodetic)147 uint8_t gflags(const RTCTX *ctx, int hasz, int hasm, int geodetic)
148 {
149   uint8_t flags = 0;
150   if ( hasz )
151     RTFLAGS_SET_Z(flags, 1);
152   if ( hasm )
153     RTFLAGS_SET_M(flags, 1);
154   if ( geodetic )
155     RTFLAGS_SET_GEODETIC(flags, 1);
156   return flags;
157 }
158 
159 /**
160 * Calculate type integer and dimensional flags from string input.
161 * Case insensitive, and insensitive to spaces at front and back.
162 * Type == 0 in the case of the string "GEOMETRY" or "GEOGRAPHY".
163 * Return RT_SUCCESS for success.
164 */
geometry_type_from_string(const RTCTX * ctx,const char * str,uint8_t * type,int * z,int * m)165 int geometry_type_from_string(const RTCTX *ctx, const char *str, uint8_t *type, int *z, int *m)
166 {
167   char *tmpstr;
168   int tmpstartpos, tmpendpos;
169   int i;
170 
171   assert(str);
172   assert(type);
173   assert(z);
174   assert(m);
175 
176   /* Initialize. */
177   *type = 0;
178   *z = 0;
179   *m = 0;
180 
181   /* Locate any leading/trailing spaces */
182   tmpstartpos = 0;
183   for (i = 0; i < strlen(str); i++)
184   {
185     if (str[i] != ' ')
186     {
187       tmpstartpos = i;
188       break;
189     }
190   }
191 
192   tmpendpos = strlen(str) - 1;
193   for (i = strlen(str) - 1; i >= 0; i--)
194   {
195     if (str[i] != ' ')
196     {
197       tmpendpos = i;
198       break;
199     }
200   }
201 
202   /* Copy and convert to upper case for comparison */
203   tmpstr = rtalloc(ctx, tmpendpos - tmpstartpos + 2);
204   for (i = tmpstartpos; i <= tmpendpos; i++)
205     tmpstr[i - tmpstartpos] = dump_toupper(ctx, str[i]);
206 
207   /* Add NULL to terminate */
208   tmpstr[i - tmpstartpos] = '\0';
209 
210   /* Now check for the type */
211   for (i = 0; i < GEOMTYPE_STRUCT_ARRAY_LEN; i++)
212   {
213     if (!strcmp(tmpstr, geomtype_struct_array[i].typename))
214     {
215       *type = geomtype_struct_array[i].type;
216       *z = geomtype_struct_array[i].z;
217       *m = geomtype_struct_array[i].m;
218 
219       rtfree(ctx, tmpstr);
220 
221       return RT_SUCCESS;
222     }
223 
224   }
225 
226   rtfree(ctx, tmpstr);
227 
228   return RT_FAILURE;
229 }
230 
231 
232 
233 
234