/*
 * mapLines.c --
 *
 * 	This file defines functions that manage maplines and maplinearrays.
 * 	See the user documentation for more information.
 * 
 * Copyright (c) 2004 Gordon D. Carrie.  All rights reserved.
 * 
 * Licensed under the Open Software License version 2.1
 * 
 * Please address questions and feedback to user0@tkgeomap.org
 *
 * @(#) $Id: mapLines.c,v 1.7 2007/06/26 21:49:30 tkgeomap Exp $
 *
 ********************************************
 *
 */

#include "mapLines.h"

/*
 * Local function declaration.
 */

static void	lnInit _ANSI_ARGS_((struct MapLn *mapLnPtr));

/*
 *----------------------------------------------------------------------
 *
 * MapLnCreate --
 *
 *	This procedure creates and initializes a new geoline.
 *
 * Results:
 * 	See the user documentation.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

MapLn 
MapLnCreate(nPtsMax)
    unsigned nPtsMax;
{
    struct MapLn *mapLnPtr;			/* Return value */

    mapLnPtr = (MapLn)CKALLOC(sizeof(*mapLnPtr));
    lnInit(mapLnPtr);
    if (nPtsMax == 0) {
	return mapLnPtr;
    }
    mapLnPtr->pts = (MapPt *)CKALLOC(nPtsMax * sizeof(MapPt));
    mapLnPtr->nPtsMax = nPtsMax;
    return mapLnPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * lnInit --
 *
 *	This procedure initializes a new geoline.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The contents of a MapLn structure are set.  The previous contents,
 *	which are assumed to be garbage, are ignored.
 *
 *----------------------------------------------------------------------
 */

