gdc-broken_edge.cc
author ladanyi
Wed, 10 Jan 2007 14:37:46 +0000
changeset 184 4e8704aae278
parent 152 d99e115d0d26
child 189 8b69c54d5bf0
permissions -rw-r--r--
Added support for setting the background form an image file.
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include "graph_displayer_canvas.h"
    20 #include <cmath>
    21 
    22 GraphDisplayerCanvas::EdgeBase::EdgeBase(Gnome::Canvas::Group& _group, Edge _edge, GraphDisplayerCanvas& _canvas) : 
    23   Gnome::Canvas::Group(_group), edge(_edge), canvas(_canvas), arrow(*this)
    24 {
    25   arrow.property_fill_color().set_value("red");
    26   arrow.lower_to_bottom();
    27   lower_to_bottom();
    28 }
    29 
    30 GraphDisplayerCanvas::EdgeBase::~EdgeBase()
    31 {
    32 }
    33 
    34 void GraphDisplayerCanvas::EdgeBase::drawArrow(XY unit_vector_in_dir)
    35 {
    36   MapStorage& ms = canvas.mytab.mapstorage;
    37   XY center(ms.arrow_pos[edge]);
    38   XY unit_norm_vector(0-unit_vector_in_dir.y, unit_vector_in_dir.x);
    39 
    40   //       /\       // top
    41   //      /  \      //
    42   //      -  -      // c(enter)l(eft), ccl, ccr, cr
    43   //       ||       //
    44   //       ||       // b(ottom)l, br
    45 
    46   double size=3;
    47 
    48   XY bl (center - unit_vector_in_dir * 3 * size + unit_norm_vector * size );
    49   XY br (center - unit_vector_in_dir * 3 * size - unit_norm_vector * size );
    50   XY ccl(center + unit_vector_in_dir *  size + unit_norm_vector * size );
    51   XY ccr(center + unit_vector_in_dir *  size - unit_norm_vector * size );
    52   XY cl (center + unit_vector_in_dir *  size + unit_norm_vector * 2 * size );
    53   XY cr (center + unit_vector_in_dir *  size - unit_norm_vector * 2 * size );
    54   XY top(center + unit_vector_in_dir * 3 * size);
    55 
    56   Gnome::Canvas::Points arrow_points;
    57   arrow_points.push_back(Gnome::Art::Point( bl.x , bl.y  ) );
    58   arrow_points.push_back(Gnome::Art::Point( br.x , br.y  ) );
    59   arrow_points.push_back(Gnome::Art::Point( ccr.x, ccr.y ) );
    60   arrow_points.push_back(Gnome::Art::Point( cr.x , cr.y  ) );
    61   arrow_points.push_back(Gnome::Art::Point( top.x, top.y ) );
    62   arrow_points.push_back(Gnome::Art::Point( cl.x , cl.y  ) );
    63   arrow_points.push_back(Gnome::Art::Point( ccl.x, ccl.y ) );
    64 
    65   arrow.property_points().set_value(arrow_points);
    66 }
    67 
    68 GraphDisplayerCanvas::BrokenEdge::BrokenEdge(Gnome::Canvas::Group & g,
    69     Edge _edge, GraphDisplayerCanvas & gc) : EdgeBase(g, _edge, gc),
    70   isbutton(false), line(*this)
    71 {
    72   arrow.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::BrokenEdge::edgeFormerEventHandler));
    73 
    74   line.property_fill_color().set_value("green");
    75   line.property_width_units().set_value(10);    
    76   line.lower_to_bottom();
    77 
    78   draw();
    79 }
    80 
    81 GraphDisplayerCanvas::BrokenEdge::~BrokenEdge()
    82 {
    83 }
    84 
    85 void GraphDisplayerCanvas::BrokenEdge::draw()
    86 {
    87   MapStorage& ms = canvas.mytab.mapstorage;
    88 
    89   //calculating coordinates of the direction indicator arrow
    90   XY head(ms.coords[ms.graph.target(edge)]);
    91   XY center(ms.arrow_pos[edge]);
    92 
    93   XY unit_vector_in_dir(head-center);
    94   double length=sqrt( unit_vector_in_dir.normSquare() );
    95 
    96   unit_vector_in_dir/=length;
    97 
    98   // update the arrow
    99   drawArrow(unit_vector_in_dir);
   100 
   101   // update the edge
   102   Gnome::Canvas::Points points;
   103   Node source = ms.graph.source(edge);
   104   Node target = ms.graph.target(edge);
   105   points.push_back(Gnome::Art::Point(ms.coords[source].x,
   106         ms.coords[source].y));
   107   points.push_back(Gnome::Art::Point(ms.arrow_pos[edge].x,
   108         ms.arrow_pos[edge].y));
   109   points.push_back(Gnome::Art::Point(ms.coords[target].x,
   110         ms.coords[target].y));
   111   line.property_points().set_value(points);
   112 }
   113 
   114 bool GraphDisplayerCanvas::BrokenEdge::edgeFormerEventHandler(GdkEvent* e)
   115 {
   116   switch(e->type)
   117   {
   118     case GDK_BUTTON_PRESS:
   119       //we mark the location of the event to be able to calculate parameters
   120       //of dragging
   121       if(canvas.getActualTool()!=CREATE_NODE)
   122       {
   123         canvas.toggleEdgeActivity(this, true);
   124         clicked_x=e->button.x;
   125         clicked_y=e->button.y;
   126         isbutton=true;
   127       }
   128       break;
   129     case GDK_BUTTON_RELEASE:
   130       if(canvas.getActualTool()!=CREATE_NODE)
   131       {
   132         canvas.toggleEdgeActivity(this, false);
   133         isbutton=false;
   134       }
   135       break;
   136     case GDK_MOTION_NOTIFY:
   137       //we only have to do sg. if the mouse button is pressed
   138       if(isbutton)
   139       {
   140         //new coordinates will be the old values,
   141         //because the item will be moved to the
   142         //new coordinate therefore the new movement
   143         //has to be calculated from here
   144 
   145         double dx=e->motion.x-clicked_x;
   146         double dy=e->motion.y-clicked_y;
   147 
   148         Gnome::Canvas::Points points_new;
   149 
   150         canvas.mytab.mapstorage.arrow_pos.set(edge, canvas.mytab.mapstorage.arrow_pos[edge] + XY(dx, dy));
   151 
   152         draw();
   153         canvas.textReposition(canvas.mytab.mapstorage.arrow_pos[edge]);
   154 
   155         clicked_x=e->motion.x;
   156         clicked_y=e->motion.y;
   157 
   158       }
   159     default: break;
   160   }
   161 
   162   return true;
   163 }
   164 
   165 void GraphDisplayerCanvas::BrokenEdge::setLineWidth(int w)
   166 {
   167   line.property_width_units().set_value(w);
   168 }
   169 
   170 void GraphDisplayerCanvas::BrokenEdge::setFillColor(Gdk::Color c)
   171 {
   172   line.property_fill_color_gdk().set_value(c);
   173 }
   174 
   175 GraphDisplayerCanvas::LoopEdge::LoopEdge(Gnome::Canvas::Group& _group,
   176     Edge _edge, GraphDisplayerCanvas& _canvas) :
   177   EdgeBase(_group, _edge, _canvas), line(*this), isbutton(false)
   178 {
   179   arrow.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::LoopEdge::edgeFormerEventHandler));
   180 
   181   line.property_outline_color().set_value("green");
   182   line.property_width_units().set_value(10);
   183   line.lower_to_bottom();
   184 
   185   draw();
   186 }
   187 
   188 GraphDisplayerCanvas::LoopEdge::~LoopEdge()
   189 {
   190 }
   191 
   192 void GraphDisplayerCanvas::LoopEdge::draw()
   193 {
   194   MapStorage& ms = canvas.mytab.mapstorage;
   195 
   196   Node node = ms.graph.source(edge);
   197   XY center = (ms.coords[node] + ms.arrow_pos[edge]) / 2.0;
   198 
   199   XY unit_vector_in_dir(rot90(center - ms.arrow_pos[edge]));
   200   double length = sqrt(unit_vector_in_dir.normSquare());
   201   unit_vector_in_dir /= length;
   202 
   203   drawArrow(unit_vector_in_dir);
   204 
   205   double radius =
   206     sqrt((ms.arrow_pos[edge] - ms.coords[node]).normSquare()) / 2.0;
   207 
   208   XY p1 = center + XY(-radius,  radius);
   209   XY p2 = center + XY( radius, -radius);
   210   line.property_x1().set_value(p1.x);
   211   line.property_y1().set_value(p1.y);
   212   line.property_x2().set_value(p2.x);
   213   line.property_y2().set_value(p2.y);
   214 }
   215 
   216 void GraphDisplayerCanvas::LoopEdge::setLineWidth(int w)
   217 {
   218   line.property_width_units().set_value(w);
   219 }
   220 
   221 void GraphDisplayerCanvas::LoopEdge::setFillColor(Gdk::Color c)
   222 {
   223   line.property_outline_color_gdk().set_value(c);
   224 }
   225 
   226 bool GraphDisplayerCanvas::LoopEdge::edgeFormerEventHandler(GdkEvent* e)
   227 {
   228   switch(e->type)
   229   {
   230     case GDK_BUTTON_PRESS:
   231       if(canvas.getActualTool()!=CREATE_NODE)
   232       {
   233         canvas.toggleEdgeActivity(this, true);
   234         isbutton=true;
   235       }
   236       break;
   237     case GDK_BUTTON_RELEASE:
   238       if(canvas.getActualTool()!=CREATE_NODE)
   239       {
   240         canvas.toggleEdgeActivity(this, false);
   241         isbutton=false;
   242       }
   243       break;
   244     case GDK_MOTION_NOTIFY:
   245       if(isbutton)
   246       {
   247         canvas.mytab.mapstorage.arrow_pos.set(edge, XY(e->motion.x, e->motion.y));
   248 
   249         draw();
   250         canvas.textReposition(canvas.mytab.mapstorage.arrow_pos[edge]);
   251       }
   252     default: break;
   253   }
   254   return true;
   255 }