Contents of /trunk/src/canvas_goocanvas.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (show annotations)
Mon Dec 15 14:17:29 2008 UTC (15 years, 5 months ago) by achadwick
File MIME type: text/plain
File size: 8150 byte(s)
Support for a dashed line style. Tweak Mapnik style to use it, and then
compensate a bit for that fact that it makes things slower.
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of OSM2Go.
5 *
6 * OSM2Go is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OSM2Go is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef USE_GOOCANVAS
21 #error "Config error!"
22 #endif
23
24 #include "appdata.h"
25
26 canvas_item_t *canvas_circle_new(map_t *map, canvas_group_t group,
27 gint x, gint y, gint radius, gint border,
28 canvas_color_t fill_col, canvas_color_t border_col) {
29 return goo_canvas_ellipse_new(map->group[group],
30 (gdouble) x, (gdouble) y,
31 (gdouble) radius, (gdouble) radius,
32 "line-width", (double)border,
33 "stroke-color-rgba", border_col,
34 "fill-color-rgba", fill_col,
35 NULL);
36 }
37
38 canvas_points_t *canvas_points_new(gint points) {
39 return goo_canvas_points_new(points);
40 }
41
42 void canvas_point_set_pos(canvas_points_t *points, gint index, lpos_t *lpos) {
43 points->coords[2*index+0] = lpos->x;
44 points->coords[2*index+1] = lpos->y;
45 }
46
47 void canvas_points_free(canvas_points_t *points) {
48 goo_canvas_points_unref(points);
49 }
50
51 canvas_item_t *canvas_polyline_new(struct map_s *map, canvas_group_t group,
52 canvas_points_t *points, gint width, canvas_color_t color) {
53 return goo_canvas_polyline_new(map->group[group], FALSE, 0,
54 "points", points,
55 "line-width", (double)width,
56 "stroke-color-rgba", color,
57 "line-join", CAIRO_LINE_JOIN_ROUND,
58 "line-cap", CAIRO_LINE_CAP_ROUND,
59 NULL);
60 }
61
62 canvas_item_t *canvas_polygon_new(struct map_s *map, canvas_group_t group,
63 canvas_points_t *points, gint width, canvas_color_t color,
64 canvas_color_t fill) {
65 return goo_canvas_polyline_new(map->group[group], TRUE, 0,
66 "points", points,
67 "line-width", (double)width,
68 "stroke-color-rgba", color,
69 "fill-color-rgba", fill,
70 "line-join", CAIRO_LINE_JOIN_ROUND,
71 "line-cap", CAIRO_LINE_CAP_ROUND,
72 NULL);
73 }
74
75 void canvas_item_set_points(canvas_item_t *item, canvas_points_t *points) {
76 g_object_set(G_OBJECT(item), "points", points, NULL);
77 }
78
79 void canvas_item_set_pos(canvas_item_t *item, lpos_t *lpos, gint radius) {
80 g_object_set(G_OBJECT(item), "center-x", (gdouble)lpos->x,
81 "center-y", (gdouble)lpos->y, NULL);
82 }
83
84 void canvas_window2world(canvas_t *canvas, gint x, gint y, gint *wx, gint *wy) {
85 double sx = x, sy = y;
86 goo_canvas_convert_from_pixels(GOO_CANVAS(canvas), &sx, &sy);
87 *wx = sx; *wy = sy;
88 }
89
90 canvas_item_t *canvas_get_item_at(canvas_t *canvas, gint x, gint y) {
91 return goo_canvas_get_item_at(GOO_CANVAS(canvas), x, y, TRUE);
92 }
93
94 void canvas_item_to_bottom(canvas_item_t *item) {
95 goo_canvas_item_lower(item, NULL);
96 }
97
98 void canvas_item_set_zoom_max(canvas_item_t *item, float zoom_max) {
99 gdouble vis_thres = zoom_max;
100 GooCanvasItemVisibility vis
101 = GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD;
102 if (vis_thres < 0) {
103 vis_thres = 0;
104 vis = GOO_CANVAS_ITEM_VISIBLE;
105 }
106 g_object_set(G_OBJECT(item),
107 "visibility", vis,
108 "visibility-threshold", vis_thres,
109 NULL);
110 }
111
112 void canvas_item_set_dashed(canvas_item_t *item) {
113 static GooCanvasLineDash *dash;
114 if (!dash) {
115 dash = goo_canvas_line_dash_new(2, 3.0, 4.0, 0);
116 goo_canvas_line_dash_ref(dash);
117 }
118 // TODO: make the pattern width-dependent, or extend the elemstyles language
119 // to allow line patterns to be specified.
120 g_object_set(G_OBJECT(item),
121 "line-dash", dash,
122 NULL);
123 }
124
125 void canvas_item_destroy(canvas_item_t *item) {
126 goo_canvas_item_remove(item);
127 }
128
129 void canvas_item_set_user_data(canvas_item_t *item, void *data) {
130 g_object_set_data(G_OBJECT(item), "user data", data);
131 }
132
133 void *canvas_item_get_user_data(canvas_item_t *item) {
134 return g_object_get_data(G_OBJECT(item), "user data");
135 }
136
137 typedef struct {
138 GCallback c_handler;
139 gpointer data;
140 } weak_t;
141
142 static void canvas_item_weak_notify(gpointer data, GObject *invalid) {
143 weak_t *weak = data;
144
145 ((void(*)(GtkWidget*, gpointer))weak->c_handler) (NULL, weak->data);
146 g_free(weak);
147 }
148
149 void canvas_item_destroy_connect(canvas_item_t *item,
150 GCallback c_handler, gpointer data) {
151 weak_t *weak = g_new(weak_t,1);
152 weak->data = data;
153 weak->c_handler = c_handler;
154
155 g_object_weak_ref(G_OBJECT(item), canvas_item_weak_notify, weak);
156 }
157
158 void canvas_set_zoom(canvas_t *canvas, double zoom) {
159 goo_canvas_set_scale(GOO_CANVAS(canvas), zoom);
160 }
161
162 void canvas_get_scroll_offsets(canvas_t *canvas, gint *sx, gint *sy) {
163 GtkAdjustment *hadj = ((struct _GooCanvas*)canvas)->hadjustment;
164 GtkAdjustment *vadj = ((struct _GooCanvas*)canvas)->vadjustment;
165 gdouble hs, vs;
166 gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(canvas));
167
168 hs = gtk_adjustment_get_value(hadj);
169 vs = gtk_adjustment_get_value(vadj);
170 goo_canvas_convert_from_pixels(GOO_CANVAS(canvas), &hs, &vs);
171
172 /* make values zoom independant */
173 *sx = hs * zoom;
174 *sy = vs * zoom;
175 }
176
177 void canvas_scroll_to(canvas_t *canvas, gint sx, gint sy) {
178 gdouble zoom = goo_canvas_get_scale(GOO_CANVAS(canvas));
179 goo_canvas_scroll_to(GOO_CANVAS(canvas), sx/zoom, sy/zoom);
180 }
181
182 void canvas_set_bounds(canvas_t *canvas, gint minx, gint miny,
183 gint maxx, gint maxy) {
184 goo_canvas_set_bounds(GOO_CANVAS(canvas), minx, miny, maxx, maxy);
185 }
186
187 canvas_item_t *canvas_image_new(map_t *map, canvas_group_t group,
188 GdkPixbuf *pix, gint x, gint y, float hscale, float vscale) {
189
190 canvas_item_t *item = goo_canvas_image_new(map->group[group], pix,
191 x/hscale, y/vscale, NULL);
192 goo_canvas_item_scale(item, hscale, vscale);
193 return item;
194 }
195
196 void canvas_image_move(canvas_item_t *item, gint x, gint y,
197 float hscale, float vscale) {
198
199 g_object_set(G_OBJECT(item),
200 "x", (gdouble)x / hscale,
201 "y", (gdouble)y / vscale,
202 NULL);
203 }
204
205 /* get the polygon/polyway segment a certain coordinate is over */
206 gint canvas_item_get_segment(canvas_item_t *item, gint x, gint y) {
207
208 canvas_points_t *points = NULL;
209 double line_width = 0;
210
211 g_object_get(G_OBJECT(item),
212 "points", &points,
213 "line-width", &line_width,
214 NULL);
215
216 if(!points) return -1;
217
218 gint retval = -1, i;
219 double mindist = 100;
220 for(i=0;i<points->num_points-1;i++) {
221
222 #define AX (points->coords[2*i+0])
223 #define AY (points->coords[2*i+1])
224 #define BX (points->coords[2*i+2])
225 #define BY (points->coords[2*i+3])
226 #define CX ((double)x)
227 #define CY ((double)y)
228
229 double len2 = pow(BY-AY,2)+pow(BX-AX,2);
230 double m = ((CX-AX)*(BX-AX)+(CY-AY)*(BY-AY)) / len2;
231
232 /* this is a possible candidate */
233 if((m >= 0.0) && (m <= 1.0)) {
234
235 double n;
236 if(fabs(BX-AX) > fabs(BY-AY))
237 n = fabs(sqrt(len2) * (AY+m*(BY-AY)-CY)/(BX-AX));
238 else
239 n = fabs(sqrt(len2) * -(AX+m*(BX-AX)-CX)/(BY-AY));
240
241 /* check if this is actually on the line and closer than anything */
242 /* we found so far */
243 if((n <= line_width/2) && (n < mindist)) {
244 retval = i;
245 mindist = n;
246 }
247 }
248 }
249
250 /* the last and first point are identical for polygons in osm2go. */
251 /* goocanvas doesn't need that, but that's how OSM works and it saves */
252 /* us from having to check the last->first connection for polygons */
253 /* seperately */
254
255 return retval;
256 }
257
258 void canvas_item_get_segment_pos(canvas_item_t *item, gint seg,
259 gint *x0, gint *y0, gint *x1, gint *y1) {
260 printf("get segment %d of item %p\n", seg, item);
261
262 canvas_points_t *points = NULL;
263 g_object_get(G_OBJECT(item), "points", &points, NULL);
264
265 g_assert(points);
266 g_assert(seg < points->num_points-1);
267
268 *x0 = points->coords[2 * seg + 0];
269 *y0 = points->coords[2 * seg + 1];
270 *x1 = points->coords[2 * seg + 2];
271 *y1 = points->coords[2 * seg + 3];
272 }