00001 #include "OglGui/Graph.h"
00002
00003 #include <string>
00004 #include <map>
00005 #include <vector>
00006 #include <utility>
00007 #include <algorithm>
00008
00009 #include <boost/graph/graph_traits.hpp>
00010 #include <boost/graph/adjacency_list.hpp>
00011 #include <boost/graph/simple_point.hpp>
00012 #include <boost/graph/circle_layout.hpp>
00013 #include <boost/graph/fruchterman_reingold.hpp>
00014
00015 #include "Tag.h"
00016
00017 using namespace OglGui;
00018 using namespace std;
00019 using namespace boost;
00020
00021 class BoostedGraph : public OglGui::Graph, public OglGui::WindowListener {
00022 public:
00023 typedef adjacency_list<vecS, vecS, undirectedS, property<vertex_name_t, string> > Graph;
00024 typedef graph_traits<Graph>::vertex_descriptor Vertex;
00025
00026 BoostedGraph(Window* parent, int w, int h, int drawShape=0, strconst txt="") : OglGui::Graph(parent, w, h, drawShape, txt) {
00027 layoutDone = false;
00028 }
00029
00030 ~BoostedGraph() {
00031 ILOG_DEBUG("Destructing BoostedGraph");
00032 initialLayoutDone = false;
00033 layoutDone = false;
00034 }
00035
00036 void addNodes(map<string, vector<string> > labels) {
00037 map<string, vector<string> >::iterator iter;
00038 for(iter = labels.begin(); iter != labels.end(); iter++) {
00039 string label = iter->first;
00040 if(nodes.count(label) == 0) addNode(label);
00041 for(uint i = 0; i < iter->second.size(); i++) {
00042 string related = iter->second[i];
00043 if(nodes.count(related) == 0) addNode(related);
00044 ConnectNode(label, related);
00045 }
00046 }
00047
00048 if(labels.begin()->first.compare("obama") == 0) {
00049 ConnectNode("election", "president"); ConnectNode("barack", "barackobama");
00050 ConnectNode("vote", "election"); ConnectNode("president", "politics");
00051 ConnectNode("vote", "president"); ConnectNode("president", "obama");
00052 ConnectNode("change", "hope"); ConnectNode("campaign", "election");
00053 }
00054 }
00055
00056 virtual void DisplayFunc() {
00057
00058 if(!layoutDone) layoutDone = doLayout();
00059 OglGui::Graph::DisplayFunc();
00060 }
00061
00062 virtual void OnLayoutChange()
00063 {
00064 layoutDone = false;
00065 OglGui::Graph::OnLayoutChange();
00066 }
00067
00068 virtual void WindowMouseEvent(OglGui::Window *src, int msg, int but, int state, int x, int y, void *userData )
00069 {
00070 if (but==oglLeftButton && msg == oglMouseMove) dragging = true;
00071
00072 if (dragging && but==oglLeftButton && msg == oglMouseUp) {
00073 OglGui::Graph* g = (OglGui::Graph*) userData;
00074
00075
00076 graph_traits<Graph>::vertex_iterator vi, vi_end;
00077 for (tie(vi, vi_end) = vertices(graph); vi != vi_end; ++vi) {
00078 string name = get(vertex_name, graph, *vi);
00079 if(name.compare(g->GetText()) != 0) continue;
00080 int x, y, w, h;
00081 g->GetDimensions(x, y, w, h);
00082 ILOG_DEBUG(g->GetText() + " moved");
00083 position[*vi].x = x-center.x;
00084 position[*vi].y = y-center.y;
00085 layoutDone = false;
00086 break;
00087 }
00088 dragging = false;
00089 }
00090 }
00091
00092 private:
00093 void addNode(string label) {
00094 int width, height;
00095 this->GetDimensions(width, height);
00096 int x = ABSRND(width-20);
00097 int y = ABSRND(height-20);
00098
00099 nodes[label].first = add_vertex(label, graph);
00100 nodes[label].second = new OglGui::Graph(this,x,y,75,20,1,label);
00101 nodes[label].second->ShapeBg(ARGB2COLOR(208,255,24,0));
00102 nodes[label].second->SetBorderType(0);
00103 nodes[label].second->ActOnModifier(0);
00104 nodes[label].second->SetAllowSizeDirections(AllDir, false);
00105 nodes[label].second->SetWindowListener(this, nodes[label].second);
00106
00107 this->AddNode(nodes[label].second);
00108 }
00109
00110 void ConnectNode(string from, string to) {
00111 add_edge(nodes[from].first, nodes[to].first, graph);
00112 OglGui::Graph::ConnectNode(nodes[from].second, nodes[to].second);
00113 }
00114
00115 void doInitialLayout() {
00116 position_vec = PositionVec(num_vertices(graph));
00117 position = PositionMap(position_vec.begin(), get(vertex_index, graph));
00118 circle_graph_layout(graph, position, 10);
00119 fruchterman_reingold_force_directed_layout(graph, position, 2*center.x-10, 2*center.y-10,
00120 force_pairs(all_force_pairs()));
00121 initialLayoutDone = true;
00122 }
00123
00124 bool doLayout() {
00125 center.x = (W()-75)/2; center.y = (H()-20)/2;
00126 if(!initialLayoutDone) doInitialLayout();
00127 fruchterman_reingold_force_directed_layout(graph, position, 2*center.x-10, 2*center.y-10,
00128 force_pairs(all_force_pairs()).
00129 cooling(linear_cooling<double>(50)));
00130
00131 graph_traits<Graph>::vertex_iterator vi, vi_end;
00132 for (tie(vi, vi_end) = vertices(graph); vi != vi_end; ++vi) {
00133 string name = get(vertex_name, graph, *vi);
00134
00135 int x, y, w, h;
00136 nodes[name].second->GetDimensions(x, y, w, h);
00137 nodes[name].second->SetDimensions(center.x+position[*vi].x, center.y+position[*vi].y, w, h);
00138 nodes[name].second->ShapeBg(ARGB2COLOR(208,255,24,0));
00139 }
00140 return true;
00141 }
00142
00143 typedef vector<simple_point<double> > PositionVec;
00144 typedef iterator_property_map<PositionVec::iterator, property_map<Graph, vertex_index_t>::type> PositionMap;
00145
00146 PositionVec position_vec;
00147 PositionMap position;
00148
00149 simple_point<double> center;
00150
00151 map<string, pair<Vertex, OglGui::Graph*> > nodes;
00152 Graph graph;
00153
00154 bool initialLayoutDone;
00155 bool layoutDone;
00156 bool dragging;
00157
00158 ILOG_VAR_DEC;
00159 };
00160
00161 ILOG_VAR_INIT(BoostedGraph, Impala.Application.TagsLife);