From: Gordon K. <gk...@cs...> - 2004-05-16 22:37:25
|
hi, In case you didn't know, teem version 1.7.0 has been released after some delay. The unofficial motto of teem is "Software that sucks less since 1998", and I'm pretty certain that this version definitely sucks much less than the previous one. I've attached the change notice for this version below, most people will only care about things in "nrrd:", "gage:", or "ten:". Please try the new version and tell me how it works for you! I haven't actually finished packaging up NrrdIO and releasing that, but I will do that soon. Gordon 1.7.0 changes: --------------------------------------------------------------------- All public teem header files: For the sake of static (or was it dll?) Windows builds, there used to be a #define macro for each library: <lib>_import (or was it <lib>_export?) which would enable linking to happen properly given Teem's use global variables, and the sort of "def file" that was created with cygwin's help. I think. In any case, having seen that this was causing some confusion in ITK's use of NrrdIO, the change was made to create a TEEM_API macro that expands as necessary, depending on how Teem is being built. TEEM_API MUST BE USED ON ALL "PUBLIC" SYMBOLS: BOTH GLOBALS AND FUNCTIONS. /* define TEEM_API */ #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(TEEM_STATIC) # if defined(TEEM_BUILD) # define TEEM_API extern __declspec(dllexport) # else # define TEEM_API extern __declspec(dllimport) # endif #else /* TEEM_STATIC || UNIX */ # define TEEM_API extern #endif --------------------------------------------------------------------- NrrdIO: This is an effort to create a simple way for other programs to do basic create/destroy input/output operations on nrrds and NRRD file, started to enable ITK to handle NRRD files. This is a seperate teem CVS module, but it is built automatically from the source files in teem, from the air, biff, and nrrd libraries. The API presented in NrrdIO is a struct subset of the API in teem. To facilitate lopping out the portions of source files that are not needed for NrrdIO, there are some new comments that delimit regions of files (both .c and .h) not needed: /* ---- BEGIN non-NrrdIO */ /* ---- END non-NrrdIO */ --------------------------------------------------------------------- air: adapted/simplified the drand48() implementation from glibc-2.3, in new functions airDrand48(), airSrand48() and re-entrant version airDrand48_r(). This became an issue as soon as echo (the ray-tracer) become genuinely multi-threaded. As part of this, I removed airRand() and airSrand(), which were so stupid. Note that airDrand48() is mathematically identical to glibc-2.3's drand48(), although the default initial seeding scheme is different. API GONE: the AIR_MEMCPY macros have been redacted, since they aren't being used, and they were always a stupid idea. --------------------------------------------------------------------- biff: FILE RENAME: biff/biff.c --> biff/biffbiff.c --------------------------------------------------------------------- ell: Matrices are now represented as row-major: 0 1 2 3 4 5 6 7 8 instead of column-major: 0 3 6 1 4 7 2 5 8 I thought I had written some further documentation about this change elsewhere, but apparently not. Alas. --------------------------------------------------------------------- limn: added two new fields to the limnCamera, "fov" and "aspect", augmented the semantics of limnCameraUpdate, added limnCameraAspectSet, and made an effort to fix/debug the limnCameraPathMake() function. "fov" is like the "fovy" argument to gluPerspective()- the angle in degrees vertically subtended by the view window, and "aspect" is the ratio of horizontal to vertical size of the view window. Now, when limCameraUpdate() is called, it will see if both fov and aspect are set (non-NaN), and if so will update uRange[] and vRange[] accordingly. Otherwise, uRange[] and vRange[] will not be touched. limnCameraAspectSet() simply sets cam->aspect according to the given number of pixels and the centering of the pixels limnCameraPathMake() is not a new function, but it never worked usefully. Now it can be used to make cool quaternion-spline-based camera paths, with arbitrary key-frame spacing in time. API RENAME: limnQN_xxx ---> limnQNxxx added simple (and incomplete!) support for reading and writing OFF files working on: drawing non-convex objects --------------------------------------------------------------------- nrrd: Two major changes, which were done simultaneously: 1) Some renamings related to NrrdAxis, nrrdAxisInfo, and so on 2) Addition of the nrrdKind information to the NrrdAxisInfo struct In detail: 1) Some renamings related to NrrdAxis, nrrdAxisInfo, and so on: struct: NrrdAxis --> NrrdAxisInfo (NB: Nrrd struct still has field "axis") functions: nrrdAxisPos() --> nrrdAxisInfoPos() nrrdAxisIdx() --> nrrdAxisInfoIdx() nrrdAxisPosRange() --> nrrdAxisInfoPosRange() nrrdAxisIdxRange() --> nrrdAxisInfoIdxRange() nrrdAxisSpacingSet() --> nrrdAxisInfoSpacingSet() nrrdAxisMinMaxSet() --> nrrdAxisInfoMinMaxSet() Now, ANYTHING having to do with setting, getting, or manipulating the meta-information about the axes starts with "nrrdAxisInfo". The single exception to this is that the Nrrd struct's "axis" field was not renamed to "axisInfo", since this seemed more annoying that it was worth. Also, (this isn't new) ANYTHING having to do the set of axes, the shape of the array, or the per-axis ordering of samples, starts with "nrrdAxes". The nrrdAxes functions are NOT merely for manipulating the per-axis meta information-- something about the array as a whole, or the set of axes as a whole, is changing. Yes, this means that there's a function called "nrrdAxesInsert", even though it only inserts a single axis, but I figured the consistency generated by strict adherence to the nrrdAxes and nrrdAxisInfo prefixes would be better in the long run. 2) Addition of the nrrdKind information to the NrrdAxisInfo struct This is nrrd's latest and probably most dangerous step towards putting real semantic information in the array representation (that is, the "nearly raw" philosophy is getting stretched). The best way to think about this is that its a *hint*: an extra bit of information, kind of like the label or the unit, that you may want to associated with the axis, and which has a sufficiently general nature to warrent direct representation. So, new to the (newly renamed) NrrdAxisInfo struct: int kind; /* what kind of information is along this axis (from the nrrdKind* enum) */ Accordingly, there is change to the file format, which of course means that the magic is once again incremented. If you write a nrrd with known kinds on any axis, the magic will be "NRRD0003". The new kinds field looks like (for-example) kinds: 3-color domain domain for an RGB image. Like other per-axis fields, its specification is plural (its "kinds:", not "kind:"), and like centering, you use "???" to mean, "I don't know", for example: kinds: ??? domain domain To make this hint more useful, there's a new function nrrdKindSize() which returns what nrrd thinks is the suggested axis size for the different nrrdKind's. This function will return 0 to indicate "I have no advice for you on how big this axis should be". The reason for using 0 instead of -1 is that someday nrrd may change the axis size type from int to unsigned int. To offer some control of the nrrdKind behavior, there is a new global "state" variable: nrrdStateKindNoop. Currently, this is AIR_TRUE by default. You can set it to AIR_FALSE to enable some minimal cleverness on the part of nrrd. The nature of that minimal cleverness is almost certainly likely to change with time. Due to the nature of nrrdAxisInfoCopy, anything which doesn't explicitly ask the axis information NOT to be copied, will have it be copied. For example, nrrdSlice will propogate through the kinds on the axes that it didn't touch, same with nrrdAxesPermute, and the like. Regardless of NrrdKindStateNoop, the output of these functions will set nrrdKindUnknown on all the axes that experienced a non-trivial change: nrrdAxesSplit, nrrdAxesMerge, nrrdReshape, nrrdReshape_nva, nrrdUnblock, nrrdJoin, nrrdApply1DLut, nrrdApply1DRegMap, and nrrdApply1DIrregMap. These functions respect nrrdKindStateNoop: nrrdCrop, nrrdPad, nrrdShuffle, nrrdFlip, nrrdSpatialResample: if (nrrdKindStateNoop) { If the axis operated on was not a nrrdKindDomain or nrrdKindList, the resulting kind is nrrdKindUnknown Else, the resulting kind is the same as the input kind. This is implemented through _nrrdKindAltered() } else { output kind is a copy of the input kind } nrrdHisto, nrrdHistoAxis, nrrdHistoJoint: if (nrrdKindStateNoop) { histogram axes are nrrdKindDomain } else { histogram axes are nrrdKindUnknown } nrrdAxisInsert: if (nrrdKindStateNoop) { new axis is nrrdKindStub } else { new axis is nrrdKindUnknown } For the record, this is what this change entailed: added: - global int nrrdStateKindNoop - nrrdKindSize() - airEnum *nrrdKind (maps between strings like "3color" and nrrdKind* values) - NRRD_KIND_MAX #define augmented: - NrrdAxisInfo struct (now has "kind" field) - _nrrdFieldInteresting(), _nrrdSprintFieldInfo(), _nrrdFormatNRRD_write() with things relating to new field ("kinds:") and magic ("NRRD0003") - _nrrdFieldValidInImage[], _nrrdFieldOnePerAxis[], _nrrdFieldValidInText[], _nrrdFieldRequired[] - _nrrdReadNrrdParseInfo[] parser callback, with new _nrrdReadNrrdParse_kinds() - airEnum *nrrdField - nrrdAxisInfo C enum (for passing to nrrdAxisInfo{Set,Get}) - nrrdField* C enum - nrrdStateGetenv(): looks for NRRD_STATE_KIND_NOOP" environment variable One annoying bit: I didn't add a new flag to "unu make" to learn the axis kinds because I *can't*. This is a basic limitation in hest which is gotten pretty annoying: there is no direct way to see if an option was given on the command line or not. Every option has to have a value supplied, either via the command-line or via the default value string, but once its all been parsed, you don't know where it came from, and nor can you tell hest "this option is really really optional, there is no default, and its okay if the user never gives you a value." This will only be fixed with a hest re-write. Actually, I have to rethink this. It may be possible to add the "-k" option to "unu make", it will just be a wild hack. IMPROVED FUNCTIONALITY: Prior to teem-1.7, a nrrd that was already already valid and allocated with some amount of memory would be stripped of that memory (the memory was freed) by nrrdRead(). The various encodings would allocate new memory via _nrrdCalloc. This meant that even when the caller to nrrdRead knew in advance that the given nrrd could hold the data that would be read from the given file, the memory was freed and re-allocated. This presented a problem for ITK's use of nrrd in NrrdIO. Now, near the beginning of nrrdRead(), any existing memory (via nrrd->data being non-NULL) and its allocated size (via nrrd->type and nrrd->axis[i].size) are remembered in the NrrdIoState struct (void *oldData, size_t oldDataSize), which is then referred to via _nrrdCalloc, or directly by the format's reader. The result is that existing memory is used whenever the allocated size matches the size described by the new nrrd's header. This change has been made in all existing formats, which involved more modifications for formatText.c and formatPNG.c, since these do not use (nor should they) functions in the existing encodingXXX.c files. Near the end of nrrdRead(), the old data is freed if it turns out that it wasn't re-used. API CHANGE: nrrdCheapMedian now takes a new argument, "pad", which tells it to pad the input by the radius of the filter, prior to filtering, and then crops the output. Without this, the samples along the boundary are left unprocessed. Note: this functionality has migrated from "unu cmedian" down into nrrd. "unu cmedian", on the other hand, has a new command-line flag, "-c", which tells it to slice along axis 0, run filtering on all slices, and then join the results together. I was too chicken to add this the nrrd API directly, but it may eventually migrate there. --------------------------------------------------------------------- gage: massive internal changes, but hopefully only the following are visible: API CHANGE: unsigned int queries are gone; now using gageQuery, a bit-vector based on an array of uchars. So, where you used to say: unsigned int query; ... gageQuerySet(ctx, pvl, 1 << gageSclValue | 1 << gageSclGradMag) you'll now say: gageQuery query; ... GAGE_QUERY_RESET(query); GAGE_QUERY_ITEM_ON(query, gageSclValue); GAGE_QUERY_ITEM_ON(query, gageSclGradMag); gageQuerySet(ctx, pvl, query); or, less annoyingly (perhaps): gageQueryReset(ctx, pvl); gageQueryItemOn(ctx, pvl, gageSclValue); gageQueryItemOn(ctx, pvl, gageSclGradMag); One unfortunate consequence of this change is that gage queries can no longer be conveniently set at compile-time. This was an issue for bane, which had to be changed to comply, inadvertently triggering a massive re-write, still unfinished. API CHANGE: many of the arrays in the gageKind have been replaced by a single array of things called gageItemEntry, which is must easier to maintain by hand. See gage.h for details. --------------------------------------------------------------------- bane: Sorry, bane is currently broken. The gage overhaul was a bit too much of a shock, and it never fully recovered. --------------------------------------------------------------------- ten: API RENAME: some function renamings, to make way for future move to doubles, or at least away from float-specificity: tenEigensolve --> tenEigensolve_f tenMakeOne --> tenMakeOne_f tenSimulateOne --> tenSimulateOne_f tenAnisoCalc --> tenAnisoCalc_f tenEvqOne --> tenEvqOne_f tenEstimateLinearSingle --> tenEstimateLinearSingle_f API NEW: tenEigensolve_d API CHANGE: Functions xxx which haven't been renamed to xxx_f, and which took float arguments (not a pointer to float), now take a double instead. This is not a change that anyone will notice. Affected functions are: tenEstimateLinear3D() tenEstimateLinear4D() tenExpand() tenSimulate() tenAnisoVolume() tenSizeScale() tenAnisoScale() tenEigenvaluePower() tenEigenvalueClamp() tenEigenvalueAdd() API CHANGE: More of a big deal: this guy took a float array ("weight"), and now its a double array: tenSizeNormalize(Nrrd *nout, Nrrd *nin, double weight[3], double amount, double target); FILE RENAME: ten/tenPrivate.h --> ten/privateTen.h API NEW: tend helix New tend comand for making cool twisting helix tensor datasets --------------------------------------------------------------------- mite: massive internal reorganization to now support volume rendering of vector and tensor fields. Still using nrrds as transfer function LUTs, and all existing axis labels should work, although they're deprecated. Good luck finding documentation. --------------------------------------------------------------------- echo: now properly multi-threaded --------------------------------------------------------------------- |