/* * "$Id: hpgl-vector.c,v 1.1.1.13 2005/01/04 19:15:58 jlovell Exp $" * * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS). * * Copyright 1993-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal * copyright law. Distribution and use rights are outlined in the file * "LICENSE.txt" which should have been included with this file. If this * file is missing or damaged please contact Easy Software Products * at: * * Attn: CUPS Licensing Information * Easy Software Products * 44141 Airport View Drive, Suite 204 * Hollywood, Maryland 20636 USA * * Voice: (301) 373-9600 * EMail: cups-info@cups.org * WWW: http://www.cups.org * * This file is subject to the Apple OS-Developed Software exception. * * Contents: * * AA_arc_absolute() - Draw an arc. * AR_arc_relative() - Draw an arc relative to the current pen * AT_arc_absolute3() - Draw an arc using 3 points. * CI_circle() - Draw a circle. * PA_plot_absolute() - Plot a line using absolute coordinates. * PD_pen_down() - Start drawing. * PE_polygon_encoded() - Draw an encoded polyline. * PR_plot_relative() - Plot a line using relative coordinates. * PU_pen_up() - Stop drawing. * RT_arc_relative3() - Draw an arc through 3 points relative to the * decode_number() - Decode an encoded number. * plot_points() - Plot the specified points. */ /* * Include necessary headers... */ #include "hpgltops.h" /* * Local functions... */ static double decode_number(unsigned char **, int, double); static void plot_points(int, param_t *); /* * 'AA_arc_absolute()' - Draw an arc. */ void AA_arc_absolute(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { float x, y, /* Transformed coordinates */ dx, dy; /* Distance from current pen */ float start, end, /* Start and end angles */ theta, /* Current angle */ dt, /* Step between points */ radius; /* Radius of arc */ if (num_params < 3) return; x = Transform[0][0] * params[0].value.number + Transform[0][1] * params[1].value.number + Transform[0][2]; y = Transform[1][0] * params[0].value.number + Transform[1][1] * params[1].value.number + Transform[1][2]; dx = PenPosition[0] - x; dy = PenPosition[1] - y; start = (float)(180.0 * atan2(dy, dx) / M_PI); if (start < 0.0) start += 360.0f; end = start + params[2].value.number; radius = (float)hypot(dx, dy); if (PenDown) { if (num_params > 3 && params[3].value.number > 0.0) dt = (float)fabs(params[3].value.number); else dt = 5.0; if (!PolygonMode) Outputf("MP\n"); PenValid = 1; Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); if (start < end) for (theta = start + dt; theta < end; theta += dt) { PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } else for (theta = start - dt; theta > end; theta -= dt) { PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } } PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); if (PenDown) { Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); if (!PolygonMode) Outputf("ST\n"); } } /* * 'AR_arc_relative()' - Draw an arc relative to the current pen * position. */ void AR_arc_relative(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { float x, y, /* Transformed coordinates */ dx, dy; /* Distance from current pen */ float start, end, /* Start and end angles */ theta, /* Current angle */ dt, /* Step between points */ radius; /* Radius of arc */ if (num_params < 3) return; x = Transform[0][0] * params[0].value.number + Transform[0][1] * params[1].value.number + PenPosition[0]; y = Transform[1][0] * params[0].value.number + Transform[1][1] * params[1].value.number + PenPosition[1]; dx = PenPosition[0] - x; dy = PenPosition[1] - y; start = (float)(180.0 * atan2(dy, dx) / M_PI); if (start < 0.0) start += 360.0f; end = start + params[2].value.number; radius = (float)hypot(dx, dy); if (PenDown) { if (num_params > 3 && params[3].value.number > 0.0) dt = (float)fabs(params[3].value.number); else dt = 5.0; if (!PolygonMode) Outputf("MP\n"); PenValid = 1; Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); if (start < end) for (theta = start + dt; theta < end; theta += dt) { PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } else for (theta = start - dt; theta > end; theta -= dt) { PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } } PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); if (PenDown) { Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); if (!PolygonMode) Outputf("ST\n"); } } /* * 'AT_arc_absolute3()' - Draw an arc using 3 points. * * Note: * * Currently this only draws two line segments through the * specified points. */ void AT_arc_absolute3(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { if (num_params < 4) return; if (PenDown) { if (!PolygonMode) Outputf("MP\n"); PenValid = 1; Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); PenPosition[0] = Transform[0][0] * params[0].value.number + Transform[0][1] * params[1].value.number + Transform[0][2]; PenPosition[1] = Transform[1][0] * params[0].value.number + Transform[1][1] * params[1].value.number + Transform[1][2]; Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } PenPosition[0] = Transform[0][0] * params[2].value.number + Transform[0][1] * params[3].value.number + Transform[0][2]; PenPosition[1] = Transform[1][0] * params[2].value.number + Transform[1][1] * params[3].value.number + Transform[1][2]; if (PenDown) { Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); if (!PolygonMode) Outputf("ST\n"); } } /* * 'CI_circle()' - Draw a circle. */ void CI_circle(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { float x, y; /* Transformed coordinates */ float theta, /* Current angle */ dt, /* Step between points */ radius; /* Radius of circle */ if (num_params < 1) return; if (!PenDown) return; radius = params[0].value.number; if (num_params > 1) dt = (float)fabs(params[1].value.number); else dt = 5.0; if (!PolygonMode) Outputf("MP\n"); PenValid = 1; for (theta = 0.0; theta < 360.0; theta += dt) { x = (float)(PenPosition[0] + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); y = (float)(PenPosition[1] + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); Outputf("%.3f %.3f %s\n", x, y, theta == 0.0 ? "MO" : "LI"); } Outputf("CP\n"); if (!PolygonMode) Outputf("ST\n"); } /* * 'PA_plot_absolute()' - Plot a line using absolute coordinates. */ void PA_plot_absolute(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { PenMotion = 0; if (num_params > 1) plot_points(num_params, params); } /* * 'PD_pen_down()' - Start drawing. */ void PD_pen_down(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { PenDown = 1; if (num_params > 1) plot_points(num_params, params); } /* * 'PE_polygon_encoded()' - Draw an encoded polyline. */ void PE_polyline_encoded(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { unsigned char *s; /* Pointer into string */ int temp, /* Temporary value */ base_bits, /* Data bits per byte */ draw, /* Draw or move */ abscoords; /* Use absolute coordinates */ double tx, ty, /* Transformed coordinates */ x, y, /* Raw coordinates */ frac_bits; /* Multiplier for encoded number */ base_bits = 6; frac_bits = 1.0; draw = PenDown; abscoords = 0; if (num_params == 0) return; if (!PolygonMode) { Outputf("MP\n"); PenValid = 0; } if (!PenValid) { Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); PenValid = 1; } for (s = (unsigned char *)params[0].value.string; *s != '\0';) switch (*s) { case '7' : s ++; base_bits = 5; #ifdef DEBUG fputs("DEBUG: 7-bit\n", stderr); #endif /* DEBUG */ Outputf("%% PE: 7-bit\n"); break; case ':' : /* Select pen */ s ++; PenNumber = (int)decode_number(&s, base_bits, 1.0); #ifdef DEBUG fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber); #endif /* DEBUG */ Outputf("%% PE: set pen #%d\n", PenNumber); if (PageDirty) printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], Pens[PenNumber].width * PenScaling); break; case '<' : /* Next coords are a move-to */ draw = 0; s ++; #ifdef DEBUG fputs("DEBUG: moveto\n", stderr); #endif /* DEBUG */ Outputf("%% PE: moveto\n"); break; case '>' : /* Set fractional bits */ s ++; temp = (int)decode_number(&s, base_bits, 1.0); frac_bits = 1.0 / (1 << temp); #ifdef DEBUG fprintf(stderr, "DEBUG: set fractional bits %d\n", temp); #endif /* DEBUG */ Outputf("%% PE: set fractional bits %d\n", temp); break; case '=' : /* Next coords are absolute */ s ++; abscoords = 1; #ifdef DEBUG fputs("DEBUG: absolute\n", stderr); #endif /* DEBUG */ Outputf("%% PE: absolute\n"); break; default : if (*s >= 63) { /* * Coordinate... */ x = decode_number(&s, base_bits, frac_bits); y = decode_number(&s, base_bits, frac_bits); #ifdef DEBUG fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y); #endif /* DEBUG */ Outputf("%% PE: coords %.3f %.3f\n", x, y); if (abscoords) { tx = Transform[0][0] * x + Transform[0][1] * y + Transform[0][2]; ty = Transform[1][0] * x + Transform[1][1] * y + Transform[1][2]; } else if (x == 0.0 && y == 0.0) { draw = 1; continue; } else { tx = Transform[0][0] * x + Transform[0][1] * y + PenPosition[0]; ty = Transform[1][0] * x + Transform[1][1] * y + PenPosition[1]; } if (draw) { if (fabs(PenPosition[0] - tx) > 0.001 || fabs(PenPosition[1] - ty) > 0.001) Outputf("%.3f %.3f LI\n", tx, ty); } else Outputf("%.3f %.3f MO\n", tx, ty); PenPosition[0] = (float)tx; PenPosition[1] = (float)ty; draw = 1; abscoords = 0; } else { /* * Junk - ignore... */ if (*s != '\n' && *s != '\r') fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s); s ++; } break; } if (!PolygonMode) Outputf("ST\n"); } /* * 'PR_plot_relative()' - Plot a line using relative coordinates. */ void PR_plot_relative(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { PenMotion = 1; if (num_params > 1) plot_points(num_params, params); } /* * 'PU_pen_up()' - Stop drawing. */ void PU_pen_up(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { PenDown = 0; if (num_params > 1) plot_points(num_params, params); } /* * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the * current pen position. * * Note: * * This currently only draws two line segments through the specified * points. */ void RT_arc_relative3(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { if (num_params < 4) return; if (PenDown) { if (!PolygonMode) Outputf("MP\n"); PenValid = 1; Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); PenPosition[0] = Transform[0][0] * params[0].value.number + Transform[0][1] * params[1].value.number + PenPosition[0]; PenPosition[1] = Transform[1][0] * params[0].value.number + Transform[1][1] * params[1].value.number + PenPosition[1]; Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); } PenPosition[0] = Transform[0][0] * params[2].value.number + Transform[0][1] * params[3].value.number + PenPosition[0]; PenPosition[1] = Transform[1][0] * params[2].value.number + Transform[1][1] * params[3].value.number + PenPosition[1]; if (PenDown) { Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); if (!PolygonMode) Outputf("ST\n"); } } /* * 'decode_number()' - Decode an encoded number. */ static double /* O - Value */ decode_number(unsigned char **s, /* IO - String to decode */ int base_bits, /* I - Number of data bits per byte */ double frac_bits) /* I - Multiplier for fractional data */ { double temp, /* Current value */ shift; /* Multiplier */ int sign; /* Sign of result */ sign = 0; if (base_bits == 5) { for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) if (**s >= 95 && **s < 127) { if (sign == 0) { if ((**s - 95) & 1) sign = -1; else sign = 1; temp += ((**s - 95) & ~1) * shift; } else temp += (**s - 95) * shift; break; } else if (**s < 63) { if (**s != '\r' && **s != '\n') fprintf(stderr, "ERROR: Bad PE character 0x%02X!\n", **s); continue; } else { if (sign == 0) { if ((**s - 63) & 1) sign = -1; else sign = 1; temp += ((**s - 63) & ~1) * shift; } else temp += (**s - 63) * shift; shift *= 32.0; } } else { for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) if (**s >= 191 && **s < 255) { if (sign == 0) { if ((**s - 191) & 1) sign = -1; else sign = 1; temp += ((**s - 191) & ~1) * shift; } else temp += (**s - 191) * shift; break; } else if (**s < 63) { if (**s != '\r' && **s != '\n') fprintf(stderr, "ERROR: Bad PE character 0x%02X!\n", **s); continue; } else { if (sign == 0) { if ((**s - 63) & 1) sign = -1; else sign = 1; temp += ((**s - 63) & ~1) * shift; } else temp += (**s - 63) * shift; shift *= 64.0; } } (*s) ++; return (temp * sign); } /* * 'plot_points()' - Plot the specified points. */ static void plot_points(int num_params, /* I - Number of parameters */ param_t *params) /* I - Parameters */ { int i; /* Looping var */ float x, y; /* Transformed coordinates */ if (PenDown) { if (!PolygonMode) { Outputf("MP\n"); Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); PenValid = 1; } } for (i = 0; i < num_params; i += 2) { if (PenMotion == 0) { x = Transform[0][0] * params[i + 0].value.number + Transform[0][1] * params[i + 1].value.number + Transform[0][2]; y = Transform[1][0] * params[i + 0].value.number + Transform[1][1] * params[i + 1].value.number + Transform[1][2]; } else { x = Transform[0][0] * params[i + 0].value.number + Transform[0][1] * params[i + 1].value.number + PenPosition[0]; y = Transform[1][0] * params[i + 0].value.number + Transform[1][1] * params[i + 1].value.number + PenPosition[1]; } if (PenDown) { if (PolygonMode && i == 0) Outputf("%.3f %.3f MO\n", x, y); else if (fabs(PenPosition[0] - x) > 0.001 || fabs(PenPosition[1] - y) > 0.001) Outputf("%.3f %.3f LI\n", x, y); } PenPosition[0] = x; PenPosition[1] = y; } if (PenDown) { if (!PolygonMode) Outputf("ST\n"); } } /* * End of "$Id: hpgl-vector.c,v 1.1.1.13 2005/01/04 19:15:58 jlovell Exp $". */