2 /* Copyright (C) 1989-2014 Free Software Foundation, Inc.
3 Written by Gaius Mulley <gaius@glam.ac.uk>
4 using adjust_arc_center() from printer.cpp, written by James Clark.
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
26 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
29 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
32 // This utility function adjusts the specified center of the
33 // arc so that it is equidistant between the specified start
34 // and end points. (p[0], p[1]) is a vector from the current
35 // point to the center; (p[2], p[3]) is a vector from the
36 // center to the end point. If the center can be adjusted,
37 // a vector from the current point to the adjusted center is
38 // stored in c[0], c[1] and 1 is returned. Otherwise 0 is
42 int adjust_arc_center(const int *p, double *c)
44 // We move the center along a line parallel to the line between
45 // the specified start point and end point so that the center
46 // is equidistant between the start and end point.
47 // It can be proved (using Lagrange multipliers) that this will
48 // give the point nearest to the specified center that is equidistant
49 // between the start and end point.
51 double x = p[0] + p[2]; // (x, y) is the end point
52 double y = p[1] + p[3];
57 double k = .5 - (c[0]*x + c[1]*y)/n;
66 int printer::adjust_arc_center(const int *p, double *c)
68 int x = p[0] + p[2]; // (x, y) is the end point
70 // Start at the current point; go in the direction of the specified
71 // center point until we reach a point that is equidistant between
72 // the specified starting point and the specified end point. Place
73 // the center of the arc there.
74 double n = p[0]*double(x) + p[1]*double(y);
76 double k = (double(x)*x + double(y)*y)/(2.0*n);
77 // (cx, cy) is our chosen center
83 // We would never reach such a point. So instead start at the
84 // specified end point of the arc. Go towards the specified
85 // center point until we reach a point that is equidistant between
86 // the specified start point and specified end point. Place
87 // the center of the arc there.
88 n = p[2]*double(x) + p[3]*double(y);
90 double k = 1 - (double(x)*x + double(y)*y)/(2.0*n);
91 // (c[0], c[1]) is our chosen center
104 * check_output_arc_limits - works out the smallest box that will encompass
105 * an arc defined by an origin (x, y) and two
106 * vectors (p0, p1) and (p2, p3).
107 * (x1, y1) -> start of arc
108 * (x1, y1) + (xv1, yv1) -> center of circle
109 * (x1, y1) + (xv1, yv1) + (xv2, yv2) -> end of arc
111 * Works out in which quadrant the arc starts and
112 * stops, and from this it determines the x, y
113 * max/min limits. The arc is drawn clockwise.
116 void check_output_arc_limits(int x_1, int y_1,
119 double c_0, double c_1,
120 int *minx, int *maxx,
121 int *miny, int *maxy)
123 int radius = (int)sqrt(c_0 * c_0 + c_1 * c_1);
124 // clockwise direction
125 int xcenter = x_1 + xv_1;
126 int ycenter = y_1 + yv_1;
127 int xend = xcenter + xv_2;
128 int yend = ycenter + yv_2;
129 // for convenience, transform to counterclockwise direction,
130 // centered at the origin
131 int xs = xend - xcenter;
132 int ys = yend - ycenter;
133 int xe = x_1 - xcenter;
134 int ye = y_1 - ycenter;
145 int qs, qe; // quadrants 0..3
147 qs = (ys >= 0) ? 0 : 3;
149 qs = (ys >= 0) ? 1 : 2;
151 qe = (ye >= 0) ? 0 : 3;
153 qe = (ye >= 0) ? 1 : 2;
154 // make qs always smaller than qe
156 || ((qs == qe) && (double(xs) * ye < double(xe) * ys)))
158 for (int i = qs; i < qe; i++)