static Field RefineField(Field field, char *args, int l) { int limit = ((Args *)args)->limit; Field newField; Array array; if (DXEmptyField(field)) return DXEndField(DXNewField()); field = (Field)DXCopy((Object)field, COPY_STRUCTURE); if (! field) return NULL; array = (Array)DXGetComponentValue(field, "connections"); if (DXQueryGridConnections(array, NULL, NULL)) newField = _dxfRefineReg(field, limit); else newField = _dxfRefineIrreg(field, limit); if (newField == NULL) DXDelete((Object)field); return newField; }
Error m_MakeXEfficient(Object *in, Object *out) { int i; /* * Initialize all outputs to NULL */ out[0] = NULL; /* * Error checks: required inputs are verified. */ /* Parameter "input" is required. */ if (in[0] == NULL) { DXSetError(ERROR_MISSING_DATA, "\"input\" must be specified"); return ERROR; } /* * Since output "output" is structure Field/Group, it initially * is a copy of input "input". */ out[0] = DXCopy(in[0], COPY_STRUCTURE); if (! out[0]) goto error; /* * If in[0] was an array, then no copy is actually made - Copy * returns a pointer to the input object. Since this can't be written to * we postpone explicitly copying it until the leaf level, when we'll need * to be creating writable arrays anyway. */ if (out[0] == in[0]) out[0] = NULL; /* * Call the hierarchical object traversal routine */ if (!traverse(in, out)) goto error; return OK; error: /* * On error, any successfully-created outputs are deleted. */ for (i = 0; i < 1; i++) { if (in[i] != out[i]) DXDelete(out[i]); out[i] = NULL; } return ERROR; }
Error m_MachNumber (Object * in,Object * out) { Object * get; int fields,i,ngases; /* Verify input */ if (in[0]==NULL) { DXSetError(ERROR_MISSING_DATA,"Input field 0 must be specified"); goto error; } if (!DXExtractInteger(in[0],&ngases)) { DXSetError(ERROR_DATA_INVALID,"Could not extract INTEGER from field 0"); goto error; } fields=INPUT_FIELDS+ngases; if (ngases < NGASES_MIN || ngases > NGASES_MAX) { DXSetError(ERROR_BAD_PARAMETER, "The value of input field 0 must be %d <= X <= %d", NGASES_MIN,NGASES_MAX); goto error; } for (i=1; i<fields; i++) { if (in[i]==NULL) { DXSetError(ERROR_MISSING_DATA,"Input field %d must be specified",i); goto error; } } /* Since this module is meant to operate on an existing Field / MultiGrid * object, initialize the output fields as a copy of the second input * field. */ for (i=0; i<OUTPUT_FIELDS; i++) { if (!(out[i]=DXCopy(in[1],COPY_STRUCTURE))) goto error; /* If in[1] is an array, DXCopy() will return a pointer to the input * object. Since this cannot be written to, an exception will be * raised. */ if (in[1]==out[i]) { DXSetError(ERROR_DATA_INVALID, "Input fields 1-%d should be Field / MultiGrid objects", fields); goto error; } } /* Skip the first input field as it is not a Field / MultiGrid object. */ get=in+1; if (!traverse (w_MachNumber,get,fields-1,out,OUTPUT_FIELDS)) goto error; return OK; error: for (i=0; i<OUTPUT_FIELDS; i++) { DXDelete(out[i]); out[i]=NULL; } return ERROR; }
Error m_Options(Object *in, Object *out) { Object a, v; char *s; int i; /* check input object */ if (!in[0]) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "input"); return ERROR; } /* create output copy */ out[0] = DXCopy(in[0], COPY_HEADER); if (!out[0]) return ERROR; /* arrays don't copy by default - you have to call something special * to get a new copy. */ if (out[0] == in[0] && DXGetObjectClass(in[0]) == CLASS_ARRAY) { out[0] = (Object)_dxfReallyCopyArray((Array)in[0]); if (!out[0]) return ERROR; } /* set attributes */ for (i=0; i<PAIRS; i++) { a = in[2*i+1]; v = in[2*i+2]; if (a) { if (!DXExtractString(a, &s)) { DXSetError(ERROR_BAD_PARAMETER, "#10200", "attribute name"); goto error; } /* NB - ok for v to be NULL - this deletes the attribute */ if (!DXSetAttribute(out[0], s, v)) goto error; } } return OK; error: if (out[0] != in[0]) DXDelete(out[0]); out[0] = NULL; return ERROR; }
Error m_SXEnum( Object *in, Object*out){ /* *+ * Name: * SXEnum * Purpose: * enumerating the positions or connections in a field * Language: * ANSI C * Syntax: * output = SXEnum( input, name, dep ); * Classification: * Realisation * Description: * The SXEnum module creates the component specified by "name", and adds * it to the "output" field. The values in the new component start at zero * and increment by one for each position or connection in the field. * * The new component is in one-to-one correspondance with either the * "positions" or "connections" component, dependant on "dep". * Parameters: * input = field (Given) * input field [none] * name = string (Given) * name of component to store the enumeration ["data"] * dep = string (Given) * object to be enumerated; "positions" or "connections" ["positions"] * output = field (Returned) * output field * Components: * Adds a component with the given "name", deleting any existing * component. All other components are copied from the "input" field. * Examples: * In this example, the 17th frame is extracted from a data set * containing scattered data, and a field created holding only those * positions with offsets between 10 and 20. * * input = Import("/usr/lpp/dx/samples/data/CO2.general"); * frame17 = Select(input,17); * enum = SXEnum(frame17,"index","positions"); * marked = Mark(enum,"index"); * included = Include(marked,10,20,1); * subset = Unmark(included,"index"); * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * 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 of * the License, 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., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 25-SEP-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables. */ char *dep; char *name; Object o=NULL; /* Check that the "input" object has been supplied. */ if( !in[0] ){ DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"input\"."); goto error; } /* Get a value for the "name" object. */ if( !in[1] ){ name = "data"; } else { name = DXGetString( (String) in[1] ); if( !name ){ DXSetError( ERROR_BAD_PARAMETER, "unable to get string parameter \"name\"."); goto error; } } /* Get a value for the "dep" object. */ if( !in[2] ){ dep = "positions"; } else { dep = DXGetString( (String) in[2] ); if( !dep ){ DXSetError( ERROR_BAD_PARAMETER, "unable to get string parameter \"dep\"."); goto error; } if( strcmp( dep, "positions" ) && strcmp( dep, "connections" ) ){ DXSetError( ERROR_BAD_PARAMETER, "bad value (\"%s\") obtained for parameter \"dep\".",dep ); goto error; } } /* Get a modifiable copy of the "input" object. */ o = (Object) DXCopy( in[0], COPY_STRUCTURE ); if( !o ) goto error; /* Enumerate it. */ if( !DoSXEnum( o, name, dep ) ) goto error; /* Return the output object. */ out[0] = o; return( OK ); error: DXDelete( o ); return( ERROR ); }
static void Slide2DEndStroke(void *data, DXMouseEvent *event) { Slide2DData sdata = (Slide2DData)data; int b = WHICH_BUTTON(event); int dx, dy; Object member; char *name; Point corners[8]; int i; if (!sdata) return; sdata = (Slide2DData)data; if (! sdata) return; dx = sdata->buttonPosition[b].x - event->x; dy = -(sdata->buttonPosition[b].y - event->y); sdata->buttonPosition[b].x = event->x; sdata->buttonPosition[b].y = event->y; sdata->strokeStart = 1; /* * End stroke. If its the left button or up'n'downish right button, * we operate on a member of the scene group. If its a left'n'right * middle button, we operate on the camera */ if (b == 0 || ((b == 1) && (abs(dy) > abs(dx)))) { Group og = (Group)sdata->obj, ng; /* * Can't do anything if we don't have a scene object group or an * arg telling us what member to operate on */ if ((sdata->label == NULL && sdata->index == -1) || !sdata->obj) return; /* * Create a new group header. */ ng = (Group)DXCopy(sdata->obj, COPY_ATTRIBUTES); if (! ng) return; /* * Loop through the scene object group. For each member NOT matching * the argument, just copy it into the new group. Otherwise, twiddle * its transform matrix and put it there. */ i = 0; while (NULL != (member = DXGetEnumeratedMember((Group)og, i++, &name))) { if ((sdata->label && !strcmp(name, sdata->label)) || ((i-1) == sdata->index)) { Object attr; /* * This is the one to manipulate. It better be a * 'transformed object' type. */ attr = DXGetAttribute(member, "object type"); if (! attr) continue; if (strcmp(DXGetString((String)attr), "transformed object")) continue; if (b == 0) { Vector x; Xform oldx = (Xform)member; Matrix oldm, newm; Object xchild; /* * Its the left button. Determine the world space * vector corresponding to the screen-space stroke, and * concatenate it onto the matrix already associated with * the object, and create a new DX Transform object with * the old transforms child and the concatenated matrices. */ x.x = -(dx * sdata->gt); x.y = -(dy * sdata->gt); x.z = 0.0; DXGetXformInfo(oldx, &xchild, &oldm); newm = DXTranslate(x); newm = DXConcatenate(oldm, newm); member = (Object)DXNewXform(xchild, newm); DXSetAttribute(member, "object type", attr); } else if (DXBoundingBox(member, corners)) { Angle r; Xform oldx = (Xform)member; Matrix oldm, newm; Object xchild; Vector center; /* * Then its an up'n'down middle button stroke. Create * a matrix that transforms the object back to the origin, * rotates it, and then back to where it was. */ DXGetXformInfo(oldx, &xchild, &oldm); /* * Move the object so its center is at the origin */ center.x = -(corners[0].x + corners[7].x) / 2.0; center.y = -(corners[0].y + corners[7].y) / 2.0; center.z = -(corners[0].z + corners[7].z) / 2.0; newm = DXTranslate(center); oldm = DXConcatenate(oldm, newm); /* * Rotate */ r = dy * sdata->gr * (2*3.14159); newm = DXRotateZ(r); oldm = DXConcatenate(oldm, newm); /* * Move the object back to its original location */ center.x = -center.x; center.y = -center.y; center.z = -center.z; newm = DXTranslate(center); oldm = DXConcatenate(oldm, newm); member = (Object)DXNewXform(xchild, oldm); DXSetAttribute(member, "object type", attr); } } DXSetMember(ng, name, member); } DXDelete(sdata->obj); sdata->obj = DXReference((Object)ng); } else if ((b == 1) && (abs(dx) > abs(dy))) { /* * Its a left'n'right middle button. Alter the camera's width * parameter based on a scaled stroke dx. */ sdata->width += (sdata->width * dx)/sdata->w; } return; }
Error m_SXConstruct( Object *in, Object*out){ /* *+ * Name: * SXConstruct * Purpose: * constructs a regular field with regular connections * Language: * ANSI C * Syntax: * output = SXConstruct( object, lower, upper, deltas, counts ); * Classification: * Realization * Description: * The SXConstruct module constructs a field with regular positions * and connections covering a volume with specified bounds. It is * similar to the standard Construct module, but is somewhat easier to * use if a simple grid is required. * If "object" is given, its bounds define the extent of the output * field. Otherwise, the vectors given for "upper" and "lower" define * the extent of the output field. * If "deltas" is supplied, it defines the distances between adjacent * positions on each axis. It should be a vector with the same number * of dimensions as "upper" and "lower", or a single value (in which * case the supplied value is used for all axes). The upper and lower * bounds are expanded if necessary until they span an integer number * of deltas. * * If "deltas" is not supplied, then "counts" must be supplied and * should be an integer vector giving the number of positions on each * axis, or a single integer (in which case the same value is used for * all axes). * Parameters: * object = field (given) * object to define extent of new field [none] * lower = vector (Given) * explicit lower bounds of new field [none] * upper = vector (Given) * explicit upper bounds of new field [none] * deltas = scalar or vector (Given) * increment for each axis * counts = integer or vector (Given) * number of positions along each axis * output = field (Returned) * output field * Components: * The output has "positions", "connections" and "box" components, but * no "data" component. * Examples: * This example imports a scattered data set from "C02.general", * extracts a single frame, uses SXConstruct to make a grid covering the * bounds of the frame, with increments of 10.0 along each axis, and * then uses SXBIN to find the mean data value in each of the square * connections of this new grid. the resulting field is displayed. * * data = Import("/usr/lpp/dx/samples/data/CO2.general"); * frame17 = Select(data,17); * newgrid = SXConstruct(frame17,deltas=10); * binned = SXBin(frame17,newgrid); * coloured = AutoColor(binned); * camera = AutoCamera(coloured); * Display(coloured,camera); * See Also: * Construct, Grid * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * 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 of * the License, 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., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 18-OCT-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables. */ int cnt[3]; /* Counts */ int *counts; /* Pointers to counts */ float del[3]; /* Deltas */ float del3d[9]; /* 3-D Deltas */ float *deltas; /* Pointers to deltas */ float *lower; /* Pointer to lower bounds */ float *upper; /* Pointer to upper bounds */ float lbnd[3]; /* lower bounds */ float ubnd[3]; /* upper bounds */ int ndim; /* No. of components for each vector */ int ndim2; /* No. of dimensions in second object */ Object o=NULL; /* Output object */ float bnd; /* Current bound value */ Point box[8]; /* Bounding box */ Category cat; /* Array category */ Array array; /* An array */ float *box_ptr; /* Pointer to box array */ int i; /* Loop count */ int j; /* Loop count */ int ncorn; /* No. of corners in the bounding box */ int rank; /* Array rank */ float tmp; /* Swapping space */ Type type; /* Array numeric type */ /* If OBJECT was supplied, check it is a field. */ if( in[0] ){ if( DXGetObjectClass(in[0]) != CLASS_FIELD ){ DXSetError( ERROR_BAD_TYPE, "input object is not a field" ); goto error; } /* Take a copy of it. */ o = DXCopy( in[0], COPY_STRUCTURE ); /* Get the bounding box component from the object */ array = (Array) DXGetComponentValue( (Field) o, "box" ); /* If no bounding box was found, create one. */ if( !array ){ if( !DXBoundingBox( o, box ) ){ DXSetError( ERROR_UNEXPECTED, "cannot obtain a bounding box." ); goto error; } array = (Array) DXGetComponentValue( (Field) o, "box" ); } /* Get a pointer to the bounding box array and the number of items in * the array, etc. */ box_ptr = (float *) DXGetArrayData( array ); DXGetArrayInfo( array, &ncorn, &type, &cat, &rank, &ndim ); if( type != TYPE_FLOAT ){ DXSetError( ERROR_BAD_TYPE, "input object positions are not TYPE_FLOAT"); goto error; } if( cat != CATEGORY_REAL ){ DXSetError( ERROR_BAD_TYPE, "input object positions are not REAL"); goto error; } if( rank > 1 ){ DXSetError( ERROR_BAD_TYPE, "input object positions have rank larger than 1"); goto error; } if( rank == 0 ) ndim = 1; if( ndim > 3 ){ DXSetError( ERROR_BAD_TYPE, "input object positions have more than 3 dimensions"); goto error; } /* Store the bounds for each dimension. */ for( j=0; j<ndim; j++){ lbnd[j] = FLT_MAX; ubnd[j] = FLT_MIN; } for( i=0; i<ncorn; i++ ){ for( j=0; j<ndim; j++ ){ bnd = *(box_ptr++); if( bnd < lbnd[j] ) lbnd[j]=bnd; if( bnd > ubnd[j] ) ubnd[j]=bnd; } } /* Delete the copy of the input object */ DXDelete( o ); o = NULL; array = NULL; /* If OBJECT was not supplied, get the bounds from LOWER and UPPER. */ } else { if( !in[1] ) { DXSetError( ERROR_MISSING_DATA, "No lower bounds supplied"); goto error; } else { lower = SXGet1r( "lower", in[1], &ndim ); if( !lower ) goto error; if( ndim > 3 ){ DXSetError( ERROR_BAD_TYPE, "lower bounds have more than 3 dimensions"); goto error; } } if( !in[2] ) { DXSetError( ERROR_MISSING_DATA, "No upper bounds supplied"); goto error; } else { upper = SXGet1r( "upper", in[2], &ndim2 ); if( !upper ) goto error; if( ndim2 != ndim ){ DXSetError( ERROR_BAD_TYPE, "number of upper and lower bounds does not match"); goto error; } } for( j=0; j<ndim; j++){ lbnd[j] = lower[j]; ubnd[j] = upper[j]; } } /* Ensure bounds are OK. */ for( j=0; j<ndim; j++ ){ if( ubnd[j] < lbnd[j] ) { tmp = ubnd[j]; ubnd[j] = lbnd[j]; lbnd[j] = tmp; } } /* If DELTAS was supplied, get its values and check dimensionality. */ if( in[3] ){ deltas = SXGet1r( "deltas", in[3], &ndim2 ); if( ndim2 == 1 ){ for( j=0; j<ndim; j++){ del[j] = *deltas; } } else { if( ndim2 != ndim ){ DXSetError( ERROR_BAD_TYPE, "incorrect number of deltas given"); goto error; } else { for( j=0; j<ndim; j++){ del[j] = deltas[j]; } } } /* Find the corresponding counts and adjust lower bounds */ for( j=0; j<ndim; j++ ){ if( del[j] > 0.0 ){ cnt[j] = 1 + (int) ( 0.9999 + (ubnd[j]-lbnd[j])/del[j] ); lbnd[j] = 0.5*( ubnd[j] + lbnd[j] - ( cnt[j] - 1 )*del[j] ); } else { DXSetError( ERROR_BAD_TYPE, "negative or zero delta given"); goto error; } } /* If COUNTS was supplied, get its values and check dimensionality. */ } else if( in[4] ){ counts = SXGet1i( "counts", in[4], &ndim2 ); if( ndim2 == 1 ){ for( j=0; j<ndim; j++){ cnt[j] = *counts; } } else { if( ndim2 != ndim ){ DXSetError( ERROR_BAD_TYPE, "incorrect number of counts given"); goto error; } else { for( j=0; j<ndim; j++){ cnt[j] = counts[j]; } } } /* Find corresponding DELTAS */ for( j=0; j<ndim; j++ ){ if( cnt[j] > 1 ) { del[j] = ( ubnd[j] - lbnd[j] )/( (float) cnt[j] - 1 ); } else { cnt[j] = 1; del[j] = 1.0; tmp = 0.5*( ubnd[j]+ lbnd[j] ); ubnd[j] = tmp; lbnd[j] = tmp; } } /* report an error if neither COUNTS nor DELTAS was supplied. */ } else { DXSetError( ERROR_MISSING_DATA, "no deltas or counts given"); goto error; } /* Construct the n-d delta vectors, form the increments on each axis. */ for( j=0; j<9; j++ ) del3d[j] = 0.0; for( j=0; j<ndim; j++ ) del3d[ j*(ndim+1) ] = del[j]; /* Create the output field. */ o = (Object) DXNewField(); if( !o ) goto error; /* Create the positions array and put it in the field. */ array = DXMakeGridPositionsV( ndim, cnt, lbnd, del3d ); if( !array ) goto error; if( !DXSetComponentValue( (Field) o, "positions", (Object) array ) ) goto error; array = NULL; /* Create the connections array and put it in the field. */ array = DXMakeGridConnectionsV( ndim, cnt ); if( !array ) goto error; if( !DXSetComponentValue( (Field) o, "connections", (Object) array ) ) goto error; array = NULL; /* Finish the field */ if( !DXEndField( (Field) o ) ) goto error; /* Return the output field. */ out[0] = o; return( OK ); error: DXDelete( o ); return( ERROR ); }
int m_Convert(Object *in, Object *out) { Array incolorvec, outcolorvec; int ismap, isfield, count, i, ii, numitems, addpoints; char *colorstrin, *colorstrout; char newstrin[30], newstrout[30]; Object gout; float *dpin=NULL, *dpout=NULL; gout=NULL; incolorvec = NULL; outcolorvec = NULL; if (!in[0]) { DXSetError(ERROR_MISSING_DATA,"#10000","data"); return ERROR; } out[0] = in[0]; ismap = 0; isfield = 0; /* * if it's an array (vector or list of vectors) */ if (DXGetObjectClass(in[0]) == CLASS_ARRAY) { if (!(DXQueryParameter((Object)in[0], TYPE_FLOAT, 3, &numitems))) { /* must be a list of 3-vectors or a field */ DXSetError(ERROR_BAD_PARAMETER,"#10550","data"); out[0] = NULL; return ERROR; } if (!(incolorvec = DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 1, 3))){ out[0] = NULL; return ERROR; } if (!(DXAddArrayData(incolorvec,0,numitems,NULL))) goto error; if (!(dpin = (float *)DXGetArrayData(incolorvec))) goto error; if (!(DXExtractParameter((Object)in[0], TYPE_FLOAT, 3, numitems, (Pointer)dpin))) { /* must be a list of 3-vectors or a field */ DXSetError(ERROR_BAD_PARAMETER,"#10550","data"); goto error; } /* * also make the output array */ if (!(outcolorvec = DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 1, 3))) goto error; if (!(DXAddArrayData(outcolorvec,0,numitems,NULL))) goto error; if (!(dpout = (float *)DXGetArrayData(outcolorvec))) goto error; } else { if (_dxfIsColorMap(in[0])) ismap = 1; else { DXResetError(); isfield = 1; } } /* now extract the to and from space names */ /* get color name */ if (!(in[1])) colorstrin = "hsv"; else if (!DXExtractString((Object)in[1], &colorstrin)) { /* invalid input string */ DXSetError(ERROR_BAD_PARAMETER,"#10200","incolorspace"); goto error; } /* convert color name to all lower case and remove spaces */ count = 0; i = 0; while ( i<29 && colorstrin[i] != '\0') { if (isalpha(colorstrin[i])){ if (isupper(colorstrin[i])) newstrin[count]= tolower(colorstrin[i]); else newstrin[count]= colorstrin[i]; count++; } i++; } newstrin[count]='\0'; if (strcmp(newstrin,"rgb")&&strcmp(newstrin,"hsv")) { DXSetError(ERROR_BAD_PARAMETER,"#10210", newstrin, "incolorspace"); goto error; } if (!in[2]) colorstrout = "rgb"; else if (!DXExtractString((Object)in[2], &colorstrout)) { /* invalid outcolorspace string */ DXSetError(ERROR_BAD_PARAMETER,"#10200","outcolorspace"); goto error; } /* convert color name to all lower case and remove spaces */ count = 0; i = 0; while ( i<29 && colorstrout[i] != '\0') { if (isalpha(colorstrout[i])){ if (isupper(colorstrout[i])) newstrout[count]= tolower(colorstrout[i]); else newstrout[count]= colorstrout[i]; count++; } i++; } newstrout[count]='\0'; if (strcmp(newstrout,"rgb")&&strcmp(newstrout,"hsv")){ /* invalid outcolorspace string */ DXSetError(ERROR_BAD_PARAMETER,"#10210", newstrout, "outcolorspace"); goto error; } if (!strcmp(newstrin,newstrout)) { DXWarning("incolorspace and outcolorspace are the same"); return OK; } if (!in[3]) { /* default behavior is to treat maps like maps (adding points) and to treat fields like fields (not adding points) */ } else { if (!DXExtractInteger(in[3], &addpoints)) { DXSetError(ERROR_BAD_PARAMETER, "#10070", "addpoints"); goto error; } if ((addpoints < 0) || (addpoints > 1)) { DXSetError(ERROR_BAD_PARAMETER, "#10070", "addpoints"); goto error; } if (isfield && addpoints) { DXSetError(ERROR_BAD_PARAMETER, "#10370", "for a field with greater than 1D positions, addpoints", "0"); goto error; } if (ismap && (!addpoints)) { /* treat the map like a field */ ismap = 0; isfield = 1; } } /* we have been given a vector value or list of values, not a map */ if ((!ismap)&&(!isfield)) { if (!strcmp(newstrin,"hsv")) { for (ii = 0; ii < numitems*3; ii = ii+3) { if (!(_dxfHSVtoRGB(dpin[ii], dpin[ii+1], dpin[ii+2], &dpout[ii], &dpout[ii+1], &dpout[ii+2]))) goto error; } } else { for (ii = 0; ii < numitems*3; ii = ii+3) { if (!(_dxfRGBtoHSV(dpin[ii], dpin[ii+1], dpin[ii+2], &dpout[ii], &dpout[ii+1], &dpout[ii+2]))) goto error; } } out[0] = (Object)outcolorvec; DXDelete((Object)incolorvec); return OK; } /* we have a map or field */ else { if (ismap) { if (!(ConvertObject(in[0], newstrin, &gout))) goto error; } else { gout = DXCopy(in[0], COPY_STRUCTURE); if (!gout) goto error; if (!(ConvertFieldObject(gout, newstrin))) goto error; } out[0] = gout; return OK; } error: out[0] = NULL; DXDelete((Object)gout); DXDelete((Object)incolorvec); DXDelete((Object)outcolorvec); return ERROR; }
Error m_SXRegrid( Object *in, Object *out ){ /* *+ * Name: * SXRegrid * Purpose: * samples a field at positions defined by a another field * Language: * ANSI C * Syntax: * output = SXRegrid( input, grid, nearest, radius, scale, exponent, * coexp, type ); * Classification: * Realisation * Description: * The SXRegrid module samples the "data" component of the "input" * field at the positions held in the "positions" component of the * "grid" field. It is similar to the standard "Regrid" module, but * provides more versatility in assigning weights to each input position, * the option of returning the sums of the weights or the weighted sum * instead of the weighted mean, and seems to be much faster. Both * supplied fields can hold scattered or regularly gridded points, and * need not contain "connections" components. The "data" component in the * "input" field must depend on "positions". * * For each grid position, a set of near-by positions in the input * field are found (using "nearest" and "radius"). Each of these input * positions is given a weight dependant on its distance from the current * grid position. The output data value (defined at the grid position) can * be the weighted mean or weighted sum of these input data values, or * the sum of the weights (selected by "type"). * * The weight for each input position is of the form: * * (d/d0)**exponent * * where "d" is the distance from the current grid position to the * current input position. If a single value is given for "scale" then * that value is used for the d0 constant for all the near-by input * positions. If more than 1 value is given for "scale" then the first * value is used for the closest input position, the second value for the * next closest, etc. The last supplied value is used for any remaining * input positions. A value of zero for "scale" causes the * corresponding input position to be given zero weight. * * If "coexp" is not zero, then the above weights are modified to * become: * * exp( coexp*( (d/d0)**exponent ) ) * * If "nearest" is given an integer value, it specifies N, the maximum * number of near-by input positions to use for each output position. * The N input positions which are closest to the output position are * used. If the string "infinity" is given, then all input positions * closer than the distance given by "radius" are used. Using "radius", * you may specify a maximum radius (from the output position) within * which to find the near-by input positions. If the string "infinity" * is given for "radius" then no limit is placed on the radius. * Parameters: * input = field (Given) * field or group with positions to regrid [none] * grid = field (Given) * grid to use as template [none] * nearest = integer or string (Given) * number of nearest neighbours to use, or "infinity" [1] * radius = scalar or string (Given) * radius from grid point to consider, or "infinity" ["infinity"] * scale = scalar or vector or scalar list (Given) * scale lengths for weights [1.0] * exponent = scalar (Given) * weighting exponent [1.0] * coexp = scalar (Given) * exponential co-efficient for weights [0.0] * type = integer (Given) * type of output values required: 0 - weighted mean, 1 - weighted sum, * 2 - sum of weights [0] * output = field (Returned) * regridded field * Components: * All components except the "data" component are copied from the "grid" * field. The output "data" component added by this module depends on * "positions". An "invalid positions" component is added if any output * data values could not be calculated (e.g. if there are no near-by input * data values to define the weighted mean, or if the weights are too * large to be represented, or if the input grid position was invalid). * Examples: * This example maps the scattered data described in "CO2.general" onto a * regular grid, and displays it. SXRegrid is used to find the data value * at the nearest input position to each grid position. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * regrid = SXRegrid(frame17,grid); * coloured = AutoColor(regrid); * Display(coloured,camera); * * The next example produces a grid containing an estimate of the density * of the scattered points (i.e. the number of points per unit area). The * positions of the original scattered points are shown as dim grey * circles. SXRegrid finds the 5 closest input positions at each grid * position. Zero weight is given to the closest 3 positions. The fourth * position has a weight which is half the density of the points within the * circle passing through the fourth point (i.e. if the fourth point * is at a distance D from the current grid position, there are 3 points * within a circle of radius D, so the density within that circle is * 3/(PI*(D**2)) ). The fifth position has a weight which is half the * density of the points within the circle passing through the fifth * point. The output data value is the sum of the weights (because * "type" is set to 2), which is the mean of the densities within the * circles touching the fourth and fifth points. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * glyphs=AutoGlyph(frame17,scale=0.1,ratio=1); * glyphs=Color(glyphs,"dim grey"); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * density=SXRegrid(frame17,grid,nearest=5,scale=[0,0,0,0.691,0.798], * exponent=-2,type=2); * coloured = AutoColor(density); * collected=Collect(coloured,glyphs); * Display(collected,camera); * See Also: * SXBin, ReGrid, Map, Construct * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * 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 of * the License, 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., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 3-OCT-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ Category cat; /* Array category type */ float coexp; /* Exponential co-efficient for weights */ Type dtype; /* Type of current input data array */ float ext; /* Amount by which to extend grid bounds */ int fld; /* Field counter */ Object grid; /* The grid object */ float *gridpos; /* Pointer to grid positions array */ int i; /* Loop count */ void *indata[MAXFLD];/* Pointer to input data array */ float *inpos; /* Pointer to input positions array */ Array inpos_array; /* Input positions array */ Object input; /* A copy of the input object */ int iopt; /* Index of selected option */ int j; /* Loop count */ float lbnd[3]; /* Lower bounds of grid */ char *opt; /* Textual option for a parameter value */ float radius; /* Max. radius for contributing input positions */ char more; /* Are there more input fields to do? */ int nearest; /* Max. no. of input positions which can contribute to an output position */ Fpair *next; /* The next Fpair structure in the linked list */ int ndim; /* No. of dimensions in grid positions array */ int nfld; /* No. of fields sharing current positions array */ int npos; /* No. of input positions */ int npindim; /* No. of dimensions in input positions array */ int nsamp; /* No. of grid positions */ int nscale; /* No. of scale distances supplied */ int outbad[MAXFLD];/* No. of invalid output positions in each field*/ void *outdata[MAXFLD];/* Pointers to output data arrays */ Array outdata_array;/* Output data array */ Object output; /* The output object */ int outtype; /* Type of output values required */ float exponent; /* Power for weights */ int rank; /* Array rank */ float rsc; /* Reciprocal squared scale distance*/ float *rscale; /* Scale distances for weights */ int tag; /* The tag for the current input positions array */ Type type; /* Array numeric type */ float ubnd[3]; /* Upper bounds of grid */ int veclen[MAXFLD];/* Dimensionality of each input data array */ /* Initialise all created objects so that they can safely be deleted if * an error occurs. */ input = NULL; output = NULL; grid = NULL; outdata_array = NULL; /* Check that the "input" object has been supplied. */ if( !in[0] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"input\"." ); goto error; } /* Remove (cull) all invalid positions and connections from the input. It is * necessary to take a copy of the input first, because the input object * itself cannot be modified. */ input = DXCopy( in[0], COPY_STRUCTURE ); if( !DXCull( input ) ) goto error; /* Check that the "grid" object has been supplied. */ if( !in[1] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"grid\"." ); goto error; } /* Get a pointer to an array holding the grid positions, and get the * size and shape of the grid. Any invalid positions are flagged with the * value FLT_MAX (defined in float.h). */ gridpos = SXGetGrid( in[1], &nsamp, &ndim, lbnd, ubnd, &grid ); if( !gridpos ) goto error; /* Get the number of input positions allowed to contribute to each * output position. */ if( !in[2] ){ nearest = 1; } else { opt = "infinity"; if( !SXGet0is( "nearest", in[2], INT_MAX, 1, 1, &opt, &nearest, &iopt ) ) goto error; if( iopt == 0 ) nearest = INT_MAX; } /* Get the maximum radius for input positions which contribute to each * output position. */ if( !in[3] ){ radius = FLT_MAX; } else { opt = "infinity"; if( !SXGet0rs( "radius", in[3], FLT_MAX, 0.0, 1, &opt, &radius, &iopt ) ) goto error; if( iopt == 0 ) radius = FLT_MAX; } /* If a maximum radius has been given, extend the bounds by one radius * at each end to catch some extra input positions. Otherwise, extend * the bounds by 10%. */ if( radius < FLT_MAX ){ for( j=0; j<ndim; j++ ){ lbnd[j] -= radius; ubnd[j] += radius; } } else { for( j=0; j<ndim; j++ ){ ext = 0.1*( ubnd[j] - lbnd[j] ); lbnd[j] -= ext; ubnd[j] += ext; } } /* Get the scale distances used to create weights for each input * position. Convert them to squared reciprocal scale distances. If * no value is supplied for the "scale" parameter, use a single scale * length of 1.0 */ if( !in[4] ){ rsc = 1.0; rscale = &rsc; nscale = 1; } else { rscale = SXGet1r( "scale", in[4], &nscale ); if( !rscale ) goto error; for( i=0; i<nscale; i++ ) { rsc = rscale[i]; if( rsc != 0.0 ){ rscale[i] = 1.0/(rsc*rsc); } else { rscale[i] = 0.0; } } } /* Get the exponent used to create weights for each input position. */ if( !in[5] ){ exponent = 1.0; } else { if( !SXGet0rs( "exponent", in[5], FLT_MAX, -FLT_MAX, 0, &opt, &exponent, &iopt ) ) goto error; } /* Get the co-efficient to used in the exponential when creating weights for * each input position. */ if( !in[6] ){ coexp = 0.0; } else { if( !SXGet0rs( "coexp", in[6], FLT_MAX, -FLT_MAX, 0, &opt, &coexp, &iopt ) ) goto error; } /* Get the type of output value required. */ if( !in[7] ){ outtype = 0; } else { if( !SXGet0is( "type", in[7], 2, 0, 0, &opt, &outtype, &iopt ) ) goto error; } /* Produce a copy of the "input" object to use as the output, replacing all * fields within it with the grid field. Also form a linked list of Fpair * structures describing the fields. */ output = SXMakeOut( input, (Field) grid, 1, 1, 3, "positions" ); if( !output ) goto error; /* Abort if no fields were found. */ if( !head ) { DXSetError( ERROR_DATA_INVALID, "no fields found in \"input\"." ); goto error; } /* Go through the list of fields looking for fields which share the same * positions component. */ more = 1; while( more ){ /* Find the first field with a non-zero positions tag. */ next = head; while( next && !next->postag ) next = next->next; /* If no non-zero positions tags were found, we've finished. */ if( !next ){ more = 0; break; } /* Find the input positions array. Get its shape, size and type. Check it is * usable. */ inpos_array = (Array) next->pos; if( !DXGetArrayInfo( inpos_array, &npos, &type, &cat, &rank, &npindim ) ) goto error; if( type != TYPE_FLOAT ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of type FLOAT." ); goto error; } if( cat != CATEGORY_REAL ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of category REAL." ); goto error; } if( rank > 1 ){ DXSetError( ERROR_DATA_INVALID, "rank %d positions component found in \"input\".", rank ); goto error; } if( rank == 0 ){ /* Scalar data is equivalent to 1-d vector data */ rank = 1; npindim = 1; } if( npindim != ndim ){ DXSetError( ERROR_DATA_INVALID, "dimensionality of \"input\" (%d) does not match \"grid\" (%d).", npindim, ndim ); goto error; } /* Get a pointer to the positions values. */ inpos = (float *) DXGetArrayData( inpos_array ); /* Find all fields which have the same positions tag and the same data * type. */ tag = next->postag; dtype = next->datatype; nfld = 0; while( next ){ if( next->postag == tag && next->datatype == dtype ){ /* Increment the number of fields found so far which share this * positions component. */ nfld++; if( nfld > MAXFLD ){ DXSetError( ERROR_MAX, "\"input\" has too many fields.", MAXFLD ); goto error; } /* Store a pointer to the input data array, and its dimensionality. */ indata[nfld-1] = (void *) DXGetArrayData( (Array) next->data ); veclen[nfld-1] = next->datalen; /* Make a new array to hold the output data values. The output data will * have the same dimensionality as the input data unless the required output * data is "sum of weights" (i.e. if parameter "type" is 2), in which case the * output data will be scalar. */ if( outtype == 2 ) veclen[nfld-1] = 1; outdata_array = DXNewArrayV( dtype, CATEGORY_REAL, 1, &veclen[nfld-1] ); if( !outdata_array ) goto error; if( !DXAddArrayData( outdata_array, 0, nsamp, NULL ) ) goto error; /* Get a pointer to the output data array. */ outdata[nfld-1] = (void *) DXGetArrayData( outdata_array ); if( !outdata[nfld-1] ) goto error; /* Place the new data component in the output field, and indicate that * it now does not need to be deleted explicitly in the event of an error. */ if( !DXSetComponentValue( next->outfld, "data", (Object) outdata_array ) ) goto error; outdata_array = NULL; /* Indicate that the data component of the output field has been * changed. */ DXChangedComponentValues( next->outfld, "data" ); /* Indicate that the data values are dependant on positions. */ if( !DXSetComponentAttribute( next->outfld, "data", "dep", (Object) DXNewString("positions")) ) goto error; } next = next->next; } /* Now sample the input data arrays at the output positions, storing the * resulting sample values in the output data arrays. */ if( dtype == TYPE_FLOAT ){ if( ! SXSampleF( nfld, ndim, veclen, npos, inpos, (float **)indata, nsamp, gridpos, (float **) outdata, lbnd, ubnd, nearest, radius, rscale, nscale, exponent, coexp, outtype, outbad ) ) goto error; } else { if( ! SXSampleD( nfld, ndim, veclen, npos, inpos, (double **)indata, nsamp, gridpos, (double **) outdata, lbnd, ubnd, nearest, radius, rscale, nscale, exponent, coexp, outtype, outbad ) ) goto error; } /* Loop round all the fields that have just been created. */ next = head; fld = 0; while( next ){ if( next->postag == tag ){ /* Create invalid positions components in each output field which have any * undefined data values */ if( outbad[fld] ){ if( dtype == TYPE_FLOAT ){ if( !SXSetInvPosF( (Object) next->outfld, nsamp, veclen[fld], (float *) outdata[fld], "positions" ) ) goto error; } else { if( !SXSetInvPosD( (Object) next->outfld, nsamp, veclen[fld], (double *) outdata[fld], "positions" ) ) goto error; } } /* Complete the construction of this output field. */ DXEndField( next->outfld ); /* Increment the field index, and indicate that this input field has * been done. */ fld++; next->postag = 0; } next = next->next; } } error: /* Free the storage used to hold the link list of Fpair structures * describing the fields in the "input" object. */ while( head ){ next = head->next; DXFree( (Pointer) head ); head = next; } /* Delete the copy of the input objects. Return the "output" object with a good status. */ DXDelete( grid ); DXDelete( input ); /* If all is OK, return the "output" object with a good status. */ if( DXGetError() == ERROR_NONE ){ out[0] = output; return( OK ); /* If an error has occurred, ensure temporary objects are deleted and return * with a bad status. */ } else { DXDelete( (Object) outdata_array ); DXDelete( output ); return( ERROR ); } }
int m_Unmark(Object *in, Object *out) { char *target; Object attr; if (!_dxfParmCheck(1, in[0], "input", NULL, NULL, 1, in[1], "component name", 1, NULL, NULL, 0, 0)) { out[0] = NULL; return ERROR; } if (_dxfDXEmptyObject(in[0])) { DXWarning("#4000", "input"); out[0] = in[0]; return OK; } if (in[1]) attr = in[1]; else attr = DXGetAttribute(in[0], "marked component"); if (!attr || !DXExtractString(attr, &target)) { DXSetError(ERROR_BAD_PARAMETER, "component name"); return ERROR; } /* the only way it makes sense to unmark a field which doesn't have * a data component is if the component you are unmarking is 'data'. * (that is interpreted as a request to move the 'saved data' component * back into 'data'.) */ if (!DXExists(in[0], "data") && strcmp(target, "data")) { DXSetError(ERROR_MISSING_DATA, "#10252", "input", "data"); return ERROR; } out[0] = DXCopy(in[0], COPY_STRUCTURE); if (!out[0]) return ERROR; /* special case unmarking the 'data' component - ignore the existing * 'data' component and overwrite it with the 'saved data' component. * if no saved data, just leave the data component alone. */ if (!strcmp(target, "data")) { if (!DXExists(out[0], "saved data")) { DXWarning("#10250", "input", "`saved data'"); return OK; } if (!DXRename(out[0], "saved data", "data")) { DXAddMessage("while trying to create output field"); goto error; } return OK; } /* normal case. put data back to its original name, and then check for * saved data and put it back to data. */ if (!DXRename(out[0], "data", target)) { DXAddMessage("while trying to create output field"); goto error; } /* if 'saved data' exists, move it back into 'data' */ if (DXExists(out[0], "saved data") && !DXRename(out[0], "saved data", "data")) { DXAddMessage("while trying to create output field"); goto error; } if (DXGetAttribute(out[0], "marked component")) DXSetAttribute(out[0], "marked component", NULL); return OK; error: DXDelete(out[0]); out[0] = NULL; return ERROR; }
Error m_SXBin( Object *in, Object *out ){ /* *+ * Name: * SXBin * Purpose: * bins a field into a grid defined by a another field * Language: * ANSI C * Syntax: * output = SXBin( input, grid, type ); * Classification: * Realization * Description: * The SXBin module bins the "data" component of the "input" field into * the bins defined by the "connections" component of the "grid" field. * The input field can hold scattered or regularly gridded points, but * the "data" component must depend on "positions". The "grid" field must * contain "connections" and "positions" components but need not contain * a "data" component. The input"data" component must be either TYPE_FLOAT * or TYPE_DOUBLE. * * The "data" component in the "output" field contains either the mean * or sum of the "input" data values falling within each connection, or * the number of data values falling within each connection, as specified * by "type". * * When binning a regular grid into another regular grid, beware of the * tendancy to produce artificial large scale structure representing the * "beat frequency" of the two grids. * Parameters: * input = field (Given) * field or group with positions to bin [none] * grid = field (Given) * grid to define the bins [none] * type = integer (Given) * type of output values required: 0 - mean, 1 - sum, * 2 - count [0] * output = field (Returned) * bined field * Components: * All components except the "data" component are copied from the "grid" * field. The output "data" component added by this module depends on * "connections". An "invalid connections" component is added if any output * data values could not be calculated (e.g. if the mean is required of an * empty bin). * Examples: * This example bins the scattered data described in "CO2.general" onto a * regular grid, and displays it. SXBin is used to find the mean data * value in each grid connection. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * bin = SXBin(frame17,grid); * coloured = AutoColor(bin); * Display(coloured,camera); * * This example produces a grid containing an estimate of the density of * the scattered points (i.e. the number of points per unit area). The * positions of the original scattered points are shown as dim grey * circles. SXBin finds the number of input positions in each bin, * Measure finds the area of each bin, and Compute divides the counts * by the areas to get the densities: * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * glyphs = AutoGlyph(frame17,scale=0.1,ratio=1); * glyphs = Color(glyphs,"dim grey"); * grid = Construct([-100,-170],deltas=[40,40],counts=[6,10]); * counts = SXBin(frame17,grid,type=2); * areas = Measure(counts,"element"); * density = Compute("$0/$1",counts,areas); * coloured = AutoColor(density); * collected=Collect(coloured,glyphs); * Display(collected,camera); * See Also: * SXRegrid, Map, Construct, Measure * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * 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 of * the License, 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., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 9-OCT-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ Array a; /* Array to hold reduced dimension positions */ float *a_ptr; /* Pointer to reduced dimension positions */ Category cat; /* Array category type */ Type dtype; /* Type of current input data array */ int fld; /* Field counter */ Object grid; /* The grid object */ int i; /* Loop count */ void *indata[MAXFLD];/* Pointer to input data array */ float *inpos; /* Pointer to input positions array */ Array inpos_array; /* Input positions array */ Object input; /* A copy of the input object */ Interpolator interp; /* Interpolator for grid */ int j; /* Loop count */ Array map; /* Map from input position to output bin number */ int *map_ptr; /* Pointer to map */ char more; /* Are there more input fields to do? */ Fpair *next; /* The next Fpair structure in the linked list */ int ndim; /* No. of dimensions in grid positions array */ int nfld; /* No. of fields sharing current positions array */ int npos; /* No. of input positions */ int npindim; /* No. of dimensions in input positions array */ int nbin; /* No. of grid positions */ int outbad[MAXFLD];/* No. of invalid output positions in each field*/ void *outdata[MAXFLD];/* Pointers to output data arrays */ Array outdata_array;/* Output data array */ Object output; /* The output object */ int outtype; /* Type of output values required */ float *pa; /* Pointer to next reduced dimension position */ float *pin; /* Pointer to next full dimension position */ int rank; /* Array rank */ int tag; /* The tag for the current input positions array */ Type type; /* Array numeric type */ int veclen[MAXFLD];/* Dimensionality of each input data array */ int *work; /* Pointer to work array */ /* Initialise all created objects so that they can safely be deleted if * an error occurs. */ input = NULL; output = NULL; grid = NULL; outdata_array = NULL; work = NULL; a = NULL; /* Check that the "input" object has been supplied. */ if( !in[0] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"input\"." ); goto error; } /* Remove (cull) all invalid positions and connections from the input. It is * necessary to take a copy of the input first, because the input object * itself cannot be modified. */ input = DXCopy( in[0], COPY_STRUCTURE ); if( !DXCull( input ) ) goto error; /* Check that the "grid" object has been supplied. */ if( !in[1] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"grid\"." ); goto error; } /* Create an interpolator which identifies the grid connection containing any * given position. */ interp = SXGetIntp( in[1], &nbin, &ndim, &grid ); if( !interp ) goto error; /* Allocate a work array for use by SXBinD or SXBinF. */ work = (int *) DXAllocate( sizeof( int )*nbin ); if( !work ) goto error; /* Get the type of output value required. */ if( !in[2] ){ outtype = 0; } else { if( !SXGet0is( "type", in[2], 2, 0, 0, NULL, &outtype, NULL ) ) goto error; } /* Produce a copy of the "input" object to use as the output, replacing all * fields within it with the grid field. Also form a linked list of Fpair * structures describing the fields. */ output = SXMakeOut( input, (Field) grid, 1, 1, 3, "positions" ); if( !output ) goto error; /* Abort if no fields were found. */ if( !head ) { DXSetError( ERROR_DATA_INVALID, "no fields found in \"input\"." ); goto error; } /* Go through the list of fields looking for fields which share the same * positions component. */ more = 1; while( more ){ /* Find the first field with a non-zero positions tag. */ next = head; while( next && !next->postag ) next = next->next; /* If no non-zero positions tags were found, we've finished. */ if( !next ){ more = 0; break; } /* Find the input positions array. Get its shape, size and type. Check it is * usable. */ inpos_array = (Array) next->pos; if( !DXGetArrayInfo( inpos_array, &npos, &type, &cat, &rank, &npindim ) ) goto error; if( type != TYPE_FLOAT ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of type FLOAT." ); goto error; } if( cat != CATEGORY_REAL ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of category REAL." ); goto error; } if( rank > 1 ){ DXSetError( ERROR_DATA_INVALID, "rank %d positions component found in \"input\".", rank ); goto error; } if( rank == 0 ){ /* Scalar data is equivalent to 1-d vector data */ rank = 1; npindim = 1; } if( npindim < ndim ){ DXSetError( ERROR_DATA_INVALID, "dimensionality of \"input\" (%d) is less than \"grid\" (%d).", npindim, ndim ); goto error; } /* Get a pointer to the positions values. */ inpos = (float *) DXGetArrayData( inpos_array ); /* If the number of dimensions in the input positions is greater than the * number of dimensions in the grid, remove trailing dimensions from the * input positions so that they match the dimensionality of the grid. */ if( npindim > ndim ){ a = DXNewArrayV( TYPE_FLOAT, CATEGORY_REAL, 1, &ndim ); if( !DXAddArrayData( a, 0, npos, NULL ) ) goto error; a_ptr = (float *) DXGetArrayData( a ); for( i=0; i<npos; i++ ){ pin = inpos + i*npindim; pa = a_ptr + i*ndim; for(j=0;j<ndim;j++) pa[j] = pin[j]; } inpos_array = a; } else { a = NULL; } /* Create an array of the same shape and size as the input positions * array, which holds integer identifiers for the grid connections * containing each input position. These identifiers start at 1 and * go upto nbin. Positions returned holding an identifier of zero do * not fall within the supplied grid. */ map = (Array) DXMap( (Object) inpos_array, (Object) interp, NULL, NULL ); map_ptr = (int *) DXGetArrayData( map ); /* Find all fields which have the same positions tag and the same data * type. */ tag = next->postag; dtype = next->datatype; nfld = 0; while( next ){ if( next->postag == tag && next->datatype == dtype ){ /* Increment the number of fields found so far which share this * positions component. */ nfld++; if( nfld > MAXFLD ){ DXSetError( ERROR_MAX, "\"input\" has too many fields.", MAXFLD ); goto error; } /* Store a pointer to the input data array, and its dimensionality. */ indata[nfld-1] = (void *) DXGetArrayData( (Array) next->data ); veclen[nfld-1] = next->datalen; /* Make a new array to hold the output data values. The output data will * have the same dimensionality as the input data unless the required output * data is "counts (i.e if parameter "type" is 2), in which case the * output data will be scalar. */ if( outtype == 2 ) veclen[nfld-1] = 1; outdata_array = DXNewArrayV( dtype, CATEGORY_REAL, 1, &veclen[nfld-1] ); if( !outdata_array ) goto error; if( !DXAddArrayData( outdata_array, 0, nbin, NULL ) ) goto error; /* Get a pointer to the output data array. */ outdata[nfld-1] = (void *) DXGetArrayData( outdata_array ); if( !outdata[nfld-1] ) goto error; /* Place the new data component in the output field, and indicate that * it now does not need to be deleted explicitly in the event of an error. */ if( !DXSetComponentValue( next->outfld, "data", (Object) outdata_array ) ) goto error; outdata_array = NULL; } next = next->next; } /* Now bin the input data arrays into the output connections, storing the * resulting bin values in the output data arrays. */ if( dtype == TYPE_FLOAT ){ if( ! SXBinF( nfld, veclen, npos, (float **)indata, nbin, (float **) outdata, map_ptr, work, outtype, outbad ) ) goto error; } else { if( ! SXBinD( nfld, veclen, npos, (double **)indata, nbin, (double **) outdata, map_ptr, work, outtype, outbad ) ) goto error; } /* Loop round all the fields that have just been created. */ next = head; fld = 0; while( next ){ if( next->postag == tag ){ /* Create invalid positions components in each output field which have any * undefined data values */ if( outbad[fld] ){ if( dtype == TYPE_FLOAT ){ if( !SXSetInvPosF( (Object) next->outfld, nbin, veclen[fld], (float *) outdata[fld], "connections" ) ) goto error; } else { if( !SXSetInvPosD( (Object) next->outfld, nbin, veclen[fld], (double *) outdata[fld], "connections" ) ) goto error; } } /* Indicate that the data values are dependant on connections. */ if( !DXSetComponentAttribute( next->outfld, "data", "dep", (Object) DXNewString("connections")) ) goto error; /* Indicate that the data component of the output field has been * changed. */ DXChangedComponentValues( next->outfld, "data" ); /* Complete the construction of this output field. */ DXEndField( next->outfld ); /* Increment the field index, and indicate that this input field has * been done. */ fld++; next->postag = 0; } next = next->next; } /* Delete the array used to store the reduced dimensionality input positions * (if used). */ if( a ) { DXDelete( (Object) a ); a = NULL; } } error: /* Free the storage used to hold the link list of Fpair structures * describing the fields in the "input" object. */ while( head ){ next = head->next; DXFree( (Pointer) head ); head = next; } /* Free the work array. */ if( work ) DXFree( (Pointer) work ); /* Delete the copy of the input and grid objects, and the array used to * store the reduced dimensionality input positions (if used). */ DXDelete( grid ); DXDelete( input ); if( a ) DXDelete( (Object) a ); /* If all is OK, return the "output" object with a good status. */ if( DXGetError() == ERROR_NONE ){ out[0] = output; return( OK ); /* If an error has occurred, ensure temporary objects are deleted and return * with a bad status. */ } else { DXDelete( (Object) outdata_array ); DXDelete( output ); return( ERROR ); } }