386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 8 Apr 1992 23:49:50 +0000 (15:49 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 8 Apr 1992 23:49:50 +0000 (15:49 -0800)
Work on file usr/othersrc/public/ghostscript-2.4.1/gspath.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/public/ghostscript-2.4.1/gspath.c [new file with mode: 0644]

diff --git a/usr/othersrc/public/ghostscript-2.4.1/gspath.c b/usr/othersrc/public/ghostscript-2.4.1/gspath.c
new file mode 100644 (file)
index 0000000..b4fac41
--- /dev/null
@@ -0,0 +1,310 @@
+/* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
+   Distributed by Free Software Foundation, Inc.
+
+This file is part of Ghostscript.
+
+Ghostscript is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
+to anyone for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.  Refer
+to the Ghostscript General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+Ghostscript, but only under the conditions described in the Ghostscript
+General Public License.  A copy of this license is supposed to have been
+given to you along with Ghostscript so you can know your rights and
+responsibilities.  It should be in a file named COPYING.  Among other
+things, the copyright notice and this notice must be preserved on all
+copies.  */
+
+/* gspath.c */
+/* Path construction routines for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxpath.h"
+#include "gzstate.h"
+
+/* Conversion parameters */
+#define degrees_to_radians (M_PI / 180.0)
+
+/* ------ Miscellaneous ------ */
+
+int
+gs_newpath(gs_state *pgs)
+{      gx_path_release(pgs->path);
+       gx_path_init(pgs->path, &pgs->memory_procs);
+       return 0;
+}
+
+int
+gs_closepath(gs_state *pgs)
+{      return gx_path_close_subpath(pgs->path);
+}
+
+int
+gs_upmergepath(gs_state *pgs)
+{      return gx_path_add_path(pgs->saved->path, pgs->path);
+}
+
+/* ------ Points and lines ------ */
+
+int
+gs_currentpoint(const gs_state *pgs, gs_point *ppt)
+{      gs_fixed_point pt;
+       int code = gx_path_current_point(pgs->path, &pt);
+       if ( code < 0 ) return code;
+       return gs_itransform(pgs, fixed2float(pt.x), fixed2float(pt.y), ppt);
+}
+
+int
+gs_moveto(gs_state *pgs, floatp x, floatp y)
+{      int code;
+       gs_fixed_point pt;
+       if ( (code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) >= 0 )
+               code = gx_path_add_point(pgs->path, pt.x, pt.y);
+       return code;
+}
+
+int
+gs_rmoveto(gs_state *pgs, floatp x, floatp y)
+{      int code;
+       gs_fixed_point dpt;
+       if ( (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) >= 0 )
+               code = gx_path_add_relative_point(pgs->path, dpt.x, dpt.y);
+       return code;
+}
+
+int
+gs_lineto(gs_state *pgs, floatp x, floatp y)
+{      int code;
+       gs_fixed_point pt;
+       if ( (code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) >= 0 )
+               code = gx_path_add_line(pgs->path, pt.x, pt.y);
+       return code;
+}
+
+int
+gs_rlineto(gs_state *pgs, floatp x, floatp y)
+{      gs_fixed_point cpt, dpt;
+       int code = gx_path_current_point(pgs->path, &cpt);
+       if ( code < 0 ) return code;
+       if ( (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) >= 0 )
+               code = gx_path_add_line(pgs->path, cpt.x + dpt.x, cpt.y + dpt.y);
+       return code;
+}
+
+/* ------ Arcs ------ */
+
+/* Forward declarations */
+private int arc_either(P7(gs_state *,
+  floatp, floatp, floatp, floatp, floatp, int));
+private int arc_add(P9(gs_state *,
+  floatp, floatp, floatp, floatp, floatp, floatp, floatp, int));
+
+int
+gs_arc(gs_state *pgs,
+  floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{      return arc_either(pgs, xc, yc, r, ang1, ang2, 0);
+}
+
+int
+gs_arcn(gs_state *pgs,
+  floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{      return arc_either(pgs, xc, yc, r, ang1, ang2, 1);
+}
+
+private int
+arc_either(gs_state *pgs,
+  floatp axc, floatp ayc, floatp arad, floatp aang1, floatp aang2,
+  int clockwise)
+{      float ar = arad;
+       fixed ang1 = float2fixed(aang1), ang2 = float2fixed(aang2), adiff;
+       float ang1r;
+       float x0, y0, sin0, cos0;
+       float x3r, y3r;
+       int first = 1;
+       int code;
+       if ( ar < 0 )
+          {    ang1 += int2fixed(180);
+               ang2 += int2fixed(180);
+               ar = - ar;
+          }
+#define fixed90 int2fixed(90)
+#define fixed360 int2fixed(360)
+       /* Don't reduce the arc by multiples of 360 degrees: */
+       /* this could lead to incorrect winding numbers. */
+       if ( ang1 != ang2 )
+          {    if ( clockwise )
+                  {    while ( ang2 >= ang1 ) ang1 += fixed360;
+                  }
+               else
+                  {    while ( ang2 <= ang1 ) ang2 += fixed360;
+                  }
+          }
+       ang1r = fixed2float(ang1 % fixed360) * degrees_to_radians;
+       sin0 = ar * sin(ang1r), cos0 = ar * cos(ang1r);
+       x0 = axc + cos0, y0 = ayc + sin0;
+       if ( clockwise )
+          {    /* Quadrant reduction */
+               while ( (adiff = ang2 - ang1) < -fixed90 )
+                  {    float w = sin0; sin0 = -cos0; cos0 = w;
+                       x3r = axc + cos0, y3r = ayc + sin0;
+                       code = arc_add(pgs, ar, x0, y0, x3r, y3r,
+                               (x0 + cos0),
+                               (y0 + sin0),
+                               first);
+                       if ( code < 0 ) return code;
+                       x0 = x3r, y0 = y3r;
+                       ang1 -= fixed90;
+                       first = 0;
+                  }
+          }
+       else
+          {    /* Quadrant reduction */
+               while ( (adiff = ang2 - ang1) > fixed90 )
+                  {    float w = cos0; cos0 = -sin0; sin0 = w;
+                       x3r = axc + cos0, y3r = ayc + sin0;
+                       code = arc_add(pgs, ar, x0, y0, x3r, y3r,
+                               (x0 + cos0),
+                               (y0 + sin0),
+                               first);
+                       if ( code < 0 ) return code;
+                       x0 = x3r, y0 = y3r;
+                       ang1 += fixed90;
+                       first = 0;
+                  }
+          }
+       /* Compute the intersection of the tangents. */
+          {    double trad = tan(fixed2float(adiff) * (degrees_to_radians / 2));
+               float ang2r = fixed2float(ang2) * degrees_to_radians;
+               code = arc_add(pgs, ar, x0, y0,
+                       (axc + ar * cos(ang2r)),
+                       (ayc + ar * sin(ang2r)),
+                       (x0 - trad * sin0),
+                       (y0 + trad * cos0),
+                       first);
+          }
+       return code;
+}
+
+int
+gs_arcto(gs_state *pgs,
+  floatp ax1, floatp ay1, floatp ax2, floatp ay2, floatp arad,
+  float *retxy)                        /* float retxy[4] */
+{      float xt0, yt0, xt2, yt2;
+       gs_point up0;
+#define ax0 up0.x
+#define ay0 up0.y
+       int code;
+       if ( arad < 0 )
+               return_error(gs_error_undefinedresult);
+       /* Transform the current point back into user coordinates */
+       if ( (code = gs_currentpoint(pgs, &up0)) < 0 ) return code;
+          {    /* Now we have to compute the tangent points. */
+               /* Basically, the idea is to compute the tangent */
+               /* of the bisector by using tan(x+y) and tan(z/2) */
+               /* formulas, without ever using any trig. */
+               float dx0 = ax0 - ax1, dy0 = ay0 - ay1;
+               float dx2 = ax2 - ax1, dy2 = ay2 - ay1;
+               /* Compute the squared lengths from p1 to p0 and p2. */
+               double sql0 = dx0 * dx0 + dy0 * dy0;
+               double sql2 = dx2 * dx2 + dy2 * dy2;
+               /* Compute the distance from p1 to the tangent points. */
+               /* This is the only hairy part. */
+               double num = dy0 * dx2 - dy2 * dx0;
+               double denom = sqrt(sql0 * sql2) - (dx0 * dx2 + dy0 * dy2);
+               /* Check for collinear points. */
+               if ( fabs(num) < 1.0e-6 || fabs(denom) < 1.0e-6 )
+                  {    gs_fixed_point pt;
+                       code = gs_point_transform2fixed(&pgs->ctm, ax1, ay1, &pt);
+                       if ( code >= 0 ) code = gx_path_add_line(pgs->path, pt.x, pt.y);
+                       xt0 = xt2 = ax1;
+                       yt0 = yt2 = ay1;
+                  }
+               else            /* not collinear */
+                  {    double dist = fabs(arad * num / denom);
+                       double l0 = dist / sqrt(sql0), l2 = dist / sqrt(sql2);
+                       xt0 = ax1 + dx0 * l0;
+                       yt0 = ay1 + dy0 * l0;
+                       xt2 = ax1 + dx2 * l2;
+                       yt2 = ay1 + dy2 * l2;
+                       code = arc_add(pgs, arad, xt0, yt0, xt2, yt2, ax1, ay1, 1);
+                  }
+          }
+       if ( retxy != 0 )
+          {    retxy[0] = xt0;
+               retxy[1] = yt0;
+               retxy[2] = xt2;
+               retxy[3] = yt2;
+          }
+       return code;
+}
+
+/* Internal routine for adding an arc to the path. */
+private int
+arc_add(gs_state *pgs,
+  floatp r, floatp x0, floatp y0, floatp x3, floatp y3, floatp xt, floatp yt,
+  int first)
+{      gx_path *path = pgs->path;
+       floatp dx = xt - x0, dy = yt - y0;
+       floatp fraction;
+       gs_fixed_point p0, p3, pt, cpt;
+       int code;
+       /* Compute the fraction coefficient for the curve. */
+       /* See gx_path_add_arc for details. */
+       if ( fabs(r) < 1.0e-4 )         /* almost zero radius */
+          {    fraction = 0.0;
+          }
+       else
+          {    double ratio2 = (dx * dx + dy * dy) / (r * r);
+               fraction = (4.0/3.0) / (1 + sqrt(1 + ratio2));
+          }
+#ifdef DEBUG
+if ( gs_debug['r'] )
+       dprintf7("[r]Arc f=%f p0=(%f,%f) pt=(%f,%f) p3=(%f,%f) first=%d\n",
+                x0, y0, xt, yt, x3, y3, first);
+#endif
+       if (    (code = gs_point_transform2fixed(&pgs->ctm, x0, y0, &p0)) < 0 ||
+               (code = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3)) < 0 ||
+               (code = gs_point_transform2fixed(&pgs->ctm, xt, yt, &pt)) < 0 ||
+               (first && (code = (gx_path_current_point(path, &cpt) >= 0 ?
+                        gx_path_add_line(path, p0.x, p0.y) :
+                        gx_path_add_point(path, p0.x, p0.y))) < 0)
+          )
+               return code;
+       return gx_path_add_arc(path, p0.x, p0.y, p3.x, p3.y, pt.x, pt.y, fraction);
+}
+
+/* ------ Curves ------ */
+
+int
+gs_curveto(gs_state *pgs,
+  floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
+{      gs_fixed_point p1, p2, p3;
+       int code;
+       if (    (code = gs_point_transform2fixed(&pgs->ctm, x1, y1, &p1)) < 0 ||
+               (code = gs_point_transform2fixed(&pgs->ctm, x2, y2, &p2)) < 0 ||
+               (code = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3)) < 0
+          ) return code;
+       return gx_path_add_curve(pgs->path,
+               p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+}
+
+int
+gs_rcurveto(gs_state *pgs,
+  floatp dx1, floatp dy1, floatp dx2, floatp dy2, floatp dx3, floatp dy3)
+{      gs_fixed_point pt, p1, p2, p3;
+       int code = gx_path_current_point(pgs->path, &pt);
+       if ( code < 0 ) return code;
+       if (    (code = gs_distance_transform2fixed(&pgs->ctm, dx1, dy1, &p1)) < 0 ||
+               (code = gs_distance_transform2fixed(&pgs->ctm, dx2, dy2, &p2)) < 0 ||
+               (code = gs_distance_transform2fixed(&pgs->ctm, dx3, dy3, &p3)) < 0
+          ) return code;
+       return gx_path_add_curve(pgs->path,
+               pt.x + p1.x, pt.y + p1.y,
+               pt.x + p2.x, pt.y + p2.y,
+               pt.x + p3.x, pt.y + p3.y);
+}