1 /* spline.c: spline and spline list (represented as arrays) manipulation.
2 *
3 * Copyright (C) 1992 Free Software Foundation, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
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)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * 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/>.
17 */
18
19 #include "config.h"
20
21 #include <assert.h>
22
23 #include <glib.h>
24
25 #include "global.h"
26 #include "bounding-box.h"
27 #include "spline.h"
28 #include "vector.h"
29
30 /* Return a new spline structure, initialized with (recognizable)
31 garbage. */
32
33 spline_type
new_spline(void)34 new_spline (void)
35 {
36 real_coordinate_type coord = { -100.0, -100.0 };
37 spline_type spline;
38
39 START_POINT (spline)
40 = CONTROL1 (spline)
41 = CONTROL2 (spline)
42 = END_POINT (spline)
43 = coord;
44 SPLINE_DEGREE (spline) = -1;
45 SPLINE_LINEARITY (spline) = 0;
46
47 return spline;
48 }
49
50
51 /* Print a spline in human-readable form. */
52
53 void
print_spline(FILE * f,spline_type s)54 print_spline (FILE *f, spline_type s)
55 {
56 if (SPLINE_DEGREE (s) == LINEAR)
57 fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n",
58 START_POINT (s).x, START_POINT (s).y,
59 END_POINT (s).x, END_POINT (s).y);
60
61 else if (SPLINE_DEGREE (s) == CUBIC)
62 fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n",
63 START_POINT (s).x, START_POINT (s).y,
64 CONTROL1 (s).x, CONTROL1 (s).y,
65 CONTROL2 (s).x, CONTROL2 (s).y,
66 END_POINT (s).x, END_POINT (s).y);
67
68 else
69 {
70 /* FATAL1 ("print_spline: strange degree (%d)", SPLINE_DEGREE (s)); */
71 }
72 }
73
74 /* Evaluate the spline S at a given T value. This is an implementation
75 of de Casteljau's algorithm. See Schneider's thesis (reference in
76 ../limn/README), p.37. The variable names are taken from there. */
77
78 real_coordinate_type
evaluate_spline(spline_type s,real t)79 evaluate_spline (spline_type s, real t)
80 {
81 spline_type V[4]; /* We need degree+1 splines, but assert degree <= 3. */
82 unsigned i, j;
83 real one_minus_t = 1.0 - t;
84 polynomial_degree degree = SPLINE_DEGREE (s);
85
86 for (i = 0; i <= degree; i++)
87 V[0].v[i] = s.v[i];
88
89 for (j = 1; j <= degree; j++)
90 for (i = 0; i <= degree - j; i++)
91 {
92 #if defined (__GNUC__)
93 real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
94 real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
95 V[j].v[i] = Padd (t1, t2);
96 #else
97 /* HB: the above is really nice, but is there any other compiler
98 * supporting this ??
99 */
100 real_coordinate_type t1;
101 real_coordinate_type t2;
102 t1.x = V[j - 1].v[i].x * one_minus_t;
103 t1.y = V[j - 1].v[i].y * one_minus_t;
104 t2.x = V[j - 1].v[i + 1].x * t;
105 t2.y = V[j - 1].v[i + 1].y * t;
106 V[j].v[i].x = t1.x + t2.x;
107 V[j].v[i].y = t1.y + t2.y;
108 #endif
109 }
110
111 return V[degree].v[0];
112 }
113
114
115
116 /* Return a new, empty, spline list. */
117
118 spline_list_type *
new_spline_list(void)119 new_spline_list (void)
120 {
121 spline_list_type *answer = g_new (spline_list_type, 1);
122
123 SPLINE_LIST_DATA (*answer) = NULL;
124 SPLINE_LIST_LENGTH (*answer) = 0;
125
126 return answer;
127 }
128
129
130 /* Return a new spline list with SPLINE as the first element. */
131
132 spline_list_type *
init_spline_list(spline_type spline)133 init_spline_list (spline_type spline)
134 {
135 spline_list_type *answer = g_new (spline_list_type, 1);
136
137 SPLINE_LIST_DATA (*answer) = g_new (spline_type, 1);
138 SPLINE_LIST_ELT (*answer, 0) = spline;
139 SPLINE_LIST_LENGTH (*answer) = 1;
140
141 return answer;
142 }
143
144
145 /* Free the storage in a spline list. We don't have to free the
146 elements, since they are arrays in automatic storage. And we don't
147 want to free the list if it was empty. */
148
149 void
free_spline_list(spline_list_type * spline_list)150 free_spline_list (spline_list_type *spline_list)
151 {
152 if (SPLINE_LIST_DATA (*spline_list) != NULL)
153 safe_free ((address *) &(SPLINE_LIST_DATA (*spline_list)));
154 }
155
156
157 /* Append the spline S to the list SPLINE_LIST. */
158
159 void
append_spline(spline_list_type * l,spline_type s)160 append_spline (spline_list_type *l, spline_type s)
161 {
162 assert (l != NULL);
163
164 SPLINE_LIST_LENGTH (*l)++;
165 SPLINE_LIST_DATA (*l) = g_realloc (SPLINE_LIST_DATA (*l),
166 SPLINE_LIST_LENGTH (*l) * sizeof (spline_type));
167 LAST_SPLINE_LIST_ELT (*l) = s;
168 }
169
170
171 /* Tack the elements in the list S2 onto the end of S1.
172 S2 is not changed. */
173
174 void
concat_spline_lists(spline_list_type * s1,spline_list_type s2)175 concat_spline_lists (spline_list_type *s1, spline_list_type s2)
176 {
177 unsigned this_spline;
178 unsigned new_length;
179
180 assert (s1 != NULL);
181
182 new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2);
183
184 SPLINE_LIST_DATA (*s1) = g_realloc(SPLINE_LIST_DATA (*s1),new_length * sizeof(spline_type));
185
186 for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++)
187 SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++)
188 = SPLINE_LIST_ELT (s2, this_spline);
189 }
190
191
192 /* Return a new, empty, spline list array. */
193
194 spline_list_array_type
new_spline_list_array(void)195 new_spline_list_array (void)
196 {
197 spline_list_array_type answer;
198
199 SPLINE_LIST_ARRAY_DATA (answer) = NULL;
200 SPLINE_LIST_ARRAY_LENGTH (answer) = 0;
201
202 return answer;
203 }
204
205
206 /* Free the storage in a spline list array. We don't
207 want to free the list if it is empty. */
208
209 void
free_spline_list_array(spline_list_array_type * spline_list_array)210 free_spline_list_array (spline_list_array_type *spline_list_array)
211 {
212 unsigned this_list;
213
214 for (this_list = 0;
215 this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array);
216 this_list++)
217 free_spline_list (&SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list));
218
219 if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL)
220 safe_free ((address *) &(SPLINE_LIST_ARRAY_DATA (*spline_list_array)));
221 }
222
223
224 /* Append the spline S to the list SPLINE_LIST_ARRAY. */
225
226 void
append_spline_list(spline_list_array_type * l,spline_list_type s)227 append_spline_list (spline_list_array_type *l, spline_list_type s)
228 {
229 SPLINE_LIST_ARRAY_LENGTH (*l)++;
230
231 SPLINE_LIST_ARRAY_DATA (*l) = g_realloc(SPLINE_LIST_ARRAY_DATA (*l),(SPLINE_LIST_ARRAY_LENGTH (*l))*sizeof(spline_list_type));
232 LAST_SPLINE_LIST_ARRAY_ELT (*l) = s;
233 }
234