1 /* curve.c: operations on the lists of pixels and lists of curves.
2
3 The code was partially derived from limn.
4
5 Copyright (C) 1992 Free Software Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif /* Def: HAVE_CONFIG_H */
24
25 #include "logreport.h"
26 #include "curve.h"
27 #include "xstd.h"
28
29 static at_real_coord int_to_real_coord (at_coord);
30
31 /* Return an entirely empty curve. */
32
33 curve_type
new_curve(void)34 new_curve (void)
35 {
36 curve_type curve;
37 XMALLOC (curve, sizeof (struct curve));
38 curve->point_list = NULL;
39 CURVE_LENGTH (curve) = 0;
40 CURVE_CYCLIC (curve) = false;
41 CURVE_START_TANGENT (curve) = CURVE_END_TANGENT (curve) = NULL;
42 PREVIOUS_CURVE (curve) = NEXT_CURVE (curve) = NULL;
43
44 return curve;
45 }
46
47
48 /* Don't copy the points or tangents, but copy everything else. */
49
50 curve_type
copy_most_of_curve(curve_type old_curve)51 copy_most_of_curve (curve_type old_curve)
52 {
53 curve_type curve = new_curve ();
54
55 CURVE_CYCLIC (curve) = CURVE_CYCLIC (old_curve);
56 PREVIOUS_CURVE (curve) = PREVIOUS_CURVE (old_curve);
57 NEXT_CURVE (curve) = NEXT_CURVE (old_curve);
58
59 return curve;
60 }
61
62
63 /* The length of CURVE will be zero if we ended up not being able to fit
64 it (which in turn implies a problem elsewhere in the program, but at
65 any rate, we shouldn't try here to free the nonexistent curve). */
66
67 void
free_curve(curve_type curve)68 free_curve (curve_type curve)
69 {
70 if (CURVE_LENGTH (curve) > 0)
71 free (curve->point_list);
72 if (CURVE_START_TANGENT (curve))
73 free (CURVE_START_TANGENT (curve));
74 if (CURVE_END_TANGENT (curve))
75 free (CURVE_END_TANGENT (curve));
76 }
77
78
79 void
append_pixel(curve_type curve,at_coord coord)80 append_pixel (curve_type curve, at_coord coord)
81 {
82 append_point (curve, int_to_real_coord (coord));
83 }
84
85
86 void
append_point(curve_type curve,at_real_coord coord)87 append_point (curve_type curve, at_real_coord coord)
88 {
89 CURVE_LENGTH (curve)++;
90 XREALLOC (curve->point_list, CURVE_LENGTH (curve) * sizeof(point_type));
91 LAST_CURVE_POINT (curve) = coord;
92 /* The t value does not need to be set. */
93 }
94
95
96 /* Print a curve in human-readable form. It turns out we never care
97 about most of the points on the curve, and so it is pointless to
98 print them all out umpteen times. What matters is that we have some
99 from the end and some from the beginning. */
100
101 #define NUM_TO_PRINT 3
102
103 #define LOG_CURVE_POINT(c, p, print_t) \
104 do \
105 { \
106 LOG2 ("(%.3f,%.3f)", CURVE_POINT (c, p).x, CURVE_POINT (c, p).y); \
107 if (print_t) \
108 LOG1 ("/%.2f", CURVE_T (c, p)); \
109 } \
110 while (0)
111
112 void
log_curve(curve_type curve,at_bool print_t)113 log_curve (curve_type curve, at_bool print_t)
114 {
115 unsigned this_point;
116
117 if (!log_file) return;
118
119 LOG1 ("curve id = %x:\n", (unsigned long) curve);
120 LOG1 (" length = %u.\n", CURVE_LENGTH (curve));
121 if (CURVE_CYCLIC (curve))
122 LOG (" cyclic.\n");
123
124 /* It should suffice to check just one of the tangents for being null
125 -- either they both should be, or neither should be. */
126 if (CURVE_START_TANGENT (curve) != NULL)
127 LOG4 (" tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
128 CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
129 CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
130
131 LOG (" ");
132
133 /* If the curve is short enough, don't use ellipses. */
134 if (CURVE_LENGTH (curve) <= NUM_TO_PRINT * 2)
135 {
136 for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
137 {
138 LOG_CURVE_POINT (curve, this_point, print_t);
139 LOG (" ");
140
141 if (this_point != CURVE_LENGTH (curve) - 1
142 && (this_point + 1) % NUM_TO_PRINT == 0)
143 LOG ("\n ");
144 }
145 }
146 else
147 {
148 for (this_point = 0;
149 this_point < NUM_TO_PRINT && this_point < CURVE_LENGTH (curve);
150 this_point++)
151 {
152 LOG_CURVE_POINT (curve, this_point, print_t);
153 LOG (" ");
154 }
155
156 LOG ("...\n ...");
157
158 for (this_point = CURVE_LENGTH (curve) - NUM_TO_PRINT;
159 this_point < CURVE_LENGTH (curve);
160 this_point++)
161 {
162 LOG (" ");
163 LOG_CURVE_POINT (curve, this_point, print_t);
164 }
165 }
166
167 LOG (".\n");
168 }
169
170
171 /* Like `log_curve', but write the whole thing. */
172
173 void
log_entire_curve(curve_type curve)174 log_entire_curve (curve_type curve)
175 {
176 unsigned this_point;
177
178 if (!log_file) return;
179
180 LOG1 ("curve id = %x:\n", (unsigned long) curve);
181 LOG1 (" length = %u.\n", CURVE_LENGTH (curve));
182 if (CURVE_CYCLIC (curve))
183 LOG (" cyclic.\n");
184
185 /* It should suffice to check just one of the tangents for being null
186 -- either they both should be, or neither should be. */
187 if (CURVE_START_TANGENT (curve) != NULL)
188 LOG4 (" tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
189 CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
190 CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
191
192 LOG (" ");
193
194 for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
195 {
196 LOG (" ");
197 LOG_CURVE_POINT (curve, this_point, true);
198 /* Compiler warning `Condition is always true' can be ignored */
199 }
200
201 LOG (".\n");
202 }
203
204
205 /* Return an initialized but empty curve list. */
206
207 curve_list_type
new_curve_list(void)208 new_curve_list (void)
209 {
210 curve_list_type curve_list;
211
212 curve_list.length = 0;
213 curve_list.data = NULL;
214
215 return curve_list;
216 }
217
218
219 /* Free a curve list and all the curves it contains. */
220
221 void
free_curve_list(curve_list_type * curve_list)222 free_curve_list (curve_list_type *curve_list)
223 {
224 unsigned this_curve;
225
226 for (this_curve = 0; this_curve < curve_list->length; this_curve++)
227 {
228 free_curve (curve_list->data[this_curve]);
229 free (curve_list->data[this_curve]);
230 }
231
232 /* If the character was empty, it won't have any curves. */
233 if (curve_list->data != NULL)
234 free (curve_list->data);
235 }
236
237
238 /* Add an element to a curve list. */
239
240 void
append_curve(curve_list_type * curve_list,curve_type curve)241 append_curve (curve_list_type *curve_list, curve_type curve)
242 {
243 curve_list->length++;
244 XREALLOC (curve_list->data, curve_list->length * sizeof (curve_type));
245 curve_list->data[curve_list->length - 1] = curve; }
246
247
248 /* Return an initialized but empty curve list array. */
249
250 curve_list_array_type
new_curve_list_array(void)251 new_curve_list_array (void)
252 {
253 curve_list_array_type curve_list_array;
254
255 CURVE_LIST_ARRAY_LENGTH (curve_list_array) = 0;
256 curve_list_array.data = NULL;
257
258 return curve_list_array;
259 }
260
261
262 /* Free a curve list array and all the curve lists it contains. */
263
264 void
free_curve_list_array(curve_list_array_type * curve_list_array,at_progress_func notify_progress,at_address client_data)265 free_curve_list_array (curve_list_array_type *curve_list_array,
266 at_progress_func notify_progress,
267 at_address client_data)
268 {
269 unsigned this_list;
270
271 for (this_list = 0; this_list < CURVE_LIST_ARRAY_LENGTH (*curve_list_array);
272 this_list++) {
273 if (notify_progress)
274 notify_progress(((at_real)this_list)/(CURVE_LIST_ARRAY_LENGTH (*curve_list_array)*(at_real)3.0)+(at_real)0.666 ,
275 client_data);
276 free_curve_list (&CURVE_LIST_ARRAY_ELT (*curve_list_array, this_list));
277 }
278
279 /* If the character was empty, it won't have any curves. */
280 if (curve_list_array->data != NULL)
281 free (curve_list_array->data);
282 }
283
284
285 /* Add an element to a curve list array. */
286
287 void
append_curve_list(curve_list_array_type * curve_list_array,curve_list_type curve_list)288 append_curve_list (curve_list_array_type *curve_list_array, curve_list_type curve_list)
289 {
290 CURVE_LIST_ARRAY_LENGTH (*curve_list_array)++;
291 XREALLOC (curve_list_array->data, CURVE_LIST_ARRAY_LENGTH (*curve_list_array) * sizeof (curve_list_type));
292 LAST_CURVE_LIST_ARRAY_ELT (*curve_list_array) = curve_list;
293 }
294
295
296 /* Turn an integer point into a real one. */
297
298 static at_real_coord
int_to_real_coord(at_coord int_coord)299 int_to_real_coord (at_coord int_coord)
300 {
301 at_real_coord real_coord;
302
303 real_coord.x = int_coord.x;
304 real_coord.y = int_coord.y;
305 real_coord.z = 0.0;
306
307 return real_coord;
308 }
309
310