00001 #include "OglGui/Graph.h"
00002
00003 #include <string>
00004 #include <map>
00005 #include <vector>
00006
00007 #include "Tag.h"
00008
00009 using namespace OglGui;
00010 using namespace std;
00011
00012 class LabeledGraph : public Graph {
00013 public:
00014 LabeledGraph(Window* parent, int w, int h, int drawShape=0, strconst txt="") : Graph(parent, w, h, drawShape, txt) {}
00015
00016 void addNodes(map<string, vector<string> > labels) {
00017 map<string, vector<string> >::iterator iter;
00018 for(iter = labels.begin(); iter != labels.end(); iter++) {
00019 string label = iter->first;
00020 if(nodes.count(label) == 0) addNode(label);
00021 for(uint i = 0; i < iter->second.size(); i++) {
00022 string related = iter->second[i];
00023 if(nodes.count(related) == 0) addNode(related);
00024 this->ConnectNode(nodes[label], nodes[related]);
00025 }
00026 }
00027 }
00028
00029 virtual void DisplayFunc()
00030 {
00031 if(!layoutDone) layoutDone = doLayout();
00032 Graph::DisplayFunc();
00033 }
00034
00035 virtual void OnLayoutChange()
00036 {
00037 layoutDone = false;
00038 Graph::OnLayoutChange();
00039 }
00040
00041 private:
00042 void addNode(string label) {
00043 int width, height;
00044 this->GetDimensions(width, height);
00045 int x = ABSRND(width-20);
00046 int y = ABSRND(height-20);
00047
00048 nodes[label] = new Graph(this,x,y,75,20,1);
00049 nodes[label]->ShapeBg(ARGB2COLOR(196,255,0,0));
00050 nodes[label]->SetBorderType(0);
00051 nodes[label]->SetText(label);
00052 nodes[label]->ActOnModifier(0);
00053 nodes[label]->SetAllowSizeDirections(AllDir, false);
00054
00055 this->AddNode(nodes[label]);
00056 }
00057
00058 bool doLayout() {
00059 return doForceDirectedLayout();
00060 return doRadialLayout();
00061 }
00062
00063 bool doRadialLayout() {
00064 int x, y, w, h;
00065 mNodes[0].nodeVector[0]->GetDimensions(x, y, w, h);
00066 uint cx = (W()-w)/2, cy = (H()-h)/2;
00067 mNodes[0].nodeVector[0]->SetDimensions(cx, cy, w, h);
00068 uint count = mNodes[0].nodeVector.size()-1;
00069 float count_2_pi = count/(M_PI*2);
00070 float rx = 1.0-0.5*w/W(), ry = 1.0-0.5*h/H();
00071 for(float i=1; i <= count; i++) {
00072 mNodes[0].nodeVector[i]->GetDimensions(x, y, w, h);
00073 x = cx * (1 + rx*sin(i/count_2_pi));
00074 y = cy * (1 + ry*cos(i/count_2_pi));
00075 mNodes[0].nodeVector[i]->SetDimensions(x, y, w, h);
00076 }
00077 return true;
00078 }
00079
00080 bool doForceDirectedLayout() {
00081 int x, y, w, h;
00082 mNodes[0].nodeVector[0]->GetDimensions(x, y, w, h);
00083 uint cx = (W()-w)/2, cy = (H()-h)/2;
00084 mNodes[0].nodeVector[0]->SetDimensions(cx, cy, w, h);
00085
00086 float energy = 0;
00087 float alpha = 0.01;
00088 for(uint i = 0; i < mNodes.size(); i++) {
00089 mNodes[i].nodeVector[0]->GetDimensions(x, y, w, h);
00090
00091 int nX, nY, nW, nH;
00092
00093 for(uint j = 0; j < mNodes.size(); j++) {
00094 if(i==j) continue;
00095 mNodes[j].nodeVector[0]->GetDimensions(nX, nY, nW, nH);
00096 int distX = nX-x, distY = nY-y;
00097
00098
00099
00100
00101 int pX = nX, pY = nY;
00102 if((abs(distX) < (nW)) && (abs(distY) < (nH))) {
00103 nX += (distX > 0) ? nW: -nW;
00104 nY += (distY > 0) ? nH : -nH;
00105 }
00106 nX = cap(nX, 0, W()-nW);
00107 nY = cap(nY, 0, H()-nH);
00108 float delta = sqrt(pow(nX-pX, 2.0) + pow(nY-pY, 2.0));
00109 if(delta > 0) {
00110 energy += delta;
00111 mNodes[j].nodeVector[0]->SetDimensions(nX, nY, nW, nH);
00112 }
00113 }
00114 for(uint j = 1; j < mNodes[i].nodeVector.size(); j++){
00115 mNodes[i].nodeVector[j]->GetDimensions(nX, nY, nW, nH);
00116
00117 mNodes[i].nodeVector[0]->SetDimensions(nX*alpha+x*(1-alpha), nY*alpha+y*(1-alpha), w, h);
00118 mNodes[i].nodeVector[j]->SetDimensions(x*alpha+nX*(1-alpha), y*alpha+nY*(1-alpha), nW, nH);
00119 }
00120 }
00121 return(energy == 0);
00122 }
00123
00124 float cap(float v, float min, float max) {
00125 if(v < min) return min;
00126 if(v > max) return max;
00127 return v;
00128 }
00129
00130 map<string, Graph* > nodes;
00131
00132 bool layoutDone;
00133
00134 ILOG_VAR_DEC;
00135 };
00136
00137 ILOG_VAR_INIT(LabeledGraph, Impala.Application.TagsLife);