summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--navit/attr.c7
-rw-r--r--navit/attr.h136
-rw-r--r--navit/attr_def.h1
-rw-r--r--navit/graphics.c404
-rw-r--r--navit/graphics.h2
-rw-r--r--navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c73
-rw-r--r--navit/graphics/qt5/graphics_qt5.cpp41
-rw-r--r--navit/graphics/win32/graphics_win32.c63
-rw-r--r--navit/item.h42
-rw-r--r--navit/layout.h129
-rw-r--r--navit/maptool/maptool.c59
-rw-r--r--navit/maptool/maptool.h172
-rw-r--r--navit/maptool/misc.c12
-rw-r--r--navit/maptool/osm.c639
14 files changed, 1420 insertions, 360 deletions
diff --git a/navit/attr.c b/navit/attr.c
index 478c44fd4..78e2a683c 100644
--- a/navit/attr.c
+++ b/navit/attr.c
@@ -43,6 +43,7 @@
#include "util.h"
#include "types.h"
#include "xmlconfig.h"
+#include "layout.h"
struct attr_name {
enum attr_type attr;
@@ -471,6 +472,9 @@ char *attr_to_text_ext(struct attr *attr, char *sep, enum attr_format fmt, enum
if (type == attr_nav_status) {
return nav_status_to_text(attr->u.num);
}
+ if (type == attr_poly_hole) {
+ return g_strdup_printf("count=%d", attr->u.poly_hole->coord_count);
+ }
return g_strdup_printf("(no text[%s])", attr_to_name(type));
}
@@ -770,6 +774,9 @@ int attr_data_size(struct attr *attr) {
while (attr->u.attr_types[i++] != attr_none);
return i*sizeof(enum attr_type);
}
+ if (attr->type == attr_poly_hole) {
+ return (sizeof(attr->u.poly_hole->coord_count) + (attr->u.poly_hole->coord_count * sizeof(*attr->u.poly_hole->coord)));
+ }
dbg(lvl_error,"size for %s unknown", attr_to_name(attr->type));
return 0;
}
diff --git a/navit/attr.h b/navit/attr.h
index f8aa8dd4a..a9e4d9467 100644
--- a/navit/attr.h
+++ b/navit/attr.h
@@ -35,8 +35,8 @@ enum attr_type {
#define ATTR2(x,y) attr_##y=x,
#define ATTR(x) attr_##x,
-/* Special macro for unused attribute types. Creates a placeholder entry
- * in the enum so the following values do not change. */
+ /* Special macro for unused attribute types. Creates a placeholder entry
+ * in the enum so the following values do not change. */
#define ATTR_UNUSED ATTR_UNUSED_L(__LINE__)
#define ATTR_UNUSED_L(x) ATTR_UNUSED_WITH_LINE_NUMBER(x)
#define ATTR_UNUSED_WITH_LINE_NUMBER(x) ATTR_UNUSED_##x,
@@ -52,8 +52,8 @@ enum attr_type {
};
enum attr_format {
- attr_format_default=0,
- attr_format_with_units=1,
+ attr_format_default=0,
+ attr_format_with_units=1,
};
#define AF_ONEWAY (1<<0)
@@ -120,19 +120,19 @@ enum attr_format {
/** Indicates whether a position is valid **/
enum attr_position_valid {
- attr_position_valid_invalid, /**< The position is invalid and should be discarded. **/
- attr_position_valid_static, /**< The position is valid but the vehicle is not moving, or moving very slowly.
+ attr_position_valid_invalid, /**< The position is invalid and should be discarded. **/
+ attr_position_valid_static, /**< The position is valid but the vehicle is not moving, or moving very slowly.
Calculations that involve the difference between two consecutive positions,
such as bearing, may therefore be inaccurate. **/
- attr_position_valid_extrapolated_time, /**< FIXME: this description is just my (mvglasow) guess; this value is not used anywhere as of r5957.
+ attr_position_valid_extrapolated_time, /**< FIXME: this description is just my (mvglasow) guess; this value is not used anywhere as of r5957.
The position is the vehicle's last known position, and the consumer of the
information should be aware that the vehicle may have moved since. **/
- attr_position_valid_extrapolated_spatial, /**< FIXME: this description is just my (mvglasow) guess; this value is not used anywhere as of r5957.
+ attr_position_valid_extrapolated_spatial, /**< FIXME: this description is just my (mvglasow) guess; this value is not used anywhere as of r5957.
The position is a prediction of the vehicle's current position, based on
its last known position, the time elapsed since it was obtained and possibly
other factors. This would be used for positions obtained through inertial
navigation. **/
- attr_position_valid_valid, /**< The position is valid and can be used for all purposes. **/
+ attr_position_valid_valid, /**< The position is valid and can be used for all purposes. **/
};
#define ATTR_IS_INT(x) ((x) >= attr_type_int_begin && (x) <= attr_type_int_end)
@@ -151,66 +151,67 @@ enum attr_position_valid {
#define ATTR_OBJECT(x,y) ((struct attr){attr_##x,{.navit=y}})
struct range {
- short min, max;
+ short min, max;
};
struct attr {
- enum attr_type type;
- union {
- char *str;
- void *data;
- long num;
- struct item *item;
- enum item_type item_type;
- enum projection projection;
- double * numd;
- struct color *color;
- struct coord_geo *coord_geo;
- struct navit *navit;
- struct callback *callback;
- struct callback_list *callback_list;
- struct vehicle *vehicle;
- struct layout *layout;
- struct layer *layer;
- struct map *map;
- struct mapset *mapset;
- struct log *log;
- struct route *route;
- struct navigation *navigation;
- struct coord *coord;
- struct pcoord *pcoord;
- struct gui *gui;
- struct graphics *graphics;
- struct tracking *tracking;
- struct itemgra *itemgra;
- struct plugin *plugin;
- struct plugins *plugins;
- struct polygon *polygon;
- struct polyline *polyline;
- struct circle *circle;
- struct text *text;
- struct icon *icon;
- struct image *image;
- struct arrows *arrows;
- struct element *element;
- struct speech *speech;
- struct cursor *cursor;
- struct displaylist *displaylist;
- struct transformation *transformation;
- struct vehicleprofile *vehicleprofile;
- struct roadprofile *roadprofile;
- struct bookmarks *bookmarks;
- struct config *config;
- struct osd *osd;
- struct range range;
- struct navit_object *navit_object;
- struct traffic *traffic;
- int *dash;
- enum item_type *item_types;
- enum attr_type *attr_types;
- long long *num64;
- struct attr *attrs;
- } u;
+ enum attr_type type;
+ union {
+ char *str;
+ void *data;
+ long num;
+ struct item *item;
+ enum item_type item_type;
+ enum projection projection;
+ double * numd;
+ struct color *color;
+ struct coord_geo *coord_geo;
+ struct navit *navit;
+ struct callback *callback;
+ struct callback_list *callback_list;
+ struct vehicle *vehicle;
+ struct layout *layout;
+ struct layer *layer;
+ struct map *map;
+ struct mapset *mapset;
+ struct log *log;
+ struct route *route;
+ struct navigation *navigation;
+ struct coord *coord;
+ struct pcoord *pcoord;
+ struct gui *gui;
+ struct graphics *graphics;
+ struct tracking *tracking;
+ struct itemgra *itemgra;
+ struct plugin *plugin;
+ struct plugins *plugins;
+ struct polygon *polygon;
+ struct polyline *polyline;
+ struct circle *circle;
+ struct text *text;
+ struct icon *icon;
+ struct image *image;
+ struct arrows *arrows;
+ struct element *element;
+ struct speech *speech;
+ struct cursor *cursor;
+ struct displaylist *displaylist;
+ struct transformation *transformation;
+ struct vehicleprofile *vehicleprofile;
+ struct roadprofile *roadprofile;
+ struct bookmarks *bookmarks;
+ struct config *config;
+ struct osd *osd;
+ struct range range;
+ struct navit_object *navit_object;
+ struct traffic *traffic;
+ int *dash;
+ enum item_type *item_types;
+ enum attr_type *attr_types;
+ long long *num64;
+ struct attr *attrs;
+ struct poly_hole *poly_hole;
+ } u;
};
struct attr_iter;
@@ -223,7 +224,8 @@ struct attr *attr_new_from_text(const char *name, const char *value);
char *attr_to_text_ext(struct attr *attr, char *sep, enum attr_format fmt, enum attr_format def_fmt, struct map *map);
char *attr_to_text(struct attr *attr, struct map *map, int pretty);
struct attr *attr_search(struct attr **attrs, struct attr *last, enum attr_type attr);
-int attr_generic_get_attr(struct attr **attrs, struct attr **def_attrs, enum attr_type type, struct attr *attr, struct attr_iter *iter);
+int attr_generic_get_attr(struct attr **attrs, struct attr **def_attrs, enum attr_type type, struct attr *attr,
+ struct attr_iter *iter);
struct attr **attr_generic_set_attr(struct attr **attrs, struct attr *attr);
struct attr **attr_generic_add_attr(struct attr **attrs, struct attr *attr);
struct attr **attr_generic_add_attr_list(struct attr **attrs, struct attr **add);
diff --git a/navit/attr_def.h b/navit/attr_def.h
index 055936b4a..5a82d9d30 100644
--- a/navit/attr_def.h
+++ b/navit/attr_def.h
@@ -416,6 +416,7 @@ ATTR(ch_edge)
ATTR(zipfile_ref_block)
ATTR(item_id)
ATTR(pdl_gps_update)
+ATTR(poly_hole)
ATTR2(0x0004ffff,type_special_end)
ATTR2(0x00050000,type_double_begin)
ATTR(position_height)
diff --git a/navit/graphics.c b/navit/graphics.c
index 40e04bb06..172315488 100644
--- a/navit/graphics.c
+++ b/navit/graphics.c
@@ -1099,6 +1099,47 @@ static void graphics_draw_polygon(struct graphics *gra, struct graphics_gc *gc,
}
}
+/**
+ * @brief Draw a plain polygon with holes on the display
+ *
+ * @param gra The graphics instance on which to draw
+ * @param gc The graphics context
+ * @param[in] pin An array of points forming the polygon
+ * @param count_in The number of elements inside @p pin
+ * @param hole_count The number of hole polygons to cut out
+ * @param pcount array of [hole_count] integers giving the number of
+ * points per hole
+ * @param holes array of point arrays for the hole polygons
+ */
+static void graphics_draw_polygon_with_holes(struct graphics *gra, struct graphics_gc *gc, struct point *pin,
+ int count_in, int hole_count, int* ccount, struct point **holes) {
+ if (! gra->meth.draw_polygon_with_holes) {
+ /* TODO: add attr to configure if polygons with holes should be drawn without
+ * the holes if no graphics support for this is present.
+ */
+ graphics_draw_polygon(gra, gc, pin, count_in);
+ return;
+ } else {
+ struct point * pin_scaled = g_alloca(sizeof (struct point)*count_in);
+ struct point ** holes_scaled = g_alloca(sizeof (struct point *)*hole_count);
+ int a;
+ int b;
+ /* scale the outline */
+ for(a=0; a < count_in; a ++)
+ pin_scaled[a] = graphics_dpi_scale_point(gra,&(pin[a]));
+ /*scale the holes */
+ for(b=0; b < hole_count; b ++) {
+ holes_scaled[b] = g_malloc(sizeof(*(holes_scaled[b])) * ccount[b]);
+ for(a=0; a < ccount[b]; a ++)
+ holes_scaled[b][a] = graphics_dpi_scale_point(gra,&(holes[b][a]));
+ }
+ gra->meth.draw_polygon_with_holes(gra->priv, gc->priv, pin_scaled, count_in, hole_count, ccount, holes_scaled);
+ /* free the hole arrays */
+ for(b=0; b < hole_count; b ++)
+ g_free(holes_scaled[b]);
+ }
+}
+
void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc *gc, struct point *plu, int w, int h,
int r, int fill) {
struct point *p=g_alloca(sizeof(struct point)*(r*4+32));
@@ -1304,16 +1345,26 @@ int graphics_hide_native_keyboard (struct graphics *this_, struct graphics_keybo
#include "popup.h"
#include <stdio.h>
+struct displayitem_poly_holes {
+ int count;
+ int *ccount;
+ struct coord ** coords;
+};
+
/**
- * FIXME
- * @param <>
- * @returns <>
- * @author Martin Schaller (04/2008)
+ * @brief graphics display item structure
+ *
+ * The graphics item passes the ap items and other items with this structure
+ * to the graphics drawing routines. The struct is only a stub. It is allocated
+ * including "count -1" struct coord's following c[0], if "holes" not NULL, by a
+ * polygon hole structure, and if label != NULL, a series of zero terminated
+ * strings followed by another zero for label.
*/
struct displayitem {
struct displayitem *next;
struct item item;
char *label;
+ struct displayitem_poly_holes * holes;
int z_order;
int count;
struct coord c[0];
@@ -1339,6 +1390,35 @@ static void xdisplay_free(struct displaylist *dl) {
}
/**
+ * @brief add the holes structure into preallocated area after displayitem
+ *
+ * @param item to extract holes from
+ * @param hole_count precounted number of holes
+ * @param p changeable pointer to buffer. Advanced by the size used
+ * @returns pointer to newly created holes structure
+ */
+static inline struct displayitem_poly_holes * display_add_holes(struct item *item,int hole_count, char ** p) {
+ struct attr attr;
+ struct displayitem_poly_holes* holes;
+ holes=(struct displayitem_poly_holes *) *p;
+ *p+=sizeof(*holes);
+ holes->count=0;
+ holes->ccount = (int *) *p;
+ *p+=hole_count * sizeof(int);
+ holes->coords = (struct coord **)*p;
+ *p+=hole_count * sizeof(struct coord *);
+ item_attr_rewind(item);
+ while(item_attr_get(item, attr_poly_hole, &attr)) {
+ holes->coords[holes->count] = (struct coord *)*p;
+ holes->ccount[holes->count] = attr.u.poly_hole->coord_count;
+ memcpy(holes->coords[holes->count], attr.u.poly_hole->coord, holes->ccount[holes->count] * sizeof(struct coord));
+ *p += holes->ccount[holes->count] * sizeof(struct coord);
+ holes->count ++;
+ }
+ return holes;
+}
+
+/**
* FIXME
* @param <>
* @returns <>
@@ -1349,8 +1429,15 @@ static void display_add(struct hash_entry *entry, struct item *item, int count,
struct displayitem *di;
int len,i;
char *p;
+ struct attr attr;
+ int hole_count=0;
+ int hole_total_coords=0;
+ int holes_length;
+ /* calculate number of bytes required */
+ /* own length */
len=sizeof(*di)+count*sizeof(*c);
+ /* add length of lables including closing zero */
if (label && label_count) {
for (i = 0 ; i < label_count ; i++) {
if (label[i])
@@ -1359,12 +1446,28 @@ static void display_add(struct hash_entry *entry, struct item *item, int count,
len++;
}
}
+ /* add length for holes */
+ item_attr_rewind(item);
+ while(item_attr_get(item, attr_poly_hole, &attr)) {
+ hole_count ++;
+ hole_total_coords += attr.u.poly_hole->coord_count;
+ }
+ holes_length = sizeof(struct displayitem_poly_holes) + hole_count * sizeof(int) + hole_count * sizeof(
+ struct coord *) + hole_total_coords * sizeof(struct coord);
+ if(hole_count > 0)
+ dbg(lvl_debug,"got %d holes with %d coords total", hole_count, hole_total_coords);
+ len += holes_length;
+
p=g_malloc(len);
di=(struct displayitem *)p;
p+=sizeof(*di)+count*sizeof(*c);
di->item=*item;
di->z_order=0;
+ di->holes=NULL;
+ if(hole_count > 0) {
+ di->holes = display_add_holes(item, hole_count, &p);
+ }
if (label && label_count) {
di->label=p;
for (i = 0 ; i < label_count ; i++) {
@@ -2230,6 +2333,180 @@ static void multiline_label_draw(struct graphics *gra, struct graphics_gc *fg, s
g_free(input_label);
}
+/**
+ * @brief coordnate transfor hole coordinates
+ *
+ * This function transform a whole set of polygon holes. It therefore allocates memory
+ * attached to a displayitem_poly_holes structure and call transform
+ *
+ * @param trans transformation to be used
+ * @param pro projection to be used
+ * @param in filled holes structure to transform
+ * @param out structure to place result in. Remember to deallocate!
+ * @param mindist minimal distance between points
+ */
+static inline void displayitem_transform_holes(struct transformation *trans, enum projection pro,
+ struct displayitem_poly_holes * in, struct displayitem_poly_holes * out, int mindist) {
+ if(out == NULL)
+ return;
+ out->count = 0;
+ out->ccount=NULL;
+ out->coords=NULL;
+ if((in != NULL) && (in->count > 0)) {
+ int a;
+ /* alloc space for hole conversion. To be freed with displayitem_free_holes later*/
+ out->count = in->count;
+ out->ccount = g_malloc0(sizeof(*(out->ccount)) * in->count);
+ out->coords = g_malloc0(sizeof(*(out->coords)) * in->count);
+ for(a = 0; a < in->count; a ++) {
+ in->ccount[a]=limit_count(in->coords[a], in->ccount[a]);
+ out->coords[a]=g_malloc0(sizeof(*(out->coords[a])) * in->ccount[a]);
+ out->ccount[a]=transform(trans, pro, in->coords[a], (struct point *)(out->coords[a]), in->ccount[a], mindist, 0, NULL);
+ }
+ }
+}
+
+/**
+ * @brief free hole structure allocated by displayitem_transform_holes
+ *
+ * @param holes structure to deallocate
+ */
+static void displayitem_free_holes(struct displayitem_poly_holes * holes) {
+ if(holes == NULL)
+ return;
+ if(holes->count > 0) {
+ int a;
+ for(a=0; a < holes->count; a ++) {
+ g_free(holes->coords[a]);
+ }
+ g_free(holes->ccount);
+ g_free(holes->coords);
+ }
+}
+
+
+static inline void displayitem_draw_polygon (struct display_context * dc, struct graphics * gra, struct point * pa,
+ int count, struct displayitem_poly_holes * holes) {
+ /*TODO: implement a "clipped" version of graphics_draw_polygon_with_holes*/
+ if((holes != NULL) && (holes->count > 0))
+ graphics_draw_polygon_with_holes(gra, dc->gc, pa, count, holes->count, holes->ccount, (struct point **)holes->coords);
+ else
+ graphics_draw_polygon_clipped(gra, dc->gc, pa, count);
+}
+
+static inline void displayitem_draw_polyline(struct display_context * dc, struct element * e, struct graphics * gra,
+ struct point * pa, int count, int *width) {
+ int i;
+ graphics_gc_set_linewidth(dc->gc, 1);
+ if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
+ graphics_gc_set_dashes(dc->gc, e->u.polyline.width, e->u.polyline.offset, e->u.polyline.dash_table,
+ e->u.polyline.dash_num);
+ for (i = 0 ; i < count ; i++) {
+ if (width[i] < 2)
+ width[i]=2;
+ }
+ graphics_draw_polyline_clipped(gra, dc->gc, pa, count, width, e->u.polyline.width > 1);
+}
+
+static inline void displayitem_draw_circle(struct displayitem *di,struct display_context *dc, struct element * e,
+ struct graphics * gra, struct point * pa, int count) {
+ if (count) {
+ if (e->u.circle.width > 1)
+ graphics_gc_set_linewidth(dc->gc, e->u.polyline.width);
+ graphics_draw_circle(gra, dc->gc, pa, e->u.circle.radius);
+ if (di->label && e->text_size) {
+ struct graphics_font *font=get_font(gra, e->text_size);
+ struct graphics_gc *gc_background=dc->gc_background;
+ if (! gc_background && e->u.circle.background_color.a) {
+ gc_background=graphics_gc_new(gra);
+ graphics_gc_set_foreground(gc_background, &e->u.circle.background_color);
+ dc->gc_background=gc_background;
+ }
+ if (font) {
+ struct point p;
+ /* Set p to the center of the circle */
+ p.x=pa[0].x+(e->u.circle.radius/2);
+ p.y=pa[0].y+(e->u.circle.radius/2);
+ multiline_label_draw(gra, dc->gc, gc_background, font, p, di->label, e->text_size+1);
+ } else
+ dbg(lvl_error,"Failed to get font with size %d",e->text_size);
+ }
+ }
+}
+
+static inline void displayitem_draw_text(struct displayitem *di,struct display_context *dc, struct element * e,
+ struct graphics * gra, struct point * pa, int count, struct displayitem_poly_holes * holes) {
+ if (count && di->label) {
+ struct graphics_font *font=get_font(gra, e->text_size);
+ struct graphics_gc *gc_background=dc->gc_background;
+ if (! gc_background && e->u.text.background_color.a) {
+ gc_background=graphics_gc_new(gra);
+ graphics_gc_set_foreground(gc_background, &e->u.text.background_color);
+ dc->gc_background=gc_background;
+ }
+ if (font) {
+ int a;
+ label_line(gra, dc->gc, gc_background, font, pa, count, di->label);
+ if(holes != NULL) {
+ for(a = 0; a < holes->count; a ++)
+ label_line(gra, dc->gc, gc_background, font, (struct point *)holes->coords[a], holes->ccount[a], di->label);
+ }
+ } else
+ dbg(lvl_error,"Failed to get font with size %d",e->text_size);
+ }
+}
+
+static inline void displayitem_draw_icon(struct displayitem *di,struct display_context *dc, struct element * e,
+ struct graphics * gra, struct point * pa, int count) {
+ if (count) {
+ struct graphics_image *img=dc->img;
+ if (!img || item_is_custom_poi(di->item)) {
+ char *path;
+ if (item_is_custom_poi(di->item)) {
+ char *icon;
+ char *src;
+ if (img)
+ graphics_image_free(dc->gra, img);
+ src=e->u.icon.src;
+ if (!src || !src[0])
+ src="%s";
+ icon=g_strdup_printf(src,di->label+strlen(di->label)+1);
+ path=graphics_icon_path(icon);
+ g_free(icon);
+ } else
+ path=graphics_icon_path(e->u.icon.src);
+ img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation);
+ if (img)
+ dc->img=img;
+ else
+ dbg(lvl_debug,"failed to load icon '%s'", path);
+ g_free(path);
+ }
+ if (img) {
+ struct point p;
+ if (e->u.icon.x != -1 || e->u.icon.y != -1) {
+ p.x=pa[0].x - e->u.icon.x;
+ p.y=pa[0].y - e->u.icon.y;
+ } else {
+ p.x=pa[0].x - img->hot.x;
+ p.y=pa[0].y - img->hot.y;
+ }
+ graphics_draw_image(gra, gra->gc[0], &p, img);
+ }
+ }
+}
+
+static inline void displayitem_draw_image (struct displayitem *di, struct display_context *dc, struct graphics * gra,
+ struct point * pa, int count) {
+ dbg(lvl_debug,"image: '%s'", di->label);
+ struct graphics_image *img=dc->img;
+ if (gra->meth.draw_image_warp) {
+ img=graphics_image_new_scaled_rotated(gra, di->label, IMAGE_W_H_UNSET, IMAGE_W_H_UNSET, 0);
+ if (img)
+ graphics_draw_image_warp(gra, gra->gc[0], pa, count, img);
+ } else
+ dbg(lvl_error,"draw_image_warp not supported by graphics driver drawing '%s'", di->label);
+}
/**
* @brief Draw a displayitem element
@@ -2242,25 +2519,30 @@ static void multiline_label_draw(struct graphics *gra, struct graphics_gc *fg, s
*/
static void displayitem_draw(struct displayitem *di, void *dummy, struct display_context *dc) {
int *width=g_alloca(sizeof(int)*dc->maxlen);
+ int limit=0;
struct point *pa=g_alloca(sizeof(struct point)*dc->maxlen);
struct graphics *gra=dc->gra;
- struct graphics_gc *gc=dc->gc;
struct element *e=dc->e;
- struct graphics_image *img=dc->img;
- struct point p;
- char *path;
while (di) {
- int i,count=di->count,mindist=dc->mindist;
+ int count=di->count,mindist=dc->mindist;
+ struct displayitem_poly_holes t_holes;
+ t_holes.count=0;
di->z_order=++(gra->current_z_order);
- if (! gc) {
- gc=graphics_gc_new(gra);
+ if (! dc->gc) {
+ struct graphics_gc * gc=graphics_gc_new(gra);
graphics_gc_set_foreground(gc, &e->color);
dc->gc=gc;
}
+
if (item_type_is_area(dc->type) && (dc->e->type == element_polyline || dc->e->type == element_text))
+ limit = 0;
+
+ displayitem_transform_holes(dc->trans, dc->pro, di->holes, &t_holes, mindist);
+
+ if (limit)
count=limit_count(di->c, count);
if (dc->type == type_poly_water_tiled)
mindist=0;
@@ -2270,108 +2552,33 @@ static void displayitem_draw(struct displayitem *di, void *dummy, struct display
count=transform(dc->trans, dc->pro, di->c, pa, count, mindist, 0, NULL);
switch (e->type) {
case element_polygon:
- graphics_draw_polygon_clipped(gra, gc, pa, count);
+ displayitem_draw_polygon(dc, gra, pa, count, &t_holes);
+ break;
+ case element_polyline:
+ displayitem_draw_polyline(dc, e, gra, pa, count, width);
break;
- case element_polyline: {
- graphics_gc_set_linewidth(gc, 1);
- if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
- graphics_gc_set_dashes(gc, e->u.polyline.width, e->u.polyline.offset, e->u.polyline.dash_table, e->u.polyline.dash_num);
- for (i = 0 ; i < count ; i++) {
- if (width[i] < 2)
- width[i]=2;
- }
- graphics_draw_polyline_clipped(gra, gc, pa, count, width, e->u.polyline.width > 1);
- }
- break;
case element_circle:
- if (count) {
- if (e->u.circle.width > 1)
- graphics_gc_set_linewidth(gc, e->u.polyline.width);
- graphics_draw_circle(gra, gc, pa, e->u.circle.radius);
- if (di->label && e->text_size) {
- struct graphics_font *font=get_font(gra, e->text_size);
- struct graphics_gc *gc_background=dc->gc_background;
- if (! gc_background && e->u.circle.background_color.a) {
- gc_background=graphics_gc_new(gra);
- graphics_gc_set_foreground(gc_background, &e->u.circle.background_color);
- dc->gc_background=gc_background;
- }
- if (font) {
- /* Set p to the center of the circle */
- p.x=pa[0].x+(e->u.circle.radius/2);
- p.y=pa[0].y+(e->u.circle.radius/2);
- multiline_label_draw(gra, gc, gc_background, font, p, di->label, e->text_size+1);
- } else
- dbg(lvl_error,"Failed to get font with size %d",e->text_size);
- }
- }
+ displayitem_draw_circle(di, dc, e, gra, pa, count);
break;
case element_text:
- if (count && di->label) {
- struct graphics_font *font=get_font(gra, e->text_size);
- struct graphics_gc *gc_background=dc->gc_background;
- if (! gc_background && e->u.text.background_color.a) {
- gc_background=graphics_gc_new(gra);
- graphics_gc_set_foreground(gc_background, &e->u.text.background_color);
- dc->gc_background=gc_background;
- }
- if (font)
- label_line(gra, gc, gc_background, font, pa, count, di->label);
- else
- dbg(lvl_error,"Failed to get font with size %d",e->text_size);
- }
+ displayitem_draw_text(di, dc, e, gra, pa, count, &t_holes);
break;
case element_icon:
- if (count) {
- if (!img || item_is_custom_poi(di->item)) {
- if (item_is_custom_poi(di->item)) {
- char *icon;
- char *src;
- if (img)
- graphics_image_free(dc->gra, img);
- src=e->u.icon.src;
- if (!src || !src[0])
- src="%s";
- icon=g_strdup_printf(src,di->label+strlen(di->label)+1);
- path=graphics_icon_path(icon);
- g_free(icon);
- } else
- path=graphics_icon_path(e->u.icon.src);
- img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation);
- if (img)
- dc->img=img;
- else
- dbg(lvl_debug,"failed to load icon '%s'", path);
- g_free(path);
- }
- if (img) {
- if (e->u.icon.x != -1 || e->u.icon.y != -1) {
- p.x=pa[0].x - e->u.icon.x;
- p.y=pa[0].y - e->u.icon.y;
- } else {
- p.x=pa[0].x - img->hot.x;
- p.y=pa[0].y - img->hot.y;
- }
- graphics_draw_image(gra, gra->gc[0], &p, img);
- }
- }
+ displayitem_draw_icon(di, dc, e, gra, pa, count);
break;
case element_image:
- dbg(lvl_debug,"image: '%s'", di->label);
- if (gra->meth.draw_image_warp) {
- img=graphics_image_new_scaled_rotated(gra, di->label, IMAGE_W_H_UNSET, IMAGE_W_H_UNSET, 0);
- if (img)
- graphics_draw_image_warp(gra, gra->gc[0], pa, count, img);
- } else
- dbg(lvl_error,"draw_image_warp not supported by graphics driver drawing '%s'", di->label);
+ displayitem_draw_image (di, dc, gra, pa, count);
break;
case element_arrows:
- display_draw_arrows(gra,gc,pa,count);
+ display_draw_arrows(gra,dc->gc,pa,count);
break;
default:
dbg(lvl_error, "Unhandled element type %d", e->type);
}
+ /* free space allocated for holes */
+ displayitem_free_holes(&t_holes);
+
di=di->next;
}
}
@@ -2418,6 +2625,7 @@ void graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct tra
di->item.map=NULL;
di->z_order=0;
di->label=label;
+ di->holes=NULL;
dc.gra=gra;
dc.gc=NULL;
dc.gc_background=NULL;
diff --git a/navit/graphics.h b/navit/graphics.h
index eec44ae14..3ea10e271 100644
--- a/navit/graphics.h
+++ b/navit/graphics.h
@@ -160,6 +160,8 @@ struct graphics_methods {
int (*show_native_keyboard)(struct graphics_keyboard *kbd);
void (*hide_native_keyboard)(struct graphics_keyboard *kbd);
navit_float (*get_dpi)(struct graphics_priv * gr);
+ void (*draw_polygon_with_holes) (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes);
};
diff --git a/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c b/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
index b61ac2403..35896791b 100644
--- a/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
+++ b/navit/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
@@ -181,7 +181,8 @@ static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics
}
-static struct graphics_image_priv *image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h, struct point *hot, int rotation) {
+static struct graphics_image_priv *image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name,
+ int *w, int *h, struct point *hot, int rotation) {
GdkPixbuf *pixbuf;
struct graphics_image_priv *ret;
const char *option;
@@ -293,6 +294,33 @@ static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
cairo_fill(gr->cairo);
}
+static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes) {
+ int i;
+ int j;
+ cairo_fill_rule_t old_rule;
+ set_drawing_color(gr->cairo, gc->c);
+ /* remember current fill rule */
+ old_rule = cairo_get_fill_rule (gr->cairo);
+ /* set fill rule */
+ cairo_set_fill_rule(gr->cairo, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_move_to(gr->cairo, p[0].x, p[0].y);
+ for (i=1; i<count; i++) {
+ cairo_line_to(gr->cairo, p[i].x, p[i].y);
+ }
+ for(j = 0; j < hole_count; j ++) {
+ if(hole_count > 0) {
+ cairo_move_to(gr->cairo, holes[j][0].x, holes[j][0].y);
+ for(i=0; i < ccount[j]; i ++) {
+ cairo_line_to(gr->cairo, holes[j][i].x, holes[j][i].y);
+ }
+ }
+ }
+ cairo_fill(gr->cairo);
+ /* restore fill rule */
+ cairo_set_fill_rule (gr->cairo,old_rule);
+}
+
static void draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h) {
cairo_save(gr->cairo);
// Use OPERATOR_SOURCE to overwrite old contents even when drawing with transparency.
@@ -310,7 +338,8 @@ static void draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, s
cairo_stroke(gr->cairo);
}
-static void draw_rgb_image_buffer(cairo_t *cairo, int buffer_width, int buffer_height, int draw_pos_x, int draw_pos_y, int stride, unsigned char *buffer) {
+static void draw_rgb_image_buffer(cairo_t *cairo, int buffer_width, int buffer_height, int draw_pos_x, int draw_pos_y,
+ int stride, unsigned char *buffer) {
cairo_surface_t *buffer_surface = cairo_image_surface_create_for_data(
buffer, CAIRO_FORMAT_ARGB32, buffer_width, buffer_height, stride);
cairo_set_source_surface(cairo, buffer_surface, draw_pos_x, draw_pos_y);
@@ -318,7 +347,8 @@ static void draw_rgb_image_buffer(cairo_t *cairo, int buffer_width, int buffer_h
cairo_surface_destroy(buffer_surface);
}
-static void display_text_draw(struct font_freetype_text *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct point *p) {
+static void display_text_draw(struct font_freetype_text *text, struct graphics_priv *gr, struct graphics_gc_priv *fg,
+ struct graphics_gc_priv *bg, struct point *p) {
int i,x,y,stride;
struct font_freetype_glyph *g, **gp;
struct color transparent= {0x0,0x0,0x0,0x0};
@@ -359,7 +389,8 @@ static void display_text_draw(struct font_freetype_text *text, struct graphics_p
}
}
-static void draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy) {
+static void draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg,
+ struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy) {
struct font_freetype_text *t;
if (! font) {
@@ -384,13 +415,15 @@ static void draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, str
gr->freetype_methods.text_destroy(t);
}
-static void draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img) {
+static void draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p,
+ struct graphics_image_priv *img) {
gdk_cairo_set_source_pixbuf(gr->cairo, img->pixbuf, p->x, p->y);
cairo_paint(gr->cairo);
}
#ifdef HAVE_IMLIB2
-static unsigned char* create_buffer_with_stride_if_required(unsigned char *input_buffer, int w, int h, size_t bytes_per_pixel, size_t output_stride) {
+static unsigned char* create_buffer_with_stride_if_required(unsigned char *input_buffer, int w, int h,
+ size_t bytes_per_pixel, size_t output_stride) {
int line;
size_t input_offset, output_offset;
unsigned char *out_buf;
@@ -408,7 +441,8 @@ static unsigned char* create_buffer_with_stride_if_required(unsigned char *input
return out_buf;
}
-static void draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, struct graphics_image_priv *img) {
+static void draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count,
+ struct graphics_image_priv *img) {
int w,h;
DATA32 *intermediate_buffer;
unsigned char* intermediate_buffer_aligned;
@@ -503,7 +537,8 @@ static void overlay_rect(struct graphics_priv *parent, struct graphics_priv *ove
r->height += parent->height;
}
-static void overlay_draw(struct graphics_priv *parent, struct graphics_priv *overlay, GdkRectangle *re, cairo_t *cairo) {
+static void overlay_draw(struct graphics_priv *parent, struct graphics_priv *overlay, GdkRectangle *re,
+ cairo_t *cairo) {
GdkRectangle or, ir;
if (parent->overlay_disabled || overlay->overlay_disabled || overlay->overlay_autodisabled)
return;
@@ -866,7 +901,8 @@ static int set_attr(struct graphics_priv *gr, struct attr *attr) {
}
}
-static struct graphics_priv *overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int wraparound) {
+static struct graphics_priv *overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p,
+ int w, int h, int wraparound) {
int w2,h2;
struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
this->widget=gr->widget;
@@ -965,6 +1001,20 @@ static void *get_data(struct graphics_priv *this, char const *type) {
return NULL;
}
+/**
+ * @brief Return number of dots per inch
+ * @param gr self handle
+ * @return dpi value
+ */
+static navit_float get_dpi(struct graphics_priv * gr) {
+ gdouble dpi = 96;
+ GdkScreen *screen = gtk_widget_get_screen(gr->widget);
+ if(screen != NULL) {
+ dpi = gdk_screen_get_resolution (screen);
+ }
+ return (navit_float) dpi;
+}
+
static struct graphics_methods graphics_methods = {
graphics_destroy,
draw_mode,
@@ -993,6 +1043,8 @@ static struct graphics_methods graphics_methods = {
set_attr,
NULL, /* show_native_keyboard */
NULL, /* hide_native_keyboard */
+ get_dpi, /* get dpi */
+ draw_polygon_with_holes
};
static struct graphics_priv *graphics_gtk_drawing_area_new_helper(struct graphics_methods *meth) {
@@ -1010,7 +1062,8 @@ static struct graphics_priv *graphics_gtk_drawing_area_new_helper(struct graphic
return this;
}
-static struct graphics_priv *graphics_gtk_drawing_area_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl) {
+static struct graphics_priv *graphics_gtk_drawing_area_new(struct navit *nav, struct graphics_methods *meth,
+ struct attr **attrs, struct callback_list *cbl) {
int i;
GtkWidget *draw;
struct attr *attr;
diff --git a/navit/graphics/qt5/graphics_qt5.cpp b/navit/graphics/qt5/graphics_qt5.cpp
index 535b370dc..10784d6b3 100644
--- a/navit/graphics/qt5/graphics_qt5.cpp
+++ b/navit/graphics/qt5/graphics_qt5.cpp
@@ -418,6 +418,44 @@ static void draw_polygon(struct graphics_priv* gr, struct graphics_gc_priv* gc,
gr->painter->drawPolygon(polygon);
}
+static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes) {
+ int i;
+ int j;
+ QPainterPath path;
+ QPainterPath inner;
+ QPolygon polygon;
+ //dbg(lvl_error,"enter gr=%p, gc=%p, (%d, %d) holes %d", gr, gc, p->x, p->y, hole_count);
+ if (gr->painter == NULL)
+ return;
+ gr->painter->setPen(*gc->pen);
+ gr->painter->setBrush(*gc->brush);
+ /* construct outer polygon */
+ for (i = 0; i < count; i++)
+ polygon.putPoints(i, 1, p[i].x, p[i].y);
+ /* add it to outer path */
+ path.addPolygon(polygon);
+ /* construct the polygons for the holes and add them to inner */
+ for(j=0; j<hole_count; j ++) {
+ QPolygon hole;
+ for (i = 0; i < ccount[j]; i++)
+ hole.putPoints(i, 1, holes[j][i].x, holes[j][i].y);
+ inner.addPolygon(hole);
+ }
+ /* intersect */
+ if(hole_count > 0)
+ path = path.subtracted(inner);
+
+ /* if the polygon is transparent, we need to clear it first */
+ if (!gc->brush->isOpaque()) {
+ QPainter::CompositionMode mode = gr->painter->compositionMode();
+ gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
+ gr->painter->drawPath(path);
+ gr->painter->setCompositionMode(mode);
+ }
+ gr->painter->drawPath(path);
+}
+
static void draw_rectangle(struct graphics_priv* gr, struct graphics_gc_priv* gc, struct point* p, int w, int h) {
// dbg(lvl_debug,"gr=%p gc=%p %d,%d,%d,%d", gr, gc, p->x, p->y, w, h);
if (gr->painter == NULL)
@@ -851,7 +889,8 @@ static struct graphics_methods graphics_methods = {
NULL, //set_attr
NULL, //show_native_keyboard
NULL, //hide_native_keyboard
- get_dpi
+ get_dpi,
+ draw_polygon_with_holes
};
/* create new graphics context on given context */
diff --git a/navit/graphics/win32/graphics_win32.c b/navit/graphics/win32/graphics_win32.c
index 1c8172c7c..6bcad3be6 100644
--- a/navit/graphics/win32/graphics_win32.c
+++ b/navit/graphics/win32/graphics_win32.c
@@ -827,6 +827,62 @@ static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
SelectObject( gr->hMemDC, holdpen);
}
+#if HAVE_API_WIN32_CE
+/*
+ * Windows CE doesn't support PaintPath used for other versions. No polygon with holes support for CE yet.
+ */
+#else
+static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes) {
+ /* remeber pen and brush */
+ HPEN holdpen = SelectObject( gr->hMemDC, gc->hpen );
+ HBRUSH holdbrush = SelectObject( gr->hMemDC, gc->hbrush );
+ /* remember fill mode */
+ int holdmode = GetPolyFillMode( gr->hMemDC );
+
+ /* set polygon fill mode */
+ SetPolyFillMode( gr->hMemDC, ALTERNATE );
+
+ /* use poly path */
+ if(BeginPath(gr->hMemDC)) {
+ int a;
+ /* add outer polygon */
+ if (sizeof(POINT) != sizeof(struct point)) {
+ int i;
+ POINT* points=g_alloca(sizeof(POINT)*count);
+ for ( i=0; i< count; i++ ) {
+ points[i].x = p[i].x;
+ points[i].y = p[i].y;
+ }
+ Polyline( gr->hMemDC, points, count );
+ } else
+ Polyline( gr->hMemDC, (POINT *)p, count);
+ /* add inner polygons */
+ for(a = 0; a<hole_count; a ++) {
+ if (sizeof(POINT) != sizeof(struct point)) {
+ int i;
+ POINT* points=g_alloca(sizeof(POINT)*ccount[a]);
+ for ( i=0; i< ccount[a]; i++ ) {
+ points[i].x = holes[a][i].x;
+ points[i].y = holes[a][i].y;
+ }
+ Polyline( gr->hMemDC, points, ccount[a] );
+ } else
+ Polyline( gr->hMemDC, (POINT *)(holes[a]), ccount[a]);
+ }
+ /* done with this path */
+ EndPath(gr->hMemDC);
+ /* fill the shape */
+ FillPath(gr->hMemDC);
+ }
+
+ /* restore fill mode */
+ SetPolyFillMode(gr->hMemDC, holdmode);
+ /* restore pen and brush */
+ SelectObject( gr->hMemDC, holdbrush);
+ SelectObject( gr->hMemDC, holdpen);
+}
+#endif
static void draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h) {
HPEN holdpen = SelectObject( gr->hMemDC, gc->hpen );
@@ -1462,8 +1518,15 @@ static struct graphics_methods graphics_methods = {
get_text_bbox,
overlay_disable,
overlay_resize,
+ NULL, /* set_attr */
NULL, /* show_native_keyboard */
NULL, /* hide_native_keyboard */
+ NULL, /* get dpi */
+#if HAVE_API_WIN32_CE
+ NULL, /* draw_polygon_with_holes */
+#else
+ draw_polygon_with_holes
+#endif
};
diff --git a/navit/item.h b/navit/item.h
index 5374240d2..0d0e84c7f 100644
--- a/navit/item.h
+++ b/navit/item.h
@@ -68,26 +68,26 @@ extern int default_flags[];
struct coord;
enum change_mode {
- change_mode_delete,
- change_mode_modify,
- change_mode_append,
- change_mode_prepend,
+ change_mode_delete,
+ change_mode_modify,
+ change_mode_append,
+ change_mode_prepend,
};
struct item_methods {
- void (*item_coord_rewind)(void *priv_data);
- int (*item_coord_get)(void *priv_data, struct coord *c, int count);
- void (*item_attr_rewind)(void *priv_data);
- int (*item_attr_get)(void *priv_data, enum attr_type attr_type, struct attr *attr);
- int (*item_coord_is_node)(void *priv_data);
- int (*item_attr_set)(void *priv_data, struct attr *attr, enum change_mode mode);
- int (*item_coord_set)(void *priv_data, struct coord *c, int count, enum change_mode mode);
- int (*item_type_set)(void *priv_data, enum item_type type);
+ void (*item_coord_rewind)(void *priv_data);
+ int (*item_coord_get)(void *priv_data, struct coord *c, int count);
+ void (*item_attr_rewind)(void *priv_data);
+ int (*item_attr_get)(void *priv_data, enum attr_type attr_type, struct attr *attr);
+ int (*item_coord_is_node)(void *priv_data);
+ int (*item_attr_set)(void *priv_data, struct attr *attr, enum change_mode mode);
+ int (*item_coord_set)(void *priv_data, struct coord *c, int count, enum change_mode mode);
+ int (*item_type_set)(void *priv_data, enum item_type type);
};
struct item_id {
- int id_hi;
- int id_lo;
+ int id_hi;
+ int id_lo;
};
#define ITEM_ID_FMT "(0x%x,0x%x)"
@@ -97,16 +97,16 @@ struct item_id {
* Represents an object on a map, such as a POI, a building, a way or a boundary.
*/
struct item {
- enum item_type type; /**< Type of the item.*/
- int id_hi; /**< First part of the ID of the item (item IDs have two parts).*/
- int id_lo; /**< Second part of the ID of the item.*/
- struct map *map; /**< The map this items belongs to.*/
- struct item_methods *meth; /**< Methods to manipulate this item.*/
- void *priv_data; /**< Private item data, only used by the map plugin which supplied this item.*/
+ enum item_type type; /**< Type of the item.*/
+ int id_hi; /**< First part of the ID of the item (item IDs have two parts).*/
+ int id_lo; /**< Second part of the ID of the item.*/
+ struct map *map; /**< The map this items belongs to.*/
+ struct item_methods *meth; /**< Methods to manipulate this item.*/
+ void *priv_data; /**< Private item data, only used by the map plugin which supplied this item.*/
};
extern struct item_range {
- enum item_type min,max;
+ enum item_type min,max;
} item_range_all;
extern struct item busy_item;
diff --git a/navit/layout.h b/navit/layout.h
index ece5d0cc8..700e6245a 100644
--- a/navit/layout.h
+++ b/navit/layout.h
@@ -22,88 +22,93 @@
#include "item.h"
#include "color.h"
+#include "coord.h"
#ifdef __cplusplus
extern "C" {
#endif
+struct poly_hole {
+ int coord_count;
+ struct coord coord[1];
+};
struct element {
- enum { element_point, element_polyline, element_polygon, element_circle, element_text, element_icon, element_image, element_arrows } type;
- struct color color;
- int text_size;
- union {
- struct element_point {
- char stub;
- } point;
- struct element_polyline {
- int width;
- int directed;
- int dash_num;
- int offset;
- unsigned char dash_table[4];
- } polyline;
- struct element_polygon {
- char stub;
- } polygon;
- struct element_circle {
- int width;
- int radius;
- struct color background_color;
- } circle;
- struct element_icon {
- char *src;
- int width;
- int height;
- int rotation;
- int x;
- int y;
- } icon;
- struct element_text {
- struct color background_color;
- } text;
- } u;
- int coord_count;
- struct coord *coord;
+ enum { element_point, element_polyline, element_polygon, element_circle, element_text, element_icon, element_image, element_arrows } type;
+ struct color color;
+ int text_size;
+ union {
+ struct element_point {
+ char stub;
+ } point;
+ struct element_polyline {
+ int width;
+ int directed;
+ int dash_num;
+ int offset;
+ unsigned char dash_table[4];
+ } polyline;
+ struct element_polygon {
+ char stub;
+ } polygon;
+ struct element_circle {
+ int width;
+ int radius;
+ struct color background_color;
+ } circle;
+ struct element_icon {
+ char *src;
+ int width;
+ int height;
+ int rotation;
+ int x;
+ int y;
+ } icon;
+ struct element_text {
+ struct color background_color;
+ } text;
+ } u;
+ int coord_count;
+ struct coord *coord;
};
struct itemgra {
- struct range order,sequence_range,speed_range,angle_range;
- GList *type;
- GList *elements;
+ struct range order,sequence_range,speed_range,angle_range;
+ GList *type;
+ GList *elements;
};
struct layer {
- NAVIT_OBJECT
- struct navit *navit;
- char *name;
- int details;
- GList *itemgras;
- int active;
- struct layer *ref;
+ NAVIT_OBJECT
+ struct navit *navit;
+ char *name;
+ int details;
+ GList *itemgras;
+ int active;
+ struct layer *ref;
};
struct cursor {
- struct attr **attrs;
- struct range *sequence_range;
- char *name;
- int w,h;
- int interval;
+ struct attr **attrs;
+ struct range *sequence_range;
+ char *name;
+ int w,h;
+ int interval;
};
struct layout {
- NAVIT_OBJECT
- struct navit *navit;
- char *name;
- char* dayname;
- char* nightname;
- char *font;
- struct color color;
- GList *layers;
- GList *cursors;
- int order_delta;
- int active;
+ NAVIT_OBJECT
+ struct navit *navit;
+ char *name;
+ char* dayname;
+ char* nightname;
+ char *font;
+ struct color color;
+ GList *layers;
+ GList *cursors;
+ int order_delta;
+ int active;
};
/* prototypes */
diff --git a/navit/maptool/maptool.c b/navit/maptool/maptool.c
index 422bc96bf..9c00a9c13 100644
--- a/navit/maptool/maptool.c
+++ b/navit/maptool/maptool.c
@@ -52,6 +52,7 @@
long long slice_size=SLIZE_SIZE_DEFAULT_GB*1024ll*1024*1024;
int attr_debug_level=1;
int ignore_unknown = 0;
+int thread_count=8; /* good default even on single cores */
GHashTable *dedupe_ways_hash;
int phase;
int slices;
@@ -278,7 +279,8 @@ static void usage(void) {
fprintf(f,"maptool --protobuf -i planet.osm.pbf planet.bin\n");
fprintf(f,"Available switches:\n");
fprintf(f,"-h (--help) : this screen\n");
- fprintf(f,"-6 (--64bit) : set zip 64 bit compression\n");
+ fprintf(f,"-3 (--32bit) : set zip 32 bit compression\n");
+ fprintf(f,"-6 (--64bit) : set zip 64 bit compression (default)\n");
fprintf(f,"-a (--attr-debug-level) <level> : control which data is included in the debug attribute\n");
fprintf(f,"-c (--dump-coordinates) : dump coordinates after phase 1\n");
#ifdef HAVE_POSTGRESQL
@@ -301,6 +303,7 @@ static void usage(void) {
"-S (--slice-size) <size> : limit memory to use for some large internal buffers, in bytes. Default is %dGB.\n",
SLIZE_SIZE_DEFAULT_GB);
fprintf(f,"-t (--timestamp) <y-m-dTh:m:s> : Set zip timestamp\n");
+ fprintf(f,"-T (--threads) <count> : Set number of threads (for some operations)\n");
fprintf(f,
"-w (--dedupe-ways) : ensure no duplicate ways or nodes. useful when using several input files\n");
fprintf(f,"-W (--ways-only) : process only ways\n");
@@ -356,6 +359,7 @@ static int parse_option(struct maptool_params *p, char **argv, int argc, int *op
int pos,c,i;
static struct option long_options[] = {
+ {"32bit", 0, 0, '3'},
{"64bit", 0, 0, '6'},
{"attr-debug-level", 1, 0, 'a'},
{"binfile", 0, 0, 'b'},
@@ -377,6 +381,7 @@ static int parse_option(struct maptool_params *p, char **argv, int argc, int *op
{"protobuf", 0, 0, 'P'},
{"start", 1, 0, 's'},
{"timestamp", 1, 0, 't'},
+ {"threads", 1, 0, 'T'},
{"input-file", 1, 0, 'i'},
{"rule-file", 1, 0, 'r'},
{"ignore-unknown", 0, 0, 'n'},
@@ -387,14 +392,17 @@ static int parse_option(struct maptool_params *p, char **argv, int argc, int *op
{"index-size", 0, 0, 'x'},
{0, 0, 0, 0}
};
- c = getopt_long (argc, argv, "6B:DEMNO:PS:Wa:bc"
+ c = getopt_long (argc, argv, "36B:DEMNO:PS:Wa:bc"
#ifdef HAVE_POSTGRESQL
"d:"
#endif
- "e:hi:knm:p:r:s:t:wu:z:Ux:", long_options, option_index);
+ "e:hi:knm:p:r:s:t:T:wu:z:Ux:", long_options, option_index);
if (c == -1)
return 1;
switch (c) {
+ case '3':
+ p->zip64=0;
+ break;
case '6':
p->zip64=1;
break;
@@ -493,6 +501,9 @@ static int parse_option(struct maptool_params *p, char **argv, int argc, int *op
case 't':
p->timestamp=optarg;
break;
+ case 'T':
+ thread_count=atoi(optarg);
+ break;
case 'w':
dedupe_ways_hash=g_hash_table_new(NULL, NULL);
break;
@@ -555,6 +566,7 @@ static void osm_read_input_data(struct maptool_params *p, char *suffix) {
p->osm.towns=tempfile(suffix,"towns",1);
}
if (p->process_ways && p->process_nodes) {
+ p->osm.multipolygons=tempfile(suffix,"multipolygons",1);
p->osm.turn_restrictions=tempfile(suffix,"turn_restrictions",1);
p->osm.line2poi=tempfile(suffix,"line2poi",1);
p->osm.poly2poi=tempfile(suffix,"poly2poi",1);
@@ -599,6 +611,8 @@ static void osm_read_input_data(struct maptool_params *p, char *suffix) {
fclose(p->osm.nodes);
if (p->osm.turn_restrictions)
fclose(p->osm.turn_restrictions);
+ if (p->osm.multipolygons)
+ fclose(p->osm.multipolygons);
if (p->osm.associated_streets)
fclose(p->osm.associated_streets);
if (p->osm.house_number_interpolations)
@@ -723,6 +737,26 @@ static void osm_process_turn_restrictions(struct maptool_params *p, char *suffix
tempfile_unlink(suffix,"turn_restrictions");
}
+static void osm_process_multipolygons(struct maptool_params *p, char *suffix) {
+ FILE *ways_split, *ways_split_index, *relations/*, *coords*/;
+ p->osm.multipolygons=tempfile(suffix,"multipolygons",0);
+ if(!p->osm.multipolygons)
+ return;
+ relations=tempfile(suffix,"multipolygons_out", 1);
+ /* no coords in multipolygons. */
+ //coords=fopen("coords.tmp", "rb");
+ ways_split=tempfile(suffix,"ways_split",0);
+ ways_split_index=tempfile(suffix,"ways_split_index",0);
+ process_multipolygons(p->osm.multipolygons,/*coords*/NULL,ways_split,ways_split_index,relations);
+ fclose(ways_split_index);
+ fclose(ways_split);
+ //fclose(coords);
+ fclose(relations);
+ fclose(p->osm.multipolygons);
+ if(!p->keep_tmpfiles)
+ tempfile_unlink(suffix,"multipolygons");
+}
+
static void maptool_dump(struct maptool_params *p, char *suffix) {
char *files[10];
int i,files_count=0;
@@ -730,8 +764,10 @@ static void maptool_dump(struct maptool_params *p, char *suffix) {
files[files_count++]="nodes";
if (p->process_ways)
files[files_count++]="ways_split";
- if (p->process_relations)
+ if (p->process_relations) {
files[files_count++]="relations";
+ files[files_count++]="multipolygons_out";
+ }
for (i = 0 ; i < files_count ; i++) {
FILE *f=tempfile(suffix,files[i],0);
if (f) {
@@ -815,6 +851,7 @@ static void maptool_assemble_map(struct maptool_params *p, char *suffix, char **
}
if(!p->keep_tmpfiles) {
tempfile_unlink(suffix,"relations");
+ tempfile_unlink(suffix,"multipolygons_out");
tempfile_unlink(suffix,"nodes");
tempfile_unlink(suffix,"ways_split");
tempfile_unlink(suffix,"poly2poi_resolved");
@@ -822,6 +859,7 @@ static void maptool_assemble_map(struct maptool_params *p, char *suffix, char **
tempfile_unlink(suffix,"ways_split_ref");
tempfile_unlink(suffix,"coastline");
tempfile_unlink(suffix,"turn_restrictions");
+ tempfile_unlink(suffix,"multipolygons");
tempfile_unlink(suffix,"graph");
tempfile_unlink(suffix,"tilesdir");
tempfile_unlink(suffix,"boundaries");
@@ -890,6 +928,7 @@ int main(int argc, char **argv) {
linguistics_init();
memset(&p, 0, sizeof(p));
+ p.zip64=1; /* default to 64 bit zip */
#ifdef HAVE_ZLIB
p.compression_level=9;
#endif
@@ -1005,9 +1044,15 @@ int main(int argc, char **argv) {
if (p.process_relations) {
osm_process_turn_restrictions(&p, suffix);
}
- if(!p.keep_tmpfiles)
- tempfile_unlink(suffix,"ways_split_index");
}
+ if (start_phase(&p,"generating multipolygons")) {
+ if(p.process_relations) {
+ osm_process_multipolygons(&p, suffix);
+ }
+ }
+ if(!p.keep_tmpfiles)
+ tempfile_unlink(suffix,"ways_split_index");
+
if (p.process_relations && p.process_ways && p.process_nodes
&& start_phase(&p,"processing associated street relations")) {
struct files_relation_processing *files_relproc = files_relation_processing_new(p.osm.line2poi, suffix);
@@ -1044,6 +1089,8 @@ int main(int argc, char **argv) {
exit(0);
}
if (p.process_relations) {
+ filenames[filename_count]="multipolygons_out";
+ referencenames[filename_count++]=NULL;
filenames[filename_count]="relations";
referencenames[filename_count++]=NULL;
filenames[filename_count]="towns_poly";
diff --git a/navit/maptool/maptool.h b/navit/maptool/maptool.h
index edb2a77ef..f0aee6fdf 100644
--- a/navit/maptool/maptool.h
+++ b/navit/maptool/maptool.h
@@ -35,37 +35,37 @@
#define RELATION_MEMBER_PARSE_FORMAT "%d:"LONGLONG_FMT":%n"
struct tile_data {
- char buffer[1024];
- int tile_depth;
- struct rect item_bbox;
- struct rect tile_bbox;
+ char buffer[1024];
+ int tile_depth;
+ struct rect item_bbox;
+ struct rect tile_bbox;
};
struct tile_parameter {
- int min;
- int max;
- int overlap;
- enum attr_type attr_to_copy;
+ int min;
+ int max;
+ int overlap;
+ enum attr_type attr_to_copy;
};
struct tile_info {
- int write;
- int maxlen;
- char *suffix;
- GList **tiles_list;
- FILE *tilesdir_out;
+ int write;
+ int maxlen;
+ char *suffix;
+ GList **tiles_list;
+ FILE *tilesdir_out;
};
extern struct tile_head {
- int num_subtiles;
- int total_size;
- char *name;
- char *zip_data;
- int total_size_used;
- int zipnum;
- int process;
- struct tile_head *next;
- // char subtiles[0];
+ int num_subtiles;
+ int total_size;
+ char *name;
+ char *zip_data;
+ int total_size_used;
+ int zipnum;
+ int process;
+ struct tile_head *next;
+ // char subtiles[0];
} *tile_head_root;
@@ -80,12 +80,12 @@ extern struct tile_head {
* @see struct attr_bin
*/
struct item_bin {
- /** Length of this item (not including this length field) in 32-bit ints. */
- int len;
- /** Item type. */
- enum item_type type;
- /** Length of the following coordinate array in 32-bit ints. */
- int clen;
+ /** Length of this item (not including this length field) in 32-bit ints. */
+ int len;
+ /** Item type. */
+ enum item_type type;
+ /** Length of the following coordinate array in 32-bit ints. */
+ int clen;
};
/**
@@ -96,27 +96,28 @@ struct item_bin {
* @see struct item_bin
*/
struct attr_bin {
- /** Length of this attribute (not including this length field) in 32-bit ints. */
- int len;
- /** Attribute type. */
- enum attr_type type;
+ /** Length of this attribute (not including this length field) in 32-bit ints. */
+ int len;
+ /** Attribute type. */
+ enum attr_type type;
};
struct item_bin_sink_func {
- int (*func)(struct item_bin_sink_func *func, struct item_bin *ib, struct tile_data *tile_data);
- void *priv_data[8];
+ int (*func)(struct item_bin_sink_func *func, struct item_bin *ib, struct tile_data *tile_data);
+ void *priv_data[8];
};
struct item_bin_sink {
- void *priv_data[8];
- GList *sink_funcs;
+ void *priv_data[8];
+ GList *sink_funcs;
};
#define NODE_ID_BITS 56
struct node_item {
- struct coord c;
- unsigned long long int nd_id:NODE_ID_BITS;
- char ref_way;
+ struct coord c;
+unsigned long long int nd_id:
+ NODE_ID_BITS;
+ char ref_way;
};
struct zip_info;
@@ -132,24 +133,24 @@ typedef unsigned long long int osmid;
/** Files needed for processing a relation. */
struct files_relation_processing {
- FILE *ways_in;
- FILE *ways_out;
- FILE *nodes_in;
- FILE *nodes_out;
- FILE *nodes2_in;
- FILE *nodes2_out;
+ FILE *ways_in;
+ FILE *ways_out;
+ FILE *nodes_in;
+ FILE *nodes_out;
+ FILE *nodes2_in;
+ FILE *nodes2_out;
};
/* boundaries.c */
struct boundary {
- struct item_bin *ib;
- struct country_table *country;
- char *iso2;
- GList *segments,*sorted_segments;
- GList *children;
- struct rect r;
- osmid admin_centre;
+ struct item_bin *ib;
+ struct country_table *country;
+ char *iso2;
+ GList *segments,*sorted_segments;
+ GList *children;
+ struct rect r;
+ osmid admin_centre;
};
char *osm_tag_value(struct item_bin *ib, char *key);
@@ -166,14 +167,14 @@ void free_boundaries(GList *l);
/** A buffer that can be grown as needed. */
struct buffer {
- /** Number of bytes to extend the buffer by when it must grow. */
- int malloced_step;
- /** Current allocated size (bytes). */
- long long malloced;
- /** Base address of this buffer. */
- unsigned char *base;
- /** Size of currently used part of the buffer. */
- long long size;
+ /** Number of bytes to extend the buffer by when it must grow. */
+ int malloced_step;
+ /** Current allocated size (bytes). */
+ long long malloced;
+ /** Base address of this buffer. */
+ unsigned char *base;
+ /** Size of currently used part of the buffer. */
+ long long size;
};
void save_buffer(char *filename, struct buffer *b, long long offset);
@@ -234,6 +235,7 @@ extern struct item_bin *tmp_item_bin;
/* maptool.c */
extern long long slice_size;
+extern int thread_count;
extern int attr_debug_level;
extern char *suffix;
extern int ignore_unknown;
@@ -270,23 +272,24 @@ int item_order_by_type(enum item_type type);
/* osm.c */
struct maptool_osm {
- FILE *boundaries;
- FILE *turn_restrictions;
- FILE *associated_streets;
- FILE *house_number_interpolations;
- FILE *nodes;
- FILE *ways;
- FILE *line2poi;
- FILE *poly2poi;
- FILE *towns;
+ FILE *boundaries;
+ FILE *multipolygons;
+ FILE *turn_restrictions;
+ FILE *associated_streets;
+ FILE *house_number_interpolations;
+ FILE *nodes;
+ FILE *ways;
+ FILE *line2poi;
+ FILE *poly2poi;
+ FILE *towns;
};
/** Type of a relation member. */
enum relation_member_type {
- UNUSED,
- rel_member_node,
- rel_member_way,
- rel_member_relation,
+ UNUSED,
+ rel_member_node,
+ rel_member_way,
+ rel_member_relation,
};
void osm_warning(char *type, osmid id, int cont, char *fmt, ...);
@@ -305,6 +308,7 @@ void flush_nodes(int final);
void sort_countries(int keep_tmpfiles);
void process_associated_streets(FILE *in, struct files_relation_processing *files_relproc);
void process_house_number_interpolations(FILE *in, struct files_relation_processing *files_relproc);
+void process_multipolygons(FILE *in, FILE *coords, FILE *ways, FILE *ways_index, FILE *out);
void process_turn_restrictions(FILE *in, FILE *coords, FILE *ways, FILE *ways_index, FILE *out);
void process_turn_restrictions_old(FILE *in, FILE *coords, FILE *ways, FILE *ways_index, FILE *out);
void clear_node_item_buffer(void);
@@ -314,7 +318,8 @@ unsigned long long item_bin_get_nodeid(struct item_bin *ib);
unsigned long long item_bin_get_wayid(struct item_bin *ib);
unsigned long long item_bin_get_relationid(struct item_bin *ib);
void process_way2poi(FILE *in, FILE *out, int type);
-int map_resolve_coords_and_split_at_intersections(FILE *in, FILE *out, FILE *out_index, FILE *out_graph, FILE *out_coastline, int final);
+int map_resolve_coords_and_split_at_intersections(FILE *in, FILE *out, FILE *out_index, FILE *out_graph,
+ FILE *out_coastline, int final);
void write_countrydir(struct zip_info *zip_info, int max_index_size);
void osm_process_towns(FILE *in, FILE *boundaries, FILE *ways, char *suffix);
void load_countries(void);
@@ -334,8 +339,10 @@ int osm_protobufdb_load(FILE *in, char *dir);
/* osm_relations.c */
struct relations * relations_new(void);
-struct relations_func *relations_func_new(void (*func)(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv), void *func_priv);
-void relations_add_relation_member_entry(struct relations *rel, struct relations_func *func, void *relation_priv, void *member_priv, enum relation_member_type type, osmid id);
+struct relations_func *relations_func_new(void (*func)(void *func_priv, void *relation_priv, struct item_bin *member,
+ void *member_priv), void *func_priv);
+void relations_add_relation_member_entry(struct relations *rel, struct relations_func *func, void *relation_priv,
+ void *member_priv, enum relation_member_type type, osmid id);
void relations_add_relation_default_entry(struct relations *rel, struct relations_func *func);
void relations_process(struct relations *rel, FILE *nodes, FILE *ways);
void relations_destroy(struct relations *rel);
@@ -350,7 +357,8 @@ int map_collect_data_osm(FILE *in, struct maptool_osm *osm);
/* sourcesink.c */
struct item_bin_sink *item_bin_sink_new(void);
-struct item_bin_sink_func *item_bin_sink_func_new(int (*func)(struct item_bin_sink_func *func, struct item_bin *ib, struct tile_data *tile_data));
+struct item_bin_sink_func *item_bin_sink_func_new(int (*func)(struct item_bin_sink_func *func, struct item_bin *ib,
+ struct tile_data *tile_data));
void item_bin_sink_func_destroy(struct item_bin_sink_func *func);
void item_bin_sink_add_func(struct item_bin_sink *sink, struct item_bin_sink_func *func);
void item_bin_sink_destroy(struct item_bin_sink *sink);
@@ -374,9 +382,9 @@ void tempfile_rename(char *suffix, char *from, char *to);
extern GHashTable *tile_hash,*tile_hash2;
struct aux_tile {
- char *name;
- char *filename;
- int size;
+ char *name;
+ char *filename;
+ int size;
};
extern GList *aux_tile_list;
@@ -415,4 +423,6 @@ void zip_close(struct zip_info *info);
void zip_destroy(struct zip_info *info);
/* Break compilation on 32 bit architectures, as we're going to cast osmid's to gpointer to use them as keys to GHashTable's */
-struct maptool_force_64 {char s[sizeof(gpointer)<sizeof(osmid)?-1:1];};
+struct maptool_force_64 {
+ char s[sizeof(gpointer)<sizeof(osmid)?-1:1];
+};
diff --git a/navit/maptool/misc.c b/navit/maptool/misc.c
index 1c30b94f7..9b1c72da2 100644
--- a/navit/maptool/misc.c
+++ b/navit/maptool/misc.c
@@ -213,12 +213,20 @@ int item_order_by_type(enum item_type type) {
return max;
}
+static inline int filter_unknown(struct item_bin * ib) {
+ if(ignore_unknown && (ib->type==type_point_unkn || ib->type==type_street_unkn || ib->type==type_none))
+ return 1;
+ return 0;
+}
+
static void phase34_process_file(struct tile_info *info, FILE *in, FILE *reference) {
struct item_bin *ib;
struct attr_bin *a;
int max;
while ((ib=read_item(in))) {
+ if(filter_unknown(ib))
+ continue;
if (ib->type < 0x80000000)
processed_nodes++;
else
@@ -239,6 +247,8 @@ static void phase34_process_file_range(struct tile_info *info, FILE *in, FILE *r
int min,max;
while ((ib=read_item_range(in, &min, &max))) {
+ if(filter_unknown(ib))
+ continue;
if (ib->type < 0x80000000)
processed_nodes++;
else
@@ -278,6 +288,8 @@ static int phase34(struct tile_info *info, struct zip_info *zip_info, FILE **in,
void dump(FILE *in) {
struct item_bin *ib;
while ((ib=read_item(in))) {
+ if(filter_unknown(ib))
+ continue;
dump_itembin(ib);
}
}
diff --git a/navit/maptool/osm.c b/navit/maptool/osm.c
index 7de4d0569..6fd05674d 100644
--- a/navit/maptool/osm.c
+++ b/navit/maptool/osm.c
@@ -1570,6 +1570,7 @@ int boundary;
void osm_add_relation(osmid id) {
osmid_attr_value=id;
in_relation=1;
+ attr_strings_clear();
debug_attr_buffer[0]='\0';
relation_type[0]='\0';
iso_code[0]='\0';
@@ -1609,21 +1610,40 @@ country_from_iso2(char *iso) {
return country_from_countryid(country_id_from_iso2(iso));
}
+static inline void osm_end_relation_multipolygon (struct maptool_osm * osm, enum item_type* type) {
+ if((!g_strcmp0(relation_type, "multipolygon")) && (!boundary)) {
+ if(attr_longest_match(attr_mapping_way, attr_mapping_way_count, type, 1)) {
+ tmp_item_bin->type = *type;
+ } else {
+ *type=type_none;
+ /* do not touch tmp_item_bin->type in this case, as it may be already set! For example
+ * indicating the turn restrictions */
+ //tmp_item_bin->type=*type;
+ }
+ item_bin_add_attr_string(tmp_item_bin, attr_label, attr_strings[attr_string_label]);
+ item_bin_write(tmp_item_bin, osm->multipolygons);
+ } else {
+ if(attr_longest_match(attr_mapping_rel2poly_place, attr_mapping_rel2poly_place_count, type, 1)) {
+ tmp_item_bin->type=*type;
+ } else {
+ *type=type_none;
+ /* do not touch tmp_item_bin->type in this case, as it may be already set! For example
+ * indicating the turn restrictions */
+ //tmp_item_bin->type=*type;
+ }
+ if ((!g_strcmp0(relation_type, "multipolygon") || !g_strcmp0(relation_type, "boundary"))
+ && (boundary || *type!=type_none)) {
+ item_bin_write(tmp_item_bin, osm->boundaries);
+ }
+ }
+}
void osm_end_relation(struct maptool_osm *osm) {
enum item_type type;
in_relation=0;
-
- if(attr_longest_match(attr_mapping_rel2poly_place, attr_mapping_rel2poly_place_count, &type, 1)) {
- tmp_item_bin->type=type;
- } else
- type=type_none;
-
- if ((!g_strcmp0(relation_type, "multipolygon") || !g_strcmp0(relation_type, "boundary"))
- && (boundary || type!=type_none)) {
- item_bin_write(tmp_item_bin, osm->boundaries);
- }
+ /* sets tmp_item_bin type and other fields */
+ osm_end_relation_multipolygon (osm, &type);
if (!g_strcmp0(relation_type, "restriction") && (tmp_item_bin->type == type_street_turn_restriction_no
|| tmp_item_bin->type == type_street_turn_restriction_only))
@@ -1667,6 +1687,8 @@ static void relation_add_tag(char *k, char *v) {
}
} else if (!g_strcmp0(k,"ISO3166-1") || !g_strcmp0(k,"ISO3166-1:alpha2")) {
g_strlcpy(iso_code, v, sizeof(iso_code));
+ } else if (! g_strcmp0(k,"name")) {
+ attr_strings_save(attr_string_label, v);
}
if (add_tag) {
char *tag;
@@ -1740,8 +1762,6 @@ void osm_end_way(struct maptool_osm *osm) {
add_flags=0;
if (types[i] == type_none)
continue;
- if (ignore_unknown && (types[i] == type_street_unkn || types[i] == type_point_unkn))
- continue;
if (types[i] != type_street_unkn) {
if(types[i]<type_area)
count_lines++;
@@ -1831,8 +1851,6 @@ void osm_end_node(struct maptool_osm *osm) {
for (i = 0 ; i < count ; i++) {
if (types[i] == type_none)
continue;
- if (ignore_unknown && (types[i] == type_street_unkn || types[i] == type_point_unkn))
- continue;
item_bin=init_item(types[i]);
if (item_is_town(*item_bin) && attr_strings[attr_string_population])
item_bin_set_type_by_population(item_bin, atoi(attr_strings[attr_string_population]));
@@ -2039,6 +2057,7 @@ static void osm_process_town_by_boundary_update_attrs(struct item_bin *town, str
case 'M':
/* Here we patch the boundary itself to convert it to town polygon later*/
b->ib->type=type_poly_place6;
+ /*fall through*/
case 'm':
attr_type=attr_municipality_name;
break;
@@ -2644,6 +2663,598 @@ void process_house_number_interpolations(FILE *in, struct files_relation_process
g_list_free(fp.allocations);
}
+struct multipolygon {
+ osmid relid;
+ struct item_bin * rel;
+ int inner_count;
+ int outer_count;
+ struct item_bin ** inner;
+ struct item_bin ** outer;
+};
+
+/**
+ * @brief find the nect matching polygon segment
+ * This can be used to find the next matching "line" to form a polygon.
+ * @param part current line part
+ * @param part_used how this part was used
+ * @param in_count number of lines passed in parts
+ * @parts array of item_bin pointers giving the single parts
+ * @parts used int array, one for each part, indicating wheather the part was already used. This
+ * function sets the usage for the mathcing part if one is found. Usage is 0: not used,
+ * 1: used forward 2: used reverse
+ * @returns: index of matching part, -1 if none matches or all are consumed already.
+ */
+static int process_multipolygons_find_match(struct item_bin* part,int part_used, int in_count, struct item_bin **parts,
+ int*used) {
+ int i;
+ struct coord * coord;
+ /*get the actual ending coordinate of the sequence*/
+ coord=(struct coord *)(part +1);
+ if(part_used == 1) {
+ /* was a standard match. Need last coordinate */
+ coord+=(part->clen / 2) - 1;
+ }
+ for(i=0; i < in_count; i ++) {
+ if(!used[i]) {
+ int have_match = 0;
+ struct coord *try_first, *try_last;
+
+ if(parts[i]->clen < 2) {
+ //fprintf(stderr,"skipping single point");
+ used[i] = 1;
+ continue;
+ }
+
+ try_first=(struct coord *)(parts[i] +1);
+ try_last=(struct coord *)(parts[i] +1);
+ try_last+=(parts[i]->clen / 2) - 1;
+ //fprintf(stderr, "0x%x,0x%x try_first[%d] 0x%x,0x%x try_last[%d] 0x%x,0x%x\n",coord->x, coord->y,i,try_first->x,
+ // try_first->y, i, try_last->x,
+ // try_last->y);
+
+ if((coord->x == try_first->x) && (coord->y == try_first->y)) {
+ /* forward match */
+ have_match=1;
+ } else if((coord->x == try_last->x) && (coord->y == try_last->y)) {
+ /* reverse match */
+ have_match=2;
+ }
+ /* add match to sequence */
+ if(have_match) {
+ used[i]=have_match;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static int is_loop (struct item_bin * start_part, int start_used, struct item_bin * end_part, int end_used) {
+ struct coord *first, *last;
+ /*get the actual starting coordinate of the sequence*/
+ first=(struct coord *)(start_part +1);
+ if(start_used != 1) {
+ /* was a reverse match. Need first coordinate */
+ first+=(start_part->clen / 2) - 1;
+ }
+
+ /*get the actual ending coordinate of the sequence*/
+ last=(struct coord *)(end_part +1);
+ if(end_used == 1) {
+ /* was a standard match. Need last coordinate */
+ last+=(end_part->clen / 2) - 1;
+ }
+ if((first->x == last->x) && (first->y == last->y))
+ return 1;
+ return 0;
+}
+
+static int process_multipolygons_find_loop(int in_count, struct item_bin ** parts, int* sequence, int * used) {
+ int a;
+ int sequence_count=0;
+ /* assume we already have the sequence array*/
+
+ /* to start find a unused part */
+ for(a=0; a < in_count; a ++) {
+ if(!used[a])
+ break;
+ }
+ if(!(a < in_count)) {
+ /* got no unused part. indicate no more loops possible */
+ return -1;
+ }
+ /* consume this part */
+ used[a] = 1;
+ sequence[sequence_count]=a;
+ sequence_count ++;
+
+ /* check all parts until no more matches, or a loop is found */
+ while(!is_loop (parts[sequence[0]], used[sequence[0]], parts[sequence[sequence_count-1]],
+ used[sequence[sequence_count-1]])) {
+ int match;
+ /* get new mathching part */
+ match=process_multipolygons_find_match(parts[sequence[sequence_count-1]],used[sequence[sequence_count-1]], in_count,
+ parts, used);
+ if(match >= 0) {
+ sequence[sequence_count]=match;
+ sequence_count ++;
+ } else {
+ break;
+ }
+ }
+
+ /* check if this is a loop already */
+ if(is_loop (parts[sequence[0]], used[sequence[0]], parts[sequence[sequence_count-1]], used[sequence[sequence_count-1]]))
+ return sequence_count;
+ else
+ return 0;
+}
+
+static int process_multipolygons_find_loops(osmid relid, int in_count, struct item_bin ** parts, int **scount,
+ int *** sequences,
+ int **direction) {
+ int done=0;
+ int loop_count=0;
+ int *used;
+ if((in_count == 0) || (parts == NULL) || (sequences == NULL) || (scount == NULL))
+ return 0;
+ //fprintf(stderr,"find loops in %d parts\n",in_count);
+ /* start with nothing */
+ *sequences = NULL;
+ *scount = NULL;
+ *direction = NULL;
+ /* allocate the usage and direction array.*/
+ used=g_malloc0(in_count * sizeof(int));
+ do {
+ int sequence_count;
+ int * sequence = g_malloc0(in_count * sizeof(int));
+ sequence_count = process_multipolygons_find_loop(in_count, parts, sequence, used);
+ if(sequence_count < 0) {
+ done = 1;
+ } else if(sequence_count == 0) {
+ osm_warning("relation",relid,0,"multipolygon: skipping non loop sequence\n");
+ /* skip empty sequence */
+ g_free(sequence);
+ } else {
+ /* increase space for sequences */
+ (*scount)=(int*) g_realloc((*scount), (loop_count +1) * sizeof(int));
+ (*sequences)=(int**) g_realloc((*sequences), (loop_count +1) * sizeof(int*));
+ /* hook it in */
+ (*scount)[loop_count] = sequence_count;
+ (*sequences)[loop_count] = sequence;
+ loop_count ++;
+ }
+ } while (!done);
+ //fprintf(stderr,"found %d loops\n", loop_count);
+ *direction = used;
+ return loop_count;
+}
+
+static int process_multipolygons_loop_dump(struct item_bin** bin, int scount, int*sequence, int*direction,
+ struct coord * buffer) {
+ int points = 0;
+ int a;
+
+ if((bin == NULL) || (scount <= 0) || (sequence == NULL))
+ return 0;
+
+ for(a=0; a < scount; a++) {
+ int pcount;
+ struct coord * c;
+ c= (struct coord *) (bin[sequence[a]] + 1);
+ pcount= bin[sequence[a]]->clen / 2;
+
+ /* remove the duplicate point if not the first one */
+ if(a!=0)
+ pcount --;
+ if((buffer != NULL) && (direction !=NULL)) {
+ if(direction[sequence[a]] == 1) {
+ memcpy(&(buffer[points]), c, pcount * sizeof(struct coord));
+ } else {
+ int b;
+ struct coord * target = &(buffer[points]);
+ //fprintf(stderr,"R:");
+ for (b=0; b < pcount; b ++) {
+ target[b] = c[(bin[sequence[a]]->clen / 2) - b -1];
+ }
+ }
+ }
+ //if(buffer !=NULL) {
+ // fprintf(stderr, "%d (%x, %x)-%d-(%x, %x)\n",sequence[a], buffer[points].x, buffer[points].y, pcount, buffer[points+pcount-1].x, buffer[points+pcount-1].y);
+ //}
+ points += pcount;
+ }
+ return points;
+}
+
+/**
+ * @brief get number of coordinates inside a sequence calculated by process_multipolygon_find_loop
+ *
+ * @param bin the array of all raw members of this multipolygon
+ * @param scount number of members inside this sequence
+ * @param sequence sequence calculated by process_multipolygon_find_loop
+ * @returns number of coords
+ */
+static int process_multipolygons_loop_count(struct item_bin** bin, int scount, int*sequence) {
+ return process_multipolygons_loop_dump(bin,scount,sequence,NULL,NULL);
+}
+
+static inline void dump_sequence(const char * string, int loop_count, int*scount, int**sequences, int*direction) {
+#if 0
+ int i;
+ int j;
+ for(j=0; j<loop_count; j++) {
+ fprintf(stderr,"loop %s :",string);
+ for(i=0; i < scount[j]; i ++) {
+ fprintf(stderr, "%s", (direction[sequences[j][i]]== 1)? "":"R");
+ fprintf(stderr, "%d ", sequences[j][i]);
+ }
+ fprintf(stderr, "\n");
+ }
+#endif
+}
+
+static void process_multipolygons_finish(GList *tr, FILE *out) {
+ GList *l=tr;
+ //fprintf(stderr,"process_multipolygons_finish\n");
+ while(l) {
+ int a;
+ int b;
+ struct multipolygon *multipolygon=l->data;
+ int inner_loop_count=0;
+ int *inner_scount=NULL;
+ int *inner_direction=NULL;
+ int **inner_sequences=NULL;
+ int outer_loop_count=0;
+ int *outer_scount=NULL;
+ int *outer_direction=NULL;
+ int **outer_sequences=NULL;
+ /* combine outer to full loops */
+ outer_loop_count = process_multipolygons_find_loops(multipolygon->relid, multipolygon->outer_count,multipolygon->outer,
+ &outer_scount,
+ &outer_sequences, &outer_direction);
+
+ /* combine inner to full loops */
+ inner_loop_count = process_multipolygons_find_loops(multipolygon->relid, multipolygon->inner_count,multipolygon->inner,
+ &inner_scount,
+ &inner_sequences, &inner_direction);
+
+ dump_sequence("outer",outer_loop_count, outer_scount, outer_sequences, outer_direction);
+ dump_sequence("inner",inner_loop_count, inner_scount, inner_sequences, inner_direction);
+
+
+ for(b=0; b<outer_loop_count; b++) {
+ struct rect outer_bbox;
+ /* write out */
+ struct item_bin* ib=tmp_item_bin;
+ int outer_length;
+ struct coord * outer_buffer;
+ if(outer_loop_count == 0) {
+ fprintf(stderr,"unresolved outer %lld\n", multipolygon->relid);
+ /* seems this polygons "outer" could not be resolved. Skip it */
+ l = g_list_next(l);
+ continue;
+ }
+ //long long relid=item_bin_get_relationid(multipolygon->rel);
+ //fprintf(stderr,"process %lld\n", relid);
+ outer_length = process_multipolygons_loop_count(multipolygon->outer, outer_scount[b],
+ outer_sequences[b]) * sizeof(struct coord);
+ outer_buffer = (struct coord *) g_malloc0(outer_length);
+ outer_length = process_multipolygons_loop_dump(multipolygon->outer, outer_scount[b], outer_sequences[b],
+ outer_direction, outer_buffer);
+ item_bin_init(ib,multipolygon->rel->type);
+ item_bin_add_coord(ib, outer_buffer, outer_length);
+ g_free(outer_buffer);
+ item_bin_copy_attr(ib,multipolygon->rel,attr_osm_relationid);
+ item_bin_copy_attr(ib,multipolygon->rel,attr_label);
+ /*calculate bbox*/
+ bbox((struct coord*)(ib +1), (ib->clen/2), &outer_bbox);
+
+ for(a = 0; a < inner_loop_count; a ++) {
+ int d;
+ int hole_len;
+ char * buffer;
+ int used =0;
+ int inner_len =0;
+ int inside = 0;
+ struct coord *hole_coord;
+ hole_len = process_multipolygons_loop_count(multipolygon->inner, inner_scount[a], inner_sequences[a]);
+ inner_len = (hole_len * sizeof(struct coord));
+ inner_len+=4;
+ buffer=g_malloc0(inner_len);
+ memcpy(&(buffer[used]), &(hole_len), sizeof(int));
+ used += sizeof(int);
+ hole_coord = (struct coord*) &(buffer[used]);
+ used += process_multipolygons_loop_dump(multipolygon->inner, inner_scount[a], inner_sequences[a], inner_direction,
+ (struct coord *)&(buffer[used])) * sizeof(struct coord);
+ /* check if at least one point is inside the outer */
+ for(d=0; d < hole_len; d++)
+ if(bbox_contains_coord(&outer_bbox,hole_coord))
+ inside=1;
+
+ if(inside)
+ item_bin_add_attr_data(ib, attr_poly_hole, buffer, inner_len);
+ g_free(buffer);
+ }
+ item_bin_write(ib, out);
+ }
+ /* just for fun...*/
+ processed_relations ++;
+ /* clean up the sequences */
+ for(a=0; a < outer_loop_count; a ++)
+ g_free (outer_sequences[a]);
+ g_free(outer_sequences);
+ g_free(outer_scount);
+ g_free(outer_direction);
+ for(a=0; a < inner_loop_count; a ++)
+ g_free (inner_sequences[a]);
+ g_free(inner_sequences);
+ g_free(inner_scount);
+ g_free(inner_direction);
+ /* clean up this item */
+ for (a=0; a < multipolygon->inner_count; a ++)
+ g_free(multipolygon->inner[a]);
+ g_free(multipolygon->inner);
+ for (a=0; a < multipolygon->outer_count; a ++)
+ g_free(multipolygon->outer[a]);
+ g_free(multipolygon->outer);
+ g_free(multipolygon->rel);
+ g_free(multipolygon);
+ /* next item */
+ l = g_list_next(l);
+ }
+ /* done with that list. All items referred should be deleted already. */
+ g_list_free(tr);
+}
+
+static void process_multipolygons_member(void *func_priv, void *relation_priv, struct item_bin *member,
+ void *member_priv) {
+ int type=(long)member_priv;
+ int * dup;
+ struct multipolygon *multipolygon=relation_priv;
+ dup=item_bin_get_attr(member,attr_duplicate,NULL);
+ if(dup != NULL) {
+ //fprintf(stderr,"skip duplicate \n");
+ return;
+ }
+ //fprintf(stderr,"process_multipolygons_member id %lld, %s, outer %d, inner %d\n", multipolygon->relid,
+ // (type)?"inner": "outer", multipolygon->outer_count, multipolygon->inner_count);
+ /* we remeber the whole binary item, as we may want to have the attributes later on finalize */
+ if(type) {
+ /* copy the member as inner */
+ multipolygon->inner=(struct item_bin**) g_realloc(multipolygon->inner,
+ sizeof(struct item_bin *) * (multipolygon->inner_count +1));
+ multipolygon->inner[multipolygon->inner_count]=item_bin_dup(member);
+ multipolygon->inner_count ++;
+ } else {
+ /* copy the member as outer */
+ multipolygon->outer=(struct item_bin**) g_realloc(multipolygon->outer,
+ sizeof(struct item_bin *) * (multipolygon->outer_count +1));
+ multipolygon->outer[multipolygon->outer_count]=item_bin_dup(member);
+ multipolygon->outer_count ++;
+ }
+ processed_ways ++;
+}
+
+/**
+ * @brief prepare one multipolygon relation for relattion processing
+ *
+ * @param ib the relation
+ * @param relations the relation processing structure
+ * @param relations_func function to use for the members
+ * @param multipolygons write the resulting multipolygons to the list
+ */
+static void process_multipolygons_setup_one(struct item_bin * ib, struct relations * relations,
+ struct relations_func * relations_func, GList ** multipolygons) {
+ if(ib != NULL) {
+ struct relation_member *outer=NULL;
+ int outer_count=0;
+ struct relation_member *inner=NULL;;
+ int inner_count=0;
+ long long relid;
+ int a;
+ int min_count;
+ struct multipolygon *p_multipolygon;
+ relid=item_bin_get_relationid(ib);
+ min_count=0;
+ /* allocate a slot for inner and outer */
+ outer = g_malloc0(sizeof(struct relation_member));
+ inner = g_malloc0(sizeof(struct relation_member));
+ while(search_relation_member(ib, "outer",&(outer[outer_count]),&min_count)) {
+ if(outer[outer_count].type != rel_member_way)
+ osm_warning("relation",relid,0,"multipolygon: wrong type for outer member\n");
+ outer_count ++;
+ /*realloc outer to make space for next */
+ outer = g_realloc(outer, sizeof(struct relation_member) * (outer_count +1));
+ }
+ min_count=0;
+ while(search_relation_member(ib, "inner",&(inner[inner_count]),&min_count)) {
+ if(inner[inner_count].type != rel_member_way)
+ osm_warning("relation",relid,0,"multipolygon: wrong type for inner member\n");
+ inner_count ++;
+ /*realloc inner to make space for next */
+ inner = g_realloc(inner, sizeof(struct relation_member) * (inner_count +1));
+ }
+ //fprintf(stderr,"Relid %lld: Got %d outer and %d inner\n", relid, outer_count, inner_count);
+ if(outer_count == 0) {
+ osm_warning("relation",relid,0,"multipolygon: missing outer member\n");
+ } else {
+ p_multipolygon=g_new0(struct multipolygon, 1);
+ p_multipolygon->relid=relid;
+ p_multipolygon->rel=item_bin_dup(ib);
+ for (a = 0; a < outer_count; a ++)
+ relations_add_relation_member_entry(relations, relations_func, p_multipolygon, (gpointer) 0, outer[a].type,
+ outer[a].id);
+ for (a = 0; a < inner_count; a ++)
+ relations_add_relation_member_entry(relations, relations_func, p_multipolygon, (gpointer) 1, inner[a].type,
+ inner[a].id);
+ *multipolygons=g_list_append(*multipolygons, p_multipolygon);
+ }
+ /* clean up*/
+ g_free(inner);
+ g_free(outer);
+ }
+}
+
+/**
+ * @brief worker thread private storage
+ */
+struct process_multipolygon_setup_thread {
+ int number;
+ GAsyncQueue * queue;
+ struct relations * relations;
+ struct relations_func * relations_func;
+ GList* multipolygons;
+ GThread * thread;
+};
+
+/**
+ * @brief dummy memory location to pass a end condition to worker threads, as NULL cannot be passed.
+ */
+static struct item_bin killer;
+
+/**
+ * @brief multipolygons setup worker thread.
+ *
+ * This thread processes any item passed to it via async queue into it's local relations
+ * function.
+ * @param data this threads local storage
+ */
+static gpointer process_multipolygons_setup_worker (gpointer data) {
+ struct item_bin * ib;
+ //long long relid;
+ struct process_multipolygon_setup_thread * me = (struct process_multipolygon_setup_thread*) data;
+ fprintf(stderr,"worker %d up\n", me->number);
+ while((ib=g_async_queue_pop (me->queue)) != &killer) {
+ processed_relations ++;
+ //relid=item_bin_get_relationid(ib);
+ //fprintf(stderr,"worker %d processing %lld\n", me->number, relid);
+ process_multipolygons_setup_one(ib, me->relations, me->relations_func, &(me->multipolygons));
+ /* done with that. Free the item_bin */
+ g_free(ib);
+ }
+ fprintf(stderr,"worker %d exit\n", me->number);
+ g_thread_exit(NULL);
+ return NULL;
+}
+
+/**
+ * @brief prepare multipolygon way matching
+ *
+ * This function reads all multipolygon relations and prepares relations structures
+ * for later way matching. Since this scales quite ugly, (O^3) i think, we use multiple threads
+ * creating their own hash each. This way none of the hashes get's that big, and we can utilize
+ * more cpu power.
+ *
+ * @param in file containing the relations
+ * @param thread_count number of threads to use
+ * @param relations array of preallocated relations structures. One per thread.
+ *
+ * @returns array of GLists. One per thread containing the resulting structures.
+ */
+static GList ** process_multipolygons_setup(FILE *in, int thread_count, struct relations **relations) {
+ struct process_multipolygon_setup_thread *sthread;
+
+ struct item_bin *ib;
+ struct relations_func *relations_func;
+ int i;
+ GList **multipolygons=NULL;
+ /* allocate and reference async queue */
+ GAsyncQueue * ib_queue=g_async_queue_new ();
+ g_async_queue_ref(ib_queue);
+ /* allocate per thread storage */
+ sthread=g_malloc0(sizeof(struct process_multipolygon_setup_thread) * thread_count);
+
+ fseek(in, 0, SEEK_SET);
+ relations_func=relations_func_new(process_multipolygons_member, NULL);
+
+ /* start the threads */
+ for(i=0; i < thread_count; i ++) {
+ sthread[i].number = i;
+ sthread[i].queue = ib_queue;
+ sthread[i].relations_func = relations_func;
+ sthread[i].relations = relations[i];
+ sthread[i].multipolygons = NULL;
+ sthread[i].thread = g_thread_new ("process_multipolygons_setup_worker", process_multipolygons_setup_worker,
+ &(sthread[i]));
+ }
+
+ while ((ib=read_item(in))) {
+ /* get a duplicate of the returned item, as the one returned shares buffer */
+ struct item_bin * dup = item_bin_dup(ib);
+ //long long relid;
+ //relid=item_bin_get_relationid(dup);
+ //fprintf(stderr,"Pushing %lld\n", relid);
+ /* the dup's will be freed by the thread processing them*/
+ g_async_queue_push(ib_queue,dup);
+ /* limit queue size. This is ugly, but since GAsyncQueue doesn't support
+ * push to block when the queue reached a decent size, I help myself
+ * with this ugly hack */
+ while(g_async_queue_length(ib_queue) > 1000)
+ usleep(200);
+ }
+
+ /* stop iand join all remaining threads */
+ for(i = 0; i < thread_count; i ++)
+ g_async_queue_push(ib_queue,&killer);
+ for(i=0; i < thread_count; i ++)
+ g_thread_join(sthread[i].thread);
+
+ /* rescue the resulting glist */
+ multipolygons = g_malloc0(sizeof(GList *) * thread_count);
+ for(i =0; i < thread_count; i ++)
+ multipolygons[i]=sthread[i].multipolygons;
+
+ /* free the thread storage */
+ g_free(sthread);
+
+ /* release the queue */
+ g_async_queue_unref(ib_queue);
+
+ /* return the list of multipolygons */
+ return multipolygons;
+}
+
+void process_multipolygons(FILE *in, FILE *coords, FILE *ways, FILE *ways_index, FILE *out) {
+ /* thread count is from maptool.c as commandline parameter */
+ int i;
+ struct relations **relations;
+ GList **multipolygons = NULL;
+ sig_alrm(0);
+
+ relations = g_malloc0(sizeof(struct relations *) * thread_count);
+ for(i=0; i < thread_count; i ++)
+ relations[i] = relations_new();
+ fseek(in, 0, SEEK_SET);
+ fprintf(stderr,"process_multipolygons:setup (threads %d)\n", thread_count);
+ multipolygons=process_multipolygons_setup(in,thread_count,relations);
+ /* Here we get an array of resulting relations structures and resultin
+ * GLists.
+ * Of course we need to iterate the ways multiple times, but that's fast
+ * compared to hashing the relations structures
+ * This even saves a lot of main memory, as we can process every result from
+ * every thread at once completely. Since we know it's self containing
+ */
+ sig_alrm(0);
+ processed_relations=0;
+ processed_ways=0;
+ sig_alrm(0);
+ for( i=0; i < thread_count; i ++) {
+ if(coords)
+ fseek(coords, 0,SEEK_SET);
+ if(ways)
+ fseek(ways, 0,SEEK_SET);
+ fprintf(stderr,"process_multipolygons:process (thread %d)\n", i);
+ relations_process(relations[i], coords, ways);
+ fprintf(stderr,"process_multipolygons:finish (thread %d)\n", i);
+ process_multipolygons_finish(multipolygons[i], out);
+ relations_destroy(relations[i]);
+ }
+ g_free(relations);
+ sig_alrm(0);
+ sig_alrm_end();
+}
+
struct turn_restriction {
osmid relid;
enum item_type type;