1/* GNUPLOT - context.trm */ 2 3/*[ 4 * Copyright (c) 2006-2011, Mojca Miklavec 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * - Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27]*/ 28 29/* 30 * AUTHORS: 31 * Mojca Miklavec 32 * <mojca.miklavec.lists at gmail.com> 33 * - author of this file 34 * - improvements to m-gnuplot.tex 35 * - mp-gnuplot.mp - metapost macros to support gnuplot-specifics 36 * inside ConTeXt 37 * 38 * Hans Hagen (author of ConTeXt) 39 * <pragma at wxs.nl> 40 * - a lot of functionality added to ConTeXt to enable better support 41 * of Gnuplot module, many bugs fixed 42 * - author of the module m-gnuplot.tex to support inclusion of Gnuplot 43 * graphics into ConTeXt 44 * - constant support on the most tricky issues 45 * Taco Hoekwater (developer of MetaPost, pdfTeX & LuaTeX) 46 * <taco at elvenkind.com> 47 * - some code of this file, many tricks, lots of bug fixes, 48 * suggestions and testing 49 * - Hans's right hand in ConTeXt development: 50 * constant support on even more tricky issues 51 * 52 * For questions, suggestions, comments, improvements please contact: 53 * - Mojca Miklavec <mojca.miklavec.lists at gmail.com> or 54 * - <gnuplot-context at googlegroups.com> 55 * - http://wiki.contextgarden.net/Gnuplot 56 * 57 * With special thanks to: 58 * - Peter Münster (ctx) for the initiative 59 * - Renaud Aubin (ctx) for maintaining the first source code repository 60 * - Aditya Mahajan (ctx) for some tricky parts in m-gnuplot.tex 61 * - Timothée Lecomte & Ethan A Merritt (gnuplot) for many suggestion about improving this terminal 62 * - Bastian Märkisch (gnuplot) for code improvements 63 * 64 */ 65 66/* 67 * GNUPLOT -- context.trm 68 * 69 * This driver creates a ConTeXt document with embded metapost (metafun) 70 * commands and is consequently used for creation of PDF documents. 71 * 72 * It is in a way similar to pslatex, but specialized for ConTeXt, 73 * where it can also be used in the following way: 74 * 75 * \usemodule[gnuplot] 76 * 77 * \starttext 78 * \title{Drawing nice graphs with \sc gnuplot} 79 * \startGNUPLOTscript{sin} 80 * plot sin(x) t '$\sin(x)$' 81 * \stopGNUPLOTscript 82 * \useGNUPLOTgraphic[sin] 83 * \stoptext 84 * 85 * For more information see http://wiki.contextgarden.net/Gnuplot 86 * 87 * Mostly based on: 88 * - default settings copied from LaTeX terminal (because I liked it) 89 * - path construction & drawing routines from MetaPost terminal 90 * - advanced functionality with reference to PostScript terminal 91 * 92 * Future plans: 93 * - most important 94 * - different syntax for font switching 95 * - improve support for (transparent) binary images 96 * - add missing functionality: 97 * - improved support for palettes 98 * - smooth shading in color bars 99 * - gouraud shading (if it will be implemented in gnuplot) 100 * - other color spaces 101 * - derive a better metapost terminal out of this one (to replace the old one) 102 */ 103 104#include "driver.h" 105#include "pm3d.h" 106 107#ifdef TERM_REGISTER 108register_term(context) 109#endif 110 111#ifdef TERM_PROTO 112TERM_PUBLIC void CONTEXT_options(void); 113TERM_PUBLIC void CONTEXT_init(void); 114TERM_PUBLIC void CONTEXT_reset(void); 115TERM_PUBLIC void CONTEXT_text(void); 116TERM_PUBLIC void CONTEXT_graphics(void); 117TERM_PUBLIC void CONTEXT_move(unsigned int x, unsigned int y); 118TERM_PUBLIC void CONTEXT_vector(unsigned int x, unsigned int y); 119TERM_PUBLIC void CONTEXT_linetype(int lt); 120TERM_PUBLIC void CONTEXT_put_text(unsigned int x, unsigned int y, const char *str); 121 122TERM_PUBLIC int CONTEXT_text_angle(int ang); 123TERM_PUBLIC int CONTEXT_justify_text(enum JUSTIFY mode); 124TERM_PUBLIC void CONTEXT_point(unsigned int x, unsigned int y, int number); 125TERM_PUBLIC void CONTEXT_arrow(unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head); 126TERM_PUBLIC int CONTEXT_set_font(const char *font); /* "font,size" */ 127TERM_PUBLIC void CONTEXT_pointsize(double pointsize); 128TERM_PUBLIC void CONTEXT_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height); /* clear part of multiplot */ 129TERM_PUBLIC void CONTEXT_fill(int style); 130TERM_PUBLIC void CONTEXT_linewidth(double linewidth); 131TERM_PUBLIC int CONTEXT_make_palette(t_sm_palette *palette); 132/* TERM_PUBLIC void CONTEXT_previous_palette(void); do we need it? */ 133TERM_PUBLIC void CONTEXT_set_color(t_colorspec *colorspec); 134TERM_PUBLIC void CONTEXT_filled_polygon(int points, gpiPoint *corners); 135TERM_PUBLIC void CONTEXT_image(unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor); 136 137/* Metapost < 1.750 can only deal with numbers between 2^{-16} and 2^12=4069 */ 138/* scale is 1cm = 1000 units */ 139 140#define CONTEXT_DPCM 1000 141#define CONTEXT_DPI (2.54 * CONTEXT_DPCM) 142/* default plot size will be 5in x 3in */ 143#define CONTEXT_XSIZE_VALUE 5 144#define CONTEXT_YSIZE_VALUE 3 145#define CONTEXT_SIZE_UNIT INCHES 146#define CONTEXT_XMAX (CONTEXT_XSIZE_VALUE * CONTEXT_DPI) 147#define CONTEXT_YMAX (CONTEXT_YSIZE_VALUE * CONTEXT_DPI) 148/* default fontsize: 12pt */ 149#define CONTEXT_FONTSIZE 12.0 150/* default height of char: 12pt by default */ 151#define CONTEXT_VCHAR (CONTEXT_DPI * CONTEXT_FONTSIZE / 72.27) 152/* in ConTeXt 12pt LM font is the default; 153 * at that size digits are 5.8749847pt wide 154 * in LaTeX, which assumes 11pt, the ratio is 5.3/11, which is similar */ 155#define CONTEXT_LM_H_TO_V_RATIO 0.4895 156#define CONTEXT_HCHAR (CONTEXT_LM_H_TO_V_RATIO * CONTEXT_VCHAR) 157/* default tic size: 3.5bp (chosen to suit the size of plot approximately) 158 * - in LaTeX it is 5bp 159 * - in TikZ it is 0.18cm (approximately 5.1bp) 160 * - in PostScript it is 3.15pt 161 * - MetaPost uses 5pt or 5bp 162 */ 163#define CONTEXT_HTIC (3.5 * CONTEXT_DPI / 72) 164#define CONTEXT_VTIC CONTEXT_HTIC 165 166#endif /* TERM_PROTO */ 167 168 169#ifndef TERM_PROTO_ONLY 170#ifdef TERM_BODY 171 172/* 173 * started counting when the code was included into CVS 174 * 175 * major number should change only in case of a complete rewrite or major incompatibility 176 * minor number should change for every new functionality 177 * patch number & date should change in every commit 178 */ 179static const char CONTEXT_term_version[] = "1.0"; 180static const char CONTEXT_term_patch[] = "0"; 181static const char CONTEXT_term_date[] = "2011-11-05"; 182 183static void CONTEXT_params_reset(void); 184 185static void CONTEXT_adjust_dimensions(void); 186static void CONTEXT_fontstring_parse(char *from_string, char *to_string, int to_size, double *fontsize); 187 188static void CONTEXT_startpath(void); 189static void CONTEXT_endpath(void); 190 191static void CONTEXT_write_palette(t_sm_palette *palette); 192static void CONTEXT_write_palette_gradient(gradient_struct *gradient, int cnt); 193 194/* Each number is divided by 100 (1/100th of a point is drawn) */ 195 196static int CONTEXT_posx; 197static int CONTEXT_posy; 198/* remembers where we started the path: 199 * if we finish it in the same point, the path is closed with --cycle 200 * 201 * After I implemented this, the functionality has been added to gnuplot core 202 * and PostScript terminal uses it, but to be on the safe side, 203 * I prefer not to add last-minute patches which could potentially break something. 204 * (the code written here proved to be rather safe & working so far) 205 * In the next version the core functionality should be integrated & tested. 206 */ 207static int CONTEXT_path_start_x; 208static int CONTEXT_path_start_y; 209/* fontname, fontsize */ 210static char CONTEXT_font[MAX_ID_LEN+1] = ""; 211static double CONTEXT_fontsize = CONTEXT_FONTSIZE; 212 213/* fontname,fontsize to be put next to font labels if needed */ 214static char CONTEXT_font_explicit[2*MAX_ID_LEN+1] = ""; 215/* this is only set to >0 if asked for explicitly (for example with set_font(",15")) */ 216static double CONTEXT_fontsize_explicit = 0.0; 217 218/* the last pointsize used (it will only be changed if it becomes different) */ 219static double CONTEXT_old_pointsize = 1.0; 220/* the last linewidth used (it will only be changed if it becomes different) */ 221static double CONTEXT_old_linewidth = 1.0; 222/* the last linetype used (it will only be changed if it becomes different) */ 223static int CONTEXT_old_linetype = -3; 224/* was the color changed explicitly? */ 225static TBOOLEAN CONTEXT_color_changed = FALSE; 226 227/* the number of path nodes before a newline (doesn't really matter, 228 * could be set to 1000; check if any editors have problems with that) */ 229#define CONTEXT_LINEMAX 4 230 231/* if we're inside a path (unfinished line) then path_count > 0 232 * (PDF has PDF_pathIsOpen) */ 233static unsigned int CONTEXT_path_count = 0; 234/* this true/false switch is used to help distinguish dots from paths */ 235static unsigned int CONTEXT_path_is_dot = 0; 236 237/* angle of text rotation */ 238static int CONTEXT_ang = 0; 239/* left/middle/right text justification */ 240static enum JUSTIFY CONTEXT_justify = LEFT; 241 242#ifdef OS2 /* same constants are defined in os2emx.h */ 243enum LINEJOIN { LINEJOIN_MITER=LINEJOIN_MITRE, _LINEJOIN_ROUND=LINEJOIN_ROUND, _LINEJOIN_BEVEL=LINEJOIN_BEVEL }; 244#else 245enum LINEJOIN { LINEJOIN_MITER, LINEJOIN_ROUND, LINEJOIN_BEVEL }; 246#endif 247enum LINECAP { LINECAP_BUTT, LINECAP_ROUND, LINECAP_SQUARE }; 248 249/* whether points are drawn with metapost or typeset with TeX (easy configurable) */ 250enum CONTEXT_POINTS { CONTEXT_POINTS_WITH_METAPOST, CONTEXT_POINTS_WITH_TEX }; 251/* whether images are inline or written out as PNGs and included (in MKII only external work) */ 252enum CONTEXT_IMAGES { CONTEXT_IMAGES_INLINE, CONTEXT_IMAGES_EXTERNAL }; 253 254/* counts the number of graphics */ 255static int CONTEXT_counter = 0; 256/* counts the number of external PNG images */ 257static int CONTEXT_image_counter = 0; 258/* length of basename for storing image name (including path, excluding extension) */ 259static int CONTEXT_image_filename_length = 0; 260/* if name is a path, remember at which index basename starts */ 261static int CONTEXT_image_filename_start = 0; 262static char *CONTEXT_image_filename = NULL; 263/* whether images will be external or not */ 264enum CONTEXT_IMAGES CONTEXT_images = CONTEXT_IMAGES_INLINE; 265 266/* Palette has to be stored for the usage in later plots */ 267static t_sm_palette *CONTEXT_old_palette; 268 269/*********************/ 270/* global parameters */ 271/*********************/ 272 273typedef struct CONTEXT_params_t { 274 double xsize; /* 5in */ 275 double ysize; /* 3in */ 276 size_units unit; /* INCHES */ 277 TBOOLEAN standalone; /* false */ 278 TBOOLEAN timestamp; /* true */ 279 char *header; /* "" */ 280 TBOOLEAN color; /* true */ 281 TBOOLEAN dashed; /* true */ 282 enum LINEJOIN linejoin; /* MITER */ 283 enum LINECAP linecap; /* BUTT */ 284 double scale_dashlength; /* 1.0 */ 285 double scale_linewidth; /* 1.0 */ 286 double scale_text; /* 1.0 */ 287 enum CONTEXT_POINTS points; /* CONTEXT_POINTS_WITH_METAPOST */ 288 enum CONTEXT_IMAGES images; /* CONTEXT_IMAGES_INLINE */ 289 char font[MAX_ID_LEN+1]; /* "" */ 290 double fontsize; /* 12pt */ 291} CONTEXT_params_t; 292 293 294#define CONTEXT_PARAMS_DEFAULT { \ 295 CONTEXT_XSIZE_VALUE,\ 296 CONTEXT_YSIZE_VALUE,\ 297 INCHES,\ 298 FALSE,\ 299 TRUE,\ 300 NULL,\ 301 TRUE,\ 302 TRUE,\ 303 LINEJOIN_MITER,\ 304 LINECAP_BUTT,\ 305 1.0,\ 306 1.0,\ 307 1.0,\ 308 CONTEXT_POINTS_WITH_METAPOST,\ 309 CONTEXT_IMAGES_INLINE,\ 310 "",\ 311 CONTEXT_FONTSIZE\ 312} 313 314static CONTEXT_params_t CONTEXT_params = CONTEXT_PARAMS_DEFAULT; 315 316enum CONTEXT_id { 317 CONTEXT_OPT_DEFAULT, 318 CONTEXT_OPT_SIZE, 319 CONTEXT_OPT_SIZE_DEFAULT, 320 CONTEXT_OPT_INPUT, CONTEXT_OPT_STANDALONE, 321 CONTEXT_OPT_TIMESTAMP, CONTEXT_OPT_NOTIMESTAMP, 322 CONTEXT_OPT_HEADER, CONTEXT_OPT_NOHEADER, 323 CONTEXT_OPT_COLOR, CONTEXT_OPT_MONOCHROME, 324 CONTEXT_OPT_DASHED, CONTEXT_OPT_SOLID, 325 CONTEXT_OPT_LINEJOIN_MITERED, CONTEXT_OPT_LINEJOIN_ROUNDED, CONTEXT_OPT_LINEJOIN_BEVELED, 326 CONTEXT_OPT_LINECAP_BUTT, CONTEXT_OPT_LINECAP_ROUNDED, CONTEXT_OPT_LINECAP_SQUARED, 327 CONTEXT_OPT_SCALE_DASHLENGTH, CONTEXT_OPT_SCALE_LINEWIDTH, CONTEXT_OPT_SCALE_TEXT, 328 CONTEXT_OPT_POINTS_WITH_METAPOST, CONTEXT_OPT_POINTS_WITH_TEX, 329 CONTEXT_OPT_IMAGES_INLINE, CONTEXT_OPT_IMAGES_EXTERNAL, 330 CONTEXT_OPT_DEFAULTFONT, 331 CONTEXT_OPT_FONT, 332 CONTEXT_OPT_OTHER 333}; 334static struct gen_table CONTEXT_opts[] = { 335 { "d$efault", CONTEXT_OPT_DEFAULT }, 336 { "size", CONTEXT_OPT_SIZE }, 337 { "defaultsize", CONTEXT_OPT_SIZE_DEFAULT }, 338 { "inp$ut", CONTEXT_OPT_INPUT }, 339 { "stand$alone", CONTEXT_OPT_STANDALONE }, 340 { "time$stamp", CONTEXT_OPT_TIMESTAMP }, 341 { "notime$stamp", CONTEXT_OPT_NOTIMESTAMP }, 342 { "header", CONTEXT_OPT_HEADER }, 343 { "noheader", CONTEXT_OPT_NOHEADER }, 344 { "col$or", CONTEXT_OPT_COLOR }, 345 { "col$our", CONTEXT_OPT_COLOR }, 346 { "mono$chrome", CONTEXT_OPT_MONOCHROME }, 347 { "da$shed", CONTEXT_OPT_DASHED }, 348 { "so$lid", CONTEXT_OPT_SOLID }, 349 { "miter$ed", CONTEXT_OPT_LINEJOIN_MITERED }, 350 { "rounded", CONTEXT_OPT_LINEJOIN_ROUNDED }, 351 { "bevel$ed", CONTEXT_OPT_LINEJOIN_BEVELED }, 352 { "butt", CONTEXT_OPT_LINECAP_BUTT }, 353 { "round", CONTEXT_OPT_LINECAP_ROUNDED }, 354 { "square$d", CONTEXT_OPT_LINECAP_SQUARED }, 355 { "dashl$ength", CONTEXT_OPT_SCALE_DASHLENGTH }, 356 { "dl", CONTEXT_OPT_SCALE_DASHLENGTH }, 357 { "linew$idth", CONTEXT_OPT_SCALE_LINEWIDTH }, 358 { "lw", CONTEXT_OPT_SCALE_LINEWIDTH }, 359 { "fontscale", CONTEXT_OPT_SCALE_TEXT }, 360 { "textscale", CONTEXT_OPT_SCALE_TEXT }, /* backward compatibility */ 361 { "mp$points", CONTEXT_OPT_POINTS_WITH_METAPOST}, 362 { "tex$points", CONTEXT_OPT_POINTS_WITH_TEX}, 363 { "pointswithmp", CONTEXT_OPT_POINTS_WITH_METAPOST}, /* (removable) backward compatibility */ 364 { "pointswithmetapost", CONTEXT_OPT_POINTS_WITH_METAPOST}, /* (removable) backward compatibility */ 365 { "pointswithtex", CONTEXT_OPT_POINTS_WITH_TEX}, /* (removable) backward compatibility */ 366 { "inline$images", CONTEXT_OPT_IMAGES_INLINE}, 367 { "external$images", CONTEXT_OPT_IMAGES_EXTERNAL}, 368 { "font", CONTEXT_OPT_FONT }, 369 { "defaultfont", CONTEXT_OPT_DEFAULTFONT }, 370 { NULL, CONTEXT_OPT_OTHER } 371}; 372 373/* ********************** 374 * CONTEXT_params_reset * 375 * ********************** 376 * 377 * Resets all parameters of the terminal to their default value. 378 */ 379static void 380CONTEXT_params_reset() 381{ 382 static const CONTEXT_params_t CONTEXT_params_default = CONTEXT_PARAMS_DEFAULT; 383 384 /* free the memory with header first */ 385 if (CONTEXT_params.header) { 386 free(CONTEXT_params.header); 387 CONTEXT_params.header = NULL; 388 } 389 390 memcpy(&CONTEXT_params, &CONTEXT_params_default, sizeof(CONTEXT_params_t)); 391} 392 393 394/* ***************** 395 * CONTEXT_options * 396 * ***************** 397 * 398 * Parses "set term context [options]". 399 */ 400TERM_PUBLIC void 401CONTEXT_options() 402{ 403 struct value a; 404 char *tmp_string; 405 char tmp_term_options[MAX_LINE_LEN+1] = ""; 406 407 while (!END_OF_COMMAND) { 408 switch (lookup_table(&CONTEXT_opts[0], c_token)) { 409 case CONTEXT_OPT_DEFAULT: 410 c_token++; 411 /* there should be a better way to do it, but I don't know how */ 412 CONTEXT_params_reset(); 413 break; 414 case CONTEXT_OPT_SIZE: { 415 float xmax_t, ymax_t; 416 size_units unit; 417 c_token++; 418 419 /* size <xsize> {cm|in}, <ysize> {cm|in} */ 420 unit = parse_term_size(&xmax_t, &ymax_t, CM); 421 CONTEXT_params.xsize = (double)xmax_t / gp_resolution; 422 CONTEXT_params.ysize = (double)ymax_t / gp_resolution; 423 CONTEXT_params.unit = unit; 424 if (unit == CM) { 425 CONTEXT_params.xsize *= 2.54; 426 CONTEXT_params.ysize *= 2.54; 427 } 428 break; 429 } 430 case CONTEXT_OPT_SIZE_DEFAULT: 431 c_token++; 432 CONTEXT_params.xsize = CONTEXT_XSIZE_VALUE; 433 CONTEXT_params.ysize = CONTEXT_YSIZE_VALUE; 434 CONTEXT_params.unit = CONTEXT_SIZE_UNIT; 435 break; 436 case CONTEXT_OPT_INPUT: 437 c_token++; 438 CONTEXT_params.standalone = FALSE; 439 break; 440 case CONTEXT_OPT_STANDALONE: 441 c_token++; 442 CONTEXT_params.standalone = TRUE; 443 break; 444 case CONTEXT_OPT_TIMESTAMP: 445 c_token++; 446 CONTEXT_params.timestamp = TRUE; 447 break; 448 case CONTEXT_OPT_NOTIMESTAMP: 449 c_token++; 450 CONTEXT_params.timestamp = FALSE; 451 break; 452 453 case CONTEXT_OPT_HEADER: 454 c_token++; 455 /* parse the string */ 456 tmp_string = try_to_get_string(); 457 if (!tmp_string) { 458 int_error(c_token,"String containing header information expected"); 459 /* only touch the options if the string is OK */ 460 } else { 461 /* remove the old header if any */ 462 if (CONTEXT_params.header) { 463 free(CONTEXT_params.header); 464 CONTEXT_params.header = NULL; 465 } 466 /* and set the new one if nonempty; 467 * empty header will be treated as 'noheader' */ 468 if (strlen(tmp_string) > 0) { 469 CONTEXT_params.header = tmp_string; 470 } else { 471 free(tmp_string); 472 } 473 } 474 break; 475 case CONTEXT_OPT_NOHEADER: 476 c_token++; 477 /* delete the header if it exists */ 478 if (CONTEXT_params.header) { 479 free(CONTEXT_params.header); 480 CONTEXT_params.header = NULL; 481 } 482 break; 483 case CONTEXT_OPT_COLOR: 484 c_token++; 485 CONTEXT_params.color = TRUE; 486 /* just mimic other terminals; no idea what it does; 487 at the moment monochrome is not fully implemented either */ 488 term->flags &= ~TERM_MONOCHROME; 489 break; 490 case CONTEXT_OPT_MONOCHROME: 491 c_token++; 492 CONTEXT_params.color = FALSE; 493 term->flags |= TERM_MONOCHROME; 494 break; 495 case CONTEXT_OPT_DASHED: 496 c_token++; 497 CONTEXT_params.dashed = TRUE; 498 break; 499 case CONTEXT_OPT_SOLID: 500 c_token++; 501 CONTEXT_params.dashed = FALSE; 502 break; 503 case CONTEXT_OPT_LINEJOIN_MITERED: 504 c_token++; 505 CONTEXT_params.linejoin = LINEJOIN_MITER; 506 break; 507 case CONTEXT_OPT_LINEJOIN_ROUNDED: 508 c_token++; 509 CONTEXT_params.linejoin = LINEJOIN_ROUND; 510 break; 511 case CONTEXT_OPT_LINEJOIN_BEVELED: 512 c_token++; 513 CONTEXT_params.linejoin = LINEJOIN_BEVEL; 514 break; 515 case CONTEXT_OPT_LINECAP_BUTT: 516 c_token++; 517 CONTEXT_params.linecap = LINECAP_BUTT; 518 break; 519 case CONTEXT_OPT_LINECAP_ROUNDED: 520 c_token++; 521 CONTEXT_params.linecap = LINECAP_ROUND; 522 break; 523 case CONTEXT_OPT_LINECAP_SQUARED: 524 c_token++; 525 CONTEXT_params.linecap = LINECAP_SQUARE; 526 break; 527 case CONTEXT_OPT_SCALE_DASHLENGTH: 528 c_token++; 529 CONTEXT_params.scale_dashlength = real(const_express(&a)); 530 break; 531 case CONTEXT_OPT_SCALE_LINEWIDTH: 532 c_token++; 533 CONTEXT_params.scale_linewidth = real(const_express(&a)); 534 break; 535 case CONTEXT_OPT_SCALE_TEXT: 536 c_token++; 537 CONTEXT_params.scale_text = real(const_express(&a)); 538 break; 539 case CONTEXT_OPT_DEFAULTFONT: 540 c_token++; 541 /* CONTEXT_params.font should be an empty string */ 542 CONTEXT_params.font[0] = 0; 543 /* default fontsize is 12pt */ 544 CONTEXT_params.fontsize = CONTEXT_FONTSIZE; 545 break; 546 case CONTEXT_OPT_POINTS_WITH_METAPOST: 547 c_token++; 548 CONTEXT_params.points = CONTEXT_POINTS_WITH_METAPOST; 549 break; 550 case CONTEXT_OPT_POINTS_WITH_TEX: 551 c_token++; 552 CONTEXT_params.points = CONTEXT_POINTS_WITH_TEX; 553 break; 554 case CONTEXT_OPT_IMAGES_INLINE: 555 c_token++; 556 CONTEXT_params.images = CONTEXT_IMAGES_INLINE; 557 break; 558 case CONTEXT_OPT_IMAGES_EXTERNAL: 559#ifdef WRITE_PNG_IMAGE 560 c_token++; 561 CONTEXT_params.images = CONTEXT_IMAGES_EXTERNAL; 562#else 563 int_warn(c_token, "Gnuplot was built without support for PNG images. You cannot use this option unless you rebuild gnuplot."); 564#endif 565 break; 566 /* 567 * The preferred way to set the font is to set it in a document itself, 568 * labels in gnuplot in graphs will then inherit that font. 569 * 570 * However, it is important to tell gnuplot which size is going to be used, 571 * so that it can estimate size of text labels. 572 * 573 * Whenever you specify 574 * set term context font "fontname,14" 575 * 576 * there are two possibilities: 577 * - if STANDALONE mode is on, then the whole string will be used as 578 * \setupbodyfont[fontname,14pt] 579 * somewhere on top of the document (you still have to make sure that you 580 * included the proper typescript, so that "fontname" will be recognised 581 * - in the other case (INPUT mode) only the font size will be used 582 * internally to estimate sizes of labels, but the font name 583 * won't be written anywhere 584 */ 585 case CONTEXT_OPT_FONT: { 586 double tmp_fontsize; 587 char tmp_font[MAX_ID_LEN+1] = ""; 588 c_token++; 589 if ((tmp_string = try_to_get_string()) && (tmp_string != NULL)) { 590 CONTEXT_fontstring_parse(tmp_string, tmp_font, MAX_ID_LEN+1, &tmp_fontsize); 591 /* copies font name to parameters */ 592 safe_strncpy(CONTEXT_params.font, tmp_font, sizeof(CONTEXT_params.font)); 593 tmp_font[MAX_ID_LEN] = NUL; 594 free(tmp_string); 595 /* save font size: 596 * 597 * - if size > 0, copy 598 * - if size < 0, fix the size to default value (12pt) 599 * - if size = 0, ignore 600 */ 601 if (tmp_fontsize > 0) 602 CONTEXT_params.fontsize = tmp_fontsize; 603 else if (tmp_fontsize < 0) 604 CONTEXT_params.fontsize = CONTEXT_FONTSIZE; 605 } 606 break; 607 } 608 case CONTEXT_OPT_OTHER: 609 default: 610 /* error */ 611 int_error(c_token, "extraneous argument in set terminal %s",term->name); 612 break; 613 } 614 } 615 616 /* current font size in pt (to be used in CONTEXT_adjust_dimensions) */ 617 CONTEXT_fontsize = CONTEXT_params.fontsize; 618 619 /* sets term->xmax, ymax, vchar, hchar */ 620 CONTEXT_adjust_dimensions(); 621 622 snprintf(term_options, sizeof(term_options), 623 "size %g%s,%g%s %s %s %s", 624 CONTEXT_params.xsize, 625 (CONTEXT_params.unit == INCHES) ? "in" : "cm", 626 CONTEXT_params.ysize, 627 (CONTEXT_params.unit == INCHES) ? "in" : "cm", 628 CONTEXT_params.standalone ? "standalone" : "input", 629 CONTEXT_params.timestamp ? "timestamp" : "notimestamp", 630 CONTEXT_params.header == NULL ? "noheader \\\n " : "\\\n header "); 631 632 if (CONTEXT_params.header != NULL) { 633 strncat(term_options,"\"", sizeof(term_options)-strlen(term_options)-1); 634 strncat(term_options,CONTEXT_params.header, sizeof(term_options)-strlen(term_options)-1); 635 strncat(term_options,"\" \\\n ", sizeof(term_options)-strlen(term_options)-1); 636 } 637 638 strncat(term_options, 639 CONTEXT_params.color ? "color " : "monochrome ", 640 sizeof(term_options)-strlen(term_options)-1); 641 642 switch (CONTEXT_params.linejoin) { 643 case LINEJOIN_MITER: 644 strncat(term_options, "mitered ", 645 sizeof(term_options)-strlen(term_options)-1); 646 break; 647 case LINEJOIN_ROUND: 648 strncat(term_options, "rounded ", 649 sizeof(term_options)-strlen(term_options)-1); 650 break; 651 case LINEJOIN_BEVEL: 652 strncat(term_options, "beveled ", 653 sizeof(term_options)-strlen(term_options)-1); 654 break; 655 } 656 switch (CONTEXT_params.linecap) { 657 case LINECAP_BUTT : 658 strncat(term_options, "butt", 659 sizeof(term_options)-strlen(term_options)-1); 660 break; 661 case LINECAP_ROUND : 662 strncat(term_options, "round", 663 sizeof(term_options)-strlen(term_options)-1); 664 break; 665 case LINECAP_SQUARE: 666 strncat(term_options, "squared", 667 sizeof(term_options)-strlen(term_options)-1); 668 break; 669 } 670 671 snprintf(tmp_term_options, sizeof(tmp_term_options), 672 " %s dashlength %g linewidth %g fontscale %g \\\n ", 673 CONTEXT_params.dashed ? "dashed" : "solid", 674 CONTEXT_params.scale_dashlength, 675 CONTEXT_params.scale_linewidth, 676 CONTEXT_params.scale_text 677 ); 678 strncat(term_options, tmp_term_options, sizeof(term_options)-strlen(term_options)-1); 679 680 switch (CONTEXT_params.points) { 681 case CONTEXT_POINTS_WITH_TEX : 682 strncat(term_options, "texpoints ", 683 sizeof(term_options)-strlen(term_options)-1); 684 break; 685 case CONTEXT_POINTS_WITH_METAPOST : 686 strncat(term_options, "mppoints ", 687 sizeof(term_options)-strlen(term_options)-1); 688 break; 689 } 690#ifdef WRITE_PNG_IMAGE 691 switch (CONTEXT_params.images) { 692 case CONTEXT_IMAGES_INLINE : 693 strncat(term_options, "inlineimages ", 694 sizeof(term_options)-strlen(term_options)-1); 695 break; 696 case CONTEXT_IMAGES_EXTERNAL : 697 strncat(term_options, "externalimages ", 698 sizeof(term_options)-strlen(term_options)-1); 699 break; 700 } 701#endif 702 snprintf(tmp_term_options, sizeof(tmp_term_options), "font \"%s,%g\"", 703 CONTEXT_params.font, CONTEXT_params.fontsize); 704 strncat(term_options, tmp_term_options, sizeof(term_options) - strlen(term_options)-1); 705} 706 707/* ************** 708 * CONTEXT_init * 709 * ************** 710 * 711 * Starts a new file. 712 * 713 * XXX: "set term context" multiple times will only include those graphics 714 * that were create before issuing a new "set term context options" 715 * this should be fixed in the core by reopening the file 716 * (removing previously written content). 717 * - PDF & binary terminals start a new file 718 * - PS & TeX-based terminals continue 719 */ 720TERM_PUBLIC void 721CONTEXT_init() 722{ 723 time_t now; 724 char timebuffer[100]; 725#ifdef WRITE_PNG_IMAGE 726 int i; 727#endif 728 729 time(&now); 730 731 CONTEXT_posx = CONTEXT_posy = 0; 732 CONTEXT_path_count = 0; 733 CONTEXT_path_is_dot = 0; 734 735 CONTEXT_counter = 0; 736 737 /* setup bitmap images */ 738 CONTEXT_image_counter = 0; 739 /* the default is to use inline images */ 740 CONTEXT_images = CONTEXT_IMAGES_INLINE; 741 742 /* only if external images are both requested and supported, we switch to them (double paranoia) */ 743 /* delete the stored filename first */ 744 if (CONTEXT_image_filename) { 745 free(CONTEXT_image_filename); 746 CONTEXT_image_filename = NULL; 747 CONTEXT_image_filename_length = 0; 748 CONTEXT_image_filename_start = 0; 749 }; 750#ifdef WRITE_PNG_IMAGE 751 if (CONTEXT_params.images == CONTEXT_IMAGES_EXTERNAL) { 752 CONTEXT_images = CONTEXT_IMAGES_EXTERNAL; 753 754 /* but only if 'set output' was set because we use that string as base for image names */ 755 if (outstr) { 756 CONTEXT_image_filename_length = strlen(outstr); 757 CONTEXT_image_filename_start = strlen(outstr) - strlen(gp_basename(outstr)); 758 /* we will cut off the last .tex ending if present */ 759 /* find the last dot if present */ 760 for (i = CONTEXT_image_filename_length - 1; i >= 0 && outstr[i] != '.'; i--); 761 if (outstr[i] == '.') 762 CONTEXT_image_filename_length = i; 763 /* it would also be very nice to do some sanity checks on filenames */ 764 765 /* <name>.xx.png; must be at least 7 characters long */ 766 CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename"); 767 strncpy(CONTEXT_image_filename, outstr, CONTEXT_image_filename_length); 768 CONTEXT_image_filename[CONTEXT_image_filename_length] = 0; 769 } else { 770 CONTEXT_image_filename_length = strlen("gp_image"); 771 CONTEXT_image_filename_start = 0; 772 /* <name>.xx.png; must be at least 7 characters long */ 773 CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename"); 774 strncpy(CONTEXT_image_filename, "gp_image", CONTEXT_image_filename_length); 775 CONTEXT_image_filename[CONTEXT_image_filename_length] = 0; 776 } 777 } 778#endif 779 780 fprintf(gpoutfile, "%% Written by ConTeXt terminal for GNUPLOT"); 781 if (CONTEXT_params.timestamp) { 782 if (strftime(timebuffer, 100, "%Y-%m-%d %H:%M %Z", localtime(&now)) != 0) 783 fprintf(gpoutfile, " on: %s", timebuffer); 784 } 785 fprintf(gpoutfile, "\n"); 786 fprintf(gpoutfile, "%% GNUPLOT version: %s.%s, terminal version: %s.%s (%s)\n", 787 gnuplot_version, gnuplot_patchlevel, CONTEXT_term_version, CONTEXT_term_patch, CONTEXT_term_date); 788 fprintf(gpoutfile, "%% See also http://wiki.contextgarden.net/Gnuplot\n%%\n"); 789 790 /* place the header first if this is a standalone graphic */ 791 if (CONTEXT_params.standalone) { 792 /* If encoding is explicitly set to UTF-8 by gnuplot, use that setting. 793 * \enableregime only makes a difference for pdfTeX; in LuaTeX and XeTeX UTF-8 is already default, 794 * so this line will be ignored. 795 * 796 * There is no extra support for other encodings on purpose: 797 * - ConTeXt doesn't support all encodings supported by Gnuplot. 798 * - In LuaTeX and XeTeX one should not use any other encoding anyway. 799 * - pdfTeX users are free to use "header '\enableregime[...]'" */ 800 switch (encoding) { 801 case S_ENC_UTF8: 802 fputs("\\enableregime\n [utf-8]\n", gpoutfile); 803 break; 804 default: 805 /* do nothing */ 806 break; 807 } 808 /* load the gnuplot module */ 809 fputs("\\usemodule\n [gnuplot]\n", gpoutfile); 810 /* enable or disable color (the only place where "color" is indeed used so far) */ 811 fprintf(gpoutfile, "\\setupcolors\n [state=%s]\n", CONTEXT_params.color ? "start" : "stop"); 812 /* additional user-provided header information (if available) */ 813 if (CONTEXT_params.header) 814 fprintf(gpoutfile, "%s\n", CONTEXT_params.header); 815 /* for some reason setting \bodyfontenvironment is needed, 816 * otherwise \switchtobodyfont[name] doesn't work OK */ 817 if (!(CONTEXT_params.fontsize == CONTEXT_FONTSIZE)) 818 fprintf(gpoutfile, "\\definebodyfontenvironment\n [%gpt]\n", 819 CONTEXT_params.fontsize); 820 /* set the proper font: \setupbodyfont[{fontname,}fontsize sizeunit] */ 821 fprintf(gpoutfile, "\\setupbodyfont\n [%s%s%gpt]\n", 822 CONTEXT_params.font, 823 /* write a comma only if the last string was non-empty */ 824 ((strlen(CONTEXT_params.font)>0) ? "," : ""), 825 CONTEXT_params.fontsize); 826 827 /*---------* 828 * options * 829 *---------*/ 830 fprintf(gpoutfile, "\\setupGNUPLOTterminal\n [context]\n ["); 831 832 /* color (gp_use_color): yes/no (true/false) 833 * default: yes 834 * - doesn't do anything useful yet; 835 * and besides that, it's already set in \setupcolors[state=start] */ 836 /* fprintf(gpoutfile, " color=%s, %% *yes* | no\n", CONTEXT_params.color ? "yes" : "no"); */ 837 838 /* linejoin: mitered/rounded/beveled 839 * default: mitered */ 840 fprintf(gpoutfile, "linejoin="); 841 switch (CONTEXT_params.linejoin) { 842 case LINEJOIN_MITER: fprintf(gpoutfile, "mitered"); break; 843 case LINEJOIN_ROUND: fprintf(gpoutfile, "rounded"); break; 844 case LINEJOIN_BEVEL: fprintf(gpoutfile, "beveled"); break; 845 } 846 fprintf(gpoutfile, ", %% *mitered* | rounded | beveled\n"); 847 848 /* linecap: butt/rounded/squared 849 * default: butt */ 850 fprintf(gpoutfile, " linecap="); 851 switch (CONTEXT_params.linecap) { 852 case LINECAP_BUTT : fprintf(gpoutfile, "butt"); break; 853 case LINECAP_ROUND : fprintf(gpoutfile, "rounded"); break; 854 case LINECAP_SQUARE: fprintf(gpoutfile, "squared"); break; 855 } 856 fprintf(gpoutfile, ", %% *butt* | rounded | squared\n"); 857 858 /* dashed (gp_use_dashed): yes/no (true/false) 859 * default: yes */ 860 fprintf(gpoutfile, " dashed=%s, %% *yes* | no\n", CONTEXT_params.dashed ? "yes" : "no"); 861 /* dashlength (gp_scale_dashlength): 1.0 */ 862 fprintf(gpoutfile, " dashlength=%g, %% scaling factor for dash lengths\n", CONTEXT_params.scale_dashlength); 863 864 /* linewidth (gp_scale_linewidth): 1.0 */ 865 fprintf(gpoutfile, " linewidth=%g, %% scaling factor for line widths (1.0 means 0.5bp)\n", CONTEXT_params.scale_linewidth); 866 867 /* fontscale (gp_scale_text): 1.0 */ 868 /* written out just for reference - it's commented out since it needs to be part of graphic 869 and affects estimation of label sizes */ 870 fprintf(gpoutfile, " %%fontscale=%g, %% scaling factor for text labels\n", CONTEXT_params.scale_text); 871 872 /* points (gp_points_with): metapost/tex (gp_points_with_metapost/gp_points_with_tex) 873 * default: metapost */ 874 fprintf(gpoutfile, " points=%s, %% *metapost* | tex (Should points be drawn with MetaPost or TeX?)\n", 875 CONTEXT_params.points == CONTEXT_POINTS_WITH_METAPOST ? "metapost" : "tex"); 876 877 /* images 878 * default: inline */ 879 fprintf(gpoutfile, " images=%s] %% *inline* | external (inline only works in MKIV, external requires png support in gnuplot)\n", 880 CONTEXT_images == CONTEXT_IMAGES_INLINE ? "inline" : "external"); 881 882 /*----------------* 883 * end of options * 884 *----------------*/ 885 886 fputs("\n\\starttext\n\n", gpoutfile); 887 } else { 888 /* Sorry, nothing! In non-standalone graphic, parameters make no sense. 889 * Setup everything in the file which includes such a graphic instead. 890 */ 891 } 892} 893 894/* *************** 895 * CONTEXT_reset * 896 * *************** 897 * 898 * finish writing the file 899 */ 900TERM_PUBLIC void 901CONTEXT_reset() 902{ 903 /* we only have to end the document if this is a stand-alone graphic */ 904 if (CONTEXT_params.standalone) { 905 fputs("\\stoptext\n", gpoutfile); 906 } else { 907 /* This means that any subsequent plots to the same file will be ignored. 908 * I don't like that - gnuplot should delete the old contents instead, 909 * just as it does in case of PNG or PDF - 910 * but it will be at least consistent with standalone graphics that way 911 */ 912 fputs("\\endinput\n", gpoutfile); 913 } 914 /* deallocate image name if present */ 915 if (CONTEXT_image_filename) { 916 free(CONTEXT_image_filename); 917 CONTEXT_image_filename = NULL; 918 CONTEXT_image_filename_length = 0; 919 CONTEXT_image_filename_start = 0; 920 }; 921} 922 923/* ************** 924 * CONTEXT_text * 925 * ************** 926 * 927 * Ends the current graphic. 928 */ 929TERM_PUBLIC void 930CONTEXT_text() 931{ 932 /* close and draw the current path first */ 933 if (CONTEXT_path_count > 0) 934 CONTEXT_endpath(); 935 936 fprintf(gpoutfile, "setbounds currentpicture to unitsquare xyscaled (w,h);\n"); 937 938 /* standalone graphic is a whole-page graphic */ 939 if (CONTEXT_params.standalone) { 940 fputs("\\stopGNUPLOTpage\n", gpoutfile); 941 /* otherwise we define a MPgraphic to be included later */ 942 } else { 943 fputs("\\stopGNUPLOTgraphic\n", gpoutfile); 944 } 945} 946 947/* ****************** 948 * CONTEXT_graphics * 949 * ****************** 950 * 951 * Starts a new graphic. 952 */ 953TERM_PUBLIC void 954CONTEXT_graphics() 955{ 956 /* standalone graphic is a whole-page graphic */ 957 if (CONTEXT_params.standalone) { 958 fprintf(gpoutfile, "\\startGNUPLOTpage %% Graphic Nr. %d\n", ++CONTEXT_counter); 959 /* otherwise we define a MPgraphic to be included later */ 960 } else { 961 /* the first parameter holds the graphic number */ 962 fprintf(gpoutfile, "\\startGNUPLOTgraphic[%d]\n", ++CONTEXT_counter); 963 } 964 965 fprintf(gpoutfile, "string gnuplotversion; gnuplotversion := \"%s\";\n", gnuplot_version); 966 fprintf(gpoutfile, "string termversion; termversion := \"%s\";\n", CONTEXT_term_version); 967 /* 968 * MetaPost can only handle numbers up to 4096. Too high resolution 969 * would thus result in number overflow, that's why we scale down all the 970 * integers from gnuplot by 1000 and multiply those numbers later by 971 * appropriate scaling factor 'a' to get the proper dimensions. 972 */ 973 fprintf(gpoutfile, "%% scaling factor, width and height of the figure\na := 1cm; w := %.3fa; h := %.3fa; %% (%g%s, %g%s)\n", 974 CONTEXT_params.xsize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */ 975 CONTEXT_params.ysize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */ 976 CONTEXT_params.xsize, (CONTEXT_params.unit == INCHES) ? "in" : "cm", 977 CONTEXT_params.ysize, (CONTEXT_params.unit == INCHES) ? "in" : "cm"); 978 /* TODO: the following if-else could be slightly nicer */ 979 if (CONTEXT_images == CONTEXT_IMAGES_INLINE) { 980 fprintf(gpoutfile, "%% temporary variable for storing the path and images\nsave p, img, ima; path p; string img, ima;\n"); 981 } else { 982 fprintf(gpoutfile, "%% temporary variable for storing the path\nsave p; path p;\n"); 983 } 984 fprintf(gpoutfile, "%% -------------------------\n"); 985 fprintf(gpoutfile, "%% Different initialisations\n"); 986 fprintf(gpoutfile, "%% -------------------------\n"); 987 fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_before;\n"); 988 /* needed (depends on terminal settings & needs to be passed) */ 989 fprintf(gpoutfile, "%% text scaling factor for the whole figure\n"); 990 fprintf(gpoutfile, "gp_scale_text := %g;\n", CONTEXT_params.scale_text); 991 fprintf(gpoutfile, "%% pointsize scaling factor\n"); 992 fprintf(gpoutfile, "gp_set_pointsize(%g);\n", CONTEXT_old_pointsize); 993 /* needed (provided by terminal) */ 994 fprintf(gpoutfile, "%% linewidth scaling factor for individual lines\n"); 995 fprintf(gpoutfile, "gp_set_linewidth(%g);\n", CONTEXT_old_linewidth); 996 fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_after;\n"); 997 fprintf(gpoutfile, "%% -------------------------\n"); 998 999 /* since palette is initialized only once, subsequent plots wouldn't see it 1000 * unless we write it on the top of relevant plots explicitly */ 1001 if (is_plot_with_palette()) { 1002 CONTEXT_write_palette(CONTEXT_old_palette); 1003 } 1004 1005 /* needed, otherwise the first linetype(-2) would be ignored */ 1006 CONTEXT_old_linetype = -3; 1007 /* different initializations - not really needed, but they cannot hurt */ 1008 CONTEXT_posx = CONTEXT_posy = 0; 1009 CONTEXT_path_count = 0; 1010 CONTEXT_path_is_dot = 0; 1011} 1012 1013/* --------------- 1014 * CONTEXT_endpath 1015 * --------------- 1016 * 1017 * Closes and strokes (draws) the current path. 1018 * 1019 * It the path ends where it started, it ends it with --cycle (we get cyclic path), 1020 * otherwise just with a semicolon. 1021 */ 1022static void 1023CONTEXT_endpath() 1024{ 1025 /* if we have a dot, draw only the dot */ 1026 if (CONTEXT_path_is_dot) { 1027 fprintf(gpoutfile, "gp_dot(%.3fa,%.3fa);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy); 1028 CONTEXT_path_is_dot = 0; 1029 1030 /* cyclic path, so let's end it with "--cycle" */ 1031 } else if ((CONTEXT_posx == CONTEXT_path_start_x) && (CONTEXT_posy == CONTEXT_path_start_y)) { 1032 fputs("--cycle;\ngp_draw(p);\n", gpoutfile); 1033 1034 /* regular non-cyclic path */ 1035 } else { 1036 fprintf(gpoutfile, "--(%.3fa,%.3fa);\ngp_draw(p);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy); 1037 } 1038 1039 /* we're not inside path any more */ 1040 CONTEXT_path_count = 0; 1041} 1042 1043/* ************** 1044 * CONTEXT_move * 1045 * ************** 1046 * 1047 * Remembers the new location for a path. 1048 * 1049 * If it doesn't differ from the current location, this is simply ignored. 1050 * If we're still in the middle of path construction and location differs, 1051 * it strokes the old path. 1052 * 1053 */ 1054TERM_PUBLIC void 1055CONTEXT_move(unsigned int x, unsigned int y) 1056{ 1057 /* we seem to be there already */ 1058 if ((x == CONTEXT_posx) && (y == CONTEXT_posy)) 1059 return; 1060 1061 /* close and draw the current path before the move */ 1062 if (CONTEXT_path_count > 0) 1063 CONTEXT_endpath(); 1064 1065 CONTEXT_posx = x; 1066 CONTEXT_posy = y; 1067} 1068 1069/* ----------------- 1070 * CONTEXT_startpath 1071 * ----------------- 1072 * 1073 * Starts ([but not yet] drawing) a new path. 1074 */ 1075static void 1076CONTEXT_startpath() 1077{ 1078 CONTEXT_path_start_x = CONTEXT_posx; 1079 CONTEXT_path_start_y = CONTEXT_posy; 1080 CONTEXT_path_count = 2; 1081 1082 fprintf(gpoutfile, "p := (%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy); 1083} 1084 1085/* **************** 1086 * CONTEXT_vector * 1087 * **************** 1088 * 1089 * Prolongs the current path for an additional line (from the last point to (x,y)) 1090 * unless it has a zero-length. 1091 * 1092 * Points have to be treated as a special case, since gnuplot sometimes tries 1093 * to draw them as moveto(a,b)--lineto(a,b) - without the proper linecap, 1094 * that wouldn't draw anything in MetaPost or PS. 1095 * (I hope that I got that part right, but I'm not completely sure.) 1096 */ 1097TERM_PUBLIC void 1098CONTEXT_vector(unsigned int x, unsigned int y) 1099{ 1100 /* this is zero-length line (or a dot) 1101 * 1102 * stupid background, has to handle 1103 * - move(0,0), vector(0,0), whatever: draw a dot 1104 * - move(0,0), vector(0,0), vector (1,1): draw a line 1105 */ 1106 if ((x == CONTEXT_posx) && (y==CONTEXT_posy)) { 1107 /* as long as this is still a dot candidate, mark it so 1108 * however - further vector() commands may set this back to 0 */ 1109 if (CONTEXT_path_count == 0) 1110 CONTEXT_path_is_dot = 1; 1111 /* if some path was already drawn up to this place, ignore (it's not a dot) */ 1112 return; 1113 } 1114 1115 /* start the path if none is started yet */ 1116 if (CONTEXT_path_count == 0) { 1117 /* the path is not a dot */ 1118 CONTEXT_path_is_dot = 0; 1119 CONTEXT_startpath(); 1120 } else { 1121 /* or prevent too long lines if you're in the middle of a path */ 1122 if ((CONTEXT_path_count % CONTEXT_LINEMAX) == 2) { 1123 fputs("\n ", gpoutfile); 1124 CONTEXT_path_count = 2; 1125 } 1126 /* and output the previous point */ 1127 fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy); 1128 } 1129 1130 CONTEXT_posx = x; 1131 CONTEXT_posy = y; 1132 CONTEXT_path_count++; 1133} 1134 1135/* ****************** 1136 * CONTEXT_linetype * 1137 * ****************** 1138 * 1139 * - If only color has been changed (recently), but not the linetype, 1140 * it resets only the color. 1141 * - If linetype was changed, it sets the new linetype 1142 */ 1143TERM_PUBLIC void 1144CONTEXT_linetype(int lt) 1145{ 1146 /* reset the color in case it has been changed in CONTEXT_set_color() */ 1147 if (CONTEXT_old_linetype != lt || CONTEXT_color_changed) { 1148 /* close and draw the current path first */ 1149 if (CONTEXT_path_count > 0) 1150 CONTEXT_endpath(); 1151 1152 fprintf(gpoutfile, "gp_set_linetype(%d);\n", lt); 1153 1154 CONTEXT_old_linetype = lt; 1155 CONTEXT_color_changed = FALSE; 1156 } 1157} 1158 1159/* ****************** 1160 * CONTEXT_put_text * 1161 * ****************** 1162 * 1163 * Places text labels. 1164 */ 1165TERM_PUBLIC void 1166CONTEXT_put_text(unsigned int x, unsigned int y, const char str[]) 1167{ 1168 const char *s; /* pointer to string */ 1169 int alignment = 0; 1170 char alignments[3][10] = {"center", "left", "right"}; 1171 1172 /* ignore empty strings */ 1173 if (!str || !strlen(str)) 1174 return; 1175 1176 /* close and draw the current path first */ 1177 if (CONTEXT_path_count > 0) 1178 CONTEXT_endpath(); 1179 1180 /* see the values of "alignments" above */ 1181 switch (CONTEXT_justify) { 1182 case CENTRE: 1183 alignment = 0; 1184 break; 1185 case LEFT: 1186 alignment = 1; 1187 break; 1188 case RIGHT: 1189 alignment = 2; 1190 break; 1191 } 1192 1193 /* remove whitespace at the beginning of string 1194 * (usually a problem in positive numbers) 1195 * They interfere with positioning: whitespace at the beginning takes 1196 * some place although it's invisible, so left-aligned and centered labels 1197 * are positioned incorrectly. 1198 * Example: 1199 * -1 0 1 2: centered labels on x axis 1200 * if we had a space in front, positive numbers would be "centered" in a weird way */ 1201 for (s = str; s[0] == ' '; s++); 1202 1203 /* label position */ 1204 fprintf(gpoutfile, "gp_put_text((%.3fa, %.3fa), ", 0.001*x, 0.001*y); 1205 /* angle of rotation - optional and needed only if it's different from 0 */ 1206 if (CONTEXT_ang != 0) 1207 fprintf(gpoutfile, "angle(%d), ", CONTEXT_ang); 1208 1209 /* alignment - "center" is optional, but we'll add it anyway */ 1210 fprintf(gpoutfile, "align(%s), \\sometxt[gp]", alignments[alignment]); 1211 /* fontface/fontsize - optional second argument */ 1212 if (CONTEXT_font_explicit[0] != 0) 1213 fprintf(gpoutfile, "[%s]", CONTEXT_font_explicit); 1214 /* finally the text label itself */ 1215 fprintf(gpoutfile, "{%s});\n", s); 1216} 1217 1218 1219/* ******************** 1220 * CONTEXT_text_angle * 1221 * ******************** 1222 * 1223 * Saves text angle to be used for text labels. 1224 */ 1225TERM_PUBLIC int 1226CONTEXT_text_angle(int ang) 1227{ 1228 CONTEXT_ang = ang; 1229 return TRUE; 1230} 1231 1232/* ********************** 1233 * CONTEXT_justify_text * 1234 * ********************** 1235 * 1236 * Saves horizontal text justification (left/middle/right) to be used for text labels. 1237 */ 1238TERM_PUBLIC int 1239CONTEXT_justify_text(enum JUSTIFY mode) 1240{ 1241 CONTEXT_justify = mode; 1242 return TRUE; 1243} 1244 1245/* *************** 1246 * CONTEXT_point * 1247 * *************** 1248 * 1249 * There are two/three possible ways of drawing points in ConTeXt: 1250 * - let gnuplot draw the points with standard move/vector commands 1251 * (points_default): not enabled 1252 * - use the points predefined in mp-gnuplot.mp (drawn with metapost) 1253 * which can easily be redefined 1254 * (points_with_metapost) 1255 * - use symbols from a symbol set predefined in m-gnuplot.tex (drawn with TeX) 1256 * (points_with_tex) 1257 * 1258 * At first this routine took care of that, but now it's up to the high-level 1259 * user interface to switch between the last two options. 1260 */ 1261TERM_PUBLIC void 1262CONTEXT_point (unsigned int x, unsigned int y, int number) 1263{ 1264 /* finish the current line first before the move */ 1265 if (CONTEXT_path_count > 0) 1266 CONTEXT_endpath(); 1267 1268 fprintf(gpoutfile, "gp_point(%.3fa,%.3fa,%d);\n", 0.001*x, 0.001*y, number); 1269} 1270 1271/* *************** 1272 * CONTEXT_arrow * 1273 * *************** 1274 * ConTeXt could draw nice arrows on its own and in such a way that user could 1275 * simply redefine arrow heads in the template file. 1276 * 1277 * This function is left here just in case that anyoune would find it useful 1278 * to define his own arrow-drawing commands. 1279 * 1280 * Currently it just calls the default gnuplot function for drawing arrows. 1281 */ 1282TERM_PUBLIC void 1283CONTEXT_arrow (unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head) 1284{ 1285 do_arrow(sx, sy, ex, ey, head); 1286} 1287 1288 1289/* ------------------------ 1290 * CONTEXT_fontstring_parse 1291 * ------------------------ 1292 * 1293 * Parses from_string, which is divided by commas (,) 1294 * and copies the whole content to to_string except for the part 1295 * which starts with a numeric value. 1296 * 1297 * That value is interpreted separately and saved to fontsize. 1298 * 1299 * to_size is the size of to_string which may not be exceeded while copying the string 1300 */ 1301static void 1302CONTEXT_fontstring_parse(char *from_string, char *to_string, int to_size, double *fontsize) 1303{ 1304 double tmp_fontsize = 0.; 1305 char * comma; 1306 size_t n; 1307 1308 comma = strrchr(from_string, ','); 1309 if (comma) { 1310 sscanf(comma + 1, "%lf", &tmp_fontsize); 1311 n = comma - from_string; 1312 } else { 1313 n = strlen(from_string); 1314 } 1315 *fontsize = tmp_fontsize; 1316 if (n >= to_size) 1317 n = to_size - 1; 1318 memcpy(to_string, from_string, n); 1319 to_string[n] = NUL; 1320} 1321 1322 1323/* ------------------------- 1324 * CONTEXT_adjust_dimensions 1325 * ------------------------- 1326 * 1327 * - sets the v_char and h_char based on current font size (approximation only) 1328 * using CONTEXT_fontsize in points (from CONTEXT_params.fontsize) and CONTEXT_params.scale_text 1329 * - sets xmax and ymax based on CONTEXT_params.xsize and CONTEXT_params.ysize 1330 */ 1331static void 1332CONTEXT_adjust_dimensions() 1333{ 1334 /* sets vertical dimension of characters based on current fontsize in pt */ 1335 term->v_char = (unsigned int)((double)CONTEXT_DPI * 1336 CONTEXT_fontsize / 72.27 * CONTEXT_params.scale_text + 0.5); 1337 /* based on proportions of LM digits at 12pt */ 1338 term->h_char = (unsigned int)(CONTEXT_LM_H_TO_V_RATIO * term->v_char + 0.5); 1339 1340 /* we might want to fix CONTEXT_DPI in case that the figure becomes too big */ 1341 if (CONTEXT_params.unit == INCHES) { 1342 term->xmax = (unsigned int)((double)CONTEXT_DPI * CONTEXT_params.xsize + 0.5); 1343 term->ymax = (unsigned int)((double)CONTEXT_DPI * CONTEXT_params.ysize + 0.5); 1344 } else { 1345 term->xmax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.xsize + 0.5); 1346 term->ymax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.ysize + 0.5); 1347 } 1348} 1349 1350/* ***************** 1351 * CONTEXT_set_font* 1352 * ***************** 1353 * 1354 * Official description: 1355 * - empty string restores the terminal's default font 1356 * - fonts are selected as strings "name,size", 1357 * where size should be a floating point number interpreted as "pt" (point) 1358 * 1359 * It's the user's own responsibility to make sure that the proper typescripts 1360 * are included in the header, else the selected font won't work out-of-the-box 1361 * 1362 * The ConTeXt terminal should support things such as 1363 * "iwona,ss,12" (iwona sans serif) or 1364 * ",10" (10 points) or 1365 * "tt" (typewriter) 1366 * 1367 * The routine saves font name to CONTEXT_font 1368 * and fontsize to CONTEXT_fontsize. 1369 * 1370 * The two are joined in CONTEXT_font_explicit for the usage in 1371 * \sometxt[gp][fontname,fontsize]{label} 1372 */ 1373TERM_PUBLIC int 1374CONTEXT_set_font(const char *font) 1375{ 1376 char tmp_fontstring[MAX_ID_LEN+1] = ""; 1377 1378 /* saves font name & family to CONTEXT_font */ 1379 CONTEXT_fontstring_parse((char *)font, CONTEXT_font, sizeof(CONTEXT_font), &CONTEXT_fontsize_explicit); 1380 safe_strncpy(CONTEXT_font_explicit, CONTEXT_font, sizeof(CONTEXT_font_explicit)); 1381 1382 /* valid fontsize has been provided */ 1383 if (CONTEXT_fontsize_explicit > 0.) { /* XXX: if valid */ 1384 1385 CONTEXT_fontsize = CONTEXT_fontsize_explicit; 1386 1387 snprintf(tmp_fontstring, sizeof(tmp_fontstring), ",%gpt", CONTEXT_fontsize_explicit); 1388 strncat(CONTEXT_font_explicit, tmp_fontstring, 1389 sizeof(CONTEXT_font_explicit) - strlen(CONTEXT_font_explicit)-1); 1390 tmp_fontstring[MAX_ID_LEN] = NUL; 1391 1392 /* no fontsize has been provided: switch back to default terminal fontsize */ 1393 } else if (CONTEXT_fontsize_explicit == 0) { 1394 CONTEXT_fontsize = CONTEXT_params.fontsize; 1395 } 1396 1397 /* tell to gnuplot how big the fonts in labels are */ 1398 CONTEXT_adjust_dimensions(); 1399 1400 return TRUE; 1401} 1402 1403/* ******************* 1404 * CONTEXT_pointsize * 1405 * ******************* 1406 * 1407 * Sets the (relative) point size for subsequent points 1408 * 1409 * The base point size is defined "somewhere else": 1410 * - depends on the font[size] used when "texpoints" option is on 1411 */ 1412TERM_PUBLIC void 1413CONTEXT_pointsize(double pointsize) 1414{ 1415 /* 1416 * my first thought was not to allow negative sizes of points, 1417 * but I see no reason why one shouldn't be able to play with 1418 * inverted point shapes, so finally I commented this out again 1419 * 1420 * if (pointsize < 0) 1421 * pointsize = 1; 1422 */ 1423 1424 if (CONTEXT_old_pointsize != pointsize) { 1425 /* close and draw the current path first */ 1426 if (CONTEXT_path_count > 0) 1427 CONTEXT_endpath(); 1428 fprintf(gpoutfile, "gp_set_pointsize(%.3f);\n", pointsize); 1429 CONTEXT_old_pointsize = pointsize; 1430 } 1431} 1432 1433/* ***************** 1434 * CONTEXT_fillbox * 1435 * ***************** 1436 * 1437 * Creates the path for the rectangle and calls the CONTEXT_fill(style) 1438 * routine (shared with CONTEXT_filled_polygon) to actually fill that shape 1439 */ 1440TERM_PUBLIC void 1441CONTEXT_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height) 1442{ 1443 /* close and draw the current path first */ 1444 if (CONTEXT_path_count > 0) 1445 CONTEXT_endpath(); 1446 1447 /* create a new path */ 1448 fprintf(gpoutfile, "p := unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n", 0.001*width, 0.001*height, 0.001*x1, 0.001*y1); 1449 /* fprintf(gpoutfile, "p := gp_rect ((%.3fa,%.3fa),(%.3fa,%.3fa));\n", 0.001*x1, 0.001*y1, 0.001*width, 0.001*height); */ 1450 1451 /* fills the box according to the "style" 1452 * the code went out of this routine because of undocumented behaviour 1453 * that also the filled_polygon should paint with patterns ... */ 1454 CONTEXT_fill(style); 1455} 1456 1457/* ************** 1458 * CONTEXT_fill * 1459 * ************** 1460 * 1461 * Filling routine, yet another undocumented feature of Gnuplot. 1462 * The code was mostly cloned from the PostScript terminal, 1463 * so that you know whom to accuse if it doesn't do what you would expect 1464 * it to do. (In case of cloning errors please inform the author of this terminal.) 1465 * 1466 * The lowest 4 bits of "style" seem to represent the style of filling 1467 * (whether it is solid or pattern-based or whatever that might appear 1468 * in that place in the future). 1469 * 1470 * The rest of the bits of "style" represent either the density 1471 * (ranging from 0 to 100) or the number of the pattern that the polygon 1472 * should be filled with. 1473 * 1474 * Used by CONTEXT_fillbox(...) and CONTEXT_filled_polygon(...) 1475 */ 1476TERM_PUBLIC void 1477CONTEXT_fill(int style) 1478{ 1479 int density; 1480 int pattern; 1481 1482 /* used in FS_[TRANSPARENT_]SOLID --> fill with intensity according to filldensity 1483 it extracts a percentage out of "style" */ 1484 density = (style >> 4); 1485 if (density < 0) 1486 density = 0; 1487 if (density > 100) 1488 density = 100; 1489 1490 fputs("gp_fill(p", gpoutfile); 1491 1492 /* do some strange trickery */ 1493 switch (style & 0xf) { 1494 1495 case FS_DEFAULT: 1496 break; 1497 1498 case FS_TRANSPARENT_SOLID: 1499 /* just a flag to tell the terminal that density() should be used to interpret transparency */ 1500 fprintf(gpoutfile, ",transparent"); 1501 case FS_SOLID: 1502 /* fill the box with density "density": if no parameter density is specified, 1503 it implies 100% density by default */ 1504 if (density < 100) 1505 fprintf(gpoutfile, ",density(%.2f)", 0.01*density); 1506 break; 1507 1508 case FS_TRANSPARENT_PATTERN: 1509 /* just a flag that should be interpreted in metapost, 1510 non-transparent patterns have to fill with background color before drawing the pattern */ 1511 fprintf(gpoutfile, ",transparent"); 1512 case FS_PATTERN: 1513 pattern = (style >> 4); 1514 fprintf(gpoutfile, ",pattern(%d)", pattern); 1515 break; 1516 1517 default: /* style == 0 (FS_EMPTY) or unknown --> fill with background color */ 1518 fprintf(gpoutfile, ",density(0)"); 1519 } 1520 /* TODO: FS_DEFAULT is missing; what should that one do? */ 1521 1522 /* gp_fill(p,...); */ 1523 fputs(");\n", gpoutfile); 1524} 1525 1526/* ******************* 1527 * CONTEXT_linewidth * 1528 * ******************* 1529 * 1530 * scale line width (similar to pointsize) 1531 * remembers the values locally (no serious need for that actually) and writes them into file 1532 */ 1533TERM_PUBLIC void 1534CONTEXT_linewidth(double linewidth) 1535{ 1536 if (linewidth < 0) 1537 linewidth = 1.0; 1538 1539 if (CONTEXT_old_linewidth != linewidth) { 1540 /* close and draw the current path first */ 1541 if (CONTEXT_path_count > 0) 1542 CONTEXT_endpath(); 1543 fprintf(gpoutfile, "gp_set_linewidth(%.3f);\n", linewidth); 1544 CONTEXT_old_linewidth = linewidth; 1545 } 1546} 1547 1548/* ------------------------------ 1549 * CONTEXT_write_palette_gradient 1550 * ------------------------------ 1551 * 1552 * Writes the colors and positions for a gradient palette. 1553 */ 1554static void 1555CONTEXT_write_palette_gradient(gradient_struct *gradient, int cnt) 1556{ 1557 int i; 1558 1559 /* i-th color */ 1560 fprintf(gpoutfile, "colors("); 1561 for (i = 0; i < cnt; i++) { 1562 if (i > 0) 1563 fprintf(gpoutfile, ","); 1564 fprintf(gpoutfile, "(%.3g,%.3g,%.3g)", gradient[i].col.r, gradient[i].col.g, gradient[i].col.b); 1565 } 1566 1567 /* position of the i-th color */ 1568 fprintf(gpoutfile, ");positions("); 1569 for (i = 0; i < cnt; i++) { 1570 if (i > 0) 1571 fprintf(gpoutfile, ","); 1572 fprintf(gpoutfile, "%.4g", gradient[i].pos); 1573 } 1574 fprintf(gpoutfile, ")"); 1575} 1576 1577/* --------------------- 1578 * CONTEXT_write_palette 1579 * --------------------- 1580 * 1581 */ 1582static void 1583CONTEXT_write_palette(t_sm_palette *palette) 1584{ 1585 if (palette == NULL) 1586 return; 1587 1588/* TODO 1589 // Color models: RGB, HSV, CMY, XYZ 1590 // 1591 // RGB: Red, Green, Blue 1592 // HSV: Hue, Saturation, Value 1593 // CMY 1594 // 1595 // two models that gnuplot uses, but which probably won't be supported by this terminal: 1596 // XYZ: three primary colors of the color model defined by the 'Commission Internationale de l'Eclairage' (CIE) 1597 // http://www.cs.rit.edu/~ncs/color/glossary.htm 1598 // http://cs.fit.edu/wds/classes/cse5255/cse5255/davis/index.html 1599*/ 1600 fprintf(gpoutfile, "gp_make_palette("); 1601 switch (sm_palette.colorMode) { 1602 /* grayscale only */ 1603 case SMPAL_COLOR_MODE_GRAY: 1604 fprintf(gpoutfile, "color_mode(gray)"); 1605 break; 1606 /* one of several fixed transformations */ 1607 case SMPAL_COLOR_MODE_RGB: 1608 fprintf(gpoutfile, "color_mode(rgb);formulae(%d,%d,%d)", 1609 sm_palette.formulaR, 1610 sm_palette.formulaG, 1611 sm_palette.formulaB); 1612 break; 1613 /* user defined transforms */ 1614 case SMPAL_COLOR_MODE_FUNCTIONS: 1615 fprintf(gpoutfile, "color_mode(functions)"); 1616 break; 1617 /* interpolated table: explicitly defined or read from file */ 1618 case SMPAL_COLOR_MODE_GRADIENT: 1619 fprintf(gpoutfile, "color_mode(gradient);"); 1620 CONTEXT_write_palette_gradient(palette->gradient, palette->gradient_num); 1621 break; 1622 case SMPAL_COLOR_MODE_NONE: 1623 break; 1624 default: 1625 break; 1626 } 1627 fprintf(gpoutfile, ");\n"); 1628} 1629 1630/* ********************* 1631 * CONTEXT_make_palette* 1632 * ********************* 1633 * 1634 * 1. if palette==NULL, then return nice/suitable 1635 * maximal number of colours supported by this terminal. 1636 * Returns 0 if it can make colours without palette (like 1637 * postscript). 1638 * 2. if palette!=NULL, then allocate its own palette 1639 * return value is undefined 1640 * 3. available: some negative values of max_colors for whatever 1641 * can be useful 1642 */ 1643TERM_PUBLIC int 1644CONTEXT_make_palette(t_sm_palette *palette) 1645{ 1646 if (palette == NULL) 1647 return 0; /* ConTeXt can do continuous colors */ 1648 1649 /* save the palette */ 1650 CONTEXT_old_palette = palette; 1651 1652 return 0; 1653} 1654 1655 1656/* 1657 * most probably this one is not needed 1658 * 1659 * TERM_PUBLIC void 1660 * CONTEXT_previous_palette(){} 1661 * 1662 */ 1663 1664/* ******************* 1665 * CONTEXT_set_color * 1666 * ******************* 1667 * 1668 * typedef struct t_colorspec { 1669 * int type; // TC_ DEFAULT, LT, LINESTYLE, RGB, CB, FRAC, Z 1670 * int lt; // used for TC_LT, TC_LINESTYLE and TC_RGB 1671 * double value; // used for TC_CB and TC_FRAC 1672 * } t_colorspec; 1673 */ 1674TERM_PUBLIC void 1675CONTEXT_set_color(t_colorspec *colorspec) 1676{ 1677 double gray, r, g, b; 1678 /* ConTeXt doesn't offer full support for palettes yet 1679 (I don't know how to trick metapost to accept the full palette specification) 1680 so we convert the colors from palettes to RGB instead. 1681 If terminal starts supporting palettes, this behaviour will change. 1682 */ 1683 rgb_color rgb1; 1684 1685/* If (colorspec->type == TC_FRAC): 1686 Set current color according to colorspec->value, where 0 <= value <= 1. 1687 If using a palette, first map value to an integer i in the interval 1688 [0...num_colors-1], then set to the ith color in the palette. 1689 If (colorspec->type == TC_RGB): 1690 Set current color to the rgb triple given in colorspec->lt. */ 1691 1692 /* close and draw the current path first */ 1693 if (CONTEXT_path_count > 0) 1694 CONTEXT_endpath(); 1695 1696 switch (colorspec->type) { 1697 1698 /* TC_DEFAULT, TC_CB, TC_Z: probably unused; what about linestyle? */ 1699 1700 /* color equal as that of linetype in colorspec->lt */ 1701 case TC_LT: 1702 fprintf(gpoutfile, "gp_set_color(lt(%d));\n", colorspec->lt); 1703 CONTEXT_color_changed = TRUE; 1704 break; 1705 1706 /* rgb color */ 1707 case TC_RGB: 1708 r = (double)((colorspec->lt >> 16 ) & 255) / 255.; 1709 g = (double)((colorspec->lt >> 8 ) & 255) / 255.; 1710 b = (double)(colorspec->lt & 255) / 255.; 1711 1712 fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", r, g, b); 1713 CONTEXT_color_changed = TRUE; 1714 break; 1715 1716 /* map [0:1] to gray colors or to the corresponding color from the palette */ 1717 case TC_FRAC: 1718 gray = colorspec->value; 1719 1720 /* limit negative and >1 values to [0:1] first */ 1721 if (gray < 0) gray = 0; 1722 if (gray > 1) gray = 1; 1723 1724 /* TODO: if ConTeXt start supporting palettes, we'll uncomment the following: */ 1725 fprintf(gpoutfile, "%%gp_set_color(frac(%.4f));\n", gray); 1726 /* but now it doesn't, so let's use the fallback instead: */ 1727 rgb1maxcolors_from_gray(gray, &rgb1); 1728 fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", rgb1.r, rgb1.g, rgb1.b); 1729 1730 CONTEXT_color_changed = TRUE; 1731 break; 1732 default: 1733 int_warn(NO_CARET,"context.trm set_color unknown colorspec->type %i", colorspec->type); 1734 break; 1735 } 1736} 1737 1738 1739/* ************************ 1740 * CONTEXT_filled_polygon * 1741 * ************************ 1742 * 1743 * Draws a polygon with the fill color set by set_color, and no border. 1744 */ 1745TERM_PUBLIC void 1746CONTEXT_filled_polygon(int points, gpiPoint *corners) 1747{ 1748 int i; 1749 1750 /* nothing to be filled if less than 3 points */ 1751 if (points < 3) 1752 return; 1753 1754 /* close and draw the current path first */ 1755 if (CONTEXT_path_count > 0) 1756 CONTEXT_endpath(); 1757 1758 /* if the first point equals the last one, skip the last point; --cycle does that already 1759 * this condition is probably always true in gnuplot, so the if condition may not be needed */ 1760 if ((corners[0].x == corners[points-1].x) && (corners[0].y == corners[points-1].y)) 1761 points--; 1762 1763 /* create new path with corners */ 1764 fputs("p := ", gpoutfile); 1765 fprintf(gpoutfile, "(%.3fa,%.3fa)", 0.001*corners[0].x, 0.001*corners[0].y); 1766 for (i = 1; i < points; i++) { 1767 if (i % CONTEXT_LINEMAX == 0) 1768 fputs("\n ", gpoutfile); 1769 fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*corners[i].x, 0.001*corners[i].y); 1770 } 1771 /* and fill it */ 1772 fprintf(gpoutfile, "--cycle;\n"); 1773 1774 /* fill the polygon 1775 * undocumented gnuplot behaviour, copied from PostScript terminal 1776 * see comments for CONTEXT_fill for details */ 1777 CONTEXT_fill(corners->style); 1778} 1779 1780/* *************** 1781 * CONTEXT_image * 1782 * *************** 1783 * 1784 Plot a pixel-based image on the display device. 1785 'M' is the number of pixels along the y-dimension of the image and 1786 'N' is the number of pixels along the x-dimension of the image. The 1787 coordval pointer 'image' is the pixel values normalized to the range 1788 [0:1]. These values should be scaled appropriately for the output 1789 device. The 'image' data starts in the upper left corner and scans 1790 along rows finishing in the lower right corner. If 'color_mode' is 1791 IC_PALETTE, the terminal is to use palette lookup to generate color 1792 information. In this scenario the size of 'image' is M*N. If 1793 'color_mode' is IC_RGB, successive bytes of the data structure are 1794 interpreted as RGB components of a single pixel. In this scenario 1795 the size of 'image' is 3*M*N. The data appears in RGB triples, i.e., 1796 image[0] = R(1,1), image[1] = G(1,1), image[2] = B(1,1), 1797 image[3] = R(1,2), image[4] = G(1,2), ..., image[3*M*N-1] = B(M,N). 1798 The mode IC_RGBA is similar except that four values red, green, blue, 1799 alpha per pixel are passed to the terminal in the image structure. 1800 The 'image' is actually an "input" image in the sense that 1801 it must also be properly resampled for the output device. Many output 1802 media, e.g., PostScript, do this work via various driver functions. 1803 To determine the appropriate rescaling, the 'corner' information 1804 should be used. There are four entries in the gpiPoint data array. 1805 'corner[0]' is the upper left corner (in terms of plot location) of 1806 the outer edge of the image. Similarly, 'corner[1]' is the lower 1807 right corner of the outer edge of the image. (Outer edge means the 1808 outer extent of the corner pixels, not the middle of the corner 1809 pixels.) 'corner[2]' is the upper left corner of the visible part 1810 of the image, and 'corner[3]' is the lower right corner of the visible 1811 part of the image. The information is provided in this way because 1812 often it is necessary to clip a portion of the outer pixels of the 1813 image. 1814 */ 1815 1816/* TODO: this code needs some improvements 1817 * 1818 * There are two different modes: 1819 * 1820 * 1. creating PNG image and including it 1821 * - it only works if gnuplot has been compiled with cairo or gdlib libraries 1822 * - there are some bugs in MKII/MKIV handling: a different syntax is required 1823 * and can only be fixed in ConTeXt core; I could abstract the code a bit 1824 * 2. printing out a string with colors 1825 * - MKIV: works, but transparency is not yet implemented 1826 * - MKII: requires MetaPost > 0.750 and is not implemented at all 1827 * two possible approaches: drawing rectangles & creating proper image 1828 * it might require one additional level of abstraction like gp_image(...) 1829 */ 1830TERM_PUBLIC void 1831CONTEXT_image(unsigned M, unsigned N, coordval *image, gpiPoint *corner, t_imagecolor color_mode) 1832{ 1833 int i, k, line_length, components_per_color; 1834 rgb_color color; 1835 TBOOLEAN is_clipped = FALSE; 1836 1837 if ((corner[2].x > corner[0].x) || (corner[0].y > corner[2].y) || 1838 (corner[1].x > corner[3].x) || (corner[3].y > corner[1].y)) 1839 is_clipped = TRUE; 1840 1841 if (CONTEXT_images == CONTEXT_IMAGES_EXTERNAL) { 1842#ifdef WRITE_PNG_IMAGE 1843 /* we reserved 10 extra bytes, so we can afford images up to 9999 */ 1844 if (CONTEXT_image_counter < 9999) 1845 sprintf(CONTEXT_image_filename + CONTEXT_image_filename_length, 1846 "_%02d.png", ++CONTEXT_image_counter); 1847 write_png_image (M, N, image, color_mode, CONTEXT_image_filename); 1848 1849 if (is_clipped) 1850 fprintf(gpoutfile, "draw image(\n "); 1851 fprintf(gpoutfile, "externalfigure \"%s\" xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n", 1852 CONTEXT_image_filename + CONTEXT_image_filename_start, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y); 1853 if (is_clipped) { 1854 fprintf(gpoutfile, " clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n", 1855 0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y); 1856 } 1857#endif 1858 } else { 1859 1860 /* Palette colors have to be converted into RGB first */ 1861 if (color_mode == IC_PALETTE) { 1862 /* write the image data */ 1863 fprintf(gpoutfile, "img := \"%%\n"); 1864 line_length = 0; 1865 for (i = 0; i < M * N; i++) { 1866 if (line_length++ >= 16) { 1867 line_length = 1; 1868 fprintf(gpoutfile, "%%\n"); 1869 } 1870 rgb1maxcolors_from_gray(image[i], &color); 1871 fprintf(gpoutfile, "%02x%02x%02x", (unsigned char)(255*color.r), (unsigned char)(255*color.g), (unsigned char)(255*color.b)); 1872 } 1873 fprintf(gpoutfile, "\";\n"); 1874 1875 /* IC_RGB or IC_RGBA */ 1876 } else { 1877 if (color_mode == IC_RGBA) { 1878 components_per_color = 4; 1879 } else { /* IC_RGB */ 1880 components_per_color = 3; 1881 } 1882 1883 /* write the image data */ 1884 fprintf(gpoutfile, "img := \"%%\n"); 1885 line_length = 0; 1886 for (i = 0; i < M * N; i++) { 1887 if (line_length++ >= 16) { 1888 line_length = 1; 1889 fprintf(gpoutfile, "%%\n"); 1890 } 1891 for (k = 0; k < 3; k++) { 1892 fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+k]*255)); 1893 } 1894 } 1895 fprintf(gpoutfile, "\";\n"); 1896 1897 /* transparency mask */ 1898 if (color_mode == IC_RGBA) { 1899 fprintf(gpoutfile, "ima := \"%%\n"); 1900 line_length = 0; 1901 for (i = 0; i < M * N; i++) { 1902 if (line_length++ >= 3*16) { 1903 line_length = 1; 1904 fprintf(gpoutfile, "%%\n"); 1905 }; 1906 fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+3]*255)); 1907 } 1908 fprintf(gpoutfile, "\";\n"); 1909 } 1910 } 1911 1912 /* TODO: transparency handling is not yet supported in ConTeXt */ 1913 if (is_clipped) 1914 fprintf(gpoutfile, "draw image(\n "); 1915 fprintf(gpoutfile, "draw bitmapimage (%u,%u,img) xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n", 1916 N, M, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y); 1917 if (is_clipped) { 1918 fprintf(gpoutfile, " clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n", 1919 0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y); 1920 } 1921 1922 /* (alternative implementation) * 1923 fprintf(gpoutfile, "gp_image_rgb"); 1924 if (color_mode == IC_RGB) 1925 fprintf(gpoutfile, "_alpha"); 1926 fprintf(gpoutfile, "((%u,%u),(%.3fa,%.3fa),(%.3fa,%.3fa));\n", 1927 N, M, 0.001*corner[0].x, 0.001*corner[1].y, 0.001*corner[1].x, 0.001*corner[0].y); 1928 */ 1929 } 1930} 1931 1932/* 1933 * TODO: Implement this function for smooth shading 1934 * 1935 * you need to fix draw_color_smooth_box(MODE_SPLOT) in graph3d.c -> color.c 1936 * 1937static void 1938CONTEXT_draw_inside_color_smooth_box() 1939{ 1940} 1941 */ 1942 1943#endif /* TERM_BODY */ 1944 1945#ifdef TERM_TABLE 1946 1947TERM_TABLE_START(context_driver) 1948 "context", "ConTeXt with MetaFun (for PDF documents)", 1949 CONTEXT_XMAX, CONTEXT_YMAX, CONTEXT_VCHAR, CONTEXT_HCHAR, 1950 CONTEXT_VTIC, CONTEXT_HTIC, CONTEXT_options, CONTEXT_init, 1951 CONTEXT_reset, CONTEXT_text, null_scale, CONTEXT_graphics, 1952 CONTEXT_move, CONTEXT_vector, 1953 CONTEXT_linetype, CONTEXT_put_text, CONTEXT_text_angle, 1954 CONTEXT_justify_text, CONTEXT_point, CONTEXT_arrow, CONTEXT_set_font, 1955 CONTEXT_pointsize, 1956 /* also add TERM_CAN_CLIP once you understand what it does */ 1957 TERM_CAN_DASH | TERM_ALPHA_CHANNEL | TERM_LINEWIDTH | TERM_FONTSCALE | TERM_IS_LATEX /* flags */, 1958 0 /* suspend */, 0 /* resume*/, 1959 CONTEXT_fillbox, CONTEXT_linewidth 1960#ifdef USE_MOUSE 1961 , 0, 0, 0, 0, 0 /* no mouse support */ 1962#endif /* USE_MOUSE */ 1963 , CONTEXT_make_palette, 1964 0, /* XXX: CONTEXT_previous_palette: not sure if we need it at all (PS does "grestore") */ 1965 CONTEXT_set_color, 1966 CONTEXT_filled_polygon, 1967 CONTEXT_image, 1968 0, 0, 0, /* No enhanced text mode because this is TeX */ 1969 0, /* layer (used to signal front/back text, used in canvas, PS, epslatex, ...); XXX: figure out what this has to do */ 1970 0 /* path (Path control for end-joins of closed polygons on PostScript-like devices); TODO: implement it (CONTEXT_path) */ 1971TERM_TABLE_END(context_driver) 1972#undef LAST_TERM 1973#define LAST_TERM context_driver 1974 1975#endif /* TERM_TABLE */ 1976#endif /* TERM_PROTO_ONLY */ 1977 1978#ifdef TERM_HELP 1979START_HELP(context) 1980"1 context", 1981"?commands set terminal context", 1982"?set terminal context", 1983"?terminal context", 1984"?set term context", 1985"?term context", 1986"?context", 1987" ConTeXt is a macro package for TeX, highly integrated with Metapost", 1988" (for drawing figures) and intended for creation of high-quality PDF documents.", 1989" The terminal outputs Metafun source, which can be edited manually,", 1990" but you should be able to configure most things from outside.", 1991"", 1992" For an average user of ConTeXt + gnuplot module it's recommended to refer to", 1993" `Using ConTeXt` rather than reading this page", 1994" or to read the manual of the gnuplot module for ConTeXt.", 1995"", 1996" The `context` terminal supports the following options:", 1997"", 1998" Syntax:", 1999" set term context {default}", 2000" {defaultsize | size <scale> | size <xsize>{in|cm}, <ysize>{in|cm}}", 2001" {input | standalone}", 2002" {timestamp | notimestamp}", 2003" {noheader | header \"<header>\"}", 2004" {color | colour | monochrome}", 2005" {rounded | mitered | beveled} {round | butt | squared}", 2006" {dashed | solid} {dashlength | dl <dl>}", 2007" {linewidth | lw <lw>}", 2008" {fontscale <fontscale>}", 2009" {mppoints | texpoints}", 2010" {inlineimages | externalimages}", 2011" {defaultfont | font \"{<fontname>}{,<fontsize>}\"}", 2012"", 2013" In non-standalone (`input`) graphic only parameters `size` to select graphic", 2014" size, `fontscale` to scale all the labels for a factor <fontscale>", 2015" and font size, make sense, the rest is silently", 2016" ignored and should be configured in the .tex file which inputs the graphic.", 2017" It's highly recommended to set the proper fontsize if document font differs from", 2018" 12pt, so that gnuplot will know how much space to reserve for labels.", 2019"", 2020" `default` resets all the options to their default values.", 2021"", 2022" `defaultsize` sets the plot size to 5in,3in.", 2023" `size` <scale> sets the plot size to <scale> times <default value>.", 2024" If two arguments are given (separated with ','), the first one sets", 2025" the horizontal size and the second one the vertical size.", 2026" Size may be given without units (in which case it means relative to the default", 2027" value), with inches ('in') or centimeters ('cm').", 2028"", 2029" `input` (default) creates a graphic that can be included into another ConTeXt", 2030" document.", 2031" `standalone` adds some lines, so that the document might be compiled as-is.", 2032" You might also want to add `header` in that case.", 2033"", 2034" Use `header` for any additional settings/definitions/macros", 2035" that you might want to include in a standalone graphic. `noheader` is the default.", 2036"", 2037" `notimestamp` prevents printing creation time in comments", 2038" (if version control is used, one may prefer not to commit new version when only date changes).", 2039"", 2040" `color` to make color plots is the default, but `monochrome` doesn't do anything special yet.", 2041" If you have any good ideas how the behaviour should differ to suit the monochrome printers better,", 2042" your suggestions are welcome.", 2043"", 2044" `rounded` (default), `mitered` and `beveled` control the shape of line joins.", 2045" `round` (default), `butt` and `squared` control the shape of line caps.", 2046" See PostScript or PDF Reference Manual for explanation. For wild-behaving functions", 2047" and thick lines", 2048" it is better to use `rounded` and `round` to prevent sharp corners in line joins.", 2049" (Some general support for this should be added to Gnuplot, so that the same options", 2050" could be set for each line (style) separately).", 2051"", 2052" `dashed` (default) uses different dash patterns for different line types,", 2053" `solid` draws all plots with solid lines.", 2054"", 2055" `dashlength` or `dl` scales the length of the dashed-line segments by <dl>.", 2056" `linewidth` or `lw` scales all linewidths by <lw>.", 2057" (lw 1 stands for 0.5bp, which is the default line width when drawing with Metapost.)", 2058" `fontscale` scales text labels for factor <fontscale> relative to default document font.", 2059"", 2060" `mppoints` uses predefined point shapes, drawn in Metapost.", 2061" `texpoints` uses easily configurable set of symbols, defined with ConTeXt", 2062" in the following way:", 2063" \\defineconversion[my own points][+,{\\ss x},\\mathematics{\\circ}]", 2064" \\setupGNUPLOTterminal[context][points=tex,pointset=my own points]", 2065"", 2066" `inlineimages` writes binary images to a string and only works in ConTeXt MKIV.", 2067" `externalimages` writes PNG files to disk and also works with ConTeXt MKII.", 2068" Gnuplot needs to have support for PNG images built in for this to work.", 2069"", 2070" With `font` you can set font name and size in standalone graphics.", 2071" In non-standalone (`input`) mode only the font size is important", 2072" to reserve enough space for text labels.", 2073" The command", 2074" set term context font \"myfont,ss,10\"", 2075" will result in", 2076" \\setupbodyfont[myfont,ss,10pt]", 2077" If you additionally set `fontscale` to 0.8 for example,", 2078" then the resulting font will be 8pt big and", 2079" set label ... font \"myfont,12\"", 2080" will come out as 9.6pt.", 2081"", 2082" It is your own responsibility to provide proper typescripts (and header),", 2083" otherwise switching the font will have no effect.", 2084" For a standard font in ConTeXt MKII (pdfTeX) you could use:", 2085" set terminal context standalone header '\\usetypescript[iwona][ec]' \\", 2086" font \"iwona,ss,11\"", 2087" Please take a look into ConTeXt documentation, wiki or mailing list (archives)", 2088" for any up-to-date information about font usage.", 2089"", 2090" Examples:", 2091" set terminal context size 10cm, 5cm # 10cm, 5cm", 2092" set terminal context size 4in, 3in # 4in, 3in", 2093" For standalone (whole-page) plots with labels in UTF-8 encoding:", 2094" set terminal context standalone header '\\enableregime[utf-8]'", 2095"", /* TODO: LaTeX formatting */ 2096"2 Requirements", 2097" You need gnuplot module for ConTeXt", 2098"^ <a href=\"http://ctan.org/pkg/context-gnuplot\">", 2099" http://ctan.org/pkg/context-gnuplot", 2100"^ </a>", 2101" and a recent version of ConTeXt.", 2102" If you want to call gnuplot on-the-fly, you also need write18 enabled.", 2103" In most TeX distributions this can be set with shell_escape=t in texmf.cnf.", 2104"", 2105" See", 2106"^ <a href=\"http://wiki.contextgarden.net/Gnuplot\">", 2107" http://wiki.contextgarden.net/Gnuplot", 2108"^ </a>", 2109" for details about this terminal and for more exhaustive help & examples.", 2110"", 2111"2 Calling gnuplot from ConTeXt", 2112" The easiest way to make plots in ConTeXt documents is", 2113" \\usemodule[gnuplot]", 2114" \\starttext", 2115" \\title{How to draw nice plots with {\\sc gnuplot}?}", 2116" \\startGNUPLOTscript[sin]", 2117" set format y \"%.1f\"", 2118" plot sin(x) t '$\\sin(x)$'", 2119" \\stopGNUPLOTscript", 2120" \\useGNUPLOTgraphic[sin]", 2121" \\stoptext", 2122" This will run gnuplot automatically and include the resulting figure in the document." 2123END_HELP(context) 2124#endif /* TERM_HELP */ 2125 2126