math.c 4.17 KB
Newer Older
1
/* math.c: define some simple array operations, and other functions.
Sven Neumann's avatar
Sven Neumann committed
2 3 4
 *
 * Copyright (C) 1992 Free Software Foundation, Inc.
 *
5
 * This program is free software: you can redistribute it and/or modify
Sven Neumann's avatar
Sven Neumann committed
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3, or (at your option)
Sven Neumann's avatar
Sven Neumann committed
8 9 10 11 12 13 14 15
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
Sven Neumann's avatar
Sven Neumann committed
17
 */
18

19 20
#include "config.h"

21
#include <errno.h>
22
#include <math.h>
23 24
#include <stdio.h>

25
#include "libgimp/gimp.h"
26

27 28 29 30 31 32 33
#include "types.h"
#include "global.h"

/* Numerical errors sometimes make a floating point number just slightly
   larger or smaller than its true value.  When it matters, we need to
   compare with some tolerance, REAL_EPSILON, defined in kbase.h.  */

34
boolean
35 36 37 38 39 40 41 42 43 44
epsilon_equal (real v1, real v2)
{
  return
    v1 == v2		       /* Usually they'll be exactly equal, anyway.  */
    || fabs (v1 - v2) <= REAL_EPSILON;
}


/* Return the Euclidean distance between P1 and P2.  */

45
real
46 47 48 49 50 51 52
distance (real_coordinate_type p1, real_coordinate_type p2)
{
  return hypot (p1.x - p2.x, p1.y - p2.y);
}


/* Same thing, for integer points.  */
53
real
54 55 56 57 58 59 60 61 62
int_distance (coordinate_type p1, coordinate_type p2)
{
  return hypot ((double) p1.x - p2.x, (double) p1.y - p2.y);
}


/* Return the arc cosine of V, in degrees in the range zero to 180.  V
   is taken to be in radians.  */

63
real
64
my_acosd (real v)
65 66 67 68 69 70 71 72 73 74 75 76 77
{
  real a;

  if (epsilon_equal (v, 1.0))
    v = 1.0;
  else if (epsilon_equal (v, -1.0))
    v = -1.0;

  errno = 0;
  a = acos (v);
  if (errno == ERANGE || errno == EDOM)
    FATAL_PERROR ("acosd");

78
  return a * 180.0 / G_PI;
79 80 81 82 83
}


/* The slope of the line defined by COORD1 and COORD2.  */

84
real
85 86
slope (real_coordinate_type coord1, real_coordinate_type coord2)
{
87
  g_assert (coord2.x - coord1.x != 0);
88 89 90 91 92 93 94

  return (coord2.y - coord1.y) / (coord2.x - coord1.x);
}


/* Turn an integer point into a real one, and vice versa.  */

95
real_coordinate_type
96 97 98 99 100 101 102 103 104 105 106
int_to_real_coord (coordinate_type int_coord)
{
  real_coordinate_type real_coord;

  real_coord.x = int_coord.x;
  real_coord.y = int_coord.y;

  return real_coord;
}


107
coordinate_type
108 109 110 111
real_to_int_coord (real_coordinate_type real_coord)
{
  coordinate_type int_coord;

Sven Neumann's avatar
Sven Neumann committed
112 113
  int_coord.x = SROUND (real_coord.x);
  int_coord.y = SROUND (real_coord.y);
114 115 116 117 118 119 120

  return int_coord;
}


/* See if two points (described by their row and column) are adjacent.  */

121
boolean
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
points_adjacent_p (int row1, int col1, int row2, int col2)
{
  int row_diff = abs (row1 - row2);
  int col_diff = abs (col1 - col2);

  return
    (row_diff == 1 && col_diff == 1)
    || (row_diff == 0 && col_diff == 1)
    || (row_diff == 1 && col_diff == 0);
}


/* Find the largest and smallest elements in an array of reals.  */

void
find_bounds (real *values, unsigned value_count, real *min, real *max)
{
  unsigned this_value;

  /* We must use FLT_MAX and FLT_MIN, instead of the corresponding
     values for double, because gcc uses the native atof to parse
     floating point constants, and many atof's choke on the extremes.  */
  *min = FLT_MAX;
  *max = FLT_MIN;

  for (this_value = 0; this_value < value_count; this_value++)
    {
      if (values[this_value] < *min)
	*min = values[this_value];

      if (values[this_value] > *max)
	*max = values[this_value];
    }
}

/* Map a range of numbers, some positive and some negative, into all
   positive, with the greatest being at one and the least at zero.

   This allocates new memory.  */

real *
map_to_unit (real *values, unsigned value_count)
{
  real smallest, largest;
  int this_value;
Sven Neumann's avatar
Sven Neumann committed
167
  real *mapped_values = g_new (real, value_count);
168 169 170 171 172 173 174 175 176 177

  find_bounds (values, value_count, &smallest, &largest);

  largest -= smallest;		/* We never care about largest itself. */

  for (this_value = 0; this_value < value_count; this_value++)
    mapped_values[this_value] = (values[this_value] - smallest) / largest;

  return mapped_values;
}