diff options
Diffstat (limited to 'converter/other/pamtosvg/curve.c')
-rw-r--r-- | converter/other/pamtosvg/curve.c | 325 |
1 files changed, 202 insertions, 123 deletions
diff --git a/converter/other/pamtosvg/curve.c b/converter/other/pamtosvg/curve.c index 369a0cd3..bd0ca70b 100644 --- a/converter/other/pamtosvg/curve.c +++ b/converter/other/pamtosvg/curve.c @@ -18,71 +18,78 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <assert.h> + #include "mallocvar.h" #include "logreport.h" #include "curve.h" -static float_coord -int_to_real_coord(pm_pixelcoord const int_coord) { +static Point +realCoordFromInt(pm_pixelcoord const int_coord) { /*---------------------------------------------------------------------------- Turn an integer point into a real one. -----------------------------------------------------------------------------*/ - float_coord real_coord; + Point 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 * -new_curve(void) { - curve * curveP; +Curve * +curve_new(void) { +/*---------------------------------------------------------------------------- + A new, entirely empty curve. +-----------------------------------------------------------------------------*/ + Curve * curveP; - MALLOCVAR_NOFAIL(curveP); + MALLOCVAR_NOFAIL(curveP); - curveP->point_list = NULL; - CURVE_LENGTH(curveP) = 0; - CURVE_CYCLIC(curveP) = false; - PREVIOUS_CURVE(curveP) = NULL; - NEXT_CURVE(curveP) = NULL; + curveP->pointList = NULL; + CURVE_LENGTH(curveP) = 0; + CURVE_CYCLIC(curveP) = false; + PREVIOUS_CURVE(curveP) = NULL; + NEXT_CURVE(curveP) = NULL; - return curveP; + return curveP; } -/* 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 * +curve_copyMost(Curve * const oldCurveP) { +/*---------------------------------------------------------------------------- + New curve that is the same as *curveP, except without any points. + + Don't copy the points or tangents, but copy everything else. +-----------------------------------------------------------------------------*/ + Curve * curveP = curve_new(); - CURVE_CYCLIC (curve) = CURVE_CYCLIC (old_curve); - PREVIOUS_CURVE (curve) = PREVIOUS_CURVE (old_curve); - NEXT_CURVE (curve) = NEXT_CURVE (old_curve); + CURVE_CYCLIC(curveP) = CURVE_CYCLIC(oldCurveP); + PREVIOUS_CURVE(curveP) = PREVIOUS_CURVE(oldCurveP); + NEXT_CURVE(curveP) = NEXT_CURVE(oldCurveP); - return curve; + return curveP; } -void -move_curve(curve * const dstP, - curve * const srcP) { - /* Move ownership of dynamically allocated memory from source - to destination; destroy source. - */ +void +curve_move(Curve * const dstP, + Curve * const srcP) { +/*---------------------------------------------------------------------------- + Move ownership of dynamically allocated memory from source to destination; + destroy source. +-----------------------------------------------------------------------------*/ if (CURVE_LENGTH(dstP) > 0) - free(dstP->point_list); - + free(dstP->pointList); + *dstP = *srcP; free(srcP); @@ -90,62 +97,124 @@ move_curve(curve * const dstP, -/* 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 * const curveP) { +curve_free(Curve * const curveP) { + + /* 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). + */ - if (CURVE_LENGTH(curveP) > 0) - free(curveP->point_list); + if (CURVE_LENGTH(curveP) > 0) + free(curveP->pointList); - free(curveP); + free(curveP); } 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; +curve_appendPoint(Curve * const curveP, + Point const coord) { +/*---------------------------------------------------------------------------- + Like `append_pixel', for a point in real coordinates. +-----------------------------------------------------------------------------*/ + CURVE_LENGTH(curveP)++; + REALLOCARRAY_NOFAIL(curveP->pointList, CURVE_LENGTH(curveP)); + LAST_CURVE_POINT(curveP) = coord; /* The t value does not need to be set. */ } + void -append_pixel(curve_type const curve, - pm_pixelcoord const coord) { +curve_appendPixel(Curve * const curveP, + pm_pixelcoord const coord) { +/*---------------------------------------------------------------------------- + Append the point 'coord' to the end of *curveP's list. +-----------------------------------------------------------------------------*/ + curve_appendPoint(curveP, realCoordFromInt(coord)); +} + + + +void +curve_setDistance(Curve * const curveP) { +/*---------------------------------------------------------------------------- + Fill in the distance values in *curveP. + + The distance value for point P on a curve is the distance P is along the + curve from the initial point, normalized so the entire curve is length 1.0 + (i.e. t of the initial point is 0.0; t of the final point is 1.0). + + There are a lot of curves that pass through the points indicated by + *curveP, but for practical computation of t, we just take the piecewise + linear locus that runs through all of them. That means we can just step + through *curveP, adding up the distance from one point to the next to get + the t value for each point. + + This is the "chord-length parameterization" method, which is described in + Plass & Stone. +-----------------------------------------------------------------------------*/ + unsigned int p; + + LOG("\nAssigning initial t values:\n "); + + /* Algorithm: We do a pass through the curve establishing how far each + point is along the curve in absolute terms, and then another pass + to normalize those distances to the fraction of the curve (i.e. + if the curve is 5 units long and Point P is 2 units in, we record + 2 units for Point P in the first pass, and then compute 0.2 as the + fraction of the curve length in the second pass. - append_point(curve, int_to_real_coord(coord)); + In the first pass, we abuse the distance property of the CurvePoint + object to remember the unnormalized distances. + */ + + CURVE_DIST(curveP, 0) = 0.0; + + for (p = 1; p < CURVE_LENGTH(curveP); ++p) { + Point const point = CURVE_POINT(curveP, p); + Point const previous_p = CURVE_POINT(curveP, p - 1); + float const d = point_distance(point, previous_p); + CURVE_DIST(curveP, p) = CURVE_DIST(curveP, p - 1) + d; + } + + assert(LAST_CURVE_DIST(curveP) != 0.0); + + /* Normalize to a curve length of 1.0 */ + + for (p = 1; p < CURVE_LENGTH(curveP); ++p) + CURVE_DIST(curveP, p) = + CURVE_DIST(curveP, p) / LAST_CURVE_DIST(curveP); + + curve_logEntire(curveP); } -/* 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)); \ - } \ +#define LOG_CURVE_POINT(c, p, printDistance) \ + do \ + { \ + LOG2 ("(%.3f,%.3f)", CURVE_POINT (c, p).x, CURVE_POINT (c, p).y); \ + if (printDistance) \ + LOG1 ("/%.2f", CURVE_DIST(c, p)); \ + } \ while (0) void -log_curve(curve * const curveP, - bool const print_t) { - +curve_log(Curve * const curveP, + bool const printDistance) { +/*---------------------------------------------------------------------------- + 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. +-----------------------------------------------------------------------------*/ if (!log_file) return; @@ -159,9 +228,9 @@ log_curve(curve * const curveP, /* If the curve is short enough, don't use ellipses. */ if (CURVE_LENGTH(curveP) <= NUM_TO_PRINT * 2) { unsigned int thisPoint; - + for (thisPoint = 0; thisPoint < CURVE_LENGTH(curveP); ++thisPoint) { - LOG_CURVE_POINT(curveP, thisPoint, print_t); + LOG_CURVE_POINT(curveP, thisPoint, printDistance); LOG(" "); if (thisPoint != CURVE_LENGTH(curveP) - 1 @@ -173,7 +242,7 @@ log_curve(curve * const curveP, for (thisPoint = 0; thisPoint < NUM_TO_PRINT && thisPoint < CURVE_LENGTH(curveP); ++thisPoint) { - LOG_CURVE_POINT(curveP, thisPoint, print_t); + LOG_CURVE_POINT(curveP, thisPoint, printDistance); LOG(" "); } @@ -183,18 +252,19 @@ log_curve(curve * const curveP, thisPoint < CURVE_LENGTH(curveP); ++thisPoint) { LOG(" "); - LOG_CURVE_POINT(curveP, thisPoint, print_t); + LOG_CURVE_POINT(curveP, thisPoint, printDistance); } } LOG(".\n"); } -/* Like `log_curve', but write the whole thing. */ void -log_entire_curve(curve * const curveP) { - +curve_logEntire(Curve * const curveP) { +/*---------------------------------------------------------------------------- + Like `log_curve', but write the whole thing. +-----------------------------------------------------------------------------*/ unsigned int thisPoint; if (!log_file) @@ -218,95 +288,104 @@ log_entire_curve(curve * const curveP) { -/* Return an initialized but empty curve list. */ - -curve_list_type -new_curve_list (void) -{ - curve_list_type curve_list; +CurveList +curve_newList(void) { +/*---------------------------------------------------------------------------- + A new initialized but empty curve list. +-----------------------------------------------------------------------------*/ + CurveList curveList; - curve_list.length = 0; - curve_list.data = NULL; + curveList.length = 0; + curveList.data = NULL; - return curve_list; + return curveList; } -/* Free a curve list and all the curves it contains. */ void -free_curve_list(curve_list_type * const curveListP) { - +curve_freeList(CurveList * const curveListP) { +/*---------------------------------------------------------------------------- + Free curve list and all the curves it contains. +-----------------------------------------------------------------------------*/ unsigned int thisCurve; for (thisCurve = 0; thisCurve < curveListP->length; ++thisCurve) - free_curve(curveListP->data[thisCurve]); + curve_free(curveListP->data[thisCurve]); /* If the character was empty, it won't have any curves. */ if (curveListP->data != NULL) - free (curveListP->data); + free(curveListP->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; } +curve_appendList(CurveList * const curveListP, + Curve * const curveP) { +/*---------------------------------------------------------------------------- + Add an element to a curve list. +-----------------------------------------------------------------------------*/ + ++curveListP->length; + REALLOCARRAY_NOFAIL(curveListP->data, curveListP->length); + curveListP->data[curveListP->length - 1] = curveP; +} -/* Return an initialized but empty curve list array. */ -curve_list_array_type -new_curve_list_array (void) -{ - curve_list_array_type curve_list_array; +CurveListArray +curve_newListArray(void) { +/*---------------------------------------------------------------------------- + An initialized but empty curve list array. +-----------------------------------------------------------------------------*/ + CurveListArray curveListArray; - CURVE_LIST_ARRAY_LENGTH (curve_list_array) = 0; - curve_list_array.data = NULL; + CURVE_LIST_ARRAY_LENGTH(curveListArray) = 0; + curveListArray.data = NULL; - return curve_list_array; + return curveListArray; } -/* 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) { +curve_freeListArray(const CurveListArray * const curveListArrayP, + at_progress_func notify_progress, + void * const clientData) { +/*---------------------------------------------------------------------------- + Free all the curve lists curveListArray contains. +-----------------------------------------------------------------------------*/ + unsigned int thisList; - unsigned this_list; + for (thisList = 0; + thisList < CURVE_LIST_ARRAY_LENGTH(*curveListArrayP); + ++thisList) { - 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) * + notify_progress(((float)thisList)/ + (CURVE_LIST_ARRAY_LENGTH(*curveListArrayP) * (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); + clientData); + curve_freeList(&CURVE_LIST_ARRAY_ELT(*curveListArrayP, thisList)); + } + + /* If the character was empty, it won't have any curves. */ + if (curveListArrayP->data) + free(curveListArrayP->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; +curve_appendArray(CurveListArray * const curveListArrayP, + CurveList const curveList) { +/*---------------------------------------------------------------------------- + Add an element to *curveListArrayP. +-----------------------------------------------------------------------------*/ + CURVE_LIST_ARRAY_LENGTH(*curveListArrayP)++; + REALLOCARRAY_NOFAIL(curveListArrayP->data, + CURVE_LIST_ARRAY_LENGTH(*curveListArrayP)); + LAST_CURVE_LIST_ARRAY_ELT(*curveListArrayP) = curveList; } |