topviewfuncs.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <assert.h>
  11. #include "topviewfuncs.h"
  12. #include <cgraph/gv_ctype.h>
  13. #include <cgraph/cgraph.h>
  14. #include "smyrna_utils.h"
  15. #include <common/colorprocs.h>
  16. #include "draw.h"
  17. #include "frmobjectui.h"
  18. #include <xdot/xdot.h>
  19. #include <glcomp/glutils.h>
  20. #include "selectionfuncs.h"
  21. #include <common/types.h>
  22. #include <common/utils.h>
  23. #include <limits.h>
  24. #include <float.h>
  25. #include <math.h>
  26. #include <stdbool.h>
  27. #include <stdlib.h>
  28. #include <util/alloc.h>
  29. static xdot *parseXdotwithattrs(void *e)
  30. {
  31. xdot* xDot=NULL;
  32. xDot=parseXDotFOn (agget(e,"_draw_" ), OpFns,sizeof(sdot_op), xDot);
  33. if (agobjkind(e) == AGRAPH)
  34. xDot=parseXDotFOn (agget(e,"_background" ), OpFns,sizeof(sdot_op), xDot);
  35. xDot=parseXDotFOn (agget(e,"_ldraw_" ), OpFns,sizeof(sdot_op), xDot);
  36. xDot=parseXDotFOn (agget(e,"_hdraw_" ), OpFns,sizeof(sdot_op), xDot);
  37. xDot=parseXDotFOn (agget(e,"_tdraw_" ), OpFns,sizeof(sdot_op), xDot);
  38. xDot=parseXDotFOn (agget(e,"_hldraw_" ), OpFns,sizeof(sdot_op), xDot);
  39. xDot=parseXDotFOn (agget(e,"_tldraw_" ), OpFns,sizeof(sdot_op), xDot);
  40. if(xDot)
  41. {
  42. for (size_t cnt = 0; cnt < xDot->cnt; cnt++)
  43. {
  44. ((sdot_op*)(xDot->ops))[cnt].obj=e;
  45. }
  46. }
  47. return xDot;
  48. }
  49. static void set_boundaries(Agraph_t * g)
  50. {
  51. Agnode_t *v;
  52. Agsym_t* pos_attr = GN_pos(g);
  53. glCompPoint pos;
  54. float left = FLT_MAX, right = -FLT_MAX, top = -FLT_MAX, bottom = FLT_MAX;
  55. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  56. {
  57. pos=getPointFromStr(agxget(v, pos_attr));
  58. left = fminf(left, pos.x);
  59. right = fmaxf(right, pos.x);
  60. top = fmaxf(top, pos.y);
  61. bottom = fminf(bottom, pos.y);
  62. }
  63. view->bdxLeft = left;
  64. view->bdyTop = top;
  65. view->bdxRight = right;
  66. view->bdyBottom = bottom;
  67. }
  68. static void draw_xdot(xdot* x, double base_z)
  69. {
  70. sdot_op *op;
  71. if (!x)
  72. return;
  73. view->Topview->global_z=base_z;
  74. op=(sdot_op*)x->ops;
  75. for (size_t i = 0; i < x->cnt; i++, op++)
  76. {
  77. if(op->op.drawfunc)
  78. op->op.drawfunc(&op->op,0);
  79. }
  80. }
  81. static glCompPoint getEdgeHead(Agedge_t * edge)
  82. {
  83. return getPointFromStr(agget(aghead(edge),"pos"));
  84. }
  85. static glCompPoint getEdgeTail(Agedge_t * edge)
  86. {
  87. return getPointFromStr(agget(agtail(edge),"pos"));
  88. }
  89. static float getEdgeLength(Agedge_t *edge) {
  90. glCompPoint A,B;
  91. A=getEdgeTail(edge);
  92. B=getEdgeHead(edge);
  93. float rv = (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z);
  94. rv=sqrtf(rv);
  95. return rv;
  96. }
  97. static void glCompColorxlate(glCompColor *c, const char *str) {
  98. gvcolor_t cl;
  99. colorxlate(str, &cl, RGBA_DOUBLE);
  100. c->R=cl.u.RGBA[0];
  101. c->G=cl.u.RGBA[1];
  102. c->B=cl.u.RGBA[2];
  103. c->A=cl.u.RGBA[3];
  104. }
  105. /* If the "visible" attribute is not set or "", return true
  106. * else evaluate as boolean
  107. */
  108. static int visible(Agsym_t* attr, void* obj)
  109. {
  110. char* s;
  111. if (attr) {
  112. s = agxget (obj, attr);
  113. if (*s) return mapbool(s);
  114. else return 1;
  115. }
  116. else return 1;
  117. }
  118. static int object_color(void* obj,glCompColor* c)
  119. {
  120. gvcolor_t cl;
  121. Agraph_t* g=view->g[view->activeGraph];
  122. Agraph_t* objg=agraphof(obj);
  123. int return_value = 1;
  124. int objType;
  125. float Alpha = 1;
  126. Agsym_t* vis;
  127. objType=AGTYPE(obj);
  128. if(objType==AGEDGE) {
  129. Alpha=getAttrFloat(g,objg,"defaultedgealpha",1);
  130. vis = GE_visible (objg);
  131. }
  132. else {
  133. assert(objType == AGNODE);
  134. Alpha=getAttrFloat(g,objg,"defaultnodealpha",1);
  135. vis = GN_visible (objg);
  136. }
  137. if (!visible(vis,obj))
  138. return 0;
  139. char *previous_color_scheme = setColorScheme(agget (obj, "colorscheme"));
  140. /*get objects's color attribute */
  141. const char *const bf = getAttrStr(g,obj,"color",NULL);
  142. if(bf && (*bf)) {
  143. colorxlate(bf, &cl, RGBA_DOUBLE);
  144. c->R = cl.u.RGBA[0];
  145. c->G = cl.u.RGBA[1];
  146. c->B = cl.u.RGBA[2];
  147. c->A = cl.u.RGBA[3]*Alpha;
  148. }
  149. else
  150. {
  151. if(objType==AGEDGE)
  152. getcolorfromschema(view->colschms, getEdgeLength(obj), view->Topview->maxedgelen,c);
  153. else
  154. {
  155. colorxlate(agget(g, "defaultnodecolor"),&cl, RGBA_DOUBLE);
  156. c->R = cl.u.RGBA[0];
  157. c->G = cl.u.RGBA[1];
  158. c->B = cl.u.RGBA[2];
  159. c->A = cl.u.RGBA[3];
  160. }
  161. c->A *= Alpha;
  162. }
  163. char *color_scheme = setColorScheme(previous_color_scheme);
  164. free(color_scheme);
  165. free(previous_color_scheme);
  166. return return_value;
  167. }
  168. /*
  169. draws multi edges , single edges
  170. this function assumes glBegin(GL_LINES) has been called
  171. */
  172. static void draw_edge(glCompPoint *posT, glCompPoint *posH, float length,
  173. int deg) {
  174. double alpha, R, ITERANGLE;
  175. double X1, Y1, X2, Y2;
  176. if (deg) {
  177. R = length / 20.0;
  178. if ((deg / 2) * 2 != deg) /*odd */
  179. ITERANGLE = (deg) * 15.00 * -1;
  180. else
  181. ITERANGLE = (deg) * 15.00;
  182. ITERANGLE = DEG2RAD * ITERANGLE;
  183. alpha = atan((posH->y - posT->y) / (posH->x - posT->x));
  184. if (posT->x > posH->x)
  185. ITERANGLE = 180 * DEG2RAD - ITERANGLE;
  186. X1 = R * cos(alpha - ITERANGLE) + posT->x;
  187. Y1 = R * sin(alpha - ITERANGLE) + posT->y;
  188. X2 = R * cos(alpha - (180 * DEG2RAD - ITERANGLE)) + posH->x;
  189. Y2 = R * sin(alpha - (180 * DEG2RAD - ITERANGLE)) + posH->y;
  190. glVertex3f(posT->x, posT->y, posT->z);
  191. glVertex3f(X1, Y1, posT->z);
  192. glVertex3f(X1, Y1, posT->z);
  193. glVertex3f(X2, Y2, posH->z);
  194. glVertex3f(X2, Y2, posH->z);
  195. glVertex3f(posH->x, posH->y, posH->z);
  196. } else {
  197. glVertex3f(posT->x, posT->y, posT->z);
  198. glVertex3f(posH->x, posH->y, posH->z);
  199. }
  200. }
  201. static char* labelOf (Agraph_t* g, Agnode_t* v)
  202. {
  203. char* lbl;
  204. char* s;
  205. Agsym_t* data_attr = GN_labelattribute(g);
  206. if (data_attr)
  207. s = agxget (v, data_attr);
  208. else
  209. s = agxget (g, GG_labelattribute(g));
  210. if ((*s == '\0') || !strcmp (s, "name"))
  211. lbl = agnameof (v);
  212. else {
  213. lbl = agget (v, s);
  214. if (!lbl) lbl = "";
  215. }
  216. return lbl;
  217. }
  218. static void renderSelectedNodes(Agraph_t * g)
  219. {
  220. Agnode_t *v;
  221. xdot * x;
  222. glCompPoint pos;
  223. Agsym_t* l_color_attr = GG_nodelabelcolor(g);
  224. glCompColor c;
  225. int defaultNodeShape;
  226. float nodeSize;
  227. glCompColorxlate(&c,agxget(g,l_color_attr));
  228. defaultNodeShape=getAttrBool(g,g,"defaultnodeshape",0);
  229. if(defaultNodeShape==0)
  230. glBegin(GL_POINTS);
  231. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  232. {
  233. if(!ND_selected(v))
  234. continue;
  235. x=parseXdotwithattrs(v);
  236. draw_xdot(x,-1);
  237. if(x)
  238. freeXDot (x);
  239. }
  240. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  241. {
  242. if(!ND_selected(v))
  243. continue;
  244. glColor4f(view->selectedNodeColor.R, view->selectedNodeColor.G,view->selectedNodeColor.B, view->selectedNodeColor.A);
  245. pos = ND_A(v);
  246. nodeSize = ND_size(v);
  247. if (defaultNodeShape == 0)
  248. glVertex3f(pos.x, pos.y, pos.z + 0.001f);
  249. else if (defaultNodeShape == 1)
  250. drawCircle(pos.x, pos.y, nodeSize, pos.z + 0.001f);
  251. }
  252. if(defaultNodeShape==0)
  253. glEnd();
  254. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  255. {
  256. if(!ND_selected(v))
  257. continue;
  258. if (ND_printLabel(v)==1)
  259. {
  260. pos = ND_A(v);
  261. glColor4f(c.R, c.G,c.B, c.A);
  262. glprintfglut(view->glutfont, pos.x, pos.y, pos.z + 0.002f, labelOf(g, v));
  263. }
  264. }
  265. }
  266. static void renderNodes(Agraph_t * g)
  267. {
  268. Agnode_t *v;
  269. glCompPoint pos;
  270. Agsym_t* pos_attr = GN_pos(g);
  271. Agsym_t* size_attr = GN_size(g);
  272. Agsym_t* selected_attr = GN_selected(g);
  273. int defaultNodeShape;
  274. float nodeSize;
  275. glCompColor c;
  276. xdot * x;
  277. int ind;
  278. defaultNodeShape=getAttrInt(g,g,"defaultnodeshape",0);
  279. x=parseXdotwithattrs(g);
  280. if (x) {
  281. draw_xdot(x, -0.2);
  282. freeXDot (x);
  283. }
  284. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  285. {
  286. if(!object_color(v,&c))
  287. continue;
  288. x=parseXdotwithattrs(v);
  289. draw_xdot(x, -0.1);
  290. if(x)
  291. freeXDot (x);
  292. }
  293. if(defaultNodeShape==0)
  294. glBegin(GL_POINTS);
  295. ind=0;
  296. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  297. {
  298. ND_TVref(v) = ind;
  299. if(!object_color(v,&c))
  300. {
  301. ND_visible(v) = 0;
  302. continue;
  303. }
  304. else
  305. ND_visible(v) = 1;
  306. if(l_int(v, selected_attr,0))
  307. {
  308. ND_selected(v) = 1;
  309. }
  310. glColor4f(c.R,c.G,c.B,c.A);
  311. pos=getPointFromStr(agxget(v, pos_attr));
  312. nodeSize = l_float(v, size_attr, 0);
  313. ND_A(v) = pos;
  314. if (nodeSize > 0)
  315. nodeSize=nodeSize*view->nodeScale;
  316. else
  317. nodeSize=view->nodeScale;
  318. if(defaultNodeShape==0)
  319. nodeSize=1;
  320. ND_size(v) = nodeSize;
  321. if (defaultNodeShape == 0)
  322. glVertex3f(pos.x,pos.y,pos.z);
  323. else if (defaultNodeShape == 1)
  324. drawCircle(pos.x,pos.y,nodeSize,pos.z);
  325. ind++;
  326. }
  327. if(defaultNodeShape==0)
  328. glEnd();
  329. }
  330. static void renderSelectedEdges(Agraph_t * g)
  331. {
  332. Agedge_t *e;
  333. Agnode_t *v;
  334. xdot * x;
  335. glCompPoint posT; /*Tail position*/
  336. glCompPoint posH; /*Head position*/
  337. glCompColor c;
  338. /*xdots tend to be drawn as background shapes,that is why they are being rendered before edges*/
  339. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  340. {
  341. for (e = agfstout(g, v); e; e = agnxtout(g, e))
  342. {
  343. if(!ED_selected(e))
  344. continue;
  345. if(!object_color(e,&c))
  346. continue;
  347. x=parseXdotwithattrs(e);
  348. draw_xdot(x,0);
  349. if(x)
  350. freeXDot (x);
  351. }
  352. }
  353. glBegin(GL_LINES);
  354. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  355. {
  356. for (e = agfstout(g, v); e; e = agnxtout(g, e))
  357. {
  358. if(!ED_selected(e))
  359. continue;
  360. if(!object_color(e,&c))
  361. continue;
  362. glColor4f(1,0,0,1);
  363. posT = ED_posTail(e);
  364. posH = ED_posHead(e);
  365. posT.z +=0.01f;
  366. posH.z +=0.01f;
  367. draw_edge(&posT,&posH,getEdgeLength(e),0);
  368. }
  369. }
  370. glEnd();
  371. }
  372. /* skipWS:
  373. * Skip whitespace
  374. */
  375. static char* skipWS (char* p)
  376. {
  377. while (gv_isspace(*p)) p++;
  378. return p;
  379. }
  380. /* skipNWS:
  381. * Skip non-whitespace
  382. */
  383. static char* skipNWS (char* p)
  384. {
  385. while (*p && !gv_isspace(*p)) p++;
  386. return p;
  387. }
  388. /* readPoint:
  389. * Parse x,y[,z] and store in pt.
  390. * If z is not specified, set to 0.
  391. * Return pointer to next character after reading the point.
  392. * Return NULL on error.
  393. */
  394. static char* readPoint (char* p, xdot_point* pt)
  395. {
  396. char* endp;
  397. pt->z = 0;
  398. pt->x = strtod (p, &endp);
  399. if (p == endp) {
  400. return 0;
  401. }
  402. else
  403. p = endp;
  404. if (*p == ',') p++;
  405. else return 0;
  406. pt->y = strtod (p, &endp);
  407. if (p == endp) {
  408. return 0;
  409. }
  410. else
  411. p = endp;
  412. if ((*p == ' ') || (*p == '\0')) return p;
  413. else if (*p == ',') p++;
  414. else return 0;
  415. pt->z = strtod (p, &endp);
  416. if (p == endp) {
  417. return 0;
  418. }
  419. else
  420. return endp;
  421. }
  422. /* countPoints:
  423. * count number of points in pos attribute; store in cntp;
  424. * check for e and s points; store if found and increment number of
  425. * points by 3 for each.
  426. * return start of point list (skip over e and s points).
  427. * return NULL on failure
  428. */
  429. static char *countPoints(char *pos, int *have_sp, xdot_point *sp, int *have_ep,
  430. xdot_point *ep, size_t *cntp) {
  431. size_t cnt = 0;
  432. char* p;
  433. pos = skipWS (pos);
  434. if (*pos == 's') {
  435. if ((pos = readPoint (pos+2, sp))) {
  436. *have_sp = 1;
  437. cnt += 3;
  438. }
  439. else
  440. return 0;
  441. }
  442. else
  443. *have_sp = 0;
  444. pos = skipWS (pos);
  445. if (*pos == 'e') {
  446. if ((pos = readPoint (pos+2, ep))) {
  447. *have_ep = 1;
  448. cnt += 3;
  449. }
  450. else
  451. return 0;
  452. }
  453. else
  454. *have_ep = 0;
  455. p = pos = skipWS (pos);
  456. while (*p) {
  457. cnt++;
  458. p = skipNWS (p);
  459. p = skipWS (p);
  460. }
  461. *cntp = cnt;
  462. return pos;
  463. }
  464. /* storePoints:
  465. * read comma-separated list of points
  466. * and store them in ps
  467. * Assumes enough storage is available.
  468. * return -1 on error
  469. */
  470. static int storePoints (char* pos, xdot_point* ps)
  471. {
  472. while (*pos) {
  473. if ((pos = readPoint (pos, ps))) {
  474. ps++;
  475. pos = skipWS(pos);
  476. }
  477. else
  478. return -1;
  479. }
  480. return 0;
  481. }
  482. /* makeXDotSpline:
  483. * Generate an xdot representation of an edge's pos attribute
  484. */
  485. static xdot* makeXDotSpline (char* pos)
  486. {
  487. xdot_point s, e;
  488. int v, have_s, have_e;
  489. size_t cnt;
  490. static const size_t sz = sizeof(sdot_op);
  491. if (*pos == '\0') return NULL;
  492. pos = countPoints (pos, &have_s, &s, &have_e, &e, &cnt);
  493. if (pos == 0) return NULL;
  494. xdot_point* pts = gv_calloc(cnt, sizeof(xdot_point));
  495. if (have_s) {
  496. v = storePoints (pos, pts+3);
  497. pts[0] = pts[1] = s;
  498. pts[2] = pts[3];
  499. }
  500. else
  501. v = storePoints (pos, pts);
  502. if (v) {
  503. free (pts);
  504. return NULL;
  505. }
  506. if (have_e) {
  507. pts[cnt-1] = pts[cnt-2] = e;
  508. pts[cnt-3] = pts[cnt-4];
  509. }
  510. xdot_op* op = gv_calloc(sz, sizeof(char));
  511. op->kind = xd_unfilled_bezier;
  512. op->drawfunc = OpFns[xop_bezier];
  513. op->u.bezier.cnt = cnt;
  514. op->u.bezier.pts = pts;
  515. xdot* xd = gv_alloc(sizeof(xdot));
  516. xd->cnt = 1;
  517. xd->sz = sz;
  518. xd->ops = op;
  519. return xd;
  520. }
  521. typedef void (*edgefn) (Agraph_t *, Agedge_t*, glCompColor);
  522. static void renderEdgesFn (Agraph_t * g, edgefn ef, int skipSelected)
  523. {
  524. Agedge_t *e;
  525. Agnode_t *v;
  526. glCompColor c;
  527. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  528. {
  529. for (e = agfstout(g, v); e; e = agnxtout(g, e))
  530. {
  531. if ((ND_visible(agtail(e))==0) || (ND_visible(aghead(e))==0))
  532. continue;
  533. if(!object_color(e,&c)) {
  534. continue;
  535. }
  536. if (ED_selected(e) && skipSelected)
  537. continue;
  538. ef (g, e, c);
  539. }
  540. }
  541. }
  542. static void edge_xdot (Agraph_t* g, Agedge_t* e, glCompColor c)
  543. {
  544. (void)g;
  545. (void)c;
  546. xdot * x;
  547. x=parseXdotwithattrs(e);
  548. draw_xdot(x,0);
  549. if(x)
  550. freeXDot (x);
  551. }
  552. static void edge_seg (Agraph_t* g, Agedge_t* e, glCompColor c)
  553. {
  554. Agsym_t* pos_attr = GN_pos(g);
  555. glCompPoint posT; /*Tail position*/
  556. glCompPoint posH; /*Head position*/
  557. glColor4f(c.R,c.G,c.B,c.A);
  558. posT=getPointFromStr(agxget(agtail(e), pos_attr));
  559. posH=getPointFromStr(agxget(aghead(e), pos_attr));
  560. draw_edge(&posT,&posH,getEdgeLength(e),0);
  561. ED_posTail(e) = posT;
  562. ED_posHead(e) = posH;
  563. }
  564. static void edge_spline (Agraph_t* g, Agedge_t* e, glCompColor c)
  565. {
  566. Agsym_t* pos_attr_e = GE_pos(g);
  567. xdot * x;
  568. glColor4f(c.R,c.G,c.B,c.A);
  569. x = makeXDotSpline (agxget(e,pos_attr_e));
  570. if (x) {
  571. draw_xdot(x,0);
  572. freeXDot (x);
  573. }
  574. }
  575. static void renderEdges(Agraph_t * g)
  576. {
  577. Agsym_t* pos_attr_e = GE_pos(g);
  578. int drawSegs = !(pos_attr_e && view->drawSplines);
  579. /*xdots tend to be drawn as background shapes,that is why they are being rendered before edges*/
  580. renderEdgesFn (g, edge_xdot, 0);
  581. if (drawSegs) {
  582. glBegin(GL_LINES);
  583. renderEdgesFn (g, edge_seg, 1);
  584. glEnd();
  585. }
  586. else
  587. renderEdgesFn (g, edge_spline, 1);
  588. }
  589. static void renderNodeLabels(Agraph_t * g)
  590. {
  591. Agnode_t *v;
  592. glCompPoint pos;
  593. Agsym_t* data_attr = GN_labelattribute(g);
  594. Agsym_t* l_color_attr = GG_nodelabelcolor(g);
  595. glCompColor c;
  596. glCompColorxlate(&c,agxget(g,l_color_attr));
  597. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  598. {
  599. if(ND_visible(v)==0)
  600. continue;
  601. if(ND_selected(v)==1)
  602. continue;
  603. pos = ND_A(v);
  604. glColor4f(c.R,c.G,c.B,c.A);
  605. if(!data_attr)
  606. glprintfglut(view->glutfont,pos.x,pos.y,pos.z,agnameof(v));
  607. else
  608. glprintfglut(view->glutfont,pos.x,pos.y,pos.z,agxget(v,data_attr));
  609. }
  610. }
  611. static void renderEdgeLabels(Agraph_t * g)
  612. {
  613. Agedge_t *e;
  614. Agnode_t *v;
  615. glCompPoint posT;
  616. glCompPoint posH;
  617. Agsym_t* data_attr = GE_labelattribute(g);
  618. Agsym_t* l_color_attr = GG_edgelabelcolor(g);
  619. glCompColor c;
  620. glCompColorxlate(&c,agxget(g,l_color_attr));
  621. if(!data_attr || !l_color_attr)
  622. return;
  623. for (v = agfstnode(g); v; v = agnxtnode(g, v))
  624. {
  625. for (e = agfstout(g, v); e; e = agnxtout(g, e))
  626. {
  627. if (ND_visible(v)==0)
  628. continue;
  629. posT = ED_posTail(e);
  630. posH = ED_posHead(e);
  631. glColor4f(c.R,c.G,c.B,c.A);
  632. float x = posH.x + (posT.x - posH.x) / 2;
  633. float y = posH.y + (posT.y - posH.y) / 2;
  634. float z = posH.z + (posT.z - posH.z) / 2;
  635. glprintfglut(view->glutfont,x,y,z,agxget(e,data_attr));
  636. }
  637. }
  638. }
  639. static void cacheNodes(Agraph_t * g,topview* t)
  640. {
  641. if (t->cache.node_id != UINT_MAX) // clean existing cache
  642. glDeleteLists(t->cache.node_id,1);
  643. t->cache.node_id=glGenLists(1);
  644. glNewList(t->cache.node_id,GL_COMPILE);
  645. renderNodes(g);
  646. glEndList();
  647. }
  648. static void cacheEdges(Agraph_t * g,topview* t)
  649. {
  650. if (t->cache.edge_id != UINT_MAX) // clean existing cache
  651. glDeleteLists(t->cache.edge_id,1);
  652. t->cache.edge_id=glGenLists(1);
  653. glNewList(t->cache.edge_id,GL_COMPILE);
  654. renderEdges(g);
  655. glEndList();
  656. }
  657. void cacheSelectedEdges(Agraph_t * g,topview* t)
  658. {
  659. if (t->cache.seledge_id != UINT_MAX) // clean existing cache
  660. glDeleteLists(t->cache.seledge_id,1);
  661. t->cache.seledge_id=glGenLists(1);
  662. glNewList(t->cache.seledge_id,GL_COMPILE);
  663. renderSelectedEdges(g);
  664. glEndList();
  665. }
  666. void cacheSelectedNodes(Agraph_t * g,topview* t)
  667. {
  668. if (t->cache.selnode_id != UINT_MAX) // clean existing cache
  669. glDeleteLists(t->cache.selnode_id,1);
  670. t->cache.selnode_id=glGenLists(1);
  671. glNewList(t->cache.selnode_id,GL_COMPILE);
  672. renderSelectedNodes(g);
  673. glEndList();
  674. }
  675. static void cacheNodeLabels(Agraph_t * g,topview* t)
  676. {
  677. if (t->cache.nodelabel_id != UINT_MAX) // clean existing cache
  678. glDeleteLists(t->cache.nodelabel_id,1);
  679. t->cache.nodelabel_id=glGenLists(1);
  680. glNewList(t->cache.nodelabel_id,GL_COMPILE);
  681. renderNodeLabels(g);
  682. glEndList();
  683. }
  684. static void cacheEdgeLabels(Agraph_t * g,topview* t)
  685. {
  686. if (t->cache.edgelabel_id != UINT_MAX) // clean existing cache
  687. glDeleteLists(t->cache.edgelabel_id,1);
  688. t->cache.edgelabel_id=glGenLists(1);
  689. glNewList(t->cache.edgelabel_id,GL_COMPILE);
  690. renderEdgeLabels(g);
  691. glEndList();
  692. }
  693. void updateSmGraph(Agraph_t * g,topview* t)
  694. {
  695. Agnode_t *v;
  696. Agedge_t *e;
  697. float eLength=0;
  698. float totalELength=0;
  699. t->Nodecount=0;
  700. t->maxedgelen=0;
  701. t->minedgelen=-1;
  702. t->global_z=0;
  703. t->sel.selPoly = (glCompPoly_t){0};
  704. if(!t)
  705. return ;
  706. /*Node Loop*/
  707. for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
  708. for (e = agfstout(g, v); e; e = agnxtout(g, e))
  709. {
  710. eLength=getEdgeLength(e);
  711. if((t->minedgelen == -1) || (t->minedgelen > eLength))
  712. t->minedgelen=eLength;
  713. if(eLength > t->maxedgelen)
  714. t->maxedgelen=eLength;
  715. totalELength += eLength;
  716. }
  717. t->Nodecount++;
  718. }
  719. aginit(g, AGNODE, "nodeRec", sizeof(nodeRec), false);
  720. aginit(g, AGEDGE, "edgeRec", sizeof(edgeRec), false);
  721. set_boundaries(g);
  722. view->Topview=t;
  723. /*render nodes once to get set some attributes set,THIS IS A HACK, FIX IT*/
  724. renderNodes(g);
  725. cacheEdges(g,t);
  726. cacheSelectedEdges(g,t);
  727. cacheNodes(g,t);
  728. cacheSelectedNodes(g,t);
  729. cacheEdgeLabels(g,t);
  730. cacheNodeLabels(g,t);
  731. }
  732. void initSmGraph(Agraph_t * g,topview* rv)
  733. {
  734. /*create attribute list*/
  735. rv->attributes=load_attr_list(view->g[view->activeGraph]);
  736. // set topological fisheye to NULL
  737. rv->fisheyeParams.h = NULL;
  738. rv->fisheyeParams.active = 0;
  739. rv->cache.node_id = UINT_MAX;
  740. rv->cache.selnode_id = UINT_MAX;
  741. rv->cache.edge_id = UINT_MAX;
  742. rv->cache.seledge_id = UINT_MAX;
  743. rv->sel.selectEdges = false;
  744. rv->sel.selectNodes = true;
  745. updateSmGraph(g,rv);
  746. }
  747. void renderSmGraph(topview* t)
  748. {
  749. /*
  750. we like to have blending affect where node and edge overlap
  751. to achive this depth test should be turned off.
  752. */
  753. glEnable(GL_POINT_SMOOTH);
  754. glEnable(GL_DEPTH_TEST);
  755. glEnable(GL_DEPTH);
  756. if(view->drawedges)
  757. {
  758. glCallList(t->cache.edge_id);
  759. glCallList(t->cache.seledge_id);
  760. if(view->drawedgelabels)
  761. {
  762. if(view->zoom*-1 < t->fitin_zoom /(float)view->labelnumberofnodes*-1)
  763. glCallList(t->cache.edgelabel_id);
  764. }
  765. }
  766. if(view->drawnodes)
  767. {
  768. glPointSize(view->nodeScale*t->fitin_zoom/view->zoom);
  769. glCallList(t->cache.node_id);
  770. glCallList(t->cache.selnode_id);
  771. if(view->drawnodelabels)
  772. {
  773. if(view->zoom*-1 < t->fitin_zoom /(float)view->labelnumberofnodes*-1)
  774. glCallList(t->cache.nodelabel_id);
  775. }
  776. }
  777. }