/* output-fig.c - output autotrace splines in FIG 3.2 format Copyright (C) 1999, 2000, 2001 Ian MacPhedran This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Def: HAVE_CONFIG_H */ #include "output-fig.h" #include "xstd.h" #include "color.h" #include "spline.h" /* use FIG_X and FIG_Y to convert from local units (pixels) to FIG ones */ /* assume 1 pixel is equal to 1/80 inches (old FIG unit) */ /* Offset by 300 units (1/4 inch) */ #define FIG_X(x) (int)((x * 15.0) + 300.0) #define FIG_Y(y) (int)(((ury - y) * 15.0) + 300.0) /* the basic colours */ #define FIG_BLACK 0 #define FIG_BLUE 1 #define FIG_GREEN 2 #define FIG_CYAN 3 #define FIG_RED 4 #define FIG_MAGENTA 5 #define FIG_YELLOW 6 #define FIG_WHITE 7 static at_real bezpnt(at_real, at_real, at_real, at_real, at_real); static void out_fig_splines(FILE *, spline_list_array_type, int, int, int, int, at_exception_type *); static int get_fig_colour(color_type, at_exception_type *); static void fig_col_init(void); /* colour information */ #define fig_col_hash(col_typ) ( ( (col_typ).r & 255 ) + ( (col_typ).g & 161 ) + ( (col_typ).b & 127 ) ) static struct { unsigned int colour; unsigned int alternate; } fig_hash[544]; static struct { unsigned char r,g,b; int alternate; } fig_colour_map[544]; static int LAST_FIG_COLOUR=32; #define MAX_FIG_COLOUR 543 /* Bounding Box data and routines */ static float glob_min_x, glob_max_x, glob_min_y, glob_max_y; static float loc_min_x, loc_max_x, loc_min_y, loc_max_y; static int glo_bbox_flag=0,loc_bbox_flag=0,fig_depth; static void fig_new_depth() { if (glo_bbox_flag == 0) { glob_max_y = loc_max_y ; glob_min_y = loc_min_y ; glob_max_y = loc_max_y ; glob_min_y = loc_min_y ; glob_max_x = loc_max_x ; glob_min_x = loc_min_x ; glo_bbox_flag = 1; } else { if ((loc_max_y <= glob_min_y) || (loc_min_y >= glob_max_y) || (loc_max_x <= glob_min_x) || (loc_min_x >= glob_max_x)) { /* outside global bounds, increase global box */ if (loc_max_y > glob_max_y) glob_max_y = loc_max_y ; if (loc_min_y < glob_min_y) glob_min_y = loc_min_y ; if (loc_max_x > glob_max_x) glob_max_x = loc_max_x ; if (loc_min_x < glob_min_x) glob_min_x = loc_min_x ; } else { /* inside global bounds, decrease depth and create new bounds */ glob_max_y = loc_max_y ; glob_min_y = loc_min_y ; glob_max_x = loc_max_x ; glob_min_x = loc_min_x ; if (fig_depth) fig_depth--; // don't let it get < 0 } } loc_bbox_flag = 0; } static void fig_addtobbox(float x, float y) { if (loc_bbox_flag == 0) { loc_max_y = y ; loc_min_y = y ; loc_max_x = x ; loc_min_x = x ; loc_bbox_flag = 1; } else { if (loc_max_y < y) loc_max_y = y ; if (loc_min_y > y) loc_min_y = y ; if (loc_max_x < x) loc_max_x = x ; if (loc_min_x > x) loc_min_x = x ; } } /* Convert Bezier Spline */ static at_real bezpnt(at_real t, at_real z1, at_real z2, at_real z3, at_real z4) { at_real temp, t1; /* Determine ordinate on Bezier curve at length "t" on curve */ if (t < (at_real) 0.0) { t = (at_real) 0.0; } if (t > (at_real) 1.0) { t = (at_real) 1.0; } t1 = ((at_real) 1.0 - t); temp = t1*t1*t1*z1 + (at_real)3.0*t*t1*t1*z2 + (at_real)3.0*t*t*t1*z3 + t*t*t*z4; return(temp); } static void out_fig_splines(FILE * file, spline_list_array_type shape, int llx, int lly, int urx, int ury, at_exception_type * exp) { unsigned this_list; /* int fig_colour, fig_depth, i; */ int fig_colour, fig_fill, fig_width, fig_subt, fig_spline_close, i; int *spline_colours; /* add an array of colours for splines (one for each group) create palette hash */ /* Need to create hash table for colours */ XMALLOC(spline_colours, (sizeof(int)*SPLINE_LIST_ARRAY_LENGTH(shape))); /* Preload the big 8 */ fig_col_init(); /* Load the colours from the splines */ for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape); this_list++) { spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list); color_type curr_color = (list.clockwise && shape.background_color != NULL) ? *(shape.background_color) : list.color; spline_colours[this_list] = get_fig_colour(curr_color, exp); } /* Output colours */ if (LAST_FIG_COLOUR > 32) { for (i=32; i 999) { fig_depth = 999; } for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape); this_list++) { unsigned this_spline; spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list); /* store the spline points in two arrays, control weights in another */ int *pointx, *pointy; at_real *contrl; int pointcount=0,is_spline=0,j; int maxlength=SPLINE_LIST_LENGTH (list) * 5 + 1; XMALLOC (pointx, maxlength * sizeof (int)); XMALLOC (pointy, maxlength * sizeof (int)); XMALLOC (contrl, maxlength * sizeof (at_real)); if (list.clockwise) { fig_colour = FIG_WHITE; } else { fig_colour = spline_colours[this_list]; } fig_spline_close = 5; for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list); this_spline++) { spline_type s = SPLINE_LIST_ELT (list, this_spline); if (pointcount == 0) { pointx[pointcount] = FIG_X(START_POINT(s).x); pointy[pointcount] = FIG_Y(START_POINT(s).y); contrl[pointcount] = (at_real) 0.0; fig_addtobbox(START_POINT(s).x,START_POINT(s).y); pointcount++; } /* Apparently START_POINT for one spline section is same as END_POINT for previous section - should at_really test for this */ if (SPLINE_DEGREE(s) == LINEARTYPE) { pointx[pointcount] = FIG_X(END_POINT(s).x); pointy[pointcount] = FIG_Y(END_POINT(s).y); contrl[pointcount] = (at_real) 0.0; fig_addtobbox(START_POINT(s).x,START_POINT(s).y); pointcount++; } else /* Assume Bezier like spline */ { /* Convert approximated bezier to interpolated X Spline */ at_real temp; for (temp = (at_real) 0.2; temp < (at_real) 0.9; temp += (at_real) 0.2) { pointx[pointcount] = FIG_X(bezpnt(temp,START_POINT(s).x,CONTROL1(s).x, CONTROL2(s).x,END_POINT(s).x)); pointy[pointcount] = FIG_Y(bezpnt(temp,START_POINT(s).y,CONTROL1(s).y, CONTROL2(s).y,END_POINT(s).y)); contrl[pointcount] = (at_real) -1.0; pointcount++; } pointx[pointcount] = FIG_X(END_POINT(s).x); pointy[pointcount] = FIG_Y(END_POINT(s).y); contrl[pointcount] = (at_real) 0.0; fig_addtobbox(START_POINT(s).x,START_POINT(s).y); fig_addtobbox(CONTROL1(s).x,CONTROL1(s).y); fig_addtobbox(CONTROL2(s).x,CONTROL2(s).y); fig_addtobbox(END_POINT(s).x,END_POINT(s).y); pointcount++; is_spline=1; } } if (shape.centerline) { fig_fill = -1; fig_width = 1; fig_spline_close = 4; } else { /* Use zero width lines - unit width is too thick */ fig_fill = 20; fig_width = 0; fig_spline_close = 5; } if (is_spline != 0) { fig_new_depth(); fprintf(file,"3 %d 0 %d %d %d %d 0 %d 0.00 0 0 0 %d\n", fig_spline_close, fig_width, fig_colour, fig_colour, fig_depth, fig_fill, pointcount); /* Print out points */ j = 0; for (i=0; i set fig number If fig number already used, go to next fig number (alternate) if alternate is 0, set next unused fig number */ static void fig_col_init(void) { int i; for (i=0;i<544;i++) { fig_hash[i].colour = 0; fig_colour_map[i].alternate = 0; } /* populate the first 8 primary colours */ /* Black */ fig_hash[0].colour = FIG_BLACK; fig_colour_map[FIG_BLACK].r = 0; fig_colour_map[FIG_BLACK].g = 0; fig_colour_map[FIG_BLACK].b = 0; /* White */ fig_hash[543].colour = FIG_WHITE; fig_colour_map[FIG_WHITE].r = 255; fig_colour_map[FIG_WHITE].g = 255; fig_colour_map[FIG_WHITE].b = 255; /* Red */ fig_hash[255].colour = FIG_RED; fig_colour_map[FIG_RED].r = 255; fig_colour_map[FIG_RED].g = 0; fig_colour_map[FIG_RED].b = 0; /* Green */ fig_hash[161].colour = FIG_GREEN; fig_colour_map[FIG_GREEN].r = 0; fig_colour_map[FIG_GREEN].g = 255; fig_colour_map[FIG_GREEN].b = 0; /* Blue */ fig_hash[127].colour = FIG_BLUE; fig_colour_map[FIG_BLUE].r = 0; fig_colour_map[FIG_BLUE].g = 0; fig_colour_map[FIG_BLUE].b = 255; /* Cyan */ fig_hash[198].colour = FIG_CYAN; fig_colour_map[FIG_CYAN].r = 0; fig_colour_map[FIG_CYAN].g = 255; fig_colour_map[FIG_CYAN].b = 255; /* Magenta */ fig_hash[382].colour = FIG_MAGENTA; fig_colour_map[FIG_MAGENTA].r = 255; fig_colour_map[FIG_MAGENTA].g = 0; fig_colour_map[FIG_MAGENTA].b = 255; /* Yellow */ fig_hash[416].colour = FIG_YELLOW; fig_colour_map[FIG_YELLOW].r = 255; fig_colour_map[FIG_YELLOW].g = 255; fig_colour_map[FIG_YELLOW].b = 0; } /* * Return the FIG colour index based on the RGB triplet. * If unknown, create a new colour index and return that. */ static int get_fig_colour(color_type this_colour, at_exception_type * exp) { int hash,i,this_ind; hash = fig_col_hash(this_colour); /* Special case: black _IS_ zero: */ if ((hash == 0) && (COLOR_EQUAL(fig_colour_map[0],this_colour))) {return(0);} if (fig_hash[hash].colour == 0) { fig_hash[hash].colour = LAST_FIG_COLOUR; fig_colour_map[LAST_FIG_COLOUR].r = this_colour.r; fig_colour_map[LAST_FIG_COLOUR].g = this_colour.g; fig_colour_map[LAST_FIG_COLOUR].b = this_colour.b; LAST_FIG_COLOUR++; if (LAST_FIG_COLOUR >= MAX_FIG_COLOUR) { LOG1("Output-Fig: too many colours: %d", LAST_FIG_COLOUR); at_exception_fatal(exp, "Output-Fig: too many colours"); return 0; } return(fig_hash[hash].colour); } else { i=0; this_ind = fig_hash[hash].colour; figcolloop: /* If colour match return current colour */ if (COLOR_EQUAL(fig_colour_map[this_ind],this_colour)) { return(this_ind); } /* If next colour zero - set it, return */ if (fig_colour_map[this_ind].alternate == 0) { fig_colour_map[this_ind].alternate = LAST_FIG_COLOUR; fig_colour_map[LAST_FIG_COLOUR].r = this_colour.r; fig_colour_map[LAST_FIG_COLOUR].g = this_colour.g; fig_colour_map[LAST_FIG_COLOUR].b = this_colour.b; LAST_FIG_COLOUR++; if (LAST_FIG_COLOUR >= MAX_FIG_COLOUR) { LOG1("Output-Fig: too many colours: %d", LAST_FIG_COLOUR); at_exception_fatal(exp, "Output-Fig: too many colours"); return 0; } return(fig_colour_map[this_ind].alternate); } /* Else get next colour */ this_ind = fig_colour_map[this_ind].alternate; /* Sanity check ... if colour too big - abort */ if (i++ > MAX_FIG_COLOUR) { LOG1("Output-Fig: too many colours (loop): %d", i); at_exception_fatal(exp, "Output-Fig: too many colours (loop)"); return 0; } /* Else loop top */ goto figcolloop; } }