summaryrefslogtreecommitdiff
path: root/lib/math.c
blob: 0939d8ef6d6a2eba0017b5b9ff6d2dab8ffbf771 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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
167
168
169
170
171
172
173
/* math.c: define some simple array operations, and other functions.

Copyright (C) 1992 Free Software Foundation, Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
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
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "config.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.  */

const boolean
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.  */

const real
distance (real_coordinate_type p1, real_coordinate_type p2)
{
  return hypot (p1.x - p2.x, p1.y - p2.y);
}


/* Same thing, for integer points.  */
const real
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.  */

const real
acosd (real v)
{
  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");

  return a * 180.0 / M_PI;
}


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

const real
slope (real_coordinate_type coord1, real_coordinate_type coord2)
{
  assert (coord2.x - coord1.x != 0);

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


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

const real_coordinate_type
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;
}


const coordinate_type
real_to_int_coord (real_coordinate_type real_coord)
{
  coordinate_type int_coord;

  int_coord.x = ROUND (real_coord.x);
  int_coord.y = ROUND (real_coord.y);

  return int_coord;
}


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

const boolean
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;
  real *mapped_values = xmalloc (sizeof (real) * value_count);

  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;
}