/* fut_new_gtbl creates a new grid table and optionally intializes it. * The input channels defined for the grid are specified in the input * channel mask portion of iomask. Each input defined must have a size * specified in a KpInt32_t array. * Gfun must be a pointer to a function accepting from zero to three * doubles (depending on values of sx, sy, and sz) in the range (0.0,1.0) * and returning a fut_gtbldat_t in the range (0,FUT_GRD_MAXVAL). * A pointer to the newly allocated table is returned if there were no * errors. (If gfun is NULL, the table is not initialized). */ fut_gtbl_p fut_new_gtblEx ( PTTableType_t tableType, KpInt32_t iomask, fut_gfunc_t gfun, fut_calcData_p data, KpInt32_p dimList) { fut_gtbl_p gtbl; KpInt32_t imask, i, dim_size, grid_size; /* get input mask */ imask = (KpInt32_t)FUT_IMASK(iomask); /* allocate grid table structure */ gtbl = fut_alloc_gtbl (); if ( gtbl == FUT_NULL_GTBL ) { DIAG("fut_new_gtblA: can't alloc grid table struct.\n", 0); return (FUT_NULL_GTBL); } /* get sizes from dimList */ grid_size = 1; for ( i=0; i<FUT_NCHAN; i++ ) { dim_size = (imask & FUT_BIT(i)) ? dimList[i] : 1; if ( dim_size <= 0 ) { dim_size = 1; /* make sure > 0 */ } gtbl->size[i] = (KpInt16_t)dim_size; grid_size *= (KpInt32_t)dim_size; } /* check for valid grid size */ if ( grid_size <= 0 || grid_size > FUT_GRD_MAX_ENT ) { DIAG("fut_new_gtblA: bad grid table size (%d).\n", grid_size); fut_free_gtbl(gtbl); return (FUT_NULL_GTBL); } gtbl->tbl_size = (KpInt32_t)grid_size * (KpInt32_t)sizeof(fut_gtbldat_t); /* allocate grid table */ if (tableType == KCP_PT_TABLES) { gtbl->refTbl = fut_alloc_gtbldat (gtbl); } else { gtbl->refTbl = fut_alloc_gmftdat (gtbl); } if ( gtbl->refTbl == NULL ) { DIAG("fut_new_gtblA: can't alloc grid table array.\n", 0); fut_free_gtbl(gtbl); return (FUT_NULL_GTBL); } /* compute the grid table entries */ if ( ! fut_calc_gtblEx (gtbl, gfun, data) ) { fut_free_gtbl(gtbl); return (FUT_NULL_GTBL); } return (gtbl); }
/* fut_free_gtbl_p This function is passed a fut_gtbl_t pointer and handle. If the ref count is zero, the table and the fut_gtbl_t is freed. Otherwise the ref count is decremented and the lock state of the fut_gtbl_t is returned to it's state on entry. */ static void fut_free_gtbl_p ( fut_gtbl_p gtblP, KpHandle_t gtblHdl) { fut_gtbl_p gtbl = gtblP; if (gtblHdl == NULL) { return; } if (gtbl == NULL) { /* gtbl is unlocked on entry */ gtbl = lockBuffer(gtblHdl); } if (IS_GTBL(gtbl)) { if (gtbl->ref == 0) { fut_free_gtbl(gtbl); /* last reference being freed */ } else { if (gtbl->ref > 0) { /* still other references, leave in original lock state */ gtbl->ref--; if (gtblP == NULL) { unlockBuffer(gtblHdl); } } } } }
/* fut_free_tbl frees any table regardless of type by checking the magic * number in the header. It will also free a fut_t or a fut_chan_t. * * fut_free_tbls will free a null terminated list of any type of table, * useful for disposing of a set of tables which were used for constructing * a fut (which the fut has now absorbed and made shared copies of). */ void fut_free_tbl (KpGenericPtr_t tbl) { /* Make sure that we do not have a NULL pointer */ if( tbl == NULL ) { return; } switch (*(KpInt32_p)tbl) { case FUT_MAGIC: fut_free ((fut_p) tbl); break; case FUT_CMAGIC: fut_free_chan ((fut_chan_p) tbl); break; case FUT_IMAGIC: fut_free_itbl ((fut_itbl_p) tbl); break; case FUT_OMAGIC: fut_free_otbl ((fut_otbl_p) tbl); break; case FUT_GMAGIC: fut_free_gtbl ((fut_gtbl_p) tbl); break; } }
/* fut_copy_gtbl makes an exact copy of an existing fut_gtbl_t */ fut_gtbl_p fut_copy_gtbl (fut_gtbl_p gtbl) { fut_gtbl_p new_gtbl; KpInt32_t gsize; KpHandle_t h; /* check for valid gtbl */ if ( ! IS_GTBL(gtbl) ) { return (FUT_NULL_GTBL); } new_gtbl = fut_alloc_gtbl (); /* allocate the new gtbl structure */ if ( new_gtbl == FUT_NULL_GTBL ) { DIAG("fut_copy_gtbl: can't alloc grid table struct.\n", 0); return (FUT_NULL_GTBL); } h = new_gtbl->handle; /* save handle before copying over old gtbl */ *new_gtbl = *gtbl; /* copy entire struct except reference count */ new_gtbl->handle = h; new_gtbl->ref = 0; /* first reference */ if (gtbl->tbl != NULL) { /* copy fixed gtbl data */ gsize = gtbl->tbl_size / (KpInt32_t)sizeof(fut_gtbldat_t); new_gtbl->tbl = fut_alloc_gtbldat (new_gtbl); if ( new_gtbl->tbl == NULL ) { DIAG("fut_copy_gtbl: can't alloc grid table array.\n", 0); goto ErrOut; } new_gtbl->tblHandle = getHandleFromPtr((KpGenericPtr_t)new_gtbl->tbl); /* copy the table entries */ KpMemCpy (new_gtbl->tbl, gtbl->tbl, gtbl->tbl_size); } if (gtbl->refTbl != NULL) { /* copy reference gtbl data */ new_gtbl->refTbl = fut_alloc_gmftdat (new_gtbl); if (new_gtbl->refTbl == NULL ) { DIAG("fut_copy_gtbl: can't alloc ref grid table array.\n", 0); goto ErrOut; } /* copy the table entries */ KpMemCpy (new_gtbl->refTbl, gtbl->refTbl, gtbl->tbl_size); } return (new_gtbl); ErrOut: fut_free_gtbl (new_gtbl); return (FUT_NULL_GTBL); }
void fut_free_chan (fut_chan_p chan) { if ( ! IS_CHAN(chan) ) /* check if defined */ return; fut_free_itbl_list (chan->itbl); /* free input tables */ fut_free_otbl (chan->otbl); /* free output table */ fut_free_gtbl (chan->gtbl); /* free grid table */ /* free fut_chan_t structure itself */ chan->magic = 0; freeBufferPtr ((KpGenericPtr_t)chan); }
fut_p fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask) { KpInt32_t ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans; fut_p fut2 = NULL, evalFut = NULL; fut_itbl_p oitbls[FUT_NICHAN]; mf2_tbldat_p indat[FUT_NICHAN], outdat[FUT_NOCHAN]; fut_gtbl_p fut1_gtbls[FUT_NOCHAN]; if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) { return (NULL); } /* extract component masks from iomask */ omask = FUT_OMASK(iomask); /* which output chans? */ pmask = FUT_PMASK(iomask); /* which ones allowed to pass through? */ order = FUT_ORDMASK(iomask); /* which interpolation to use? */ if ( order == FUT_DEFAULT ) { order = fut1->iomask.order; } /* adjust masks for iomask_check below */ pmask &= fut0->iomask.out; /* available for "pass through" */ if ( omask == 0 ) { /* required outputs (0 means all) */ omask = fut1->iomask.out; } /* see if fut0 can provide required inputs to fut1 */ imask = fut0->iomask.out; /* available inputs for fut1 */ iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask); if ( ! fut_iomask_check (fut1, iomask) ) { return (NULL); } /* make sure the futs are in the reference state */ if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) { return (NULL); } /* fut1 will be used to process the grid tables of fut0, placing the * results in the grid tables of fut2. Fut0's grid table data must first * be passed through its output tables before sending it through fut1's * input tables. This is accomplished more efficiently by composing * fut1's input tables with fut0's output tables and using these directly * on fut0 grid data rather than the normal input tables. * * Create the result fut (fut2) which will be the composition of fut1 * and fut0. Fut2 will inherit the input tables of fut0 and the output * tables of fut1. Its grid data will be in the same color coordinates * as fut1's. */ fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL); if ( fut2 == NULL ) { return (NULL); } /* for each desired channel i in fut2, create a new grid table. The * dimensions of each new grid table are derived from fut0 and fut1 * like so: for every input required for channel i of fut1, form the * union of the input sets of all corresponding fut0 outputs. */ /* null all io tables and table pointers */ KpMemSet (oitbls, 0, sizeof(oitbls)); imask = 0; /* will be the input mask for all inputs needed to fut1 */ evalomask = 0; /* omask for evaluation */ for (i = 0; (i < FUT_NOCHAN) && ok; i++) { KpInt32_t size[FUT_NICHAN]; fut_gtbl_p gtbl; KpInt32_t imask1, imask2; fut1_gtbls[i] = NULL; /* assume not needed */ if ((omask & FUT_BIT(i)) == 0) { /* is this output channel needed? */ continue; /* no */ } /* if a specified output is to be passed through from fut0, do that here */ if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) { ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, fut0->chan[i]->gtbl, fut0->chan[i]->otbl); continue; /* no need to evaluate this ochan */ } if (! IS_CHAN(fut1->chan[i])) { ok = 0; /* something wrong */ goto GetOut; } /* At this point we know that (fut1->chan[i] != 0). We also * have determined (from iomask_check above) that fut0->chan[j] != 0. */ imask2 = 0; /* determine inputs from fut0 needed for this channel */ imask1 = fut1->chan[i]->imask; /* inputs used by this chan */ for (j = 0; (j < FUT_NICHAN) && ok; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this input chan is needed */ if ( ! IS_CHAN(fut0->chan[j])) { /* available? */ ok = 0; /* composition fails */ goto GetOut; } if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) { /* shared itbl? */ goto nextOChan; /* nope, ignore this ochan */ } imask2 |= fut0->chan[j]->imask; } } evalomask |= FUT_BIT(i); /* will be evalutating this channel */ imask |= imask1; /* build mask of all needed inputs */ /* determine required dimensions from mask */ for (j = 0; j < FUT_NICHAN; j++) { size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1; } /* create the new grid table * insert it along with fut1's output table into fut2 */ gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size); ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl); fut_free_gtbl (gtbl); if (!ok) { goto GetOut; } fut1_gtbls[i] = fut1->chan[i]->gtbl; /* collect gtbls for evaluation fut */ /* verify the input data for the evaluation of the output channel in fut1 */ for (j = 0; j < FUT_NICHAN; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this channel needed as input */ if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) { /* it's inputs must be used by output */ ok = 0; /* composition fails */ goto GetOut; } } } nextOChan:; } /* collect the gtbls which are the input data for the chan evaluation. * also pre-compose fut0's otbls with fut1's itbls. */ for (i = 0; i < FUT_NICHAN; i++) { oitbls[i] = NULL; if (ok) { fut_chan_p theChan = fut0->chan[i]; if ((imask & FUT_BIT(i)) == 0) { continue; /* this output from fut0 not required */ } indat[i] = theChan->gtbl->refTbl; /* collect gtbls: the input data for the evaluation */ ok = (indat[i] != NULL); /* allocate memory for composed i/o tables * these have the same size as the output tables of the channel supplying the input */ if (ok) { fut_itbl_p theITbl = fut1->itbl[i]; fut_otbl_p theOTbl = theChan->otbl; oitbls[i] = fut_alloc_itbl (); /* get an itbl */ oitbls[i]->size = theITbl->size; oitbls[i]->dataClass = KCP_FIXED_RANGE; nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries); ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL); if (ok) { /* make input table for evaluation */ ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]); } } } } /* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */ evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL); if (( ! ok) || (evalFut == NULL) || /* if evaluation fut ok */ (fut_to_mft (fut2) != 1)) { /* make sure the futs are in the reference state */ ok = 0; goto GetOut; } else { /* Finally, we are ready to pass fut0's grid tables through fut1 */ for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) { if ((evalomask & FUT_BIT(i)) != 0) { fut_gtbl_p gtbl; gtbl = fut2->chan[i]->gtbl; nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t); /* grid points for eval */ if (evalFut->iomask.in != evalFut->chan[i]->imask) { /* must evaluate this channel singly */ evalomask &= ~FUT_BIT(i); /* remove channel from multiple eval list */ ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl)); } else { outdat[nOutChans] = gtbl->refTbl; nOutChans++; } } } /* eval result is composed fut's gtbls */ ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat); } GetOut: /* must always free up the evaluation fut and io tables, even if an error occurred! */ fut_free (evalFut); fut_free_tbls (FUT_NICHAN, (void *)oitbls); /* check for errors */ if ( !ok ) { fut_free (fut2); fut2 = NULL; } return (fut2); }