gdc-broken_edge.cc
author hegyi
Tue, 27 Feb 2007 17:18:19 +0000
changeset 191 af2ed974ab68
parent 174 95872af46fc4
child 194 6b2b718420eb
permissions -rw-r--r--
GUI can now export graph to EPS.
     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   if(length!=0)
    97     {
    98       unit_vector_in_dir/=length;
    99     }
   100 
   101   // update the arrow
   102   drawArrow(unit_vector_in_dir);
   103 
   104   // update the edge
   105   Gnome::Canvas::Points points;
   106   Node source = ms.graph.source(edge);
   107   Node target = ms.graph.target(edge);
   108   points.push_back(Gnome::Art::Point(ms.coords[source].x,
   109         ms.coords[source].y));
   110   points.push_back(Gnome::Art::Point(ms.arrow_pos[edge].x,
   111         ms.arrow_pos[edge].y));
   112   points.push_back(Gnome::Art::Point(ms.coords[target].x,
   113         ms.coords[target].y));
   114   line.property_points().set_value(points);
   115 }
   116 
   117 bool GraphDisplayerCanvas::BrokenEdge::edgeFormerEventHandler(GdkEvent* e)
   118 {
   119   switch(e->type)
   120   {
   121     case GDK_BUTTON_PRESS:
   122       //we mark the location of the event to be able to calculate parameters
   123       //of dragging
   124       if(canvas.getActualTool()!=CREATE_NODE)
   125       {
   126         canvas.toggleEdgeActivity(this, true);
   127         clicked_x=e->button.x;
   128         clicked_y=e->button.y;
   129         isbutton=true;
   130       }
   131       break;
   132     case GDK_BUTTON_RELEASE:
   133       if(canvas.getActualTool()!=CREATE_NODE)
   134       {
   135         canvas.toggleEdgeActivity(this, false);
   136         isbutton=false;
   137       }
   138       break;
   139     case GDK_MOTION_NOTIFY:
   140       //we only have to do sg. if the mouse button is pressed
   141       if(isbutton)
   142       {
   143         //new coordinates will be the old values,
   144         //because the item will be moved to the
   145         //new coordinate therefore the new movement
   146         //has to be calculated from here
   147 
   148         double dx=e->motion.x-clicked_x;
   149         double dy=e->motion.y-clicked_y;
   150 
   151         Gnome::Canvas::Points points_new;
   152 
   153         canvas.mytab.mapstorage.arrow_pos.set(edge, canvas.mytab.mapstorage.arrow_pos[edge] + XY(dx, dy));
   154 
   155         draw();
   156         canvas.textReposition(canvas.mytab.mapstorage.arrow_pos[edge]);
   157 
   158         clicked_x=e->motion.x;
   159         clicked_y=e->motion.y;
   160 
   161       }
   162     default: break;
   163   }
   164 
   165   return true;
   166 }
   167 
   168 void GraphDisplayerCanvas::BrokenEdge::setLineWidth(int w)
   169 {
   170   line.property_width_units().set_value(w);
   171 }
   172 
   173 void GraphDisplayerCanvas::BrokenEdge::setFillColor(Gdk::Color c)
   174 {
   175   line.property_fill_color_gdk().set_value(c);
   176 }
   177 
   178 GraphDisplayerCanvas::LoopEdge::LoopEdge(Gnome::Canvas::Group& _group,
   179     Edge _edge, GraphDisplayerCanvas& _canvas) :
   180   EdgeBase(_group, _edge, _canvas), line(*this), isbutton(false)
   181 {
   182   arrow.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::LoopEdge::edgeFormerEventHandler));
   183 
   184   line.property_outline_color().set_value("green");
   185   line.property_width_units().set_value(10);
   186   line.lower_to_bottom();
   187 
   188   draw();
   189 }
   190 
   191 GraphDisplayerCanvas::LoopEdge::~LoopEdge()
   192 {
   193 }
   194 
   195 void GraphDisplayerCanvas::LoopEdge::draw()
   196 {
   197   MapStorage& ms = canvas.mytab.mapstorage;
   198 
   199   Node node = ms.graph.source(edge);
   200   XY center = (ms.coords[node] + ms.arrow_pos[edge]) / 2.0;
   201 
   202   XY unit_vector_in_dir(rot90(center - ms.arrow_pos[edge]));
   203   double length = sqrt(unit_vector_in_dir.normSquare());
   204   unit_vector_in_dir /= length;
   205 
   206   drawArrow(unit_vector_in_dir);
   207 
   208   double radius =
   209     sqrt((ms.arrow_pos[edge] - ms.coords[node]).normSquare()) / 2.0;
   210 
   211   XY p1 = center + XY(-radius,  radius);
   212   XY p2 = center + XY( radius, -radius);
   213   line.property_x1().set_value(p1.x);
   214   line.property_y1().set_value(p1.y);
   215   line.property_x2().set_value(p2.x);
   216   line.property_y2().set_value(p2.y);
   217 }
   218 
   219 void GraphDisplayerCanvas::LoopEdge::setLineWidth(int w)
   220 {
   221   line.property_width_units().set_value(w);
   222 }
   223 
   224 void GraphDisplayerCanvas::LoopEdge::setFillColor(Gdk::Color c)
   225 {
   226   line.property_outline_color_gdk().set_value(c);
   227 }
   228 
   229 bool GraphDisplayerCanvas::LoopEdge::edgeFormerEventHandler(GdkEvent* e)
   230 {
   231   switch(e->type)
   232   {
   233     case GDK_BUTTON_PRESS:
   234       if(canvas.getActualTool()!=CREATE_NODE)
   235       {
   236         canvas.toggleEdgeActivity(this, true);
   237         isbutton=true;
   238       }
   239       break;
   240     case GDK_BUTTON_RELEASE:
   241       if(canvas.getActualTool()!=CREATE_NODE)
   242       {
   243         canvas.toggleEdgeActivity(this, false);
   244         isbutton=false;
   245       }
   246       break;
   247     case GDK_MOTION_NOTIFY:
   248       if(isbutton)
   249       {
   250         canvas.mytab.mapstorage.arrow_pos.set(edge, XY(e->motion.x, e->motion.y));
   251 
   252         draw();
   253         canvas.textReposition(canvas.mytab.mapstorage.arrow_pos[edge]);
   254       }
   255     default: break;
   256   }
   257   return true;
   258 }