00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "render.h"
00019
00020 #define EPSILON .0001
00021
00022
00023 #define ARROW_LENGTH 10.
00024
00025
00026 #define ARR_TYPE_NONE (ARR_NONE)
00027 #define ARR_TYPE_NORM 1
00028 #define ARR_TYPE_CROW 2
00029 #define ARR_TYPE_TEE 3
00030 #define ARR_TYPE_BOX 4
00031 #define ARR_TYPE_DIAMOND 5
00032 #define ARR_TYPE_DOT 6
00033
00034
00035 #define ARR_MOD_OPEN (1<<8)
00036 #define ARR_MOD_INV (1<<9)
00037 #define ARR_MOD_LEFT (1<<10)
00038 #define ARR_MOD_RIGHT (1<<11)
00039
00040 typedef struct arrowdir_t {
00041 char *dir;
00042 int sflag;
00043 int eflag;
00044 } arrowdir_t;
00045
00046 static arrowdir_t Arrowdirs[] = {
00047 {"forward", ARR_TYPE_NONE, ARR_TYPE_NORM},
00048 {"back", ARR_TYPE_NORM, ARR_TYPE_NONE},
00049 {"both", ARR_TYPE_NORM, ARR_TYPE_NORM},
00050 {"none", ARR_TYPE_NONE, ARR_TYPE_NONE},
00051 {(char *) 0, ARR_TYPE_NONE, ARR_TYPE_NONE}
00052 };
00053
00054 typedef struct arrowname_t {
00055 char *name;
00056 int type;
00057 } arrowname_t;
00058
00059 static arrowname_t Arrowsynonyms[] = {
00060
00061
00062 {"invempty", (ARR_TYPE_NORM | ARR_MOD_INV | ARR_MOD_OPEN)},
00063 {(char *) 0, (ARR_TYPE_NONE)}
00064 };
00065
00066 static arrowname_t Arrowmods[] = {
00067 {"o", ARR_MOD_OPEN},
00068 {"r", ARR_MOD_RIGHT},
00069 {"l", ARR_MOD_LEFT},
00070
00071 {"e", ARR_MOD_OPEN},
00072 {"half", ARR_MOD_LEFT},
00073 {(char *) 0, ARR_TYPE_NONE}
00074 };
00075
00076 static arrowname_t Arrownames[] = {
00077 {"normal", ARR_TYPE_NORM},
00078 {"crow", ARR_TYPE_CROW},
00079 {"tee", ARR_TYPE_TEE},
00080 {"box", ARR_TYPE_BOX},
00081 {"diamond", ARR_TYPE_DIAMOND},
00082 {"dot", ARR_TYPE_DOT},
00083 {"none", ARR_TYPE_NONE},
00084
00085
00086 {"inv", (ARR_TYPE_NORM | ARR_MOD_INV)},
00087 {"vee", (ARR_TYPE_CROW | ARR_MOD_INV)},
00088
00089
00090
00091 {"pen", (ARR_TYPE_CROW | ARR_MOD_INV)},
00092
00093
00094
00095 {"mpty", ARR_TYPE_NORM},
00096 {(char *) 0, ARR_TYPE_NONE}
00097 };
00098
00099 typedef struct arrowtype_t {
00100 int type;
00101 double lenfact;
00102 void (*gen) (GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00103 } arrowtype_t;
00104
00105
00106 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00107 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00108 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00109 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00110 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00111 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00112
00113 static arrowtype_t Arrowtypes[] = {
00114 {ARR_TYPE_NORM, 1.0, arrow_type_normal},
00115 {ARR_TYPE_CROW, 1.0, arrow_type_crow},
00116 {ARR_TYPE_TEE, 0.5, arrow_type_tee},
00117 {ARR_TYPE_BOX, 1.0, arrow_type_box},
00118 {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond},
00119 {ARR_TYPE_DOT, 0.8, arrow_type_dot},
00120 {ARR_TYPE_NONE, 0.0, NULL}
00121 };
00122
00123 static char *arrow_match_name_frag(char *name, arrowname_t * arrownames,
00124 int *flag)
00125 {
00126 arrowname_t *arrowname;
00127 int namelen = 0;
00128 char *rest = name;
00129
00130 for (arrowname = arrownames; arrowname->name; arrowname++) {
00131 namelen = strlen(arrowname->name);
00132 if (strncmp(name, arrowname->name, namelen) == 0) {
00133 *flag |= arrowname->type;
00134 rest += namelen;
00135 break;
00136 }
00137 }
00138 return rest;
00139 }
00140
00141 static char *arrow_match_shape(char *name, int *flag)
00142 {
00143 char *next, *rest;
00144 int f = ARR_TYPE_NONE;
00145
00146 rest = arrow_match_name_frag(name, Arrowsynonyms, &f);
00147 if (rest == name) {
00148 do {
00149 next = rest;
00150 rest = arrow_match_name_frag(next, Arrowmods, &f);
00151 } while (next != rest);
00152 rest = arrow_match_name_frag(rest, Arrownames, &f);
00153 }
00154 if (f && !(f & ((1 << 8) - 1)))
00155 f |= ARR_TYPE_NORM;
00156 *flag |= f;
00157 return rest;
00158 }
00159
00160 static void arrow_match_name(char *name, int *flag)
00161 {
00162 char *rest;
00163 int f1 = ARR_TYPE_NONE, f2 = ARR_TYPE_NONE;
00164
00165 rest = arrow_match_shape(name, &f1);
00166 rest = arrow_match_shape(rest, &f2);
00167 *flag = f1 | (f2 << 16);
00168 }
00169
00170 void arrow_flags(Agedge_t * e, int *sflag, int *eflag)
00171 {
00172 char *attr;
00173 arrowdir_t *arrowdir;
00174
00175 *sflag = ARR_TYPE_NONE;
00176 *eflag =
00177 AG_IS_DIRECTED(e->tail->graph) ? ARR_TYPE_NORM : ARR_TYPE_NONE;
00178 if (E_dir && ((attr = agxget(e, E_dir->index)))[0]) {
00179 for (arrowdir = Arrowdirs; arrowdir->dir; arrowdir++) {
00180 if (streq(attr, arrowdir->dir)) {
00181 *sflag = arrowdir->sflag;
00182 *eflag = arrowdir->eflag;
00183 break;
00184 }
00185 }
00186 }
00187 if (E_arrowhead && ((attr = agxget(e, E_arrowhead->index)))[0])
00188 arrow_match_name(attr, eflag);
00189 if (E_arrowtail && ((attr = agxget(e, E_arrowtail->index)))[0])
00190 arrow_match_name(attr, sflag);
00191 if (ED_conc_opp_flag(e)) {
00192 edge_t *f;
00193 int s0, e0;
00194
00195 f = agfindedge(e->tail->graph, e->head, e->tail);
00196 arrow_flags(f, &s0, &e0);
00197 *eflag = *eflag | s0;
00198 *sflag = *sflag | e0;
00199 }
00200 }
00201
00202 double arrow_length(edge_t * e, int flag)
00203 {
00204 arrowtype_t *arrowtype;
00205 double lenfact = 0.0;
00206 int f;
00207
00208
00209 f = flag & ((1 << 8) - 1);
00210 for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) {
00211 if (f == arrowtype->type) {
00212 lenfact += arrowtype->lenfact;
00213 break;
00214 }
00215 }
00216 f = (flag >> 16) & ((1 << 8) - 1);
00217 for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) {
00218 if (f == arrowtype->type) {
00219 lenfact += arrowtype->lenfact;
00220 break;
00221 }
00222 }
00223
00224
00225 return ARROW_LENGTH * lenfact * late_double(e, E_arrowsz, 1.0, 0.0);
00226 }
00227
00228
00229 static boolean inside(inside_t * inside_context, pointf p)
00230 {
00231 return DIST2(p, inside_context->a.p[0]) <= inside_context->a.r[0];
00232 }
00233
00234 int arrowEndClip(edge_t* e, point * ps, int startp,
00235 int endp, bezier * spl, int eflag)
00236 {
00237 inside_t inside_context;
00238 pointf sp[4];
00239 double elen, elen2;
00240
00241 elen = arrow_length(e, eflag);
00242 elen2 = elen * elen;
00243 spl->eflag = eflag, spl->ep = ps[endp + 3];
00244 if (endp > startp && DIST2(ps[endp], ps[endp + 3]) < elen2) {
00245 endp -= 3;
00246 }
00247 P2PF(ps[endp], sp[3]);
00248 P2PF(ps[endp + 1], sp[2]);
00249 P2PF(ps[endp + 2], sp[1]);
00250 P2PF(spl->ep, sp[0]);
00251
00252 inside_context.a.p = &sp[0];
00253 inside_context.a.r = &elen2;
00254 bezier_clip(&inside_context, inside, sp, TRUE);
00255
00256 PF2P(sp[3], ps[endp]);
00257 PF2P(sp[2], ps[endp + 1]);
00258 PF2P(sp[1], ps[endp + 2]);
00259 PF2P(sp[0], ps[endp + 3]);
00260 return endp;
00261 }
00262
00263 int arrowStartClip(edge_t* e, point * ps, int startp,
00264 int endp, bezier * spl, int sflag)
00265 {
00266 inside_t inside_context;
00267 pointf sp[4];
00268 double slen, slen2;
00269
00270 slen = arrow_length(e, sflag);
00271 slen2 = slen * slen;
00272 spl->sflag = sflag, spl->sp = ps[startp];
00273 if (endp > startp && DIST2(ps[startp], ps[startp + 3]) < slen2) {
00274 startp += 3;
00275 }
00276 P2PF(ps[startp + 3], sp[0]);
00277 P2PF(ps[startp + 2], sp[1]);
00278 P2PF(ps[startp + 1], sp[2]);
00279 P2PF(spl->sp, sp[3]);
00280
00281 inside_context.a.p = &sp[3];
00282 inside_context.a.r = &slen2;
00283 bezier_clip(&inside_context, inside, sp, FALSE);
00284
00285 PF2P(sp[3], ps[startp]);
00286 PF2P(sp[2], ps[startp + 1]);
00287 PF2P(sp[1], ps[startp + 2]);
00288 PF2P(sp[0], ps[startp + 3]);
00289 return startp;
00290 }
00291
00292 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00293 {
00294 pointf q, v, a[5];
00295 double arrowwidth;
00296
00297 arrowwidth = 0.35;
00298 if (penwidth > 4)
00299 arrowwidth *= penwidth / 4;
00300
00301 v.x = -u.y * arrowwidth;
00302 v.y = u.x * arrowwidth;
00303 q.x = p.x + u.x;
00304 q.y = p.y + u.y;
00305 if (flag & ARR_MOD_INV) {
00306 a[0] = a[4] = p;
00307 a[1].x = p.x - v.x;
00308 a[1].y = p.y - v.y;
00309 a[2] = q;
00310 a[3].x = p.x + v.x;
00311 a[3].y = p.y + v.y;
00312 } else {
00313 a[0] = a[4] = q;
00314 a[1].x = q.x - v.x;
00315 a[1].y = q.y - v.y;
00316 a[2] = p;
00317 a[3].x = q.x + v.x;
00318 a[3].y = q.y + v.y;
00319 }
00320 if (flag & ARR_MOD_LEFT)
00321 gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
00322 else if (flag & ARR_MOD_RIGHT)
00323 gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
00324 else
00325 gvrender_polygon(job, &a[1], 3, !(flag & ARR_MOD_OPEN));
00326 }
00327
00328 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00329 {
00330 pointf m, q, v, w, a[9];
00331 double arrowwidth, shaftwidth;
00332
00333 arrowwidth = 0.45;
00334 if (penwidth > (4 * arrowsize) && (flag & ARR_MOD_INV))
00335 arrowwidth *= penwidth / (4 * arrowsize);
00336
00337 shaftwidth = 0;
00338 if (penwidth > 1 && (flag & ARR_MOD_INV))
00339 shaftwidth = 0.05 * (penwidth - 1) / arrowsize;
00340
00341 v.x = -u.y * arrowwidth;
00342 v.y = u.x * arrowwidth;
00343 w.x = -u.y * shaftwidth;
00344 w.y = u.x * shaftwidth;
00345 q.x = p.x + u.x;
00346 q.y = p.y + u.y;
00347 m.x = p.x + u.x * 0.5;
00348 m.y = p.y + u.y * 0.5;
00349 if (flag & ARR_MOD_INV) {
00350 a[0] = a[8] = p;
00351 a[1].x = q.x - v.x;
00352 a[1].y = q.y - v.y;
00353 a[2].x = m.x - w.x;
00354 a[2].y = m.y - w.y;
00355 a[3].x = q.x - w.x;
00356 a[3].y = q.y - w.y;
00357 a[4] = q;
00358 a[5].x = q.x + w.x;
00359 a[5].y = q.y + w.y;
00360 a[6].x = m.x + w.x;
00361 a[6].y = m.y + w.y;
00362 a[7].x = q.x + v.x;
00363 a[7].y = q.y + v.y;
00364 } else {
00365 a[0] = a[8] = q;
00366 a[1].x = p.x - v.x;
00367 a[1].y = p.y - v.y;
00368 a[2].x = m.x - w.x;
00369 a[2].y = m.y - w.y;
00370 a[3].x = p.x;
00371 a[3].y = p.y;
00372 a[4] = p;
00373 a[5].x = p.x;
00374 a[5].y = p.y;
00375 a[6].x = m.x + w.x;
00376 a[6].y = m.y + w.y;
00377 a[7].x = p.x + v.x;
00378 a[7].y = p.y + v.y;
00379 }
00380 if (flag & ARR_MOD_LEFT)
00381 gvrender_polygon(job, a, 6, 1);
00382 else if (flag & ARR_MOD_RIGHT)
00383 gvrender_polygon(job, &a[3], 6, 1);
00384 else
00385 gvrender_polygon(job, a, 9, 1);
00386 }
00387
00388 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00389 {
00390 pointf m, n, q, v, a[4];
00391
00392 v.x = -u.y;
00393 v.y = u.x;
00394 q.x = p.x + u.x;
00395 q.y = p.y + u.y;
00396 m.x = p.x + u.x * 0.2;
00397 m.y = p.y + u.y * 0.2;
00398 n.x = p.x + u.x * 0.6;
00399 n.y = p.y + u.y * 0.6;
00400 a[0].x = m.x + v.x;
00401 a[0].y = m.y + v.y;
00402 a[1].x = m.x - v.x;
00403 a[1].y = m.y - v.y;
00404 a[2].x = n.x - v.x;
00405 a[2].y = n.y - v.y;
00406 a[3].x = n.x + v.x;
00407 a[3].y = n.y + v.y;
00408 if (flag & ARR_MOD_LEFT) {
00409 a[0] = m;
00410 a[3] = n;
00411 } else if (flag & ARR_MOD_RIGHT) {
00412 a[1] = m;
00413 a[2] = n;
00414 }
00415 gvrender_polygon(job, a, 4, 1);
00416 a[0] = p;
00417 a[1] = q;
00418 gvrender_polyline(job, a, 2);
00419 }
00420
00421 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00422 {
00423 pointf m, q, v, a[4];
00424
00425 v.x = -u.y * 0.4;
00426 v.y = u.x * 0.4;
00427 m.x = p.x + u.x * 0.8;
00428 m.y = p.y + u.y * 0.8;
00429 q.x = p.x + u.x;
00430 q.y = p.y + u.y;
00431 a[0].x = p.x + v.x;
00432 a[0].y = p.y + v.y;
00433 a[1].x = p.x - v.x;
00434 a[1].y = p.y - v.y;
00435 a[2].x = m.x - v.x;
00436 a[2].y = m.y - v.y;
00437 a[3].x = m.x + v.x;
00438 a[3].y = m.y + v.y;
00439 if (flag & ARR_MOD_LEFT) {
00440 a[0] = p;
00441 a[3] = m;
00442 } else if (flag & ARR_MOD_RIGHT) {
00443 a[1] = p;
00444 a[2] = m;
00445 }
00446 gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
00447 a[0] = m;
00448 a[1] = q;
00449 gvrender_polyline(job, a, 2);
00450 }
00451
00452 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00453 {
00454 pointf q, r, v, a[5];
00455
00456 v.x = -u.y / 3.;
00457 v.y = u.x / 3.;
00458 r.x = p.x + u.x / 2.;
00459 r.y = p.y + u.y / 2.;
00460 q.x = p.x + u.x;
00461 q.y = p.y + u.y;
00462 a[0] = a[4] = q;
00463 a[1].x = r.x + v.x;
00464 a[1].y = r.y + v.y;
00465 a[2] = p;
00466 a[3].x = r.x - v.x;
00467 a[3].y = r.y - v.y;
00468 if (flag & ARR_MOD_LEFT)
00469 gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
00470 else if (flag & ARR_MOD_RIGHT)
00471 gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
00472 else
00473 gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
00474 }
00475
00476 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00477 {
00478 double r;
00479 pointf AF[2];
00480
00481 r = sqrt(u.x * u.x + u.y * u.y) / 2.;
00482 AF[0].x = p.x + u.x / 2. - r;
00483 AF[0].y = p.y + u.y / 2. - r;
00484 AF[1].x = p.x + u.x / 2. + r;
00485 AF[1].y = p.y + u.y / 2. + r;
00486 gvrender_ellipse(job, AF, 2, !(flag & ARR_MOD_OPEN));
00487 }
00488
00489 static pointf arrow_gen_type(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00490 {
00491 int f;
00492 arrowtype_t *arrowtype;
00493
00494 f = flag & ((1 << 8) - 1);
00495 for (arrowtype = Arrowtypes; arrowtype->type; arrowtype++) {
00496 if (f == arrowtype->type) {
00497 u.x *= arrowtype->lenfact * arrowsize;
00498 u.y *= arrowtype->lenfact * arrowsize;
00499 (arrowtype->gen) (job, p, u, arrowsize, penwidth, flag);
00500 p.x = p.x + u.x;
00501 p.y = p.y + u.y;
00502 break;
00503 }
00504 }
00505 return p;
00506 }
00507
00508 boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag)
00509 {
00510 double s;
00511 boxf bb;
00512 double ax,ay,bx,by,cx,cy,dx,dy;
00513 double ux2, uy2;
00514
00515
00516 u.x -= p.x;
00517 u.y -= p.y;
00518
00519 s = ARROW_LENGTH * arrowsize / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
00520 u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
00521 u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
00522 u.x *= s;
00523 u.y *= s;
00524
00525
00526 ux2 = u.x / 2.;
00527 uy2 = u.y / 2.;
00528 ax = p.x - uy2;
00529 ay = p.y - ux2;
00530 bx = p.x + uy2;
00531 by = p.y + ux2;
00532 cx = ax + u.x;
00533 cy = ay + u.y;
00534 dx = bx + u.x;
00535 dy = by + u.y;
00536
00537
00538 bb.UR.x = MAX(ax, MAX(bx, MAX(cx, dx)));
00539 bb.UR.y = MAX(ay, MAX(by, MAX(cy, dy)));
00540 bb.LL.x = MIN(ax, MIN(bx, MIN(cx, dx)));
00541 bb.LL.y = MIN(ay, MIN(by, MIN(cy, dy)));
00542
00543 return bb;
00544 }
00545
00546 void arrow_newgen(GVJ_t * job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00547 {
00548 obj_state_t *obj = job->obj;
00549 double s;
00550 int f;
00551 emit_state_t old_emit_state;
00552
00553 old_emit_state = obj->emit_state;
00554 obj->emit_state = emit_state;
00555
00556
00557
00558 gvrender_begin_context(job);
00559 gvrender_set_style(job, job->gvc->defaultlinestyle);
00560
00561
00562 u.x -= p.x;
00563 u.y -= p.y;
00564
00565 s = ARROW_LENGTH / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
00566 u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
00567 u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
00568 u.x *= s;
00569 u.y *= s;
00570
00571
00572 f = flag & ((1 << 16) - 1);
00573 p = arrow_gen_type(job, p, u, arrowsize, penwidth, f);
00574
00575
00576
00577 f = (flag >> 16) & ((1 << 16) - 1);
00578 arrow_gen_type(job, p, u, arrowsize, penwidth, f);
00579
00580 gvrender_end_context(job);
00581
00582 obj->emit_state = old_emit_state;
00583 }
00584
00585
00586 void arrow_gen(GVJ_t * job, emit_state_t emit_state, point p, point u, double arrowsize, double penwidth, int flag)
00587 {
00588 pointf P, U;
00589
00590 P2PF(p, P);
00591 P2PF(u, U);
00592 arrow_newgen(job, emit_state, P, U, arrowsize, penwidth, flag);
00593 }