/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmvmap.c,v 1.6 2005/02/19 16:22:50 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.6 $ * $Log: rmvmap.c,v $ * Revision 1.6 2005/02/19 16:22:50 wes * Distro sync and consolidation. * * Revision 1.5 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.4 2004/03/30 14:13:31 wes * Fixed declarations and man page docs for several routines. * * Revision 1.3 2004/01/16 16:49:50 wes * Updated copyright line for 2004. * * Revision 1.2 2003/02/02 02:07:16 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.5 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.4 2002/04/30 19:36:22 wes * Updated copyright dates. * * Revision 1.3 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.2 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:47 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ #include #include "rmprivat.h" /* PRIVATE declarations */ RMenum private_rmVismapCheckSize (const RMvisMap *v, int indx, char *funcName); /* * ---------------------------------------------------- * @Name rmVismapNew @pstart RMvisMap *rmVismapNew (int size) @pend @astart int size - an int that specifyingthe size of the visualization colormap (input). @aend @dstart Creates a new visualization Colormap, returning the handle to the caller. The caller should use rmVismapDelete() when the vismap is no longer needed to free memory. The size of the visualization colormap is dictated by the input parameter. The newly created visualization colormap of length "size" is set to all zeroes. @dend * ---------------------------------------------------- */ RMvisMap * rmVismapNew (int size) { RMvisMap *v = malloc(sizeof(RMvisMap)); memset(v, 0, sizeof(RMvisMap)); rmVismapSetSize(v, size); return(v); } /* * ---------------------------------------------------- * @Name rmVismapDup @pstart RMvisMap * rmVismapDup (const RMvisMap *toDuplicate) @pend @astart const RMvisMap *toDuplicate - a handle to an RMvisMap @aend @dstart Creates a new RMvisMap object that is an exact duplicate of the input RMvisMap object. Returns a handle to the newly created RMvisMap to the caller if successful, or returns NULL upon failure. The caller should use rmVismapDelete() to free the new RMvisMap object when no longer needed. @dend * ---------------------------------------------------- */ RMvisMap * rmVismapDup (const RMvisMap *toDuplicate) { /* create a new vismap, copy contents of an existing one into it */ RMvisMap *t = rmVismapNew(rmVismapGetSize(toDuplicate)); if (t == NULL) { rmError("rmVismapDup() error: unable to create a new RMvisMap, possibly due to a malloc error inside rmVismapNew()."); return NULL; } /* we really should do a component-by-component copy, but instead.. */ memcpy((void *)t, (void *)toDuplicate, sizeof(RMvisMap)); /* * this works for the time being ONLY because we used fixed-size * arrays for the vismap. when we graduate to dynamically-sized * arrays, things will become more complicated and the memcpy * won't work. */ return(t); } /* * ---------------------------------------------------- * @Name rmVismapDelete @pstart RMenum rmVismapDelete (RMvisMap *toDelete) @pend @astart RMvisMap *toDelete - a handle to an RMvisMap that will be deleted @aend @dstart Releases the resources associated with an RMvisMap object. This routine is the opposite of rmVismapNew(). The caller should not reference the RMvisMap object after making this call. Returns RM_CHILL upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmVismapDelete (RMvisMap *toDelete) { if (toDelete == NULL) { rmWarning("rmVismapDelete() warning: the input RMvisMap object is NULL, avoiding NULL pointer free."); return(RM_WHACKED); } else free(toDelete); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapSetColor3D @pstart RMenum rmVismapSetColor3D (RMvisMap *toModify, int indx, const RMcolor3D *newColor) @pend @astart RMvisMap *toModify - input RMvisMap object that will be modified. int index - an integer index of the entry in the RMvisMap that will be modified. const RMcolor3D *newColor - the 4-component color that will be copied into the RMvisMap at location "index". @aend @dstart Use this routine to set the 3-component color of an RMvisMap object. Each entry in the RMvisMap object is a 4-component color (RGBA), and this routine writes over the RGB channels at one such entry at location "index" in the RMvisMap with the caller supplied data. RM_CHILL is returned upon successful modification of the RMvisMap object. RM_WHACKED is returned if "toModify" is NULL, if "indx" is out of range, or if the input RMcolor3D object "newColor" is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapSetColor3D (RMvisMap *toModify, int indx, const RMcolor3D *newColor) { if ((RM_ASSERT(toModify, "rmVismapSetColor3D() error: the input RMvisMap object is NULL") == RM_WHACKED) || (RM_ASSERT(newColor, "rmVismapSetColor3D() error: the input RMcolorD object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize((const RMvisMap *)toModify, indx, "rmVismapSetColor3D") == RM_WHACKED)) return(RM_WHACKED); toModify->r[indx] = newColor->r; toModify->g[indx] = newColor->g; toModify->b[indx] = newColor->b; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetColor3D @pstart RMenum rmVismapGetColor3D (const RMvisMap *toQuery, int indx, RMcolor3D *retColor) @pend @astart RMvisMap *toQuery - input RMvisMap object that will be queried. int index - an integer index of the entry in the RMvisMap that will be returned to the caller. RMcolor3D *retColor - a handle to an RMcolor3D object that will be modified to contain the 3-component color at location "indx" from within the RMvisMap "toQuery." 3-component color means the R,G,B channels of the RMvisMap; the alpha channel is ignored. @aend @dstart Copies the 3-component color from the RMvisMap object "toQuery" at location "indx" into the caller supplied object. This routine returns RM_CHILL upon success, or RM_WHACKED if "toQuery" is NULL, if "indx" is out of range, or if the pointer to the caller supplied object is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapGetColor3D (const RMvisMap *toQuery, int indx, RMcolor3D *retColor) { if ((RM_ASSERT(toQuery, "rmVismapGetColor3D() error: the input RMvisMap object is NULL") == RM_WHACKED) || (RM_ASSERT(retColor, "rmVismapGetColor3D() error: the return RMcolor3D object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize(toQuery, indx, "rmVismapGetColor3D") == RM_WHACKED)) return(RM_WHACKED); retColor->r = toQuery->r[indx]; retColor->g = toQuery->g[indx]; retColor->b = toQuery->b[indx]; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapSetColor4D @pstart RMenum rmVismapSetColor4D (RMvisMap *toModify, int index, const RMcolor4D *newColor) @pend @astart RMvisMap *toModify - input RMvisMap object that will be modified. int index - an integer index of the entry in the RMvisMap that will be modified. const RMcolor4D *newColor - the 4-component color that will be copied into the RMvisMap at location "index" @aend @dstart Use this routine to set the 4-component color of an RMvisMap object. Each entry in the RMvisMap object is a 4-component color, and this routine writes over one such entry at location "index" in the RMvisMap with the caller supplied data. RM_CHILL is returned upon successful modification of the RMvisMap object. RM_WHACKED is returned if "toModify" is NULL, if "indx" is out of range, or if the input RMcolor4D object "newColor" is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapSetColor4D (RMvisMap *toModify, int indx, const RMcolor4D *newColor) { if ((RM_ASSERT(toModify, "rmVismapSetColor4D() error: the input RMvisMap object is NULL") == RM_WHACKED) || (RM_ASSERT(newColor, "rmVismapSetColor4D() error: the input RMcolor4D object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize((const RMvisMap *)toModify, indx, "rmVismapSetColor4D") == RM_WHACKED)) return(RM_WHACKED); toModify->r[indx] = newColor->r; toModify->g[indx] = newColor->g; toModify->b[indx] = newColor->b; toModify->a[indx] = newColor->a; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetColor4D @pstart RMenum rmVismapGetColor4D (const RMvisMap *toQuery, int indx, RMcolor4D *retColor) @pend @astart RMvisMap *toQuery - input RMvisMap object that will be queried. int index - an integer index of the entry in the RMvisMap that will be returned to the caller. RMcolor4D *retColor - a handle to an RMcolor4D object that will be modified to contain the 4-component color at location "indx" from within the RMvisMap "toQuery." @aend @dstart Copies the 4-component color from the RMvisMap object "toQuery" at location "indx" into the caller supplied object. This routine returns RM_CHILL upon success, or RM_WHACKED if "toQuery" is NULL, if "indx" is out of range, or if the pointer to the caller supplied object is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapGetColor4D (const RMvisMap *toQuery, int indx, RMcolor4D *retColor) { if ((RM_ASSERT(toQuery, "rmVismapGetColor4D() error: the input RMvisMap object is NULL") == RM_WHACKED) || (RM_ASSERT(retColor, "rmVismapGetColor4D() error: the return RMcolor4D object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize(toQuery, indx, "rmVismapGetColor4D") == RM_WHACKED)) return(RM_WHACKED); retColor->r = toQuery->r[indx]; retColor->g = toQuery->g[indx]; retColor->b = toQuery->b[indx]; retColor->a = toQuery->a[indx]; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapSetTfMin @pstart RMenum rmVismapSetTfMin (RMvisMap *toModify, float newTFMin) @pend @astart RMvisMap *toModify - a handle to an RMvisMap object that will be modified by this routine (input). float newTFMin - a floating point value that will be assigned to the RMvisMap object's minimum transfer function attribute. @aend @dstart Use this routine in conjunction with rmVismapSetTfMax to define a linear transfer function for the RMvisMap object. Returns RM_CHILL upon success, or RM_WHACKED if the input RMvisMap object is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapSetTfMin (RMvisMap *toModify, float newTFMin) { if (RM_ASSERT(toModify, "rmVismapSetTfMin() error: the input RMvisMap is NULL") == RM_WHACKED) return(RM_WHACKED); toModify->transfer_min = newTFMin; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetTfMin @pstart float rmVismapGetTfMin (const RMvisMap *toQuery) @pend @astart const RMvisMap *toQuery - a handle to an RMvisMap object (input) @aend @dstart Returns to the caller a floating point value that is the RMvisMap object's transfer function lower bound. @dend * ---------------------------------------------------- */ float rmVismapGetTfMin (const RMvisMap *toQuery) { if (RM_ASSERT(toQuery, "rmVismapGetTfMin error() the input RMvisMap object is NULL") == RM_WHACKED) return(0.0F); return(toQuery->transfer_min); } /* * ---------------------------------------------------- * @Name rmVismapSetTfMax @pstart RMenum rmVismapSetTfMax (RMvisMap *toModify, float newTFMax) @pend @astart RMvisMap *toModify - a handle to an RMvisMap object that will be modified by this routine (input). float newTFMax - a floating point value that will be assigned to the RMvisMap object's maximum transfer function attribute (input). @aend @dstart Use this routine in conjunction with rmVismapSetTfMin to define a linear transfer function for the RMvisMap object. Returns RM_CHILL upon success, or RM_WHACKED if the input RMvisMap object is NULL. @dend * ---------------------------------------------------- */ RMenum rmVismapSetTfMax (RMvisMap *toModify, float newTFMax) { if (RM_ASSERT(toModify, "rmVismapSetTfMax() error: the input RMvisMap is NULL") == RM_WHACKED) return(RM_WHACKED); toModify->transfer_max = newTFMax; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetTfMax @pstart float rmVismapGetTfMax (const RMvisMap *toQuery) @pend @astart const RMvisMap *toQuery - a handle to an RMvisMap object (input) @aend @dstart Returns to the caller a floating point value that is the RMvisMap object's transfer function upper bound. @dend * ---------------------------------------------------- */ float rmVismapGetTfMax (const RMvisMap *toQuery) { if (RM_ASSERT(toQuery,"rmVismapGetTfMax() error: the input RMvisMap object is NULL") == RM_WHACKED) return(0.0F); return(toQuery->transfer_max); } /* * ---------------------------------------------------- * @Name rmVismapIndexFromData @pstart int rmVismapIndexFromData (const RMvisMap *map, float val) @pend @astart const RMvisMap *map - a handle to an RMvisMap object (input). float val - a floating point value (input). @aend @dstart Use this routine to compute an index from a raw data value. RMvisMap objects contain internal parameters to define a transfer function (see rmVismapSetTfMin() and rmVismapSetTfMax() ). This routine computes an integer index thus: ((val-min)/(max-min))*(size-1). The return value is clamped to be in the range 0..size-1, where "size" is the number of entries in the RMvisMap object. @dend * ---------------------------------------------------- */ int rmVismapIndexFromData (const RMvisMap *map, float val) { /* look through the bracket values in the map, return the index into the map */ int index; float fval; if (RM_ASSERT(map, "rmVismapIndexFromData() error: the input RMvisMap object is NULL") == RM_WHACKED) return(0); fval = ((val-map->transfer_min) / (map->transfer_max-map->transfer_min)); if (fval < 0.0) fval = 0.0; else if (fval > 1.0) fval = 1.0; index = (float)(map->nentries - 1) * fval; return(index); } /* * ---------------------------------------------------- * @Name rmVismapSetSize @pstart RMenum rmVismapSetSize (RMvisMap *toModify, int newSize) @pend @astart RMvisMap *toModify - a handle to an RMvisMap object. int newSize - an integer value defining the new number of entries in the RMvisMap object "toModify." @aend @dstart This routine is used to modify the number of entries in the RMvisMap object. The new requested size must be greater than 0 and less than 256. As of 1/15/2000, 256 is the current maximum and default size of the RMvisMap object. This routine does not cause any internal tables to be realloced, it just changes the size attribute of the table. The size attribute is checked by routines that set/get RMvisMap entries in validity checking input. This routine will return RM_CHILL to the caller upon success, or RM_WHACKED if the input RMvisMap object is NULL or if the "newSize" parameter is out of range. @dend * ---------------------------------------------------- */ RMenum rmVismapSetSize (RMvisMap *toModify, int newSize) { if (RM_ASSERT(toModify, "rmVismapSetSize() error: the input RMvisMap object is NULL") == RM_WHACKED) return(RM_WHACKED); if ((newSize <= 0) || (newSize > RMV_DEFAULT_MAP_SIZE )) { rmError(" rmVismapSetSize() the requested newSize is either too large or too small."); return(RM_WHACKED); } /* * TODO: * * at this time (1/15/2000) the size of the R,G,B,A tables in the * RMvisMap object is fixed, defined by the constant RMV_DEFAULT_MAP_SIZE. * at some point in the future, we will want to dynamically allocate * those tables. when we do that, we'll need to change this set size * routine to realloc the tables to the new requested size. */ toModify->nentries = newSize; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetSize @pstart int rmVismapGetSize (const RMvisMap *toQuery) @pend @astart const RMvisMap *toQuery - a handle to the RMvisMap object to be queried. @aend @dstart Returns to the caller the number of entries in the visualization colormap of the of the RMvisMap object. A non-negative integer is returned upon success, or -1 is returned if the input RMvisMap object is NULL. @dend * ---------------------------------------------------- */ int rmVismapGetSize (const RMvisMap *toQuery) { if (RM_ASSERT(toQuery, "rmVismapGetSize() error: input RMvisMap pointer is NULL.") == RM_WHACKED) return(-1); return(toQuery->nentries); } /* * ---------------------------------------------------- * @Name rmVismapSetAlpha @pstart RMenum rmVismapSetAlpha (RMvisMap *toModify, int indx, float newAlpha) @pend @astart RMvisMap *toModify - a handle to an RMvisMap object (input). int indx - an integer value specifying which entry of the RMvisMap object will be modified by this routine (input). float newAlpha - a floating point value that will be copied into the RMvisMap object "toModify" at location "indx". Alpha values usually range between 0.0 and 1.0. @aend @dstart Sets that alpha component of the 4-component color in the RMvisMap object "toModify" at entry "indx." Returns RM_CHILL to the caller if successful. RM_WHACKED is returned if "toModify" is NULL, or if "indx" is out of range. @dend * ---------------------------------------------------- */ RMenum rmVismapSetAlpha (RMvisMap *toModify, int indx, float value) { if ((RM_ASSERT(toModify, "rmVismapSetAlpha() error: the input RMvisMap object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize(toModify, indx, "rmVismapSetAlpha") == RM_WHACKED)) return(RM_WHACKED); toModify->a[indx] = value; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmVismapGetAlpha @pstart float rmVismapGetAlpha (const RMvisMap *toQuery, int indx) @pend @astart const RMvisMap *toQuery - a handle to an RMvisMap object to be queried (input). int indx - the index of the entry in the RMvisMap object to query (input). @aend @dstart Returns to the caller the alpha component of the RMvisMap object at entry "indx." If "indx" is out of range, rmWarning() is called issuing an error message, and -1.0 is returned to the caller. Alpha values usually range between 0.0 and 1.0. @dend * ---------------------------------------------------- */ float rmVismapGetAlpha (const RMvisMap *toQuery, int indx) { if ((RM_ASSERT(toQuery, "rmVismapGetAlpha() error: the input RMvisMap object is NULL") == RM_WHACKED) || (private_rmVismapCheckSize(toQuery, indx, "rmVismapGetAlpha") == RM_WHACKED)) return(0.0F); else return(toQuery->a[indx]); } /* * ---------------------------------------------------- * @Name rmDefaultVismap @pstart RMvisMap *rmDefaultVismap (void) @pend @astart No arguments. @aend @dstart This routine performs a two-fold function. First, it creates a new RMvisMap object containing 256 entries. Second, it assigns default values to the RGBA channels of the new colormap. A handle to the new RMvisMap object is returned to the caller. When caller no longer needs the RMvisMap object, use "rmVismapDelete()" to free the object. The default colormap will be set to: 1. A hue ramp from .66 to 0.0 (blue-cyan-green-yellow-orange-red) 2. Constant saturation & brightness of 1.0 3. Alpha ramp from 0..1 (low to high) 4. transfer function min/max of 0..1 @dend * ---------------------------------------------------- */ RMvisMap * rmDefaultVismap (void) { int i, n; float h, dh, s, v, a, da; RMvisMap *t; RMcolor3D rgb; n = RMV_DEFAULT_MAP_SIZE; t = rmVismapNew(n); if (t == NULL) { rmError(" rmDefaultVismap() error: unable to allocate a new RMvisMap object."); return(NULL); } h = 0.66F; dh = -0.66 / (float)(n - 1); s = 1.0; v = 1.0; a = 0.0; da = 1.0 / (float)(n - 1); for (i = 0; i < n; i++) { rmHSVtoRGB(h, s, v, &(rgb.r), &(rgb.g), &(rgb.b)); rmVismapSetColor3D(t, i, &rgb); rmVismapSetAlpha(t, i, a); h += dh; a += da; } rmVismapSetTfMin(t, 0.0F); rmVismapSetTfMax(t, 1.0F); return(t); } /* PRIVATE * * private_rmVismapCheckSize performs a validity/range check operation. The * input parameter "indx" is compared to the RMvisMap object's size attribute. * If "indx" is greater than or equal to zero, but less than the RMvisMap * object's size attribute, this routine returns RM_CHILL. Otherwise, * rmWarning is called with a descriptive error message, and RM_WHACKED * is returned to the caller. */ RMenum private_rmVismapCheckSize (const RMvisMap *v, int indx, char *funcName) { if ((indx < 0) || (indx >= rmVismapGetSize(v))) { char buf[1024]; if (strlen(funcName) > 900) { rmWarning("private_rmVismapCheckSize() warning: the index into the RMvisMap object is out of range, and the string length of the function name is unreasonable."); return(RM_WHACKED); } sprintf(buf, "in function %s the index (value = %d) is out of range (<= 0 or >= %d) \n", funcName, indx, rmVismapGetSize(v)); rmWarning(buf); return(RM_WHACKED); } else return(RM_CHILL); } /* EOF */