/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * PURPOSE: * * The rviewMDD module encapsulates various generic operations on * MDD objects; it relies heavily on templates for this. All functions * provided here are a) completely independent from the rest of rView * and b) work on any kind of MDD, i.e. no restrictions whatsoever on * dimensionality or base type. Most functions utilize * mdd_objectFunctionType() for this which iterates over the MDD object * basetype first and calls functions provided in the mdd_function_pointers * structure which perform the required operation on each of the primitive * basetypes. * * Functions provided are: * * - mdd_objectRange(): return the minimum and maximum cell values. * - mdd_createSubcube(): creates a new MDD object by copying a subcube * (or all of) a source MDD object; optionally persistent. * - mdd_objectScaleInter(): creates new object by resampling (part of) * the source object using n-linear interpolation. Use for upsampling. * - mdd_objectScaleAverage(): creates new object by resampling (part of) * the source object using averaging. Use for downsampling. * - mdd_objectScaleSimple(): creates new object by scaling (part of) * the source object using simple nearest neighbour. Fast but blocky. * - mdd_objectChangeEndianness(): creates a new object where the * endianness is inverted compared to the source object, or changes * the object itself. * * COMMENTS: * No comments */ // For early templates #ifndef _RVIEW_MDD_CPP_ #define _RVIEW_MDD_CPP_ #ifdef __GNUG__ #pragma implementation #endif #include #include #include // Was this file included from rviewMDD.hh? #ifdef EARLY_TEMPLATE #ifndef __EXECUTABLE__ #define __EXECUTABLE__ #define _RVIEW_MDD_EXECUTABLE_ #endif #endif #include "rasodmg/transaction.hh" #include "raslib/primitivetype.hh" #include "raslib/structuretype.hh" #include "raslib/endian.hh" #include "rasodmg/alignedtiling.hh" #include "rasodmg/storagelayout.hh" #include "rviewMDD.hh" #include "rviewTypes.hh" #ifdef _RVIEW_MDD_EXECUTABLE_ #undef __EXECUTABLE__ #endif #define MDD_FIXPREC 16 // auxData interpreted as double[2] containing min, max, initialised externally template int objectRange_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *auxData) { long *pos; char *srcdata; T **srcptr; int i, j; double min, max, val; pos = new long[dim]; srcptr = new T *[dim]; srcdata = objectCalcStart((const char *)src, mfd, dim); for (i=0; i max) max = val; i = dim-1; while (i >= 0) { pos[i]++; srcptr[i] = (T*)(((char*)(srcptr[i])) + mfd[i].srcoff); if (pos[i] <= mfd[i].useHigh) break; pos[i] = mfd[i].useLow; i--; } if (i >= 0) { for (j=i+1; j= 0); ((double*)auxData)[0] = min; ((double*)auxData)[1] = max; delete [] srcptr; delete [] pos; return 1; } // Additional template code for objectScaleInter template inline void objectScaleInterICore(double *srcf, double *destf, double pos, int idx1, int idx2) { destf[idx1] = srcf[idx1] + pos * (srcf[idx2] - srcf[idx1]); } template int objectScaleInter_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *auxData) { double *pos, *f, *fwork; long *lastpos; long *ipos; long *dp; char **srcptr; char *srcbase; long offset; int i, j, k; int slowOffset; T *srcdata, *destdata; long *cubeoff = (long*)auxData; f = new double[(1< high. if (ipos[i] >= mfd[i].high) {ipos[i] = mfd[i].useHigh; slowOffset = 1;} } srcbase = srcptr[dim-1]; if (slowOffset != 0) { for (i=0; i<(1<= srchigh) cout << "Overflow1" << endl; } } else { for (i=0; i<(1<0; k--) { // n-linear interpolation for (j=0; j<(1<= mfd[dim-1].high) slowOffset = 1; offset = (1<<(dim-1)); memcpy(f, f + offset, offset*sizeof(double)); if (slowOffset != 0) { for (i=(1<<(dim-1)); i<(1<= srchigh) cout << "Overflow2" << endl; } } else { for (i=(1<<(dim-1)); i<(1<= 0) { dp[i]++; pos[i] += mfd[i].step; offset = (long)(pos[i]); if (offset != lastpos[i]) { offset -= lastpos[i]; lastpos[i] = (long)(pos[i]); // high, not useHigh if (lastpos[i] <= mfd[i].high) { srcptr[i] += offset*mfd[i].srcoff; ipos[i] = lastpos[i]; } } if (dp[i] <= mfd[i].newHigh) break; dp[i] = mfd[i].newLow; pos[i] = (double)(mfd[i].useLow); lastpos[i] = mfd[i].useLow; i--; } if (i >= 0) { for (j=i+1; j= 0); delete [] pos; delete [] f; delete [] fwork; delete [] ipos; delete [] lastpos; delete [] dp; delete [] srcptr; return 1; } template int objectScaleAverage_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *aux) { long *pos, *subpos, *dp; T **srcptr, **subptr; long lastpos, number; double avg; int i, j; T *destdata; char *srcdata; pos = new long[dim]; subpos = new long[dim]; dp = new long[dim]; srcptr = new T*[dim]; subptr = new T*[dim]; srcdata = objectCalcStart((const char*)src, mfd, dim); for (i=0; i>MDD_FIXPREC) << ':' << (void*)(srcptr[i]) << ' '; cout << endl; // start averaging over a subcube avg = 0; number = 0; // init subcube iteration for (i=0; i= 0) { subpos[i] += (1<> MDD_FIXPREC) < ((pos[i] + mfd[i].lstep) >> MDD_FIXPREC)) break; subpos[i] = pos[i]; i--; } if (i >= 0) { for (j=i+1; j= 0); *destdata = (T)(avg/number); destdata = (T*)(((char*)destdata) + datastep); i = dim-1; do { dp[i]++; lastpos = (pos[i] >> MDD_FIXPREC); pos[i] += mfd[i].lstep; srcptr[i] = (T*)(((char*)(srcptr[i])) + ((pos[i] >> MDD_FIXPREC) - lastpos) * mfd[i].srcoff); if (dp[i] <= mfd[i].newHigh) break; dp[i] = mfd[i].newLow; pos[i] = (mfd[i].useLow << MDD_FIXPREC); i--; } while (i >= 0); if (i >= 0) { for (j=i+1; j= 0); delete [] subptr; delete [] srcptr; delete [] dp; delete [] subpos; delete [] pos; return 1; } template int objectScaleSimple_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *aux) { long *pos, *dp; long lastpos; T **srcptr; T *destdata; char *srcdata; int i, j; pos = new long[dim]; dp = new long[dim]; srcptr = new T*[dim]; srcdata = objectCalcStart((const char*)src, mfd, dim); for (i=0; i= 0) { dp[i]++; lastpos = (pos[i] >> MDD_FIXPREC); pos[i] += mfd[i].lstep; srcptr[i] = (T*)(((char*)srcptr[i]) + ((pos[i] >> MDD_FIXPREC) - lastpos)*mfd[i].srcoff); if (dp[i] <= mfd[i].newHigh) break; dp[i] = mfd[i].newLow; pos[i] = (mfd[i].useLow << MDD_FIXPREC); i--; } if (i >= 0) { for (j=i+1; j= 0); delete [] srcptr; delete [] dp; delete [] pos; return 1; } /* Must not compile non-template code when this file was just included */ #ifndef __EXECUTABLE__ // in raslib/odmgtypes.hh there are the following typedefs: // typedef unsigned char r_Boolean; // typedef unsigned char r_Char; // so the template instantiation is done twice for the same type. gcc 2.95.2 doesn't // like this. // Sadly, this is necessary with VisualC... #define DECLARE_MDD_FUNC(f) \ // template int f MDD_FUNCTION_SIGNATURE(r_Boolean); \ template int f MDD_FUNCTION_SIGNATURE(r_Char); \ template int f MDD_FUNCTION_SIGNATURE(r_Octet); \ template int f MDD_FUNCTION_SIGNATURE(r_Short); \ template int f MDD_FUNCTION_SIGNATURE(r_UShort); \ template int f MDD_FUNCTION_SIGNATURE(r_Long); \ template int f MDD_FUNCTION_SIGNATURE(r_ULong); \ template int f MDD_FUNCTION_SIGNATURE(r_Float); \ template int f MDD_FUNCTION_SIGNATURE(r_Double); DECLARE_MDD_FUNC(objectScaleInter_temp); DECLARE_MDD_FUNC(objectScaleAverage_temp); DECLARE_MDD_FUNC(objectScaleSimple_temp); DECLARE_MDD_FUNC(objectRange_temp); // Calculate the starting point in the source cube char *objectCalcStart(const char *src, const mdd_function_desc *mfd, int dim) { int i; char *d; d = (char*)src; for (i=0; i > mddPtr = (r_Ref >)(src) int mdd_createSubcube(r_Ref srcMdd, r_Ref &newMdd, r_Minterval *domain, r_Database *db) { r_Dimension dim; char *destdata, *srcdata; r_Ref newMddPtr; r_Minterval interv; r_Minterval newInterv; int tpsize; int i, j; long length; mdd_function_desc *mfd; long *pos; char **srcptr; interv = srcMdd->spatial_domain(); dim = interv.dimension(); if (dim < 1) return 0; tpsize = srcMdd->get_type_length(); newInterv = r_Minterval(dim); for (i=0; i<(int)dim; i++) { if (domain == NULL) { newInterv << interv[i]; } else { newInterv << (*domain)[i]; } } if ((destdata = mdd_objectFunctionInitMdd(srcMdd, newMddPtr, newInterv, tpsize, dim, db)) == NULL) { cerr << "Couldn't create new MDD object" << endl; return 0; } mfd = mdd_objectFunctionInitData(interv, newInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV); srcdata = objectCalcStart(srcMdd->get_array(), mfd, (int)dim); pos = new long[dim]; srcptr = new char *[dim]; for (i=0; i<(int)dim; i++) { pos[i] = mfd[i].useLow; srcptr[i] = srcdata; } // Lenght of one strip of data to copy length = (mfd[dim-1].useHigh - mfd[dim-1].useLow + 1) * tpsize; do { memcpy(destdata, srcptr[dim-1], length); destdata += length; i = (int)dim-2; while (i >= 0) { pos[i]++; srcptr[i] += mfd[i].srcoff; if (pos[i] <= mfd[i].useHigh) break; pos[i] = mfd[i].useLow; i--; } if (i >= 0) { for (j=i+1; j<(int)dim; j++) srcptr[j] = srcptr[i]; } } while (i >= 0); delete [] srcptr; delete [] pos; delete [] mfd; newMdd = newMddPtr; return 1; } // Support functions for (recursive) member-by-member resampling of a data cube via interpolation int mdd_objectFunctionPrim(const mdd_function_pointers *mfp, r_Primitive_Type *primType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData) { switch (primType->type_id()) { case r_Primitive_Type::BOOL: if (mfp->mddf_bool != NULL) mfp->mddf_bool((r_Boolean*)dest, (const r_Boolean *)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::CHAR: if (mfp->mddf_char != NULL) mfp->mddf_char((r_Char*)dest, (const r_Char *)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::OCTET: if (mfp->mddf_octet != NULL) mfp->mddf_octet((r_Octet *)dest, (const r_Octet*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::SHORT: if (mfp->mddf_short != NULL) mfp->mddf_short((r_Short *)dest, (const r_Short*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::USHORT: if (mfp->mddf_ushort != NULL) mfp->mddf_ushort((r_UShort *)dest, (const r_UShort*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::LONG: if (mfp->mddf_long != NULL) mfp->mddf_long((r_Long *)dest, (const r_Long*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::ULONG: if (mfp->mddf_ulong != NULL) mfp->mddf_ulong((r_ULong *)dest, (const r_ULong*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::FLOAT: if (mfp->mddf_float != NULL) mfp->mddf_float((r_Float *)dest, (const r_Float*)src, mfd, dim, tpsize, auxData); break; case r_Primitive_Type::DOUBLE: if (mfp->mddf_double != NULL) mfp->mddf_double((r_Double *)dest, (const r_Double*)src, mfd, dim, tpsize, auxData); break; default: return 0; } return 1; } // Support functions for (recursive) member-by-member resampling of a data cube via interpolation int mdd_objectFunctionStruct(const mdd_function_pointers *mfp, r_Structure_Type *structType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData) { r_Type *newType; unsigned long offset; char *inc, *outc; r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin()); while (iter != structType->defines_attribute_end()) { newType = (*iter).type_of().clone(); offset = (*iter).offset(); inc = (char*)src + offset; outc = (char*)dest + offset; if (newType->isStructType()) { r_Structure_Type *newStructType = (r_Structure_Type*)newType; mdd_objectFunctionStruct(mfp, newStructType, inc, outc, mfd, dim, tpsize, auxData); } else { r_Primitive_Type *newPrimType = (r_Primitive_Type*)newType; mdd_objectFunctionPrim(mfp, newPrimType, inc, outc, mfd, dim, tpsize, auxData); } delete newType; iter++; } return 1; } int mdd_objectFunctionType(const mdd_function_pointers *mfp, const r_Type *baseType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData) { if (((r_Type*)baseType)->isStructType()) { r_Structure_Type *structType = (r_Structure_Type*)baseType; return mdd_objectFunctionStruct(mfp, structType, src, dest, mfd, dim, tpsize, auxData); } else { r_Primitive_Type *primType = (r_Primitive_Type*)baseType; return mdd_objectFunctionPrim(mfp, primType, src, dest, mfd, dim, tpsize, auxData); } } char *mdd_objectFunctionInitMdd(r_Ref mddPtr, r_Ref &newMddPtr, r_Minterval &newInterv, int tpsize, r_Dimension dim, r_Database *db) { char *destdata; const char *b; r_Storage_Layout *store; if (mddPtr->get_storage_layout() != NULL) { store = new r_Storage_Layout(*(mddPtr->get_storage_layout())); } else { r_Minterval tileInterv(dim); r_Aligned_Tiling *dfltTiling; int dim, i; dim = newInterv.dimension(); for (i=0; iget_array(); newMddPtr->set_current_format(mddPtr->get_current_format()); if ((b = mddPtr->get_type_name()) != NULL) newMddPtr->set_type_by_name(b); if ((b = mddPtr->get_type_structure()) != NULL) newMddPtr->set_type_structure(b); return destdata; } mdd_function_desc *mdd_objectFunctionInitData(r_Minterval &interv, r_Minterval &useInterv, r_Minterval &newInterv, int tpsize, unsigned int flags) { int i, offset; r_Dimension dim; mdd_function_desc *mfd; dim = interv.dimension(); mfd = new mdd_function_desc[dim]; // Calculate scaling factors for (i=0; i<(int)dim; i++) { mfd[i].low = interv[i].low(); mfd[i].high = interv[i].high(); mfd[i].useLow = useInterv[i].low(); mfd[i].useHigh = useInterv[i].high(); if ((flags & MDD_OBJECT_INIT_NEWIV) != 0) { mfd[i].newLow = newInterv[i].low(); mfd[i].newHigh = newInterv[i].high(); if ((flags & MDD_OBJECT_INIT_FPSTEP) == MDD_OBJECT_INIT_FPSTEP) { // In order to avoid doubling right-boundary pixels we have to use (h-l), not (h-l+1) // as nominator mfd[i].step = ((double)(mfd[i].useHigh - mfd[i].useLow)) / (mfd[i].newHigh - mfd[i].newLow + 1); } else { double h = ((double)(mfd[i].useHigh - mfd[i].useLow + 1)) / (mfd[i].newHigh - mfd[i].newLow + 1); mfd[i].lstep = (long)(h * (1<=0; i--) { mfd[i].srcoff = offset; offset *= (mfd[i].high - mfd[i].low + 1); } return mfd; } int mdd_objectRange(r_Ref mddPtr, r_Minterval &useInterv, double &min, double &max) { r_Dimension dim; double minmax[2]; r_Ref newMddPtr; // Dummy... r_Minterval newInterv; // Dummy... r_Minterval interv; const r_Type *baseType; int tpsize; mdd_function_desc *mfd; mdd_function_pointers mfp; interv = mddPtr->spatial_domain(); dim = interv.dimension(); if (dim < 1) return 0; if ((baseType = mddPtr->get_base_type_schema()) == NULL) { cerr << "No schema information available!" << endl; return 0; } tpsize = mddPtr->get_type_length(); MDD_INIT_FUNCTIONS(mfp, objectRange_temp); mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, 0); minmax[0] = DBL_MAX; minmax[1] = -DBL_MAX; // these are unsigned!!! mdd_objectFunctionType(&mfp, baseType, mddPtr->get_array(), NULL, mfd, (int)dim, tpsize, (void*)minmax); min = minmax[0]; max = minmax[1]; delete [] mfd; return 1; } // Scale an object using n-linear interpolation (recommended for magnification) int mdd_objectScaleInter(r_Ref mddPtr, r_Minterval &useInterv, r_Ref &newMdd, r_Minterval &newInterv) { r_Dimension dim; r_Minterval interv; r_Ref newMddPtr; mdd_function_desc *mfd; int i, j; long *cubeoff; char *srcdata, *destdata; int tpsize; long offset; const r_Type *baseType; mdd_function_pointers mfp; interv = mddPtr->spatial_domain(); dim = interv.dimension(); if ((dim < 1) || (dim != newInterv.dimension())) return 0; // Type information available? if ((baseType = mddPtr->get_base_type_schema()) == NULL) { cerr << "No schema information available!" << endl; return 0; } tpsize = mddPtr->get_type_length(); if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL) return 0; MDD_INIT_FUNCTIONS(mfp, objectScaleInter_temp); // create temporary arrays mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_FPSTEP); cubeoff = new long[(1<get_array()) + offset;*/ srcdata = (char*)(mddPtr->get_array()); // Precalculate cube-offsets for more speed in inner loop for (i=0; i<(1< mddPtr, r_Minterval &useInterv, r_Ref &newMdd, r_Minterval &newInterv) { r_Dimension dim; r_Minterval interv; r_Ref newMddPtr; mdd_function_desc *mfd; char *srcdata, *destdata; int tpsize; const r_Type *baseType; mdd_function_pointers mfp; interv = mddPtr->spatial_domain(); dim = interv.dimension(); if ((dim < 1) || (dim != newInterv.dimension())) return 0; if ((baseType = mddPtr->get_base_type_schema()) == NULL) { cerr << "No schema information available!" << endl; return 0; } tpsize = mddPtr->get_type_length(); if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL) return 0; MDD_INIT_FUNCTIONS(mfp, objectScaleAverage_temp); mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV); srcdata = mddPtr->get_array(); mdd_objectFunctionType(&mfp, baseType, srcdata, destdata, mfd, (int)dim, tpsize, NULL); delete [] mfd; newMdd = (r_Ref)newMddPtr; return 1; } int mdd_objectScaleSimple(r_Ref mddPtr, r_Minterval &useInterv, r_Ref &newMdd, r_Minterval &newInterv) { r_Dimension dim; r_Minterval interv; r_Ref newMddPtr; mdd_function_desc *mfd; char *srcdata, *destdata; int tpsize; const r_Type *baseType; mdd_function_pointers mfp; interv = mddPtr->spatial_domain(); dim = interv.dimension(); if ((dim < 1) || (dim != newInterv.dimension())) return 0; if ((baseType = mddPtr->get_base_type_schema()) == NULL) { cerr << "No schema information available!" << endl; return 0; } tpsize = mddPtr->get_type_length(); if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL) return 0; MDD_INIT_FUNCTIONS(mfp, objectScaleSimple_temp); mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV); srcdata = mddPtr->get_array(); mdd_objectFunctionType(&mfp, baseType, srcdata, destdata, mfd, (int)dim, tpsize, NULL); newMdd = (r_Ref)newMddPtr; delete [] mfd; return 1; } int mdd_objectChangeEndianness(r_Ref mddPtr, r_Minterval &useInterv, r_Ref *newMdd, r_Minterval *newInterv) { char *srcdata; const r_Base_Type *baseType; r_Ref newMddPtr; // only used in "new" mode r_Minterval dom, *iterDom; int tpsize; if ((baseType = (r_Base_Type*)(mddPtr->get_base_type_schema())) == NULL) { cerr << "No schema information available!" << endl; return 0; } tpsize = mddPtr->get_type_length(); srcdata = mddPtr->get_array(); dom = mddPtr->spatial_domain(); if (newMdd == NULL) { r_Endian::swap_array( baseType, dom, dom, srcdata, srcdata ); } else { void *destdata; r_Dimension dim = dom.dimension(); if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, *newInterv, tpsize, dim)) == NULL) return 0; r_Endian::swap_array( baseType, dom, *newInterv, *newInterv, *newInterv, srcdata, destdata ); } if (newMdd != NULL) { *newMdd = newMddPtr; } return 1; } #endif #endif