diff options
Diffstat (limited to 'map/garmin/garmin.c')
-rw-r--r-- | map/garmin/garmin.c | 997 |
1 files changed, 997 insertions, 0 deletions
diff --git a/map/garmin/garmin.c b/map/garmin/garmin.c new file mode 100644 index 00000000..da0f5804 --- /dev/null +++ b/map/garmin/garmin.c @@ -0,0 +1,997 @@ +/* + Copyright (C) 2007 Alexander Atanasov <aatanasov@gmail.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA + + Garmin and MapSource are registered trademarks or trademarks + of Garmin Ltd. or one of its subsidiaries. + +*/ + +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include "config.h" +#include "plugin.h" +#include "data.h" +#include "projection.h" +#include "item.h" +#include "debug.h" +#include "map.h" +#include "maptype.h" +#include "attr.h" +#include "coord.h" +#include "transform.h" +#include <stdio.h> +#include "attr.h" +#include "coord.h" +#include <libgarmin.h> +#include "garmin.h" +#include "gar2navit.h" + + +static int map_id; + +struct map_priv { + int id; + char *filename; + struct gar2nav_conv *conv; + struct gar *g; +}; + +struct map_rect_priv { + int id; + struct coord_rect r; + char *label; // FIXME: Register all strings for searches + int limit; + struct map_priv *mpriv; + struct gmap *gmap; + struct gobject *cobj; + struct gobject *objs; + struct item item; + unsigned int last_coord; + void *last_itterated; + struct coord last_c; + void *last_oattr; + unsigned int last_attr; + struct gar_search *search; +}; + +int garmin_debug = 10; + +void +logfn(char *file, int line, int level, char *fmt, ...) +{ + va_list ap; + char fileline[256]; + int sz; + if (level > garmin_debug) + return; + va_start(ap, fmt); + sz = sprintf(fileline, "%s:%d:%d|", file, line, level); + debug_vprintf(0, "", strlen(""), fileline, sz, + 1, fmt, ap); + va_end(ap); +} +// need a base map and a map +struct gscale { + char *label; + float scale; + int bits; +}; + +static struct gscale mapscales[] = { + {"7000 km", 70000.0, 8} + ,{"5000 km", 50000.0, 8} + ,{"3000 km", 30000.0, 9} + ,{"2000 km", 20000.0, 9} + ,{"1500 km", 15000.0, 10} + ,{"1000 km", 10000.0, 10} + ,{"700 km", 7000.0, 11} + ,{"500 km", 5000.0, 11} + ,{"300 km", 3000.0, 13} + ,{"200 km", 2000.0, 13} + ,{"150 km", 1500.0, 13} + ,{"100 km", 1000.0, 14} + ,{"70 km", 700.0, 15} + ,{"50 km", 500.0, 16} + ,{"30 km", 300.0, 16} + ,{"20 km", 200.0, 17} + ,{"15 km", 150.0, 17} + ,{"10 km", 100.0, 18} + ,{"7 km", 70.0, 18} + ,{"5 km", 50.0, 19} + ,{"3 km", 30.0, 19} + ,{"2 km", 20.0, 20} + ,{"1.5 km", 15.0, 22} + ,{"1 km", 10.0, 24} + ,{"700 m", 7.0, 24} + ,{"500 m", 5.0, 24} + ,{"300 m", 3.0, 24} + ,{"200 m", 2.0, 24} + ,{"150 m", 1.5, 24} + ,{"100 m", 1.0, 24} + ,{"70 m", 0.7, 24} + ,{"50 m", 0.5, 24} + ,{"30 m", 0.3, 24} + ,{"20 m", 0.2, 24} + ,{"15 m", 0.1, 24} + ,{"10 m", 0.15, 24} +}; + + +static int +garmin_object_label(struct gobject *o, struct attr *attr) +{ + struct map_rect_priv *mr = o->priv_data; + char *codepage; + char *label; + if (!mr) { + dlog(1, "Error object do not have priv_data!!\n"); + return 0; + } + if (mr->label) { + free(mr->label); + } + label = gar_get_object_lbl(o); + if (label) { + codepage = gar_obj_codepage(o); + if (*codepage != 'a') { + mr->label = g_convert(label, -1,"utf-8",codepage,NULL,NULL,NULL); + free(label); + } else + mr->label = label; + } else { + mr->label = NULL; + return 0; + } + if (mr->label) { + char *cp = mr->label; +#warning FIXME Process label and give only the visible part + if (*mr->label == '@' || *mr->label == '^') + cp++; + /* FIXME: If zoomlevel is high convert ^ in the string to spaces */ + attr->u.str = cp; + return 1; + } + return 0; +} + +static int +garmin_object_debug(struct gobject *o, struct attr *attr) +{ + struct map_rect_priv *mr = o->priv_data; + if (!mr) { + dlog(1, "Error object do not have priv_data!!\n"); + return 0; + } + if (mr->label) + free(mr->label); + mr->label = gar_object_debug_str(o); + if (mr->label) { + attr->u.str = mr->label; + return 1; + } + return 0; +} + + +static struct map_search_priv * +gmap_search_new(struct map_priv *map, struct item *item, struct attr *search, int partial) +{ + struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1); + struct gar_search *gs; + int rc; + + dlog(1, "Called!\n"); + mr->mpriv=map; + gs = g_new0(struct gar_search,1); + if (!gs) { + dlog(1, "Can not init search \n"); + free(mr); + return NULL; + } + mr->search = gs; + switch (search->type) { + case attr_country_name: + gs->type = GS_COUNTRY; + break; + case attr_town_name: + gs->type = GS_CITY; + break; + case attr_town_postal: + gs->type = GS_ZIP; + break; + case attr_street_name: + gs->type = GS_ROAD; + break; +#if someday + case attr_region_name: + case attr_intersection: + case attr_housenumber: +#endif + default: + dlog(1, "Don't know how to search for %d\n", search->type); + goto out_err; + } + gs->match = partial ? GM_START : GM_EXACT; + gs->needle = strdup(search->u.str); + dlog(5, "Needle: %s\n", gs->needle); + + mr->gmap = gar_find_subfiles(mr->mpriv->g, gs, GO_GET_SEARCH); + if (!mr->gmap) { + dlog(1, "Can not init search \n"); + goto out_err; + } + rc = gar_get_objects(mr->gmap, 0, gs, &mr->objs, GO_GET_SEARCH); + if (rc < 0) { + dlog(1, "Error loading objects\n"); + goto out_err; + } + mr->cobj = mr->objs; + dlog(4, "Loaded %d objects\n", rc); + return (struct map_search_priv *)mr; + +out_err: + free(gs); + free(mr); + return NULL; +} + +/* Assumes that only one item will be itterated at time! */ +static void +coord_rewind(void *priv_data) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + mr->last_coord = 0; +}; + +static void +attr_rewind(void *priv_data) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + mr->last_attr = 0; +}; + +static int +point_coord_get(void *priv_data, struct coord *c, int count) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + struct gcoord gc; + if (!count) + return 0; + if (g != mr->last_itterated) { + mr->last_itterated = g; + mr->last_coord = 0; + } + + if (mr->last_coord > 0) + return 0; + + gar_get_object_coord(mr->gmap, g, &gc); + c->x = gc.x; + c->y = gc.y; + mr->last_coord++; +// dlog(1,"point: x=%d y=%d\n", c->x, c->y); + // dlog(1, "point: x=%f y=%f\n", GARDEG(c->x), GARDEG(c->y)); + return 1; +} + +static int +coord_is_node(void *priv_data) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + + return gar_is_object_dcoord_node(mr->gmap, g, mr->last_coord); +} + +static int +poly_coord_get(void *priv_data, struct coord *c, int count) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + int ndeltas = 0, total = 0; + struct gcoord dc; + + if (!count) + return 0; + + if (g != mr->last_itterated) { + mr->last_itterated = g; + mr->last_coord = 0; + } + ndeltas = gar_get_object_deltas(g); + if (mr->last_coord > ndeltas + 1) + return 0; + while (count --) { + if (mr->last_coord == 0) { + gar_get_object_coord(mr->gmap, g, &dc); + mr->last_c.x = dc.x; + mr->last_c.y = dc.y; + } else { + if (!gar_get_object_dcoord(mr->gmap, g, mr->last_coord - 1, &dc)) { + mr->last_coord = ndeltas + 2; + return total; + } + mr->last_c.x += dc.x; + mr->last_c.y += dc.y; + } + c->x = mr->last_c.x; + c->y = mr->last_c.y; + ddlog(1, "poly: x=%f y=%f\n", GARDEG(c->x), GARDEG(c->y)); +// dlog(1,"poly: x=%d y=%d\n", c->x, c->y); + c++; + total++; + mr->last_coord ++; + } + return total; +} + +// for _any we must return one by one +static int +point_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + int rc; + switch (attr_type) { + case attr_any: + if (g != mr->last_oattr) { + mr->last_oattr = g; + mr->last_attr = 0; + } + switch(mr->last_attr) { + case 0: + mr->last_attr++; + attr->type = attr_label; + rc = garmin_object_label(g, attr); + if (rc) + return rc; + case 1: + mr->last_attr++; + attr->type = attr_debug; + rc = garmin_object_debug(g, attr); + if (rc) + return rc; + case 2: + mr->last_attr++; + if (g->type == GO_POLYLINE) { + attr->type = attr_street_name; + rc = garmin_object_label(g, attr); + if (rc) + return rc; + } + case 3: + mr->last_attr++; + attr->type = attr_flags; + attr->u.num = 0; + rc = gar_object_flags(g); + if (rc & F_ONEWAY) + attr->u.num |= AF_ONEWAY; + if (rc & F_SEGMENTED) + attr->u.num |= AF_SEGMENTED; + return 1; + default: + return 0; + } + break; + case attr_label: + attr->type = attr_label; + return garmin_object_label(g, attr); + case attr_town_name: + attr->type = attr_town_name; + return garmin_object_label(g, attr); + case attr_street_name: + attr->type = attr_type; + return garmin_object_label(g, attr); + case attr_street_name_systematic: + /* TODO: Get secondary labels of roads */ + return 0; + case attr_flags: + attr->type = attr_flags; + attr->u.num = 0; + rc = gar_object_flags(g); + if (rc & F_ONEWAY) + attr->u.num |= AF_ONEWAY; + if (rc & F_SEGMENTED) + attr->u.num |= AF_SEGMENTED; + return 1; + default: + dlog(1, "Dont know about attribute %d[%04X]=%s yet\n", attr_type,attr_type, attr_to_name(attr_type)); + } + + return 0; +} + +static struct item_methods methods_garmin_point = { + coord_rewind, + point_coord_get, + attr_rewind, + point_attr_get, +}; + +static struct item_methods methods_garmin_poly = { + coord_rewind, + poly_coord_get, + attr_rewind, // point_attr_rewind, + point_attr_get, // poly_attr_get, + coord_is_node, +}; + +static int +search_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + int rc; + switch (attr_type) { + case attr_any: + if (g != mr->last_oattr) { + mr->last_oattr = g; + mr->last_attr = 0; + } + switch(mr->last_attr) { + case 0: + mr->last_attr++; + attr->type = attr_label; + rc = garmin_object_label(g, attr); + if (rc) + return rc; + case 1: + mr->last_attr++; + attr->type = attr_debug; + rc = garmin_object_debug(g, attr); + if (rc) + return rc; + case 2: + mr->last_attr++; + if (g->type == GO_POLYLINE) { + attr->type = attr_street_name; + rc = garmin_object_label(g, attr); + if (rc) + return rc; + } + case 3: + mr->last_attr++; + attr->type = attr_flags; + attr->u.num = 0; + rc = gar_object_flags(g); + if (rc & F_ONEWAY) + attr->u.num |= AF_ONEWAY; + if (rc & F_SEGMENTED) + attr->u.num |= AF_SEGMENTED; + return 1; + default: + return 0; + } + break; + case attr_label: + attr->type = attr_label; + return garmin_object_label(g, attr); + case attr_town_name: + attr->type = attr_town_name; + if (mr->label) + free(mr->label); + mr->label = gar_srch_get_city(g); + attr->u.str = mr->label; + if (attr->u.str) + return 1; + return 0; + case attr_town_id: + rc = gar_srch_get_cityid(g); + if (rc) { + attr->type = attr_town_id; + attr->u.num = rc; + return 1; + } + return 0; + case attr_town_postal: + attr->type = attr_town_postal; + attr->u.str = gar_srch_get_zip(g); + if (attr->u.str) + return 1; + return 0; + case attr_street_name: + attr->type = attr_street_name; + if (mr->label) + free(mr->label); + mr->label = gar_srch_get_roadname(g); + attr->u.str = mr->label; + if (attr->u.str) + return 1; + return 0; + case attr_street_id: + attr->type = attr_street_id; + attr->u.num = gar_srch_get_roadid(g); + if (attr->u.num) + return 1; + return 0; + case attr_flags: + attr->type = attr_flags; + attr->u.num = 0; + rc = gar_object_flags(g); + if (rc & F_ONEWAY) + attr->u.num |= AF_ONEWAY; + if (rc & F_SEGMENTED) + attr->u.num |= AF_SEGMENTED; + return 1; + case attr_country_id: + rc = gar_srch_get_countryid(g); + if (rc) { + attr->type = attr_country_id; + attr->u.num = rc; + return 1; + } + return 0; + case attr_country_name: + attr->type = attr_country_name; + attr->u.str = gar_srch_get_country(g); + if (attr->u.str) + return 1; + return 0; + case attr_district_id: + rc = gar_srch_get_regionid(g); + if (rc) { + attr->type = attr_district_id; + attr->u.num = rc; + return 1; + } + return 0; + case attr_district_name: + attr->type = attr_district_name; + attr->u.str = gar_srch_get_region(g); + if (attr->u.str) + return 1; + return 0; + case attr_town_streets_item: + return 0; + default: + dlog(1, "Dont know about attribute %d[%04X]=%s yet\n", + attr_type,attr_type, attr_to_name(attr_type)); + } + + return 0; +} + +static int +search_coord_get(void *priv_data, struct coord *c, int count) +{ + struct gobject *g = priv_data; + struct map_rect_priv *mr = g->priv_data; + struct gcoord gc; + if (!count) + return 0; + if (g != mr->last_itterated) { + mr->last_itterated = g; + mr->last_coord = 0; + } + + if (mr->last_coord > 0) + return 0; + + if (gar_get_object_coord(mr->gmap, g, &gc)) { + c->x = gc.x; + c->y = gc.y; + mr->last_coord++; + return 1; + } + return 0; +} + +static struct item_methods methods_garmin_search = { + coord_rewind, + search_coord_get, + attr_rewind, + search_attr_get, +}; + + +static struct item * +garmin_poi2item(struct map_rect_priv *mr, struct gobject *o, unsigned short otype) +{ + if (mr->mpriv->conv) { + int mask = gar_object_group(o) << G2N_KIND_SHIFT; + mr->item.type = g2n_get_type(mr->mpriv->conv, G2N_POINT|mask, otype); + } + mr->item.meth = &methods_garmin_point; + return &mr->item; +} + +static struct item * +garmin_pl2item(struct map_rect_priv *mr, struct gobject *o, unsigned short otype) +{ + if (mr->mpriv->conv) { + int mask = gar_object_group(o) << G2N_KIND_SHIFT; + mr->item.type = g2n_get_type(mr->mpriv->conv, G2N_POLYLINE|mask, otype); + } + mr->item.meth = &methods_garmin_poly; + return &mr->item; +} + +static struct item * +garmin_pg2item(struct map_rect_priv *mr, struct gobject *o, unsigned short otype) +{ + if (mr->mpriv->conv) { + int mask = gar_object_group(o) << G2N_KIND_SHIFT; + mr->item.type = g2n_get_type(mr->mpriv->conv, G2N_POLYGONE|mask, otype); + } + mr->item.meth = &methods_garmin_poly; + return &mr->item; +} + +static struct item * +garmin_srch2item(struct map_rect_priv *mr, struct gobject *o, unsigned short otype) +{ + mr->item.type = type_country_label; + mr->item.meth = &methods_garmin_search; + return &mr->item; +} + +static struct item * +garmin_obj2item(struct map_rect_priv *mr, struct gobject *o) +{ + unsigned short otype; + otype = gar_obj_type(o); + mr->item.type = type_none; + switch (o->type) { + case GO_POINT: + return garmin_poi2item(mr, o, otype); + case GO_POLYLINE: + return garmin_pl2item(mr, o, otype); + case GO_POLYGON: + return garmin_pg2item(mr, o, otype); + case GO_ROAD: + return garmin_pl2item(mr, o, otype); +#if 0 + case GO_SEARCH: + return garmin_srch2item(mr, o, otype); +#endif + default: + dlog(1, "Unknown garmin object type:%d\n", + o->type); + } + return NULL; +} + +static struct item * +gmap_rect_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + struct gobject *o; + o = mr->objs = gar_get_object_by_id(mr->mpriv->g, id_hi, id_lo); + if (!o) { + dlog(1, "Can not find object\n"); + return NULL; + } + + mr->item.id_hi = id_hi; + mr->item.id_lo = id_lo; + mr->item.priv_data = o; + mr->item.type = type_none; + o->priv_data = mr; + if (!garmin_obj2item(mr, o)) + return NULL; + return &mr->item; +} + +static struct item * +gmap_rect_get_item(struct map_rect_priv *mr) +{ + struct gobject *o; + if (!mr->objs) + return NULL; + if (!mr->cobj) + return NULL; + // mr->cobj = mr->objs; + o = mr->cobj; +// dlog(1, "gi:o=%p\n", o); + mr->cobj = mr->cobj->next; + if (o) { + mr->item.id_hi = gar_object_mapid(o); + mr->item.id_lo = gar_object_index(o); + mr->item.priv_data = o; + mr->item.type = type_none; + o->priv_data = mr; + if (!garmin_obj2item(mr, o)) + return NULL; + return &mr->item; + } + return NULL; +} + +#define max(a,b) ((a) > (b) ? (a) : (b)) +struct nl2gl_t { + int g; + int bits; + char *descr; +}; + +struct nl2gl_t nl2gl_1[] = { + { /* 0 */ .g = 12, .descr = "0-120m", }, + { /* 1 */ .g = 11, .descr = "0-120m", }, + { /* 2 */ .g = 10, .descr = "0-120m", }, + { /* 3 */ .g = 9, .descr = "0-120m", }, + { /* 4 */ .g = 8, .descr = "0-120m", }, + { /* 5 */ .g = 7, .descr = "0-120m", }, + { /* 6 */ .g = 6, .descr = "0-120m", }, + { /* 7 */ .g = 5, .descr = "0-120m", }, + { /* 8 */ .g = 4, .descr = "0-120m", }, + { /* 9 */ .g = 4, .descr = "0-120m", }, + { /* 10 */ .g = 3, .descr = "0-120m", }, + { /* 11 */ .g = 3, .descr = "0-120m", }, + { /* 12 */ .g = 2, .descr = "0-120m", }, + { /* 13 */ .g = 2, .descr = "0-120m", }, + { /* 14 */ .g = 2, .descr = "0-120m", }, + { /* 15 */ .g = 1, .descr = "0-120m", }, + { /* 16 */ .g = 1, .descr = "0-120m", }, + { /* 17 */ .g = 1, .descr = "0-120m", }, + { /* 18 */ .g = 0, .descr = "0-120m", }, +}; + +struct nl2gl_t nl2gl[] = { + { /* 0 */ .g = 9, .descr = "0-120m", }, + { /* 1 */ .g = 9, .descr = "0-120m", }, + { /* 2 */ .g = 8, .descr = "0-120m", }, + { /* 3 */ .g = 8, .descr = "0-120m", }, + { /* 4 */ .g = 7, .descr = "0-120m", }, + { /* 5 */ .g = 7, .descr = "0-120m", }, + { /* 6 */ .g = 6, .descr = "0-120m", }, + { /* 7 */ .g = 6, .descr = "0-120m", }, + { /* 8 */ .g = 5, .descr = "0-120m", }, + { /* 9 */ .g = 5, .descr = "0-120m", }, + { /* 10 */ .g = 4, .descr = "0-120m", }, + { /* 11 */ .g = 4, .descr = "0-120m", }, + { /* 12 */ .g = 3, .descr = "0-120m", }, + { /* 13 */ .g = 3, .descr = "0-120m", }, + { /* 14 */ .g = 2, .descr = "0-120m", }, + { /* 15 */ .g = 2, .descr = "0-120m", }, + { /* 16 */ .g = 1, .descr = "0-120m", }, + { /* 17 */ .g = 1, .descr = "0-120m", }, + { /* 18 */ .g = 0, .descr = "0-120m", }, +}; + +static int +get_level(struct map_selection *sel) +{ + return sel->order; +} + +static int +garmin_get_selection(struct map_rect_priv *map, struct map_selection *sel) +{ + struct gar_rect r; + struct gmap *gm; + struct gobject **glast = NULL; + int rc; + int sl, el; + int level = 0; // 18; /* max level for maps, overview maps can have bigger + /* levels we do not deal w/ them + */ + int flags = 0; + if (sel && sel->range.min == type_street_0 && sel->range.max == type_ferry) { + // Get all roads + flags = GO_GET_ROUTABLE; + } else if (sel) + flags = GO_GET_SORTED; + + if (sel) { + r.lulat = sel->u.c_rect.lu.y; + r.lulong = sel->u.c_rect.lu.x; + r.rllat = sel->u.c_rect.rl.y; + r.rllong = sel->u.c_rect.rl.x; + level = get_level(sel); +// level = nl2gl[level].g; + dlog(2, "Looking level=%d for %f %f %f %f\n", + level, r.lulat, r.lulong, r.rllat, r.rllong); + } + gm = gar_find_subfiles(map->mpriv->g, sel ? &r : NULL, flags); + if (!gm) { + if (sel) { + dlog(1, "Can not find map data for the area: %f %f %f %f\n", + r.lulat, r.lulong, r.rllat, r.rllong); + } else { + dlog(1, "Can not find map data\n"); + } + return -1; + } +#if 0 + sl = (18-(gm->maxlevel - gm->minlevel))/2; + el = sl + (gm->maxlevel - gm->minlevel); + if (level < sl) + level = sl; + if (level > el) + level = el; + level = level - sl; + level = (gm->maxlevel - gm->minlevel) - level; + dlog(3, "sl=%d el=%d level=%d\n", sl, el, level); +#endif + sl = (18-gm->zoomlevels)/2; + el = sl + gm->zoomlevels; + if (level < sl) + level = sl; + if (level > el) + level = el; + level = level - sl; + level = gm->basebits + level; + dlog(3, "sl=%d el=%d level=%d\n", sl, el, level); + map->gmap = gm; + glast = &map->objs; + while (*glast) { + if ((*glast)->next) { + *glast = (*glast)->next; + } else + break; + } + rc = gar_get_objects(gm, level, sel ? &r : NULL, glast, flags); + if (rc < 0) { + dlog(1, "Error loading objects\n"); + return -1; + } + map->cobj = map->objs; + dlog(2, "Loaded %d objects\n", rc); + return rc; +} +// Can not return NULL, navit segfaults +static struct map_rect_priv * +gmap_rect_new(struct map_priv *map, struct map_selection *sel) +{ + struct map_selection *ms = sel; + struct map_rect_priv *mr; + + if (!map) + return NULL; + mr = calloc(1, sizeof(*mr)); + if (!mr) + return mr; + mr->mpriv = map; + if (!sel) { + return mr; + } else { + while (ms) { + dlog(2, "order %d\n", ms->order); + if (garmin_get_selection(mr, ms) < 0) { + // free(mr); + // return NULL; + } + ms = ms->next; + } + } + return mr; +} + +static void +gmap_rect_destroy(struct map_rect_priv *mr) +{ + dlog(11,"destroy maprect\n"); + if (mr->gmap) + gar_free_gmap(mr->gmap); + if (mr->objs) + gar_free_objects(mr->objs); + if (mr->label) + free(mr->label); + free(mr); +} + +static void +gmap_search_destroy(struct map_search_priv *ms) +{ + gmap_rect_destroy((struct map_rect_priv *)ms); +} + +static void +gmap_destroy(struct map_priv *m) +{ + dlog(5, "garmin_map_destroy\n"); + if (m->g) + gar_free(m->g); + if (m->filename) + free(m->filename); + free(m); +} + +static struct map_methods map_methods = { + projection_garmin, + "utf-8", + gmap_destroy, + gmap_rect_new, + gmap_rect_destroy, + gmap_rect_get_item, + gmap_rect_get_item_byid, + gmap_search_new, + gmap_search_destroy, + gmap_rect_get_item, +}; + +static struct map_priv * +gmap_new(struct map_methods *meth, struct attr **attrs) +{ + struct map_priv *m; + struct attr *data; + struct attr *debug; + struct attr *flags; + char buf[PATH_MAX]; + struct stat st; + int dl = 1; + struct gar_config cfg; + int debugmask = 0; + + data=attr_search(attrs, NULL, attr_data); + if (! data) + return NULL; + debug=attr_search(attrs, NULL, attr_debug); + if (debug) { + dl = atoi(debug->u.str); + if (!dl) + dl = 1; + } + flags=attr_search(attrs, NULL, attr_flags); + if (flags) { + debugmask = flags->u.num; + } + m=g_new(struct map_priv, 1); + m->id=++map_id; + m->filename = strdup(data->u.str); + if (!m->filename) { + g_free(m); + return NULL; + } + memset(&cfg, 0, sizeof(struct gar_config)); + cfg.opm = OPM_GPS; + cfg.debuglevel = dl; + cfg.debugmask = debugmask; + garmin_debug = dl; + m->g = gar_init_cfg(NULL, logfn, &cfg); + if (!m->g) { + g_free(m->filename); + g_free(m); + return NULL; + } + // we want the data now, later we can load only what's necessery + if (gar_img_load(m->g, m->filename, 1) < 0) { + gar_free(m->g); + g_free(m->filename); + g_free(m); + return NULL; + } + m->conv = NULL; + snprintf(buf, sizeof(buf), "%s.types", m->filename); + if (!stat(buf, &st)) { + dlog(1, "Loading custom types from %s\n", buf); + m->conv = g2n_conv_load(buf); + } + if (!m->conv) { + dlog(1, "Using builtin types\n"); + m->conv = g2n_default_conv(); + } + if (!m->conv) { + dlog(1, "Failed to load map types\n"); + } + *meth=map_methods; + return m; +} + +void +plugin_init(void) +{ + plugin_register_map_type("garmin", gmap_new); +} |