1 /* Hey Emacs this is -*- C -*-
2 * $Id: cgm.trm,v 1.77.2.5 2009/02/16 21:41:56 sfeam Exp $
5 /* GNUPLOT - cgm.trm */
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
38 * This file is included by ../term.c and ../docs/termdoc.c.
40 * This terminal driver supports:
41 * Computer Graphics Metafile
44 * better control over plot size (never cutting off labels, correct font
49 * ISO 8632-1:1992 Computer Graphics Metafile (CGM), Part 1,
50 * Functional Specification.
52 * ISO 8632-1:1992 Computer Graphics Metafile (CGM), Part 3,
55 * FIPS PUB 128 - Computer Graphics Metafile (CGM).
57 * MIL-STD-2301A Computer Graphics Metafile (CGM) Implementation
58 * Standard for the National Imagery Transmission Format Standard, 5
59 * June 1998, http://164.214.2.51/ntb/baseline/docs/2301a/. Only a
60 * subset of CGM version 1, but does include the binary format for
63 * MIL-D-28003A "Digital Representation for Communication of
64 * Illustration Data: CGM Application Profile", 15 November 1991,
65 * http://www-cals.itsi.disa.mil/core/standards/28003aa1.pdf.
67 * "The computer graphics metafile", Lofton R. Henderson and Anne
68 * M. Mumford, Butterworths, London, 1990, ISBN 0-408-02680-4.
71 * Jim Van Zandt <jrvz@comcast.net>
73 * send your comments or suggestions to the author or
74 * gnuplot-info@lists.sourceforge.net.
84 TERM_PUBLIC void CGM_options __PROTO((void));
85 TERM_PUBLIC void CGM_init __PROTO((void));
86 TERM_PUBLIC void CGM_reset __PROTO((void));
87 TERM_PUBLIC void CGM_text __PROTO((void));
88 TERM_PUBLIC void CGM_graphics __PROTO((void));
89 TERM_PUBLIC void CGM_move __PROTO((unsigned int x, unsigned int y));
90 TERM_PUBLIC void CGM_dashed_vector __PROTO((unsigned int ux, unsigned int uy));
91 TERM_PUBLIC void CGM_solid_vector __PROTO((unsigned int ux, unsigned int uy));
92 TERM_PUBLIC void CGM_linetype __PROTO((int linetype));
93 TERM_PUBLIC void CGM_linecolor __PROTO((int color));
94 TERM_PUBLIC void CGM_dashtype __PROTO((int dashtype));
95 TERM_PUBLIC void CGM_linewidth __PROTO((double width));
96 TERM_PUBLIC void CGM_put_text __PROTO((unsigned int x, unsigned int y,
98 TERM_PUBLIC int CGM_text_angle __PROTO((int ang));
99 TERM_PUBLIC int CGM_justify_text __PROTO((enum JUSTIFY mode));
100 TERM_PUBLIC int CGM_set_font __PROTO((const char *font));
101 TERM_PUBLIC void CGM_point __PROTO((unsigned int x, unsigned int y,
103 TERM_PUBLIC void CGM_fillbox __PROTO((int style, unsigned int x1, unsigned int y1,
104 unsigned int width, unsigned int height));
105 TERM_PUBLIC int CGM_make_palette __PROTO((t_sm_palette *palette));
106 TERM_PUBLIC void CGM_set_color __PROTO((t_colorspec *));
108 TERM_PUBLIC void CGM_filled_polygon __PROTO((int points, gpiPoint *corner));
110 TERM_PUBLIC void CGM_set_pointsize __PROTO((double size));
112 #define FATAL(msg) { fprintf(stderr, "%s\nFile %s line %d\n", msg, __FILE__, __LINE__); exit(EXIT_FAILURE); }
114 #define CGM_LARGE 32767
115 #define CGM_SMALL 32767/18*13 /* aspect ratio 1:.7222 */
116 #define CGM_MARGIN (CGM_LARGE/180)
117 /* convert from plot units to pt */
118 #define CGM_PT ((term->xmax + CGM_MARGIN)/cgm_plotwidth)
119 #define CGM_LINE_TYPES 9 /* number of line types we support */
120 #define CGM_COLORS WEB_N_COLORS /* sizeof(web_color_rgbs) currently in bitmap.c */
121 #define CGM_POINTS 13 /* number of markers we support */
122 #define CGM_MAX_SEGMENTS 16382 /* maximum # polyline coordinates */
123 #define CGM_VCHAR (CGM_SMALL/360*12)
124 #define CGM_HCHAR (CGM_SMALL/360*12*5/9)
125 #define CGM_VTIC (CGM_LARGE/80)
126 #define CGM_HTIC (CGM_LARGE/80)
129 #ifndef TERM_PROTO_ONLY
132 static int CGM_find_font __PROTO((const char *name, int len, double *relwidth));
133 static int CGM_find_nearest_color __PROTO((t_colorspec *colorspec));
135 * on NeXTstep, id is an identifier (in ObjC) and causes a parse error
136 * since some asserts below are mistaken as casts. datum is a type
137 * defined in ndbm.h which also causes a parse error (ndbm.h is
138 * included as part of appkit.h, I think). Strangely enough, both
139 * errors only happen with cpp-precomp -smart, not with the regular
148 #include <ctype.h> /* for isspace() */
151 #define assert(x) 0 /* defeat assertions */
154 /* uncomment the following to enable assertions for this module only,
155 regardless of compiler switches
157 #define DEFEAT_ASSERTIONS
163 #define CGM_ADJ (sizeof(int)/sizeof(short))
165 static unsigned int cgm_posx;
166 static unsigned int cgm_posy;
167 static unsigned int cgm_linetype = 1;
168 static unsigned int cgm_linetypes = CGM_LINE_TYPES + 3;
169 static unsigned int cgm_dashtype = 0;
170 static unsigned int cgm_color = 0;
171 static int *cgm_polyline; /* stored polyline coordinates */
172 static int cgm_coords = 0; /* # polyline coordinates saved */
173 static int cgm_doing_polygon = 0; /* nonzero if creating polygon, else
174 * creating polyline */
175 /* static enum JUSTIFY cgm_justify = LEFT; */ /* unused */
176 static int cgm_step_sizes[8]; /* array of currently used dash
177 lengths in plot units */
178 static int cgm_step_index = 0; /* index into cgm_step_sizes[] */
179 static int cgm_step = 0; /* amount of current dash not yet
180 drawn, in plot units */
181 static int cgm_tic, cgm_tic707, cgm_tic866, cgm_tic500, cgm_tic1241, cgm_tic1077, cgm_tic621; /* marker dimensions */
182 struct cgm_properties {
183 double angle; /* angle of text baseline (radians
184 counter-clockwise from horizontal) */
185 int font_index; /* font index */
186 int char_height; /* character height in picture units */
187 enum JUSTIFY justify_mode; /* how text is justified */
189 int edge_visibility; /* nonzero if edge is visible */
196 static struct cgm_properties
197 cgm_current={-1,-1,-1,(enum JUSTIFY)-1,-1,-1,-1,-1,-1}, /* written to file */
198 cgm_next={0,-2,-2,LEFT,-2,-2,-2,-1,-1}, /* needed for next text string/marker */
199 cgm_reset={-1,-1,-1,(enum JUSTIFY)-1,-1,-1,-1,-1,-1}; /* invalid entries */
201 static int cgm_user_color_count = 0;
202 static int cgm_user_color_max = 0;
203 static int cgm_smooth_colors = 0;
204 static int GPFAR *cgm_user_color_table = (int GPFAR*)0;
205 static int cgm_maximum_color_index = 255; /* Size of color table we will write */
208 char *name; /* the name of the font */
209 double width; /* the width of the font, relative to
210 Times Bold Italic. The width
211 adjustment can only be approximate.
212 Of the standard fonts, only the
213 four versions of "Courier" are
214 monospaced. Also, metrics of the
215 same font from different foundaries
216 are sometimes different. */
219 static struct fontdata cgm_basic_font_data[]={
220 /* these are WebCGM recommended fonts */
222 {"Helvetica Oblique",1.099},
223 {"Helvetica Bold",1.083},
224 {"Helvetica Bold Oblique",1.011},
225 {"Times Roman",.981},
227 {"Times Italic",.959},
228 {"Times Bold Italic",1.0},
230 {"Courier Bold",1.327},
231 {"Courier Oblique",1.218},
232 {"Courier Bold Oblique",1.341},
235 /* These are basic public domain fonts required by MIL-D-28003A */
236 {"Hershey/Cartographic_Roman",1.2404},
237 {"Hershey/Cartographic_Greek",.9094},
238 {"Hershey/Simplex_Roman",1.2369},
239 {"Hershey/Simplex_Greek",.9129},
240 {"Hershey/Simplex_Script",1.4181},
241 {"Hershey/Complex_Roman",1.1150},
242 {"Hershey/Complex_Greek",.9059},
243 {"Hershey/Complex_Script",1.3868},
244 {"Hershey/Complex_Italic",1.4146},
245 {"Hershey/Complex_Cyrillic",1.2056},
246 {"Hershey/Duplex_Roman",1.1707},
247 {"Hershey/Triplex_Roman",1.3240},
248 {"Hershey/Triplex_Italic",1.3310},
249 {"Hershey/Gothic_German",1.2056},
250 {"Hershey/Gothic_English",1.2021},
251 {"Hershey/Gothic_Italian",1.2021},
252 {"Hershey/Symbol_Set_1",.9059},
253 {"Hershey/Symbol_Set_2",.9059},
254 {"Hershey/Symbol_Math",.9059},
256 /* These are available in the Microsoft Office import filter. By
257 default, the script font can apparently be accessed only via
259 {"ZapfDingbats",1.583},
263 /* in the Microsoft Office and Corel Draw import filters, these
264 are pseudonyms for some of the above */
265 {"Helvetica Italic",1.099},
266 {"Helvetica Bold Italic",1.011},
267 {"Courier Italic",1.218},
268 {"Courier Bold Italic",1.341},
269 {"Times Oblique",.959},
270 {"Times Bold Oblique",1.0},
275 static struct fontdata *cgm_font_data = cgm_basic_font_data;
277 #define DEFAULT_CGMFONT "Helvetica Bold"
278 static char CGM_default_font[MAX_ID_LEN+1] = {'\0'};
280 /* variables to record the options */
281 static char cgm_font[32] = DEFAULT_CGMFONT;
282 static unsigned int cgm_fontsize = 12;
283 static unsigned cgm_linewidth; /* line width in plot units */
284 static unsigned cgm_linewidth_pt = 1; /* line width in pt */
285 static TBOOLEAN cgm_monochrome = FALSE; /* colors enabled? */
286 static int cgm_plotwidth = 432; /* assumed width of plot in pt. */
287 static TBOOLEAN cgm_portrait = FALSE; /* portrait orientation? */
288 static TBOOLEAN cgm_rotate = TRUE; /* text rotation enabled? */
289 static TBOOLEAN cgm_dashed = TRUE; /* dashed linestyles enabled? */
290 static TBOOLEAN cgm_nofontlist_mode = FALSE; /* omit font list? */
292 /* prototypes for static functions */
293 static void CGM_local_reset __PROTO((void));
294 static void CGM_flush_polyline __PROTO((void));
295 static void CGM_flush_polygon __PROTO((void));
296 static void CGM_write_char_record __PROTO((int class, int cgm_id, int length,
298 static void CGM_write_code __PROTO((int class, int cgm_id, int length));
299 static void CGM_write_int __PROTO((int value));
300 static void CGM_write_int_record __PROTO((int class, int cgm_id, int length,
302 static void CGM_write_mixed_record __PROTO((int class, int cgm_id,
303 int numint, int *int_data,
304 int numchar, const char *char_data));
305 static void CGM_write_byte_record __PROTO((int class, int cgm_id, int length,
310 CGM_PORTRAIT, CGM_LANDSCAPE, CGM_DEFAULT,
312 CGM_MONOCHROME, CGM_COLOR,
314 CGM_ROTATE, CGM_NOROTATE,
315 CGM_DASHED, CGM_SOLID,
316 CGM_LINEWIDTH, CGM_WIDTH, CGM_NOFONTLIST, CGM_OTHER
319 static struct gen_table CGM_opts[] =
321 { "p$ortrait", CGM_PORTRAIT },
322 { "la$ndscape", CGM_LANDSCAPE },
323 { "de$fault", CGM_DEFAULT },
324 { "nof$ontlist", CGM_NOFONTLIST },
325 { "win$word6", CGM_NOFONTLIST }, /* deprecated */
326 { "m$onochrome", CGM_MONOCHROME },
327 { "c$olor", CGM_COLOR },
328 { "c$olour", CGM_COLOR },
329 { "r$otate", CGM_ROTATE },
330 { "nor$otate", CGM_NOROTATE },
331 { "da$shed", CGM_DASHED },
332 { "s$olid", CGM_SOLID },
333 { "li$newidth", CGM_LINEWIDTH },
334 { "lw", CGM_LINEWIDTH },
335 { "wid$th", CGM_WIDTH },
346 /* Annoying hack to handle the case of 'set termoption' after */
347 /* we have already initialized the terminal. */
351 while (!END_OF_COMMAND) {
352 switch(lookup_table(&CGM_opts[0],c_token)) {
358 cgm_portrait = FALSE;
366 cgm_nofontlist_mode = TRUE;
370 cgm_monochrome = TRUE;
374 cgm_monochrome = FALSE;
395 if (!END_OF_COMMAND) {
396 cgm_linewidth_pt = (unsigned int) real(const_express(&a));
397 if (cgm_linewidth_pt == 0 || cgm_linewidth_pt > 10000) {
398 int_warn(c_token,"linewidth out of range");
399 cgm_linewidth_pt = 1;
405 if (!END_OF_COMMAND) {
406 cgm_plotwidth = (int) real(const_express(&a));
407 if (cgm_plotwidth < 0 || cgm_plotwidth > 10000) {
408 int_warn(c_token,"width out of range");
409 cgm_plotwidth = 6 * 72;
415 string = gp_input_line + token[c_token].start_index;
417 if (string[0] == 'x') { /* set color */
418 unsigned short red, green, blue;
420 if (sscanf(string, "x%2hx%2hx%2hx", &red, &green, &blue ) != 3)
421 int_error(c_token, "invalid color spec, must be xRRGGBB");
422 if (cgm_user_color_count >= cgm_user_color_max) {
423 cgm_user_color_max = cgm_user_color_max*2 + 4;
424 cgm_user_color_table =
425 gp_realloc(cgm_user_color_table,
426 (cgm_user_color_max*3+1)*sizeof(int),
428 /* 1st table entry is the minimum color index value */
429 cgm_user_color_table[0] = 0;
431 cgm_user_color_table[1 + 3*cgm_user_color_count] = red;
432 cgm_user_color_table[2 + 3*cgm_user_color_count] = green;
433 cgm_user_color_table[3 + 3*cgm_user_color_count] = blue;
434 cgm_user_color_count++;
437 if (equals(c_token,"font"))
439 if (isstring(c_token)) {
442 quote_str(cgm_font, c_token, MAX_ID_LEN);
443 comma = strchr(cgm_font,',');
444 if (comma && (1 == sscanf(comma+1,"%d",&cgm_fontsize))) {
447 if (CGM_find_font(cgm_font, strlen(cgm_font),
449 /* insert the font in the font table */
450 size_t l = strlen(cgm_font);
452 for (n=0; cgm_font_data[n].name; n++)
455 struct fontdata *new_font_data;
458 gp_alloc((n + 2)*sizeof(struct fontdata),
460 new_font_data->name = gp_alloc(l+1,"CGM font list");
461 strcpy(new_font_data->name, cgm_font);
462 /* punt, since we don't know the real font width */
463 new_font_data->width = 1.0;
464 for (i = 0; i <= n; i++)
465 new_font_data[i+1] = cgm_font_data[i];
466 cgm_font_data = new_font_data;
471 /* the user is specifying the font size */
472 cgm_fontsize = (int) real(const_express(&a));
480 term->xmax = CGM_SMALL - CGM_MARGIN;
481 term->ymax = CGM_LARGE - CGM_MARGIN;
483 term->xmax = CGM_LARGE - CGM_MARGIN;
484 term->ymax = CGM_SMALL - CGM_MARGIN;
487 { /* cgm_font, cgm_fontsize, and/or term->v_char may have changed */
489 CGM_find_font(cgm_font, strlen(cgm_font), &w);
490 term->v_char = (unsigned int) (cgm_fontsize*CGM_PT);
491 term->h_char = (unsigned int) (cgm_fontsize*CGM_PT*.527*w);
494 sprintf(CGM_default_font, "%s,%d", cgm_font, cgm_fontsize);
495 /* CGM_default_font holds the font and size set at 'set term' */
496 sprintf(term_options, "%s %s %s %s %s width %d linewidth %d \"%s\" %d",
497 cgm_portrait ? "portrait" : "landscape",
498 cgm_monochrome ? "monochrome" : "color",
499 cgm_rotate ? "rotate" : "norotate",
500 cgm_dashed ? "dashed" : "solid",
501 cgm_nofontlist_mode ? "nofontlist" : "",
504 cgm_font, cgm_fontsize);
506 if (cgm_user_color_count) {
507 int i, red, green, blue;
508 for (i = 0; i < cgm_user_color_count &&
509 (strlen(term_options) + 9 < MAX_LINE_LEN); i++) {
510 red = cgm_user_color_table[1 + 3*i];
511 green = cgm_user_color_table[2 + 3*i];
512 blue = cgm_user_color_table[3 + 3*i];
513 sprintf(term_options + strlen(term_options),
514 " x%02x%02x%02x", red, green, blue);
518 if (cgm_user_color_count < CGM_COLORS) {
521 /* fill in colors not set by the user with the default colors */
523 /* 1st table entry is the minimum color index value */
524 cgm_user_color_table = gp_realloc(cgm_user_color_table,
525 (CGM_COLORS * 3 + 1) * sizeof (int), "CGM color table");
526 cgm_user_color_table[0] = 0;
528 for (i = cgm_user_color_count, j = cgm_user_color_count * 3;
529 i < CGM_COLORS; i++, j+=3) {
530 cgm_user_color_table[j+1] = web_color_rgbs[i].r;
531 cgm_user_color_table[j+2] = web_color_rgbs[i].g;
532 cgm_user_color_table[j+3] = web_color_rgbs[i].b;
535 cgm_user_color_count = CGM_COLORS;
544 strcpy(cgm_font, DEFAULT_CGMFONT);
545 CGM_find_font(cgm_font, strlen(cgm_font), &w);
547 term->v_char = (unsigned int) (cgm_fontsize * CGM_PT);
548 term->h_char = (unsigned int) (cgm_fontsize * CGM_PT * .527 * w);
549 cgm_linewidth_pt = 1;
550 cgm_monochrome = FALSE;
551 cgm_plotwidth = 6 * 72;
552 cgm_portrait = FALSE;
555 cgm_nofontlist_mode = FALSE;
556 cgm_current = cgm_reset;
557 cgm_user_color_count = 0;
563 cgm_posx = cgm_posy = 0;
566 cgm_next.interior_style = 1;
567 cgm_next.hatch_index = 1;
568 cgm_polyline = gp_alloc(CGM_MAX_SEGMENTS*sizeof(int), "cgm_polylines");
574 register struct termentry *t = term;
575 static int version_data[] = { 1 };
576 static int vdc_type_data[] = { 0 };
577 static int integer_precision_data[] = { 16 };
578 static int real_precision_data[] = { 1, 16, 16 };
579 static int index_precision_data[] = { 16 };
580 static int color_precision_data[] = { 16 };
581 static int color_index_precision_data[] = { 16 };
582 static int scaling_mode_data[] = { 0, 0, 0 };
583 static int color_value_extent_data[] = { 0, 0, 0, 255, 255, 255 };
584 static int color_selection_mode_data[] = { 0 };
585 static int linewidth_specification_mode_data[] = { 0 };
586 static int edge_width_specification_mode_data[] = { 0 };
587 static int marker_size_specification_mode_data[] = { 0 };
588 static int vdc_extent_data[] = { 0, 0, 0, 0 };
589 static int line_type_data[] = { 1 };
590 static int interior_style_data[] = { 1 }; /* 0=hollow 1=filled
593 static int hatch_index_data[] = { 1 }; /* 1=horizontal 2=vertical
596 * 5=horizontal/vertical
598 * 6=positive/negative
599 * slope crosshatch */
601 static int GPFAR elements_list_data[] =
603 0, /* will be set to # elements in this list */
604 0, 1, /* Begin Metafile */
605 0, 2, /* End Metafile */
606 0, 3, /* Begin Picture */
607 0, 4, /* Begin Picture Body */
608 0, 5, /* End Picture */
609 1, 1, /* Metafile Version */
610 1, 2, /* Metafile Description */
612 1, 4, /* Integer Precision */
613 1, 5, /* Real Precision */
614 1, 6, /* Index Precision */
615 1, 7, /* Color Precision */
616 1, 8, /* Color Index Precision */
617 1, 9, /* Maximum Color Index */
618 1, 10, /* Color Value Extent */
619 1, 13, /* Font List */
620 2, 1, /* Scaling Mode */
621 2, 2, /* Color Selection Mode */
622 2, 3, /* Line Width Specification Mode */
623 2, 4, /* Marker Size Specification Mode */
624 2, 5, /* Edge Width Specification Mode */
625 2, 6, /* VDC Extent */
627 /* disabled due to complaints from CGM import filters */
628 3, 1, /* VDC Integer Precision */
629 3, 4, /* Transparency */
630 3, 6, /* Clip Indicator */
633 4, 3, /* Polymarker */
636 4, 11, /* Rectangle */
638 4, 15, /* Circular Arc Center */
639 4, 16, /* Circular Arc Center Close */
641 4, 18, /* Elliptical Arc */
642 4, 19, /* Elliptical Arc Close */
643 5, 2, /* Line Type */
644 5, 3, /* Line Width */
645 5, 4, /* Line Color */
646 5, 6, /* Marker Type */
647 5, 7, /* Marker Size */
648 5, 8, /* Marker Color */
649 5, 10, /* Text Font Index */
650 5, 14, /* Text Color */
651 5, 15, /* Character Height */
652 5, 16, /* Character Orientation */
653 5, 18, /* Text Alignment */
654 5, 22, /* Interior Style */
655 5, 23, /* Fill Color */
656 5, 24, /* Hatch Index */
657 5, 27, /* Edge Type */
658 5, 28, /* Edge Width */
659 5, 29, /* Edge Color */
660 5, 30, /* Edge Visibility */
661 5, 34, /* Color Table */
663 7, 2 /* Application Data */
666 /* metafile description (class 1), including filename if available */
668 CGM_write_char_record(0, 1, 1, outstr);
670 CGM_write_char_record(0, 1, strlen(outstr) + 1, outstr);
671 CGM_write_int_record(1, 1, 2, version_data);
673 char description_data[256];
674 sprintf(description_data, "\
675 Gnuplot version %s patchlevel %s,\
676 Computer Graphics Metafile version 1 per MIL-D-28003A/BASIC-1.%d",
677 gnuplot_version, gnuplot_patchlevel, cgm_monochrome?0:2);
678 CGM_write_char_record(1, 2, strlen(description_data),
681 elements_list_data[0] = (sizeof(elements_list_data) / CGM_ADJ - 2) / 4;
682 CGM_write_int_record(1, 11, sizeof(elements_list_data) / CGM_ADJ,
684 CGM_write_int_record(1, 3, 2, vdc_type_data);
685 CGM_write_int_record(1, 4, 2, integer_precision_data);
686 CGM_write_int_record(1, 5, 6, real_precision_data);
687 CGM_write_int_record(1, 6, 2, index_precision_data);
688 CGM_write_int_record(1, 7, 2, color_precision_data);
689 CGM_write_int_record(1, 8, 2, color_index_precision_data);
690 CGM_write_int_record(1, 9, 2, &cgm_maximum_color_index);
691 CGM_write_int_record(1, 10, sizeof(color_value_extent_data) / CGM_ADJ,
692 color_value_extent_data);
693 if (cgm_nofontlist_mode == FALSE)
697 for (i = 0; cgm_font_data[i].name; i++)
698 lgh += strlen(cgm_font_data[i].name) + 1;
699 buf = gp_alloc(lgh + 1, "CGM font list");
700 for (s = buf, i = 0; cgm_font_data[i].name; i++)
702 int lgh = strlen(cgm_font_data[i].name);
704 strcpy(s, cgm_font_data[i].name);
707 CGM_write_byte_record(1, 13, lgh, buf);
711 /* picture description (classes 2 and 3) */
712 CGM_write_char_record(0, 3, 8, "PICTURE1");
713 CGM_write_int_record(2, 1, 6, scaling_mode_data);
714 CGM_write_int_record(2, 2, 2, color_selection_mode_data);
715 CGM_write_int_record(2, 3, 2, linewidth_specification_mode_data);
716 CGM_write_int_record(2, 4, 2, marker_size_specification_mode_data);
717 CGM_write_int_record(2, 5, 2, edge_width_specification_mode_data);
718 vdc_extent_data[2] = t->xmax + CGM_MARGIN;
719 vdc_extent_data[3] = t->ymax + CGM_MARGIN;
720 CGM_write_int_record(2, 6, 8, vdc_extent_data);
722 /* picture body (classes 4 and 5) */
723 CGM_write_int_record(0, 4, 0, NULL);
725 #ifdef NEVER /* no need for these, since we accept the defaults */
727 static int vdc_integer_precision_data[] = { 16 };
728 CGM_write_int_record(3, 1, 2, vdc_integer_precision_data);
731 static int transparency_data[] = { 1 }; /* text background:
734 CGM_write_int_record(3, 4, sizeof(transparency_data) / CGM_ADJ,
738 static int clip_indicator_data[] = { 0 };
739 CGM_write_int_record(3, 6, sizeof(clip_indicator_data) / CGM_ADJ,
740 clip_indicator_data);
744 CGM_write_int_record(5, 34, (cgm_user_color_count*3+1)*
745 sizeof(cgm_user_color_table[0])/CGM_ADJ,
746 cgm_user_color_table);
747 CGM_write_int_record(5, 2, sizeof(line_type_data) / CGM_ADJ,
748 line_type_data); /* line type 1=SOLID */
749 cgm_linewidth = cgm_linewidth_pt * CGM_PT;
750 CGM_write_int_record(5, 3, sizeof(cgm_linewidth) / CGM_ADJ,
751 (int *) &cgm_linewidth); /* line width */
752 CGM_write_int_record(5, 28, sizeof(cgm_linewidth) / CGM_ADJ,
753 (int *) &cgm_linewidth); /* edge width */
754 CGM_write_int_record(5, 27, sizeof(line_type_data) / CGM_ADJ,
755 line_type_data); /* edge type 1=SOLID */
758 cgm_current = cgm_reset;
759 cgm_next.char_height = t->v_char;
761 CGM_write_int_record(5, 22, 2, interior_style_data);
762 CGM_write_int_record(5, 24, 2, hatch_index_data);
765 sprintf(buf, "%.31s,%d", cgm_font, cgm_fontsize);
768 CGM_set_pointsize(pointsize);
770 /* Fill with background color if user has specified one */
771 if (!cgm_monochrome && cgm_user_color_count > 0) {
772 CGM_linecolor(LT_BACKGROUND);
773 CGM_fillbox(FS_SOLID, 0, 0, t->xmax, t->ymax);
778 /* Return the index for the font with the name `name'. The index for
779 the first font is 1. Set relwidth to the width of the font,
780 relative to Times Bold Italic. If the font is not in the table,
781 set *relwidth to 1.0 and return 0. */
783 CGM_find_font(const char *name, int numchar, double *relwidth)
787 for (i=0; cgm_font_data[i].name; i++)
788 /* strncasecmp is not standard, but defined by stdfn.c if not available */
789 if (strlen(cgm_font_data[i].name) == numchar &&
790 strncasecmp(name, cgm_font_data[i].name, numchar) == 0)
792 *relwidth = cgm_font_data[i].width;
800 CGM_set_font(const char *font)
802 register struct termentry *t = term;
803 int size, font_index;
804 char *comma = strchr(font, ',');
808 /* Allow null string to indicaute default font */
809 if (!font || !(*font))
810 font = CGM_default_font;
812 /* find font in font table, or use 1st font */
818 font_index = CGM_find_font(font, len, &width);
821 cgm_next.font_index = font_index;
824 char *s = cgm_font_data[font_index-1].name;
829 strncpy(cgm_font, s, len);
836 sscanf(comma + 1, "%d", &size);
837 t->v_char = size * CGM_PT;
838 t->h_char = size * CGM_PT * .527 * width;
840 cgm_next.char_height = t->v_char;
848 CGM_flush_polyline();
849 CGM_write_int_record(0, 5, 0, NULL); /* end picture */
850 CGM_write_int_record(0, 2, 0, NULL); /* end metafile */
854 CGM_linetype(int linetype)
856 if (linetype < LT_NODRAW)
857 linetype = LT_NODRAW;
859 if (linetype == cgm_linetype)
861 cgm_linetype = linetype;
863 CGM_linecolor(linetype);
865 CGM_dashtype(linetype); /* DBT 10-8-98 use dashes */
867 /* dashes for gridlines, solid for everything else */
868 CGM_dashtype(linetype == -1 ? 2 : 0);
873 CGM_linecolor(int linecolor)
875 if (linecolor >= 0) {
876 /* subtract 2 due to linetypes -2 / -1 */
877 if (cgm_linetypes > 3)
878 linecolor %= (cgm_linetypes - 3);
881 } else if (linecolor == LT_BACKGROUND && !cgm_monochrome) {
883 } else if (linecolor <= LT_NODRAW)
888 cgm_color = linecolor = 1;
889 if (linecolor == cgm_color)
891 cgm_color = linecolor;
892 cgm_next.fill_color = linecolor;
894 CGM_flush_polyline();
895 CGM_write_int_record(5, 4, 2, (int *) &cgm_color); /* line color */
896 CGM_write_int_record(5, 14, 2, (int *) &cgm_color); /* text color */
902 unsigned int x1, unsigned int y1,
903 unsigned int width, unsigned int height)
907 corner[0].x = x1; corner[0].y = y1;
908 corner[1].x = x1+width; corner[1].y = y1;
909 corner[2].x = x1+width; corner[2].y = y1+height;
910 corner[3].x = x1; corner[3].y = y1+height;
911 corner[4].x = x1; corner[4].y = y1;
913 corner->style = style;
914 CGM_filled_polygon(5, corner);
918 CGM_linewidth(double width)
925 new_linewidth = width * cgm_linewidth_pt * CGM_PT;
926 if (new_linewidth == cgm_linewidth)
929 CGM_flush_polyline();
931 cgm_linewidth = new_linewidth;
932 CGM_write_int_record(5, 3, sizeof(cgm_linewidth) / CGM_ADJ,
933 (int *) &cgm_linewidth);
934 CGM_dashtype(cgm_dashtype); /* have dash lengths recalculated */
938 CGM_dashtype(int dashtype)
941 /* Each group of 8 entries in dot_length[] defines a dash
942 pattern. Entries in each group are alternately length of
943 whitespace and length of line, in units of 2/3 of the
945 static int dot_length[CGM_LINE_TYPES * 8] =
947 5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes */
948 5, 3, 5, 3, 5, 3, 5, 3, /* 2 - short dashes */
949 4, 1, 4, 1, 4, 1, 4, 1, /* 3 - dotted */
950 4, 8, 4, 1, 4, 8, 4, 1, /* 4 - dash-dot */
951 4, 9, 4, 1, 4, 1, 0, 0, /* 5 - dash-dot-dot */
952 4, 10, 4, 1, 4, 1, 4, 1, /* 6 - dash-dot-dot-dot */
953 4, 10, 4, 10, 4, 1, 0, 0, /* 7 - dash-dash-dot */
954 4, 10, 4, 10, 4, 1, 4, 1}; /* 8 - dash-dash-dot-dot */
957 if (dashtype == cgm_dashtype)
959 cgm_dashtype = dashtype;
961 CGM_flush_polyline();
963 if (dashtype >= CGM_LINE_TYPES)
964 dashtype = dashtype % CGM_LINE_TYPES;
966 term->vector = CGM_solid_vector;
969 term->vector = CGM_dashed_vector;
971 /* set up dash dimensions */
972 j = (dashtype - 1) * 8;
973 for (i = 0; i < 8; i++, j++) {
975 cgm_step_sizes[i] = (dot_length[j] * cgm_linewidth) * 2 / 3;
977 cgm_step_sizes[i] = 0;
979 /* first thing drawn will be a line */
980 cgm_step = cgm_step_sizes[1];
985 CGM_move(unsigned int x, unsigned int y)
992 if (x == cgm_posx && y == cgm_posy)
994 CGM_flush_polyline();
1000 CGM_make_palette(t_sm_palette *palette)
1005 cgm_smooth_colors = palette->colors;
1006 if (CGM_COLORS + cgm_smooth_colors > cgm_user_color_max) {
1007 cgm_user_color_max = CGM_COLORS + cgm_smooth_colors;
1008 cgm_user_color_table =
1009 gp_realloc(cgm_user_color_table,
1010 (cgm_user_color_max*3+1)*sizeof(int),
1013 k = 1 + (CGM_COLORS)*3;
1014 for (i = 0; i < cgm_smooth_colors; i++) {
1015 cgm_user_color_table[k++] = palette->color[i].r*255.9;
1016 cgm_user_color_table[k++] = palette->color[i].g*255.9;
1017 cgm_user_color_table[k++] = palette->color[i].b*255.9;
1019 cgm_user_color_count = CGM_COLORS + cgm_smooth_colors;
1020 CGM_write_int_record(5, 34, (cgm_user_color_count*3+1)*
1021 sizeof(cgm_user_color_table[0])/CGM_ADJ,
1022 cgm_user_color_table);
1025 return (cgm_maximum_color_index - CGM_COLORS);
1030 CGM_set_color(t_colorspec *colorspec)
1032 if (colorspec->type == TC_LT) {
1033 CGM_linecolor(colorspec->lt);
1034 cgm_linetype = colorspec->lt;
1037 } else if (colorspec->type == TC_FRAC) {
1038 double gray = colorspec->value;
1039 /* map [0...1] to interval [0...cgm_smooth_colors-1], then add
1040 offset to get past the default colors */
1041 cgm_next.fill_color = (gray <= 0) ? 0 : (int)(gray * cgm_smooth_colors);
1042 if (cgm_next.fill_color >= cgm_smooth_colors)
1043 cgm_next.fill_color = cgm_smooth_colors - 1;
1044 cgm_next.fill_color += CGM_COLORS;
1046 } else if (colorspec->type == TC_RGB) {
1047 /* To truly support RGB we would have to write a new color table to the */
1048 /* output file every time the RGB matched no previous color. That seems */
1049 /* prohibitive, so instead we just look for the closest match. */
1050 cgm_next.fill_color = CGM_find_nearest_color(colorspec);
1053 /* Should not happen! */
1056 /* EAM - force color immediately so that lines and text can use it */
1057 if (cgm_color != cgm_next.fill_color) {
1058 cgm_color = cgm_next.fill_color;
1059 cgm_linetype = cgm_color;
1060 CGM_flush_polyline();
1061 CGM_write_int_record(5, 4, 2, (int *) &cgm_color); /* line color */
1062 CGM_write_int_record(5, 14, 2, (int *) &cgm_color); /* text color */
1067 CGM_filled_polygon(int points, gpiPoint *corner)
1069 /* Note: This implementation cannot handle polygons with more than
1070 * about 8190 edges. The best fix is to implement continuation
1071 * blocks. If the high order bit of the "length" field of a block
1072 * is set, then it is followed by another block with more data.
1073 * This allows an arbitrary amount of data in a record. However,
1074 * we implement a big enough block that problems should be rare.
1077 /* We will use solid fill for patterns 0 and 3 */
1078 int hatch_index[]={0, 6, 5, 0, 4, 3};
1079 int style = corner->style;
1080 int pattern = (style >> 4) % 6;
1083 switch( style & 0xf ) {
1086 cgm_next.interior_style = 1;
1091 /* FIXME - for unknown reasons, solid fill messes up the subsequent */
1092 /* color state. Just leave it empty and let the background show */
1093 cgm_next.interior_style = 0; /* empty */
1097 /* Fill with solid color */
1098 cgm_next.interior_style = 1;
1102 /* The rest of the patterns are hatch-filled */
1103 cgm_next.interior_style = 3; /* hatched */
1104 cgm_next.hatch_index = hatch_index[pattern];
1107 default: /* style == 0 or unknown --> fill with background color */
1108 cgm_next.fill_color = 0;
1109 cgm_next.interior_style = 1; /* solid */
1113 if (cgm_current.interior_style != cgm_next.interior_style){
1114 cgm_current.interior_style = cgm_next.interior_style;
1115 CGM_write_int_record(5, 22, 2, &cgm_next.interior_style);
1118 if (cgm_current.fill_color != cgm_next.fill_color){
1119 cgm_current.fill_color = cgm_next.fill_color;
1120 CGM_write_int_record(5, 23, 2, &cgm_next.fill_color); /* fill color */
1123 if (cgm_current.hatch_index != cgm_next.hatch_index &&
1124 cgm_next.interior_style == 3){
1125 cgm_current.hatch_index = cgm_next.hatch_index;
1126 CGM_write_int_record(5, 24, 2, &cgm_next.hatch_index);
1129 cgm_next.edge_visibility = 0; /* We draw the borders elsewhere */
1130 if (cgm_current.edge_visibility != cgm_next.edge_visibility){
1131 cgm_current.edge_visibility = cgm_next.edge_visibility;
1132 CGM_write_int_record(5, 30, 2, &cgm_current.edge_visibility);
1135 CGM_move(corner[0].x, corner[0].y);
1136 cgm_doing_polygon = 1;
1137 for (i = 1; i < points; i++)
1138 CGM_solid_vector(corner[i].x, corner[i].y);
1139 CGM_flush_polygon();
1140 cgm_doing_polygon = 0;
1144 CGM_flush_polyline()
1146 if (cgm_coords == 0)
1148 CGM_write_int_record(4, 1, cgm_coords * 2, cgm_polyline);
1153 CGM_write_char_record(int class, int cgm_id, int numbytes, char *data)
1156 static unsigned char flag = 0xff;
1157 static unsigned char paddata = 0;
1161 length = numbytes + 1;
1162 if (numbytes >= 255)
1163 length += 2; /* long string */
1165 pad = 1; /* needs pad */
1166 CGM_write_code(class, cgm_id, length);
1169 short_len = (char)numbytes;
1170 fwrite(&short_len, 1, 1, gpoutfile); /* write true length */
1172 fwrite(&flag, 1, 1, gpoutfile);
1173 CGM_write_int(numbytes);
1177 fwrite(data, 1, numbytes, gpoutfile); /* write string */
1179 for (i=0; i<numbytes+pad; i++)
1180 fputc('\0', gpoutfile); /* write null bytes */
1183 fwrite(&paddata, 1, 1, gpoutfile);
1187 CGM_write_byte_record(int class, int cgm_id, int numbytes, char *data)
1190 static unsigned char paddata = 0;
1193 CGM_write_code(class, cgm_id, numbytes);
1194 fwrite(data, 1, numbytes, gpoutfile); /* write string */
1196 fwrite(&paddata, 1, 1, gpoutfile);
1200 CGM_write_int_record(int class, int cgm_id, int numbytes, int *data)
1203 assert((numbytes & 1) == 0);
1204 CGM_write_code(class, cgm_id, numbytes);
1206 for (i = 0; i < numbytes; i++)
1207 CGM_write_int(data[i]);
1211 CGM_write_mixed_record(
1212 int class, int cgm_id,
1213 int numint, int *int_data,
1214 int numchar, const char *char_data)
1217 static unsigned char paddata = 0;
1218 static unsigned char flag = 0xff;
1222 length = numchar + 1;
1224 length += 2; /* long string */
1226 pad = 1; /* needs pad */
1228 CGM_write_code(class, cgm_id, numint * 2 + length);
1230 for (i = 0; i < numint; i++)
1231 CGM_write_int(int_data[i]); /* write integers */
1233 if (numchar < 255) {
1234 short_len = (char)numchar;
1235 fwrite(&short_len, 1, 1, gpoutfile); /* write string length */
1237 fwrite(&flag, 1, 1, gpoutfile);
1238 CGM_write_int(numchar);
1240 fwrite(char_data, 1, numchar, gpoutfile); /* write string */
1242 fwrite(&paddata, 1, 1, gpoutfile);
1246 Write the code word that starts a CGM record.
1247 bits in code word are as follows...
1250 cccc is a 4-bit class number
1251 iiiiiii is a 7-bit ID number
1252 lllll is a 5-bit length (# bytes following the code word, or
1253 31 followed by a word with the actual number)
1256 CGM_write_code(int class, int cgm_id, int length)
1260 assert((0 <= class) &&(class <16));
1261 assert((0 <= cgm_id) && (cgm_id < 128));
1262 assert(0 <= length);
1264 code = ((class &0x0f) <<12) |
1265 ((cgm_id & 0x7f) << 5) |
1267 CGM_write_int(code);
1269 code = ((class &0x0f) <<12) |
1270 ((cgm_id & 0x7f) << 5) |
1272 CGM_write_int(code);
1273 CGM_write_int(length);
1278 CGM_write_int(int value)
1285 #if !defined(DOS16) && !defined(WIN16)
1286 assert( -32768 <= value );
1287 assert( value <= 32767 );
1290 u.c[0] = (value >> 8) & 255; /* convert to network order */
1291 u.c[1] = value & 255;
1293 fwrite(&u.s, 1, 2, gpoutfile);
1296 /* Draw a dashed line to (ux,uy). CGM has linestyles, but they are
1297 * not usable -- at least with the Word for Windows 6.0 filter, where
1298 * lines of significant width (even 1 pt) always come out solid.
1299 * Therefore, we implement dashed lines here instead. */
1301 CGM_dashed_vector(unsigned int ux, unsigned int uy)
1304 int dx, dy, adx, ady;
1305 int dist; /* approximate distance in plot units
1306 from starting point to specified end
1308 long remain; /* approximate distance in plot units
1309 remaining to specified end point. */
1311 if (ux >= term->xmax)
1313 if (uy >= term->ymax)
1316 dx = (ux - cgm_posx);
1317 dy = (uy - cgm_posy);
1321 /* using the approximation
1322 sqrt(x**2 + y**2) ~ x + (5*x*x)/(12*y) when x > y.
1323 Note ordering of calculations to avoid overflow on 16 bit
1326 dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5;
1330 dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10;
1335 while (remain > cgm_step) {
1337 if (cgm_step_index & 1)
1338 CGM_solid_vector((int) (ux - (remain * dx) / dist),
1339 (int) (uy - (remain * dy) / dist));
1341 xa = (int) (ux - (remain * dx) / dist);
1342 ya = (int) (uy - (remain * dy) / dist);
1345 if (++cgm_step_index >= 8)
1347 cgm_step = cgm_step_sizes[cgm_step_index];
1349 if (cgm_step_index & 1)
1350 CGM_solid_vector(ux, uy);
1353 cgm_step -= (int) remain;
1357 CGM_solid_vector(unsigned int ux, unsigned int uy)
1359 if (ux >= term->xmax)
1361 if (uy >= term->ymax)
1364 if (ux == cgm_posx && uy == cgm_posy)
1366 if (cgm_coords > CGM_MAX_SEGMENTS - 2) {
1367 if (cgm_doing_polygon)
1368 CGM_flush_polygon();
1370 CGM_flush_polyline();
1371 cgm_polyline[cgm_coords++] = cgm_posx;
1372 cgm_polyline[cgm_coords++] = cgm_posy + CGM_MARGIN;
1373 } else if (cgm_coords == 0) {
1374 cgm_polyline[cgm_coords++] = cgm_posx;
1375 cgm_polyline[cgm_coords++] = cgm_posy + CGM_MARGIN;
1377 cgm_polyline[cgm_coords++] = ux;
1378 cgm_polyline[cgm_coords++] = uy + CGM_MARGIN;
1384 CGM_put_text(unsigned int x, unsigned int y, const char str[])
1386 static int where[3] = { 0, 0, 1 }; /* the final "1" signals that
1387 this is the last text in the
1389 const char *s = str;
1391 /* sanity check - labels are not clipped */
1392 if ((x > 32767) || (y > 32767))
1396 if (!isspace((unsigned char) *s++))
1402 CGM_flush_polyline();
1404 /* update the text characteristics if they have changed since the
1405 last text string was output */
1406 if (cgm_current.font_index != cgm_next.font_index) {
1407 cgm_current.font_index = cgm_next.font_index;
1408 CGM_write_int_record(5, 10, 2, &cgm_next.font_index);
1410 if (cgm_current.justify_mode != cgm_next.justify_mode) {
1411 static int data[6] = { 1, 3, 0, 0, 0, 0 };
1412 cgm_current.justify_mode = cgm_next.justify_mode;
1414 switch (cgm_current.justify_mode) {
1427 CGM_write_int_record(5, 18, 12, data);
1430 if (cgm_current.char_height != cgm_next.char_height) {
1431 int h = cgm_next.char_height;
1432 cgm_current.char_height = h;
1433 h = h*2/3; /* gnuplot measures fonts by the
1434 baseline-to-baseline distance,
1435 while the CGM file needs the actual
1436 height of the upper case
1438 CGM_write_int_record(5, 15, 2, &h);
1441 /* "angle" is the angle of the text baseline (counter-clockwise in
1442 radians from horizontal). This is a bit more general than
1443 gnuplot needs right now. */
1444 if (cgm_current.angle != cgm_next.angle) {
1445 /* The first two elements of orient are components of a vector
1446 "upward" with respect to the text. The next two elements are
1447 components of a vector along the baseline of the text. The
1448 lengths of both vectors are equal to the baseline-to-baseline
1449 distance in plot units. */
1450 static int orient[4];
1451 cgm_current.angle = cgm_next.angle;
1453 orient[0] = (int)cgm_next.char_height*cos(cgm_next.angle+M_PI_2);
1454 orient[1] = (int)cgm_next.char_height*sin(cgm_next.angle+M_PI_2);
1455 orient[2] = (int)cgm_next.char_height*cos(cgm_next.angle);
1456 orient[3] = (int)cgm_next.char_height*sin(cgm_next.angle);
1457 CGM_write_int_record(5, 16, 8, orient);
1461 where[1] = y + CGM_MARGIN;
1462 CGM_write_mixed_record(4, 4, 3, where, strlen(str), str);
1464 cgm_posx = cgm_posy = -2000;
1468 CGM_text_angle(int ang)
1471 cgm_next.angle = ang * M_PI_2 / 90.;
1474 return ang ? FALSE : TRUE;
1478 CGM_justify_text(enum JUSTIFY mode)
1480 cgm_next.justify_mode = mode;
1487 cgm_posx = cgm_posy = 0;
1492 CGM_point(unsigned int x, unsigned int y, int number)
1496 if (number < 0) { /* draw dot */
1498 CGM_solid_vector(x + 1, y);
1501 number %= CGM_POINTS;
1503 CGM_flush_polyline();
1504 old_dashtype = cgm_dashtype;
1506 if (number >= 3) /* using a polygon */
1507 cgm_next.interior_style = 1; /* solid */
1508 if (number == 4 || number == 6 || number == 8
1509 || number == 10 || number == 12) {
1511 cgm_next.edge_visibility = 0;
1512 cgm_next.fill_color = cgm_color;
1515 cgm_next.edge_visibility = 1;
1516 cgm_next.interior_style = 0; /* empty */
1517 cgm_next.edge_color = cgm_color;
1520 if (cgm_current.interior_style != cgm_next.interior_style){
1521 cgm_current.interior_style = cgm_next.interior_style;
1522 CGM_write_int_record(5, 22, 2, &cgm_next.interior_style);
1524 if (cgm_current.fill_color != cgm_next.fill_color){
1525 cgm_current.fill_color = cgm_next.fill_color;
1526 CGM_write_int_record(5, 23, 2, &cgm_next.fill_color);
1528 if (cgm_current.edge_visibility != cgm_next.edge_visibility){
1529 cgm_current.edge_visibility = cgm_next.edge_visibility;
1530 CGM_write_int_record(5, 30, 2, &cgm_current.edge_visibility);
1532 if (cgm_current.edge_visibility &&
1533 cgm_current.edge_color != cgm_next.edge_color){
1534 cgm_current.edge_color = cgm_next.edge_color;
1535 CGM_write_int_record(5, 29, 2, &cgm_current.edge_color);
1539 case 0: /* draw plus */
1540 CGM_move(x - cgm_tic, y);
1541 CGM_solid_vector(x + cgm_tic, y);
1542 CGM_move(x, y - cgm_tic);
1543 CGM_solid_vector(x, y + cgm_tic);
1545 case 1: /* draw X */
1546 CGM_move(x - cgm_tic707, y - cgm_tic707);
1547 CGM_solid_vector(x + cgm_tic707, y + cgm_tic707);
1548 CGM_move(x - cgm_tic707, y + cgm_tic707);
1549 CGM_solid_vector(x + cgm_tic707, y - cgm_tic707);
1551 case 2: /* draw star (asterisk) */
1552 CGM_move(x, y - cgm_tic);
1553 CGM_solid_vector(x, y + cgm_tic);
1554 CGM_move(x + cgm_tic866, y - cgm_tic500);
1555 CGM_solid_vector(x - cgm_tic866, y + cgm_tic500);
1556 CGM_move(x + cgm_tic866, y + cgm_tic500);
1557 CGM_solid_vector(x - cgm_tic866, y - cgm_tic500);
1559 case 3: /* draw box */
1561 CGM_move(x - cgm_tic707, y - cgm_tic707);
1562 CGM_solid_vector(x + cgm_tic707, y - cgm_tic707);
1563 CGM_solid_vector(x + cgm_tic707, y + cgm_tic707);
1564 CGM_solid_vector(x - cgm_tic707, y + cgm_tic707);
1565 CGM_flush_polygon();
1568 case 6: /* draw circle (actually, dodecagon)
1569 (WinWord 6 accepts the CGM "circle"
1570 element, but the resulting circle
1571 is not correctly centered!) */
1572 CGM_move(x, y - cgm_tic);
1573 CGM_solid_vector(x + cgm_tic500, y - cgm_tic866);
1574 CGM_solid_vector(x + cgm_tic866, y - cgm_tic500);
1575 CGM_solid_vector(x + cgm_tic, y);
1576 CGM_solid_vector(x + cgm_tic866, y + cgm_tic500);
1577 CGM_solid_vector(x + cgm_tic500, y + cgm_tic866);
1578 CGM_solid_vector(x, y + cgm_tic);
1579 CGM_solid_vector(x - cgm_tic500, y + cgm_tic866);
1580 CGM_solid_vector(x - cgm_tic866, y + cgm_tic500);
1581 CGM_solid_vector(x - cgm_tic, y);
1582 CGM_solid_vector(x - cgm_tic866, y - cgm_tic500);
1583 CGM_solid_vector(x - cgm_tic500, y - cgm_tic866);
1584 CGM_flush_polygon();
1586 case 7: /* draw triangle (point up) */
1588 CGM_move(x, y + cgm_tic1241);
1589 CGM_solid_vector(x - cgm_tic1077, y - cgm_tic621);
1590 CGM_solid_vector(x + cgm_tic1077, y - cgm_tic621);
1591 CGM_flush_polygon();
1593 case 9: /* draw triangle (point down) */
1595 CGM_move(x, y - cgm_tic1241);
1596 CGM_solid_vector(x - cgm_tic1077, y + cgm_tic621);
1597 CGM_solid_vector(x + cgm_tic1077, y + cgm_tic621);
1598 CGM_flush_polygon();
1600 case 11: /* draw diamond */
1602 CGM_move(x - cgm_tic, y);
1603 CGM_solid_vector(x, y - cgm_tic);
1604 CGM_solid_vector(x + cgm_tic, y);
1605 CGM_solid_vector(x, y + cgm_tic);
1606 CGM_flush_polygon();
1609 CGM_dashtype(old_dashtype);
1614 CGM_set_pointsize(double size)
1616 /* Markers were chosen to have approximately equal
1617 areas. Dimensions are as follows, in units of
1620 plus, diamond: half height = 1
1622 square, cross: half height = sqrt(1/2) ~ 12/17
1624 triangle: half width = sqrt(sqrt(4/3)) ~ 14/13,
1625 height = sqrt(3*sqrt(4/3)) ~ 54/29
1627 star: half height = 1, half width = sqrt(3/4) ~ 13/15
1629 dodecagon: coordinates of vertices are 0,
1630 sin(30) = 1/2, cos(30) = sqrt(3/4) ~ 13/15, or 1
1632 The fractions are approximates of the equivalent
1633 continued fractions. */
1636 cgm_tic = (size * term->h_tic / 2);
1637 cgm_tic707 = cgm_tic * 12 / 17;
1638 cgm_tic866 = cgm_tic * 13 / 15;
1639 cgm_tic500 = cgm_tic / 2;
1640 cgm_tic1241 = cgm_tic * 36 / 29;
1641 cgm_tic1077 = cgm_tic * 14 / 13;
1642 cgm_tic621 = cgm_tic * 18 / 29;
1648 if (cgm_coords == 0)
1650 CGM_write_int_record(4, 7, cgm_coords * 2, cgm_polyline);
1655 * This terminal driver does not support true RGB color,
1656 * but we can at least try to find some reasonable approximation.
1658 #define CLOSE_ENOUGH 32 /* 0 would require a perfect match */
1660 CGM_find_nearest_color(t_colorspec *colorspec)
1662 int red = (colorspec->lt >> 16) & 0xff;
1663 int green = (colorspec->lt >> 8) & 0xff;
1664 int blue = colorspec->lt & 0xff;
1666 int howclose = 1<<16;
1669 int dr, dg, db, distance;
1671 for (k=0; k<cgm_user_color_max; k++) {
1672 dr = cgm_user_color_table[++i] - red;
1673 dg = cgm_user_color_table[++i] - green;
1674 db = cgm_user_color_table[++i] - blue;
1675 distance = (dr*dr + dg*dg + db*db);
1676 if (distance < howclose) {
1678 howclose = distance;
1680 if (distance < CLOSE_ENOUGH)
1684 FPRINTF((stderr,"CGM_find_nearest_color: asked for %d %d %d\n",red,green,blue));
1685 FPRINTF((stderr," got index %3d %d %d %d\n", closest,
1686 cgm_user_color_table[closest*3], cgm_user_color_table[closest*3+1],
1687 cgm_user_color_table[closest*3+2]));
1693 #ifdef DEFEAT_ASSERTIONS
1696 #undef DEFEAT_ASSERTIONS
1697 #endif /* DEFEAT_ASSERTIONS */
1704 #endif /* TERM_BODY */
1707 TERM_TABLE_START(cgm_driver)
1708 "cgm", "Computer Graphics Metafile",
1709 CGM_LARGE - CGM_MARGIN, CGM_SMALL - CGM_MARGIN, CGM_VCHAR, CGM_HCHAR,
1710 CGM_VTIC, CGM_HTIC, CGM_options, CGM_init, CGM_reset,
1711 CGM_text, null_scale, CGM_graphics, CGM_move, CGM_solid_vector,
1712 CGM_linetype, CGM_put_text, CGM_text_angle,
1713 CGM_justify_text, CGM_point, do_arrow, CGM_set_font,
1715 TERM_BINARY, /* various flags */
1716 NULL, /* after one plot of multiplot */
1717 NULL, /* before subsequent plot of multiplot */
1721 , NULL, NULL, NULL, NULL, NULL
1722 /* , waitforinput, put_tmptext, set_ruler, set_cursor, set_clipboard */
1725 NULL /* _previous_palette */,
1728 TERM_TABLE_END(cgm_driver)
1731 #define LAST_TERM cgm_driver
1733 #endif /* TERM_TABLE */
1734 #endif /* TERM_PROTO_ONLY */
1739 "?commands set terminal cgm",
1740 "?set terminal cgm",
1745 " The `cgm` terminal generates a Computer Graphics Metafile, Version 1. ",
1746 " This file format is a subset of the ANSI X3.122-1986 standard entitled",
1747 " \"Computer Graphics - Metafile for the Storage and Transfer of Picture",
1748 " Description Information\".",
1751 " set terminal cgm {color | monochrome} {solid | dashed} {{no}rotate}",
1752 " {<mode>} {width <plot_width>} {linewidth <line_width>}",
1753 " {font \"<fontname>,<fontsize>\"}",
1754 " {<color0> <color1> <color2> ...}",
1756 " `solid` draws all curves with solid lines, overriding any dashed patterns;",
1757 " <mode> is `landscape`, `portrait`, or `default`;",
1758 " <plot_width> is the assumed width of the plot in points; ",
1759 " <line_width> is the line width in points (default 1); ",
1760 " <fontname> is the name of a font (see list of fonts below)",
1761 " <fontsize> is the size of the font in points (default 12).",
1763 " The first six options can be in any order. Selecting `default` sets all",
1764 " options to their default values.",
1766 " Each color must be of the form 'xrrggbb', where x is the literal",
1767 " character 'x' and 'rrggbb' are the red, green and blue components in",
1768 " hex. For example, 'x00ff00' is green. The background color is set",
1769 " first, then the plotting colors.",
1772 " set terminal cgm landscape color rotate dashed width 432 \\",
1773 " linewidth 1 'Helvetica Bold' 12 # defaults",
1774 " set terminal cgm linewidth 2 14 # wider lines & larger font",
1775 " set terminal cgm portrait \"Times Italic\" 12",
1776 " set terminal cgm color solid # no pesky dashes!",
1779 "?commands set terminal cgm font",
1780 "?set terminal cgm font",
1781 "?set term cgm font",
1783 " The first part of a Computer Graphics Metafile, the metafile description,",
1784 " includes a font table. In the picture body, a font is designated by an",
1785 " index into this table. By default, this terminal generates a table with",
1786 " the following 35 fonts, plus six more with `italic` replaced by",
1787 " `oblique`, or vice-versa (since at least the Microsoft Office and Corel",
1788 " Draw CGM import filters treat `italic` and `oblique` as equivalent):",
1789 "@start table - first is interactive cleartext form",
1792 " Helvetica Oblique",
1793 " Helvetica Bold Oblique",
1797 " Times Bold Italic",
1801 " Courier Bold Oblique",
1803 " Hershey/Cartographic_Roman",
1804 " Hershey/Cartographic_Greek",
1805 " Hershey/Simplex_Roman",
1806 " Hershey/Simplex_Greek",
1807 " Hershey/Simplex_Script",
1808 " Hershey/Complex_Roman",
1809 " Hershey/Complex_Greek",
1810 " Hershey/Complex_Script",
1811 " Hershey/Complex_Italic",
1812 " Hershey/Complex_Cyrillic",
1813 " Hershey/Duplex_Roman",
1814 " Hershey/Triplex_Roman",
1815 " Hershey/Triplex_Italic",
1816 " Hershey/Gothic_German",
1817 " Hershey/Gothic_English",
1818 " Hershey/Gothic_Italian",
1819 " Hershey/Symbol_Set_1",
1820 " Hershey/Symbol_Set_2",
1821 " Hershey/Symbol_Math",
1825 "#\\begin{tabular}{|ccl|} \\hline",
1826 "#\\multicolumn{3}{|c|}{CGM fonts}\\\\",
1828 "#&Helvetica Bold&\\\\",
1829 "#&Helvetica Oblique&\\\\",
1830 "#&Helvetica Bold Oblique&\\\\",
1831 "#&Times Roman&\\\\",
1832 "#&Times Bold&\\\\",
1833 "#&Times Italic&\\\\",
1834 "#&Times Bold Italic&\\\\",
1836 "#&Courier Bold&\\\\",
1837 "#&Courier Oblique&\\\\",
1838 "#&Courier Bold Oblique&\\\\",
1840 "#&Hershey/Cartographic\\_Roman&\\\\",
1841 "#&Hershey/Cartographic\\_Greek&\\\\",
1842 "#&Hershey/Simplex\\_Roman&\\\\",
1843 "#&Hershey/Simplex\\_Greek&\\\\",
1844 "#&Hershey/Simplex\\_Script&\\\\",
1845 "#&Hershey/Complex\\_Roman&\\\\",
1846 "#&Hershey/Complex\\_Greek&\\\\",
1847 "#&Hershey/Complex\\_Script&\\\\",
1848 "#&Hershey/Complex\\_Italic&\\\\",
1849 "#&Hershey/Complex\\_Cyrillic&\\\\",
1850 "#&Hershey/Duplex\\_Roman&\\\\",
1851 "#&Hershey/Triplex\\_Roman&\\\\",
1852 "#&Hershey/Triplex\\_Italic&\\\\",
1853 "#&Hershey/Gothic\\_German&\\\\",
1854 "#&Hershey/Gothic\\_English&\\\\",
1855 "#&Hershey/Gothic\\_Italian&\\\\",
1856 "#&Hershey/Symbol\\_Set\\_1&\\\\",
1857 "#&Hershey/Symbol\\_Set\\_2&\\\\",
1858 "#&Hershey/Symbol\\_Math&\\\\",
1859 "#&ZapfDingbats&\\\\",
1866 "%@@Helvetica Bold",
1867 "%@@Helvetica Oblique",
1868 "%@@Helvetica Bold Oblique",
1872 "%@@Times Bold Italic",
1875 "%@@Courier Oblique",
1876 "%@@Courier Bold Oblique",
1878 "%@@Hershey/Cartographic_Roman",
1879 "%@@Hershey/Cartographic_Greek",
1880 "%@@Hershey/Simplex_Roman",
1881 "%@@Hershey/Simplex_Greek",
1882 "%@@Hershey/Simplex_Script",
1883 "%@@Hershey/Complex_Roman",
1884 "%@@Hershey/Complex_Greek",
1885 "%@@Hershey/Complex_Script",
1886 "%@@Hershey/Complex_Italic",
1887 "%@@Hershey/Complex_Cyrillic",
1888 "%@@Hershey/Duplex_Roman",
1889 "%@@Hershey/Triplex_Roman",
1890 "%@@Hershey/Triplex_Italic",
1891 "%@@Hershey/Gothic_German",
1892 "%@@Hershey/Gothic_English",
1893 "%@@Hershey/Gothic_Italian",
1894 "%@@Hershey/Symbol_Set_1",
1895 "%@@Hershey/Symbol_Set_2",
1896 "%@@Hershey/Symbol_Math",
1902 " The first thirteen of these fonts are required for WebCGM. The",
1903 " Microsoft Office CGM import filter implements the 13 standard fonts",
1904 " listed above, and also 'ZapfDingbats' and 'Script'. However, the",
1905 " script font may only be accessed under the name '15'. For more on",
1906 " Microsoft import filter font substitutions, check its help file which",
1907 " you may find here:",
1908 " C:\\Program Files\\Microsoft Office\\Office\\Cgmimp32.hlp",
1909 " and/or its configuration file, which you may find here:",
1910 " C:\\Program Files\\Common Files\\Microsoft Shared\\Grphflt\\Cgmimp32.cfg",
1912 " In the `set term` command, you may specify a font name which does not",
1913 " appear in the default font table. In that case, a new font table is",
1914 " constructed with the specified font as its first entry. You must ensure",
1915 " that the spelling, capitalization, and spacing of the name are",
1916 " appropriate for the application that will read the CGM file. (Gnuplot",
1917 " and any MIL-D-28003A compliant application ignore case in font names.)",
1918 " If you need to add several new fonts, use several `set term` commands.",
1921 " set terminal cgm 'Old English'",
1922 " set terminal cgm 'Tengwar'",
1923 " set terminal cgm 'Arabic'",
1924 " set output 'myfile.cgm'",
1928 " You cannot introduce a new font in a `set label` command.",
1931 "?commands set terminal cgm fontsize",
1932 "?set terminal cgm fontsize",
1933 "?set term cgm fontsize",
1935 " Fonts are scaled assuming the page is 6 inches wide. If the `size`",
1936 " command is used to change the aspect ratio of the page or the CGM file",
1937 " is converted to a different width, the resulting font sizes will be",
1938 " scaled up or down accordingly. To change the assumed width, use the",
1942 "?commands set terminal cgm linewidth",
1943 "?set terminal cgm linewidth",
1944 "?set term cgm linewidth",
1946 " The `linewidth` option sets the width of lines in pt. The default width",
1947 " is 1 pt. Scaling is affected by the actual width of the page, as",
1948 " discussed under the `fontsize` and `width` options.",
1951 "?commands set terminal cgm rotate",
1952 "?set terminal cgm rotate",
1953 "?set term cgm rotate",
1955 " The `norotate` option may be used to disable text rotation. For",
1956 " example, the CGM input filter for Word for Windows 6.0c can accept",
1957 " rotated text, but the DRAW editor within Word cannot. If you edit a",
1958 " graph (for example, to label a curve), all rotated text is restored to",
1959 " horizontal. The Y axis label will then extend beyond the clip boundary.",
1960 " With `norotate`, the Y axis label starts in a less attractive location,",
1961 " but the page can be edited without damage. The `rotate` option confirms",
1962 " the default behavior.",
1965 "?set terminal cgm solid",
1966 "?set term cgm solid",
1968 " The `solid` option may be used to disable dashed line styles in the",
1969 " plots. This is useful when color is enabled and the dashing of the",
1970 " lines detracts from the appearance of the plot. The `dashed` option",
1971 " confirms the default behavior, which gives a different dash pattern to",
1975 "?commands set terminal cgm size",
1976 "?set terminal cgm size",
1977 "?set term cgm size",
1979 " Default size of a CGM plot is 32599 units wide and 23457 units high for",
1980 " landscape, or 23457 units wide by 32599 units high for portrait.",
1983 "?commands set terminal cgm width",
1984 "?set terminal cgm width",
1985 "?set term cgm width",
1987 " All distances in the CGM file are in abstract units. The application",
1988 " that reads the file determines the size of the final plot. By default,",
1989 " the width of the final plot is assumed to be 6 inches (15.24 cm). This",
1990 " distance is used to calculate the correct font size, and may be changed",
1991 " with the `width` option. The keyword should be followed by the width in",
1992 " points. (Here, a point is 1/72 inch, as in PostScript. This unit is",
1993 " known as a \"big point\" in TeX.) Gnuplot `expressions` can be used to",
1994 " convert from other units.",
1997 " set terminal cgm width 432 # default",
1998 " set terminal cgm width 6*72 # same as above",
1999 " set terminal cgm width 10/2.54*72 # 10 cm wide",
2002 "?commands set terminal cgm nofontlist",
2003 "?set terminal cgm nofontlist",
2004 "?set term cgm nofontlist",
2006 "?set terminal cgm winword6",
2007 "?set term cgm winword6",
2009 " The default font table includes the fonts recommended for WebCGM, which",
2010 " are compatible with the Computer Graphics Metafile input filter for",
2011 " Microsoft Office and Corel Draw. Another application might use",
2012 " different fonts and/or different font names, which may not be",
2013 " documented. The `nofontlist` (synonym `winword6`) option deletes the font",
2014 " table from the CGM file. In this case, the reading application should",
2015 " use a default table. Gnuplot will still use its own default font table",
2016 " to select font indices. Thus, 'Helvetica' will give you an index of 1,",
2017 " which should get you the first entry in your application's default font",
2018 " table. 'Helvetica Bold' will give you its second entry, etc.",
2022 #endif /* TERM_HELP */
2028 * eval: (c-set-style "k&r")