|
Graphviz 2.29.20120208.0545
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include "render.h" 00016 00017 #define EPSILON .0001 00018 00019 /* standard arrow length in points */ 00020 #define ARROW_LENGTH 10. 00021 00022 #define NUMB_OF_ARROW_HEADS 4 00023 /* each arrow in 8 bits. Room for NUMB_OF_ARROW_HEADS arrows in 32 bit int. */ 00024 00025 #define BITS_PER_ARROW 8 00026 00027 #define BITS_PER_ARROW_TYPE 3 00028 /* arrow types (in BITS_PER_ARROW_TYPE bits) */ 00029 #define ARR_TYPE_NONE (ARR_NONE) 00030 #define ARR_TYPE_NORM 1 00031 #define ARR_TYPE_CROW 2 00032 #define ARR_TYPE_TEE 3 00033 #define ARR_TYPE_BOX 4 00034 #define ARR_TYPE_DIAMOND 5 00035 #define ARR_TYPE_DOT 6 00036 /* Spare: #define ARR_TYPE_xxx 7 */ 00037 00038 /* arrow mods (in (BITS_PER_ARROW - BITS_PER_ARROW_TYPE) bits) */ 00039 #define ARR_MOD_OPEN (1<<(BITS_PER_ARROW_TYPE+0)) 00040 #define ARR_MOD_INV (1<<(BITS_PER_ARROW_TYPE+1)) 00041 #define ARR_MOD_LEFT (1<<(BITS_PER_ARROW_TYPE+2)) 00042 #define ARR_MOD_RIGHT (1<<(BITS_PER_ARROW_TYPE+3)) 00043 /* Spare: #define ARR_MOD_xxx (1<<(BITS_PER_ARROW_TYPE+4)) */ 00044 00045 typedef struct arrowdir_t { 00046 char *dir; 00047 int sflag; 00048 int eflag; 00049 } arrowdir_t; 00050 00051 static arrowdir_t Arrowdirs[] = { 00052 {"forward", ARR_TYPE_NONE, ARR_TYPE_NORM}, 00053 {"back", ARR_TYPE_NORM, ARR_TYPE_NONE}, 00054 {"both", ARR_TYPE_NORM, ARR_TYPE_NORM}, 00055 {"none", ARR_TYPE_NONE, ARR_TYPE_NONE}, 00056 {(char *) 0, ARR_TYPE_NONE, ARR_TYPE_NONE} 00057 }; 00058 00059 typedef struct arrowname_t { 00060 char *name; 00061 int type; 00062 } arrowname_t; 00063 00064 static arrowname_t Arrowsynonyms[] = { 00065 /* synonyms for deprecated arrow names - included for backward compatibility */ 00066 /* evaluated before primary names else "invempty" would give different results */ 00067 {"invempty", (ARR_TYPE_NORM | ARR_MOD_INV | ARR_MOD_OPEN)}, /* oinv */ 00068 {(char *) 0, (ARR_TYPE_NONE)} 00069 }; 00070 00071 static arrowname_t Arrowmods[] = { 00072 {"o", ARR_MOD_OPEN}, 00073 {"r", ARR_MOD_RIGHT}, 00074 {"l", ARR_MOD_LEFT}, 00075 /* deprecated alternates for backward compat */ 00076 {"e", ARR_MOD_OPEN}, /* o - needed for "ediamond" */ 00077 {"half", ARR_MOD_LEFT}, /* l - needed for "halfopen" */ 00078 {(char *) 0, ARR_TYPE_NONE} 00079 }; 00080 00081 static arrowname_t Arrownames[] = { 00082 {"normal", ARR_TYPE_NORM}, 00083 {"crow", ARR_TYPE_CROW}, 00084 {"tee", ARR_TYPE_TEE}, 00085 {"box", ARR_TYPE_BOX}, 00086 {"diamond", ARR_TYPE_DIAMOND}, 00087 {"dot", ARR_TYPE_DOT}, 00088 {"none", ARR_TYPE_NONE}, 00089 /* ARR_MOD_INV is used only here to define two additional shapes 00090 since not all types can use it */ 00091 {"inv", (ARR_TYPE_NORM | ARR_MOD_INV)}, 00092 {"vee", (ARR_TYPE_CROW | ARR_MOD_INV)}, 00093 /* WARNING ugly kludge to deal with "o" v "open" conflict */ 00094 /* Define "open" as just "pen" since "o" already taken as ARR_MOD_OPEN */ 00095 /* Note that ARR_MOD_OPEN has no meaning for ARR_TYPE_CROW shape */ 00096 {"pen", (ARR_TYPE_CROW | ARR_MOD_INV)}, 00097 /* WARNING ugly kludge to deal with "e" v "empty" conflict */ 00098 /* Define "empty" as just "mpty" since "e" already taken as ARR_MOD_OPEN */ 00099 /* Note that ARR_MOD_OPEN has expected meaning for ARR_TYPE_NORM shape */ 00100 {"mpty", ARR_TYPE_NORM}, 00101 {(char *) 0, ARR_TYPE_NONE} 00102 }; 00103 00104 typedef struct arrowtype_t { 00105 int type; 00106 double lenfact; /* ratio of length of this arrow type to standard arrow */ 00107 void (*gen) (GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); /* generator function for type */ 00108 } arrowtype_t; 00109 00110 /* forward declaration of functions used in Arrowtypes[] */ 00111 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00112 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00113 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00114 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00115 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00116 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); 00117 00118 static arrowtype_t Arrowtypes[] = { 00119 {ARR_TYPE_NORM, 1.0, arrow_type_normal}, 00120 {ARR_TYPE_CROW, 1.0, arrow_type_crow}, 00121 {ARR_TYPE_TEE, 0.5, arrow_type_tee}, 00122 {ARR_TYPE_BOX, 1.0, arrow_type_box}, 00123 {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond}, 00124 {ARR_TYPE_DOT, 0.8, arrow_type_dot}, 00125 {ARR_TYPE_NONE, 0.0, NULL} 00126 }; 00127 00128 static char *arrow_match_name_frag(char *name, arrowname_t * arrownames, int *flag) 00129 { 00130 arrowname_t *arrowname; 00131 int namelen = 0; 00132 char *rest = name; 00133 00134 for (arrowname = arrownames; arrowname->name; arrowname++) { 00135 namelen = strlen(arrowname->name); 00136 if (strncmp(name, arrowname->name, namelen) == 0) { 00137 *flag |= arrowname->type; 00138 rest += namelen; 00139 break; 00140 } 00141 } 00142 return rest; 00143 } 00144 00145 static char *arrow_match_shape(char *name, int *flag) 00146 { 00147 char *next, *rest; 00148 int f = ARR_TYPE_NONE; 00149 00150 rest = arrow_match_name_frag(name, Arrowsynonyms, &f); 00151 if (rest == name) { 00152 do { 00153 next = rest; 00154 rest = arrow_match_name_frag(next, Arrowmods, &f); 00155 } while (next != rest); 00156 rest = arrow_match_name_frag(rest, Arrownames, &f); 00157 } 00158 if (f && !(f & ((1 << BITS_PER_ARROW_TYPE) - 1))) 00159 f |= ARR_TYPE_NORM; 00160 *flag |= f; 00161 return rest; 00162 } 00163 00164 static void arrow_match_name(char *name, int *flag) 00165 { 00166 char *rest = name; 00167 int i, f; 00168 00169 *flag = 0; 00170 for (i = 0; *rest != '\0' && i < NUMB_OF_ARROW_HEADS; i++) { 00171 f = ARR_TYPE_NONE; 00172 rest = arrow_match_shape(rest, &f); 00173 *flag |= (f << (i * BITS_PER_ARROW)); 00174 } 00175 } 00176 00177 void arrow_flags(Agedge_t * e, int *sflag, int *eflag) 00178 { 00179 char *attr; 00180 arrowdir_t *arrowdir; 00181 00182 *sflag = ARR_TYPE_NONE; 00183 #ifdef WITH_CGRAPH 00184 *eflag = agisdirected(agraphof(e)) ? ARR_TYPE_NORM : ARR_TYPE_NONE; 00185 if (E_dir && ((attr = agxget(e, E_dir)))[0]) { 00186 #else 00187 *eflag = AG_IS_DIRECTED(e->tail->graph) ? ARR_TYPE_NORM : ARR_TYPE_NONE; 00188 if (E_dir && ((attr = agxget(e, E_dir->index)))[0]) { 00189 #endif 00190 for (arrowdir = Arrowdirs; arrowdir->dir; arrowdir++) { 00191 if (streq(attr, arrowdir->dir)) { 00192 *sflag = arrowdir->sflag; 00193 *eflag = arrowdir->eflag; 00194 break; 00195 } 00196 } 00197 } 00198 #ifdef WITH_CGRAPH 00199 if (E_arrowhead && (*eflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowhead)))[0]) 00200 arrow_match_name(attr, eflag); 00201 if (E_arrowtail && (*sflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowtail)))[0]) 00202 arrow_match_name(attr, sflag); 00203 #else 00204 if (E_arrowhead && (*eflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowhead->index)))[0]) 00205 arrow_match_name(attr, eflag); 00206 if (E_arrowtail && (*sflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowtail->index)))[0]) 00207 arrow_match_name(attr, sflag); 00208 #endif 00209 if (ED_conc_opp_flag(e)) { 00210 edge_t *f; 00211 int s0, e0; 00212 /* pick up arrowhead of opposing edge */ 00213 f = agfindedge(agraphof(aghead(e)), aghead(e), agtail(e)); 00214 arrow_flags(f, &s0, &e0); 00215 *eflag = *eflag | s0; 00216 *sflag = *sflag | e0; 00217 } 00218 } 00219 00220 double arrow_length(edge_t * e, int flag) 00221 { 00222 arrowtype_t *arrowtype; 00223 double lenfact = 0.0; 00224 int f, i; 00225 00226 for (i = 0; i < NUMB_OF_ARROW_HEADS; i++) { 00227 /* we don't simply index with flag because arrowtypes are not necessarily sorted */ 00228 f = (flag >> (i * BITS_PER_ARROW)) & ((1 << BITS_PER_ARROW_TYPE) - 1); 00229 for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) { 00230 if (f == arrowtype->type) { 00231 lenfact += arrowtype->lenfact; 00232 break; 00233 } 00234 } 00235 } 00236 /* The original was missing the factor E_arrowsz, but I believe it 00237 should be here for correct arrow clipping */ 00238 return ARROW_LENGTH * lenfact * late_double(e, E_arrowsz, 1.0, 0.0); 00239 } 00240 00241 /* inside function for calls to bezier_clip */ 00242 static boolean inside(inside_t * inside_context, pointf p) 00243 { 00244 return DIST2(p, inside_context->a.p[0]) <= inside_context->a.r[0]; 00245 } 00246 00247 int arrowEndClip(edge_t* e, pointf * ps, int startp, 00248 int endp, bezier * spl, int eflag) 00249 { 00250 inside_t inside_context; 00251 pointf sp[4]; 00252 double elen, elen2; 00253 00254 elen = arrow_length(e, eflag); 00255 elen2 = elen * elen; 00256 spl->eflag = eflag, spl->ep = ps[endp + 3]; 00257 if (endp > startp && DIST2(ps[endp], ps[endp + 3]) < elen2) { 00258 endp -= 3; 00259 } 00260 sp[3] = ps[endp]; 00261 sp[2] = ps[endp + 1]; 00262 sp[1] = ps[endp + 2]; 00263 sp[0] = spl->ep; /* ensure endpoint starts inside */ 00264 00265 inside_context.a.p = &sp[0]; 00266 inside_context.a.r = &elen2; 00267 bezier_clip(&inside_context, inside, sp, TRUE); 00268 00269 ps[endp] = sp[3]; 00270 ps[endp + 1] = sp[2]; 00271 ps[endp + 2] = sp[1]; 00272 ps[endp + 3] = sp[0]; 00273 return endp; 00274 } 00275 00276 int arrowStartClip(edge_t* e, pointf * ps, int startp, 00277 int endp, bezier * spl, int sflag) 00278 { 00279 inside_t inside_context; 00280 pointf sp[4]; 00281 double slen, slen2; 00282 00283 slen = arrow_length(e, sflag); 00284 slen2 = slen * slen; 00285 spl->sflag = sflag, spl->sp = ps[startp]; 00286 if (endp > startp && DIST2(ps[startp], ps[startp + 3]) < slen2) { 00287 startp += 3; 00288 } 00289 sp[0] = ps[startp + 3]; 00290 sp[1] = ps[startp + 2]; 00291 sp[2] = ps[startp + 1]; 00292 sp[3] = spl->sp; /* ensure endpoint starts inside */ 00293 00294 inside_context.a.p = &sp[3]; 00295 inside_context.a.r = &slen2; 00296 bezier_clip(&inside_context, inside, sp, FALSE); 00297 00298 ps[startp] = sp[3]; 00299 ps[startp + 1] = sp[2]; 00300 ps[startp + 2] = sp[1]; 00301 ps[startp + 3] = sp[0]; 00302 return startp; 00303 } 00304 00305 /* arrowOrthoClip: 00306 * For orthogonal routing, we know each Bezier of spl is a horizontal or vertical 00307 * line segment. We need to guarantee the B-spline stays this way. At present, we shrink 00308 * the arrows if necessary to fit the last segment at either end. Alternatively, we could 00309 * maintain the arrow size by dropping the 3 points of spl, and adding a new spl encoding 00310 * the arrow, something "ex_0,y_0 x_1,y_1 x_1,y_1 x_1,y_1 x_1,y_1", when the last line 00311 * segment is x_1,y_1 x_2,y_2 x_3,y_3 x_0,y_0. With a good deal more work, we could guarantee 00312 * that the truncated spl clips to the arrow shape. 00313 */ 00314 void arrowOrthoClip(edge_t* e, pointf* ps, int startp, int endp, bezier* spl, int sflag, int eflag) 00315 { 00316 pointf p, q, r, s, t; 00317 double d, tlen, hlen, maxd; 00318 00319 if (sflag && eflag && (endp == startp)) { /* handle special case of two arrows on a single segment */ 00320 p = ps[endp]; 00321 q = ps[endp+3]; 00322 tlen = arrow_length (e, sflag); 00323 hlen = arrow_length (e, eflag); 00324 d = DIST(p, q); 00325 if (hlen + tlen >= d) { 00326 hlen = tlen = d/3.0; 00327 } 00328 if (p.y == q.y) { /* horz segment */ 00329 s.y = t.y = p.y; 00330 if (p.x < q.x) { 00331 t.x = q.x - hlen; 00332 s.x = p.x + tlen; 00333 } 00334 else { 00335 t.x = q.x + hlen; 00336 s.x = p.x - tlen; 00337 } 00338 } 00339 else { /* vert segment */ 00340 s.x = t.x = p.x; 00341 if (p.y < q.y) { 00342 t.y = q.y - hlen; 00343 s.y = p.y + tlen; 00344 } 00345 else { 00346 t.y = q.y + hlen; 00347 s.y = p.y - tlen; 00348 } 00349 } 00350 ps[endp] = ps[endp + 1] = s; 00351 ps[endp + 2] = ps[endp + 3] = t; 00352 spl->eflag = eflag, spl->ep = p; 00353 spl->sflag = sflag, spl->sp = q; 00354 return; 00355 } 00356 if (eflag) { 00357 hlen = arrow_length(e, eflag); 00358 p = ps[endp]; 00359 q = ps[endp+3]; 00360 d = DIST(p, q); 00361 maxd = 0.9*d; 00362 if (hlen >= maxd) { /* arrow too long */ 00363 hlen = maxd; 00364 } 00365 if (p.y == q.y) { /* horz segment */ 00366 r.y = p.y; 00367 if (p.x < q.x) r.x = q.x - hlen; 00368 else r.x = q.x + hlen; 00369 } 00370 else { /* vert segment */ 00371 r.x = p.x; 00372 if (p.y < q.y) r.y = q.y - hlen; 00373 else r.y = q.y + hlen; 00374 } 00375 ps[endp + 1] = p; 00376 ps[endp + 2] = ps[endp + 3] = r; 00377 spl->eflag = eflag; 00378 spl->ep = q; 00379 } 00380 if (sflag) { 00381 tlen = arrow_length(e, sflag); 00382 p = ps[startp]; 00383 q = ps[startp+3]; 00384 d = DIST(p, q); 00385 maxd = 0.9*d; 00386 if (tlen >= maxd) { /* arrow too long */ 00387 tlen = maxd; 00388 } 00389 if (p.y == q.y) { /* horz segment */ 00390 r.y = p.y; 00391 if (p.x < q.x) r.x = p.x + tlen; 00392 else r.x = p.x - tlen; 00393 } 00394 else { /* vert segment */ 00395 r.x = p.x; 00396 if (p.y < q.y) r.y = p.y + tlen; 00397 else r.y = p.y - tlen; 00398 } 00399 ps[startp] = ps[startp + 1] = r; 00400 ps[startp + 2] = q; 00401 spl->sflag = sflag; 00402 spl->sp = p; 00403 } 00404 } 00405 00406 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00407 { 00408 pointf q, v, a[5]; 00409 double arrowwidth; 00410 00411 arrowwidth = 0.35; 00412 if (penwidth > 4) 00413 arrowwidth *= penwidth / 4; 00414 00415 v.x = -u.y * arrowwidth; 00416 v.y = u.x * arrowwidth; 00417 q.x = p.x + u.x; 00418 q.y = p.y + u.y; 00419 if (flag & ARR_MOD_INV) { 00420 a[0] = a[4] = p; 00421 a[1].x = p.x - v.x; 00422 a[1].y = p.y - v.y; 00423 a[2] = q; 00424 a[3].x = p.x + v.x; 00425 a[3].y = p.y + v.y; 00426 } else { 00427 a[0] = a[4] = q; 00428 a[1].x = q.x - v.x; 00429 a[1].y = q.y - v.y; 00430 a[2] = p; 00431 a[3].x = q.x + v.x; 00432 a[3].y = q.y + v.y; 00433 } 00434 if (flag & ARR_MOD_LEFT) 00435 gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN)); 00436 else if (flag & ARR_MOD_RIGHT) 00437 gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN)); 00438 else 00439 gvrender_polygon(job, &a[1], 3, !(flag & ARR_MOD_OPEN)); 00440 } 00441 00442 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00443 { 00444 pointf m, q, v, w, a[9]; 00445 double arrowwidth, shaftwidth; 00446 00447 arrowwidth = 0.45; 00448 if (penwidth > (4 * arrowsize) && (flag & ARR_MOD_INV)) 00449 arrowwidth *= penwidth / (4 * arrowsize); 00450 00451 shaftwidth = 0; 00452 if (penwidth > 1 && (flag & ARR_MOD_INV)) 00453 shaftwidth = 0.05 * (penwidth - 1) / arrowsize; /* arrowsize to cancel the arrowsize term already in u */ 00454 00455 v.x = -u.y * arrowwidth; 00456 v.y = u.x * arrowwidth; 00457 w.x = -u.y * shaftwidth; 00458 w.y = u.x * shaftwidth; 00459 q.x = p.x + u.x; 00460 q.y = p.y + u.y; 00461 m.x = p.x + u.x * 0.5; 00462 m.y = p.y + u.y * 0.5; 00463 if (flag & ARR_MOD_INV) { /* vee */ 00464 a[0] = a[8] = p; 00465 a[1].x = q.x - v.x; 00466 a[1].y = q.y - v.y; 00467 a[2].x = m.x - w.x; 00468 a[2].y = m.y - w.y; 00469 a[3].x = q.x - w.x; 00470 a[3].y = q.y - w.y; 00471 a[4] = q; 00472 a[5].x = q.x + w.x; 00473 a[5].y = q.y + w.y; 00474 a[6].x = m.x + w.x; 00475 a[6].y = m.y + w.y; 00476 a[7].x = q.x + v.x; 00477 a[7].y = q.y + v.y; 00478 } else { /* crow */ 00479 a[0] = a[8] = q; 00480 a[1].x = p.x - v.x; 00481 a[1].y = p.y - v.y; 00482 a[2].x = m.x - w.x; 00483 a[2].y = m.y - w.y; 00484 a[3].x = p.x; 00485 a[3].y = p.y; 00486 a[4] = p; 00487 a[5].x = p.x; 00488 a[5].y = p.y; 00489 a[6].x = m.x + w.x; 00490 a[6].y = m.y + w.y; 00491 a[7].x = p.x + v.x; 00492 a[7].y = p.y + v.y; 00493 } 00494 if (flag & ARR_MOD_LEFT) 00495 gvrender_polygon(job, a, 6, 1); 00496 else if (flag & ARR_MOD_RIGHT) 00497 gvrender_polygon(job, &a[3], 6, 1); 00498 else 00499 gvrender_polygon(job, a, 9, 1); 00500 } 00501 00502 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00503 { 00504 pointf m, n, q, v, a[4]; 00505 00506 v.x = -u.y; 00507 v.y = u.x; 00508 q.x = p.x + u.x; 00509 q.y = p.y + u.y; 00510 m.x = p.x + u.x * 0.2; 00511 m.y = p.y + u.y * 0.2; 00512 n.x = p.x + u.x * 0.6; 00513 n.y = p.y + u.y * 0.6; 00514 a[0].x = m.x + v.x; 00515 a[0].y = m.y + v.y; 00516 a[1].x = m.x - v.x; 00517 a[1].y = m.y - v.y; 00518 a[2].x = n.x - v.x; 00519 a[2].y = n.y - v.y; 00520 a[3].x = n.x + v.x; 00521 a[3].y = n.y + v.y; 00522 if (flag & ARR_MOD_LEFT) { 00523 a[0] = m; 00524 a[3] = n; 00525 } else if (flag & ARR_MOD_RIGHT) { 00526 a[1] = m; 00527 a[2] = n; 00528 } 00529 gvrender_polygon(job, a, 4, 1); 00530 a[0] = p; 00531 a[1] = q; 00532 gvrender_polyline(job, a, 2); 00533 } 00534 00535 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00536 { 00537 pointf m, q, v, a[4]; 00538 00539 v.x = -u.y * 0.4; 00540 v.y = u.x * 0.4; 00541 m.x = p.x + u.x * 0.8; 00542 m.y = p.y + u.y * 0.8; 00543 q.x = p.x + u.x; 00544 q.y = p.y + u.y; 00545 a[0].x = p.x + v.x; 00546 a[0].y = p.y + v.y; 00547 a[1].x = p.x - v.x; 00548 a[1].y = p.y - v.y; 00549 a[2].x = m.x - v.x; 00550 a[2].y = m.y - v.y; 00551 a[3].x = m.x + v.x; 00552 a[3].y = m.y + v.y; 00553 if (flag & ARR_MOD_LEFT) { 00554 a[0] = p; 00555 a[3] = m; 00556 } else if (flag & ARR_MOD_RIGHT) { 00557 a[1] = p; 00558 a[2] = m; 00559 } 00560 gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN)); 00561 a[0] = m; 00562 a[1] = q; 00563 gvrender_polyline(job, a, 2); 00564 } 00565 00566 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00567 { 00568 pointf q, r, v, a[5]; 00569 00570 v.x = -u.y / 3.; 00571 v.y = u.x / 3.; 00572 r.x = p.x + u.x / 2.; 00573 r.y = p.y + u.y / 2.; 00574 q.x = p.x + u.x; 00575 q.y = p.y + u.y; 00576 a[0] = a[4] = q; 00577 a[1].x = r.x + v.x; 00578 a[1].y = r.y + v.y; 00579 a[2] = p; 00580 a[3].x = r.x - v.x; 00581 a[3].y = r.y - v.y; 00582 if (flag & ARR_MOD_LEFT) 00583 gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN)); 00584 else if (flag & ARR_MOD_RIGHT) 00585 gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN)); 00586 else 00587 gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN)); 00588 } 00589 00590 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00591 { 00592 double r; 00593 pointf AF[2]; 00594 00595 r = sqrt(u.x * u.x + u.y * u.y) / 2.; 00596 AF[0].x = p.x + u.x / 2. - r; 00597 AF[0].y = p.y + u.y / 2. - r; 00598 AF[1].x = p.x + u.x / 2. + r; 00599 AF[1].y = p.y + u.y / 2. + r; 00600 gvrender_ellipse(job, AF, 2, !(flag & ARR_MOD_OPEN)); 00601 } 00602 00603 static pointf arrow_gen_type(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00604 { 00605 int f; 00606 arrowtype_t *arrowtype; 00607 00608 f = flag & ((1 << BITS_PER_ARROW_TYPE) - 1); 00609 for (arrowtype = Arrowtypes; arrowtype->type; arrowtype++) { 00610 if (f == arrowtype->type) { 00611 u.x *= arrowtype->lenfact * arrowsize; 00612 u.y *= arrowtype->lenfact * arrowsize; 00613 (arrowtype->gen) (job, p, u, arrowsize, penwidth, flag); 00614 p.x = p.x + u.x; 00615 p.y = p.y + u.y; 00616 break; 00617 } 00618 } 00619 return p; 00620 } 00621 00622 boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag) 00623 { 00624 double s; 00625 boxf bb; 00626 double ax,ay,bx,by,cx,cy,dx,dy; 00627 double ux2, uy2; 00628 00629 /* generate arrowhead vector */ 00630 u.x -= p.x; 00631 u.y -= p.y; 00632 /* the EPSILONs are to keep this stable as length of u approaches 0.0 */ 00633 s = ARROW_LENGTH * arrowsize / (sqrt(u.x * u.x + u.y * u.y) + EPSILON); 00634 u.x += (u.x >= 0.0) ? EPSILON : -EPSILON; 00635 u.y += (u.y >= 0.0) ? EPSILON : -EPSILON; 00636 u.x *= s; 00637 u.y *= s; 00638 00639 /* compute all 4 corners of rotated arrowhead bounding box */ 00640 ux2 = u.x / 2.; 00641 uy2 = u.y / 2.; 00642 ax = p.x - uy2; 00643 ay = p.y - ux2; 00644 bx = p.x + uy2; 00645 by = p.y + ux2; 00646 cx = ax + u.x; 00647 cy = ay + u.y; 00648 dx = bx + u.x; 00649 dy = by + u.y; 00650 00651 /* compute a right bb */ 00652 bb.UR.x = MAX(ax, MAX(bx, MAX(cx, dx))); 00653 bb.UR.y = MAX(ay, MAX(by, MAX(cy, dy))); 00654 bb.LL.x = MIN(ax, MIN(bx, MIN(cx, dx))); 00655 bb.LL.y = MIN(ay, MIN(by, MIN(cy, dy))); 00656 00657 return bb; 00658 } 00659 00660 void arrow_gen(GVJ_t * job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, int flag) 00661 { 00662 obj_state_t *obj = job->obj; 00663 double s; 00664 int i, f; 00665 emit_state_t old_emit_state; 00666 00667 old_emit_state = obj->emit_state; 00668 obj->emit_state = emit_state; 00669 00670 /* Dotted and dashed styles on the arrowhead are ugly (dds) */ 00671 /* linewidth needs to be reset */ 00672 gvrender_set_style(job, job->gvc->defaultlinestyle); 00673 00674 /* generate arrowhead vector */ 00675 u.x -= p.x; 00676 u.y -= p.y; 00677 /* the EPSILONs are to keep this stable as length of u approaches 0.0 */ 00678 s = ARROW_LENGTH / (sqrt(u.x * u.x + u.y * u.y) + EPSILON); 00679 u.x += (u.x >= 0.0) ? EPSILON : -EPSILON; 00680 u.y += (u.y >= 0.0) ? EPSILON : -EPSILON; 00681 u.x *= s; 00682 u.y *= s; 00683 00684 /* the first arrow head - closest to node */ 00685 for (i = 0; i < NUMB_OF_ARROW_HEADS; i++) { 00686 f = (flag >> (i * BITS_PER_ARROW)) & ((1 << BITS_PER_ARROW) - 1); 00687 if (f == ARR_TYPE_NONE) 00688 break; 00689 p = arrow_gen_type(job, p, u, arrowsize, penwidth, f); 00690 } 00691 00692 obj->emit_state = old_emit_state; 00693 }
1.7.4