00001
00049 #include <LEDA/graphwin.h>
00050 #include <LEDA/color.h>
00051 #include <LEDA/impl/x_window.h>
00052 #include "DAG.h"
00053 #include "ShockGraph.h"
00054 #include "VisualDAG.h"
00055 #include "UnixFuncPrototypes.h"
00056
00057 #include <stdio.h>
00058
00059
00060 #define GW_LEFT_MARGIN 50
00061 #define GW_RIGHT_MARGIN 50
00062 #define GW_TOP_MARGIN 50
00063 #define GW_BOTTOM_MARGIN 50
00064 #define NODE_WIDTH 54
00065 #define NODE_HEIGHT 25
00066 #define NODE_FONT_SIZE 11
00067
00068 #define HGAP (NODE_WIDTH / 4)
00069 #define VGAP (NODE_HEIGHT * 2)
00070
00071
00072 #define SW_LEFT_MARGIN 50
00073 #define SW_RIGHT_MARGIN 50
00074 #define SW_TOP_MARGIN 50
00075 #define SW_BOTTOM_MARGIN 50
00076
00077
00078
00079
00080 #define SW_CENTER_MARGIN 20
00081 #define SW_WIN_WIDTH 800
00082
00083
00084 #define Y_OFFSET 10
00085
00086 unsigned char* ReadPPMFile(const char* szPPMFileName, int* pnRows, int* pnCols);
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 void RecomputeTSV(leda_GraphWin& gw, leda_node v)
00098 {
00099 DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00100
00101 dag.ComputeTSVs(dag.GetFirstRootNode());
00102 dag.PrintTSVs();
00103 }
00104
00105 void OnRecomputeTSV(leda_GraphWin& gw, const leda_point& pt)
00106 {
00107 double x = pt.xcoord(), y = pt.ycoord();
00108 leda_list<leda_node> nodes = gw.get_nodes_in_area(x, y, x, y);
00109
00110 RecomputeTSV(gw, nodes.pop());
00111 }
00112
00113 void OnDisplayNodeEigenSum(leda_GraphWin& gw, const leda_point& pt)
00114 {
00115 const DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00116 double x = pt.xcoord(), y = pt.ycoord();
00117 leda_node v = gw.get_nodes_in_area(x, y, x, y).pop();
00118
00119 if (v != nil)
00120 {
00121 double n = dag.GetNode(v)->GetEigenLbl();
00122 char sz[50];
00123 sprintf(sz, "Eigenvalue Sum = %.4f.", n);
00124 gw.message(sz);
00125 }
00126 }
00127
00128 void OnDisplayNodeInfo(leda_GraphWin& gw, const leda_point& pt)
00129 {
00130 const DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00131 double x = pt.xcoord(), y = pt.ycoord();
00132 leda_node v = gw.get_nodes_in_area(x, y, x, y).pop();
00133
00134 if (v != nil)
00135 {
00136 double n = dag.GetNode(v)->GetEigenLbl();
00137 char sz[500];
00138
00139 const ShockGraph* pSG = dynamic_cast<const ShockGraph*>(&dag);
00140
00141 if (pSG) {
00142 sprintf(sz, "%s %d: DFS index: %d, EigenSum: %.4f, Shock Pts: %d",
00143 (const char*)pSG->GetObjName(),
00144 pSG->GetViewNumber(),
00145 pSG->GetNodeDFSIndex(v),
00146 n,
00147 pSG->NodeLength(v));
00148
00149 cout << endl; pSG->GetSGNode(v)->Print();
00150 cout << endl; pSG->GetSGNode(v)->m_shocks.Print();
00151 }
00152 else
00153 sprintf(sz, "Label:%s\nEigenSum: %.4f.", (const char*)dag.GetDAGLbl(), n);
00154
00155 gw.message(sz);
00156 }
00157 }
00158
00159 void OnShowAdjMatrix(leda_GraphWin& gw, const leda_point& pt)
00160 {
00161 DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00162
00163 dag.PrintAdjMatrix();
00164 }
00165
00166 void OnNewNode(leda_GraphWin& gw, leda_node v)
00167 {
00168 DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00169
00170 dag[v] = dag.CreateNodeObject((const char*)gw.get_label(v));
00171 RecomputeTSV(gw, v);
00172 }
00173
00174 void OnNewEdge(leda_GraphWin& gw, leda_edge e)
00175 {
00176 DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
00177
00178 dag[e] = 1.0;
00179 RecomputeTSV(gw, dag.source(e));
00180 }
00181
00182 void OnDelNode(leda_GraphWin& gw)
00183 {
00184 RecomputeTSV(gw, nil);
00185 }
00186
00187 void OnDelEdge(leda_GraphWin& gw)
00188 {
00189 RecomputeTSV(gw, nil);
00190 }
00191
00192 int CompNumOfLeaves(DAG& g, leda_node v, NodeIndexMap& map)
00193 {
00194 if (!map.defined(v))
00195 {
00196 leda_node u;
00197 int n = 0;
00198
00199 if (g.outdeg(v) == 0)
00200 n = 1;
00201 else
00202 forall_adj_nodes(u, v)
00203 n += CompNumOfLeaves(g, u, map);
00204
00205 return map[v] = n;
00206 }
00207
00208 return map[v];
00209 }
00210
00216 double SetNodePos(leda_GraphWin& gw, DAG& g, leda_node v, POINT top_left, NodeIndexMap& map)
00217 {
00218 leda_node u;
00219 int num_lea = map[v];
00220
00221 double w = num_lea * NODE_WIDTH + (num_lea - 1) * HGAP;
00222
00223 leda_point pos(top_left.x + w / 2, top_left.y);
00224
00225 gw.set_position(v, pos);
00226
00227 top_left.y -= NODE_HEIGHT + VGAP;
00228
00229 forall_adj_nodes(u, v)
00230 {
00231 if (indeg(u) <= 1 || g.GetNodeLevel(u) == g.GetNodeLevel(v) + 1)
00232 top_left.x += SetNodePos(gw, g, u, top_left, map) + HGAP;
00233 }
00234
00235 return w;
00236 }
00237
00238 void ShowTree(DAG& g)
00239 {
00240 leda_node v, r = g.GetFirstRootNode();
00241
00242
00243 int nMaxHeight = 0;
00244
00245 forall_nodes(v, g)
00246 if (g.GetNodeLevel(v) > nMaxHeight)
00247 nMaxHeight = g.GetNodeLevel(v);
00248
00249 NodeIndexMap map;
00250 int nLeaves = CompNumOfLeaves(g, r, map);
00251
00252
00253 int nWinWidth = NODE_WIDTH * nLeaves + HGAP * (nLeaves - 1)
00254 + GW_LEFT_MARGIN + GW_RIGHT_MARGIN;
00255
00256 int nWinHeight = NODE_HEIGHT * (nMaxHeight + 1) + VGAP * nMaxHeight
00257 + GW_TOP_MARGIN + GW_BOTTOM_MARGIN;
00258
00259
00260 leda_GraphWin gw(g, nWinWidth, nWinHeight);
00261 gw.win_init(0, nWinWidth, 0);
00262
00263
00264 POINT top_left;
00265
00266 top_left.x = GW_LEFT_MARGIN;
00267 top_left.y = gw.get_ymax() - GW_TOP_MARGIN - NODE_HEIGHT / 2;
00268
00269 SetNodePos(gw, g, r, top_left, map);
00270
00271
00272 forall_nodes(v, g)
00273 {
00274 const DAGNodePtr node = g.GetNode(v);
00275
00276 gw.set_label(v, (const char*)node->GetLblForGraph());
00277 gw.set_color(v, node->GetColorForGraph());
00278 gw.set_shape(v, (leda_gw_node_shape)node->GetShapeForGraph());
00279 }
00280
00281 gw.set_node_shape(leda_ellipse_node, false);
00282 gw.set_node_width(NODE_WIDTH, true);
00283 gw.set_node_height(NODE_HEIGHT, true);
00284
00285
00286 gw.set_node_label_font(leda_roman_font, NODE_FONT_SIZE);
00287 gw.set_show_status(false);
00288
00289 gw.add_node_menu("Recompute TSV", OnRecomputeTSV);
00290 gw.add_node_menu("Display EigenSum", OnDisplayNodeEigenSum);
00291 gw.add_node_menu("Display node info", OnDisplayNodeInfo);
00292 gw.add_node_menu("Show adj matrix", OnShowAdjMatrix);
00293 gw.set_new_node_handler(OnNewNode);
00294 gw.set_new_edge_handler(OnNewEdge);
00295 gw.set_del_node_handler(OnDelNode);
00296 gw.set_del_edge_handler(OnDelEdge);
00297
00298
00299 gw.display();
00300 gw.message((const char*)g.GetDAGLbl());
00301
00302 gw.edit();
00303 }
00304
00305 void ShowGraph(DAG& g)
00306 {
00307 ShowTree(g);
00308 }
00309
00311
00312
00313 SGMatchWnd::SGMatchWnd()
00314 {
00315 m_pWnd = NULL;
00316 m_bShowLabels = true;
00317 m_bShowNodeType = false;
00318 m_nShowColorLines = 0;
00319 m_bShowCoords = true;
00320
00321 m_pSGInfo1 = m_pSGInfo2 = NULL;
00322 }
00323
00324 SGMatchWnd::~SGMatchWnd()
00325 {
00326 if (m_pWnd) delete m_pWnd;
00327
00328 delete m_pSGInfo1;
00329 delete m_pSGInfo2;
00330 }
00331
00332 bool SGMatchWnd::Create(const ShockGraph* pSG1, const ShockGraph* pSG2, bool bAsyncMode)
00333 {
00334 ASSERT(pSG1 && pSG2);
00335
00336
00337 double xmin = 0;
00338 double xmax = SW_LEFT_MARGIN + SW_CENTER_MARGIN + SW_RIGHT_MARGIN;
00339 double ymin = 0;
00340 double ymax = SW_BOTTOM_MARGIN + SW_TOP_MARGIN;
00341
00342 xmax += pSG1->Width() + pSG2->Width();
00343 ymax += (pSG1->Height() > pSG2->Height()) ? pSG1->Height():pSG2->Height();
00344
00345
00346 double width = xmax;
00347 double height = (ymax - ymin) * width / (xmax - xmin);
00348
00349 double delta_x, delta_y, reflex_y;
00350
00351
00352 delta_x = pSG1->xmin - SW_LEFT_MARGIN;
00353 delta_y = pSG1->ymin - SW_BOTTOM_MARGIN;
00354 reflex_y = pSG1->ymax + pSG1->ymin;
00355
00356 m_pSGInfo1 = new SGInfo(pSG1, delta_x, delta_y, reflex_y);
00357
00358 delta_x = pSG2->xmin - (SW_LEFT_MARGIN + pSG1->Width() + SW_CENTER_MARGIN);
00359 delta_y = pSG2->ymin - SW_BOTTOM_MARGIN;
00360 reflex_y = pSG2->ymax + pSG2->ymin;
00361
00362 m_pSGInfo2 = new SGInfo(pSG2, delta_x, delta_y, reflex_y);
00363
00364
00365
00366 if (bAsyncMode && fork() != 0)
00367 return true;
00368
00369
00370 m_pWnd = new Wnd((int)width, (int)height, "r:redraw, l:labels, t:types, a,b:graphs, q:quit", this);
00371 m_pWnd->init(xmin, xmax, ymin);
00372
00373
00374 m_pWnd->display(0, 0);
00375 m_pWnd->redraw();
00376
00377 int val;
00378 double x, y;
00379 int event;
00380
00381 while (true)
00382 {
00383 event = m_pWnd->read_event(val, x, y);
00384
00385 if (event == leda_key_release_event)
00386 {
00387 if (val == 'r' || val == 'R')
00388 m_pWnd->reset_clipping();
00389 else if (val == 'l' || val == 'L')
00390 m_bShowLabels = !m_bShowLabels;
00391 else if (val == 't' || val == 'T')
00392 m_bShowNodeType = !m_bShowNodeType;
00393 else if (val == 'a' || val == 'b')
00394 {
00395 ShockGraph sg;
00396 sg = (val == 'a') ? *GetSGInfo1()->pSG:*GetSGInfo2()->pSG;
00397 ShowGraph(sg);
00398 }
00399 else if (val == 'c' || val == 'C')
00400 m_bShowCoords = !m_bShowCoords;
00401
00402 else if (isdigit(val))
00403 m_nShowColorLines = val - '0';
00404 else
00405 break;
00406
00407 m_pWnd->redraw();
00408 }
00409 else if (event == leda_exposure_event)
00410 m_pWnd->reset_clipping();
00411 else if (event == leda_destroy_event)
00412 break;
00413 }
00414
00415 if (bAsyncMode)
00416 exit(0);
00417
00418 return true;
00419 }
00420
00421 leda_point ReMapPt(const sg::Point& a, const SGMatchWnd::SGInfo* si)
00422 {
00423 return leda_point(a.x - si->delta_x, si->reflex_y - a.y - si->delta_y);
00424 }
00425
00426 leda_point ReMapPt(const leda_point& a, const SGMatchWnd::SGInfo* si)
00427 {
00428 return leda_point(a.xcoord() - si->delta_x, si->reflex_y - a.ycoord() - si->delta_y);
00429 }
00430
00431 void SGMatchWnd::Wnd::OnShowCoord(leda_window* pBaseWnd, double x, double y)
00432 {
00433 Wnd* pWnd = dynamic_cast<Wnd*>(pBaseWnd);
00434 SGMatchWnd* pSGWnd = pWnd->m_pParent;
00435
00436 double centerPt = SW_LEFT_MARGIN + pSGWnd->GetSGInfo1()->pSG->Width() + SW_CENTER_MARGIN / 2.0;
00437
00438 leda_point pt = ReMapPt(leda_point(-x, y), (x <= centerPt) ? pSGWnd->GetSGInfo1():pSGWnd->GetSGInfo2());
00439
00440 x = pWnd->xmin();
00441 y = pWnd->ymax();
00442 pWnd->draw_box(x, y - 30, x + 100, y, leda_white);
00443
00444 if (pSGWnd->m_bShowCoords)
00445 {
00446 char szTxt[100];
00447 sprintf(szTxt, "%.1f %.1f", -pt.xcoord(), pt.ycoord());
00448 pWnd->draw_text(x + 10, y - 10, szTxt);
00449 }
00450 }
00451
00452 void SGMatchWnd::Wnd::OnDraw(leda_window* pBaseWnd)
00453 {
00454 Wnd* pWnd = dynamic_cast<Wnd*>(pBaseWnd);
00455 ASSERT(pWnd);
00456
00457 SGMatchWnd* pSGWnd = pWnd->m_pParent;
00458
00459
00460
00461
00462
00463 pSGWnd->DrawSG();
00464 pSGWnd->DrawMatchingLines();
00465
00466
00467
00468
00469
00470
00471
00472 }
00473
00474 bool SGMatchWnd::DrawSkeleton(const SGInfo* si) const
00475 {
00476 if (!si->pSG->GetSkeleton())
00477 return false;
00478
00479 sg::DDSkeleton* sk = ((McGillSkeleton*)si->pSG->GetSkeleton())->GetSkeleton();
00480
00481
00482 Curve *c = sk->getShape()->getCurves()->front();
00483 const double step = 0.5;
00484 double t=0;
00485 sg::Point p1, p2;
00486 leda_list<leda_point> pts;
00487
00488 for(t = 0; t < c->getLength() - 2 * step; t += step)
00489 pts.push(ReMapPt(c->atT(t), si));
00490
00491 m_pWnd->draw_polygon(pts);
00492
00493
00494 m_pWnd->draw_segment(ReMapPt(c->atT(t), si), ReMapPt(c->atT(0), si));
00495
00496 return true;
00497 }
00498
00499 void SGMatchWnd::DrawSG() const
00500 {
00501 const SGNode* pNode;
00502 leda_node v;
00503 int i, j, size;
00504 const SGInfo* info[] = {GetSGInfo1(), GetSGInfo2()};
00505 double x1, y1, m;
00506 char cEndPt;
00507 leda_color c;
00508 int t, rows, cols, colorIdx;
00509
00510
00511 leda_color color[] = {leda_black, leda_red, leda_brown, leda_blue, leda_violet, leda_grey3};
00512
00513 m_pWnd->start_buffering();
00514
00515 m_pWnd->clear(leda_white);
00516
00517 for (i = 0; i < 2; i++)
00518 {
00519 unsigned char* pImg = ReadPPMFile(info[i]->pSG->GetDAGLbl(), &rows, &cols);
00520
00521 if (pImg)
00522 {
00523 int r,c,k;
00524
00525 for (r = 0, k = 0; r < rows; r++)
00526 for (c = 0; c < cols; c++, k++)
00527 if (pImg[k] != 1)
00528 m_pWnd->draw_pixel(ReMapPt(leda_point(c, r), info[i]), leda_grey1);
00529
00530
00531 delete[] pImg;
00532 }
00533
00534 DrawSkeleton(info[i]);
00535
00536 colorIdx = 0;
00537
00538 forall_nodes(v, *(info[i]->pSG))
00539 {
00540 pNode = info[i]->pSG->GetSGNode(v);
00541 cEndPt = pNode->GetEndPt();
00542
00543 t = pNode->m_nType;
00544
00545 if (t == SHOCK_1 || t == SHOCK_2 || t == SHOCK_3 || t == SHOCK_4)
00546 {
00547 size = pNode->m_shocks.GetSize();
00548
00549 if (size == 0)
00550 {
00551
00552 continue;
00553 }
00554
00555 const ShockInfo& s0 = pNode->m_shocks[0];
00556 const ShockInfo& sN = pNode->m_shocks[size - 1];
00557
00558 if (s0.xcoord != sN.xcoord)
00559 m = (s0.ycoord - sN.ycoord) / (s0.xcoord - sN.xcoord);
00560 else
00561 m = 1;
00562
00563 for (j = 0; j < size; j++)
00564 {
00565 const ShockInfo& s1 = pNode->m_shocks[j];
00566
00567 x1 = s1.xcoord - info[i]->delta_x;
00568 y1 = (info[i]->reflex_y - s1.ycoord) - info[i]->delta_y;
00569 c = color[colorIdx % (sizeof(color) / sizeof(color[0]))];
00570
00571 m_pWnd->draw_pixel(x1, y1, c);
00572
00573 if (m_bShowLabels)
00574 {
00575 if ((cEndPt == 'a' && j == 0) ||
00576 (cEndPt == 'b' && j == 0) ||
00577 (cEndPt != 'a' && cEndPt != 'b' && j == size / 2))
00578 {
00579
00580
00581
00582
00583
00584 if (m_bShowNodeType)
00585 m_pWnd->draw_text(x1, y1, (const char*)info[i]->pSG->GetNodeLbl(v),
00586 c);
00587 else
00588 m_pWnd->draw_text(x1, y1, (const char*)((const DAG*)(const ShockGraph*)info[i]->pSG)->GetNodeLbl(v),
00589 c);
00590 }
00591 }
00592 }
00593
00594 colorIdx++;
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 }
00612 else if (t != ROOT)
00613 cerr << "\nERROR: Unknown node type." << endl;
00614 }
00615 }
00616
00617 m_pWnd->flush_buffer();
00618 m_pWnd->stop_buffering();
00619 }
00620
00621 void SGMatchWnd::DrawMatchingLines() const
00622 {
00623 DAGNodePtr ptr;
00624 const SGNode* pNode1, *pNode2;
00625 leda_color color[] = {leda_yellow, leda_pink, leda_grey1, leda_grey2, leda_grey3,
00626 leda_black, leda_violet, leda_red, leda_blue, leda_green};
00627 const int NUMCOLORS = sizeof(color) / sizeof(color[0]);
00628 int color_index = 0, c;
00629 double arc_x,arc_y;
00630
00631 unsigned int i = 0;
00632
00633 if (m_matchMap.empty())
00634 return;
00635
00636 forall_defined(ptr, m_matchMap)
00637 {
00638 pNode1 = dynamic_cast<const SGNode*>((const DAGNode*) ptr);
00639 pNode2 = dynamic_cast<const SGNode*>((const DAGNode*) m_matchMap[ptr]);
00640
00641 if (pNode1->GetShockCount() > 0 && pNode2->GetShockCount() > 0)
00642 {
00643 const ShockInfo& s1 = pNode1->m_shocks[pNode1->GetShockCount()/2];
00644 const ShockInfo& s2 = pNode2->m_shocks[pNode2->GetShockCount()/2];
00645
00646
00647
00648 leda_point start(s1.xcoord - GetSGInfo1()->delta_x,
00649 (GetSGInfo1()->reflex_y - s1.ycoord) - GetSGInfo1()->delta_y);
00650 leda_point end(s2.xcoord - GetSGInfo2()->delta_x,
00651 (GetSGInfo2()->reflex_y - s2.ycoord) - GetSGInfo2()->delta_y);
00652 arc_x = (start.xcoord() + end.xcoord())/2;
00653 arc_y = (start.ycoord() + end.ycoord())/2 + abs(start.xcoord() - end.xcoord()) * (Y_OFFSET / 100.0);
00654 if (arc_y >= (start.ycoord() + end.ycoord())/2 + Y_OFFSET)
00655 {
00656 arc_y = (start.ycoord() + end.ycoord())/2 + Y_OFFSET;
00657 }
00658
00659 leda_point mid(arc_x, arc_y);
00660
00661
00662 c = int(pNode2->GetSimilarity() * NUMCOLORS - 1);
00663 if (c < 0) c = 0;
00664
00665 if (m_nShowColorLines == 0 || m_nShowColorLines - 1 == c)
00666 m_pWnd->draw_arc(start, mid, end, color[c]);
00667
00668
00669
00670
00671
00672
00673
00674
00675 }
00676 }
00677 }
00678
00679 void SGMatchWnd::SetMatchMap(const DAGNodeMap& matchMap)
00680 {
00681 m_matchMap = matchMap;
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703 }
00704
00710 unsigned char* ReadPPMFile(const char* szPPMFileName, int* pnRows, int* pnCols)
00711 {
00712 FILE* fp;
00713
00714 if ((fp = fopen(szPPMFileName, "r")) == NULL)
00715 return NULL;
00716
00717 pixel** img;
00718 pixval maxval;
00719 int i, j, k;
00720 char r, g, b;
00721
00722 img = ppm_readppm(fp, pnCols, pnRows, &maxval);
00723 fclose(fp);
00724
00725 unsigned char* arr = new unsigned char[(*pnRows)*(*pnCols)];
00726
00727 for(i = 0, k = 0; i < *pnRows; i++)
00728 for(j = 0; j < *pnCols; j++, k++)
00729 {
00730 r = (0xff * PPM_GETR(img[i][j])) / maxval;
00731 g = (0xff * PPM_GETG(img[i][j])) / maxval;
00732 b = (0xff * PPM_GETB(img[i][j])) / maxval;
00733
00734 arr[k] = (r==0 && b==0 && g==0) ? 0:1;
00735 }
00736
00737 ppm_freearray(img, *pnRows);
00738
00739 return arr;
00740 }
00741