From 8dd903fdeee8860695c71e637d6230a87cbb73ff Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sun, 17 Jan 2010 02:36:49 +0000 Subject: cleanup git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1102 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- lib/libppmd.c | 199 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 74 deletions(-) (limited to 'lib/libppmd.c') diff --git a/lib/libppmd.c b/lib/libppmd.c index 235df40d..deb47c0f 100644 --- a/lib/libppmd.c +++ b/lib/libppmd.c @@ -966,7 +966,7 @@ typedef struct int edge; } coord; -typedef struct fillobj { +typedef struct fillState { int n; /* Number of elements in 'coords' */ int size; @@ -975,6 +975,16 @@ typedef struct fillobj { int ydir; int startydir; coord * coords; +} fillState; + +typedef struct fillobj { + + /* The only reason we have a struct fillState separate from + struct fillobj is that the drawproc interface is defined to + have drawing not modify the fillobj, i.e. it passed + const fillobj * to the drawing program. + */ + struct fillState * stateP; } fillobj; #define SOME 1000 @@ -985,16 +995,24 @@ struct fillobj * ppmd_fill_create(void) { fillobj * fillObjP; + struct fillState * stateP; MALLOCVAR(fillObjP); if (fillObjP == NULL) pm_error("out of memory allocating a fillhandle"); - fillObjP->n = 0; - fillObjP->size = SOME; - MALLOCARRAY(fillObjP->coords, fillObjP->size); - if (fillObjP->coords == NULL) + + MALLOCVAR(stateP); + if (stateP == NULL) pm_error("out of memory allocating a fillhandle"); - fillObjP->curedge = 0; + + stateP->n = 0; + stateP->size = SOME; + MALLOCARRAY(stateP->coords, stateP->size); + if (stateP->coords == NULL) + pm_error("out of memory allocating a fillhandle"); + stateP->curedge = 0; + + fillObjP->stateP = stateP; /* Turn off line clipping. */ /* UGGH! We must eliminate this global variable */ @@ -1022,28 +1040,95 @@ ppmd_fill_init(void) { void -ppmd_fill_destroy(struct fillobj * fillObjP) { +ppmd_fill_destroy(struct fillobj * const fillObjP) { - free(fillObjP->coords); + free(fillObjP->stateP->coords); + free(fillObjP->stateP); free(fillObjP); } static void -addCoord(fillobj * const fhP, +addCoord(struct fillState * const stateP, ppmd_point const point) { - coord * const cp = &fhP->coords[fhP->n]; + stateP->coords[stateP->n].point = point; + stateP->coords[stateP->n].edge = stateP->curedge; + + ++stateP->n; +} + + - cp->point = point; - cp->edge = fhP->curedge; +static void +startNewSegment(struct fillState * const stateP) { +/*---------------------------------------------------------------------------- + Close off the segment we're currently building and start a new one. +-----------------------------------------------------------------------------*/ + if (stateP->startydir != 0 && stateP->ydir != 0) { + /* There's stuff in the current segment. */ + if (stateP->startydir == stateP->ydir) { + /* Oops, first edge and last edge of current segment are the same. + Change all points in the first edge to be in the last. + */ + int const firstEdge = stateP->coords[stateP->segstart].edge; + int const lastEdge = stateP->coords[stateP->n - 1].edge; + coord * const segStartCoordP = &stateP->coords[stateP->segstart]; + coord * const segEndCoordP = &stateP->coords[stateP->n]; - ++fhP->n; + coord * fcP; + + for (fcP = segStartCoordP; + fcP < segEndCoordP && fcP->edge == firstEdge; + ++fcP) + fcP->edge = lastEdge; + } + } + /* And start new segment. */ + ++stateP->curedge; + stateP->segstart = stateP->n; + stateP->ydir = 0; + stateP->startydir = 0; } +static void +continueSegment(struct fillState * const stateP, + int const dy) { +/*---------------------------------------------------------------------------- + 'dy' is how much the current point is above the previous one. +-----------------------------------------------------------------------------*/ + if (dy != 0) { + if (stateP->ydir != 0 && stateP->ydir != dy) { + /* Direction changed. Insert a fake coord, old + position but new edge number. + */ + ++stateP->curedge; + addCoord(stateP, stateP->coords[stateP->n - 1].point); + } + stateP->ydir = dy; + if (stateP->startydir == 0) + stateP->startydir = dy; + } +} + + + + +/* ppmd_fill_drawprocp() is a drawproc that turns an outline drawing function + into a filled shape function. This is a somewhat off-label application of + a drawproc: A drawproc is intended just to draw a point. So e.g. you + might draw a circle with a fat brush by calling ppmd_circle with a drawproc + that draws a point as a 10-pixel disk. + + But ppmd_fill_drawproc() just draws a point the trivial way: as one pixel. + However, it tracks every point that is drawn in a form that a subsequent + ppmd_fill() call can use to to fill in the shape drawn, assuming it turns + out to be a closed shape. +*/ + void ppmd_fill_drawprocp(pixel ** const pixels, unsigned int const cols, @@ -1052,75 +1137,39 @@ ppmd_fill_drawprocp(pixel ** const pixels, ppmd_point const p, const void * const clientdata) { - fillobj * fh; - - fh = (fillobj*) clientdata; + const fillobj * const fillObjP = clientdata; + struct fillState * const stateP = fillObjP->stateP; - /* If these are the same coords we saved last time, don't bother. */ - if (fh->n > 0) { - ppmd_point const lastPoint = fh->coords[fh->n - 1].point; - if (pointsEqual(p, lastPoint)) - return; - } - - /* Ok, these are new; make room for two more coords. */ - if (fh->n + 1 >= fh->size) { - fh->size += SOME; - REALLOCARRAY(fh->coords, fh->size); - if (fh->coords == NULL) + /* Make room for two more coords, the max we might add. */ + if (stateP->n + 2 > stateP->size) { + stateP->size += SOME; + REALLOCARRAY(stateP->coords, stateP->size); + if (stateP->coords == NULL) pm_error("out of memory enlarging a fillhandle"); } - /* Check for extremum and set the edge number. */ - if (fh->n == 0) { + if (stateP->n == 0) { /* Start first segment. */ - fh->segstart = fh->n; - fh->ydir = 0; - fh->startydir = 0; + stateP->segstart = stateP->n; + stateP->ydir = 0; + stateP->startydir = 0; + addCoord(stateP, p); } else { - coord * const ocp = &(fh->coords[fh->n - 1]); - int const dx = p.x - ocp->point.x; - int const dy = p.y - ocp->point.y; - - if (dx < -1 || dx > 1 || dy < -1 || dy > 1) { - /* Segment break. Close off old one. */ - if (fh->startydir != 0 && fh->ydir != 0) - if (fh->startydir == fh->ydir) { - /* Oops, first edge and last edge are the same. - Renumber the first edge in the old segment. - */ - const coord * const fcpLast= &(fh->coords[fh->n - 1]); - coord * fcp; - - int oldedge; - - fcp = &(fh->coords[fh->segstart]); - oldedge = fcp->edge; - for (; fcp <= fcpLast && fcp->edge == oldedge ; ++fcp) - fcp->edge = ocp->edge; - } - /* And start new segment. */ - ++fh->curedge; - fh->segstart = fh->n; - fh->ydir = 0; - fh->startydir = 0; + ppmd_point const prevPoint = stateP->coords[stateP->n - 1].point; + int const dx = p.x - prevPoint.x; + int const dy = p.y - prevPoint.y; + + if (dx == 0 && dy == 0) { + /* These are the same coords we had last time; don't bother */ } else { - /* Segment continues. */ - if (dy != 0) { - if (fh->ydir != 0 && fh->ydir != dy) { - /* Direction changed. Insert a fake coord, old - position but new edge number. - */ - ++fh->curedge; - addCoord(fh, ocp->point); - } - fh->ydir = dy; - if (fh->startydir == 0) - fh->startydir = dy; - } + if (abs(dx) > 1 || abs(dy) > 1) + startNewSegment(stateP); + else + continueSegment(stateP, dy); + + addCoord(stateP, p); } } - addCoord(fh, p); } @@ -1178,10 +1227,12 @@ ppmd_fill(pixel ** const pixels, int const cols, int const rows, pixval const maxval, - struct fillobj * const fh, + struct fillobj * const fillObjP, ppmd_drawproc drawProc, const void * const clientdata) { + struct fillState * const fh = fillObjP->stateP; + int pedge; int i, edge, lx, rx, py; coord * cp; -- cgit 1.4.1