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