IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 7454


Ignore:
Timestamp:
Jun 9, 2006, 12:23:43 PM (20 years ago)
Author:
Paul Price
Message:

Adding FPA mosaicking; generalised some of the chip-specific functions to support multiple calls (as for an FPA with multiple chips). Still need to update the headers. Will rename these files to pmFPAMosaic.[ch] in the near future.

Location:
trunk/psModules/src/camera
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmChipMosaic.c

    r7382 r7454  
    44#include "pmFPA.h"
    55#include "pmHDU.h"
    6 
     6#include "pmChipMosaic.h"
     7
     8#define CELL_LIST_BUFFER 50             // Buffer size for cell lists
    79
    810//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    3335}
    3436
    35 // Are the pixels for the chip contiguous on the HDU?
    36 // Work this out by examining all the CELL.TRIMSEC and CELL.BIASSEC regions for the component cells
    37 static bool chipContiguous(psRegion *bounds, // The bounds of the image, altered if primary==true
    38                            pmChip *chip, // The chip to examine for contiguity
    39                            bool primary // Is this the primary chip of interest?
    40                           )
    41 {
    42     assert(bounds);
     37
     38// Get the bounds for an chip's pixels on the HDU
     39static bool chipBounds(psRegion *bounds, // The bounds for the chip
     40                       const pmChip *chip // The chip to examine for contiguity
     41                      )
     42{
    4343    assert(chip);
    4444
    45     if (primary) {
    46         *bounds = psRegionSet(INFINITY, 0, INFINITY, 0);
    47     }
    4845    psArray *cells = chip->cells;       // The array of cells
    4946    bool mdok = true;                   // Status of MD lookup
     
    5249        psRegion *trimsec = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.TRIMSEC"); // Trim section
    5350        if (!mdok || !trimsec || psRegionIsNaN(*trimsec)) {
    54             psError(PS_ERR_IO, true, "CELL.TRIMSEC hasn't been set for cell %d.\n", i);
     51            psError(PS_ERR_UNKNOWN, true, "CELL.TRIMSEC hasn't been set for cell %d.\n", i);
    5552            return false;
    5653        }
    5754
    58         if (primary) {
    59             if (trimsec->x0 < bounds->x0) {
    60                 bounds->x0 = trimsec->x0;
    61             }
    62             if (trimsec->x1 > bounds->x1) {
    63                 bounds->x1 = trimsec->x1;
    64             }
    65             if (trimsec->y0 < bounds->y0) {
    66                 bounds->y0 = trimsec->y0;
    67             }
    68             if (trimsec->y1 > bounds->y1) {
    69                 bounds->y1 = trimsec->y1;
    70             }
    71         } else if (REGIONS_OVERLAP(trimsec, bounds)) {
     55        if (trimsec->x0 < bounds->x0) {
     56            bounds->x0 = trimsec->x0;
     57        }
     58        if (trimsec->x1 > bounds->x1) {
     59            bounds->x1 = trimsec->x1;
     60        }
     61        if (trimsec->y0 < bounds->y0) {
     62            bounds->y0 = trimsec->y0;
     63        }
     64        if (trimsec->y1 > bounds->y1) {
     65            bounds->y1 = trimsec->y1;
     66        }
     67    }
     68
     69    return true;
     70}
     71
     72// Make sure the TRIMSEC doesn't overlap with the established image bounds
     73static bool chipContiguousTrimsec(psRegion *bounds, // The bounds of the image, altered if primary==true
     74                                  const pmChip *chip // The chip to examine for contiguity
     75                                 )
     76{
     77    assert(bounds);
     78    assert(chip);
     79
     80    psArray *cells = chip->cells;       // The array of cells
     81    bool mdok = true;                   // Status of MD lookup
     82    for (int i = 0; i < cells->n; i++) {
     83        pmCell *cell = cells->data[i];  // Cell of interest
     84        psRegion *trimsec = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.TRIMSEC"); // Trim section
     85        if (!mdok || !trimsec || psRegionIsNaN(*trimsec)) {
     86            psError(PS_ERR_UNKNOWN, true, "CELL.TRIMSEC hasn't been set for cell %d.\n", i);
    7287            return false;
    7388        }
    7489
     90        if (REGIONS_OVERLAP(trimsec, bounds)) {
     91            return false;
     92        }
     93    }
     94
     95    return true;
     96}
     97
     98// Make sure the BIASSEC doesn't overlap with the established image bounds
     99static bool chipContiguousBiassec(psRegion *bounds, // The bounds of the image, altered if primary==true
     100                                  const pmChip *chip // The chip to examine for contiguity
     101                                 )
     102{
     103    assert(bounds);
     104    assert(chip);
     105
     106    // Check that the biases don't get in the way
     107    psArray *cells = chip->cells;       // The array of cells
     108    bool mdok = true;                   // Status of MD lookup
     109    for (int i = 0; i < cells->n; i++) {
     110        pmCell *cell = cells->data[i];  // Cell of interest
    75111        psList *biassecs = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.BIASSEC"); // Bias sections
    76112        if (!mdok || !biassecs) {
    77             psError(PS_ERR_IO, true, "CELL.BIASSEC hasn't been set for cell %d.\n", i);
     113            psError(PS_ERR_UNKNOWN, true, "CELL.BIASSEC hasn't been set for cell %d.\n", i);
    78114            return false;
    79115        }
     
    100136}
    101137
     138// Are the pixels for the FPA contiguous on the HDU?
     139// Work this out by examining all the CELL.TRIMSEC and CELL.BIASSEC regions for the component cells
     140static bool fpaContiguous(psRegion *bounds, // The bounds of the image, returned
     141                          const pmFPA *fpa // The FPA to examine for contiguity
     142                         )
     143{
     144    assert(bounds);
     145    assert(fpa);
     146
     147    *bounds = psRegionSet(INFINITY, 0, INFINITY, 0);
     148
     149    // Get the size of the pixels on the HDU
     150    psArray *chips = fpa->chips;        // The array of chips
     151    for (int i = 0; i < chips->n; i++) {
     152        pmChip *chip = chips->data[i];  // Chip of interest
     153        if (!chipBounds(bounds, chip)) {
     154            return false;
     155        }
     156    }
     157
     158    // Make sure the bias regions don't get in the way of the HDU
     159    for (int i = 0; i < chips->n; i++) {
     160        pmChip *chip = chips->data[i];  // Chip of interest
     161        if (!chipContiguousBiassec(bounds, chip)) {
     162            return false;
     163        }
     164    }
     165
     166    // If we got through it all, they must all be contiguous
     167    return true;
     168}
     169
     170
     171
     172// Check a cell for niceness in the parity and binning
     173static bool niceCellParityBinning(int *xBin, int *yBin, // Binning for cell, to be returned
     174                                  const pmCell *cell // Cell to check for niceness
     175                                 )
     176{
     177    assert(xBin);
     178    assert(yBin);
     179    assert(cell);
     180
     181    // A "nice" cell must have only a single readout
     182    if (cell->readouts->n != 1) {
     183        return false;
     184    }
     185
     186    // A "nice" cell must have parity == 1
     187    bool mdok = true;                   // Status of MD lookup
     188    int xParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY"); // Parity in x
     189    if (!mdok || xParity == 0) {
     190        psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY hasn't been set for cell.\n");
     191        return false;
     192    }
     193    if (xParity != 1) {
     194        return false;
     195    }
     196    int yParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY"); // Parity in y
     197    if (!mdok || yParity == 0) {
     198        psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY hasn't been set for cell.\n");
     199        return false;
     200    }
     201    if (yParity != 1) {
     202        return false;
     203    }
     204
     205    // A "nice" cell must have consistent binning
     206    int xBinCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN"); // Binning in x
     207    if (!mdok || xBin <= 0) {
     208        psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY hasn't been set for cell.\n");
     209        return false;
     210    }
     211    int yBinCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN"); // Binning in y
     212    if (!mdok || yBin <= 0) {
     213        psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY hasn't been set for cell.\n");
     214        return false;
     215    }
     216    if (*xBin == 0 || *yBin == 0) {
     217        *xBin = xBinCell;
     218        *yBin = yBinCell;
     219    } else if (xBinCell != *xBin || yBinCell != *yBin) {
     220        return false;
     221    }
     222
     223    return true;
     224}
     225
     226
     227// Check a cell for niceness in the boundaries
     228static bool niceCellBounds(const pmCell *cell, // Cell to check for niceness
     229                           const psRegion *imageBounds // Bounds of the image on the HDU
     230                          )
     231{
     232    // A "nice" cell must have the (0,0) pixel at CELL.X0,CELL.Y0
     233    bool mdok = true;                   // Status of MD lookup
     234    int x0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0"); // Position of (0,0) on chip
     235    if (!mdok) {
     236        psError(PS_ERR_UNKNOWN, true, "CELL.X0 hasn't been set for cell.\n");
     237        return false;
     238    }
     239    int y0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0"); // Position of (0,0) on chip
     240    if (!mdok) {
     241        psError(PS_ERR_UNKNOWN, true, "CELL.Y0 hasn't been set for cell.\n");
     242        return false;
     243    }
     244    pmReadout *readout = cell->readouts->data[0]; // A representative readout
     245    if (!readout) {
     246        return false;                   // Nothing here
     247    }
     248    if (x0 != readout->col0 + readout->image->col0 - (int)imageBounds->x0 ||
     249            y0 != readout->row0 + readout->image->row0 - (int)imageBounds->y0) {
     250        psTrace(__func__, 5, "CELL.X0,Y0 don't match: %d,%d vs %d,%d\n", x0, y0,
     251                readout->col0 + readout->image->col0 - (int)imageBounds->x0,
     252                readout->row0 + readout->image->row0 - (int)imageBounds->y0);
     253        return false;
     254    }
     255
     256    return true;
     257}
     258
    102259
    103260// Is the chip "nice"?  If so, return the region containing the chip pixels
    104261static psRegion *niceChip(int *xBinChip, int *yBinChip, // Binning for chip, to be returned
    105                           pmChip *chip // Chip to examine for "niceness".
     262                          const pmChip *chip // Chip to examine for "niceness".
    106263                         )
    107264{
     
    116273
    117274    // Check parity and binning for component cells
    118     bool mdok = true;                   // Status of MD lookup
    119275    *xBinChip = 0;
    120276    *yBinChip = 0;
    121277    for (int i = 0; i < chip->cells->n; i++) {
    122278        pmCell *cell = chip->cells->data[i]; // The cell of interest
    123 
    124         // A "nice" chip must have only a single readout
    125         if (cell->readouts->n != 1) {
     279        if (!niceCellParityBinning(xBinChip, yBinChip, cell)) {
    126280            return NULL;
    127281        }
    128 
    129         // A "nice" chip must have parity == 1
    130         int xParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY"); // Parity in x
    131         if (!mdok || xParity == 0) {
    132             psError(PS_ERR_IO, true, "CELL.XPARITY hasn't been set for cell %d.\n", i);
    133             return NULL;
    134         }
    135         if (xParity != 1) {
    136             return NULL;
    137         }
    138         int yParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY"); // Parity in y
    139         if (!mdok || yParity == 0) {
    140             psError(PS_ERR_IO, true, "CELL.YPARITY hasn't been set for cell %d.\n", i);
    141             return NULL;
    142         }
    143         if (yParity != 1) {
    144             return NULL;
    145         }
    146 
    147         // A "nice" chip must have consistent binning
    148         int xBin = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN"); // Binning in x
    149         if (!mdok || xBin <= 0) {
    150             psError(PS_ERR_IO, true, "CELL.XPARITY hasn't been set for cell %d.\n", i);
    151             return NULL;
    152         }
    153         int yBin = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN"); // Binning in y
    154         if (!mdok || yBin <= 0) {
    155             psError(PS_ERR_IO, true, "CELL.YPARITY hasn't been set for cell %d.\n", i);
    156             return NULL;
    157         }
    158         if (*xBinChip == 0 || *yBinChip == 0) {
    159             *xBinChip = xBin;
    160             *yBinChip = yBin;
    161         } else if (xBin != *xBinChip || yBin != *yBinChip) {
    162             return NULL;
    163         }
    164282    }
    165283
    166284    // Now check that the pixels are all contiguous
    167     psRegion *imageBounds = psRegionAlloc(0, 0, 0, 0); // Bound of image on HDU
    168     if (!chipContiguous(imageBounds, chip, true)) {
     285    psRegion *imageBounds = psRegionAlloc(INFINITY, 0, INFINITY, 0); // Bound of image on HDU
     286    if (!chipBounds(imageBounds, chip) || !chipContiguousBiassec(imageBounds, chip)) {
    169287        psTrace(__func__, 5, "Image isn't contiguous.\n");
    170288        psFree(imageBounds);
     
    178296    for (int i = 0; i < chip->cells->n; i++) {
    179297        pmCell *cell = chip->cells->data[i]; // The cell of interest
    180 
    181         // A "nice" chip must have the (0,0) pixel at CELL.X0,CELL.Y0
    182         int x0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0"); // Position of (0,0) on chip
    183         if (!mdok) {
    184             psError(PS_ERR_IO, true, "CELL.X0 hasn't been set for cell %d.\n", i);
    185             return NULL;
    186         }
    187         int y0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0"); // Position of (0,0) on chip
    188         if (!mdok) {
    189             psError(PS_ERR_IO, true, "CELL.Y0 hasn't been set for cell %d.\n", i);
    190             return NULL;
    191         }
    192         pmReadout *readout = cell->readouts->data[0]; // A representative readout
    193         if (!readout) {
    194             return NULL;                // Nothing here
    195         }
    196         if (x0 != readout->col0 + readout->image->col0 - (int)imageBounds->x0 ||
    197                 y0 != readout->row0 + readout->image->row0 - (int)imageBounds->y0) {
    198             psTrace(__func__, 5, "CELL.X0,Y0 don't match: %d,%d vs %d,%d\n", x0, y0,
    199                     readout->col0 + readout->image->col0 - (int)imageBounds->x0,
    200                     readout->row0 + readout->image->row0 - (int)imageBounds->y0);
     298        if (!niceCellBounds(cell, imageBounds)) {
    201299            psFree(imageBounds);
    202300            return NULL;
     
    214312                continue;
    215313            }
    216             if (!chipContiguous(imageBounds, testChip, false)) {
     314            if (!chipContiguousTrimsec(imageBounds, testChip) ||
     315                    !chipContiguousBiassec(imageBounds, testChip)) {
    217316                psTrace(__func__, 5, "Image isn't contiguous.\n");
     317                psFree(imageBounds);
     318                return NULL;
     319            }
     320        }
     321    }
     322
     323    return imageBounds;
     324}
     325
     326// Is the FPA "nice"?  If so, return the region containing the FPA pixels
     327static psRegion *niceFPA(int *xBinFPA, int *yBinFPA, // Binning for FPA, to be returned
     328                         const pmFPA *fpa  // FPA to examine for "niceness".
     329                        )
     330{
     331    assert(xBinFPA);
     332    assert(yBinFPA);
     333    assert(fpa);
     334
     335    // Check that we've got the HDU in the chip or the FPA
     336    if (!fpa->hdu || !fpa->hdu->images) {
     337        return NULL;
     338    }
     339
     340    // Check parity and binning for component cells
     341    *xBinFPA = 0;
     342    *yBinFPA = 0;
     343    for (int i = 0; i < fpa->chips->n; i++) {
     344        pmChip *chip = fpa->chips->data[i]; // The chip of interest
     345        for (int j = 0; i < chip->cells->n; i++) {
     346            pmCell *cell = chip->cells->data[j]; // The cell of interest
     347            if (!niceCellParityBinning(xBinFPA, yBinFPA, cell)) {
     348                return NULL;
     349            }
     350        }
     351    }
     352
     353    // Now check that the pixels are all contiguous
     354    psRegion *imageBounds = psRegionAlloc(0, 0, 0, 0); // Bound of image on HDU
     355    if (!fpaContiguous(imageBounds, fpa)) {
     356        psTrace(__func__, 5, "Image isn't contiguous.\n");
     357        psFree(imageBounds);
     358        return NULL;
     359    }
     360
     361    psString region = psRegionToString(*imageBounds);
     362    psTrace(__func__, 7, "Image bounds: %s\n", region);
     363    psFree(region);
     364
     365    for (int i = 0; i < fpa->chips->n; i++) {
     366        pmChip *chip = fpa->chips->data[i]; // The chip of interest
     367        for (int j = 0; i < chip->cells->n; i++) {
     368            pmCell *cell = chip->cells->data[j]; // The cell of interest
     369            if (!niceCellBounds(cell, imageBounds)) {
    218370                psFree(imageBounds);
    219371                return NULL;
     
    259411    psElemType type = 0;
    260412    int numImages = 0;                  // Number of images
     413    psTrace(__func__, 3, "Mosaicking %ld cells.\n", source->n);
    261414    for (int i = 0; i < source->n; i++) {
    262415        psImage *image = source->data[i]; // The image of interest
     
    315468                xFlip->data.U8[i] == 0 && yFlip->data.U8[i] == 0) {
    316469            // Let someone else do the hard work; useful to test psImageOverlaySection if no other reason
    317             psImageOverlaySection(mosaic, image, x0->data.S32[i], y0->data.S32[i], "+");
     470            psImageOverlaySection(mosaic, image, x0->data.S32[i] - xMin, y0->data.S32[i] - yMin, "+");
    318471        } else {
    319472            // We have to do the hard work ourself
    320473            for (int y = 0; y < image->numRows; y++) {
    321474                int yParity = yFlip->data.U8[i] ? -1 : 1;
    322                 float yTargetBase = (y0->data.S32[i] + yParity * yBinSource->data.S32[i] * y) / yBinTarget;
     475                float yTargetBase = (y0->data.S32[i] + yParity * yBinSource->data.S32[i] * y - yMin) /
     476                                    yBinTarget;
    323477                for (int x = 0; x < image->numCols; x++) {
    324478                    int xParity = xFlip->data.U8[i] ? -1 : 1;
    325                     float xTargetBase = (x0->data.S32[i] + xParity * xBinSource->data.S32[i] * x) /
     479                    float xTargetBase = (x0->data.S32[i] + xParity * xBinSource->data.S32[i] * x - xMin) /
    326480                                        xBinTarget;
    327481
     
    359513// Set the concepts in the new cell, based on the values in the old one
    360514static bool cellConcepts(pmCell *target,// Target cell
    361                          psArray *sources, // Source cells
     515                         psList *sources, // Source cells
    362516                         int xBin, int yBin, // Binning
    363517                         psRegion *trimsec // The trim section
     
    378532    double time      = 0.0;             // Time of observation
    379533    psTimeType timeSys = 0;             // Time system
     534    int readdir      = 0;               // Cell read direction
    380535
    381536    int nCells = 0;                     // Number of cells;
    382     for (int i = 0; i < sources->n; i++) {
    383         pmCell *cell = sources->data[i];// The cell of interest
     537    psListIterator *sourcesIter = psListIteratorAlloc(sources, PS_LIST_HEAD, false); // Iterator for sources
     538    pmCell *cell = NULL;                // Source cell from iteration
     539    while ((cell = psListGetAndIncrement(sourcesIter))) {
    384540        if (!cell) {
    385541            continue;
     
    393549        psTime *cellTime = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TIME");
    394550        time       += psTimeToMJD(cellTime);
    395         if (i == 0) {
     551        if (nCells == 1) {
    396552            timeSys = psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS");
    397         } else if (timeSys != psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS")) {
    398             psLogMsg(__func__, PS_LOG_ERROR, "Differing time systems in use: %d vs %d\n", timeSys,
    399                      psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS"));
    400             success = false;
     553            readdir = psMetadataLookupS32(NULL, cell->concepts, "CELL.READDIR");
     554        } else {
     555            if (timeSys != psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS")) {
     556                psLogMsg(__func__, PS_LOG_ERROR, "Differing time systems in use: %d vs %d\n", timeSys,
     557                         psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS"));
     558                success = false;
     559            }
     560            if (readdir != psMetadataLookupS32(NULL, cell->concepts, "CELL.READDIR")) {
     561                psLogMsg(__func__, PS_LOG_ERROR, "Differing cell read directions in use: %d vs %d\n", readdir,
     562                         psMetadataLookupS32(NULL, cell->concepts, "CELL.READDIR"));
     563                success = false;
     564            }
    401565        }
    402566
     
    410574        }
    411575    }
     576    psFree(sourcesIter);
     577
    412578    gain      /= (float)nCells;
    413579    readnoise /= (float)nCells;
     
    429595    MD_UPDATE(target->concepts, "CELL.XBIN", S32, xBin);
    430596    MD_UPDATE(target->concepts, "CELL.YBIN", S32, yBin);
     597    MD_UPDATE(target->concepts, "CELL.READDIR", S32, readdir);
    431598
    432599    // CELL.TIME needs special care
     
    448615
    449616
     617// Add a cell and its various properties to the arrays
     618static bool addCell(psArray *images,    // Array of images
     619                    psArray *masks,     // Array of masks
     620                    psArray *weights,   // Array of weights
     621                    psVector *x0,       // Array of X0
     622                    psVector *y0,       // Array of Y0
     623                    psVector *xBin,     // Array of XBIN
     624                    psVector *yBin,     // Array of YBIN
     625                    psVector *xFlip,    // Array indicating whether x axis should be flipped
     626                    psVector *yFlip,    // Array indicating whether y axis should be flipped
     627                    const pmCell *cell, // Cell to add
     628                    int *xBinMin,       // The minimum x binning, returned
     629                    int *yBinMin,       // The minimum y binning, returned
     630                    bool chipStuff      // Worry about chip stuff as well?
     631                   )
     632{
     633    if (!cell) {
     634        return false;
     635    }
     636
     637    // Expand the arrays and vectors to handle new data
     638    long index = images->n;               // The index to use
     639    if (images->n == images->nalloc) {
     640        images  = psArrayRealloc(images,  index + CELL_LIST_BUFFER);
     641        masks   = psArrayRealloc(masks,   index + CELL_LIST_BUFFER);
     642        weights = psArrayRealloc(weights, index + CELL_LIST_BUFFER);
     643        x0    = psVectorRealloc(x0,    index+ CELL_LIST_BUFFER);
     644        y0    = psVectorRealloc(y0,    index+ CELL_LIST_BUFFER);
     645        xBin  = psVectorRealloc(xBin,  index+ CELL_LIST_BUFFER);
     646        yBin  = psVectorRealloc(yBin,  index+ CELL_LIST_BUFFER);
     647        xFlip = psVectorRealloc(xFlip, index+ CELL_LIST_BUFFER);
     648        yFlip = psVectorRealloc(yFlip, index+ CELL_LIST_BUFFER);
     649    }
     650
     651    images->n = index + 1;
     652    masks->n = index + 1;
     653    weights->n = index + 1;
     654    x0->n = index + 1;
     655    y0->n = index + 1;
     656    xBin->n = index + 1;
     657    yBin->n = index + 1;
     658    xFlip->n = index + 1;
     659    yFlip->n = index + 1;
     660
     661    bool mdok = true;                   // Status of MD lookup
     662    bool good = true;                   // Is everything good?
     663
     664    // Offset of the cell on the chip
     665    int x0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0");
     666    if (!mdok) {
     667        psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell is not set.\n");
     668        good = false;
     669    }
     670    int y0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0");
     671    if (!mdok) {
     672        psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell is not set.\n");
     673        good = false;
     674    }
     675    psTrace(__func__, 5, "Cell %d: x0=%d y0=%d\n", index, x0Cell, y0Cell);
     676
     677    // Offset of the chip on the FPA
     678    int x0Chip = 0, y0Chip = 0;
     679    if (chipStuff) {
     680        pmChip *chip = cell->parent;    // The parent chip
     681        if (!chip) {
     682            psError(PS_ERR_UNKNOWN, true, "Cell has no parent chip --- can't find CHIP.X0 and CHIP.Y0\n");
     683            good = false;
     684        }
     685        x0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.X0");
     686        if (!mdok) {
     687            psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip is not set.\n");
     688            good = false;
     689        }
     690        y0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.Y0");
     691        if (!mdok) {
     692            psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip is not set.\n");
     693            good = false;
     694        }
     695    }
     696
     697    // Binning
     698    xBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN");
     699    if (!mdok || xBin->data.S32[index] == 0) {
     700        psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell is not set.\n");
     701        good = false;
     702    }
     703    if (xBin->data.S32[index] < *xBinMin) {
     704        *xBinMin = xBin->data.S32[index];
     705    }
     706    yBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN");
     707    if (!mdok || yBin->data.S32[index] == 0) {
     708        psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell is not set.\n");
     709        good = false;
     710    }
     711    if (yBin->data.S32[index] < *yBinMin) {
     712        *yBinMin = yBin->data.S32[index];
     713    }
     714
     715    // Do we need to flip?
     716    int xParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY");
     717    if (!mdok || (xParityCell != 1 && xParityCell != -1)) {
     718        psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell is not set.\n");
     719        good = false;
     720    }
     721    int yParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY");
     722    if (!mdok || (yParityCell != 1 && yParityCell != -1)) {
     723        psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell is not set.\n");
     724        good = false;
     725    }
     726
     727    // Parity of the chip on the FPA
     728    int xParityChip = 0, yParityChip = 0;
     729    if (chipStuff) {
     730        pmChip *chip = cell->parent;    // The parent chip
     731        xParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.XPARITY");
     732        if (!mdok || (xParityChip != 1 && xParityChip != -1)) {
     733            psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip is not set.\n");
     734            good = false;
     735        }
     736        yParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.YPARITY");
     737        if (!mdok || (yParityChip != 1 && yParityChip != -1)) {
     738            psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip is not set.\n");
     739            good = false;
     740        }
     741    }
     742
     743    // Set the flips on the basis of the parity
     744    if (xParityCell * xParityChip == -1) {
     745        xFlip->data.U8[index] = 1;
     746    } else {
     747        xFlip->data.U8[index] = 0;
     748    }
     749    if (yParityCell * yParityChip == -1) {
     750        yFlip->data.U8[index] = 1;
     751    } else {
     752        yFlip->data.U8[index] = 0;
     753    }
     754
     755    x0->data.S32[index] = x0Chip + x0Cell;
     756    y0->data.S32[index] = y0Chip + y0Cell;
     757
     758    // Add the readout to the array of images to be mosaicked
     759    psArray *readouts = cell->readouts; // The array of readouts
     760    if (readouts->n > 1) {
     761        psLogMsg(__func__, PS_LOG_WARN, "Cell contains more than one readout (%ld) --- only the first will "
     762                 "be mosaicked.\n", readouts->n);
     763    }
     764    pmReadout *readout = readouts->data[0]; // The only readout we'll bother with
     765
     766    // The images to put into the mosaic
     767    images->data[index]  = psMemIncrRefCounter(readout->image);
     768    weights->data[index] = psMemIncrRefCounter(readout->weight);
     769    masks->data[index]   = psMemIncrRefCounter(readout->mask);
     770
     771    psTrace(__func__, 9, "Added cell (%x) %ld: %d,%d; %d,%d, %d,%d.\n", cell, index,
     772            x0->data.S32[index], y0->data.S32[index], xBin->data.S32[index], yBin->data.S32[index],
     773            xFlip->data.U8[index], yFlip->data.U8[index]);
     774
     775    return true;
     776}
     777
     778
    450779// Mosaic together the cells in a chip
    451 bool chipMosaic(psImage **mosaicImage, // The mosaic image, to be returned
    452                 psImage **mosaicMask,  // The mosaic mask, to be returned
    453                 psImage **mosaicWeights, // The mosaic weights, to be returned
    454                 int *xBinChip, int *yBinChip, // The binning in x and y, to be returned
    455                 pmChip *chip            // Chip to mosaic
    456                )
     780static bool chipMosaic(psImage **mosaicImage, // The mosaic image, to be returned
     781                       psImage **mosaicMask, // The mosaic mask, to be returned
     782                       psImage **mosaicWeights, // The mosaic weights, to be returned
     783                       int *xBinChip, int *yBinChip, // The binning in x and y, to be returned
     784                       const pmChip *chip // Chip to mosaic
     785                      )
    457786{
    458787    assert(mosaicImage);
     
    461790    assert(chip);
    462791
    463     psArray *cells = chip->cells;       // The array of cells
    464     int numCells = cells->n;            // Number of cells
    465     psArray *images = psArrayAlloc(numCells); // Array of images that will be mosaicked
    466     psArray *weights = psArrayAlloc(numCells); // Array of weight images to be mosaicked
    467     psArray *masks = psArrayAlloc(numCells); // Array of mask images to be mosaicked
    468     psVector *x0 = psVectorAlloc(numCells, PS_TYPE_S32); // Origin x coordinates
    469     psVector *y0 = psVectorAlloc(numCells, PS_TYPE_S32); // Origin y coordinates
    470     psVector *xBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in x
    471     psVector *yBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in y
    472     psVector *xFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Flip in x?
    473     psVector *yFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Flip in y?
    474     images->n = weights->n = masks->n = numCells;
    475     x0->n = y0->n = xBin->n = yBin->n = xFlip->n = yFlip->n = numCells;
     792    psArray *images = psArrayAlloc(0); // Array of images that will be mosaicked
     793    psArray *weights = psArrayAlloc(0); // Array of weight images to be mosaicked
     794    psArray *masks = psArrayAlloc(0); // Array of mask images to be mosaicked
     795    psVector *x0 = psVectorAlloc(0, PS_TYPE_S32); // Origin x coordinates
     796    psVector *y0 = psVectorAlloc(0, PS_TYPE_S32); // Origin y coordinates
     797    psVector *xBin = psVectorAlloc(0, PS_TYPE_S32); // Binning in x
     798    psVector *yBin = psVectorAlloc(0, PS_TYPE_S32); // Binning in y
     799    psVector *xFlip = psVectorAlloc(0, PS_TYPE_U8); // Flip in x?
     800    psVector *yFlip = psVectorAlloc(0, PS_TYPE_U8); // Flip in y?
    476801
    477802    // Binning for the mosaicked chip is the minimum binning allowed by the cells
     
    480805
    481806    // Set up the required inputs
    482     psTrace(__func__, 1, "Mosaicking %d cells...\n", numCells);
    483     bool good = true;                   // Is everything good, well-behaved?
    484     for (int i = 0; i < numCells && good; i++) {
     807    bool allGood = true;                // Is everything good, well-behaved?
     808    psArray *cells = chip->cells;       // The array of cells
     809    for (int i = 0; i < cells->n; i++) {
    485810        pmCell *cell = cells->data[i];  // The cell of interest
    486811        if (!cell) {
    487812            continue;
    488813        }
    489         bool mdok = true;               // Status of MD lookup
    490         x0->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0");
    491         if (!mdok) {
    492             psError(PS_ERR_IO, true, "CELL.X0 for cell %d is not set.\n", i);
    493             good = false;
    494         }
    495         y0->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0");
    496         if (!mdok) {
    497             psError(PS_ERR_IO, true, "CELL.Y0 for cell %d is not set.\n", i);
    498             good = false;
    499         }
    500         psTrace(__func__, 5, "Cell %d: x0=%d y0=%d\n", i, x0->data.S32[i], y0->data.S32[i]);
    501         xBin->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN");
    502         if (!mdok || xBin->data.S32[i] == 0) {
    503             psError(PS_ERR_IO, true, "CELL.XBIN for cell %d is not set.\n", i);
    504             good = false;
    505         }
    506         if (xBin->data.S32[i] < *xBinChip) {
    507             *xBinChip = xBin->data.S32[i];
    508         }
    509         yBin->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN");
    510         if (!mdok || yBin->data.S32[i] == 0) {
    511             psError(PS_ERR_IO, true, "CELL.YBIN for cell %d is not set.\n", i);
    512             good = false;
    513         }
    514         if (yBin->data.S32[i] < *yBinChip) {
    515             *yBinChip = yBin->data.S32[i];
    516         }
    517         int xParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY");
    518         if (!mdok || (xParity != 1 && xParity != -1)) {
    519             psError(PS_ERR_IO, true, "CELL.XPARITY for cell %d is not set.\n", i);
    520             good = false;
    521         }
    522         int yParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY");
    523         if (!mdok || (yParity != 1 && yParity != -1)) {
    524             psError(PS_ERR_IO, true, "CELL.YPARITY for cell %d is not set.\n", i);
    525             good = false;
    526         }
    527         if (xParity == -1) {
    528             xFlip->data.U8[i] = 1;
    529         } else {
    530             xFlip->data.U8[i] = 0;
    531         }
    532         if (yParity == -1) {
    533             yFlip->data.U8[i] = 1;
    534         } else {
    535             yFlip->data.U8[i] = 0;
    536         }
    537 
    538         psArray *readouts = cell->readouts; // The array of readouts
    539         if (readouts->n > 1) {
    540             psLogMsg(__func__, PS_LOG_WARN, "Cell %d contains more than one readout --- only the first will "
    541                      "be mosaicked.\n", i);
    542         }
    543         pmReadout *readout = readouts->data[0]; // The only readout we'll bother with
    544 
    545         // The images to put into the mosaic
    546         images->data[i]  = psMemIncrRefCounter(readout->image);
    547         weights->data[i] = psMemIncrRefCounter(readout->weight);
    548         masks->data[i]   = psMemIncrRefCounter(readout->mask);
     814        allGood |= addCell(images, masks, weights, x0, y0, xBin, yBin, xFlip, yFlip,
     815                           cell, xBinChip, yBinChip, false);
    549816    }
    550817
    551818    // Mosaic the images together and we're done
    552     if (good) {
     819    if (allGood) {
    553820        *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0);
    554821        *mosaicWeights = imageMosaic(weights, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0);
     
    567834    psFree(y0);
    568835
    569     return good;
     836    return allGood;
     837}
     838
     839// Mosaic together the cells in a FPA
     840static bool fpaMosaic(psImage **mosaicImage, // The mosaic image, to be returned
     841                      psImage **mosaicMask, // The mosaic mask, to be returned
     842                      psImage **mosaicWeights, // The mosaic weights, to be returned
     843                      int *xBinFPA, int *yBinFPA, // The binning in x and y, to be returned
     844                      const pmFPA *fpa  // FPA to mosaic
     845                     )
     846{
     847    assert(mosaicImage);
     848    assert(mosaicMask);
     849    assert(mosaicWeights);
     850    assert(fpa);
     851
     852    psArray *images = psArrayAlloc(0); // Array of images that will be mosaicked
     853    psArray *weights = psArrayAlloc(0); // Array of weight images to be mosaicked
     854    psArray *masks = psArrayAlloc(0); // Array of mask images to be mosaicked
     855    psVector *x0 = psVectorAlloc(0, PS_TYPE_S32); // Origin x coordinates
     856    psVector *y0 = psVectorAlloc(0, PS_TYPE_S32); // Origin y coordinates
     857    psVector *xBin = psVectorAlloc(0, PS_TYPE_S32); // Binning in x
     858    psVector *yBin = psVectorAlloc(0, PS_TYPE_S32); // Binning in y
     859    psVector *xFlip = psVectorAlloc(0, PS_TYPE_U8); // Flip in x?
     860    psVector *yFlip = psVectorAlloc(0, PS_TYPE_U8); // Flip in y?
     861
     862    // Binning for the mosaicked chip is the minimum binning allowed by the cells
     863    *xBinFPA = INT_MAX;
     864    *yBinFPA = INT_MAX;
     865
     866    // Set up the required inputs
     867    bool allGood = true;                // Is everything good, well-behaved?
     868    psArray *chips = fpa->chips;        // Array of chips
     869    for (int i = 0; i < chips->n; i++) {
     870        pmChip *chip = chips->data[i];  // The chip of interest
     871        if (!chip) {
     872            continue;
     873        }
     874        psArray *cells = chip->cells;   // The array of cells
     875        for (int j = 0; j < cells->n; j++) {
     876            pmCell *cell = cells->data[j];  // The cell of interest
     877            if (!cell) {
     878                continue;
     879            }
     880            allGood |= addCell(images, masks, weights, x0, y0, xBin, yBin, xFlip, yFlip,
     881                               cell, xBinFPA, yBinFPA, true);
     882        }
     883    }
     884
     885    // Mosaic the images together and we're done
     886    if (allGood) {
     887        *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0);
     888        *mosaicWeights = imageMosaic(weights, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0);
     889        *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0);
     890    }
     891
     892    // Clean up
     893    psFree(images);
     894    psFree(weights);
     895    psFree(masks);
     896    psFree(xFlip);
     897    psFree(yFlip);
     898    psFree(xBin);
     899    psFree(yBin);
     900    psFree(x0);
     901    psFree(y0);
     902
     903    return allGood;
    570904}
    571905
     
    599933// Once the demands of case 1 have been met, or case 2 has been performed, then we can create a cell to hold
    600934// the mosaic image.
    601 bool pmChipMosaic(pmChip *chip      // Chip whose cells will be mosaicked
     935bool pmChipMosaic(pmChip *target,       // Target chip --- may contain only a single cell
     936                  const pmChip *source  // Source chip whose cells will be mosaicked
    602937                 )
    603938{
    604     PS_ASSERT_PTR_NON_NULL(chip, false);
     939    // Target exists, and has only a single cell
     940    PS_ASSERT_PTR_NON_NULL(target, false);
     941    PS_ASSERT_PTR_NON_NULL(target->cells, false);
     942    if (target->cells->n != 1) {
     943        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Target chip for mosaicking must contain a single cell.\n");
     944        return false;
     945    }
     946    pmCell *targetCell = target->cells->data[0]; // The target cell
     947    PS_ASSERT_PTR_NON_NULL(targetCell, false);
     948    // Source exists
     949    PS_ASSERT_PTR_NON_NULL(source, false);
     950
    605951
    606952    psImage *mosaicImage   = NULL;      // The mosaic image
     
    611957    psRegion *chipRegion = NULL;        // Region on the HDU that corresponds to the chip
    612958    int xBin = 0, yBin = 0;             // Binning for the chip mosaic
    613     if ((chipRegion = niceChip(&xBin, &yBin, chip))) {
     959    if ((chipRegion = niceChip(&xBin, &yBin, source))) {
    614960        // Case 1 --- we need only cut out the region
    615961        psTrace(__func__, 1, "Case 1 mosaicking: simple cut-out.\n");
    616         pmHDU *hdu = chip->hdu;         // The HDU that has the pixels
     962        pmHDU *hdu = source->hdu;       // The HDU that has the pixels
    617963        if (!hdu || !hdu->images) {
    618             hdu = chip->parent->hdu;
    619         }
    620         mosaicImage   = psMemIncrRefCounter(psImageSubset(hdu->images->data[0], *chipRegion));
     964            hdu = source->parent->hdu;
     965        }
     966        mosaicImage = psMemIncrRefCounter(psImageSubset(hdu->images->data[0], *chipRegion));
    621967        if (hdu->masks) {
    622             mosaicMask    = psMemIncrRefCounter(psImageSubset(hdu->masks->data[0], *chipRegion));
     968            mosaicMask = psMemIncrRefCounter(psImageSubset(hdu->masks->data[0], *chipRegion));
    623969        }
    624970        if (hdu->weights) {
     
    628974        // Case 2 --- we need to mosaic by cut and paste
    629975        psTrace(__func__, 1, "Case 2 mosaicking: cut and paste.\n");
    630         if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicWeights, &xBin, &yBin, chip)) {
    631             psError(PS_ERR_IO, false, "Unable to mosaic cells.\n");
     976        if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicWeights, &xBin, &yBin, source)) {
     977            psError(PS_ERR_UNKNOWN, false, "Unable to mosaic cells.\n");
    632978            return false;
    633979        }
     
    635981    }
    636982
    637     // Construct a new cell, set the concepts, and add the mosaic in
    638     pmCell *newCell = pmCellAlloc(NULL, "MOSAIC"); // New cell
    639     cellConcepts(newCell, chip->cells, xBin, yBin, chipRegion);
     983    // Set the concepts for the target cell
     984    psList *sourceCells = psArrayToList(source->cells); // List of cells
     985    cellConcepts(targetCell, sourceCells, xBin, yBin, chipRegion);
     986    psFree(sourceCells);
    640987    psFree(chipRegion);
    641     chip->mosaic = (struct pmCell*)newCell;
    642 
    643     // Now make a new readout to go in the new cell
    644     pmReadout *newReadout = pmReadoutAlloc(newCell); // New readout
     988
     989    // Now make a new readout to go in the target cell
     990    pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout
    645991    newReadout->image  = mosaicImage;
    646992    newReadout->mask   = mosaicMask;
     
    650996    return true;
    651997}
     998
     999
     1000// Same deal with the FPA
     1001bool pmFPAMosaic(pmFPA *target,         // Target FPA --- may contain only a single chip with a single cell
     1002                 const pmFPA *source    // FPA whose chips and cells will be mosaicked
     1003                )
     1004{
     1005    // Target exists, and has only a single chip with single cell
     1006    PS_ASSERT_PTR_NON_NULL(target, false);
     1007    PS_ASSERT_PTR_NON_NULL(target->chips, false);
     1008    if (target->chips->n != 1) {
     1009        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Target FPA for mosaicking must contain a single chip.\n");
     1010        return false;
     1011    }
     1012    pmChip *targetChip = target->chips->data[0]; // The target chip
     1013    PS_ASSERT_PTR_NON_NULL(targetChip, false);
     1014    PS_ASSERT_PTR_NON_NULL(targetChip->cells, false);
     1015    if (target->chips->n != 1) {
     1016        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Target FPA for mosaicking must contain a single cell.\n");
     1017        return false;
     1018    }
     1019    pmCell *targetCell = targetChip->cells->data[0]; // The target cell
     1020    PS_ASSERT_PTR_NON_NULL(targetCell, false);
     1021    // Source exists
     1022    PS_ASSERT_PTR_NON_NULL(source, false);
     1023
     1024    psImage *mosaicImage   = NULL;      // The mosaic image
     1025    psImage *mosaicMask    = NULL;      // The mosaic mask
     1026    psImage *mosaicWeights = NULL;      // The mosaic weights
     1027
     1028    // Find the HDU
     1029    psRegion *fpaRegion = NULL;         // Region on the HDU that corresponds to the FPA
     1030    int xBin = 0, yBin = 0;             // Binning for the FPA mosaic
     1031    if ((fpaRegion = niceFPA(&xBin, &yBin, source))) {
     1032        // Case 1 --- we need only cut out the region
     1033        psTrace(__func__, 1, "Case 1 mosaicking: simple cut-out.\n");
     1034        pmHDU *hdu = source->hdu;         // The HDU that has the pixels
     1035        mosaicImage = psMemIncrRefCounter(psImageSubset(hdu->images->data[0], *fpaRegion));
     1036        if (hdu->masks) {
     1037            mosaicMask = psMemIncrRefCounter(psImageSubset(hdu->masks->data[0], *fpaRegion));
     1038        }
     1039        if (hdu->weights) {
     1040            mosaicWeights = psMemIncrRefCounter(psImageSubset(hdu->weights->data[0], *fpaRegion));
     1041        }
     1042    } else {
     1043        // Case 2 --- we need to mosaic by cut and paste
     1044        psTrace(__func__, 1, "Case 2 mosaicking: cut and paste.\n");
     1045        if (!fpaMosaic(&mosaicImage, &mosaicMask, &mosaicWeights, &xBin, &yBin, source)) {
     1046            psError(PS_ERR_UNKNOWN, false, "Unable to mosaic chips.\n");
     1047            return false;
     1048        }
     1049        fpaRegion = psRegionAlloc(NAN, NAN, NAN, NAN); // We've cut and paste, so there's no valid trimsec
     1050    }
     1051
     1052    // Set the concepts for the target cell, and add the mosaic in
     1053    // First we need a list of cells
     1054    psList *sourceCells = psListAlloc(NULL); // List of source cells
     1055    psArray *chips = source->chips;        // Array of chips
     1056    for (long i = 0; i < chips->n; i++) {
     1057        pmChip *chip = chips->data[i];  // Chip of interest
     1058        if (!chip) {
     1059            continue;
     1060        }
     1061        psArray *cells = chip->cells;
     1062        for (long j = 0; j < cells->n; j++) {
     1063            pmCell *cell = cells->data[j]; // Cell of interest
     1064            if (!cell) {
     1065                continue;
     1066            }
     1067            psListAdd(sourceCells, PS_LIST_TAIL, cell);
     1068        }
     1069    }
     1070    cellConcepts(targetCell, sourceCells, xBin, yBin, fpaRegion);
     1071    psFree(sourceCells);
     1072    psFree(fpaRegion);
     1073
     1074    // Now make a new readout to go in the new cell
     1075    pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout
     1076    newReadout->image  = mosaicImage;
     1077    newReadout->mask   = mosaicMask;
     1078    newReadout->weight = mosaicWeights;
     1079    psFree(newReadout);                 // Drop reference
     1080
     1081    return true;
     1082}
     1083
  • trunk/psModules/src/camera/pmChipMosaic.h

    r7017 r7454  
    22#define PM_CHIP_MOSAIC_H
    33
    4 #include "pslib.h"
    54#include "pmFPA.h"
    65
    76// Mosaic all cells within a chip
    8 bool pmChipMosaic(pmChip *chip      // Chip whose cells will be mosaicked
     7bool pmChipMosaic(pmChip *target,       // Target chip --- may contain only a single cell
     8                  const pmChip *source  // Source chip whose cells will be mosaicked
    99                 );
    1010
     11// Mosaic all cells within an FPA
     12bool pmFPAMosaic(pmFPA *target,         // Target FPA --- may contain only a single chip with a single cell
     13                 const pmFPA *source    // FPA whose chips and cells will be mosaicked
     14                );
     15
    1116#endif
Note: See TracChangeset for help on using the changeset viewer.