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