1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: p_draw.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib drawing routines 16 * 17 */ 18 19#include "p_intern.h" 20 21/* Path segment operators */ 22 23void 24pdf_begin_path(PDF *p) 25{ 26 if (PDF_GET_STATE(p) == pdf_state_path) 27 return; 28 29 pdf_end_text(p); 30 p->contents = c_path; 31 PDF_PUSH_STATE(p, "pdf_begin_path", pdf_state_path); 32} 33 34void 35pdf_end_path(PDF *p) 36{ 37 p->contents = c_page; 38 PDF_POP_STATE(p, "pdf_end_path"); 39 40 p->gstate[p->sl].x = (float) 0.0; 41 p->gstate[p->sl].y = (float) 0.0; 42} 43 44/* ----------------- Basic functions for API functions --------------*/ 45 46void 47pdf__moveto(PDF *p, float x, float y) 48{ 49 p->gstate[p->sl].startx = p->gstate[p->sl].x = x; 50 p->gstate[p->sl].starty = p->gstate[p->sl].y = y; 51 52 pdf_begin_path(p); 53 pdc_printf(p->out, "%f %f m\n", x, y); 54} 55 56void 57pdf__rmoveto(PDF *p, float x, float y) 58{ 59 float x_0 = p->gstate[p->sl].x; 60 float y_0 = p->gstate[p->sl].y; 61 62 pdf__moveto(p, x_0 + x, y_0 + y); 63} 64 65void 66pdf__lineto(PDF *p, float x, float y) 67{ 68 pdc_printf(p->out, "%f %f l\n", x, y); 69 70 p->gstate[p->sl].x = x; 71 p->gstate[p->sl].y = y; 72} 73 74void 75pdf__rlineto(PDF *p, float x, float y) 76{ 77 float x_0 = p->gstate[p->sl].x; 78 float y_0 = p->gstate[p->sl].y; 79 80 pdf__lineto(p, x_0 + x, y_0 + y); 81} 82 83void 84pdf__curveto(PDF *p, 85 float x_1, float y_1, 86 float x_2, float y_2, 87 float x_3, float y_3) 88{ 89 if (x_2 == x_3 && y_2 == y_3) /* second c.p. coincides with final point */ 90 pdc_printf(p->out, "%f %f %f %f y\n", x_1, y_1, x_3, y_3); 91 92 else /* general case with four distinct points */ 93 pdc_printf(p->out, "%f %f %f %f %f %f c\n", 94 x_1, y_1, x_2, y_2, x_3, y_3); 95 96 p->gstate[p->sl].x = x_3; 97 p->gstate[p->sl].y = y_3; 98} 99 100void 101pdf__rcurveto(PDF *p, 102 float x_1, float y_1, 103 float x_2, float y_2, 104 float x_3, float y_3) 105{ 106 float x_0 = p->gstate[p->sl].x; 107 float y_0 = p->gstate[p->sl].y; 108 109 pdf__curveto(p, x_0 + x_1, y_0 + y_1, 110 x_0 + x_2, y_0 + y_2, 111 x_0 + x_3, y_0 + y_3); 112} 113 114void 115pdf__rrcurveto(PDF *p, 116 float x_1, float y_1, 117 float x_2, float y_2, 118 float x_3, float y_3) 119{ 120 pdf__rcurveto(p, x_1, y_1, 121 x_1 + x_2, y_1 + y_2, 122 x_1 + x_2 + x_3, y_1 + y_2 + y_3); 123} 124 125void 126pdf__hvcurveto(PDF *p, float x_1, float x_2, float y_2, float y_3) 127{ 128 pdf__rrcurveto(p, x_1, 0, x_2, y_2, 0, y_3); 129} 130 131void 132pdf__vhcurveto(PDF *p, float y_1, float x_2, float y_2, float x_3) 133{ 134 pdf__rrcurveto(p, 0, y_1, x_2, y_2, x_3, 0); 135} 136 137void 138pdf__rect(PDF *p, float x, float y, float width, float height) 139{ 140 p->gstate[p->sl].startx = p->gstate[p->sl].x = x; 141 p->gstate[p->sl].starty = p->gstate[p->sl].y = y; 142 143 pdf_begin_path(p); 144 pdc_printf(p->out, "%f %f %f %f re\n", x, y, width, p->ydirection * height); 145} 146 147/* 4/3 * (1-cos 45�)/sin 45� = 4/3 * sqrt(2) - 1 */ 148#define ARC_MAGIC ((float) 0.552284749) 149 150static void 151pdf_short_arc(PDF *p, float x, float y, float r, float alpha, float beta) 152{ 153 float bcp; 154 float cos_alpha, cos_beta, sin_alpha, sin_beta; 155 156 alpha = (float) (alpha * PDC_M_PI / 180); 157 beta = (float) (beta * PDC_M_PI / 180); 158 159 /* This formula yields ARC_MAGIC for alpha == 0, beta == 90 degrees */ 160 bcp = (float) (4.0/3 * (1 - cos((beta - alpha)/2)) / sin((beta - alpha)/2)); 161 162 sin_alpha = (float) sin(alpha); 163 sin_beta = (float) sin(beta); 164 cos_alpha = (float) cos(alpha); 165 cos_beta = (float) cos(beta); 166 167 pdf__curveto(p, 168 x + r * (cos_alpha - bcp * sin_alpha), /* p1 */ 169 y + r * (sin_alpha + bcp * cos_alpha), 170 x + r * (cos_beta + bcp * sin_beta), /* p2 */ 171 y + r * (sin_beta - bcp * cos_beta), 172 x + r * cos_beta, /* p3 */ 173 y + r * sin_beta); 174} 175 176static void 177pdf_orient_arc(PDF *p, float x, float y, float r, float alpha, float beta, 178 float orient) 179{ 180 float rad_a = (float) (alpha * PDC_M_PI / 180); 181 float startx = (float) (x + r * cos(rad_a)); 182 float starty = (float) (y + r * sin(rad_a)); 183 184 if (r < 0) 185 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 186 "r", pdc_errprintf(p->pdc, "%f", r), 0, 0); 187 188 if (p->contents != c_path) 189 pdf__moveto(p, startx, starty); 190 else if ((p->gstate[p->sl].x != startx || p->gstate[p->sl].y != starty)) 191 pdf__lineto(p, startx, starty); 192 193 if (orient > 0) 194 { 195 while (beta < alpha) 196 beta += 360; 197 198 if (alpha == beta) 199 return; 200 201 while (beta - alpha > 90) 202 { 203 pdf_short_arc(p, x, y, r, alpha, alpha + 90); 204 alpha += 90; 205 } 206 } 207 else 208 { 209 while (alpha < beta) 210 alpha += 360; 211 212 if (alpha == beta) 213 return; 214 215 while (alpha - beta > 90) 216 { 217 pdf_short_arc(p, x, y, r, alpha, alpha - 90); 218 alpha -= 90; 219 } 220 } 221 222 if (alpha != beta) 223 pdf_short_arc(p, x, y, r, alpha, beta); 224} 225 226void 227pdf__arc(PDF *p, float x, float y, float r, float alpha, float beta) 228{ 229 pdf_orient_arc(p, x, y, r, 230 p->ydirection * alpha, p->ydirection * beta, p->ydirection); 231} 232 233void 234pdf__arcn(PDF *p, float x, float y, float r, float alpha, float beta) 235{ 236 pdf_orient_arc(p, x, y, r, 237 p->ydirection * alpha, p->ydirection * beta, -p->ydirection); 238} 239 240void 241pdf__circle(PDF *p, float x, float y, float r) 242{ 243 if (r < 0) 244 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 245 "r", pdc_errprintf(p->pdc, "%f", r), 0, 0); 246 247 /* 248 * pdf_begin_path() not required since we descend to other 249 * path segment functions. 250 */ 251 252 /* draw four Bezier curves to approximate a circle */ 253 pdf__moveto(p, x + r, y); 254 pdf__curveto(p, x + r, y + r*ARC_MAGIC, x + r*ARC_MAGIC, y + r, x, y + r); 255 pdf__curveto(p, x - r*ARC_MAGIC, y + r, x - r, y + r*ARC_MAGIC, x - r, y); 256 pdf__curveto(p, x - r, y - r*ARC_MAGIC, x - r*ARC_MAGIC, y - r, x, y - r); 257 pdf__curveto(p, x + r*ARC_MAGIC, y - r, x + r, y - r*ARC_MAGIC, x + r, y); 258 259 pdf__closepath(p); 260} 261 262void 263pdf__closepath(PDF *p) 264{ 265 pdc_puts(p->out, "h\n"); 266 267 p->gstate[p->sl].x = p->gstate[p->sl].startx; 268 p->gstate[p->sl].y = p->gstate[p->sl].starty; 269} 270 271void 272pdf__endpath(PDF *p) 273{ 274 pdc_puts(p->out, "n\n"); 275 pdf_end_path(p); 276} 277 278void 279pdf__stroke(PDF *p) 280{ 281 pdc_puts(p->out, "S\n"); 282 pdf_end_path(p); 283} 284 285void 286pdf__closepath_stroke(PDF *p) 287{ 288 pdc_puts(p->out, "s\n"); 289 pdf_end_path(p); 290} 291 292void 293pdf__fill(PDF *p) 294{ 295 if (p->fillrule == pdf_fill_winding) 296 pdc_puts(p->out, "f\n"); 297 else if (p->fillrule == pdf_fill_evenodd) 298 pdc_puts(p->out, "f*\n"); 299 300 pdf_end_path(p); 301} 302 303void 304pdf__fill_stroke(PDF *p) 305{ 306 if (p->fillrule == pdf_fill_winding) 307 pdc_puts(p->out, "B\n"); 308 else if (p->fillrule == pdf_fill_evenodd) 309 pdc_puts(p->out, "B*\n"); 310 311 pdf_end_path(p); 312} 313 314void 315pdf__closepath_fill_stroke(PDF *p) 316{ 317 if (p->fillrule == pdf_fill_winding) 318 pdc_puts(p->out, "b\n"); 319 else if (p->fillrule == pdf_fill_evenodd) 320 pdc_puts(p->out, "b*\n"); 321 322 pdf_end_path(p); 323} 324 325void 326pdf__clip(PDF *p) 327{ 328 if (p->fillrule == pdf_fill_winding) 329 pdc_puts(p->out, "W n\n"); 330 else if (p->fillrule == pdf_fill_evenodd) 331 pdc_puts(p->out, "W* n\n"); 332 333 pdf_end_path(p); 334} 335 336/* --------------------------- API functions ------------------------------*/ 337 338PDFLIB_API void PDFLIB_CALL 339PDF_moveto(PDF *p, float x, float y) 340{ 341 static const char fn[] = "PDF_moveto"; 342 343 if (pdf_enter_api(p, fn, 344 (pdf_state) (pdf_state_content | pdf_state_path), 345 "(p[%p], %g, %g)\n", (void *) p, x, y)) 346 { 347 pdf__moveto(p, x, y); 348 } 349} 350 351PDFLIB_API void PDFLIB_CALL 352PDF_rmoveto(PDF *p, float x, float y) 353{ 354 static const char fn[] = "PDF_rmoveto"; 355 356 if (pdf_enter_api(p, fn, 357 (pdf_state) (pdf_state_content | pdf_state_path), 358 "(p[%p], %g, %g)\n", (void *) p, x, y)) 359 { 360 pdf__rmoveto(p, x, y); 361 } 362} 363 364PDFLIB_API void PDFLIB_CALL 365PDF_lineto(PDF *p, float x, float y) 366{ 367 static const char fn[] = "PDF_lineto"; 368 369 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p], %g, %g)\n", 370 (void *) p, x, y)) 371 { 372 pdf__lineto(p, x, y); 373 } 374} 375 376PDFLIB_API void PDFLIB_CALL 377PDF_rlineto(PDF *p, float x, float y) 378{ 379 static const char fn[] = "PDF_rlineto"; 380 381 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p], %g, %g)\n", 382 (void *) p, x, y)) 383 { 384 pdf__rlineto(p, x, y); 385 } 386} 387 388PDFLIB_API void PDFLIB_CALL 389PDF_curveto(PDF *p, 390 float x_1, float y_1, float x_2, float y_2, float x_3, float y_3) 391{ 392 static const char fn[] = "PDF_curveto"; 393 394 if (pdf_enter_api(p, fn, pdf_state_path, 395 "(p[%p], %g, %g, %g, %g, %g, %g)\n", 396 (void *) p, x_1, y_1, x_2, y_2, x_3, y_3)) 397 { 398 pdf__curveto(p, x_1, y_1, x_2, y_2, x_3, y_3); 399 } 400} 401 402PDFLIB_API void PDFLIB_CALL 403PDF_rcurveto(PDF *p, 404 float x_1, float y_1, float x_2, float y_2, float x_3, float y_3) 405{ 406 static const char fn[] = "PDF_rcurveto"; 407 408 if (pdf_enter_api(p, fn, pdf_state_path, 409 "(p[%p], %g, %g, %g, %g, %g, %g)\n", 410 (void *) p, x_1, y_1, x_2, y_2, x_3, y_3)) 411 { 412 pdf__rcurveto(p, x_1, y_1, x_2, y_2, x_3, y_3); 413 } 414} 415 416PDFLIB_API void PDFLIB_CALL 417PDF_rect(PDF *p, float x, float y, float width, float height) 418{ 419 static const char fn[] = "PDF_rect"; 420 421 if (pdf_enter_api(p, fn, 422 (pdf_state) (pdf_state_content | pdf_state_path), 423 "(p[%p], %g, %g, %g, %g)\n", (void *) p, x, y, width, height)) 424 { 425 pdf__rect(p, x, y, width, height); 426 } 427} 428 429PDFLIB_API void PDFLIB_CALL 430PDF_arc(PDF *p, float x, float y, float r, float alpha, float beta) 431{ 432 static const char fn[] = "PDF_arc"; 433 434 if (pdf_enter_api(p, fn, 435 (pdf_state) (pdf_state_content | pdf_state_path), 436 "(p[%p], %g, %g, %g, %g, %g)\n", (void *) p, x, y, r, alpha, beta)) 437 { 438 pdf__arc(p, x, y, r, alpha, beta); 439 } 440} 441 442PDFLIB_API void PDFLIB_CALL 443PDF_arcn(PDF *p, float x, float y, float r, float alpha, float beta) 444{ 445 static const char fn[] = "PDF_arcn"; 446 447 if (pdf_enter_api(p, fn, 448 (pdf_state) (pdf_state_content | pdf_state_path), 449 "(p[%p], %g, %g, %g, %g, %g)\n", (void *) p, x, y, r, alpha, beta)) 450 { 451 pdf__arcn(p, x, y, r, alpha, beta); 452 } 453} 454 455PDFLIB_API void PDFLIB_CALL 456PDF_circle(PDF *p, float x, float y, float r) 457{ 458 static const char fn[] = "PDF_circle"; 459 460 if (pdf_enter_api(p, fn, 461 (pdf_state) (pdf_state_content | pdf_state_path), 462 "(p[%p], %g, %g, %g)\n", (void *) p, x, y, r)) 463 { 464 pdf__circle(p, x, y, r); 465 } 466} 467 468PDFLIB_API void PDFLIB_CALL 469PDF_closepath(PDF *p) 470{ 471 static const char fn[] = "PDF_closepath"; 472 473 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 474 { 475 pdf__closepath(p); 476 } 477} 478 479PDFLIB_API void PDFLIB_CALL 480PDF_endpath(PDF *p) 481{ 482 static const char fn[] = "PDF_endpath"; 483 484 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 485 { 486 pdf__endpath(p); 487 } 488} 489 490PDFLIB_API void PDFLIB_CALL 491PDF_stroke(PDF *p) 492{ 493 static const char fn[] = "PDF_stroke"; 494 495 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 496 { 497 pdf__stroke(p); 498 } 499} 500 501PDFLIB_API void PDFLIB_CALL 502PDF_closepath_stroke(PDF *p) 503{ 504 static const char fn[] = "PDF_closepath_stroke"; 505 506 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 507 { 508 pdf__closepath_stroke(p); 509 } 510} 511 512PDFLIB_API void PDFLIB_CALL 513PDF_fill(PDF *p) 514{ 515 static const char fn[] = "PDF_fill"; 516 517 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 518 { 519 pdf__fill(p); 520 } 521} 522 523PDFLIB_API void PDFLIB_CALL 524PDF_fill_stroke(PDF *p) 525{ 526 static const char fn[] = "PDF_fill_stroke"; 527 528 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 529 { 530 pdf__fill_stroke(p); 531 } 532} 533 534PDFLIB_API void PDFLIB_CALL 535PDF_closepath_fill_stroke(PDF *p) 536{ 537 static const char fn[] = "PDF_closepath_fill_stroke"; 538 539 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 540 { 541 pdf__closepath_fill_stroke(p); 542 } 543} 544 545PDFLIB_API void PDFLIB_CALL 546PDF_clip(PDF *p) 547{ 548 static const char fn[] = "PDF_clip"; 549 550 if (pdf_enter_api(p, fn, pdf_state_path, "(p[%p])\n", (void *) p)) 551 { 552 pdf__clip(p); 553 } 554} 555