PageRenderTime 21ms CodeModel.GetById 1ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/libs/libgroff/geometry.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 179 lines | 106 code | 11 blank | 62 comment | 19 complexity | 120bb7705ea71938b606815a5203d3ae MD5 | raw file
  1// -*- C++ -*-
  2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
  3   Free Software Foundation, Inc.
  4     Written by Gaius Mulley <gaius@glam.ac.uk>
  5     using adjust_arc_center() from printer.cpp, written by James Clark.
  6
  7This file is part of groff.
  8
  9groff is free software; you can redistribute it and/or modify it under
 10the terms of the GNU General Public License as published by the Free
 11Software Foundation; either version 2, or (at your option) any later
 12version.
 13
 14groff is distributed in the hope that it will be useful, but WITHOUT ANY
 15WARRANTY; without even the implied warranty of MERCHANTABILITY or
 16FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 17for more details.
 18
 19You should have received a copy of the GNU General Public License along
 20with groff; see the file COPYING.  If not, write to the Free Software
 21Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
 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
 44int 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
 68int 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
118void 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}