Remove no longer needed catman periodic via 'make upgrade'.
[dragonfly.git] / contrib / groff / src / libs / libgroff / geometry.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004,
3                  2009
4    Free Software Foundation, Inc.
5      Written by Gaius Mulley <gaius@glam.ac.uk>
6      using adjust_arc_center() from printer.cpp, written by James Clark.
7
8 This file is part of groff.
9
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22
23
24 #include <stdio.h>
25 #include <math.h>
26
27 #undef  MAX
28 #define MAX(a, b)  (((a) > (b)) ? (a) : (b))
29
30 #undef  MIN
31 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
32
33
34 // This utility function adjusts the specified center of the
35 // arc so that it is equidistant between the specified start
36 // and end points.  (p[0], p[1]) is a vector from the current
37 // point to the center; (p[2], p[3]) is a vector from the 
38 // center to the end point.  If the center can be adjusted,
39 // a vector from the current point to the adjusted center is
40 // stored in c[0], c[1] and 1 is returned.  Otherwise 0 is
41 // returned.
42
43 #if 1
44 int adjust_arc_center(const int *p, double *c)
45 {
46   // We move the center along a line parallel to the line between
47   // the specified start point and end point so that the center
48   // is equidistant between the start and end point.
49   // It can be proved (using Lagrange multipliers) that this will
50   // give the point nearest to the specified center that is equidistant
51   // between the start and end point.
52
53   double x = p[0] + p[2];       // (x, y) is the end point
54   double y = p[1] + p[3];
55   double n = x*x + y*y;
56   if (n != 0) {
57     c[0]= double(p[0]);
58     c[1] = double(p[1]);
59     double k = .5 - (c[0]*x + c[1]*y)/n;
60     c[0] += k*x;
61     c[1] += k*y;
62     return 1;
63   }
64   else
65     return 0;
66 }
67 #else
68 int printer::adjust_arc_center(const int *p, double *c)
69 {
70   int x = p[0] + p[2];  // (x, y) is the end point
71   int y = p[1] + p[3];
72   // Start at the current point; go in the direction of the specified
73   // center point until we reach a point that is equidistant between
74   // the specified starting point and the specified end point.  Place
75   // the center of the arc there.
76   double n = p[0]*double(x) + p[1]*double(y);
77   if (n > 0) {
78     double k = (double(x)*x + double(y)*y)/(2.0*n);
79     // (cx, cy) is our chosen center
80     c[0] = k*p[0];
81     c[1] = k*p[1];
82     return 1;
83   }
84   else {
85     // We would never reach such a point.  So instead start at the
86     // specified end point of the arc.  Go towards the specified
87     // center point until we reach a point that is equidistant between
88     // the specified start point and specified end point.  Place
89     // the center of the arc there.
90     n = p[2]*double(x) + p[3]*double(y);
91     if (n > 0) {
92       double k = 1 - (double(x)*x + double(y)*y)/(2.0*n);
93       // (c[0], c[1]) is our chosen center
94       c[0] = p[0] + k*p[2];
95       c[1] = p[1] + k*p[3];
96       return 1;
97     }
98     else
99       return 0;
100   }
101 }  
102 #endif
103
104
105 /*
106  *  check_output_arc_limits - works out the smallest box that will encompass
107  *                            an arc defined by an origin (x, y) and two
108  *                            vectors (p0, p1) and (p2, p3).
109  *                            (x1, y1) -> start of arc
110  *                            (x1, y1) + (xv1, yv1) -> center of circle
111  *                            (x1, y1) + (xv1, yv1) + (xv2, yv2) -> end of arc
112  *
113  *                            Works out in which quadrant the arc starts and
114  *                            stops, and from this it determines the x, y
115  *                            max/min limits.  The arc is drawn clockwise.
116  */
117
118 void check_output_arc_limits(int x_1, int y_1,
119                              int xv_1, int yv_1,
120                              int xv_2, int yv_2,
121                              double c_0, double c_1,
122                              int *minx, int *maxx,
123                              int *miny, int *maxy)
124 {
125   int radius = (int)sqrt(c_0 * c_0 + c_1 * c_1);
126   // clockwise direction
127   int xcenter = x_1 + xv_1;
128   int ycenter = y_1 + yv_1;
129   int xend = xcenter + xv_2;
130   int yend = ycenter + yv_2;
131   // for convenience, transform to counterclockwise direction,
132   // centered at the origin
133   int xs = xend - xcenter;
134   int ys = yend - ycenter;
135   int xe = x_1 - xcenter;
136   int ye = y_1 - ycenter;
137   *minx = *maxx = xs;
138   *miny = *maxy = ys;
139   if (xe > *maxx)
140     *maxx = xe;
141   else if (xe < *minx)
142     *minx = xe;
143   if (ye > *maxy)
144     *maxy = ye;
145   else if (ye < *miny)
146     *miny = ye;
147   int qs, qe;                   // quadrants 0..3
148   if (xs >= 0)
149     qs = (ys >= 0) ? 0 : 3;
150   else
151     qs = (ys >= 0) ? 1 : 2;
152   if (xe >= 0)
153     qe = (ye >= 0) ? 0 : 3;
154   else
155     qe = (ye >= 0) ? 1 : 2;
156   // make qs always smaller than qe
157   if ((qs > qe)
158       || ((qs == qe) && (double(xs) * ye < double(xe) * ys)))
159     qe += 4;
160   for (int i = qs; i < qe; i++)
161     switch (i % 4) {
162     case 0:
163       *maxy = radius;
164       break;
165     case 1:
166       *minx = -radius;
167       break;
168     case 2:
169       *miny = -radius;
170       break;
171     case 3:
172       *maxx = radius;
173       break;
174     }
175   *minx += xcenter;
176   *maxx += xcenter;
177   *miny += ycenter;
178   *maxy += ycenter;
179 }