From ca5510e359671d1ecc164cca6f013c30fc9c8769 Mon Sep 17 00:00:00 2001 From: martin-s Date: Thu, 25 Dec 2008 17:09:33 +0000 Subject: [PATCH] Add:Core:3d Support git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@1850 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/navit/cursor.c | 2 +- navit/navit/graphics.c | 442 +++++++++++++++++++++++++++++------ navit/navit/graphics.h | 1 - navit/navit/gui/gtk/gui_gtk_window.c | 62 +++++ navit/navit/navit.c | 60 +++-- navit/navit/transform.c | 304 ++++++++++++++++++------ navit/navit/transform.h | 2 +- 7 files changed, 714 insertions(+), 159 deletions(-) diff --git a/navit/navit/cursor.c b/navit/navit/cursor.c index 970584f..a669088 100644 --- a/navit/navit/cursor.c +++ b/navit/navit/cursor.c @@ -69,7 +69,7 @@ cursor_draw_do(struct cursor *this_, int lazy) return; if (!this_->gra) return; - transform_set_angle(this_->trans, -this_->angle); + transform_set_yaw(this_->trans, -this_->angle); graphics_draw_mode(this_->gra, draw_mode_begin); p.x=0; p.y=0; diff --git a/navit/navit/graphics.c b/navit/navit/graphics.c index e16f349..5eb04da 100644 --- a/navit/navit/graphics.c +++ b/navit/navit/graphics.c @@ -66,8 +66,7 @@ struct graphics struct attr **attrs; struct callback_list *cbl; int ready; - int w; - int h; + struct point_rect r; }; @@ -77,10 +76,9 @@ struct displaylist { void -graphics_resize(struct graphics *gra, int w, int h) +graphics_set_rect(struct graphics *gra, struct point_rect *pr) { - gra->w=w; - gra->h=h; + gra->r=*pr; } /** @@ -495,6 +493,9 @@ static void popup_view_html(struct popup_item *item, char *file) system(command); } +struct transformatin *tg; +enum projection pg; + //############################################################################################################## //# Description: //# Comment: @@ -538,7 +539,7 @@ struct displayitem { char *label; int displayed; int count; - struct point pnt[0]; + struct coord c[0]; }; /** @@ -580,14 +581,14 @@ static void xdisplay_free(GHashTable *display_list) * @returns <> * @author Martin Schaller (04/2008) */ -void display_add(struct displaylist *displaylist, struct item *item, int count, struct point *pnt, char *label) +static void display_add(struct displaylist *displaylist, struct item *item, int count, struct coord *c, char *label) { struct displayitem *di; int len; GList *l; char *p; - len=sizeof(*di)+count*sizeof(*pnt); + len=sizeof(*di)+count*sizeof(*c); if (label) len+=strlen(label)+1; @@ -595,7 +596,7 @@ void display_add(struct displaylist *displaylist, struct item *item, int count, di=(struct displayitem *)p; di->displayed=0; - p+=sizeof(*di)+count*sizeof(*pnt); + p+=sizeof(*di)+count*sizeof(*c); di->item=*item; if (label) { di->label=p; @@ -603,7 +604,7 @@ void display_add(struct displaylist *displaylist, struct item *item, int count, } else di->label=NULL; di->count=count; - memcpy(di->pnt, pnt, count*sizeof(*pnt)); + memcpy(di->c, c, count*sizeof(*c)); l=g_hash_table_lookup(displaylist->dl, GINT_TO_POINTER(item->type)); l=g_list_prepend(l, di); @@ -661,7 +662,7 @@ static void label_line(struct graphics *gra, struct graphics_gc *fg, struct grap #if 0 dbg(0,"display_text: '%s', %d, %d, %d, %d %d\n", label, x, y, dx*0x10000/l, dy*0x10000/l, l); #endif - if (x < gra->w && x + tl > 0 && y + tl > 0 && y - tl < gra->h) + if (x < gra->r.rl.x && x + tl > gra->r.lu.x && y + tl > gra->r.lu.y && y - tl < gra->r.rl.y) gra->meth.draw_text(gra->priv, fg->priv, bg->priv, font->priv, label, &p_t, dx*0x10000/l, dy*0x10000/l); } } @@ -678,22 +679,22 @@ static void display_draw_arrow(struct point *p, int dx, int dy, int l, struct gr gra->meth.draw_lines(gra->priv, gc->priv, pnt, 3); } -static void display_draw_arrows(struct displayitem *di, struct graphics_gc *gc, struct graphics *gra) +static void display_draw_arrows(struct graphics *gra, struct graphics_gc *gc, struct point *pnt, int count) { int i,dx,dy,l; struct point p; - for (i = 0 ; i < di->count-1 ; i++) { - dx=di->pnt[i+1].x-di->pnt[i].x; - dy=di->pnt[i+1].y-di->pnt[i].y; + for (i = 0 ; i < count-1 ; i++) { + dx=pnt[i+1].x-pnt[i].x; + dy=pnt[i+1].y-pnt[i].y; l=sqrt(dx*dx+dy*dy); if (l) { dx=dx*65536/l; dy=dy*65536/l; - p=di->pnt[i]; + p=pnt[i]; p.x+=dx*15/65536; p.y+=dy*15/65536; display_draw_arrow(&p, dx, dy, 10, gc, gra); - p=di->pnt[i+1]; + p=pnt[i+1]; p.x-=dx*15/65536; p.y-=dy*15/65536; display_draw_arrow(&p, dx, dy, 10, gc, gra); @@ -884,17 +885,10 @@ graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, int fow, fowo, delta; int wi, ppos = maxpoints/2, npos = maxpoints/2; int state,prec=5; - j = 0; int max_circle_points=20; -#if 0 - dbg(0,"enter: count=%d\n", count); -#endif for (i = 0; i < count; i++) { wi=*width; width+=step; -#if 0 - dbg(0,"p[%d]=%d,%d wi=%d\n", i,pnt[i].x,pnt[i].y, wi); -#endif if (i < count - 1) { dx = (pnt[i + 1].x - pnt[i].x); dy = (pnt[i + 1].y - pnt[i].y); @@ -903,6 +897,9 @@ graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, } if (! l) l=1; +#if 0 + dbg(0,"p[%d of %d]=%d,%d wi=%d l=%d\n", i,count-1,pnt[i].x,pnt[i].y, wi, l); +#endif calc_offsets(wi, l, dx, dy, &o); pos.x = pnt[i].x + o.ny; pos.y = pnt[i].y + o.px; @@ -958,6 +955,10 @@ graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, dbg_assert(npos > 0); dbg_assert(ppos < maxpoints); gra->meth.draw_polygon(gra->priv, gc->priv, res+npos, ppos-npos); +#if 0 + for (j = npos ; j < ppos ; j++) + dbg(0,"res[%d]=%d,%d\n", j-npos, res[j].x, res[j].y); +#endif if (state == 2) break; npos=maxpoints/2; @@ -979,6 +980,260 @@ graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, } } +struct transformation *tg; +enum projection pg; + +struct wpoint { + int x,y,w; +}; + +static int +clipcode(struct wpoint *p, struct point_rect *r) +{ + int code=0; + if (p->x < r->lu.x) + code=1; + if (p->x > r->rl.x) + code=2; + if (p->y < r->lu.y) + code |=4; + if (p->y > r->rl.y) + code |=8; + return code; +} + + +static int +clip_line(struct wpoint *p1, struct wpoint *p2, struct point_rect *r) +{ + int code1,code2,ret=1; + int dx,dy,dw; + code1=clipcode(p1, r); + if (code1) + ret |= 2; + code2=clipcode(p2, r); + if (code2) + ret |= 4; + dx=p2->x-p1->x; + dy=p2->y-p1->y; + dw=p2->w-p1->w; + while (code1 || code2) { + if (code1 & code2) + return 0; + if (code1 & 1) { + p1->y+=(r->lu.x-p1->x)*dy/dx; + p1->w+=(r->lu.x-p1->x)*dw/dx; + p1->x=r->lu.x; + } else if (code1 & 2) { + p1->y+=(r->rl.x-p1->x)*dy/dx; + p1->w+=(r->rl.x-p1->x)*dw/dx; + p1->x=r->rl.x; + } else if (code1 & 4) { + p1->x+=(r->lu.y-p1->y)*dx/dy; + p1->w+=(r->lu.y-p1->y)*dw/dy; + p1->y=r->lu.y; + } else if (code1 & 8) { + p1->x+=(r->rl.y-p1->y)*dx/dy; + p1->w+=(r->rl.y-p1->y)*dw/dy; + p1->y=r->rl.y; + } + code1=clipcode(p1, r); + if (code1 & code2) + return 0; + if (code2 & 1) { + p2->y+=(r->lu.x-p2->x)*dy/dx; + p2->w+=(r->lu.x-p2->x)*dw/dx; + p2->x=r->lu.x; + } else if (code2 & 2) { + p2->y+=(r->rl.x-p2->x)*dy/dx; + p2->w+=(r->rl.x-p2->x)*dw/dx; + p2->x=r->rl.x; + } else if (code2 & 4) { + p2->x+=(r->lu.y-p2->y)*dx/dy; + p2->w+=(r->lu.y-p2->y)*dw/dy; + p2->y=r->lu.y; + } else if (code2 & 8) { + p2->x+=(r->rl.y-p2->y)*dx/dy; + p2->w+=(r->rl.y-p2->y)*dw/dy; + p2->y=r->rl.y; + } + code2=clipcode(p2, r); + } + return ret; +} + +static void +graphics_draw_polyline_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pa, int count, int *width, int step, int poly) +{ + struct point p[count+1]; + int w[count*step+1]; + struct wpoint p1,p2; + int i,code,out=0,codeo=0; + int dx,dy; + int wmax; + struct point_rect r=gra->r; + + wmax=width[0]; + if (step) { + for (i = 1 ; i < count ; i++) { + if (width[i*step] > wmax) + wmax=width[i*step]; + } + } + if (wmax <= 0) + return; + r.lu.x-=wmax; + r.lu.y-=wmax; + r.rl.x+=wmax; + r.rl.y+=wmax; +#if 0 + for (i = 0 ; i < count ; i++) { + dbg(0,"in[%d]=%d,%d (%d)\n", i, pa[i].x, pa[i].y, width[i*step]); + } +#endif + for (i = 0 ; i < count ; i++) { + if (i) { + p1.x=pa[i-1].x; + p1.y=pa[i-1].y; + p1.w=width[(i-1)*step]; + p2.x=pa[i].x; + p2.y=pa[i].y; + p2.w=width[i*step]; + /* 0 = invisible, 1 = completely visible, 3 = start point clipped, 5 = end point clipped, 7 both points clipped */ + code=clip_line(&p1, &p2, &r); +#if 0 + dbg(0,"code=%d\n", code); +#endif + if (((code == 1 || code == 5) && i == 1) || (code & 2)) { +#if 0 + dbg(0,"start = %d,%d\n", p1.x, p1.y); +#endif + p[out].x=p1.x; + p[out].y=p1.y; + w[out*step]=p1.w; + out++; + } + if (code) { +#if 0 + dbg(0,"end = %d,%d\n", p2.x, p2.y); +#endif + p[out].x=p2.x; + p[out].y=p2.y; + w[out*step]=p2.w; + out++; + } + if (i == count-1 || (code & 4)) { +#if 0 + int j; + for (j = 0 ; j < out ; j++) { + dbg(0,"out[%d]=%d,%d (%d)\n", j, p[j].x, p[j].y, w[j*step]); + } +#endif + if (out > 1) { + if (poly) { + graphics_draw_polyline_as_polygon(gra, gc, p, out, w, step); + } else + gra->meth.draw_lines(gra->priv, gc->priv, p, out); + out=0; + } + } + } + } +#if 0 + dbg(0,"done\n"); +#endif +} + +static int +is_inside(struct point *p, struct point_rect *r, int edge) +{ + switch(edge) { + case 0: + return p->x >= r->lu.x; + case 1: + return p->x <= r->rl.x; + case 2: + return p->y >= r->lu.y; + case 3: + return p->y <= r->rl.y; + } +} + +static void +poly_intersection(struct point *p1, struct point *p2, struct point_rect *r, int edge, struct point *ret) +{ + int dx=p2->x-p1->x; + int dy=p2->y-p1->y; + switch(edge) { + case 0: + ret->y=p1->y+(r->lu.x-p1->x)*dy/dx; + ret->x=r->lu.x; + break; + case 1: + ret->y=p1->y+(r->rl.x-p1->x)*dy/dx; + ret->x=r->rl.x; + break; + case 2: + ret->x=p1->x+(r->lu.y-p1->y)*dx/dy; + ret->y=r->lu.y; + break; + case 3: + ret->x=p1->x+(r->rl.y-p1->y)*dx/dy; + ret->y=r->rl.y; + break; + } +} + +static void +graphics_draw_polygon_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pin, int count_in) +{ + struct point_rect r=gra->r; + struct point *pout,*p,*s,pi; + struct point p1[count_in+1]; + struct point p2[count_in+1]; + int count_out,edge=3; + int i; +#if 0 + r.lu.x+=20; + r.lu.y+=20; + r.rl.x-=20; + r.rl.y-=20; +#endif + + pout=p1; + for (edge = 0 ; edge < 4 ; edge++) { + p=pin; + s=pin+count_in-1; + count_out=0; + for (i = 0 ; i < count_in ; i++) { + if (is_inside(p, &r, edge)) { + if (! is_inside(s, &r, edge)) { + poly_intersection(s,p,&r,edge,&pi); + pout[count_out++]=pi; + } + pout[count_out++]=*p; + } else { + if (is_inside(s, &r, edge)) { + poly_intersection(p,s,&r,edge,&pi); + pout[count_out++]=pi; + } + } + s=p; + p++; + } + count_in=count_out; + if (pin == p1) { + pin=p2; + pout=p1; + } else { + pin=p1; + pout=p2; + } + } + gra->meth.draw_polygon(gra->priv, gc->priv, pin, count_in); +} + + /** * FIXME @@ -992,9 +1247,12 @@ static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_lis GList *l,*ls,*es,*types; enum item_type type; struct graphics_gc *gc = NULL; - struct graphics_image *img; + struct graphics_image *img=NULL; struct point p; char path[PATH_MAX]; + struct point pa[16384]; + int width[16384]; + int count; es=itm->elements; while (es) { @@ -1006,6 +1264,8 @@ static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_lis l=ls; if (gc) graphics_gc_destroy(gc); + if (img) + graphics_image_free(gra, img); gc=NULL; img=NULL; while (l) { @@ -1016,15 +1276,31 @@ static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_lis gc=graphics_gc_new(gra); gc->meth.gc_set_foreground(gc->priv, &e->color); } + if (e->type == element_polyline) { + count=transform(tg, pg, di->c, pa, di->count, 1, e->u.polyline.width, width); + } + else + count=transform(tg, pg, di->c, pa, di->count, 1, 0, NULL); switch (e->type) { case element_polygon: - gra->meth.draw_polygon(gra->priv, gc->priv, di->pnt, di->count); +#if 0 + { + int i; + for (i = 0 ; i < count ; i++) { + dbg(0,"pa[%d]=%d,%d\n", i, pa[i].x, pa[i].y); + } + } + dbg(0,"element_polygon count=%d\n",count); +#endif +#if 1 + graphics_draw_polygon_clipped(gra, gc, pa, count); +#endif break; case element_polyline: #if 0 - if (e->u.polyline.width > 1) - graphics_draw_polyline_as_polygon(gra, gc, di->pnt, di->count, &e->u.polyline.width, 0); - else { + if (e->u.polyline.width > 1) { + graphics_draw_polyline_as_polygon(gra, gc, pa, count, width, 0); + } else { #else { if (e->u.polyline.width > 1) @@ -1037,55 +1313,64 @@ static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_lis e->u.polyline.offset, e->u.polyline.dash_table, e->u.polyline.dash_num); - gra->meth.draw_lines(gra->priv, gc->priv, di->pnt, di->count); +#if 0 + if (di->label && !strcmp(di->label, "Bahnhofstr.") && di->item.type != type_street_1_city) { + dbg(0,"0x%x,0x%x %s\n", di->item.id_hi, di->item.id_lo, item_to_name(di->item.type)); +#endif + graphics_draw_polyline_clipped(gra, gc, pa, count, width, 1, e->u.polyline.width > 1); +#if 0 + } +#endif } break; case element_circle: - if (e->u.circle.width > 1) - gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width); - gra->meth.draw_circle(gra->priv, gc->priv, &di->pnt[0], e->u.circle.radius); - if (di->label && e->text_size) { - p.x=di->pnt[0].x+3; - p.y=di->pnt[0].y+10; - if (! gra->font[e->text_size]) - gra->font[e->text_size]=graphics_font_new(gra, e->text_size*20, 0); - gra->meth.draw_text(gra->priv, gra->gc[2]->priv, gra->gc[1]->priv, gra->font[e->text_size]->priv, di->label, &p, 0x10000, 0); + if (count) { + if (e->u.circle.width > 1) + gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width); + gra->meth.draw_circle(gra->priv, gc->priv, pa, e->u.circle.radius); + if (di->label && e->text_size) { + p.x=pa[0].x+3; + p.y=pa[0].y+10; + if (! gra->font[e->text_size]) + gra->font[e->text_size]=graphics_font_new(gra, e->text_size*20, 0); + gra->meth.draw_text(gra->priv, gra->gc[2]->priv, gra->gc[1]->priv, gra->font[e->text_size]->priv, di->label, &p, 0x10000, 0); + } } break; case element_text: - if (di->label) { + if (count && di->label) { if (! gra->font[e->text_size]) gra->font[e->text_size]=graphics_font_new(gra, e->text_size*20, 0); - label_line(gra, gra->gc[2], gra->gc[1], gra->font[e->text_size], di->pnt, di->count, di->label); + label_line(gra, gra->gc[2], gra->gc[1], gra->font[e->text_size], pa, count, di->label); } break; case element_icon: - if (!img) { - if (e->u.icon.src[0] == '/') - strcpy(path,e->u.icon.src); - else - sprintf(path,"%s/xpm/%s", navit_sharedir, 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) - dbg(0,"failed to load icon '%s'\n", e->u.icon.src); - } - if (img) { - p.x=di->pnt[0].x - img->hot.x; - p.y=di->pnt[0].y - img->hot.y; - gra->meth.draw_image(gra->priv, gra->gc[0]->priv, &p, img->priv); - graphics_image_free(gra, img); - img = NULL; + if (count) { + if (!img) { + if (e->u.icon.src[0] == '/') + strcpy(path,e->u.icon.src); + else + sprintf(path,"%s/xpm/%s", navit_sharedir, 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) + dbg(0,"failed to load icon '%s'\n", e->u.icon.src); + } + if (img) { + p.x=pa[0].x - img->hot.x; + p.y=pa[0].y - img->hot.y; + gra->meth.draw_image(gra->priv, gra->gc[0]->priv, &p, img->priv); + } } break; case element_image: dbg(1,"image: '%s'\n", di->label); if (gra->meth.draw_image_warp) - gra->meth.draw_image_warp(gra->priv, gra->gc[0]->priv, di->pnt, di->count, di->label); + gra->meth.draw_image_warp(gra->priv, gra->gc[0]->priv, pa, count, di->label); else dbg(0,"draw_image_warp not supported by graphics driver drawing '%s'\n", di->label); break; case element_arrows: - display_draw_arrows(di,gc,gra); + display_draw_arrows(gra,gc,pa,count); break; default: printf("Unhandled element type %d\n", e->type); @@ -1099,6 +1384,8 @@ static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_lis } if (gc) graphics_gc_destroy(gc); + if (img) + graphics_image_free(gra, img); } void @@ -1119,9 +1406,9 @@ graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct transfor int count=e->coord_count; struct point pnt[count+1]; if (count) - transform(t, projection_screen, e->coord, pnt, count, 0); + transform(t, projection_screen, e->coord, pnt, count, 0, 0, NULL); else { - transform(t, projection_screen, &c, pnt, 1, 0); + transform(t, projection_screen, &c, pnt, 1, 0, 0, NULL); count=1; } gc=graphics_gc_new(gra); @@ -1231,14 +1518,19 @@ static void do_draw_map(struct displaylist *displaylist, struct transformation * struct map_rect *mr; struct item *item; int conv,count,max=16384; - struct point pnt[max]; struct coord ca[max]; struct attr attr; struct map_selection *sel; + int num=0; pro=map_projection(m); conv=map_requires_conversion(m); sel=transform_get_selection(t, pro, order); + tg=t; + pg=pro; +#if 0 + sel=NULL; +#endif if (route_selection) mr=map_rect_new(m, route_selection); else @@ -1248,6 +1540,15 @@ static void do_draw_map(struct displaylist *displaylist, struct transformation * return; } while ((item=map_rect_get_item(mr))) { + num++; +#if 0 + if (num < 7599 || num > 7599) + continue; +#endif +#if 0 + if (item->id_hi != 0xb0031 || item->id_lo != 0x20c9aeea) + continue; +#endif count=item_coord_get(item, ca, item->type < type_line ? 1: max); if (item->type >= type_line && count < 2) { dbg(1,"poly from map has only %d points\n", count); @@ -1271,7 +1572,6 @@ static void do_draw_map(struct displaylist *displaylist, struct transformation * } if (count == max) dbg(0,"point count overflow\n", count); - count=transform(t, pro, ca, pnt, count, 1); if (item->type >= type_line && count < 2) { dbg(1,"poly from transform has only %d points\n", count); continue; @@ -1280,10 +1580,10 @@ static void do_draw_map(struct displaylist *displaylist, struct transformation * attr.u.str=NULL; if (conv && attr.u.str && attr.u.str[0]) { char *str=map_convert_string(m, attr.u.str); - display_add(displaylist, item, count, pnt, str); + display_add(displaylist, item, count, ca, str); map_convert_free(str); } else - display_add(displaylist, item, count, pnt, attr.u.str); + display_add(displaylist, item, count, ca, attr.u.str); } map_rect_destroy(mr); map_selection_destroy(sel); @@ -1332,6 +1632,7 @@ void graphics_displaylist_draw(struct graphics *gra, struct displaylist *display { int order=transform_get_order(trans); struct point p; + tg=trans; p.x=0; p.y=0; // FIXME find a better place to set the background color @@ -1350,6 +1651,7 @@ void graphics_displaylist_draw(struct graphics *gra, struct displaylist *display gra->meth.draw_mode(gra->priv, draw_mode_end); } +#if 0 /** * FIXME * @param <> @@ -1371,6 +1673,7 @@ void graphics_displaylist_move(struct displaylist *displaylist, int dx, int dy) } graphics_displaylist_close(dlh); } +#endif /** * FIXME @@ -1604,11 +1907,16 @@ static int within_dist_polygon(struct point *p, struct point *poly_pnt, int coun */ int graphics_displayitem_within_dist(struct displayitem *di, struct point *p, int dist) { + struct point pa[16384]; + int count; + + count=transform(tg, pg, di->c, pa, di->count, 1, 0, NULL); + if (di->item.type < type_line) { - return within_dist_point(p, &di->pnt[0], dist); + return within_dist_point(p, &pa[0], dist); } if (di->item.type < type_area) { - return within_dist_polyline(p, di->pnt, di->count, dist, 0); + return within_dist_polyline(p, pa, count, dist, 0); } - return within_dist_polygon(p, di->pnt, di->count, dist); + return within_dist_polygon(p, pa, count, dist); } diff --git a/navit/navit/graphics.h b/navit/navit/graphics.h index a1b6fc7..685ab5e 100644 --- a/navit/navit/graphics.h +++ b/navit/navit/graphics.h @@ -152,7 +152,6 @@ void graphics_overlay_disable(struct graphics *this_, int disable); void graphics_draw_image(struct graphics *this_, struct graphics_gc *gc, struct point *p, struct graphics_image *img); int graphics_draw_drag(struct graphics *this_, struct point *p); void graphics_background_gc(struct graphics *this_, struct graphics_gc *gc); -void display_add(struct displaylist *displaylist, struct item *item, int count, struct point *pnt, char *label); int graphics_ready(struct graphics *this_); void graphics_displaylist_draw(struct graphics *gra, struct displaylist *displaylist, struct transformation *trans, struct layout *l, int callback); void graphics_displaylist_move(struct displaylist *displaylist, int dx, int dy); diff --git a/navit/navit/gui/gtk/gui_gtk_window.c b/navit/navit/gui/gtk/gui_gtk_window.c index 8e65f13..1178cb3 100644 --- a/navit/navit/gui/gtk/gui_gtk_window.c +++ b/navit/navit/gui/gtk/gui_gtk_window.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #if !defined(GDK_Book) || !defined(GDK_Calendar) #include @@ -71,6 +72,7 @@ static gboolean keypress(GtkWidget *widget, GdkEventKey *event, struct gui_priv *this) { int w,h; + struct transformation *t; #ifdef USE_HILDON GtkToggleAction *action; gboolean *fullscreen; @@ -110,6 +112,66 @@ keypress(GtkWidget *widget, GdkEventKey *event, struct gui_priv *this) case KEY_ZOOM_OUT: navit_zoom_out(this->nav, 2, NULL); break; + case 'a': + t=navit_get_trans(this->nav); + transform_set_yaw(t, (transform_get_yaw(t,0)+15)%360); + navit_draw(this->nav); + break; + case 'd': + t=navit_get_trans(this->nav); + transform_set_yaw(t, (transform_get_yaw(t,0)-15)%360); + navit_draw(this->nav); + break; + case 'w': + t=navit_get_trans(this->nav); + transform_set_pitch(t, (transform_get_pitch(t,0)+5)%360); + navit_draw(this->nav); + break; + case 'x': + t=navit_get_trans(this->nav); + transform_set_pitch(t, (transform_get_pitch(t,0)-5)%360); + navit_draw(this->nav); + break; + case 'r': + t=navit_get_trans(this->nav); + transform_set_distance(t, (transform_get_distance(t,0)-5)); + navit_draw(this->nav); + break; + case 'f': + t=navit_get_trans(this->nav); + transform_set_distance(t, (transform_get_distance(t,0)+5)); + navit_draw(this->nav); + break; + case 't': + { + struct coord *p; + struct pcoord pc; + t=navit_get_trans(this->nav); + struct coord *c=transform_center(t); + p=transform_center(t); + pc.pro=projection_mg; + p->y+=50*cos(transform_get_yaw(t, 0)*M_PI/180); + p->x+=50*sin(transform_get_yaw(t, 0)*M_PI/180); + pc.x=p->x; + pc.y=p->y; + navit_set_center(this->nav, &pc); + } + break; + case 'g': + { + struct coord *p; + struct pcoord pc; + t=navit_get_trans(this->nav); + struct coord *c=transform_center(t); + p=transform_center(t); + pc.pro=projection_mg; + p->y-=50*cos(transform_get_yaw(t, 0)*M_PI/180); + p->x-=50*sin(transform_get_yaw(t, 0)*M_PI/180); + pc.x=p->x; + pc.y=p->y; + navit_set_center(this->nav, &pc); + } + break; #ifdef USE_HILDON case HILDON_HARDKEY_FULLSCREEN: action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (this->base_group, "FullscreenAction")); diff --git a/navit/navit/navit.c b/navit/navit/navit.c index c2bff8b..5688404 100644 --- a/navit/navit/navit.c +++ b/navit/navit/navit.c @@ -192,6 +192,14 @@ navit_draw(struct navit *this_) l=g_list_next(l); } graphics_draw(this_->gra, this_->displaylist, this_->mapsets, this_->trans, this_->layout_current); +#if 0 + { + int i; + for (i = 0 ; i < 500 ; i++) + graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layout_current, 1); + exit(0); + } +#endif } void @@ -206,13 +214,13 @@ navit_handle_resize(struct navit *this_, int w, int h) { struct map_selection sel; memset(&sel, 0, sizeof(sel)); - sel.u.p_rect.rl.x=w; - sel.u.p_rect.rl.y=h; this_->w=w; this_->h=h; + sel.u.p_rect.rl.x=w; + sel.u.p_rect.rl.y=h; transform_set_screen_selection(this_->trans, &sel); this_->ready |= 2; - graphics_resize(this_->gra, w, h); + graphics_set_rect(this_->gra, &sel.u.p_rect); if (this_->ready == 3) navit_draw(this_); } @@ -260,6 +268,21 @@ navit_ignore_graphics_events(struct navit *this_, int ignore) this_->ignore_graphics_events=ignore; } +void +update_transformation(struct transformation *tr, struct point *old, struct point *new) +{ + struct coord co,cn; + struct coord c,*cp; + int dx,dy; + transform_reverse(tr, old, &co); + transform_reverse(tr, new, &cn); + cp=transform_get_center(tr); + c.x=cp->x+co.x-cn.x; + c.y=cp->y+co.y-cn.y; + dbg(1,"from 0x%x,0x%x to 0x%x,0x%x\n", cp->x, cp->y, c.x, c.y); + transform_set_center(tr, &c); +} + int navit_handle_button(struct navit *this_, int pressed, int button, struct point *p, struct callback *popup_callback) { @@ -311,18 +334,13 @@ navit_handle_button(struct navit *this_, int pressed, int button, struct point * } if (this_->moved) { struct point pt; - this_->last=*p; - transform_get_size(this_->trans, &pt.x, &pt.y); - pt.x/=2; - pt.y/=2; - pt.x-=this_->last.x-this_->pressed.x; - pt.y-=this_->last.y-this_->pressed.y; + update_transformation(this_->trans, &this_->pressed, p); graphics_draw_drag(this_->gra, NULL); graphics_overlay_disable(this_->gra, 0); if (!this_->zoomed) { this_->last_moved = time(NULL); } - navit_set_center_screen(this_, &pt); + navit_draw(this_); } else return 1; } @@ -361,10 +379,16 @@ navit_motion_timeout(struct navit *this_) dx=(this_->current.x-this_->last.x); dy=(this_->current.y-this_->last.y); if (dx || dy) { + struct transformation *tr; this_->last=this_->current; graphics_overlay_disable(this_->gra, 1); + tr=transform_dup(this_->trans); + update_transformation(tr, &this_->pressed, &this_->current); +#if 0 graphics_displaylist_move(this_->displaylist, dx, dy); - graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layout_current, 0); +#endif + graphics_displaylist_draw(this_->gra, this_->displaylist, tr, this_->layout_current, 0); + transform_destroy(tr); this_->moved=1; } this_->motion_timeout=NULL; @@ -1382,8 +1406,8 @@ navit_zoom_to_route(struct navit *this_) struct point p1,p2; transform_set_scale(this_->trans, scale); transform_setup_source_rect(this_->trans); - transform(this_->trans, transform_get_projection(this_->trans), &r.lu, &p1, 1, 0); - transform(this_->trans, transform_get_projection(this_->trans), &r.rl, &p2, 1, 0); + transform(this_->trans, transform_get_projection(this_->trans), &r.lu, &p1, 1, 0, 0, NULL); + transform(this_->trans, transform_get_projection(this_->trans), &r.rl, &p2, 1, 0, 0, NULL); dbg(0,"%d,%d-%d,%d\n",p1.x,p1.y,p2.x,p2.y); if (p1.x < 0 || p2.x < 0 || p1.x > this_->w || p2.x > this_->w || p1.y < 0 || p2.y < 0 || p1.y > this_->h || p2.y > this_->h) @@ -1432,7 +1456,7 @@ navit_set_center_cursor(struct navit *this_, struct coord *cursor, int dir, int transform_get_size(this_->trans, &width, &height); *c=*cursor; - transform_set_angle(this_->trans, dir); + transform_set_yaw(this_->trans, dir); p.x=(100-xpercent)*width/100; p.y=(100-ypercent)*height/100; transform_reverse(this_->trans, &p, &cnew); @@ -1484,7 +1508,7 @@ navit_set_attr(struct navit *this_, struct attr *attr) dir = this_->vehicle->dir; } } - transform_set_angle(this_->trans, dir); + transform_set_yaw(this_->trans, dir); if (orient_old != this_->orientation) { if (this_->ready == 3) navit_draw(this_); @@ -1728,9 +1752,9 @@ navit_vehicle_draw(struct navit *this_, struct navit_vehicle *nv, struct point * cursor_pnt=*pnt; else { pro=transform_get_projection(this_->trans); - transform(this_->trans, pro, &nv->coord, &cursor_pnt, 1, 0); + transform(this_->trans, pro, &nv->coord, &cursor_pnt, 1, 0, 0, NULL); } - cursor_draw(cursor.u.cursor, this_->gra, &cursor_pnt, pnt ? 0:1, nv->dir-transform_get_angle(this_->trans, 0), nv->speed); + cursor_draw(cursor.u.cursor, this_->gra, &cursor_pnt, pnt ? 0:1, nv->dir-transform_get_yaw(this_->trans, 0), nv->speed); #if 0 if (pnt) pnt2=*pnt; @@ -1815,7 +1839,7 @@ navit_vehicle_update(struct navit *this_, struct navit_vehicle *nv) callback_list_call_attr_0(this_->attr_cbl, attr_position); } navit_textfile_debug_log(this_, "type=trackpoint_tracked"); - transform(this_->trans, pro, &nv->coord, &cursor_pnt, 1, 0); + transform(this_->trans, pro, &nv->coord, &cursor_pnt, 1, 0, 0, NULL); if (!transform_within_border(this_->trans, &cursor_pnt, border)) { if (!this_->cursor_flag) { profile(0,"return 4\n"); diff --git a/navit/navit/transform.c b/navit/navit/transform.c index 3eda8a5..a1f406d 100644 --- a/navit/navit/transform.c +++ b/navit/navit/transform.c @@ -32,27 +32,107 @@ #include "projection.h" #include "point.h" +#define POST_SHIFT 8 + struct transformation { - int angle; /* Rotation angle */ - double cos_val,sin_val; /* cos and sin of rotation angle */ + int yaw; /* Rotation angle */ + int pitch; + int roll; + int ddd; + int m00,m01,m10,m11; /* 2d transformation matrix */ + int m20,m21; /* additional 3d parameters */ + double im00,im01,im10,im11; /* inverse 2d transformation matrix */ struct map_selection *map_sel; struct map_selection *screen_sel; struct point screen_center; + int screen_dist; + int offx,offy,offz; struct coord map_center; /* Center of source rectangle */ enum projection pro; - long scale; /* Scale factor */ + double scale; /* Scale factor */ + int scale_shift; + int order; }; +static void +transform_setup_matrix(struct transformation *t) +{ + double det; + double fac; + double yawc=cos(M_PI*t->yaw/180); + double yaws=sin(M_PI*t->yaw/180); + double pitchc=cos(M_PI*t->pitch/180); + double pitchs=sin(M_PI*t->pitch/180); + + int scale=t->scale; + int order_dir=-1; + + dbg(1,"yaw=%d pitch=%d center=0x%x,0x%x\n", t->yaw, t->pitch, t->map_center.x, t->map_center.y); + t->scale_shift=0; + t->order=14; + if (t->scale >= 1) { + scale=t->scale; + } else { + scale=1.0/t->scale; + order_dir=1; + } + while (scale > 1) { + if (order_dir < 0) + t->scale_shift++; + t->order+=order_dir; + scale >>= 1; + } + fac=(1 << POST_SHIFT) * (1 << t->scale_shift) / t->scale; + dbg(1,"scale_shift=%d order=%d scale=%f fac=%f\n", t->scale_shift, t->order,t->scale,fac); + + t->m00=yawc*fac; + t->m01=-yaws*fac; + t->m10=-pitchc*yaws*fac; + t->m11=-pitchc*yawc*fac; + t->m20=pitchs*yaws*fac; + t->m21=pitchs*yawc*fac; + t->offz=0; + t->ddd=0; + t->offx=t->screen_center.x; + t->offy=t->screen_center.y; + if (t->pitch) { + t->ddd=1; + t->offz=t->screen_dist; + t->m00*=t->offz; + t->m01*=t->offz; + t->m10*=t->offz; + t->m11*=t->offz; + } + det=((double)t->m00*(double)t->m11-(double)t->m01*(double)t->m10); + dbg(1,"det=%f\n", det); + t->im00=t->m11/det; + t->im01=-t->m01/det; + t->im10=-t->m10/det; + t->im11=t->m00/det; +} + struct transformation * transform_new(void) { struct transformation *this_; this_=g_new0(struct transformation, 1); - + this_->screen_dist=100; +#if 0 + this_->pitch=20; +#endif + transform_setup_matrix(this_); return this_; } +struct transformation * +transform_dup(struct transformation *t) +{ + struct transformation *ret=g_new0(struct transformation, 1); + *ret=*t; + return ret; +} + static const double gar2geo_units = 360.0/(1<<24); static const double geo2gar_units = 1/(360.0/(1<<24)); @@ -134,17 +214,23 @@ transform_datum(struct coord_geo *from, enum map_datum from_datum, struct coord_ } int -transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int unique) +transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int unique, int width, int *width_return) { struct coord c1; int xcn, ycn; struct coord_geo g; + int z; #ifdef AVOID_FLOAT - int xc,yc; + int xc,yc,zc,xco,yco,zco; #else - double xc,yc; + int xc,yc,zc,xco,yco,zco,xc2,yc2,zc2; #endif + int xm,ym,xr,yr,zct; + int zlimit=1000; + int visible, visibleo=-1; + int limit=t->screen_center.y+250; int i,j = 0; + dbg(1,"count=%d\n", count); for (i=0; i < count; i++) { if (pro == t->pro) { xc=c[i].x; @@ -155,44 +241,81 @@ transform(struct transformation *t, enum projection pro, struct coord *c, struct xc=c1.x; yc=c1.y; } + xm=xc; + ym=yc; // dbg(2,"0x%x, 0x%x - 0x%x,0x%x contains 0x%x,0x%x\n", t->r.lu.x, t->r.lu.y, t->r.rl.x, t->r.rl.y, c->x, c->y); // ret=coord_rect_contains(&t->r, c); xc-=t->map_center.x; yc-=t->map_center.y; - yc=-yc; - if (t->angle) { - xcn=xc*t->cos_val+yc*t->sin_val; - ycn=-xc*t->sin_val+yc*t->cos_val; - xc=xcn; - yc=ycn; - } - xc=xc*16; - yc=yc*16; -#ifndef AVOID_FLOAT - if (t->scale!=1) { - xc=xc/(double)(t->scale); - yc=yc/(double)(t->scale); - } + xc >>= t->scale_shift; + yc >>= t->scale_shift; + xcn=xc*t->m00+yc*t->m01; + ycn=xc*t->m10+yc*t->m11; + + if (t->ddd) { + zc=(xc*t->m20+yc*t->m21); + zct=zc; + zc+=t->offz << POST_SHIFT; + dbg(1,"zc=%d\n", zc); + dbg(1,"zc(%d)=xc(%d)*m20(%d)+yc(%d)*m21(%d)\n", (xc*t->m20+yc*t->m21), xc, t->m20, yc, t->m21); + /* visibility */ + visible=(zc < zlimit ? 0:1); + dbg(1,"visible=%d old %d\n", visible, visibleo); + if (visible != visibleo && visibleo != -1) { + dbg(1,"clipping (%d,%d,%d)-(%d,%d,%d) (%d,%d,%d)\n", xcn, ycn, zc, xco, yco, zco, xco-xcn, yco-ycn, zco-zc); + if (zco != zc) { + xcn=xcn+(long long)(xco-xcn)*(zlimit-zc)/(zco-zc); + ycn=ycn+(long long)(yco-ycn)*(zlimit-zc)/(zco-zc); + } + dbg(1,"result (%d,%d,%d) * %d / %d\n", xcn,ycn,zc,zlimit-zc,zco-zc); + zc=zlimit; + xco=xcn; + yco=ycn; + zco=zc; + if (visible) + i--; + visibleo=visible; + } else { + xco=xcn; + yco=ycn; + zco=zc; + visibleo=visible; + if (! visible) + continue; + } + dbg(1,"zc=%d\n", zc); + dbg(1,"xcn %d ycn %d\n", xcn, ycn); + dbg(1,"%d,%d %d\n",xc,yc,zc); +#if 0 + dbg(0,"%d/%d=%d %d/%d=%d\n",xcn,xc,xcn/xc,ycn,yc,ycn/yc); +#endif +#if 1 + xc=xcn/zc; + yc=ycn/zc; #else - if (t->scale!=1) { - xc=xc/t->scale; - yc=yc/t->scale; - } + xc=xcn/(1000+zc); + yc=ycn/(1000+zc); #endif - xc+=t->screen_center.x; - yc+=t->screen_center.y; - if (xc < -0x8000) - xc=-0x8000; - if (xc > 0x7fff) { - xc=0x7fff; + dbg(1,"%d,%d %d\n",xc,yc,zc); + } else { + xc=xcn; + yc=ycn; + xc>>=POST_SHIFT; + yc>>=POST_SHIFT; } - if (yc < -0x8000) - yc=-0x8000; - if (yc > 0x7fff) - yc=0x7fff; + xc+=t->offx; + yc+=t->offy; + dbg(1,"xc=%d yc=%d\n", xc, yc); if (j == 0 || !unique || p[j-1].x != xc || p[j-1].y != yc) { + struct coord cn; p[j].x=xc; p[j].y=yc; + if (width_return) { + if (t->ddd) + width_return[j]=width*(t->offz << POST_SHIFT)/zc; + else + width_return[j]=width; + } j++; } } @@ -202,22 +325,30 @@ transform(struct transformation *t, enum projection pro, struct coord *c, struct void transform_reverse(struct transformation *t, struct point *p, struct coord *c) { - int xc,yc; - xc=p->x; - yc=p->y; - xc-=t->screen_center.x; - yc-=t->screen_center.y; - xc=xc*t->scale/16; - yc=-yc*t->scale/16; - if (t->angle) { - int xcn, ycn; - xcn=xc*t->cos_val+yc*t->sin_val; - ycn=-xc*t->sin_val+yc*t->cos_val; - xc=xcn; - yc=ycn; + double zc,xc,yc,xcn,ycn,q; + xc=p->x - t->offx; + yc=p->y - t->offy; + if (t->ddd) { + double f00=xc*t->im00*t->m20; + double f01=yc*t->im01*t->m20; + double f10=xc*t->im10*t->m21; + double f11=yc*t->im11*t->m21; + q=(1-f00-f01-f10-f11); + if (q < 0) + q=0.15; + zc=(t->offz << POST_SHIFT)*(1+(f00+f01+f10+f11)/q); + xcn=xc*zc; + ycn=yc*zc; + xc=xcn*t->im00+ycn*t->im01; + yc=xcn*t->im10+ycn*t->im11; + } else { + xcn=xc; + ycn=yc; + xc=(xcn*t->im00+ycn*t->im01)*(1 << POST_SHIFT); + yc=(xcn*t->im10+ycn*t->im11)*(1 << POST_SHIFT); } - c->x=t->map_center.x+xc; - c->y=t->map_center.y+yc; + c->x=xc*(1 << t->scale_shift)+t->map_center.x; + c->y=yc*(1 << t->scale_shift)+t->map_center.y; } enum projection @@ -292,18 +423,55 @@ transform_center(struct transformation *this_) return &this_->map_center; } +struct coord * +transform_get_center(struct transformation *this_) +{ + return &this_->map_center; +} + void -transform_set_angle(struct transformation *t,int angle) +transform_set_center(struct transformation *this_, struct coord *c) { - t->angle=angle; - t->cos_val=cos(M_PI*t->angle/180); - t->sin_val=sin(M_PI*t->angle/180); + this_->map_center=*c; +} + + +void +transform_set_yaw(struct transformation *t,int yaw) +{ + t->yaw=yaw; + transform_setup_matrix(t); } int -transform_get_angle(struct transformation *this_,int angle) +transform_get_yaw(struct transformation *this_) { - return this_->angle; + return this_->yaw; +} + +void +transform_set_pitch(struct transformation *this_,int pitch) +{ + this_->pitch=pitch; + transform_setup_matrix(this_); +} +int +transform_get_pitch(struct transformation *this_,int angle) +{ + return this_->pitch; +} + +void +transform_set_distance(struct transformation *this_,int distance) +{ + this_->screen_dist=distance; + transform_setup_matrix(this_); +} + +int +transform_get_distance(struct transformation *this_,int angle) +{ + return this_->screen_dist; } void @@ -314,6 +482,7 @@ transform_set_screen_selection(struct transformation *t, struct map_selection *s if (sel) { t->screen_center.x=(sel->u.p_rect.rl.x-sel->u.p_rect.lu.x)/2; t->screen_center.y=(sel->u.p_rect.rl.y-sel->u.p_rect.lu.y)/2; + transform_setup_matrix(t); } } @@ -344,13 +513,13 @@ transform_get_size(struct transformation *t, int *width, int *height) } void -transform_setup(struct transformation *t, struct pcoord *c, int scale, int angle) +transform_setup(struct transformation *t, struct pcoord *c, int scale, int yaw) { t->pro=c->pro; t->map_center.x=c->x; t->map_center.y=c->y; - t->scale=scale; - transform_set_angle(t, angle); + t->scale=scale/16.0; + transform_set_yaw(t, yaw); } #if 0 @@ -399,6 +568,7 @@ transform_setup_source_rect(struct transformation *t) screen_pnt[3].y=pr->rl.y; for (i = 0 ; i < 4 ; i++) { transform_reverse(t, &screen_pnt[i], &screen[i]); + dbg(1,"map(%d) %d,%d=0x%x,0x%x\n", i,screen_pnt[i].x, screen_pnt[i].y, screen[i].x, screen[i].y); } msm->u.c_rect.lu.x=min4(screen[0].x,screen[1].x,screen[2].x,screen[3].x); msm->u.c_rect.rl.x=max4(screen[0].x,screen[1].x,screen[2].x,screen[3].x); @@ -413,29 +583,21 @@ transform_setup_source_rect(struct transformation *t) long transform_get_scale(struct transformation *t) { - return t->scale; + return (int)(t->scale*16); } void transform_set_scale(struct transformation *t, long scale) { - t->scale=scale; + t->scale=scale/16.0; + transform_setup_matrix(t); } int transform_get_order(struct transformation *t) { - int scale=t->scale; - int order=0; - while (scale > 1) { - order++; - scale>>=1; - } - order=18-order; - if (order < 0) - order=0; - return order; + return t->order; } diff --git a/navit/navit/transform.h b/navit/navit/transform.h index 138a218..6599c92 100644 --- a/navit/navit/transform.h +++ b/navit/navit/transform.h @@ -41,7 +41,7 @@ void transform_from_to(struct coord *cfrom, enum projection from, struct coord * void transform_geo_to_cart(struct coord_geo *geo, double a, double b, struct coord_geo_cart *cart); void transform_cart_to_geo(struct coord_geo_cart *cart, double a, double b, struct coord_geo *geo); void transform_datum(struct coord_geo *from, enum map_datum from_datum, struct coord_geo *to, enum map_datum to_datum); -int transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int unique); +int transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int unique, int width, int *width_return); void transform_reverse(struct transformation *t, struct point *p, struct coord *c); enum projection transform_get_projection(struct transformation *this_); void transform_set_projection(struct transformation *this_, enum projection pro); -- 2.7.4