static void
lnInit(mapLnPtr)
    struct MapLn *mapLnPtr;
{
    mapLnPtr->nPts = mapLnPtr->nPtsMax = 0;
    mapLnPtr->ordMax = mapLnPtr->absMax = -FLT_MAX;
    mapLnPtr->ordMin = mapLnPtr->absMin = FLT_MAX;
    mapLnPtr->pts = NULL;  /* Assumes previous value is garbage */
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnClear --
 *
 *	This procedure set the number of points in a geoline to zero without
 *	releasing its internal storage.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnClear(mapLnPtr)
    struct MapLn *mapLnPtr;
{
    /* Reset a Line without changing its memory allocation */
    mapLnPtr->nPts = 0;
    mapLnPtr->ordMax = mapLnPtr->absMax = -FLT_MAX;
    mapLnPtr->ordMin = mapLnPtr->absMin = FLT_MAX;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnDestroy --
 *
 *	This procedure frees internal storage in a MapLn structure, and
 *	frees the structure.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnDestroy(mapLnPtr)
    struct MapLn *mapLnPtr;
{
    /* Free storage associated with mapLnPtr and then free the mapLnPtr */
    if (!mapLnPtr) {
	return;
    }
    CKFREE((char *)mapLnPtr->pts);
    CKFREE((char *)mapLnPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnSetAlloc --
 *
 *	This procedure changes the number of points a mapline can store.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	This procedure reallocates a MapLn structure's internal storage.
 *	If the number of points is reduced, the geoline's maxima and minima
 *	are recomputed.
 *
 *----------------------------------------------------------------------
 */

void
MapLnSetAlloc(mapLnPtr, nPtsMax)
    struct MapLn *mapLnPtr;
    unsigned nPtsMax;
{
    /*
     * Set mapLnPtr->nPtsMax to nPtsMax.  Returns 1 on success or 0 on failure
     * (if reallocation is required and fails).
     * If mapLnPtr has more points than nPtsMax, the excess points are lost.
     */

    if (mapLnPtr->nPtsMax == nPtsMax) {
	return;
    }
    if (nPtsMax == 0) {
	CKFREE((char *)mapLnPtr->pts);
	lnInit(mapLnPtr);
	return;
    }
    mapLnPtr->pts
	= (MapPt *)CKREALLOC((char *)mapLnPtr->pts, nPtsMax * sizeof(MapPt));
    mapLnPtr->nPtsMax = nPtsMax;
    if (mapLnPtr->nPts > mapLnPtr->nPtsMax) {
	/*
	 * If line is shrinking, reset nPts and recompute maxima and minima.
	 */

	MapPt *p, *ep;

	mapLnPtr->nPts = mapLnPtr->nPtsMax;
	for (p = mapLnPtr->pts, ep = mapLnPtr->pts + mapLnPtr->nPts; p < ep;
		p++) {
	    mapLnPtr->absMax
		= (mapLnPtr->absMax > p->abs) ? mapLnPtr->absMax : p->abs;
	    mapLnPtr->absMin
		= (mapLnPtr->absMin < p->abs) ? mapLnPtr->absMin : p->abs;
	    mapLnPtr->ordMax
		= (mapLnPtr->ordMax > p->ord) ? mapLnPtr->ordMax : p->ord;
	    mapLnPtr->ordMin
		= (mapLnPtr->ordMin < p->ord) ? mapLnPtr->ordMin : p->ord;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnAddPt --
 *
 * 	This procedure adds a point to a mapline.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The mapline's allocation might increase.  It's maxima and minima will
 *	be adjusted.
 *
 *----------------------------------------------------------------------
 */

void
MapLnAddPt(p, mapLnPtr)
    MapPt p;
    struct MapLn *mapLnPtr;
{
    if (mapLnPtr->nPts + 1 > mapLnPtr->nPtsMax) {
	MapLnSetAlloc(mapLnPtr, ((mapLnPtr->nPtsMax + 4) * 5) / 4);
    }
    mapLnPtr->absMin = (mapLnPtr->absMin < p.abs) ? mapLnPtr->absMin : p.abs;
    mapLnPtr->absMax = (mapLnPtr->absMax > p.abs) ? mapLnPtr->absMax : p.abs;
    mapLnPtr->ordMin = (mapLnPtr->ordMin < p.ord) ? mapLnPtr->ordMin : p.ord;
    mapLnPtr->ordMax = (mapLnPtr->ordMax > p.ord) ? mapLnPtr->ordMax : p.ord;
    mapLnPtr->pts[mapLnPtr->nPts] = p;
    mapLnPtr->nPts++;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnGetPt --
 *
 *	This procedure retrieve a map-point from a mapline.
 *
 * Results:
 * 	See the user documentation.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

MapPt
MapLnGetPt(mapLnPtr, n)
    struct MapLn *mapLnPtr;
    unsigned n;
{
    return (n < mapLnPtr->nPts) ? *(mapLnPtr->pts + n) : MapPtNowhere();
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrCreate --
 *
 *	This procedure creates and initializes an new maplinearray.
 *
 * Results:
 * 	See the user documentation.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

MapLnArr 
MapLnArrCreate(nLinesMax)
    unsigned nLinesMax;
{
    struct MapLnArr *mapLnArrPtr;
    int n;

    mapLnArrPtr = (MapLnArr)CKALLOC(sizeof(*mapLnArrPtr));
    mapLnArrPtr->descr = NULL;
    mapLnArrPtr->lines = NULL;
    MapLnArrSetDescr(mapLnArrPtr, "");
    mapLnArrPtr->nLines = mapLnArrPtr->nLinesMax = 0;
    mapLnArrPtr->nPts = mapLnArrPtr->nMax = 0;
    mapLnArrPtr->ordMax = mapLnArrPtr->absMax = -FLT_MAX;
    mapLnArrPtr->ordMin = mapLnArrPtr->absMin = FLT_MAX;
    mapLnArrPtr->proj = NULL;
    if (nLinesMax == 0) {
	return mapLnArrPtr;
    }
    mapLnArrPtr->lines = (MapLn *)CKALLOC(nLinesMax * sizeof(MapLn));
    mapLnArrPtr->nLinesMax = nLinesMax;
    for (n = 0; n < nLinesMax; n++) {
	mapLnArrPtr->lines[n] = NULL;
    }

    return mapLnArrPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrDestroy --
 *
 *	This procedure frees internal storage in a maplinearray and frees the
 *	maplinearray.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrDestroy(mapLnArrPtr)
    struct MapLnArr *mapLnArrPtr;
{
    int n;

    if ( !mapLnArrPtr ) {
	return;
    }
    for (n = 0; n < mapLnArrPtr->nLines; n++) {
	MapLnDestroy(mapLnArrPtr->lines[n]);
    }
    CKFREE((char *)mapLnArrPtr->lines);
    CKFREE((char *)mapLnArrPtr->descr);
    CKFREE((char *)mapLnArrPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrSetDescr --
 *
 *	This procedure sets the descriptor for a maplinearray.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrSetDescr(mapLnArrPtr, descr)
    struct MapLnArr *mapLnArrPtr;
    CONST char *descr;
{
    mapLnArrPtr->descr = CKREALLOC(mapLnArrPtr->descr, strlen(descr) + 1);
    strcpy(mapLnArrPtr->descr, descr);
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrSetAlloc --
 *
 *	This procedure changes the number of maplines a maplinearray can store.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrSetAlloc(mapLnArrPtr, nLinesMax)
    struct MapLnArr *mapLnArrPtr;
    unsigned nLinesMax;
{
    int n;		/* Loop index */

    if (mapLnArrPtr->nLinesMax == nLinesMax) {
	return;
    }

    /*
     * If number of lines decreases, free excess lines
     */

    for (n = nLinesMax; n < mapLnArrPtr->nLinesMax; n++) {
	MapLnDestroy(mapLnArrPtr->lines[n]);
    }

    /*
     * Reallocate
     */

    mapLnArrPtr->lines = (MapLn *)CKREALLOC((char *)mapLnArrPtr->lines,
	    nLinesMax * sizeof(MapLn));
    mapLnArrPtr->nLinesMax = nLinesMax;

    /*
     * Initialize new lines
     */

    for (n = mapLnArrPtr->nLines; n < mapLnArrPtr->nLinesMax; n++) {
	mapLnArrPtr->lines[n] = NULL;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrSet --
 *
 *	This procedure is used to store the geolinearray, projection
 *	that produced a maplinearray.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrSet(mapLnArrPtr, geoLnArr, proj)
    struct MapLnArr *mapLnArrPtr;
    GeoLnArr geoLnArr;
    GeoProj proj;
{
    mapLnArrPtr->geoLnArr = geoLnArr;
    mapLnArrPtr->proj = proj;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrAddLine --
 *
 *	This procedure copies a mapline onto the end of a maplinearray.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrAddLine(mapLnPtr, mapLnArrPtr)
    struct MapLn *mapLnPtr;
    struct MapLnArr *mapLnArrPtr;
{
    int nLines;			/* Initial number of lines in mapLnArrPtr */

    /*
     * If mapLnArrPtr needs more space in its allocation, grow it by 25%
     */

    nLines = mapLnArrPtr->nLines;
    if (nLines + 1 > mapLnArrPtr->nLinesMax) {
	MapLnArrSetAlloc(mapLnArrPtr, ((mapLnArrPtr->nLinesMax + 4) * 5) / 4);
    }

    /*
     * Update information and add copy of mapLnPtr to array
     */

    mapLnArrPtr->lines[nLines] = MapLnCreate(mapLnPtr->nPts);
    mapLnArrPtr->nPts += mapLnPtr->nPts;
    mapLnArrPtr->nMax = (mapLnArrPtr->nMax > mapLnPtr->nPts)
	? mapLnArrPtr->nMax : mapLnPtr->nPts;
    mapLnArrPtr->absMin = (mapLnArrPtr->absMin < mapLnPtr->absMin)
	? mapLnArrPtr->absMin : mapLnPtr->absMin;
    mapLnArrPtr->absMax = (mapLnArrPtr->absMax > mapLnPtr->absMax)
	? mapLnArrPtr->absMax : mapLnPtr->absMax;
    mapLnArrPtr->ordMin = (mapLnArrPtr->ordMin < mapLnPtr->ordMin)
	? mapLnArrPtr->ordMin : mapLnPtr->ordMin;
    mapLnArrPtr->ordMax = (mapLnArrPtr->ordMax > mapLnPtr->ordMax)
	? mapLnArrPtr->ordMax : mapLnPtr->ordMax;
    memcpy(mapLnArrPtr->lines[nLines]->pts, mapLnPtr->pts,
	    mapLnPtr->nPts * sizeof(MapPt));
    mapLnArrPtr->lines[nLines]->nPts = mapLnPtr->nPts;
    mapLnArrPtr->lines[nLines]->absMin = mapLnPtr->absMin;
    mapLnArrPtr->lines[nLines]->absMax = mapLnPtr->absMax;
    mapLnArrPtr->lines[nLines]->ordMin = mapLnPtr->ordMin;
    mapLnArrPtr->lines[nLines]->ordMax = mapLnPtr->ordMax;
    mapLnArrPtr->nLines++;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrPutLine --
 *
 *	This procedure gives a mapline to a maplinearray.
 *
 * Results:
 *	None.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

void
MapLnArrPutLine(mapLnPtr, mapLnArrPtr)
    MapLn mapLnPtr;
    struct MapLnArr *mapLnArrPtr;
{
    int nLines;			/* Initial number of lines in mapLnArrPtr */

    /*
     * If mapLnArrPtr needs more space in its allocation, grow it by 25%
     */

    nLines = mapLnArrPtr->nLines;
    if (nLines + 1 > mapLnArrPtr->nLinesMax) {
	MapLnArrSetAlloc(mapLnArrPtr, ((mapLnArrPtr->nLinesMax + 4) * 5) / 4);
    }

    /*
     * Update information and add the line to the array
     */

    mapLnArrPtr->nPts += mapLnPtr->nPts;
    mapLnArrPtr->nMax = (mapLnArrPtr->nMax > mapLnPtr->nPts)
	? mapLnArrPtr->nMax : mapLnPtr->nPts;
    mapLnArrPtr->absMin = (mapLnArrPtr->absMin < mapLnPtr->absMin)
	? mapLnArrPtr->absMin : mapLnPtr->absMin;
    mapLnArrPtr->absMax = (mapLnArrPtr->absMax > mapLnPtr->absMax)
	? mapLnArrPtr->absMax : mapLnPtr->absMax;
    mapLnArrPtr->ordMin = (mapLnArrPtr->ordMin < mapLnPtr->ordMin)
	? mapLnArrPtr->ordMin : mapLnPtr->ordMin;
    mapLnArrPtr->ordMax = (mapLnArrPtr->ordMax > mapLnPtr->ordMax)
	? mapLnArrPtr->ordMax : mapLnPtr->ordMax;
    mapLnArrPtr->lines[nLines] = mapLnPtr;
    mapLnArrPtr->nLines++;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrGetDescr --
 *
 *	This is a member access function.
 *
 * Results:
 * 	See the user documentation.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

char *
MapLnArrGetDescr(mapLnArrPtr)
    struct MapLnArr *mapLnArrPtr;
{
    return mapLnArrPtr->descr;
}

/*
 *----------------------------------------------------------------------
 *
 * MapLnArrGetLine --
 *
 *	This procedure retrieves a mapline from a maplinearray.
 *
 * Results:
 * 	See the user documentation.
 *
 * Side effects:
 * 	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

MapLn 
MapLnArrGetLine(mapLnArrPtr, n)
    struct MapLnArr *mapLnArrPtr;
    unsigned n;
{
    return (n < mapLnArrPtr->nLines) ? mapLnArrPtr->lines[n] : NULL;
}


syntax highlighted by Code2HTML, v. 0.9.1