… | |
… | |
16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA. |
17 | * Boston, MA 02110-1301, USA. |
18 | */ |
18 | */ |
19 | #include <stdio.h> |
19 | #include <stdio.h> |
20 | #include <string.h> |
20 | #include <string.h> |
|
|
21 | #include <ctype.h> |
21 | #include "maptool.h" |
22 | #include "maptool.h" |
22 | |
23 | |
23 | struct boundary { |
|
|
24 | struct item_bin *ib; |
|
|
25 | GList *segments,*sorted_segments; |
|
|
26 | GList *children; |
|
|
27 | struct rect r; |
|
|
28 | }; |
|
|
29 | |
24 | |
30 | struct boundary_member { |
25 | char * |
31 | long long wayid; |
26 | osm_tag_value(struct item_bin *ib, char *key) |
32 | enum geom_poly_segment_type role; |
|
|
33 | struct boundary *boundary; |
|
|
34 | }; |
|
|
35 | |
|
|
36 | static guint |
|
|
37 | boundary_member_hash(gconstpointer key) |
|
|
38 | { |
27 | { |
39 | const struct boundary_member *memb=key; |
28 | char *tag=NULL; |
40 | return (memb->wayid >> 32)^(memb->wayid & 0xffffffff); |
29 | int len=strlen(key); |
|
|
30 | while ((tag=item_bin_get_attr(ib, attr_osm_tag, tag))) { |
|
|
31 | if (!strncmp(tag,key,len) && tag[len] == '=') |
|
|
32 | return tag+len+1; |
|
|
33 | } |
|
|
34 | return NULL; |
41 | } |
35 | } |
42 | |
|
|
43 | static gboolean |
|
|
44 | boundary_member_equal(gconstpointer a, gconstpointer b) |
|
|
45 | { |
|
|
46 | const struct boundary_member *memba=a; |
|
|
47 | const struct boundary_member *membb=b; |
|
|
48 | return (memba->wayid == membb->wayid); |
|
|
49 | } |
|
|
50 | |
|
|
51 | GHashTable *member_hash; |
|
|
52 | |
36 | |
53 | static char * |
37 | static char * |
54 | osm_tag_name(struct item_bin *ib) |
38 | osm_tag_name(struct item_bin *ib) |
55 | { |
39 | { |
56 | char *tag=NULL; |
40 | return osm_tag_value(ib, "name"); |
57 | while ((tag=item_bin_get_attr(ib, attr_osm_tag, tag))) { |
41 | } |
58 | if (!strncmp(tag,"name=",5)) |
42 | |
59 | return tag+5; |
43 | long long * |
60 | } |
44 | boundary_relid(struct boundary *b) |
|
|
45 | { |
|
|
46 | long long *id; |
|
|
47 | if (!b) |
|
|
48 | return 0; |
|
|
49 | if (!b->ib) |
|
|
50 | return 0; |
|
|
51 | id=item_bin_get_attr(b->ib, attr_osm_relationid, NULL); |
|
|
52 | if (id) |
|
|
53 | return *id; |
61 | return NULL; |
54 | return 0; |
|
|
55 | } |
|
|
56 | |
|
|
57 | static void |
|
|
58 | process_boundaries_member(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv) |
|
|
59 | { |
|
|
60 | struct boundary *b=relation_priv; |
|
|
61 | enum geom_poly_segment_type role=(long)member_priv; |
|
|
62 | b->segments=g_list_prepend(b->segments,item_bin_to_poly_segment(member, role)); |
62 | } |
63 | } |
63 | |
64 | |
64 | static GList * |
65 | static GList * |
65 | build_boundaries(FILE *boundaries) |
66 | process_boundaries_setup(FILE *boundaries, struct relations *relations) |
66 | { |
67 | { |
67 | struct item_bin *ib; |
68 | struct item_bin *ib; |
68 | GList *boundaries_list=NULL; |
69 | GList *boundaries_list=NULL; |
|
|
70 | struct relations_func *relations_func; |
69 | |
71 | |
|
|
72 | relations_func=relations_func_new(process_boundaries_member, NULL); |
70 | while ((ib=read_item(boundaries))) { |
73 | while ((ib=read_item(boundaries))) { |
71 | char *member=NULL; |
74 | char *member=NULL; |
72 | struct boundary *boundary=g_new0(struct boundary, 1); |
75 | struct boundary *boundary=g_new0(struct boundary, 1); |
|
|
76 | char *admin_level=osm_tag_value(ib, "admin_level"); |
|
|
77 | char *iso=osm_tag_value(ib, "ISO3166-1"); |
|
|
78 | /* disable spain for now since it creates a too large index */ |
|
|
79 | if (admin_level && !strcmp(admin_level, "2") && (!iso || strcasecmp(iso,"es"))) { |
|
|
80 | if (iso) { |
|
|
81 | struct country_table *country=country_from_iso2(iso); |
|
|
82 | if (!country) |
|
|
83 | osm_warning("relation",item_bin_get_relationid(ib),0,"Country Boundary contains unknown ISO3166-1 value '%s'\n",iso); |
|
|
84 | else { |
|
|
85 | boundary->iso2=g_strdup(iso); |
|
|
86 | osm_info("relation",item_bin_get_relationid(ib),0,"Country Boundary for '%s'\n",iso); |
|
|
87 | } |
|
|
88 | boundary->country=country; |
|
|
89 | } else |
|
|
90 | osm_warning("relation",item_bin_get_relationid(ib),0,"Country Boundary doesn't contain an ISO3166-1 tag\n"); |
|
|
91 | } |
73 | while ((member=item_bin_get_attr(ib, attr_osm_member, member))) { |
92 | while ((member=item_bin_get_attr(ib, attr_osm_member, member))) { |
74 | long long wayid; |
93 | long long wayid; |
75 | int read=0; |
94 | int read=0; |
76 | if (sscanf(member,"2:%Ld:%n",&wayid,&read) >= 1) { |
95 | if (sscanf(member,"2:%Ld:%n",&wayid,&read) >= 1) { |
77 | struct boundary_member *memb=g_new(struct boundary_member, 1); |
|
|
78 | char *role=member+read; |
96 | char *rolestr=member+read; |
79 | memb->wayid=wayid; |
97 | enum geom_poly_segment_type role; |
80 | memb->boundary=boundary; |
98 | if (!strcmp(rolestr,"outer") || !strcmp(rolestr,"exclave")) |
81 | if (!strcmp(role,"outer")) |
|
|
82 | memb->role=geom_poly_segment_type_way_outer; |
99 | role=geom_poly_segment_type_way_outer; |
83 | else if (!strcmp(role,"inner")) |
100 | else if (!strcmp(rolestr,"inner") || !strcmp(rolestr,"enclave")) |
84 | memb->role=geom_poly_segment_type_way_inner; |
101 | role=geom_poly_segment_type_way_inner; |
85 | else if (!strcmp(role,"")) |
102 | else if (!strcmp(rolestr,"")) |
86 | memb->role=geom_poly_segment_type_way_unknown; |
103 | role=geom_poly_segment_type_way_unknown; |
87 | else { |
104 | else { |
88 | printf("Unknown role %s\n",role); |
105 | osm_warning("relation",item_bin_get_relationid(ib),0,"Unknown role %s in member ",rolestr); |
|
|
106 | osm_warning("way",wayid,1,"\n"); |
89 | memb->role=geom_poly_segment_type_none; |
107 | role=geom_poly_segment_type_none; |
90 | } |
108 | } |
91 | g_hash_table_insert(member_hash, memb, g_list_append(g_hash_table_lookup(member_hash, memb), memb)); |
109 | relations_add_func(relations, relations_func, boundary, (gpointer)role, 2, wayid); |
92 | |
|
|
93 | } |
110 | } |
94 | } |
111 | } |
95 | boundary->ib=item_bin_dup(ib); |
112 | boundary->ib=item_bin_dup(ib); |
96 | boundaries_list=g_list_append(boundaries_list, boundary); |
113 | boundaries_list=g_list_append(boundaries_list, boundary); |
97 | } |
114 | } |
98 | return boundaries_list; |
115 | return boundaries_list; |
99 | } |
116 | } |
100 | |
117 | |
101 | static void |
118 | GList * |
102 | find_matches(GList *l, struct coord *c) |
119 | boundary_find_matches(GList *l, struct coord *c) |
103 | { |
120 | { |
|
|
121 | GList *ret=NULL; |
104 | while (l) { |
122 | while (l) { |
105 | struct boundary *boundary=l->data; |
123 | struct boundary *boundary=l->data; |
106 | if (bbox_contains_coord(&boundary->r, c)) { |
124 | if (bbox_contains_coord(&boundary->r, c)) { |
107 | struct item_bin *ib=boundary->ib; |
|
|
108 | if (geom_poly_segments_point_inside(boundary->sorted_segments,c)) |
125 | if (geom_poly_segments_point_inside(boundary->sorted_segments,c) > 0) |
109 | printf("%s,",osm_tag_name(ib)); |
126 | ret=g_list_prepend(ret, boundary); |
110 | find_matches(boundary->children, c); |
127 | ret=g_list_concat(ret,boundary_find_matches(boundary->children, c)); |
111 | } |
128 | } |
112 | l=g_list_next(l); |
129 | l=g_list_next(l); |
113 | } |
130 | } |
|
|
131 | return ret; |
114 | } |
132 | } |
115 | |
133 | |
116 | static void |
134 | static void |
117 | test(GList *boundaries_list) |
135 | test(GList *boundaries_list) |
118 | { |
136 | { |
… | |
… | |
121 | printf("start\n"); |
139 | printf("start\n"); |
122 | while ((ib=read_item(f))) { |
140 | while ((ib=read_item(f))) { |
123 | struct coord *c=(struct coord *)(ib+1); |
141 | struct coord *c=(struct coord *)(ib+1); |
124 | char *name=item_bin_get_attr(ib, attr_town_name, NULL); |
142 | char *name=item_bin_get_attr(ib, attr_town_name, NULL); |
125 | printf("%s:",name); |
143 | printf("%s:",name); |
126 | find_matches(boundaries_list, c); |
144 | boundary_find_matches(boundaries_list, c); |
127 | printf("\n"); |
145 | printf("\n"); |
128 | } |
146 | } |
129 | fclose(f); |
147 | fclose(f); |
130 | printf("end\n"); |
148 | printf("end\n"); |
131 | } |
149 | } |
… | |
… | |
136 | char *newprefix=g_alloca(sizeof(char)*(strlen(prefix)+2)); |
154 | char *newprefix=g_alloca(sizeof(char)*(strlen(prefix)+2)); |
137 | strcpy(newprefix, prefix); |
155 | strcpy(newprefix, prefix); |
138 | strcat(newprefix," "); |
156 | strcat(newprefix," "); |
139 | while (l) { |
157 | while (l) { |
140 | struct boundary *boundary=l->data; |
158 | struct boundary *boundary=l->data; |
141 | printf("%s:%s\n",prefix,osm_tag_name(boundary->ib)); |
159 | fprintf(stderr,"%s:%s (0x%x,0x%x)-(0x%x,0x%x)\n",prefix,osm_tag_name(boundary->ib),boundary->r.l.x,boundary->r.l.y,boundary->r.h.x,boundary->r.h.y); |
142 | dump_hierarchy(boundary->children, newprefix); |
160 | dump_hierarchy(boundary->children, newprefix); |
143 | l=g_list_next(l); |
161 | l=g_list_next(l); |
144 | } |
162 | } |
145 | } |
163 | } |
146 | |
164 | |
… | |
… | |
156 | if (areaa < areab) |
174 | if (areaa < areab) |
157 | return -1; |
175 | return -1; |
158 | return 0; |
176 | return 0; |
159 | } |
177 | } |
160 | |
178 | |
161 | int |
179 | static GList * |
162 | process_boundaries(FILE *boundaries, FILE *ways) |
180 | process_boundaries_insert(GList *list, struct boundary *boundary) |
163 | { |
181 | { |
164 | struct item_bin *ib; |
182 | GList *l=list; |
165 | GList *boundaries_list,*l,*sl,*l2,*ln; |
|
|
166 | |
|
|
167 | member_hash=g_hash_table_new_full(boundary_member_hash, boundary_member_equal, NULL, NULL); |
|
|
168 | boundaries_list=build_boundaries(boundaries); |
|
|
169 | while ((ib=read_item(ways))) { |
|
|
170 | long long *wayid=item_bin_get_attr(ib, attr_osm_wayid, NULL); |
|
|
171 | if (wayid) { |
|
|
172 | GList *l=g_hash_table_lookup(member_hash, wayid); |
|
|
173 | while (l) { |
183 | while (l) { |
174 | struct boundary_member *memb=l->data; |
184 | struct boundary *b=l->data; |
175 | memb->boundary->segments=g_list_prepend(memb->boundary->segments,item_bin_to_poly_segment(ib, memb->role)); |
185 | if (bbox_contains_bbox(&boundary->r, &b->r)) { |
176 | |
186 | list=g_list_remove(list, b); |
|
|
187 | boundary->children=g_list_prepend(boundary->children, b); |
|
|
188 | l=list; |
|
|
189 | } else if (bbox_contains_bbox(&b->r, &boundary->r)) { |
|
|
190 | b->children=process_boundaries_insert(b->children, boundary); |
|
|
191 | return list; |
|
|
192 | } else |
177 | l=g_list_next(l); |
193 | l=g_list_next(l); |
178 | } |
|
|
179 | } |
194 | } |
180 | } |
195 | return g_list_prepend(list, boundary); |
|
|
196 | } |
|
|
197 | |
|
|
198 | |
|
|
199 | static GList * |
|
|
200 | process_boundaries_finish(GList *boundaries_list) |
|
|
201 | { |
|
|
202 | GList *l,*sl,*l2,*ln; |
|
|
203 | GList *ret=NULL; |
181 | l=boundaries_list; |
204 | l=boundaries_list; |
|
|
205 | char *f1_name=NULL; |
|
|
206 | char *f2_name=NULL; |
182 | while (l) { |
207 | while (l) |
|
|
208 | { |
183 | struct boundary *boundary=l->data; |
209 | struct boundary *boundary=l->data; |
184 | int first=1; |
210 | int first=1; |
|
|
211 | FILE *f=NULL,*fu=NULL; |
|
|
212 | |
|
|
213 | // only lowercase country code |
|
|
214 | if (boundary->iso2) |
|
|
215 | { |
|
|
216 | int i99; |
|
|
217 | for (i99 = 0; boundary->iso2[i99]; i99++) |
|
|
218 | { |
|
|
219 | boundary->iso2[i99] = tolower(boundary->iso2[i99]); |
|
|
220 | } |
|
|
221 | } |
|
|
222 | // only lowercase country code |
|
|
223 | |
|
|
224 | if (boundary->country) { |
|
|
225 | char *name=g_strdup_printf("country_%s_poly",boundary->iso2); |
|
|
226 | f1_name=g_strdup_printf("country_%s_poly",boundary->iso2); |
|
|
227 | f=tempfile("",name,1); |
|
|
228 | g_free(name); |
|
|
229 | } |
185 | boundary->sorted_segments=geom_poly_segments_sort(boundary->segments, geom_poly_segment_type_way_right_side); |
230 | boundary->sorted_segments=geom_poly_segments_sort(boundary->segments, geom_poly_segment_type_way_right_side); |
186 | sl=boundary->sorted_segments; |
231 | sl=boundary->sorted_segments; |
187 | while (sl) { |
232 | while (sl) |
|
|
233 | { |
188 | struct geom_poly_segment *gs=sl->data; |
234 | struct geom_poly_segment *gs=sl->data; |
189 | struct coord *c=gs->first; |
235 | struct coord *c=gs->first; |
190 | while (c <= gs->last) { |
236 | while (c <= gs->last) { |
191 | if (first) { |
237 | if (first) { |
192 | boundary->r.l=*c; |
238 | boundary->r.l=*c; |
… | |
… | |
194 | first=0; |
240 | first=0; |
195 | } else |
241 | } else |
196 | bbox_extend(c, &boundary->r); |
242 | bbox_extend(c, &boundary->r); |
197 | c++; |
243 | c++; |
198 | } |
244 | } |
|
|
245 | if (f) { |
|
|
246 | struct item_bin *ib=item_bin; |
|
|
247 | item_bin_init(ib, type_selected_line); |
|
|
248 | item_bin_add_coord(ib, gs->first, gs->last-gs->first+1); |
|
|
249 | item_bin_write(ib, f); |
|
|
250 | } |
|
|
251 | if (boundary->country) { |
|
|
252 | if (!coord_is_equal(*gs->first,*gs->last)) { |
|
|
253 | if (!fu) { |
|
|
254 | char *name=g_strdup_printf("country_%s_broken",boundary->iso2); |
|
|
255 | f2_name=g_strdup_printf("country_%s_broken",boundary->iso2); |
|
|
256 | fu=tempfile("",name,1); |
|
|
257 | g_free(name); |
|
|
258 | } |
|
|
259 | struct item_bin *ib=item_bin; |
|
|
260 | item_bin_init(ib, type_selected_point); |
|
|
261 | item_bin_add_coord(ib, gs->first, 1); |
|
|
262 | item_bin_write(ib, fu); |
|
|
263 | |
|
|
264 | item_bin_init(ib, type_selected_point); |
|
|
265 | item_bin_add_coord(ib, gs->last, 1); |
|
|
266 | item_bin_write(ib, fu); |
|
|
267 | } |
|
|
268 | } |
199 | sl=g_list_next(sl); |
269 | sl=g_list_next(sl); |
|
|
270 | |
|
|
271 | if (f2_name) |
|
|
272 | { |
|
|
273 | tempfile_unlink("",f2_name); |
|
|
274 | g_free(f2_name); |
|
|
275 | f2_name=NULL; |
|
|
276 | } |
200 | } |
277 | } |
|
|
278 | ret=process_boundaries_insert(ret, boundary); |
201 | l=g_list_next(l); |
279 | l=g_list_next(l); |
|
|
280 | if (f) |
|
|
281 | fclose(f); |
|
|
282 | if (fu) { |
|
|
283 | if (boundary->country) |
|
|
284 | osm_warning("relation",item_bin_get_relationid(boundary->ib),0,"Broken country polygon '%s'\n",boundary->iso2); |
|
|
285 | fclose(fu); |
202 | |
286 | } |
|
|
287 | |
|
|
288 | if (f1_name) |
|
|
289 | { |
|
|
290 | tempfile_unlink("",f1_name); |
|
|
291 | g_free(f1_name); |
|
|
292 | f1_name=NULL; |
203 | } |
293 | } |
|
|
294 | } |
|
|
295 | #if 0 |
204 | printf("hierarchy\n"); |
296 | printf("hierarchy\n"); |
|
|
297 | #endif |
205 | boundaries_list=g_list_sort(boundaries_list, boundary_bbox_compare); |
298 | boundaries_list=g_list_sort(boundaries_list, boundary_bbox_compare); |
206 | l=boundaries_list; |
299 | l=boundaries_list; |
207 | while (l) { |
300 | while (l) { |
208 | struct boundary *boundary=l->data; |
301 | struct boundary *boundary=l->data; |
209 | ln=l2=g_list_next(l); |
302 | ln=l2=g_list_next(l); |
210 | while (l2) { |
303 | while (l2) { |
211 | struct boundary *boundary2=l2->data; |
304 | struct boundary *boundary2=l2->data; |
212 | if (bbox_contains_bbox(&boundary2->r, &boundary->r)) { |
305 | if (bbox_contains_bbox(&boundary2->r, &boundary->r)) { |
213 | boundaries_list=g_list_remove(boundaries_list, boundary); |
306 | boundaries_list=g_list_remove(boundaries_list, boundary); |
214 | boundary2->children=g_list_append(boundary2->children, boundary); |
307 | boundary2->children=g_list_append(boundary2->children, boundary); |
|
|
308 | #if 0 |
215 | printf("found\n"); |
309 | printf("found\n"); |
|
|
310 | #endif |
216 | break; |
311 | break; |
217 | } |
312 | } |
218 | l2=g_list_next(l2); |
313 | l2=g_list_next(l2); |
219 | } |
314 | } |
220 | l=ln; |
315 | l=ln; |
221 | } |
316 | } |
|
|
317 | // dump_hierarchy(boundaries_list,""); --> make much data!! be careful |
|
|
318 | #if 0 |
222 | printf("hierarchy done\n"); |
319 | printf("hierarchy done\n"); |
223 | dump_hierarchy(boundaries_list,""); |
|
|
224 | printf("test\n"); |
320 | printf("test\n"); |
225 | test(boundaries_list); |
321 | test(boundaries_list); |
226 | return 1; |
322 | #endif |
|
|
323 | return boundaries_list; |
227 | } |
324 | } |
|
|
325 | |
|
|
326 | GList * |
|
|
327 | process_boundaries(FILE *boundaries, FILE *ways) |
|
|
328 | { |
|
|
329 | GList *boundaries_list; |
|
|
330 | struct relations *relations=relations_new(); |
|
|
331 | |
|
|
332 | boundaries_list=process_boundaries_setup(boundaries, relations); |
|
|
333 | relations_process(relations, NULL, ways, NULL); |
|
|
334 | return process_boundaries_finish(boundaries_list); |
|
|
335 | } |
|
|
336 | |
|
|
337 | |