LCOV - code coverage report
Current view: top level - libs/libgroff - geometry.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 59 60 98.3 %
Date: 2026-01-16 17:51:41 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright 1989-2020 Free Software Foundation, Inc.
       2             :      Written by Gaius Mulley <gaius@glam.ac.uk>
       3             :      using adjust_arc_center() from printer.cpp, written by James Clark.
       4             : 
       5             : This file is part of groff, the GNU roff typesetting system.
       6             : 
       7             : groff is free software; you can redistribute it and/or modify it under
       8             : the terms of the GNU General Public License as published by the Free
       9             : Software Foundation, either version 3 of the License, or
      10             : (at your option) any later version.
      11             : 
      12             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      13             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15             : for more details.
      16             : 
      17             : You should have received a copy of the GNU General Public License
      18             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      19             : 
      20             : #ifdef HAVE_CONFIG_H
      21             : #include <config.h>
      22             : #endif
      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         281 : 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         281 :   double x = p[0] + p[2];       // (x, y) is the end point
      54         281 :   double y = p[1] + p[3];
      55         281 :   double n = x*x + y*y;
      56         281 :   if (n != 0) {
      57         281 :     c[0]= double(p[0]);
      58         281 :     c[1] = double(p[1]);
      59         281 :     double k = .5 - (c[0]*x + c[1]*y)/n;
      60         281 :     c[0] += k*x;
      61         281 :     c[1] += k*y;
      62         281 :     return 1;
      63             :   }
      64             :   else
      65           0 :     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 toward the specified center
      87             :     // point until we reach a point that is equidistant between the
      88             :     // specified start point and specified end point.  Place the center
      89             :     // 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         141 : 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         141 :   int radius = (int)sqrt(c_0 * c_0 + c_1 * c_1);
     126             :   // clockwise direction
     127         141 :   int xcenter = x_1 + xv_1;
     128         141 :   int ycenter = y_1 + yv_1;
     129         141 :   int xend = xcenter + xv_2;
     130         141 :   int yend = ycenter + yv_2;
     131             :   // for convenience, transform to counterclockwise direction,
     132             :   // centered at the origin
     133         141 :   int xs = xend - xcenter;
     134         141 :   int ys = yend - ycenter;
     135         141 :   int xe = x_1 - xcenter;
     136         141 :   int ye = y_1 - ycenter;
     137         141 :   *minx = *maxx = xs;
     138         141 :   *miny = *maxy = ys;
     139         141 :   if (xe > *maxx)
     140          68 :     *maxx = xe;
     141          73 :   else if (xe < *minx)
     142          73 :     *minx = xe;
     143         141 :   if (ye > *maxy)
     144          76 :     *maxy = ye;
     145          65 :   else if (ye < *miny)
     146          63 :     *miny = ye;
     147             :   int qs, qe;                   // quadrants 0..3
     148         141 :   if (xs >= 0)
     149         107 :     qs = (ys >= 0) ? 0 : 3;
     150             :   else
     151          34 :     qs = (ys >= 0) ? 1 : 2;
     152         141 :   if (xe >= 0)
     153         110 :     qe = (ye >= 0) ? 0 : 3;
     154             :   else
     155          31 :     qe = (ye >= 0) ? 1 : 2;
     156             :   // make qs always smaller than qe
     157         141 :   if ((qs > qe)
     158         105 :       || ((qs == qe) && (double(xs) * ye < double(xe) * ys)))
     159          36 :     qe += 4;
     160         277 :   for (int i = qs; i < qe; i++)
     161         136 :     switch (i % 4) {
     162          31 :     case 0:
     163          31 :       *maxy = radius;
     164          31 :       break;
     165          35 :     case 1:
     166          35 :       *minx = -radius;
     167          35 :       break;
     168          34 :     case 2:
     169          34 :       *miny = -radius;
     170          34 :       break;
     171          36 :     case 3:
     172          36 :       *maxx = radius;
     173          36 :       break;
     174             :     }
     175         141 :   *minx += xcenter;
     176         141 :   *maxx += xcenter;
     177         141 :   *miny += ycenter;
     178         141 :   *maxy += ycenter;
     179         141 : }
     180             : 
     181             : // Local Variables:
     182             : // fill-column: 72
     183             : // mode: C++
     184             : // End:
     185             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14