… | |
… | |
15 | * along with this program; if not, write to the |
15 | * along with this program; if not, write to the |
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 <string.h> |
19 | #include <string.h> |
|
|
20 | #include <math.h> |
20 | #include "maptool.h" |
21 | #include "maptool.h" |
21 | |
22 | |
22 | void |
23 | void |
23 | geom_coord_copy(struct coord *from, struct coord *to, int count, int reverse) |
24 | geom_coord_copy(struct coord *from, struct coord *to, int count, int reverse) |
24 | { |
25 | { |
… | |
… | |
30 | from+=count; |
31 | from+=count; |
31 | for (i = 0 ; i < count ; i++) |
32 | for (i = 0 ; i < count ; i++) |
32 | *to++=*--from; |
33 | *to++=*--from; |
33 | } |
34 | } |
34 | |
35 | |
|
|
36 | /** |
|
|
37 | * Get coordinates of polyline middle point. |
|
|
38 | * @param in *p array of poly vertex coordinates |
|
|
39 | * @param in count count of poly vertexes |
|
|
40 | * @param out *c coordinates of middle point |
|
|
41 | * @returns number of first vertex of segment containing middle point |
|
|
42 | */ |
|
|
43 | int |
|
|
44 | geom_line_middle(struct coord *p, int count, struct coord *c) |
|
|
45 | { |
|
|
46 | double length=0,half=0,len=0; |
|
|
47 | int i; |
|
|
48 | |
|
|
49 | if(count==1) { |
|
|
50 | *c=*p; |
|
|
51 | return 0; |
|
|
52 | } |
|
|
53 | |
|
|
54 | for (i=0; i<count-1; i++) { |
|
|
55 | length+=sqrt(sq(p[i].x-p[i+1].x)+sq(p[i].y-p[i+1].y)); |
|
|
56 | } |
|
|
57 | |
|
|
58 | length/=2; |
|
|
59 | for (i=0; (i<count-1) && (half<length); i++) { |
|
|
60 | len=sqrt(sq(p[i].x-p[i+1].x)+sq(p[i].y-p[i+1].y)); |
|
|
61 | half+=len; |
|
|
62 | } |
|
|
63 | if (i > 0) { |
|
|
64 | i--; |
|
|
65 | half-=length; |
|
|
66 | if (len) { |
|
|
67 | c->x=(p[i].x*half+p[i+1].x*(len-half))/len; |
|
|
68 | c->y=(p[i].y*half+p[i+1].y*(len-half))/len; |
|
|
69 | } else |
|
|
70 | *c=p[i]; |
|
|
71 | } else |
|
|
72 | *c=p[0]; |
|
|
73 | return i; |
|
|
74 | } |
|
|
75 | |
|
|
76 | |
35 | void |
77 | void |
36 | geom_coord_revert(struct coord *c, int count) |
78 | geom_coord_revert(struct coord *c, int count) |
37 | { |
79 | { |
38 | struct coord tmp; |
80 | struct coord tmp; |
39 | int i; |
81 | int i; |
… | |
… | |
58 | if (++j == count) |
100 | if (++j == count) |
59 | j=0; |
101 | j=0; |
60 | #if 0 |
102 | #if 0 |
61 | fprintf(stderr,"(%d+%d)*(%d-%d)=%d*%d="LONGLONG_FMT"\n",c[i].x,c[j].x,c[i].y,c[j].y,c[i].x+c[j].x,c[i].y-c[j].y,(long long)(c[i].x+c[j].x)*(c[i].y-c[j].y)); |
103 | fprintf(stderr,"(%d+%d)*(%d-%d)=%d*%d="LONGLONG_FMT"\n",c[i].x,c[j].x,c[i].y,c[j].y,c[i].x+c[j].x,c[i].y-c[j].y,(long long)(c[i].x+c[j].x)*(c[i].y-c[j].y)); |
62 | #endif |
104 | #endif |
63 | area+=(long long)(c[i].x+c[j].x)*(c[i].y-c[j].y); |
105 | area+=(long long)(c[i].x+c[j].x)*(c[i].y-c[j].y); |
64 | #if 0 |
106 | #if 0 |
65 | fprintf(stderr,"area="LONGLONG_FMT"\n",area); |
107 | fprintf(stderr,"area="LONGLONG_FMT"\n",area); |
66 | #endif |
108 | #endif |
67 | } |
109 | } |
68 | return area/2; |
110 | return area/2; |
69 | } |
111 | } |
|
|
112 | |
|
|
113 | /** |
|
|
114 | * Get poly centroid coordinates. |
|
|
115 | * @param in *p array of poly vertex coordinates |
|
|
116 | * @param in count count of poly vertexes |
|
|
117 | * @param out *c coordinates of poly centroid |
|
|
118 | * @returns 1 on success, 0 if poly area is 0 |
|
|
119 | */ |
|
|
120 | int |
|
|
121 | geom_poly_centroid(struct coord *p, int count, struct coord *c) |
|
|
122 | { |
|
|
123 | long long area=0; |
|
|
124 | long long sx=0,sy=0,tmp; |
|
|
125 | int i,j; |
|
|
126 | long long x0=p[0].x, y0=p[0].y, xi, yi, xj, yj; |
|
|
127 | |
|
|
128 | /*fprintf(stderr,"area="LONGLONG_FMT"\n", area );*/ |
|
|
129 | for (i=0,j=0; i<count; i++) { |
|
|
130 | if (++j == count) |
|
|
131 | j=0; |
|
|
132 | xi=p[i].x-x0; |
|
|
133 | yi=p[i].y-y0; |
|
|
134 | xj=p[j].x-x0; |
|
|
135 | yj=p[j].y-y0; |
|
|
136 | tmp=(xi*yj-xj*yi); |
|
|
137 | sx+=(xi+xj)*tmp; |
|
|
138 | sy+=(yi+yj)*tmp; |
|
|
139 | area+=xi*yj-xj*yi; |
|
|
140 | } |
|
|
141 | if(area!=0) { |
|
|
142 | c->x=x0+sx/3/area; |
|
|
143 | c->y=y0+sy/3/area; |
|
|
144 | return 1; |
|
|
145 | } |
|
|
146 | return 0; |
|
|
147 | } |
|
|
148 | |
|
|
149 | /** |
|
|
150 | * Get coordinates of polyline point c most close to given point p. |
|
|
151 | * @param in *pl array of polyline vertex coordinates |
|
|
152 | * @param in count count of polyline vertexes |
|
|
153 | * @param in *p point coordinates |
|
|
154 | * @param out *c coordinates of polyline point most close to given point. |
|
|
155 | * @returns first vertex number of polyline segment to which c belongs |
|
|
156 | */ |
|
|
157 | int |
|
|
158 | geom_poly_closest_point(struct coord *pl, int count, struct coord *p, struct coord *c) |
|
|
159 | { |
|
|
160 | int i,vertex=0; |
|
|
161 | long long x, y, xi, xj, yi, yj, u, d, dmin=0; |
|
|
162 | if(count<2) { |
|
|
163 | c->x=pl->x; |
|
|
164 | c->y=pl->y; |
|
|
165 | return 0; |
|
|
166 | } |
|
|
167 | for(i=0;i<count-1;i++) { |
|
|
168 | xi=pl[i].x; |
|
|
169 | yi=pl[i].y; |
|
|
170 | xj=pl[i+1].x; |
|
|
171 | yj=pl[i+1].y; |
|
|
172 | u=(xj-xi)*(xj-xi)+(yj-yi)*(yj-yi); |
|
|
173 | if(u!=0) { |
|
|
174 | u=((p->x-xi)*(xj-xi)+(p->y-yi)*(yj-yi))*1000/u; |
|
|
175 | } |
|
|
176 | if(u<0) |
|
|
177 | u=0; |
|
|
178 | else if (u>1000) |
|
|
179 | u=1000; |
|
|
180 | x=xi+u*(xj-xi)/1000; |
|
|
181 | y=yi+u*(yj-yi)/1000; |
|
|
182 | d=(p->x-x)*(p->x-x)+(p->y-y)*(p->y-y); |
|
|
183 | if(i==0 || d<dmin) { |
|
|
184 | dmin=d; |
|
|
185 | c->x=x; |
|
|
186 | c->y=y; |
|
|
187 | vertex=i; |
|
|
188 | } |
|
|
189 | } |
|
|
190 | return vertex; |
|
|
191 | } |
|
|
192 | |
|
|
193 | /** |
|
|
194 | * Check if point is inside polgone. |
|
|
195 | * @param in *cp array of polygon vertex coordinates |
|
|
196 | * @param in count count of polygon vertexes |
|
|
197 | * @param in *c point coordinates |
|
|
198 | * @returns 1 - inside, 0 - outside |
|
|
199 | */ |
|
|
200 | int |
|
|
201 | geom_poly_point_inside(struct coord *cp, int count, struct coord *c) |
|
|
202 | { |
|
|
203 | int ret=0; |
|
|
204 | struct coord *last=cp+count-1; |
|
|
205 | while (cp < last) { |
|
|
206 | if ((cp[0].y > c->y) != (cp[1].y > c->y) && |
|
|
207 | c->x < ((long long)cp[1].x-cp[0].x)*(c->y-cp[0].y)/(cp[1].y-cp[0].y)+cp[0].x) { |
|
|
208 | #if 0 |
|
|
209 | fprintf(stderr," cross 0x%x,0x%x-0x%x,0x%x %dx%d",cp,cp[0].x,cp[0].y,cp[1].x,cp[1].y,cp[1].x-cp[0].x,c->y-cp[0].y); |
|
|
210 | printf("type=selected_line\n"); |
|
|
211 | coord_print(projection_mg, &cp[0], stdout); |
|
|
212 | coord_print(projection_mg, &cp[1], stdout); |
|
|
213 | #endif |
|
|
214 | ret=!ret; |
|
|
215 | } |
|
|
216 | cp++; |
|
|
217 | } |
|
|
218 | return ret; |
|
|
219 | } |
|
|
220 | |
|
|
221 | |
70 | |
222 | |
71 | GList * |
223 | GList * |
72 | geom_poly_segments_insert(GList *list, struct geom_poly_segment *first, struct geom_poly_segment *second, struct geom_poly_segment *third) |
224 | geom_poly_segments_insert(GList *list, struct geom_poly_segment *first, struct geom_poly_segment *second, struct geom_poly_segment *third) |
73 | { |
225 | { |
74 | int count; |
226 | int count; |
… | |
… | |
141 | geom_poly_segment_compatible(struct geom_poly_segment *s1, struct geom_poly_segment *s2, int dir) |
293 | geom_poly_segment_compatible(struct geom_poly_segment *s1, struct geom_poly_segment *s2, int dir) |
142 | { |
294 | { |
143 | int same=0,opposite=0; |
295 | int same=0,opposite=0; |
144 | if (s1->type == geom_poly_segment_type_none || s2->type == geom_poly_segment_type_none) |
296 | if (s1->type == geom_poly_segment_type_none || s2->type == geom_poly_segment_type_none) |
145 | return 0; |
297 | return 0; |
146 | if (s1->type == s2->type) |
298 | if (s1->type == s2->type) { |
147 | same=1; |
299 | same=1; |
148 | if (s1->type == geom_poly_segment_type_way_inner && s2->type == geom_poly_segment_type_way_outer) |
300 | if (s1->type == geom_poly_segment_type_way_inner || s1->type == geom_poly_segment_type_way_outer) { |
149 | opposite=1; |
301 | opposite=1; |
150 | if (s1->type == geom_poly_segment_type_way_outer && s2->type == geom_poly_segment_type_way_inner) |
302 | } |
151 | opposite=1; |
303 | } |
152 | if (s1->type == geom_poly_segment_type_way_left_side && s2->type == geom_poly_segment_type_way_right_side) |
304 | if (s1->type == geom_poly_segment_type_way_left_side && s2->type == geom_poly_segment_type_way_right_side) |
153 | opposite=1; |
305 | opposite=1; |
154 | if (s1->type == geom_poly_segment_type_way_right_side && s2->type == geom_poly_segment_type_way_left_side) |
306 | if (s1->type == geom_poly_segment_type_way_right_side && s2->type == geom_poly_segment_type_way_left_side) |
155 | opposite=1; |
307 | opposite=1; |
156 | if (s1->type == geom_poly_segment_type_way_unknown || s2->type == geom_poly_segment_type_way_unknown) { |
308 | if (s1->type == geom_poly_segment_type_way_unknown || s2->type == geom_poly_segment_type_way_unknown) { |
… | |
… | |
206 | } |
358 | } |
207 | |
359 | |
208 | int |
360 | int |
209 | geom_poly_segments_point_inside(GList *in, struct coord *c) |
361 | geom_poly_segments_point_inside(GList *in, struct coord *c) |
210 | { |
362 | { |
211 | int ret=0; |
363 | int open_matches=0,closed_matches=0; |
212 | struct coord *cp; |
364 | struct coord *cp; |
|
|
365 | #if 0 |
|
|
366 | fprintf(stderr,"try 0x%x,0x%x:",c->x,c->y); |
|
|
367 | #endif |
213 | while (in) { |
368 | while (in) { |
214 | struct geom_poly_segment *seg=in->data; |
369 | struct geom_poly_segment *seg=in->data; |
215 | cp=seg->first; |
370 | cp=seg->first; |
216 | while (cp < seg->last) { |
371 | if (geom_poly_point_inside(seg->first, seg->last-seg->first+1, c)) { |
217 | if ((cp[0].y > c->y) != (cp[1].y > c->y) && |
372 | #if 0 |
218 | c->x < (cp[1].x-cp[0].x)*(c->y-cp[0].y)/(cp[1].y-cp[0].y)+cp[0].x) |
373 | fprintf(stderr," inside"); |
219 | ret=!ret; |
374 | #endif |
220 | cp++; |
375 | if (coord_is_equal(*seg->first,*seg->last)) |
|
|
376 | closed_matches++; |
|
|
377 | else |
|
|
378 | open_matches++; |
|
|
379 | } else { |
|
|
380 | #if 0 |
|
|
381 | fprintf(stderr," outside"); |
|
|
382 | #endif |
221 | } |
383 | } |
222 | in=g_list_next(in); |
384 | in=g_list_next(in); |
223 | } |
385 | } |
|
|
386 | #if 0 |
|
|
387 | fprintf(stderr,"\n"); |
|
|
388 | fprintf(stderr,"open_matches %d closed_matches %d\n",open_matches,closed_matches); |
|
|
389 | #endif |
|
|
390 | if (closed_matches) { |
|
|
391 | if (closed_matches & 1) |
|
|
392 | return 1; |
|
|
393 | else |
|
|
394 | return 0; |
|
|
395 | } |
|
|
396 | if (open_matches) { |
|
|
397 | if (open_matches & 1) |
|
|
398 | return -1; |
|
|
399 | else |
|
|
400 | return 0; |
|
|
401 | } |
224 | return ret; |
402 | return 0; |
225 | } |
403 | } |
226 | |
404 | |
227 | struct geom_poly_segment * |
405 | struct geom_poly_segment * |
228 | item_bin_to_poly_segment(struct item_bin *ib, int type) |
406 | item_bin_to_poly_segment(struct item_bin *ib, int type) |
229 | { |
407 | { |