Broken edges are appearing.
1 #include <graph_displayer_canvas.h>
2 #include <broken_edge.h>
5 GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & gr, CoordinatesMap & cm, MapStorage & ms):g(gr),nodesmap(g),edgesmap(g),edgetextmap(g),displayed_graph(*(root()), 0, 0),mapstorage(ms),isbutton(false),active_item(NULL),target_item(NULL)
8 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
13 //set_center_scroll_region(true);
15 //first edges are drawn, to hide joining with nodes later
17 for (EdgeIt i(g); i!=INVALID; ++i)
20 //drawing green lines, coordinates are from cm
22 Gnome::Canvas::Points coos;
23 coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y));
24 coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y));
26 //edgesmap[i]=new Gnome::Canvas::Line(displayed_graph, coos);
27 edgesmap[i]=new BrokenEdge(displayed_graph, coos);
28 *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green");
29 edgesmap[i]->property_width_pixels().set_value(10);
31 //initializing edge-text as well, to empty string
33 double x1, x2, y1, y2;
34 edgesmap[i]->get_bounds(x1, y1, x2, y2);
36 edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
37 edgetextmap[i]->property_fill_color().set_value("black");
40 //afterwards nodes come to be drawn
43 int maxx=0, maxy=0, minx=(int)cm[i].x, miny=(int)cm[i].y;
45 for (; i!=INVALID; ++i)
47 //minimum and maximum is gathered to be able to zoom to the graph correctly (whole figure should be seen)
49 if(cm[i].x>maxx)maxx=(int)cm[i].x;
50 if(cm[i].y>maxy)maxy=(int)cm[i].y;
51 if(cm[i].x<minx)minx=(int)cm[i].x;
52 if(cm[i].y<miny)miny=(int)cm[i].y;
54 //drawing bule nodes, with black line around them
56 nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20);
57 *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
58 *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
59 //!!!!!!! (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i));
65 GraphDisplayerCanvas::~GraphDisplayerCanvas()
68 //writing out the end state of the graph
69 //\todo all the maps has to be write out!
71 Graph::NodeMap <int> id(g);
72 Graph::NodeMap <double> xc(g);
73 Graph::NodeMap <double> yc(g);
77 for (NodeIt i(g); i!=INVALID; ++i)
80 nodesmap[i]->get_bounds(x1, y1, x2, y2);
87 GraphWriter<Graph> writer(std::cout,g);
89 writer.writeNodeMap("id", id);
90 writer.writeNodeMap("coordinates_x", xc);
91 writer.writeNodeMap("coordinates_y", yc);
95 int GraphDisplayerCanvas::changeLineWidth (std::string mapname)
97 for (EdgeIt i(g); i!=INVALID; ++i)
99 int w=(int)(*(mapstorage.edgemap_storage)[mapname])[i];
100 edgesmap[i]->property_width_pixels().set_value(w);
105 int GraphDisplayerCanvas::changeColor (std::string mapname)
108 //function maps the range of the maximum and
109 //the minimum of the nodemap to the range of
112 for (EdgeIt i(g); i!=INVALID; ++i)
114 double w=(*(mapstorage.edgemap_storage)[mapname])[i];
115 double max=mapstorage.maxOfEdgeMap(mapname);
116 double min=mapstorage.minOfEdgeMap(mapname);
118 //std::cout<<w<<" "<<max<<" "<<min<<" "<<100*(w-min)/(max-min)<<std::endl;
122 color.set_rgb_p (0, 100*(w-min)/(max-min), 0);
126 color.set_rgb_p (0, 100, 0);
129 edgesmap[i]->property_fill_color_gdk().set_value(color);
134 int GraphDisplayerCanvas::changeText (std::string mapname)
137 //the number in the map will be written on the edge
138 //EXCEPT when the name of the map is Text, because
139 //in that case empty string will be written, because
140 //that is the deleter map
141 //\todo isn't it a bit woodcutter?
143 for (EdgeIt i(g); i!=INVALID; ++i)
147 double number=(*(mapstorage.edgemap_storage)[mapname])[i];
148 int length=(int)(floor(log(number)/log(10)))+1;
149 int maxpos=(int)(pow(10,length-1));
150 int strl=length+1+RANGE;
151 char * str=new char[strl];
155 for(int j=0;j<strl;j++)
159 int digit=(int)(number/maxpos);
161 number-=digit*maxpos;
166 edgetextmap[i]->property_text().set_value(str);
170 edgetextmap[i]->property_text().set_value("");
176 bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n)
180 case GDK_BUTTON_PRESS:
181 //we mark the location of the event to be able to calculate parameters of dragging
182 clicked_x=e->button.x;
183 clicked_y=e->button.y;
184 active_item=(get_item_at(e->button.x, e->button.y));
187 case GDK_BUTTON_RELEASE:
190 updateScrollRegion();
192 case GDK_MOTION_NOTIFY:
193 //we only have to do sg. if the mouse button is pressed
196 //new coordinates will be the old values,
197 //because the item will be moved to the
198 //new coordinate therefore the new movement
199 //has to be calculated from here
201 double dx=e->motion.x-clicked_x;
202 double dy=e->motion.y-clicked_y;
203 active_item->move(dx, dy);
204 clicked_x=e->motion.x;
205 clicked_y=e->motion.y;
207 //all the edges connected to the moved point has to be redrawn
211 for(;e!=INVALID;g.nextOut(e))
213 Gnome::Canvas::Points coos;
214 double x1, x2, y1, y2;
216 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
217 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
219 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
220 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
222 edgesmap[e]->property_points().set_value(coos);
224 edgesmap[e]->get_bounds(x1, y1, x2, y2);
226 edgetextmap[e]->property_x().set_value((x1+x2)/2);
227 edgetextmap[e]->property_y().set_value((y1+y2)/2);
231 for(;e!=INVALID;g.nextIn(e))
233 Gnome::Canvas::Points coos;
234 double x1, x2, y1, y2;
236 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
237 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
239 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
240 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
242 edgesmap[e]->property_points().set_value(coos);
244 edgesmap[e]->get_bounds(x1, y1, x2, y2);
246 edgetextmap[e]->property_x().set_value((x1+x2)/2);
247 edgetextmap[e]->property_y().set_value((y1+y2)/2);
255 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
257 Gnome::Canvas::CanvasAA::on_expose_event(event);
263 void GraphDisplayerCanvas::zoomIn()
266 (1.0 + (double) zoom_step / 100.0) * get_pixels_per_unit());
269 void GraphDisplayerCanvas::zoomOut()
272 (1.0 - (double) zoom_step / 100.0) * get_pixels_per_unit());
275 void GraphDisplayerCanvas::zoomFit()
277 // get the height and width of the canvas
278 Gtk::Allocation a = get_allocation();
279 int aw = a.get_width();
280 int ah = a.get_height();
282 aw -= 5; if (aw < 0) aw = 0;
283 ah -= 5; if (ah < 0) ah = 0;
285 // get the bounding box of the graph
286 double wx1, wy1, wx2, wy2;
287 Gnome::Canvas::Item* pCanvasItem = root();
288 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
290 // fit the graph to the window
291 double ppu1 = (double) aw / fabs(wx2 - wx1);
292 double ppu2 = (double) ah / fabs(wy2 - wy1);
293 set_pixels_per_unit((ppu1 < ppu2) ? ppu1 : ppu2);
296 void GraphDisplayerCanvas::zoom100()
298 set_pixels_per_unit(1.0);
301 void GraphDisplayerCanvas::updateScrollRegion()
303 double wx1, wy1, wx2, wy2;
304 Gnome::Canvas::Item* pCanvasItem = root();
305 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
306 set_scroll_region(wx1, wy1, wx2, wy2);
309 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
311 actual_handler.disconnect();
316 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::move_event_handler), false);
319 //it has to assigned to canvas, because all the canvas has to be monitored, not only the elements of the already drawn group
321 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false);
325 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
329 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraser_event_handler), false);
337 bool GraphDisplayerCanvas::move_event_handler(GdkEvent* e)
341 case GDK_BUTTON_PRESS:
342 //we mark the location of the event to be able to calculate parameters of dragging
343 clicked_x=e->button.x;
344 clicked_y=e->button.y;
345 active_item=(get_item_at(e->button.x, e->button.y));
347 for (NodeIt i(g); i!=INVALID; ++i)
349 if(nodesmap[i]==active_item)
356 case GDK_BUTTON_RELEASE:
360 updateScrollRegion();
362 case GDK_MOTION_NOTIFY:
363 //we only have to do sg. if the mouse button is pressed AND the click was on a node that was found in the set of nodes
364 if(active_node!=INVALID)
366 //new coordinates will be the old values,
367 //because the item will be moved to the
368 //new coordinate therefore the new movement
369 //has to be calculated from here
371 double dx=e->motion.x-clicked_x;
372 double dy=e->motion.y-clicked_y;
374 active_item->move(dx, dy);
376 clicked_x=e->motion.x;
377 clicked_y=e->motion.y;
379 //all the edges connected to the moved point has to be redrawn
382 g.firstOut(e,active_node);
384 for(;e!=INVALID;g.nextOut(e))
386 Gnome::Canvas::Points coos;
387 double x1, x2, y1, y2;
389 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
390 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
392 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
393 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
395 edgesmap[e]->property_points().set_value(coos);
397 edgesmap[e]->get_bounds(x1, y1, x2, y2);
399 edgetextmap[e]->property_x().set_value((x1+x2)/2);
400 edgetextmap[e]->property_y().set_value((y1+y2)/2);
403 g.firstIn(e,active_node);
404 for(;e!=INVALID;g.nextIn(e))
406 Gnome::Canvas::Points coos;
407 double x1, x2, y1, y2;
409 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
410 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
412 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
413 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
415 edgesmap[e]->property_points().set_value(coos);
417 edgesmap[e]->get_bounds(x1, y1, x2, y2);
419 edgetextmap[e]->property_x().set_value((x1+x2)/2);
420 edgetextmap[e]->property_y().set_value((y1+y2)/2);
429 bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e)
434 //draw the new node in red at the clicked place
435 case GDK_BUTTON_PRESS:
438 active_node=NodeIt(g,g.addNode());
440 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
442 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
443 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
444 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
445 *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
446 (nodesmap[active_node])->show();
450 case GDK_MOTION_NOTIFY:
452 double world_motion_x, world_motion_y;
453 GdkEvent * generated=new GdkEvent();
454 window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y);
455 generated->motion.x=world_motion_x;
456 generated->motion.y=world_motion_y;
457 generated->type=GDK_MOTION_NOTIFY;
458 move_event_handler(generated);
462 //finalize the new node
463 case GDK_BUTTON_RELEASE:
465 *active_item << Gnome::Canvas::Properties::fill_color("blue");
468 updateScrollRegion();
476 bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e)
480 case GDK_BUTTON_PRESS:
481 //in edge creatino right button has special meaning
482 if(e->button.button!=3)
484 //there is not yet selected node
485 if(active_node==INVALID)
487 //we mark the location of the event to be able to calculate parameters of dragging
488 clicked_x=e->button.x;
489 clicked_y=e->button.y;
490 active_item=(get_item_at(e->button.x, e->button.y));
492 for (NodeIt i(g); i!=INVALID; ++i)
494 if(nodesmap[i]==active_item)
499 //the clicked item is really a node
500 if(active_node!=INVALID)
502 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
505 //clicked item was not a node. It could be e.g. edge.
511 //we only have to do sg. if the mouse button
512 // is pressed already once AND the click was
513 // on a node that was found in the set of
514 //nodes, and now we only search for the second
518 target_item=(get_item_at(e->button.x, e->button.y));
519 Graph::NodeIt target_node=INVALID;
520 for (NodeIt i(g); i!=INVALID; ++i)
522 if(nodesmap[i]==target_item)
527 //the clicked item is a node, the edge can be drawn
528 if(target_node!=INVALID)
530 *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
533 active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
535 //calculating coordinates of new edge
536 Gnome::Canvas::Points coos;
537 double x1, x2, y1, y2;
539 active_item->get_bounds(x1, y1, x2, y2);
540 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
542 target_item->get_bounds(x1, y1, x2, y2);
543 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
546 edgesmap[active_edge]=new Gnome::Canvas::Line(displayed_graph, coos);
547 *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
548 edgesmap[active_edge]->property_width_pixels().set_value(10);
550 //redraw nodes to blank terminations of the new edge
551 target_item->raise_to_top();
552 active_item->raise_to_top();
554 //initializing edge-text as well, to empty string
555 edgesmap[active_edge]->get_bounds(x1, y1, x2, y2);
556 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
557 edgetextmap[active_edge]->property_fill_color().set_value("black");
559 //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore.
567 case GDK_BUTTON_RELEASE:
569 //we clear settings in two cases
570 //1: the edge is ready (target_item has valid value)
571 //2: the edge creation is cancelled with right button
572 if((target_item)||(e->button.button==3))
576 *active_item << Gnome::Canvas::Properties::fill_color("blue");
581 *target_item << Gnome::Canvas::Properties::fill_color("blue");
594 bool GraphDisplayerCanvas::eraser_event_handler(GdkEvent* e)
598 case GDK_BUTTON_PRESS:
599 active_item=(get_item_at(e->button.x, e->button.y));
602 for (NodeIt i(g); i!=INVALID; ++i)
604 if(nodesmap[i]==active_item)
609 if(active_node==INVALID)
611 for (EdgeIt i(g); i!=INVALID; ++i)
613 if(edgesmap[i]==active_item)
619 *active_item << Gnome::Canvas::Properties::fill_color("red");
622 case GDK_BUTTON_RELEASE:
623 if(active_item==(get_item_at(e->button.x, e->button.y)))
625 if(active_node!=INVALID)
628 //collecting edges to delete
630 std::set<Graph::Edge> edges_to_delete;
632 g.firstOut(e,active_node);
633 for(;e!=INVALID;g.nextOut(e))
635 edges_to_delete.insert(e);
638 g.firstIn(e,active_node);
639 for(;e!=INVALID;g.nextIn(e))
641 edges_to_delete.insert(e);
644 //deleting collected edges
645 for(std::set<Graph::Edge>::iterator edge_set_it=edges_to_delete.begin();edge_set_it!=edges_to_delete.end();edge_set_it++)
647 delete_item(*edge_set_it);
649 delete_item(active_node);
651 //a simple edge was chosen
654 delete_item(active_edge);
659 //pointer was moved, deletion is cancelled
662 if(active_node!=INVALID)
664 *active_item << Gnome::Canvas::Properties::fill_color("blue");
668 *active_item << Gnome::Canvas::Properties::fill_color("green");
677 case GDK_MOTION_NOTIFY:
686 void GraphDisplayerCanvas::delete_item(NodeIt node_to_delete)
688 delete(nodesmap[node_to_delete]);
689 g.erase(node_to_delete);
692 void GraphDisplayerCanvas::delete_item(EdgeIt edge_to_delete)
694 delete(edgesmap[edge_to_delete]);
695 g.erase(edge_to_delete);
698 void GraphDisplayerCanvas::delete_item(Graph::Edge edge_to_delete)
700 delete(edgesmap[edge_to_delete]);
701 g.erase(edge_to_delete);