IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25405


Ignore:
Timestamp:
Sep 15, 2009, 4:00:18 PM (17 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/eam_branches/20090715/psLib
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/20090715/psLib/src/db/psDB.c

    r23915 r25405  
    22612261    PS_DB_OP_LE,
    22622262    PS_DB_OP_GE,
     2263    PS_DB_OP_NE,
    22632264} psDBOpValue;
    22642265
     
    23082309            opStr = "<";
    23092310            op = PS_DB_OP_LT;
    2310         }
    2311     }
     2311        } else if (strstr(item->comment, "!=")) {
     2312            opStr = "!=";
     2313            op = PS_DB_OP_NE;
     2314        }
     2315    }
     2316
    23122317
    23132318    // XXX why are >, < searches not supported here????
     
    23412346        case PS_DB_OP_EQ:
    23422347            psStringAppend(&query, "(ABS(%s - %.8f) < %.8f)", itemName, (float)(item->data.F32), PS_DB_FLT_PAD);
     2348            break;
     2349        case PS_DB_OP_NE:
     2350            psStringAppend(&query, "(ABS(%s - %.8f) >= %.8f)", itemName, (float)(item->data.F32), PS_DB_FLT_PAD);
    23432351            break;
    23442352        case PS_DB_OP_LE:
     
    23602368            psStringAppend(&query, "(ABS(%s - %.17f) < %.17f)", itemName, (float)(item->data.F64), PS_DB_DBL_PAD);
    23612369            break;
     2370        case PS_DB_OP_NE:
     2371            psStringAppend(&query, "(ABS(%s - %.17f) >= %.17f)", itemName, (float)(item->data.F64), PS_DB_DBL_PAD);
     2372            break;
    23622373        case PS_DB_OP_LE:
    23632374        case PS_DB_OP_LT:
     
    23762387        case PS_DB_OP_EQ:
    23772388            psStringAppend(&query, "%s = %d", itemName, (int)(item->data.B));
     2389            break;
     2390        case PS_DB_OP_NE:
     2391            psStringAppend(&query, "%s != %d", itemName, (int)(item->data.B));
    23782392            break;
    23792393        default:
     
    23972411                psStringAppend(&query, "%s LIKE '%s'", itemName, item->data.str);
    23982412            } else {
    2399                 psStringAppend(&query, "%s = '%s'", itemName, item->data.str);
     2413                psStringAppend(&query, "%s %s '%s'", itemName, opStr, item->data.str);
    24002414            }
    24012415        }
  • branches/eam_branches/20090715/psLib/src/fits/psFits.c

    r25022 r25405  
    150150            char errorBuf[MAX_STRING_LENGTH], *errorMsg;
    151151#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE)
    152             errorMsg = strerror_r(thisErrno, errorBuf, MAX_STRING_LENGTH);
    153 #else
    154152            strerror_r(thisErrno, errorBuf, MAX_STRING_LENGTH);
    155153            errorMsg = errorBuf;
     154#else
     155            errorMsg = strerror_r(thisErrno, errorBuf, MAX_STRING_LENGTH);
    156156#endif
    157157            psError(PS_ERR_IO, true, "Directory (%s) for requested file is not accessible: %s",
     
    209209                char errorBuf[64], *errorMsg;
    210210# if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE)
    211                 errorMsg = strerror_r (errno, errorBuf, 64);
    212 # else
    213211                strerror_r (errno, errorBuf, 64);
    214212                errorMsg = errorBuf;
     213# else
     214                errorMsg = strerror_r (errno, errorBuf, 64);
    215215# endif
    216216                psError(PS_ERR_IO, true, "Failed to delete a previously-existing file (%s), error %d: %s",
     
    344344// Therefore, we implement our own version of moving to an extension specified by name.  The pure cfitsio
    345345// version is used if "conventions.compression" handling is turned off in the psFits structure.
    346 bool psFitsMoveExtName(const psFits* fits,
    347                        const char* extname)
     346static bool fitsMoveExtName(const psFits* fits, // FITS file
     347                            const char* extname, // Extension name
     348                            bool errors // Generate errors?
     349    )
    348350{
    349351    PS_ASSERT_FITS_NON_NULL(fits, false);
     
    356358        // User wants to use cfitsio.  Good luck to them!
    357359        if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
    358             psFitsError(status, true, _("Could not find HDU '%s'"), extname);
     360            if (errors) {
     361                psFitsError(status, true, _("Could not find HDU '%s'"), extname);
     362            }
    359363            return false;
    360364        }
     
    378382        if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
    379383            // We've run off the end
    380             psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
     384            if (errors) {
     385                psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
     386            }
    381387            return false;
    382388        }
     
    406412    }
    407413    psAbort("Should never reach here.");
     414}
     415
     416
     417bool psFitsMoveExtName(const psFits* fits, const char* extname)
     418{
     419    return fitsMoveExtName(fits, extname, true);
     420}
     421
     422bool psFitsMoveExtNameClean(const psFits* fits, const char* extname)
     423{
     424    return fitsMoveExtName(fits, extname, false);
    408425}
    409426
  • branches/eam_branches/20090715/psLib/src/fits/psFits.h

    r19035 r25405  
    245245);
    246246
     247/** Moves the FITS HDU to the specified extension name without generating errors.
     248 *
     249 *  @return bool        TRUE if the extension name was found and move was
     250 *                      successful, otherwise FALSE
     251 */
     252bool psFitsMoveExtNameClean(
     253    const psFits* fits,                ///< the psFits object to move
     254    const char* extname                ///< the extension name
     255);
     256
    247257/** Moves the FITS HDU to the specified extension number
    248258 *
  • branches/eam_branches/20090715/psLib/src/fits/psFitsHeader.c

    r25022 r25405  
    5050
    5151// List of the start of FITS header keys not to write (handled by cfitsio); NULL-terminated
    52 static const char *noWriteFitsKeyStarts[] = { "NAXIS", "TTYPE", "TFORM", NULL };
     52static const char *noWriteFitsKeyStarts[] = { "NAXIS", "TTYPE", "TFORM", "TZERO", "TSCAL", NULL };
    5353
    5454// List of compressed FITS header keys not to write (handled by cfitsio); NULL-terminated
     
    305305                keyType = 'C';
    306306            }
     307            psTrace("psLib.fits", 3, "Reading keyword %s, type %c\n", keyName, keyType);
    307308            if (status != 0) {
    308309                break;
     
    327328                                               -INFINITY);
    328329                } else {
    329                     success = psMetadataAddS32(header, PS_LIST_TAIL, keyNameTrans, dupFlag, keyComment,
    330                                                atoi(keyValue));
     330                    long long value = atoll(keyValue); // Value
     331                    if (value > PS_MIN_S32 && value < PS_MAX_S32) {
     332                        success = psMetadataAddS32(header, PS_LIST_TAIL, keyNameTrans, dupFlag, keyComment,
     333                                                   value);
     334                    } else {
     335                        success = psMetadataAddS64(header, PS_LIST_TAIL, keyNameTrans, dupFlag, keyComment,
     336                                                   value);
     337                    }
    331338                }
    332339                break;
     
    509516        psMetadataItem *simpleItem = psMetadataLookup(output, "SIMPLE"); // SIMPLE in the header
    510517        if (simpleItem) {
    511             if (simpleItem->type != PS_DATA_BOOL) {
    512                 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "SIMPLE in a FITS header must be of boolean type: "
    513                         "not %x --- assuming FALSE.\n", simpleItem->type);
     518            if (simpleItem->type != PS_DATA_BOOL || !simpleItem->data.B) {
    514519                int value = false;          // Temporary holder for boolean
     520                psWarning("Writing SIMPLE=F to FITS header by request");
    515521                fits_update_key(fits->fd, TLOGICAL, "SIMPLE", &value,
    516522                                "File does not conform to FITS standard", &status);
    517523                simple = false;
    518             } else if (!simpleItem->data.B) {
    519                 simple = false;
    520                 int value = false;      // Temporary holder for boolean
    521                 fits_update_key(fits->fd, TLOGICAL, "SIMPLE", &value,
    522                                 "File does not conform to FITS standard", &status);
    523524            }
    524525            // Uncompressed SIMPLE = T is taken care of by cfitsio.
     
    546547            char comment[FLEN_CARD];    // Comment for ZIMAGE; unused
    547548            int value;                  // Value for ZIMAGE; unused
     549            psTrace("psLib.fits", 3, "Writing header ZSIMPLE to preserve PHU");
    548550            fits_read_key(fits->fd, TLOGICAL, "ZIMAGE", &value, comment, &status);
    549551            fits_insert_key_log(fits->fd, "ZSIMPLE", simple, "Uncompressed file's conforms to FITS", &status);
     
    575577                if (keywordInList(name, noWriteCompressedKeys) ||
    576578                    (keyStarts && keywordStartsWith(name, noWriteCompressedKeyStarts))) {
     579                    psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
    577580                    continue;
    578581                }
    579582            } else if (keywordInList(name, noWriteCompressedKeys) ||
    580583                       (keyStarts && keywordStartsWith(name, noWriteCompressedKeyStarts))) {
     584                psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
    581585                continue;
    582586            }
     
    584588            if (keywordInList(name, noWriteFitsKeys) ||
    585589                (keyStarts && keywordStartsWith(name, noWriteFitsKeyStarts))) {
     590                psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
    586591                continue;
    587592            }
     
    592597                psWarning("COMMENT header is not of type STRING (%x) --- ignored.", item->type);
    593598            } else {
     599                psTrace("psLib.fits", 5, "Writing header COMMENT: %s", item->data.str);
    594600                fits_write_comment(fits->fd, item->data.str, &status);
    595601            }
     
    598604                psWarning("COMMENT header is not of type STRING (%x) --- ignored.", item->type);
    599605            } else {
     606                psTrace("psLib.fits", 5, "Writing header HISTORY: %s", item->data.str);
    600607                fits_write_history(fits->fd, item->data.str, &status);
    601608            }
     
    605612              case PS_DATA_BOOL: {
    606613                  int value = item->data.B;
     614                  psTrace("psLib.fits", 5, "Writing BOOL header %s: %d", name, value);
    607615                  fits_update_key(fits->fd, TLOGICAL, name, &value, item->comment, &status);
    608616                  break;
    609617              }
    610618              case PS_DATA_S8:
     619                psTrace("psLib.fits", 5, "Writing S8 header %s: %d", name, (int)item->data.S8);
    611620                fits_update_key(fits->fd, TBYTE, name, &item->data.S8, item->comment, &status);
    612621                break;
    613622              case PS_DATA_S16:
     623                psTrace("psLib.fits", 5, "Writing S16 header %s: %d", name, (int)item->data.S16);
    614624                fits_update_key(fits->fd, TSHORT, name, &item->data.S16, item->comment, &status);
    615625                break;
    616626              case PS_DATA_S32:
     627                psTrace("psLib.fits", 5, "Writing S32 header %s: %d", name, (int)item->data.S32);
    617628                fits_update_key(fits->fd, TINT, name, &item->data.S32, item->comment, &status);
    618629                break;
    619630              case PS_DATA_S64:
     631                psTrace("psLib.fits", 5, "Writing S64 header %s: %" PRId64, name, item->data.S64);
    620632                fits_update_key(fits->fd, TLONGLONG, name, &item->data.S64, item->comment, &status);
    621633                break;
    622634              case PS_DATA_U8: {
    623635                  unsigned short int temp = item->data.U8;
     636                psTrace("psLib.fits", 5, "Writing U8 header %s: %d", name, (int)item->data.U8);
    624637                  fits_update_key(fits->fd, TUSHORT, name, &temp, item->comment, &status);
    625638                  break;
    626639              }
    627640              case PS_DATA_U16:
     641                psTrace("psLib.fits", 5, "Writing U16 header %s: %d", name, (int)item->data.U16);
    628642                fits_update_key(fits->fd, TUSHORT, name, &item->data.U16, item->comment, &status);
    629643                break;
    630644              case PS_DATA_U32:
     645                psTrace("psLib.fits", 5, "Writing U32 header %s: %d", name, (unsigned int)item->data.U32);
    631646                fits_update_key(fits->fd, TUINT, name, &item->data.U32, item->comment, &status);
    632647                break;
     
    639654                }
    640655                psS64 temp = item->data.U64; // Signed version
     656                psTrace("psLib.fits", 5, "Writing U64 header %s: %" PRIu64, name, item->data.U64);
    641657                fits_update_key(fits->fd, TLONGLONG, name, &temp, item->comment, &status);
    642658                break;
    643659              case PS_DATA_F32: {
    644660                  int infCheck = 0;         // Result of isinf()
     661                  psTrace("psLib.fits", 5, "Writing F32 header %s: %f", name, item->data.F32);
    645662                  if (isnan(item->data.F32)) {
    646663                      fits_update_key(fits->fd, TSTRING, name, "NaN", item->comment, &status);
     
    659676              case PS_DATA_F64: {
    660677                  int infCheck = 0;         // Result of isinf()
     678                  psTrace("psLib.fits", 5, "Writing F32 header %s: %lf", name, item->data.F64);
    661679                  if (isnan(item->data.F64)) {
    662680                      fits_update_key(fits->fd, TSTRING, name, "NaN", item->comment, &status);
     
    674692              }
    675693              case PS_DATA_STRING:
     694                psTrace("psLib.fits", 5, "Writing STR header %s: %s", name, item->data.str);
    676695                fits_update_key(fits->fd, TSTRING, name, item->data.V, item->comment, &status);
    677696                break;
  • branches/eam_branches/20090715/psLib/src/imageops/psImageConvolve.c

    r24272 r25405  
    678678}
    679679
     680static bool imageSmoothMaskPixels(psVector *out, const psImage *image, const psImage *mask,
     681                                  psImageMaskType maskVal, const psVector *x, const psVector *y,
     682                                  const psVector *gaussNorm, float minGauss, int size, int start, int stop)
     683{
     684    const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel
     685    int numCols = image->numCols, numRows = image->numRows; // Size of image
     686    int xLast = numCols - 1, yLast = numRows - 1; // Last index
     687    for (int i = start; i < stop; i++) {
     688        int xPix = x->data.S32[i], yPix = y->data.S32[i]; // Pixel coordinates for smoothing
     689
     690        int yMin = PS_MAX(yPix - size, 0);
     691        int yMax = PS_MIN(yPix + size, yLast);
     692        int xMin = PS_MAX(xPix - size, 0);
     693        int xMax = PS_MIN(xPix + size, xLast);
     694
     695        const float *yGauss = &gauss[yMin - yPix];
     696
     697        double ySumIG = 0.0, ySumG = 0.0;
     698        for (int v = yMin; v <= yMax; v++, yGauss++) {
     699            const float *xGauss = &gauss[xMin - xPix];
     700            double xSumIG = 0.0, xSumG = 0.0;
     701            const psImageMaskType *maskData = &mask->data.PS_TYPE_IMAGE_MASK_DATA[v][xMin];
     702            const psF32 *imageData = &image->data.F32[v][xMin];
     703            for (int u = xMin; u <= xMax; u++, xGauss++, imageData++, maskData++) {
     704                if (*maskData & maskVal) {
     705                    continue;
     706                }
     707                xSumIG += *imageData * *xGauss;
     708                xSumG += *xGauss;
     709            }
     710            if (xSumG > minGauss) {
     711                ySumIG += xSumIG * *yGauss;
     712                ySumG += xSumG * *yGauss;
     713            }
     714        }
     715
     716        out->data.F32[i] = ySumG > minGauss ? ySumIG / ySumG : NAN;
     717    }
     718
     719    return true;
     720}
     721
     722static bool psImageSmoothMaskPixelsThread(psThreadJob *job)
     723{
     724    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
     725    psAssert(job->args, "programming error: no job arguments");
     726    psAssert(job->args->n == 11, "programming error: wrong number of job arguments");
     727
     728    psVector *out = job->args->data[0]; // Output vector
     729    const psImage *image  = job->args->data[1]; // Input image
     730    const psImage *mask   = job->args->data[2]; // Input mask
     731    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[3], PS_TYPE_IMAGE_MASK_DATA);
     732    const psVector *x = job->args->data[4];
     733    const psVector *y = job->args->data[5];
     734    const psVector *gaussNorm = job->args->data[6];
     735    float minGauss = PS_SCALAR_VALUE(job->args->data[7], F32);
     736    int size = PS_SCALAR_VALUE(job->args->data[8], S32);
     737    int start = PS_SCALAR_VALUE(job->args->data[9], S32);
     738    int stop = PS_SCALAR_VALUE(job->args->data[10], S32);
     739    return imageSmoothMaskPixels(out, image, mask, maskVal, x, y, gaussNorm,
     740                                 minGauss, size, start, stop);
     741}
     742
     743
     744psVector *psImageSmoothMaskPixels(const psImage *image, const psImage *mask, psImageMaskType maskVal,
     745                                  const psVector *x, const psVector *y,
     746                                  float sigma, float numSigma, float minGauss)
     747{
     748    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
     749    PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
     750    PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL);
     751    PS_ASSERT_IMAGES_SIZE_EQUAL(image, mask, NULL);
     752    PS_ASSERT_VECTOR_NON_NULL(x, NULL);
     753    PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_S32, NULL);
     754    PS_ASSERT_VECTOR_NON_NULL(y, NULL);
     755    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_S32, NULL);
     756    PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, NULL);
     757
     758    int size = sigma * numSigma + 0.5;  // Half-size of kernel
     759
     760    int num = x->n;                     // Number of pixels to smooth
     761    psVector *out = psVectorAlloc(num, PS_TYPE_F32); // Output results
     762
     763    // Generate normalized gaussian
     764    IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32);
     765
     766    // Columns
     767    if (threaded) {
     768        int numThreads = psThreadPoolSize(); // Number of threads
     769        int delta = (numThreads) ? num / numThreads + 1 : num; // Block of cols to do at once
     770        for (int start = 0; start < num; start += delta) {
     771            int stop = PS_MIN(start + delta, num);  // End of block
     772
     773            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS");
     774            psArrayAdd(job->args, 1, out);
     775            psArrayAdd(job->args, 1, (psImage*)image);
     776            psArrayAdd(job->args, 1, (psImage*)mask);
     777            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
     778            psArrayAdd(job->args, 1, (psVector*)x);
     779            psArrayAdd(job->args, 1, (psVector*)y);
     780            psArrayAdd(job->args, 1, gaussNorm);
     781            PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
     782            PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32);
     783            PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32);
     784            PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32);
     785            if (!psThreadJobAddPending(job)) {
     786                psFree(job);
     787                psFree(gaussNorm);
     788                psFree(out);
     789                return NULL;
     790            }
     791            psFree(job);
     792        }
     793    } else if (!imageSmoothMaskPixels(out, image, mask, maskVal, x, y,
     794                                      gaussNorm, minGauss, size, 0, num)) {
     795        psError(PS_ERR_UNKNOWN, false, "Unable to smooth pixels.");
     796        psFree(gaussNorm);
     797        psFree(out);
     798        return NULL;
     799    }
     800
     801    if (threaded && !psThreadPoolWait(true)) {
     802        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
     803        psFree(gaussNorm);
     804        psFree(out);
     805        return NULL;
     806    }
     807
     808    psFree(gaussNorm);
     809    return out;
     810}
     811
     812
    680813// Smooth an image with masked pixels
    681814// The calculation and calcMask images are *deliberately* backwards (row,col instead of col,row or
     
    13251458    if (threaded) {
    13261459        int numThreads = psThreadPoolSize(); // Number of threads
    1327         int deltaRows = (numThreads) ? numRows / numThreads : numRows; // Block of rows to do at once
     1460        int deltaRows = (numThreads) ? numRows / numThreads + 1 : numRows; // Block of rows to do at once
    13281461        for (int start = 0; start < numRows; start += deltaRows) {
    1329             int stop = PS_MIN (start + deltaRows, numRows);  // end of row block
     1462            int stop = PS_MIN(start + deltaRows, numRows);  // end of row block
    13301463
    13311464            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
     
    13631496    if (threaded) {
    13641497        int numThreads = psThreadPoolSize(); // Number of threads
    1365         int deltaCols = (numThreads) ? numCols / numThreads : numCols; // Block of cols to do at once
     1498        int deltaCols = (numThreads) ? numCols / numThreads + 1 : numCols; // Block of cols to do at once
    13661499        for (int start = 0; start < numCols; start += deltaCols) {
    1367             int stop = PS_MIN (start + deltaCols, numCols);  // end of col block
     1500            int stop = PS_MIN(start + deltaCols, numCols);  // end of col block
    13681501
    13691502            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
     
    14861619            psFree(task);
    14871620        }
     1621        {
     1622            psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS", 9);
     1623            task->function = &psImageSmoothMaskPixelsThread;
     1624            psThreadTaskAdd(task);
     1625            psFree(task);
     1626        }
    14881627    } else if (!set && threaded) {
    14891628        psThreadTaskRemove("PSLIB_IMAGE_CONVOLVE_MASK");
  • branches/eam_branches/20090715/psLib/src/imageops/psImageConvolve.h

    r24272 r25405  
    222222    );
    223223
     224/// Smooth particular pixels on an image, allowing for masked pixels
     225///
     226/// Applies a circularly symmetric Gaussian smoothing first in x and then in y
     227/// directions with just a vector.  This process is 2N faster than 2D convolutions (in general).
     228psVector *psImageSmoothMaskPixels(
     229    const psImage *image,               ///< Input image (F32)
     230    const psImage *mask,                ///< Mask image
     231    psImageMaskType maskVal,            ///< Value to mask
     232    const psVector *x,                  ///< x coordinates
     233    const psVector *y,                  ///< y coordinates
     234    float sigma,                        ///< Width of the smoothing kernel (pixels)
     235    float numSigma,                     ///< Size of the smoothing box (sigma)
     236    float minGauss                      ///< Minimum fraction of Gaussian to accept
     237    );
    224238
    225239psImage *psImageSmoothMask_Threaded(psImage *output,
  • branches/eam_branches/20090715/psLib/src/sys/psType.h

    r21183 r25405  
    141141} psDataType;
    142142
    143 // macros to abstract the generic mask type : these values must be consistent 
     143// macros to abstract the generic mask type : these values must be consistent
    144144#define PS_TYPE_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
    145145#define PS_TYPE_MASK_DATA U8           /**< the data member to use for mask image */
     
    152152// alternate versions if needed
    153153// #define PS_NOT_MASK(A)(UINT16_MAX-(A))
    154 // #define PS_NOT_MASK(A)(UINT32_MAX-(A)) 
     154// #define PS_NOT_MASK(A)(UINT32_MAX-(A))
    155155// #define PS_NOT_MASK(A)(UINT64_MAX-(A))
    156156
    157 // macros to abstract the vector mask type : these values must be consistent 
     157// macros to abstract the vector mask type : these values must be consistent
    158158#define PS_TYPE_VECTOR_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
    159159#define PS_TYPE_VECTOR_MASK_DATA U8           /**< the data member to use for mask image */
     
    161161#define PS_MIN_VECTOR_MASK_TYPE 0             /**< minimum valid Vector Mask value */
    162162#define PS_MAX_VECTOR_MASK_TYPE UINT8_MAX     /**< maximum valid Vector Mask value */
    163 typedef psU8 psVectorMaskType;                    ///< the C datatype for a mask image
     163typedef psU8 psVectorMaskType;                    ///< the C datatype for a mask image
    164164#define PS_NOT_VECTOR_MASK(A)(UINT8_MAX-(A))
    165165
    166 // macros to abstract the image mask type : these values must be consistent 
    167 #define PS_TYPE_IMAGE_MASK PS_TYPE_U16       /**< the psElemType to use for mask image */
    168 #define PS_TYPE_IMAGE_MASK_DATA U16          /**< the data member to use for mask image */
    169 #define PS_TYPE_IMAGE_MASK_NAME "psU16"      /**< the data type for mask as a string */
     166// macros to abstract the image mask type : these values must be consistent
     167#define PS_TYPE_IMAGE_MASK PS_TYPE_U16       /**< the psElemType to use for mask image */
     168#define PS_TYPE_IMAGE_MASK_DATA U16          /**< the data member to use for mask image */
     169#define PS_TYPE_IMAGE_MASK_NAME "psU16"      /**< the data type for mask as a string */
    170170#define PS_MIN_IMAGE_MASK_TYPE 0             /**< minimum valid Image Mask value */
    171171#define PS_MAX_IMAGE_MASK_TYPE UINT16_MAX    /**< maximum valid Image Mask value */
     
    246246};
    247247
    248 /// Macro to get the bad pixel reason code (stored as part of mask value)
    249 #define PS_BADPIXEL_BITMASK 0x0f
    250 #define PS_GET_BADPIXEL(maskValue) (maskValue & PS_BADPIXEL_BITMASK)
    251 
    252 #define PS_IS_BADPIXEL(maskValue) (PS_GET_BADPIXEL(maskValue) != 0)
    253 
    254 /// Macro to apply a bad pixel reason code to mask image
    255 #define PS_SET_BADPIXEL(maskValue, reasonCode) \
    256 { \
    257     maskValue = (psMaskType)((reasonCode & PS_BADPIXEL_BITMASK) | (maskValue & ~PS_BADPIXEL_BITMASK)); \
    258 }
    259 
    260248/// Macro to determine if the psElemType is an integer.
    261249#define PS_IS_PSELEMTYPE_INT(x) ((x & 0x100) == 0x100)
  • branches/eam_branches/20090715/psLib/src/types/psMetadata.c

    r21183 r25405  
    996996    if (metadataItem->type == PS_DATA_METADATA_MULTI) {
    997997        // if multiple keys found, use the first.
    998         //        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head);
    999998        metadataItem = (psMetadataItem*)(metadataItem->data.list->head->data);
    1000999        if (status) {
     
    10821081    } \
    10831082    \
    1084     /* psFree(metadataItem); currently, the lookup doesn't increment the ref count */ \
    10851083    return value; \
    10861084}
     
    11011099psMetadataLookupNumTYPE(VectorMaskType,VectorMask)
    11021100psMetadataLookupNumTYPE(ImageMaskType,ImageMask)
     1101
     1102#define psMetadataLookupPtrTYPE(TYPENAME,NAME,TYPE,VAL) \
     1103TYPENAME psMetadataLookup##NAME(bool *status, const psMetadata *md, const char *key) \
     1104{ \
     1105    PS_ASSERT_METADATA_NON_NULL(md, NULL); \
     1106    PS_ASSERT_STRING_NON_EMPTY(key, NULL); \
     1107    psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); /* The item of interest */ \
     1108    if (!item) { \
     1109        if (status) { \
     1110            *status = false; \
     1111        } else { \
     1112            psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key); \
     1113        } \
     1114        return NULL; \
     1115    } \
     1116    \
     1117    if (item->type == PS_DATA_METADATA_MULTI) { \
     1118        /* if multiple keys found, use the first. */ \
     1119        item = item->data.list->head->data; \
     1120    } \
     1121    if (item->type != TYPE) { \
     1122        if (status) { \
     1123            *status = false; \
     1124        } else { \
     1125            psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_META, as expected.\n", key); \
     1126        } \
     1127        return NULL; \
     1128    } \
     1129    \
     1130    if (status) { \
     1131        *status = true; \
     1132    } \
     1133    return item->data.VAL; \
     1134}
     1135
     1136psMetadataLookupPtrTYPE(psMetadata*, Metadata, PS_DATA_METADATA, md)
     1137psMetadataLookupPtrTYPE(psString, Str, PS_DATA_STRING, str)
     1138psMetadataLookupPtrTYPE(psTime*, Time, PS_DATA_TIME, V)
     1139psMetadataLookupPtrTYPE(psVector*, Vector, PS_DATA_VECTOR, V)
     1140
    11031141
    11041142psMetadataItem* psMetadataGet(const psMetadata *md,
     
    12571295}
    12581296
    1259 psMetadata *psMetadataLookupMetadata(bool *status,
    1260                                      const psMetadata *md,
    1261                                      const char *key)
    1262 {
    1263     PS_ASSERT_METADATA_NON_NULL(md,NULL);
    1264     psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
    1265     psMetadata *value = NULL;  // The value to return
    1266     if (!item) {
    1267         // The given key isn't in the metadata
    1268         if (status) {
    1269             *status = false;
    1270         } else {
    1271             psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
    1272         }
    1273     } else if (item->type != PS_DATA_METADATA) {
    1274         // The value at the key isn't metadata
    1275         if (status) {
    1276             *status = false;
    1277         } else {
    1278             psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_META, as expected.\n", key);
    1279         }
    1280         //        value = NULL;
    1281     } else {
    1282         // We have the requested metadata
    1283         if (status) {
    1284             *status = true;
    1285         }
    1286         value = item->data.md; // The requested metadata
    1287     }
    1288     return value;
    1289 }
    1290 
    1291 psTime *psMetadataLookupTime(bool *status,
    1292                              const psMetadata *md,
    1293                              const char *key)
    1294 {
    1295     PS_ASSERT_METADATA_NON_NULL(md,NULL);
    1296 
    1297     psMetadataItem *item = psMetadataLookup((psMetadata*)md, key);
    1298     if (!item) {
    1299         // The given key isn't in the metadata
    1300         if (status) {
    1301             *status = false;
    1302         } else {
    1303             psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
    1304         }
    1305         return NULL;
    1306     }
    1307 
    1308     if (item->type != PS_DATA_TIME) {
    1309         // The value at the key isn't metadata
    1310         if (status) {
    1311             *status = false;
    1312         } else {
    1313             psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_TIME, as expected.\n", key);
    1314         }
    1315         return NULL;
    1316     }
    1317 
    1318     // We have the requested metadata
    1319     if (status) {
    1320         *status = true;
    1321     }
    1322 
    1323     return item->data.V;
    1324 }
    1325 
    1326 
    1327 psString psMetadataLookupStr(bool *status,
    1328                              const psMetadata *md,
    1329                              const char *key)
    1330 {
    1331     PS_ASSERT_METADATA_NON_NULL(md,NULL);
    1332 
    1333     psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
    1334     //    char *value = NULL;   // The value to return
    1335     psString value = NULL;
    1336     if (!item) {
    1337         // The given key isn't in the metadata
    1338         if (status) {
    1339             *status = false;
    1340         } else {
    1341             psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
    1342         }
    1343     } else if (item->type != PS_DATA_STRING) {
    1344         // The value at the key isn't of the desired type
    1345         if (status) {
    1346             *status = false;
    1347         } else {
    1348             psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_STRING, as expected.\n", key);
    1349         }
    1350         //        value = NULL;
    1351     } else {
    1352         // We have the requested metadata
    1353         if (status) {
    1354             *status = true;
    1355         }
    1356         value = item->data.V;
    1357     }
    1358     return value;
    1359 }
     1297
     1298
     1299
    13601300
    13611301psList *psMetadataKeys(psMetadata *md)
  • branches/eam_branches/20090715/psLib/src/types/psMetadata.h

    r23148 r25405  
    717717PS_METADATA_LOOKUP_TYPE_DECL(Ptr, psPtr);
    718718PS_METADATA_LOOKUP_TYPE_DECL(Str, psString);
     719PS_METADATA_LOOKUP_TYPE_DECL(Vector, psVector*);
    719720PS_METADATA_LOOKUP_TYPE_DECL(Metadata, psMetadata*);
    720721PS_METADATA_LOOKUP_TYPE_DECL(Time, psTime*);
  • branches/eam_branches/20090715/psLib/src/types/psTree.c

    r18344 r25405  
    1414#include "psTree.h"
    1515
     16//#define INPUT_CHECK                   // Check inputs for functions that may be in a tight loop?
     17
    1618
    1719// XXX Upgrades:
     
    8486}
    8587
    86 psTree *psTreeAlloc(int dim, int maxLeafContents, long numNodes)
     88psTree *psTreeAlloc(int dim, int maxLeafContents, psTreeType type, long numNodes)
    8789{
    8890    psAssert(dim > 0, "Dimensionality (%d) must be positive", dim);
     
    9597    tree->dim = dim;
    9698    tree->maxLeafContents = maxLeafContents;
     99    tree->type = type;
    97100
    98101    tree->numNodes = numNodes;
     
    115118
    116119
    117 psTree *psTreePlant(int dim, int maxLeafContents, ...)
     120psTree *psTreePlant(int dim, int maxLeafContents, psTreeType type, ...)
    118121{
    119122    PS_ASSERT_INT_POSITIVE(dim, NULL);
     
    122125    // Parse coordinate list
    123126    va_list args;                       // Variable argument list
    124     va_start(args, maxLeafContents);
     127    va_start(args, type);
    125128    psArray *coords = psArrayAlloc(dim); // Array of coordinates
    126129    long numData = 0;                   // Number of data points
     
    145148        long pow2;                      // Smallest power of two >= numData
    146149        for (pow2 = 1; pow2 < numData; pow2 <<= 1);
    147         numNodes = PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1);
    148     }
    149 
    150     psTree *tree = psTreeAlloc(dim, maxLeafContents, numNodes);
     150        numNodes = PS_MAX(PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1), 1);
     151    }
     152
     153    psTree *tree = psTreeAlloc(dim, maxLeafContents, type, numNodes);
    151154    tree->data = psTreeCoordArrayAlloc(numData, dim);
    152155    tree->numData = numData;
     
    199202    }
    200203
     204    if (numData <= maxLeafContents) {
     205        // Don't need to do any more work
     206        return tree;
     207    }
     208
    201209    psArray *work = psArrayAlloc(numNodes); // Work queue
    202210    work->data[0] = root;
     
    365373psTreeNode *psTreeLeaf(const psTree *tree, const psVector *coords)
    366374{
    367 #if 1 // Might be in a tight loop
     375#ifdef INPUT_CHECK // Might be in a tight loop
    368376    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    369377    PS_ASSERT_VECTOR_NON_NULL(coords, NULL);
     
    403411{
    404412    int dim = tree->dim;                // Dimensionality
    405     switch (dim) {
    406       case 2:
    407         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    408             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
    409       case 3:
    410         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    411             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
    412             PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
    413       default: {
    414           double distance2 = 0.0;             // Distance of interest
    415           for (int i = 0; i < dim; i++) {
    416               distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     413    switch (tree->type) {
     414      case PS_TREE_EUCLIDEAN:
     415        switch (dim) {
     416          case 2:
     417            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     418                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
     419          case 3:
     420            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     421                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
     422                PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
     423          default: {
     424              double distance2 = 0.0;             // Distance of interest
     425              for (int i = 0; i < dim; i++) {
     426                  distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     427              }
     428              return distance2;
    417429          }
    418           return distance2;
    419       }
    420     }
     430        }
     431        break;
     432      case PS_TREE_SPHERICAL:
     433        switch (dim) {
     434          case 2: {
     435              // Haversine formula
     436              double dphi = coords->data.F64[1] - tree->data->F64[index][1];
     437              double sindphi = sin(dphi / 2.0);
     438              double dlambda = coords->data.F64[0] - tree->data->F64[index][0];
     439              double sindlambda = sin(dlambda / 2.0);
     440              return PS_SQR(sindphi) +
     441                  cos(coords->data.F64[1]) * cos(tree->data->F64[index][1]) * PS_SQR(sindlambda);
     442          }
     443          default:
     444            psAbort("Spherical distances not supported for more than 2 dimensions");
     445        }
     446      default:
     447        psAbort("Unrecognised type: %x", tree->type);
     448    }
     449
    421450    return NAN;
    422451}
     
    430459        double minDiff = tree->min->F64[index][i] - coords->data.F64[i];
    431460        if (minDiff > 0) {
    432             distance += PS_SQR(minDiff);
     461            switch (tree->type) {
     462              case PS_TREE_EUCLIDEAN:
     463                distance += PS_SQR(minDiff);
     464                break;
     465              case PS_TREE_SPHERICAL: {
     466                  double sinDiff = sin(minDiff / 2.0);
     467                  distance += PS_SQR(sinDiff);
     468                  break;
     469              }
     470              default:
     471                psAbort("Unrecognised type: %x", tree->type);
     472            }
    433473            continue;
    434474        }
    435475        double maxDiff = coords->data.F64[i] - tree->max->F64[index][i];
    436476        if (maxDiff > 0) {
    437             distance += PS_SQR(maxDiff);
     477            switch (tree->type) {
     478              case PS_TREE_EUCLIDEAN:
     479                distance += PS_SQR(maxDiff);
     480                break;
     481              case PS_TREE_SPHERICAL: {
     482                  double sinDiff = sin(maxDiff / 2.0);
     483                  distance += PS_SQR(sinDiff);
     484                  break;
     485              }
     486              default:
     487                psAbort("Unrecognised type: %x", tree->type);
     488            }
    438489            continue;
    439490        }
     
    479530}
    480531
    481 // Return the index of the nearest neighbour to given coordinates, within some radius
     532// Return the index of the nearest neighbour to given coordinates, within some distance measure
    482533// This is the engine for psTreeNearest() and psTreeNearestWithin()
    483534static inline long treeNearestWithin(const psTree *tree, // Tree
    484535                                     const psVector *coordinates, // Coordinates of interest
    485                                      double bestDistance // Distance (radius-squared) to best point
     536                                     double bestDistance // Distance measure to best point
    486537    )
    487538{
    488 #if 1 // Might be in a tight loop
     539#ifdef INPUT_CHECK // Might be in a tight loop
    489540    PS_ASSERT_TREE_NON_NULL(tree, -1);
    490541    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    545596
    546597
     598// Convert a radius to our internal "distance measure"
     599// Often, we're given a search radius, but for efficiency reasons, we don't use that internally.
     600static double treeRadiusToDistance(const psTree *tree, double radius)
     601{
     602    switch (tree->type) {
     603      case PS_TREE_EUCLIDEAN:
     604        // Using the square of the distance as the distance measure
     605        return PS_SQR(radius);
     606      case PS_TREE_SPHERICAL: {
     607          // Using a rearrangement of the Haversine formula
     608          double sindist = sin(radius / 2.0);
     609          return PS_SQR(sindist);
     610      }
     611      default:
     612        psAbort("Unrecognised type: %x", tree->type);
     613    }
     614}
     615
     616
    547617long psTreeNearestWithin(const psTree *tree, const psVector *coords, double radius)
    548618{
    549     return treeNearestWithin(tree, coords, PS_SQR(radius));
    550 }
    551 
    552 
    553 // Search a leaf node for points within radius squared
    554 static inline long treeLeafSearchWithin(double radius2, // Radius squared to search
     619    return treeNearestWithin(tree, coords, treeRadiusToDistance(tree, radius));
     620}
     621
     622
     623// Search a leaf node for points within distance
     624static inline long treeLeafSearchWithin(double distance, // Distance to search
    555625                                        const psTree *tree, // Tree of interest
    556626                                        const psTreeNode *leaf, // Leaf to search
     
    561631    for (int i = 0; i < leaf->num; i++) {
    562632        long index = leaf->contents[i]; // Index of point
    563         double distance = treeContentDistance(tree, index, coords); // Distance to point
    564         if (distance < radius2) {
     633        if (treeContentDistance(tree, index, coords) < distance) {
    565634            num++;
    566635        }
     
    572641long psTreeWithin(const psTree *tree, const psVector *coordinates, double radius)
    573642{
    574 #if 1 // Might be in a tight loop
     643#ifdef INPUT_CHECK // Might be in a tight loop
    575644    PS_ASSERT_TREE_NON_NULL(tree, -1);
    576645    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    581650                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    582651
    583     radius *= radius;                   // We work with the radius-squared
     652    double distance = treeRadiusToDistance(tree, radius); // Distance measure
    584653    long num = 0;                       // Number of points in circle
    585654
     
    588657    // Find the closest point in the leaf that contains the point of interest
    589658    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    590     num += treeLeafSearchWithin(radius, tree, leaf, coords);
     659    num += treeLeafSearchWithin(distance, tree, leaf, coords);
    591660
    592661    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    605674            }
    606675            // Leaf node
    607             num += treeLeafSearchWithin(radius, tree, node, coords);
     676            num += treeLeafSearchWithin(distance, tree, node, coords);
    608677            work->data[workIndex] = NULL;
    609678            workIndex--;
     
    618687}
    619688
    620 // Search a leaf node for any points within radius squared
    621 static inline bool treeLeafSearchWithinAny(double radius2, // Radius squared to search
    622                                            const psTree *tree, // Tree of interest
    623                                            const psTreeNode *leaf, // Leaf to search
    624                                            const psVector *coords // Coordinates of interest
     689// Search a leaf node for points within distance
     690static inline void treeLeafSearchAllWithin(psVector *result,       // Result vector
     691                                          double distance, // Distance to search
     692                                          const psTree *tree, // Tree of interest
     693                                          const psTreeNode *leaf, // Leaf to search
     694                                          const psVector *coords // Coordinates of interest
    625695    )
    626696{
    627697    for (int i = 0; i < leaf->num; i++) {
    628698        long index = leaf->contents[i]; // Index of point
    629         double distance = treeContentDistance(tree, index, coords); // Distance to point
    630         if (distance < radius2) {
    631             return true;
    632         }
    633     }
    634     return false;
    635 }
    636 
    637 // Given an arbitrary point and a matching radius, return whether there are any points within that radius
    638 bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
    639 {
    640 #if 1 // Might be in a tight loop
    641     PS_ASSERT_TREE_NON_NULL(tree, false);
    642     PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
    643     PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     699        if (treeContentDistance(tree, index, coords) < distance) {
     700            psVectorAppend(result, index);
     701        }
     702    }
     703    return;
     704}
     705
     706// Given an arbitrary point and a matching radius, return the index of all points within that radius
     707psVector *psTreeAllWithin(const psTree *tree, const psVector *coordinates, double radius)
     708{
     709#ifdef INPUT_CHECK // Might be in a tight loop
     710    PS_ASSERT_TREE_NON_NULL(tree, NULL);
     711    PS_ASSERT_VECTOR_NON_NULL(coordinates, NULL);
     712    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, NULL);
    644713#endif
    645714
     
    647716                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    648717
    649     radius *= radius;                   // We work with the radius-squared
    650 
    651     // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     718    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     719
     720    psVector *result = psVectorAllocEmpty(4, PS_TYPE_S64); // Indices of points within match radius
     721
     722    // This is essentially the same as psTreeNearest, except we're not allowed to prune
    652723
    653724    // Find the closest point in the leaf that contains the point of interest
    654725    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    655     if (treeLeafSearchWithinAny(radius, tree, leaf, coords)) {
    656         psFree(coords);
    657         return true;
    658     }
     726    treeLeafSearchAllWithin(result, distance, tree, leaf, coords);
    659727
    660728    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    673741            }
    674742            // Leaf node
    675             if (treeLeafSearchWithinAny(radius, tree, node, coords)) {
     743            treeLeafSearchAllWithin(result, distance, tree, node, coords);
     744            work->data[workIndex] = NULL;
     745            workIndex--;
     746        }
     747
     748        leaf = up;
     749    }
     750    psFree(work);
     751    psFree(coords);
     752
     753    return result;
     754}
     755
     756// Search a leaf node for any points within distance measure
     757static inline bool treeLeafSearchWithinAny(double distance, // Distance to search
     758                                           const psTree *tree, // Tree of interest
     759                                           const psTreeNode *leaf, // Leaf to search
     760                                           const psVector *coords // Coordinates of interest
     761    )
     762{
     763    for (int i = 0; i < leaf->num; i++) {
     764        long index = leaf->contents[i]; // Index of point
     765        if (treeContentDistance(tree, index, coords) < distance) {
     766            return true;
     767        }
     768    }
     769    return false;
     770}
     771
     772// Given an arbitrary point and a matching radius, return whether there are any points within that radius
     773bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
     774{
     775#ifdef INPUT_CHECK // Might be in a tight loop
     776    PS_ASSERT_TREE_NON_NULL(tree, false);
     777    PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
     778    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     779#endif
     780
     781    psVector *coords = (coordinates->type.type == PS_TYPE_F64 ? psMemIncrRefCounter((psVector*)coordinates) :
     782                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
     783
     784    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     785
     786    // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     787
     788    // Find the closest point in the leaf that contains the point of interest
     789    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
     790    if (treeLeafSearchWithinAny(distance, tree, leaf, coords)) {
     791        psFree(coords);
     792        return true;
     793    }
     794
     795    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     796    while (leaf->up) {
     797        psTreeNode *up = leaf->up;      // Parent node
     798
     799        long workIndex = 0;
     800        work->data[workIndex] = (leaf == up->left ? up->right : up->left); // The other node
     801        while (workIndex >= 0) {
     802            psTreeNode *node = work->data[workIndex];
     803            if (node->left) {
     804                // Branch node
     805                work->data[workIndex] = node->right;
     806                work->data[++workIndex] = node->left;
     807                continue;
     808            }
     809            // Leaf node
     810            if (treeLeafSearchWithinAny(distance, tree, node, coords)) {
    676811                // Clear out the work queue
    677812                memset(work->data, 0, (workIndex + 1) * sizeof(void));
     
    695830psVector *psTreeCoords(psVector *out, const psTree *tree, long index)
    696831{
    697 #if 1 // Might be in a tight loop
     832#ifdef INPUT_CHECK // Might be in a tight loop
    698833    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    699834    PS_ASSERT_INT_NONNEGATIVE(index, NULL);
  • branches/eam_branches/20090715/psLib/src/types/psTree.h

    r19539 r25405  
    1616} psTreeCoordArray;
    1717
     18/// Type of tree
     19///
     20/// Specifies how distances are measured
     21typedef enum {
     22    PS_TREE_EUCLIDEAN,                  // d^2 = dx^2 + dy^2 + ...
     23    PS_TREE_SPHERICAL,                  // sin(dist/2)^2 = sin(dphi/2)^2 + cos(phi1)cos(phi2)sin(dlambda/2)^2
     24} psTreeType;
     25
    1826/// A simple kd-tree implementation
    1927///
     
    2331    int dim;                            ///< Dimensionality
    2432    int maxLeafContents;                ///< Maximum number of points on a leaf
     33    psTreeType type;                    ///< Type of tree
    2534    long numNodes;                      ///< Number of nodes
    2635    long numData;                       ///< Number of data points
     
    6776psTree *psTreeAlloc(int dim,            ///< Dimensionality
    6877                    int maxLeafContents,///< Maximum number of points on a leaf
     78                    psTreeType type,    ///< Type of tree
    6979                    long numNodes       ///< Number of nodes in tree
    7080                    );
     
    7585psTree *psTreePlant(int dim,            ///< Dimensionality
    7686                    int maxLeafContents,///< Maximum number of points on a leaf
     87                    psTreeType type,    ///< Type of tree
    7788                    ...                 ///< psVector for each coordinate
    7889                    );
     
    108119                     );
    109120
     121/// Return the index of all points within some radius of given coordinates
     122psVector *psTreeAllWithin(const psTree *tree,          ///< Tree
     123                          const psVector *coordinates, ///< Coordinates of interest
     124                          double radius                ///< Radius of interest
     125                          );
     126
    110127/// Return the coordinates of a point in the tree, specified by its index
    111128psVector *psTreeCoords(psVector *out,   ///< Output vector, or NULL
  • branches/eam_branches/20090715/psLib/test/optime

    • Property svn:ignore
      •  

        old new  
        22Makefile.in
        33.deps
         4tap_psStatsTiming
  • branches/eam_branches/20090715/psLib/test/types/tap_psTree.c

    r23259 r25405  
    33#include "pstap.h"
    44
    5 #define NUM 10000                       // Number of points
     5#define NUM 1000000                      // Number of points
     6#define SPHERICAL_DISTANCE 3.0          // Distance of interest for spherical test
    67
    78int main(int argc, char *argv[])
    89{
    910    psLibInit(NULL);
    10     plan_tests(6);
     11    plan_tests(13);
    1112
     13    // Euclidean geometry: 6 tests
    1214    {
    1315        psMemId id = psMemGetId();
     
    2325        psFree(rng);
    2426
    25         psTree *tree = psTreePlant(2, 2, x, y);
     27        psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y);
    2628
    2729        ok(tree, "Tree planted");
     
    3537            long closeIndex = psTreeNearest(tree, coords);
    3638            psFree(coords);
    37             ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found point: %ld", closeIndex);
     39            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
    3840
    3941            long bestIndex = -1;
     
    6870    }
    6971
     72    // Spherical geometry: 7 tests
     73    {
     74        psMemId id = psMemGetId();
     75
     76        psVector *ra = psVectorAlloc(NUM, PS_TYPE_F64);
     77        psVector *dec = psVectorAlloc(NUM, PS_TYPE_F64);
     78
     79        psRandom *rng = psRandomAllocSpecific(PS_RANDOM_TAUS, 0);
     80        for (int i = 0; i < NUM; i++) {
     81            // Using http://mathworld.wolfram.com/SpherePointPicking.html
     82            ra->data.F64[i] = psRandomUniform(rng);
     83            dec->data.F64[i] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
     84        }
     85
     86        psTree *tree = psTreePlant(2, 2, PS_TREE_SPHERICAL, ra, dec);
     87
     88        ok(tree, "Tree planted");
     89        skip_start(!tree, 4, "tree died");
     90        {
     91            //            psTreePrint(stderr, tree);
     92
     93            psVector *coords = psVectorAlloc(2, PS_TYPE_F64);
     94            coords->data.F64[0] = psRandomUniform(rng);
     95            coords->data.F64[1] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
     96
     97            psVector *indices = psTreeAllWithin(tree, coords, DEG_TO_RAD(SPHERICAL_DISTANCE));
     98            ok(indices && indices->type.type == PS_TYPE_S64, "got list of indices (%ld points)", indices->n);
     99            long closeIndex = psTreeNearest(tree, coords);
     100            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
     101
     102            ok(psVectorSortInPlace(indices), "sorted indices");
     103
     104            bool allgood = true;        // All points in the appropriate place?
     105            double bestDistance = INFINITY; // Distance to best point
     106            long bestIndex = -1;        // Index of best point
     107            for (long i = 0, j = 0; i < NUM; i++) {
     108#if 1
     109                // Traditional formula
     110                double dist = acos(sin(coords->data.F64[1]) * sin(dec->data.F64[i]) +
     111                                   cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
     112                                   cos(coords->data.F64[0] - ra->data.F64[i]));
     113#else
     114                // Haversine formula: used in psTree
     115                double dphi = coords->data.F64[1] - dec->data.F64[i];
     116                double sindphi = sin(dphi/2.0);
     117                double dlambda = coords->data.F64[0] - ra->data.F64[i];
     118                double sindlambda = sin(dlambda/2.0);
     119                double dist = 2.0 * asin(sqrt(PS_SQR(sindphi) +
     120                                              cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
     121                                              PS_SQR(sindlambda)));
     122#endif
     123                                              if (dist < bestDistance) {
     124                    bestDistance = dist;
     125                    bestIndex = i;
     126                }
     127                if (i == indices->data.S64[j]) {
     128                    j++;
     129                    if (dist > DEG_TO_RAD(SPHERICAL_DISTANCE)) {
     130                        diag("%ld is in the list, but shouldn't be (%lf vs %lf)",
     131                             i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
     132                        allgood = false;
     133                    }
     134                } else if (dist <= DEG_TO_RAD(SPHERICAL_DISTANCE)) {
     135                    diag("%ld is not in the list, but should be (%lf vs %lf)",
     136                         i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
     137                    allgood = false;
     138                }
     139            }
     140            ok(allgood, "list is acurate");
     141            ok(bestIndex == closeIndex, "correct point: %ld vs %ld", closeIndex, bestIndex);
     142
     143            psFree(coords);
     144            psFree(indices);
     145
     146        }
     147        skip_end();
     148
     149        psFree(rng);
     150        psFree(tree);
     151        psFree(ra);
     152        psFree(dec);
     153
     154        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
     155    }
     156
    70157    psLibFinalize();
    71158}
Note: See TracChangeset for help on using the changeset viewer.