$search
00001 00002 /*************************************************************************** 00003 * graph_drawing_area.cpp - Graph drawing area derived from Gtk::DrawingArea 00004 * 00005 * Created: Wed Mar 18 10:40:00 2009 00006 * Copyright 2008-2009 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "graph_drawing_area.h" 00024 #include "gvplugin_skillgui_cairo.h" 00025 00026 #include <cmath> 00027 #include <libgen.h> 00028 00036 SkillGuiGraphDrawingArea::SkillGuiGraphDrawingArea() 00037 { 00038 add_events(Gdk::SCROLL_MASK | Gdk::BUTTON_MOTION_MASK); 00039 00040 __gvc = gvContext(); 00041 __graph = NULL; 00042 00043 __graph_fsm = ""; 00044 __graph_dot = ""; 00045 00046 __bbw = __bbh = __pad_x = __pad_y = 0.0; 00047 __translation_x = __translation_y = 0.0; 00048 __scale = 1.0; 00049 __speed = 0.0; 00050 __speed_max = 200.0; 00051 __speed_ramp_distance = 40.0; 00052 __translation_x_setpoint = __translation_y_setpoint = 0.0; 00053 __scale_override = false; 00054 __update_graph = true; 00055 __recording = false; 00056 00057 timeval now; 00058 gettimeofday(&now, NULL); 00059 __last_update_time = (float)now.tv_sec + now.tv_usec/1000000.; 00060 00061 __mouse_motion = false; 00062 00063 gvplugin_skillgui_cairo_setup(__gvc, this); 00064 00065 __fcd_save = new Gtk::FileChooserDialog("Save Graph", 00066 Gtk::FILE_CHOOSER_ACTION_SAVE); 00067 __fcd_open = new Gtk::FileChooserDialog("Load Graph", 00068 Gtk::FILE_CHOOSER_ACTION_OPEN); 00069 __fcd_recording = new Gtk::FileChooserDialog("Recording Directory", 00070 Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); 00071 00072 //Add response buttons the the dialog: 00073 __fcd_save->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00074 __fcd_save->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); 00075 __fcd_open->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00076 __fcd_open->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); 00077 __fcd_recording->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00078 __fcd_recording->add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); 00079 00080 __filter_pdf = new Gtk::FileFilter(); 00081 __filter_pdf->set_name("Portable Document Format (PDF)"); 00082 __filter_pdf->add_pattern("*.pdf"); 00083 __filter_svg = new Gtk::FileFilter(); 00084 __filter_svg->set_name("Scalable Vector Graphic (SVG)"); 00085 __filter_svg->add_pattern("*.svg"); 00086 __filter_png = new Gtk::FileFilter(); 00087 __filter_png->set_name("Portable Network Graphic (PNG)"); 00088 __filter_png->add_pattern("*.png"); 00089 __filter_dot = new Gtk::FileFilter(); 00090 __filter_dot->set_name("DOT Graph"); 00091 __filter_dot->add_pattern("*.dot"); 00092 __fcd_save->add_filter(*__filter_pdf); 00093 __fcd_save->add_filter(*__filter_svg); 00094 __fcd_save->add_filter(*__filter_png); 00095 __fcd_save->add_filter(*__filter_dot); 00096 __fcd_save->set_filter(*__filter_pdf); 00097 00098 __fcd_open->add_filter(*__filter_dot); 00099 __fcd_open->set_filter(*__filter_dot); 00100 00101 add_events(Gdk::SCROLL_MASK | Gdk::BUTTON_MOTION_MASK | 00102 Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK ); 00103 00104 #ifndef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED 00105 signal_expose_event().connect(sigc::mem_fun(*this, &SkillGuiGraphDrawingArea::on_expose_event)); 00106 signal_button_press_event().connect(sigc::mem_fun(*this, &SkillGuiGraphDrawingArea::on_button_press_event)); 00107 signal_button_release_event().connect(sigc::mem_fun(*this, &SkillGuiGraphDrawingArea::on_button_release_event)); 00108 signal_motion_notify_event().connect(sigc::mem_fun(*this, &SkillGuiGraphDrawingArea::on_motion_notify_event)); 00109 #endif 00110 } 00111 00112 SkillGuiGraphDrawingArea::~SkillGuiGraphDrawingArea() 00113 { 00114 if (__graph) { 00115 gvFreeLayout(__gvc, __graph); 00116 agclose(__graph); 00117 } 00118 gvFreeContext(__gvc); 00119 //delete __fcd; 00120 delete __fcd_save; 00121 delete __fcd_open; 00122 delete __fcd_recording; 00123 delete __filter_pdf; 00124 delete __filter_svg; 00125 delete __filter_png; 00126 delete __filter_dot; 00127 } 00128 00129 00133 sigc::signal<void> 00134 SkillGuiGraphDrawingArea::signal_update_disabled() 00135 { 00136 return __signal_update_disabled; 00137 } 00138 00139 00143 void 00144 SkillGuiGraphDrawingArea::set_graph_fsm(std::string fsm_name) 00145 { 00146 if ( __update_graph ) { 00147 if ( __graph_fsm != fsm_name ) { 00148 __scale_override = false; 00149 } 00150 __graph_fsm = fsm_name; 00151 } else { 00152 __nonupd_graph_fsm = fsm_name; 00153 } 00154 } 00155 00156 00160 void 00161 SkillGuiGraphDrawingArea::set_graph(std::string graph) 00162 { 00163 if ( __update_graph ) { 00164 __graph_dot = graph; 00165 layout_graph(); 00166 queue_draw(); 00167 } else { 00168 __nonupd_graph = graph; 00169 } 00170 00171 if ( __recording ) { 00172 char *tmp; 00173 timespec t; 00174 if (clock_gettime(CLOCK_REALTIME, &t) == 0) { 00175 struct tm tms; 00176 localtime_r(&t.tv_sec, &tms); 00177 00178 if ( asprintf(&tmp, "%s/%s_%04i%02i%02i-%02i%02i%02i.%09li.dot", 00179 __record_directory.c_str(), __graph_fsm.c_str(), 00180 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, 00181 tms.tm_hour, tms.tm_min, tms.tm_sec, t.tv_nsec) != -1) { 00182 00183 //printf("Would record to filename %s\n", tmp); 00184 save_dotfile(tmp); 00185 free(tmp); 00186 } else { 00187 printf("Warning: Could not create file name for recording, skipping graph\n"); 00188 } 00189 } else { 00190 printf("Warning: Could not time recording, skipping graph\n"); 00191 } 00192 } 00193 } 00194 00200 void 00201 SkillGuiGraphDrawingArea::set_bb(double bbw, double bbh) 00202 { 00203 __bbw = bbw; 00204 __bbh = bbh; 00205 } 00206 00207 00213 void 00214 SkillGuiGraphDrawingArea::set_pad(double pad_x, double pad_y) 00215 { 00216 __pad_x = pad_x; 00217 __pad_y = pad_y; 00218 } 00219 00220 00226 void 00227 SkillGuiGraphDrawingArea::get_pad(double &pad_x, double &pad_y) 00228 { 00229 if (__scale_override) { 00230 pad_x = pad_y = 0; 00231 } else { 00232 pad_x = __pad_x; 00233 pad_y = __pad_y; 00234 } 00235 } 00236 00237 00243 void 00244 SkillGuiGraphDrawingArea::set_translation(double tx, double ty) 00245 { 00246 __translation_x = tx; 00247 __translation_y = ty; 00248 } 00249 00250 00255 void 00256 SkillGuiGraphDrawingArea::set_scale(double scale) 00257 { 00258 __scale = scale; 00259 } 00260 00265 double 00266 SkillGuiGraphDrawingArea::get_scale() 00267 { 00268 return __scale; 00269 } 00270 00275 void 00276 SkillGuiGraphDrawingArea::get_translation(double &tx, double &ty) 00277 { 00278 tx = __translation_x; 00279 ty = __translation_y; 00280 } 00281 00286 void 00287 SkillGuiGraphDrawingArea::get_dimensions(double &width, double &height) 00288 { 00289 Gtk::Allocation alloc = get_allocation(); 00290 width = alloc.get_width(); 00291 height = alloc.get_height(); 00292 } 00293 00294 00298 void 00299 SkillGuiGraphDrawingArea::zoom_in() 00300 { 00301 __scale_override = true; 00302 Gtk::Allocation alloc = get_allocation(); 00303 double old_scale = __scale; 00304 __scale /= 0.80; 00305 double px, py; 00306 px = (alloc.get_width()/2 - __translation_x ) / (old_scale * __bbw); 00307 py = (alloc.get_height()/2 - __translation_y + __bbh * old_scale) / (old_scale * __bbh); 00308 __translation_x = alloc.get_width()/2 - px*__bbw*__scale; 00309 __translation_y = alloc.get_height()/2 - py*__bbh*__scale + __bbh * __scale; 00310 queue_draw(); 00311 } 00312 00316 void 00317 SkillGuiGraphDrawingArea::zoom_out() 00318 { 00319 __scale_override = true; 00320 if ( __scale > 0.1 ) { 00321 Gtk::Allocation alloc = get_allocation(); 00322 double old_scale = __scale; 00323 __scale *= 0.80; 00324 double px, py; 00325 px = (alloc.get_width()/2 - __translation_x ) / (old_scale * __bbw); 00326 py = (alloc.get_height()/2 - __translation_y + __bbh * old_scale) / (old_scale * __bbh); 00327 __translation_x = alloc.get_width()/2 - px*__bbw*__scale; 00328 __translation_y = alloc.get_height()/2 - py*__bbh*__scale + __bbh * __scale; 00329 queue_draw(); 00330 } 00331 } 00332 00333 00337 void 00338 SkillGuiGraphDrawingArea::zoom_fit() 00339 { 00340 __scale_override = false; 00341 queue_draw(); 00342 } 00343 00344 00348 void 00349 SkillGuiGraphDrawingArea::zoom_reset() 00350 { 00351 Gtk::Allocation alloc = get_allocation(); 00352 if (__scale != 1.0 || ! __scale_override) { 00353 __scale = 1.0; 00354 __scale_override = true; 00355 __translation_x = (alloc.get_width() - __bbw) / 2.0 + __pad_x; 00356 __translation_y = (alloc.get_height() - __bbh) / 2.0 + __bbh - __pad_y; 00357 } 00358 queue_draw(); 00359 } 00360 00361 00365 bool 00366 SkillGuiGraphDrawingArea::scale_override() 00367 { 00368 return __scale_override; 00369 } 00370 00371 00377 Cairo::RefPtr<Cairo::Context> 00378 SkillGuiGraphDrawingArea::get_cairo() 00379 { 00380 return __cairo; 00381 } 00382 00383 00384 00388 bool 00389 SkillGuiGraphDrawingArea::get_update_graph() 00390 { 00391 return __update_graph; 00392 } 00393 00394 00398 void 00399 SkillGuiGraphDrawingArea::set_update_graph(bool update) 00400 { 00401 if (update && ! __update_graph) { 00402 if ( __graph_fsm != __nonupd_graph_fsm ) { 00403 __scale_override = false; 00404 } 00405 __graph_dot = __nonupd_graph; 00406 __graph_fsm = __nonupd_graph_fsm; 00407 queue_draw(); 00408 } 00409 __update_graph = update; 00410 } 00411 00412 00413 void 00414 SkillGuiGraphDrawingArea::save_dotfile(const char *filename) 00415 { 00416 FILE *f = fopen(filename, "w"); 00417 if (f) { 00418 if (fwrite(__graph_dot.c_str(), __graph_dot.length(), 1, f) != 1) { 00419 // bang, ignored 00420 printf("Failed to write dot file '%s'\n", filename); 00421 } 00422 fclose(f); 00423 } 00424 } 00425 00426 00431 bool 00432 SkillGuiGraphDrawingArea::set_follow_active_state(bool follow_active_state) 00433 { 00434 if (follow_active_state) { 00435 __follow_active_state = true; 00436 } else { 00437 __follow_active_state = false; 00438 } 00439 queue_draw(); 00440 return __follow_active_state; 00441 } 00442 00443 00450 bool 00451 SkillGuiGraphDrawingArea::set_recording(bool recording) 00452 { 00453 if (recording) { 00454 Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel()); 00455 __fcd_recording->set_transient_for(*w); 00456 int result = __fcd_recording->run(); 00457 if (result == Gtk::RESPONSE_OK) { 00458 __record_directory = __fcd_recording->get_filename(); 00459 __recording = true; 00460 } 00461 __fcd_recording->hide(); 00462 } else { 00463 __recording = false; 00464 } 00465 return __recording; 00466 } 00467 00468 00470 void 00471 SkillGuiGraphDrawingArea::save() 00472 { 00473 Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel()); 00474 __fcd_save->set_transient_for(*w); 00475 00476 int result = __fcd_save->run(); 00477 if (result == Gtk::RESPONSE_OK) { 00478 00479 Gtk::FileFilter *f = __fcd_save->get_filter(); 00480 std::string filename = __fcd_save->get_filename(); 00481 if (filename != "") { 00482 if (f == __filter_dot) { 00483 save_dotfile(filename.c_str()); 00484 } else { 00485 Cairo::RefPtr<Cairo::Surface> surface; 00486 00487 bool write_to_png = false; 00488 if (f == __filter_pdf) { 00489 surface = Cairo::PdfSurface::create(filename, __bbw, __bbh); 00490 } else if (f == __filter_svg) { 00491 surface = Cairo::SvgSurface::create(filename, __bbw, __bbh); 00492 } else if (f == __filter_png) { 00493 surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 00494 (int)ceilf(__bbw), 00495 (int)ceilf(__bbh)); 00496 write_to_png = true; 00497 } 00498 00499 if (surface) { 00500 __cairo = Cairo::Context::create(surface); 00501 00502 bool old_scale_override = __scale_override; 00503 double old_tx = __translation_x; 00504 double old_ty = __translation_y; 00505 double old_scale = __scale; 00506 __translation_x = __pad_x; 00507 __translation_y = __bbh - __pad_y; 00508 __scale = 1.0; 00509 __scale_override = true; 00510 00511 if (__graph) { 00512 gvRender(__gvc, __graph, (char *)"skillguicairo", NULL); 00513 } 00514 00515 if (write_to_png) { 00516 surface->write_to_png(filename); 00517 } 00518 00519 __cairo.clear(); 00520 00521 __translation_x = old_tx; 00522 __translation_y = old_ty; 00523 __scale = old_scale; 00524 __scale_override = old_scale_override; 00525 } 00526 } 00527 00528 } else { 00529 Gtk::MessageDialog md(*w, "Invalid filename", 00530 /* markup */ false, Gtk::MESSAGE_ERROR, 00531 Gtk::BUTTONS_OK, /* modal */ true); 00532 md.set_title("Invalid File Name"); 00533 md.run(); 00534 } 00535 } 00536 00537 __fcd_save->hide(); 00538 } 00539 00540 00542 void 00543 SkillGuiGraphDrawingArea::open() 00544 { 00545 Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel()); 00546 __fcd_open->set_transient_for(*w); 00547 00548 int result = __fcd_open->run(); 00549 if (result == Gtk::RESPONSE_OK) { 00550 __update_graph = false; 00551 __graph_dot = ""; 00552 char *basec = strdup(__fcd_open->get_filename().c_str()); 00553 char *basen = basename(basec); 00554 __graph_fsm = basen; 00555 free(basec); 00556 00557 FILE *f = fopen(__fcd_open->get_filename().c_str(), "r"); 00558 while (! feof(f)) { 00559 char tmp[4096]; 00560 size_t s; 00561 if ((s = fread(tmp, 1, 4096, f)) > 0) { 00562 __graph_dot.append(tmp, s); 00563 } 00564 } 00565 fclose(f); 00566 __signal_update_disabled.emit(); 00567 queue_draw(); 00568 } 00569 00570 __fcd_open->hide(); 00571 } 00572 00573 00578 bool 00579 SkillGuiGraphDrawingArea::on_expose_event(GdkEventExpose* event) 00580 { 00581 update_translations(); 00582 // This is where we draw on the window 00583 Glib::RefPtr<Gdk::Window> window = get_window(); 00584 if(window) { 00585 //Gtk::Allocation allocation = get_allocation(); 00586 //const int width = allocation.get_width(); 00587 //const int height = allocation.get_height(); 00588 00589 // coordinates for the center of the window 00590 //int xc, yc; 00591 //xc = width / 2; 00592 //yc = height / 2; 00593 00594 __cairo = window->create_cairo_context(); 00595 __cairo->set_source_rgb(1, 1, 1); 00596 __cairo->paint(); 00597 00598 if (__graph) { 00599 Glib::Timer t; 00600 gvRender(__gvc, __graph, (char *)"skillguicairo", NULL); 00601 t.stop(); 00602 //printf("Rendering took %f seconds\n", t.elapsed()); 00603 } 00604 00605 __cairo.clear(); 00606 } 00607 return true; 00608 } 00609 00614 bool 00615 SkillGuiGraphDrawingArea::on_scroll_event(GdkEventScroll *event) 00616 { 00617 if (event->direction == GDK_SCROLL_UP) { 00618 zoom_in(); 00619 } else if (event->direction == GDK_SCROLL_DOWN) { 00620 zoom_out(); 00621 } 00622 return true; 00623 } 00624 00625 00630 bool 00631 SkillGuiGraphDrawingArea::on_button_press_event(GdkEventButton *event) 00632 { 00633 __mouse_motion = true; 00634 __last_mouse_x = event->x; 00635 __last_mouse_y = event->y; 00636 return true; 00637 } 00638 00639 00644 bool 00645 SkillGuiGraphDrawingArea::on_button_release_event(GdkEventButton *event) 00646 { 00647 __mouse_motion = false; 00648 queue_draw(); 00649 return true; 00650 } 00651 00652 00657 bool 00658 SkillGuiGraphDrawingArea::on_motion_notify_event(GdkEventMotion *event) 00659 { 00660 __scale_override = true; 00661 __translation_x -= __last_mouse_x - event->x; 00662 __translation_y -= __last_mouse_y - event->y; 00663 __last_mouse_x = event->x; 00664 __last_mouse_y = event->y; 00665 queue_draw(); 00666 return true; 00667 } 00668 00669 00678 bool 00679 SkillGuiGraphDrawingArea::get_state_position(std::string state_name, 00680 double &px, double &py) 00681 { 00682 if (! __graph) { 00683 return false; 00684 } 00685 00686 for (node_t *n = agfstnode(__graph); n; n = agnxtnode(__graph, n)) { 00687 const char *name = agnameof(n); 00688 pointf nodepos = ND_coord(n); 00689 00690 if (state_name == name) { 00691 boxf bb = GD_bb(__graph); 00692 double bb_width = bb.UR.x - bb.LL.x; 00693 double bb_height = bb.UR.y - bb.LL.y; 00694 00695 px = nodepos.x / bb_width; 00696 py = 1. - (nodepos.y / bb_height); 00697 00698 return true; 00699 } 00700 } 00701 00702 return false; 00703 } 00704 00710 std::string 00711 SkillGuiGraphDrawingArea::get_active_state(graph_t *graph) 00712 { 00713 if (! graph) { 00714 return ""; 00715 } 00716 00717 // Loop through the nodes in the graph/subgraph and find the active node 00718 for (node_t *n = agfstnode(graph); n; n = agnxtnode(graph, n)) { 00719 const char *actattr = agget(n, (char *)"active"); 00720 if (actattr && (strcmp(actattr, "true") == 0) ) { 00721 node_t *mn = agmetanode(graph); 00722 graph_t *mg = mn->graph; 00723 // Check to see if the node has an edge going into a subgraph 00724 for (edge_t *me = agfstout(mg, mn); me; me = agnxtout(mg, me)) { 00725 graph_t *subgraph = agusergraph(me->head); 00726 for (edge_t *e = agfstout(graph, n); e; e = agnxtout(graph, e)) { 00727 for (node_t *subnode = agfstnode(subgraph); subnode; subnode = agnxtnode(subgraph, subnode)) { 00728 if (agnameof(subnode) == agnameof(e->head)) { 00729 // The node goes into a subgraph, recursively find and return the active subnode name 00730 return get_active_state(subgraph); 00731 } 00732 } 00733 } 00734 } 00735 // The node has no subgraph, return the name of the active node 00736 return agnameof(n); 00737 } 00738 } 00739 00740 return ""; 00741 } 00742 00743 00747 void 00748 SkillGuiGraphDrawingArea::update_translations() 00749 { 00750 timeval now; 00751 gettimeofday(&now, NULL); 00752 double now_time = (float)now.tv_sec + now.tv_usec/1000000.; 00753 00754 if (__follow_active_state && __scale_override && !__mouse_motion) { 00755 double px, py; 00756 std::string active_state = get_active_state(__graph); 00757 if (! get_state_position(active_state, px, py)) { 00758 px = py = 0.5; 00759 } 00760 Gtk::Allocation alloc = get_allocation(); 00761 __translation_x_setpoint = alloc.get_width()/2 - px*__bbw*__scale; 00762 __translation_y_setpoint = alloc.get_height()/2 - py*__bbh*__scale + __bbh * __scale; 00763 00764 float d, dx, dy, dt; 00765 dx = __translation_x_setpoint - __translation_x; 00766 dy = __translation_y_setpoint - __translation_y; 00767 d = sqrt(pow(dx,2) + pow(dy,2)); 00768 dt = std::min(1.0, std::max(0.1, now_time - __last_update_time)); 00769 double v = 0.0; 00770 //printf("d=%f speed=%f\n", d, __speed); 00771 if (d < 0.05) { 00772 // At goal, don't move 00773 v = 0; 00774 //printf("Reached, v=%f, d=%f, dx=%f, dy=%f, txs=%f tys=%f, tx=%f ty=%f\n", 00775 // v, d, dx, dy, __translation_x_setpoint, __translation_y_setpoint, 00776 // __translation_x, __translation_y); 00777 __translation_x = __translation_x_setpoint; 00778 __translation_y = __translation_y_setpoint; 00779 } else if (d < __speed_ramp_distance) { 00780 // Approaching goal, slow down 00781 v = __speed - __speed_max * dt; 00782 //printf("Approaching, v=%f\n", v); 00783 } else if (__speed == 0.0) { 00784 // just starting 00785 v = __speed_max / 10.; 00786 dt = 0.1; 00787 //printf("Starting, v=%f\n", v); 00788 } else if (__speed < __speed_max) { 00789 // Starting toward goal, speed up 00790 v = __speed + __speed_max * dt; 00791 //printf("Speeding up, v=%f\n", v); 00792 } else { 00793 // Moving towards goal, keep going 00794 v = __speed; 00795 //printf("Moving, v=%f\n", v); 00796 } 00797 00798 // Limit v to __speed_max 00799 v = std::min(v, __speed_max); 00800 00801 // Set new translations 00802 //printf("d=%f v=%f dx=%f dy=%f dt=%f dto=%f\n", d, v, dx, dy, dt, 00803 // now_time - __last_update_time); 00804 if ( d <= v * dt ) { 00805 __translation_x = __translation_x_setpoint; 00806 __translation_y = __translation_y_setpoint; 00807 __speed = 0; 00808 } else { 00809 __translation_x = (dx / d) * v * dt + __translation_x; 00810 __translation_y = (dy / d) * v * dt + __translation_y; 00811 __speed = v; 00812 } 00813 if (false) { 00814 __translation_x = __translation_x_setpoint; 00815 __translation_y = __translation_y_setpoint; 00816 __speed = 0; 00817 queue_draw(); 00818 } 00819 __last_update_time = now_time; 00820 if (__speed > 0) { 00821 queue_draw(); 00822 } 00823 } 00824 } 00825 00826 00827 void 00828 SkillGuiGraphDrawingArea::layout_graph() 00829 { 00830 if (__graph) { 00831 gvFreeLayout(__gvc, __graph); 00832 agclose(__graph); 00833 } 00834 __graph = agmemread((char *)__graph_dot.c_str()); 00835 if (__graph) { 00836 gvLayout(__gvc, __graph, (char *)"dot"); 00837 } 00838 }