diff options
Diffstat (limited to 'converter/other/pamtosvg/curve.c')
-rw-r--r-- | converter/other/pamtosvg/curve.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/converter/other/pamtosvg/curve.c b/converter/other/pamtosvg/curve.c new file mode 100644 index 00000000..cc8aeb59 --- /dev/null +++ b/converter/other/pamtosvg/curve.c @@ -0,0 +1,314 @@ +/* curve.c: operations on the lists of pixels and lists of curves. + + The code was partially derived from limn. + + 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 "mallocvar.h" + +#include "logreport.h" +#include "curve.h" + + +static float_coord +int_to_real_coord(pm_pixelcoord const int_coord) { +/*---------------------------------------------------------------------------- + Turn an integer point into a real one. +-----------------------------------------------------------------------------*/ + float_coord real_coord; + + real_coord.x = int_coord.col; + real_coord.y = int_coord.row; + real_coord.z = 0.0; + + return real_coord; +} + + + +/* Return an entirely empty curve. */ + +curve_type +new_curve (void) +{ + curve_type curve; + MALLOCVAR_NOFAIL(curve); + curve->point_list = NULL; + CURVE_LENGTH (curve) = 0; + CURVE_CYCLIC (curve) = false; + CURVE_START_TANGENT (curve) = CURVE_END_TANGENT (curve) = NULL; + PREVIOUS_CURVE (curve) = NEXT_CURVE (curve) = NULL; + + return curve; +} + + +/* Don't copy the points or tangents, but copy everything else. */ + +curve_type +copy_most_of_curve (curve_type old_curve) +{ + curve_type curve = new_curve (); + + CURVE_CYCLIC (curve) = CURVE_CYCLIC (old_curve); + PREVIOUS_CURVE (curve) = PREVIOUS_CURVE (old_curve); + NEXT_CURVE (curve) = NEXT_CURVE (old_curve); + + return curve; +} + + +/* The length of CURVE will be zero if we ended up not being able to fit + it (which in turn implies a problem elsewhere in the program, but at + any rate, we shouldn't try here to free the nonexistent curve). */ + +void +free_curve (curve_type curve) +{ + if (CURVE_LENGTH (curve) > 0) + free (curve->point_list); + if (CURVE_START_TANGENT (curve)) + free (CURVE_START_TANGENT (curve)); + if (CURVE_END_TANGENT (curve)) + free (CURVE_END_TANGENT (curve)); +} + + +void +append_point(curve_type const curve, + float_coord const coord) { + + CURVE_LENGTH(curve)++; + REALLOCARRAY_NOFAIL(curve->point_list, CURVE_LENGTH(curve)); + LAST_CURVE_POINT(curve) = coord; + /* The t value does not need to be set. */ +} + + +void +append_pixel(curve_type const curve, + pm_pixelcoord const coord) { + + append_point(curve, int_to_real_coord(coord)); +} + + +/* Print a curve in human-readable form. It turns out we never care + about most of the points on the curve, and so it is pointless to + print them all out umpteen times. What matters is that we have some + from the end and some from the beginning. */ + +#define NUM_TO_PRINT 3 + +#define LOG_CURVE_POINT(c, p, print_t) \ + do \ + { \ + LOG2 ("(%.3f,%.3f)", CURVE_POINT (c, p).x, CURVE_POINT (c, p).y); \ + if (print_t) \ + LOG1 ("/%.2f", CURVE_T (c, p)); \ + } \ + while (0) + +void +log_curve (curve_type curve, bool print_t) +{ + unsigned this_point; + + if (!log_file) return; + + LOG1 ("curve id = %lx:\n", (unsigned long) curve); + LOG1 (" length = %u.\n", CURVE_LENGTH (curve)); + if (CURVE_CYCLIC (curve)) + LOG (" cyclic.\n"); + + /* It should suffice to check just one of the tangents for being null + -- either they both should be, or neither should be. */ + if (CURVE_START_TANGENT (curve) != NULL) + LOG4 (" tangents = (%.3f,%.3f) & (%.3f,%.3f).\n", + CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy, + CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy); + + LOG (" "); + + /* If the curve is short enough, don't use ellipses. */ + if (CURVE_LENGTH (curve) <= NUM_TO_PRINT * 2) + { + for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++) + { + LOG_CURVE_POINT (curve, this_point, print_t); + LOG (" "); + + if (this_point != CURVE_LENGTH (curve) - 1 + && (this_point + 1) % NUM_TO_PRINT == 0) + LOG ("\n "); + } + } + else + { + for (this_point = 0; + this_point < NUM_TO_PRINT && this_point < CURVE_LENGTH (curve); + this_point++) + { + LOG_CURVE_POINT (curve, this_point, print_t); + LOG (" "); + } + + LOG ("...\n ..."); + + for (this_point = CURVE_LENGTH (curve) - NUM_TO_PRINT; + this_point < CURVE_LENGTH (curve); + this_point++) + { + LOG (" "); + LOG_CURVE_POINT (curve, this_point, print_t); + } + } + + LOG (".\n"); +} + + +/* Like `log_curve', but write the whole thing. */ + +void +log_entire_curve (curve_type curve) +{ + unsigned this_point; + + if (!log_file) return; + + LOG1 ("curve id = %lx:\n", (unsigned long) curve); + LOG1 (" length = %u.\n", CURVE_LENGTH (curve)); + if (CURVE_CYCLIC (curve)) + LOG (" cyclic.\n"); + + /* It should suffice to check just one of the tangents for being null + -- either they both should be, or neither should be. */ + if (CURVE_START_TANGENT (curve) != NULL) + LOG4 (" tangents = (%.3f,%.3f) & (%.3f,%.3f).\n", + CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy, + CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy); + + LOG (" "); + + for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++) + { + LOG (" "); + LOG_CURVE_POINT (curve, this_point, true); + /* Compiler warning `Condition is always true' can be ignored */ + } + + LOG (".\n"); +} + + +/* Return an initialized but empty curve list. */ + +curve_list_type +new_curve_list (void) +{ + curve_list_type curve_list; + + curve_list.length = 0; + curve_list.data = NULL; + + return curve_list; +} + + +/* Free a curve list and all the curves it contains. */ + +void +free_curve_list(curve_list_type * const curve_list) { + + unsigned this_curve; + + for (this_curve = 0; this_curve < curve_list->length; this_curve++) + { + free_curve (curve_list->data[this_curve]); + free (curve_list->data[this_curve]); + } + + /* If the character was empty, it won't have any curves. */ + if (curve_list->data != NULL) + free (curve_list->data); +} + + +/* Add an element to a curve list. */ + +void +append_curve (curve_list_type *curve_list, curve_type curve) +{ + curve_list->length++; + REALLOCARRAY_NOFAIL(curve_list->data, curve_list->length); + curve_list->data[curve_list->length - 1] = curve; } + + +/* Return an initialized but empty curve list array. */ + +curve_list_array_type +new_curve_list_array (void) +{ + curve_list_array_type curve_list_array; + + CURVE_LIST_ARRAY_LENGTH (curve_list_array) = 0; + curve_list_array.data = NULL; + + return curve_list_array; +} + + +/* Free a curve list array and all the curve lists it contains. */ + +void +free_curve_list_array(const curve_list_array_type * const curve_list_array, + at_progress_func notify_progress, + void * const client_data) { + + unsigned this_list; + + for (this_list = 0; this_list < CURVE_LIST_ARRAY_LENGTH(*curve_list_array); + this_list++) { + if (notify_progress) + notify_progress(((float)this_list)/ + (CURVE_LIST_ARRAY_LENGTH(*curve_list_array) * + (float)3.0)+(float)0.666 , + client_data); + free_curve_list(&CURVE_LIST_ARRAY_ELT (*curve_list_array, this_list)); + } + + /* If the character was empty, it won't have any curves. */ + if (curve_list_array->data != NULL) + free(curve_list_array->data); +} + + +/* Add an element to a curve list array. */ + +void +append_curve_list(curve_list_array_type * const curve_list_array, + curve_list_type const curve_list) { + + CURVE_LIST_ARRAY_LENGTH (*curve_list_array)++; + REALLOCARRAY_NOFAIL(curve_list_array->data, + CURVE_LIST_ARRAY_LENGTH(*curve_list_array)); + LAST_CURVE_LIST_ARRAY_ELT (*curve_list_array) = curve_list; +} + + + |