/*! * \return Number of intervals in object. This is always zero on * error but may also be zero if the object has no intervals. * \ingroup WlzDomainOps * \brief Counts the number of intervals in an object, * where the object type is WLZ_EMPTY_OBJ, * WLZ_2D_DOMAINOBJ or WLZ_3D_DOMAINOBJ. Any other * object type (including compound objects is an * error). * \param obj Given object. * \param dstErr Destination error pointer, may be NULL. */ WlzLong WlzIntervalCountObj(WlzObject *obj, WlzErrorNum *dstErr) { WlzLong iCnt = 0; WlzErrorNum errNum = WLZ_ERR_NONE; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch(obj->type) { case WLZ_EMPTY_OBJ: break; case WLZ_2D_DOMAINOBJ: if(obj->domain.core != NULL) { iCnt = WlzIntervalCount(obj->domain.i, &errNum); } break; case WLZ_3D_DOMAINOBJ: if(obj->domain.core != NULL) { int p, pCnt; WlzPlaneDomain *pDom; pDom = obj->domain.p; pCnt = pDom->lastpl - pDom->plane1; for(p = 0; p <= pCnt; ++p) { WlzDomain dom; dom = pDom->domains[p]; if(dom.core != NULL) { iCnt += WlzIntervalCount(dom.i, &errNum); } } } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if(errNum != WLZ_ERR_NONE) { iCnt = 0; } } if(dstErr) { *dstErr = errNum; } return(iCnt); }
/*! * \ingroup WlzAllocation * \brief Make in interval values table to match the input object The table will have linkcount set to zero. * * \return New interval values table. * \param type Required table type. * \param obj Input object. * \param bckgrnd Values table background value. * \param dstErr Error return. * \par Constraints The woolz object type must resolve to WLZ_GREY_TAB_INTL using WlzGreyTableTypeToTableType()or an error will be reported and NULL returned. For historical reasons the type encodes the table type as well as the grey-value type. * \par Source: * WlzMakeIntervalValues.c */ WlzIntervalValues * WlzMakeIntervalValues(WlzObjectType type, WlzObject *obj, WlzPixelV bckgrnd, WlzErrorNum *dstErr) { WlzValues v; WlzValueIntervalLine *vil; WlzValueLine *val; WlzGreyP g; WlzIntervalWSpace iwsp; WlzIntervalDomain *idom; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the values table type */ v.i = NULL; (void) WlzGreyTableTypeToTableType(type, &errNum); if( errNum == WLZ_ERR_NONE ){ (void) WlzGreyTableTypeToGreyType(type, &errNum); } /* check the object */ if( (errNum == WLZ_ERR_NONE) && (obj == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; break; } idom = obj->domain.i; break; case WLZ_EMPTY_OBJ: default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* * allocate space for basic, per line and per interval structures */ if((errNum == WLZ_ERR_NONE) && ((v.i = (WlzIntervalValues *) AlcCalloc(sizeof(WlzIntervalValues) + (idom->lastln - idom->line1 + 1) * sizeof(WlzValueIntervalLine) + WlzIntervalCount(idom, NULL) * sizeof(WlzValueLine), 1)) == NULL) ){ errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ){ vil = (WlzValueIntervalLine *) (v.i + 1); val = (WlzValueLine *) (vil + idom->lastln - idom->line1 + 1); v.i->bckgrnd = bckgrnd; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: g.inp = (int *) AlcCalloc(WlzArea(obj, NULL), sizeof(int)); break; case WLZ_GREY_SHORT: g.shp = (short *) AlcCalloc(WlzArea(obj, NULL), sizeof(short)); break; case WLZ_GREY_UBYTE: g.ubp = (WlzUByte *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUByte)); break; case WLZ_GREY_FLOAT: g.flp = (float *) AlcCalloc(WlzArea(obj, NULL), sizeof(float)); break; case WLZ_GREY_DOUBLE: g.dbp = (double *) AlcCalloc(WlzArea(obj, NULL), sizeof(double)); break; case WLZ_GREY_RGBA: g.rgbp = (WlzUInt *) AlcCalloc(WlzArea(obj, NULL), sizeof(WlzUInt)); break; default: WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_GREY_TYPE; break; } } if( (errNum == WLZ_ERR_NONE) && (g.inp == NULL) ){ WlzFreeValues( v ); v.i = NULL; errNum = WLZ_ERR_MEM_ALLOC; } /* * fill in structure values and initialise scanning */ if( errNum == WLZ_ERR_NONE ){ v.i->type = type; v.i->freeptr = AlcFreeStackPush(v.i->freeptr, (void *)g.inp, NULL); v.i->line1 = idom->line1; v.i->lastln = idom->lastln; v.i->kol1 = idom->kol1; v.i->width = idom->lastkl - idom->kol1 + 1; v.i->vil = vil; v.i->linkcount = 0; v.i->original_table.core = NULL; vil--; if((errNum = WlzInitRasterScan(obj, &iwsp, WLZ_RASTERDIR_ILIC)) != WLZ_ERR_NONE ){ WlzFreeValues( v ); v.i = NULL; } } /* * fill in the line and interval structures, note grey-type already checked. */ if( errNum == WLZ_ERR_NONE ){ while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE){ if (iwsp.nwlpos != 0) { vil += iwsp.nwlpos; vil->vtbint = val; } vil->nintvs++; val->vkol1 = iwsp.lftpos - v.i->kol1; val->vlastkl = iwsp.rgtpos - v.i->kol1; switch( WlzGreyTableTypeToGreyType(type, NULL) ){ case WLZ_GREY_INT: val->values.inp = g.inp; g.inp += iwsp.colrmn; break; case WLZ_GREY_SHORT: val->values.shp = g.shp; g.shp += iwsp.colrmn; break; case WLZ_GREY_UBYTE: val->values.ubp = g.ubp; g.ubp += iwsp.colrmn; break; case WLZ_GREY_FLOAT: val->values.flp = g.flp; g.flp += iwsp.colrmn; break; case WLZ_GREY_DOUBLE: val->values.dbp = g.dbp; g.dbp += iwsp.colrmn; break; case WLZ_GREY_RGBA: val->values.rgbp = g.rgbp; g.rgbp += iwsp.colrmn; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } val++; } switch( errNum ){ case WLZ_ERR_NONE: case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; break; default: WlzFreeValues( v ); v.i = NULL; break; } } if( dstErr ){ *dstErr = errNum; } return(v.i); }
/*! * \return Transformed object. * \ingroup WlzTransform * \brief Transform an object using the given view-transform. * Typically this is for mapping section data back into * the 3D space of the reference image/reconstruction. * \param srcObj Given source object. * \param viewStr Given view transform. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *Wlz3DViewTransformObj( WlzObject *srcObj, WlzThreeDViewStruct *viewStr, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; AlcErrno alcErr = ALC_ER_NONE; WlzObject *dstObj=NULL; int area; int i, k, p, xp, yp, line; int plane1, lastpl, line1, lastln, kol1, lastkl; WlzIVertex3 *vertices; int numVtxs, vtxIdx; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzDomain domain, tmpDomain; WlzValues values; int numInts, itvlFlg; WlzInterval *itvl; /* check the object */ if( srcObj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ) { case WLZ_2D_DOMAINOBJ: if( srcObj->domain.core == NULL ) { errNum = WLZ_ERR_DOMAIN_NULL; } area = WlzArea(srcObj, &errNum); if( area == 0 ) { dstObj = WlzMakeEmpty(&errNum); } break; case WLZ_2D_POLYGON: /* to be done at some time to 3D polyline */ case WLZ_BOUNDLIST: /* convert to 3D polylines */ case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* create the voxel list */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { numVtxs = sizeof(WlzIVertex3) * (area+4); vertices = AlcMalloc(sizeof(WlzIVertex3) * (area+4)); numVtxs = 0; if( vertices ) { errNum = WlzInitRasterScan(srcObj, &iwsp, WLZ_RASTERDIR_ILIC); } else { errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ) { while( (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE ) { float x, y, z; if((iwsp.linpos < (int) viewStr->minvals.vtY) || (iwsp.linpos > (int) viewStr->maxvals.vtY)) { continue; } yp = iwsp.linpos - (int) viewStr->minvals.vtY; for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++) { if((k < (int) viewStr->minvals.vtX) || (k > (int) viewStr->maxvals.vtX)) { continue; } xp = k - (int) viewStr->minvals.vtX; x = (float )(viewStr->xp_to_x[xp] + viewStr->yp_to_x[yp]); y = (float )(viewStr->xp_to_y[xp] + viewStr->yp_to_y[yp]); z = (float )(viewStr->xp_to_z[xp] + viewStr->yp_to_z[yp]); vertices[numVtxs].vtX = WLZ_NINT(x); vertices[numVtxs].vtY = WLZ_NINT(y); vertices[numVtxs].vtZ = WLZ_NINT(z); numVtxs++; } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } } } /* sort wrt planes, lines, kols */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { qsort((void *) vertices, (size_t) numVtxs, sizeof(WlzIVertex3), compareVtxVal); /* create planedomain */ plane1 = vertices[0].vtZ; lastpl = vertices[numVtxs - 1].vtZ; line1 = vertices[0].vtY; lastln = line1; kol1 = vertices[0].vtX; lastkl = kol1; for(i=1; i < numVtxs; i++) { if( kol1 > vertices[i].vtX ) { kol1 = vertices[i].vtX; } if( lastkl < vertices[i].vtX ) { lastkl = vertices[i].vtX; } if( line1 > vertices[i].vtY ) { line1 = vertices[i].vtY; } if( lastln < vertices[i].vtY ) { lastln = vertices[i].vtY; } } if( (domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, line1, lastln, kol1, lastkl, &errNum)) == NULL ) { AlcFree((void *) vertices); } } /* for each plane count intervals and make domain */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { vtxIdx = 0; for(p=plane1; p <= lastpl; p++) { /* increment vertex index to current plane */ while( vertices[vtxIdx].vtZ < p ) { vtxIdx++; } /* check for empty domain */ if( vertices[vtxIdx].vtZ > p ) { domain.p->domains[p - plane1].i = NULL; continue; } /* estimate intervals - foreach pixel add one, foreach adjacent pixel on the same line subtract one */ numInts = 1; kol1 = vertices[vtxIdx].vtX; lastkl = kol1; for(i=vtxIdx+1; i < numVtxs; i++) { if( vertices[i].vtZ > p ) { break; } numInts++; if((vertices[i].vtY == vertices[i-1].vtY) && ((vertices[i].vtX == (vertices[i-1].vtX)) || (vertices[i].vtX == (vertices[i-1].vtX + 1)) )) { numInts--; } if(kol1 > vertices[i].vtX) { kol1 = vertices[i].vtX; } if(lastkl < vertices[i].vtX) { lastkl = vertices[i].vtX; } } line1 = vertices[vtxIdx].vtY; lastln = vertices[i-1].vtY; /* make the domain and add the intervals pointer */ tmpDomain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, kol1, lastkl, &errNum); itvl = (WlzInterval *) AlcMalloc(sizeof(WlzInterval)*numInts); tmpDomain.i->freeptr = AlcFreeStackPush(tmpDomain.i->freeptr, (void *) itvl, &alcErr); if(alcErr != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; } /* one more loop to add the intervals */ itvl->ileft = vertices[vtxIdx].vtX - kol1; line = vertices[vtxIdx].vtY; itvlFlg = 1; /* interval started */ numInts = 1; for(i=vtxIdx+1; i < numVtxs; i++) { /* new plane -> interval finished if started */ if( vertices[i].vtZ > p ) { if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvlFlg = 0; /* interval finished */ numInts = 0; } break; } /* check if new interval */ if( !itvlFlg ) { itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; continue; /* no further tests */ } /* check for gap - increment interval count */ if((vertices[i].vtY == line) && ((vertices[i].vtX - vertices[i-1].vtX) > 1)) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; numInts++; itvl[numInts-1].ileft = vertices[i].vtX - kol1; itvlFlg = 1; } /* check for new-line */ if( line < vertices[i].vtY ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; } } /* complete the last interval */ if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; } /* add the domain to the planedomain */ domain.p->domains[p - plane1] = WlzAssignDomain(tmpDomain, &errNum); (void) WlzIntervalCount(tmpDomain.i, 0); } } /* create the new object */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { values.core = NULL; dstObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } /* check for grey-level data */ if((errNum == WLZ_ERR_NONE) && dstObj && (dstObj->type != WLZ_EMPTY_OBJ) && srcObj->values.core ) { WlzPixelV bckgrnd; WlzObject *tmpObj; WlzValues tmpValues; WlzDVertex3 vtx; WlzGreyValueWSpace *gVWSp = NULL; WlzObjectType valueTbType; /* explicit intialisation to satisfy strict ANSI on SGI */ bckgrnd = WlzGetBackground(srcObj, &errNum); valueTbType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, bckgrnd.type, NULL); /* make a voxel table */ values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bckgrnd, NULL, &errNum); dstObj->values = WlzAssignValues(values, &errNum); /* set up grey-value random access to original and loop through planes setting values */ gVWSp = WlzGreyValueMakeWSp(srcObj, NULL); for(p=plane1; p <= lastpl; p++) { /* check for empty domain */ if( domain.p->domains[p-plane1].core == NULL ) { continue; } /* make a value table */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain.p->domains[p-plane1], values.vox->values[p-plane1], NULL, NULL, &errNum); tmpValues.v = WlzNewValueTb(tmpObj, valueTbType, bckgrnd, &errNum); values.vox->values[p-plane1] = WlzAssignValues(tmpValues, &errNum); tmpObj->values = WlzAssignValues(tmpValues, &errNum); /* transfer values */ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { for(i=0; i<iwsp.colrmn; i++) { vtx.vtX = iwsp.colpos + i; vtx.vtY = iwsp.linpos; vtx.vtZ = p; Wlz3DSectionTransformVtx(&vtx, viewStr); WlzGreyValueGet(gVWSp, 0.0, WLZ_NINT(vtx.vtY), WLZ_NINT(vtx.vtX)); switch( gwsp.pixeltype ) { case WLZ_GREY_LONG: *(gwsp.u_grintptr.lnp+i) = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: *(gwsp.u_grintptr.inp+i) = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: *(gwsp.u_grintptr.shp+i) = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: *(gwsp.u_grintptr.ubp+i) = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *(gwsp.u_grintptr.flp+i) = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *(gwsp.u_grintptr.dbp+i) = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: *(gwsp.u_grintptr.rgbp+i) = gVWSp->gVal[0].rgbv; break; case WLZ_GREY_BIT: /* not sure what to do with these */ default: break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } WlzFreeObj(tmpObj); } WlzGreyValueFreeWSp(gVWSp); } /* clean temp allocation */ if( vertices ) { AlcFree((void *) vertices); } if( dstErr ) { *dstErr = errNum; } return dstObj; }
/*! * \return Rescaled object. * \ingroup WlzTransform * \brief Rescales the given 2D domain object using an integer scale. * \param obj Given object. * \param scale Integer scale factor. * \param expand If zero use \f$\frac{1}{scale}\f$. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzIntRescaleObj2D( WlzObject *obj, int scale, int expand, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzDomain domain; WlzValues values; WlzInterval *intvls; int k1, kl, l1, ll, l, num_intvls; WlzErrorNum errNum=WLZ_ERR_NONE; /* check expand or contract */ if( expand ) { k1 = obj->domain.i->kol1 * scale; kl = obj->domain.i->lastkl * scale + scale - 1; l1 = obj->domain.i->line1 * scale; ll = obj->domain.i->lastln * scale + scale - 1; } else { k1 = obj->domain.i->kol1 / scale; kl = obj->domain.i->lastkl / scale; l1 = obj->domain.i->line1 / scale; ll = obj->domain.i->lastln / scale; } /* create a new object */ if((domain.i = WlzMakeIntervalDomain(obj->domain.i->type, l1, ll, k1, kl, &errNum)) != NULL){ values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, NULL); } /* fill in the intervals */ if( errNum == WLZ_ERR_NONE){ if( domain.i->type == WLZ_INTERVALDOMAIN_INTVL ) { int intvline_offset, max_offset; WlzIntervalLine *intvline; num_intvls = WlzIntervalCount(obj->domain.i, NULL); num_intvls = expand ? num_intvls * scale : num_intvls; intvls = (WlzInterval *)AlcMalloc(sizeof(WlzInterval) * num_intvls); domain.i->freeptr = AlcFreeStackPush(domain.i->freeptr, (void *)intvls, NULL); max_offset = obj->domain.i->lastln - obj->domain.i->line1; for(l=l1; l <= ll; l++) { int i; intvline_offset = (expand?l/scale:l*scale) - obj->domain.i->line1; intvline_offset = WLZ_MAX(intvline_offset, 0); intvline_offset = WLZ_MIN(intvline_offset, max_offset); intvline = obj->domain.i->intvlines + intvline_offset; for(i=0; i < intvline->nintvs; i++) { intvls[i].ileft = (intvline->intvs + i)->ileft; intvls[i].iright = (intvline->intvs + i)->iright; if( expand ) { intvls[i].ileft *= scale; intvls[i].iright *= scale; intvls[i].iright += scale - 1; } else { intvls[i].ileft /= scale; intvls[i].iright /= scale; } } i = check_intvs(intvls, i); WlzMakeInterval(l, domain.i, i, intvls); intvls += i; } (void) WlzStandardIntervalDomain( domain.i ); } } /* create the valuetable */ if( (errNum == WLZ_ERR_NONE) && obj->values.core ) { WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzPixelV backgrnd; WlzGreyValueWSpace *gVWSp = NULL; WlzGreyType gtype; backgrnd = WlzGetBackground(obj, NULL); if((values.v = WlzNewValueTb(rtnObj, obj->values.v->type, backgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); /* fill in the grey-values */ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.v->type, NULL); } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE) { int k; int lp = expand ? iwsp.linpos/scale : iwsp.linpos*scale; for( k=0; k <= (iwsp.rgtpos - iwsp.lftpos); k++ ) { int kp = expand ? (k+iwsp.lftpos)/scale : (k+iwsp.lftpos)*scale; WlzGreyValueGet(gVWSp, 0, (double) lp, (double) kp); switch(gtype) { case WLZ_GREY_INT: gwsp.u_grintptr.inp[k] = (*(gVWSp->gVal)).inv; break; case WLZ_GREY_SHORT: gwsp.u_grintptr.shp[k] = (*(gVWSp->gVal)).shv; break; case WLZ_GREY_UBYTE: gwsp.u_grintptr.ubp[k] = (*(gVWSp->gVal)).ubv; break; case WLZ_GREY_FLOAT: gwsp.u_grintptr.flp[k] = (*(gVWSp->gVal)).flv; break; case WLZ_GREY_DOUBLE: gwsp.u_grintptr.dbp[k] = (*(gVWSp->gVal)).dbv; break; case WLZ_GREY_RGBA: gwsp.u_grintptr.rgbp[k] = (*(gVWSp->gVal)).rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); (void )WlzEndGreyScan(&iwsp, &gwsp); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return Object with domain equal to the set difference between the * first and second object, with valuetable from the first * object. * \ingroup WlzDomainOps * \brief Calculates the domain difference between two objects. * \param obj1 First object. * \param obj2 Second object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDiffDomain( WlzObject *obj1, WlzObject *obj2, WlzErrorNum *dstErr) { WlzIntervalWSpace iwsp2, iwsp1; WlzInterval *intp; WlzInterval *jntp; WlzDomain diffdom; WlzValues values; WlzIntervalDomain *idom1; int k1, dfinished, intervalcount; WlzObject *diff=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; diffdom.core = NULL; /* check object 1 */ if( obj1 == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj1->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if( obj1->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: diffdom.i = NULL; values.v = NULL; return WlzMakeMain(WLZ_EMPTY_OBJ, diffdom, values, NULL, NULL, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check object 2 - obj2 == NULL is now an error */ if( (errNum == WLZ_ERR_NONE) && (obj2 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj2->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if( obj2->type != obj1->type ){ errNum = WLZ_ERR_OBJECT_TYPE; break; } if( obj2->domain.core == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; break; } break; case WLZ_EMPTY_OBJ: return WlzMakeMain(obj1->type, obj1->domain, obj1->values, NULL, NULL, dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* switch for 3D objects */ if( (errNum == WLZ_ERR_NONE) && (obj1->type == WLZ_3D_DOMAINOBJ) ){ return WlzDiffDomain3d( obj1, obj2, dstErr ); } /* * make a new interval table that is big enough */ if( errNum == WLZ_ERR_NONE ){ idom1 = obj1->domain.i; k1 = idom1->kol1; if( (intp = (WlzInterval *) AlcCalloc(WlzIntervalCount(idom1, NULL) + WlzIntervalCount(obj2->domain.i, NULL), sizeof(WlzInterval))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } jntp = intp; } if( errNum == WLZ_ERR_NONE ){ if( (diffdom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, idom1->line1, idom1->lastln, k1, idom1->lastkl, &errNum)) == NULL ){ AlcFree((void *) intp); } else { diffdom.i->freeptr = AlcFreeStackPush(diffdom.i->freeptr, (void *)intp, NULL); } } if( errNum == WLZ_ERR_NONE ){ if( (diff = WlzMakeMain(WLZ_2D_DOMAINOBJ, diffdom, obj1->values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain(diffdom.i); } } /* * initialise interval scanning */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitRasterScan(obj1, &iwsp1, WLZ_RASTERDIR_ILIC); } if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitRasterScan(obj2, &iwsp2, WLZ_RASTERDIR_ILIC); dfinished = 0; intervalcount = 0; } /* * scan object constructing intervals after subtraction of obj2 */ if( (errNum == WLZ_ERR_NONE) && ((errNum = WlzNextInterval(&iwsp2)) == WLZ_ERR_NONE) ){ while( (errNum = WlzNextInterval(&iwsp1)) == WLZ_ERR_NONE ){ /* * case 1 - interval in obj1 succedes interval in obj2 - * get next interval of obj2 */ while( (errNum == WLZ_ERR_NONE) && (dfinished == 0) && (iwsp1.linpos > iwsp2.linpos || (iwsp1.linpos == iwsp2.linpos && iwsp1.lftpos > iwsp2.rgtpos))){ switch( errNum = WlzNextInterval(&iwsp2) ){ case WLZ_ERR_NONE: dfinished = 0; break; case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; dfinished = 1; break; default: break; } } if( errNum != WLZ_ERR_NONE ){ break; } /* * case 2 - interval in obj1 precedes interval in obj2 * or obj2 finished - just copy interval */ if( (dfinished != 0) || (iwsp1.linpos < iwsp2.linpos || ((iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos < iwsp2.lftpos)) ) ){ jntp->ileft = iwsp1.lftpos - k1; jntp->iright = iwsp1.rgtpos - k1; intervalcount++; jntp++; } /* * case 3 - intervals overlap. * there may be more than one obj2 interval. */ else { /* * test left end of obj1 interval < left * end of obj2 interval, when complete * interval can be constructed immediately */ if (iwsp2.lftpos > iwsp1.lftpos) { jntp->ileft = iwsp1.lftpos - k1; jntp->iright = iwsp2.lftpos -1 - k1; intervalcount++; jntp++; } do { /* * if right end of obj2 interval < * right end of obj1 interval can * plant left end of new interval */ if (iwsp2.rgtpos < iwsp1.rgtpos) { jntp->ileft = iwsp2.rgtpos +1 - k1; switch( errNum = WlzNextInterval(&iwsp2) ){ case WLZ_ERR_NONE: dfinished = 0; break; case WLZ_ERR_EOO: errNum = WLZ_ERR_NONE; dfinished = 1; break; default: break; } if( errNum != WLZ_ERR_NONE ){ break; } /* * check if next obj2 interval * still overlaps this obj1 interval */ if( (dfinished == 0) && (iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos >= iwsp2.lftpos)) jntp->iright = iwsp2.lftpos -1 -k1; else jntp->iright = iwsp1.rgtpos - k1; intervalcount++; jntp++; } } while( (dfinished == 0) && (iwsp1.linpos == iwsp2.linpos) && (iwsp1.rgtpos > iwsp2.rgtpos) ); } if( errNum != WLZ_ERR_NONE ){ break; } /* * is this obj1 interval the last in the line ? * if so, load up the new intervals into the * diff domain. */ if (iwsp1.intrmn == 0) { errNum = WlzMakeInterval(iwsp1.linpos, diffdom.i, intervalcount, intp); intervalcount = 0; intp = jntp; } if( errNum != WLZ_ERR_NONE ){ break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } /* this checks the area and returns NULL if zero in principle it should return an "empty object" */ if(errNum == WLZ_ERR_NONE) { if(WlzIntervalCount(diffdom.i, NULL) == 0){ WlzFreeObj(diff); diffdom.i = NULL; values.v = NULL; diff = WlzMakeEmpty(&errNum); } else { WlzStandardIntervalDomain(diff->domain.i); } } else { WlzFreeObj(diff); diff = NULL; } if( dstErr ){ *dstErr = errNum; } return diff; }
/*! * \ingroup WlzBinaryOps * \brief Calculate the set union of an array of domain objects. Domians only unless uvt non-zero in which case make an average grey table. Note background values are used in the averaging process. All objects must be domain objects of the same type (2D or 3D) unless WLZ_EMPTY_OBJ, NULL input objects are an error. This function may modify the order of the objects in the array it is passed if the array contains empty objects. * * \return Union of the array of object. * \param n number of input objects * \param objs input object array * \param uvt grey-table copy flag, copy if non-zero. * \param dstErr error return. * \par Source: * WlzUnionN.c */ WlzObject *WlzUnionN( int n, WlzObject **objs, int uvt, WlzErrorNum *dstErr) { WlzObject *obj=NULL; WlzDomain domain; WlzValues values; WlzIntervalDomain *idom; WlzInterval *itvl, *jtvl; WlzIntervalWSpace *iwsp; WlzIntervalWSpace *biwsp, *tiwsp, niwsp; WlzGreyWSpace *gwsp, ngwsp; WlzObjectType type; int i, j, k, l; int inttot, numactive, change, lwas, nints, noverlap; WlzPixelV backg; int line1, lastln; int kol1,lastkl; WlzGreyV gv; WlzGreyP greyptr; int **locbuff; int *locbuffs; int span; WlzErrorNum errNum=WLZ_ERR_NONE; /* preliminary stuff - count of non-NULL objects, note WLZ_EMPTY_OBJs are ignored but NULL objects are an error */ if( n < 1 ){ errNum = WLZ_ERR_PARAM_DATA; } else { for (i=0; i<n ; i++ ){ if ( objs[i] == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; break; } if( objs[i]->type == WLZ_EMPTY_OBJ ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } /* n has been checked therefore no objects implies all empty */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } /* now check they are all of the same type */ if( errNum == WLZ_ERR_NONE ){ for(i=1; i < n; i++){ if( objs[i]->type != objs[0]->type ){ errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now test the type note empty objects have been discarded */ if( errNum == WLZ_ERR_NONE ){ switch( objs[0]->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: return WlzUnion3d(n, objs, uvt, dstErr); case WLZ_TRANS_OBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* now discard empty objects */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( WlzIsEmpty(objs[i], NULL) ){ obj = objs[i]; for ( j=i; j<n-1 ; j++ ){ objs[j] = objs[j+1]; } objs[n-1] = obj; n--; i--; } } } obj = NULL; /* recheck number of objects */ if( (errNum == WLZ_ERR_NONE) && (n < 1) ){ return WlzMakeEmpty(dstErr); } if( (errNum == WLZ_ERR_NONE) && (n == 1) ){ return WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values, NULL, NULL, dstErr); } /* check if grey-value merge is possible */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n ; i++ ){ if( objs[i]->values.core == NULL ){ uvt = 0; break; } } } /* * find the line and column bounds of the union. */ if( errNum == WLZ_ERR_NONE ){ line1 = objs[0]->domain.i->line1; lastln = objs[0]->domain.i->lastln; kol1 = objs[0]->domain.i->kol1; lastkl = objs[0]->domain.i->lastkl; for (i=1; i<n; i++) { idom = objs[i]->domain.i; if (line1 > idom->line1) line1 = idom->line1; if (lastln < idom->lastln) lastln = idom->lastln; if (kol1 > idom->kol1) kol1 = idom->kol1; if (lastkl < idom->lastkl) lastkl = idom->lastkl; } span = lastkl - kol1 +1 ; if( (locbuff = (int **) AlcMalloc((n+1)*sizeof(int *))) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } } /* space must be allocated for the largest variety of grey-value */ if( errNum == WLZ_ERR_NONE ){ if( (locbuffs = (int *) AlcMalloc(sizeof(double)*span*(n+1))) == NULL ){ AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; } else { for(i=0; i <= n; i++){ locbuff[i] = locbuffs + i*span; } } } /* * count the individual intervals so that sufficient space * for the union may be allocated. */ if( errNum == WLZ_ERR_NONE ){ inttot=0; for(i=0; i < n; i++){ inttot += WlzIntervalCount(objs[i]->domain.i, &errNum); } } /* * set up domain, value table structures, and object. */ if( errNum == WLZ_ERR_NONE ){ if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1,lastln,kol1,lastkl, &errNum)) == NULL ){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); } else if( (itvl = (WlzInterval *) AlcMalloc(inttot * sizeof(WlzInterval))) == NULL){ AlcFree((void *) locbuffs); AlcFree((void *) locbuff); WlzFreeIntervalDomain(idom); errNum = WLZ_ERR_MEM_ALLOC; } else { idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL); lwas = line1; jtvl = itvl; nints = 0; domain.i = idom; values.v = NULL; if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain( idom ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); return(NULL); } } } /* * allocate space for workspaces */ if( errNum == WLZ_ERR_NONE ){ if( (iwsp = (WlzIntervalWSpace *) AlcMalloc (n * sizeof (WlzIntervalWSpace))) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } else { biwsp = iwsp; tiwsp = iwsp + n; } } /* * Construct the union object's table of intervals. * Initialise scanning on each object/workspace combination. * Scan synchronously, setting up the union of adjacent and * overlapping intervals. Needs a clear head !! */ if( errNum == WLZ_ERR_NONE ){ for (i=0; i<n; i++) { WlzInitRasterScan(objs[i], iwsp, WLZ_RASTERDIR_ILIC); WlzNextInterval(iwsp++); } numactive = n; /* * find next line and left hand end of next interval of union */ while (numactive > 0) { /* * find first remaining active object */ iwsp = biwsp; while( iwsp->linrmn < 0 ){ iwsp++; } /* * find minimum line number of remaining active intervals */ l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; for (iwsp++; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos < l) { l = iwsp->linpos; kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * find left-most interval in this line */ for (iwsp=biwsp; iwsp<tiwsp; iwsp++) if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos < kol1) { kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } /* * construct maximal interval with current left end-point */ do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while( iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= lastkl+1 ){ if (iwsp->rgtpos > lastkl) { lastkl = iwsp->rgtpos; change = 1; } if (WlzNextInterval(iwsp) != WLZ_ERR_NONE) { numactive--; } } } } while (change == 1); itvl->ileft = kol1 - idom->kol1; itvl->iright = lastkl - idom->kol1; if (l == lwas) nints++; else { (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<l; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } lwas = l; nints = 1; jtvl = itvl; } itvl++; } (void) WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; j<=lastln; j++) { (void) WlzMakeInterval(j,idom,0,NULL); } } /* now deal with the grey-values if required */ if( (errNum == WLZ_ERR_NONE) && (uvt != 0) ){ WlzGreyType grey_type; if( (gwsp = (WlzGreyWSpace *) AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); errNum = WLZ_ERR_MEM_ALLOC; obj = NULL; } /* construct an empty "ragged-rectangle" greytable with appropriate grey-type */ if( errNum == WLZ_ERR_NONE ){ backg = WlzGetBackground(objs[0], NULL); grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type, NULL); type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, NULL); if( (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); obj = NULL; } else { obj->values = WlzAssignValues(values, NULL); } } /* fill the grey table. Where more than one input objects overlap, take mean of grey values. */ if( errNum == WLZ_ERR_NONE ){ WlzInitGreyScan(obj, &niwsp, &ngwsp); iwsp = biwsp; for (i=0; i<n; i++) { WlzInitGreyScan(objs[i], iwsp, &gwsp[i]); WlzNextGreyInterval(iwsp++); if( gwsp[i].pixeltype != grey_type ){ AlcFree((void *) gwsp); AlcFree((void *) locbuffs); AlcFree((void *) locbuff); AlcFree((void *) biwsp); WlzFreeObj( obj ); obj = NULL; errNum = WLZ_ERR_GREY_TYPE; } } } if( errNum == WLZ_ERR_NONE ){ while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) { l = niwsp.linpos; greyptr = ngwsp.u_grintptr; switch( ngwsp.pixeltype ){ case WLZ_GREY_INT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos); } } *greyptr.inp = gv.inv / noverlap; greyptr.inp++; } break; case WLZ_GREY_SHORT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.shv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos); } } *greyptr.shp = (short )(gv.shv / noverlap); greyptr.shp++; } break; case WLZ_GREY_UBYTE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.inv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos); } } *greyptr.ubp = (WlzUByte )(gv.inv / noverlap); greyptr.ubp++; } break; case WLZ_GREY_FLOAT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.flv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos); } } *greyptr.flp = gv.flv / noverlap; greyptr.flp++; } break; case WLZ_GREY_DOUBLE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.dbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos); } } *greyptr.dbp = gv.dbv / noverlap; greyptr.dbp++; } break; case WLZ_GREY_RGBA: /* RGBA to be done - do properly RAB */ for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { noverlap = 0; gv.rgbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while (iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ WlzNextGreyInterval(iwsp); } if (iwsp->linrmn >= 0 && iwsp->linpos == l && iwsp->lftpos <= k) { noverlap++; gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos); } } *greyptr.rgbp = gv.rgbv / noverlap; greyptr.rgbp++; } break; default: break; } } } AlcFree((void *) gwsp); } if( errNum == WLZ_ERR_NONE ){ AlcFree( (void *) biwsp); AlcFree( (void *)locbuff ); AlcFree( (void *)locbuffs ); } if( dstErr ){ *dstErr = errNum; } return( obj ); }
/*! * \ingroup WlzBinaryOps * \brief Calculate the intersection of a set of objects. If uvt=0 calculate domain only, uvt=1 calculate the mmean grey-value at each point. Input objects must be all non-NULL and domain objects of the same type i.e. either 2D or 3D otherwise an error is returned. * * \return Intersection object with grey-table as required, if the intersection is empty returns WLZ_EMPTY_OBJ, NULL on error. * \param n number of input objects * \param objs input object array * \param uvt grey-table copy flag (1 - copy, 0 - no copy) * \param dstErr error return. * \par Source: * WlzIntersectN.c */ WlzObject *WlzIntersectN( int n, WlzObject **objs, int uvt, WlzErrorNum *dstErr) { WlzObject *obj = NULL; WlzIntervalDomain *idom; WlzInterval *itvl, *jtvl; WlzIntervalWSpace *iwsp; WlzIntervalWSpace *biwsp,*tiwsp,niwsp; WlzGreyWSpace *gwsp,ngwsp; WlzDomain domain; WlzValues values; WlzObjectType type; WlzPixelV backg; WlzGreyP greyptr; WlzGreyV gv; int i, j, k, l, inttot, change, lwas, nints; int line1, lastln; int kol1, lastkl; WlzErrorNum errNum = WLZ_ERR_NONE; /* * check pointers */ /* intersecction of no objects is an empty domain */ domain.i = NULL; values.v = NULL; if( n < 1 ) { return WlzMakeEmpty(dstErr); } /* array pointer == NULL or any object pointer == NULL is an error */ if(objs == NULL){ errNum = WLZ_ERR_OBJECT_NULL; } else { for(i=0; i<n; i++){ if(objs[i] == NULL){ errNum = WLZ_ERR_OBJECT_NULL; } } } if(errNum != WLZ_ERR_NONE) { obj = NULL; if(dstErr) { *dstErr = errNum; } return(obj); } /* check type of first object */ switch( objs[0]->type ){ case WLZ_2D_DOMAINOBJ: break; case WLZ_3D_DOMAINOBJ: return WlzIntersect3d(objs, n, uvt, &errNum); case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; if(dstErr) { *dstErr = errNum; } return NULL; } /* check number */ if (n == 1){ obj = WlzMakeMain(objs[0]->type, objs[0]->domain, objs[0]->values, NULL, NULL, &errNum); if(dstErr) { *dstErr = errNum; } return(obj); } /* check all objects are non-empty and have the same type Note an empty object is not an error */ for (i=0; i<n; i++){ if( objs[i]->type != objs[0]->type ){ if( objs[i]->type == WLZ_EMPTY_OBJ ){ return WlzMakeEmpty(dstErr); } else { errNum = WLZ_ERR_OBJECT_TYPE; if(dstErr) { *dstErr = errNum; } return NULL; } } /* check for size */ if( WlzIsEmpty(objs[i], &errNum) ){ return WlzMakeEmpty(dstErr); } else { if( errNum != WLZ_ERR_NONE ){ if(dstErr) { *dstErr = errNum; } return NULL; } } } /* * Find the line and column bounds of the intersection. */ line1 = objs[0]->domain.i->line1; lastln = objs[0]->domain.i->lastln; kol1 = objs[0]->domain.i->kol1; lastkl = objs[0]->domain.i->lastkl; for (i=1; i<n; i++) { idom = objs[i]->domain.i; if (line1 < idom->line1) { line1 = idom->line1; } if (lastln > idom->lastln) { lastln = idom->lastln; } if (kol1 < idom->kol1) { kol1 = idom->kol1; } if (lastkl > idom->lastkl) { lastkl = idom->lastkl; } } if( lastkl < kol1 || lastln < line1 ){ return WlzMakeEmpty(dstErr); } /* * Count the individual intervals so that sufficient space * for the intersection may be allocated. */ inttot=0; for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { inttot += WlzIntervalCount(objs[i]->domain.i, &errNum); } if(errNum != WLZ_ERR_NONE) { if(dstErr) { *dstErr = errNum; } return NULL; } /* * Set up domain, value table structures, and object. */ if( (idom = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, 0, lastkl-kol1, &errNum)) == NULL ){ if(dstErr) { *dstErr = errNum; } return NULL; } if( (itvl = (WlzInterval *) AlcMalloc (inttot * sizeof(WlzInterval))) == NULL ){ WlzFreeIntervalDomain(idom); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } idom->freeptr = AlcFreeStackPush(idom->freeptr, (void *)itvl, NULL); lwas = line1; jtvl = itvl; nints = 0; domain.i = idom; values.v = NULL; if( (obj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) == NULL ){ WlzFreeIntervalDomain(idom); if(dstErr) { *dstErr = errNum; } return NULL; } /* * allocate space for workspaces */ if( (iwsp = (WlzIntervalWSpace *) AlcMalloc(n * sizeof(WlzIntervalWSpace))) == NULL ){ WlzFreeObj( obj ); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } biwsp = iwsp; tiwsp = biwsp + n; /* * Construct the intersection object's table of intervals. * Initialise scanning on each object/workspace combination. * Scan synchronously, setting up the intersection of * overlapping intervals. Needs a clear head !! */ for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { errNum = WlzInitRasterScan(objs[i],iwsp,WLZ_RASTERDIR_ILIC); if(errNum == WLZ_ERR_NONE) { errNum = WlzNextInterval(iwsp++); } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); if(dstErr) { *dstErr = errNum; } return NULL; } l = lwas; for (;;) { /* * find next line of intersection */ do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { if (iwsp->linpos > l) { l = iwsp->linpos; } } for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while (iwsp->linpos < l) { if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) { if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } goto firstfinished; } if (iwsp->linpos > l) { change = 1; } } } } while (change != 0); /* * find next interval of intersection */ kol1 = biwsp->lftpos; lastkl = biwsp->rgtpos; while(errNum == WLZ_ERR_NONE) { do { change = 0; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) if (iwsp->lftpos > lastkl) { kol1 = iwsp->lftpos; lastkl = iwsp->rgtpos; } else if (iwsp->lftpos > kol1) kol1 = iwsp->lftpos; for (iwsp=biwsp; iwsp<tiwsp; iwsp++) { while (iwsp->rgtpos < kol1) { if ((errNum = WlzNextInterval(iwsp)) != WLZ_ERR_NONE) { if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } goto firstfinished; } if (iwsp->linpos != l) { l = iwsp->linpos; goto jumpline; } if (iwsp->lftpos > kol1) change = 1; } } } while ((change != 0) && (errNum == WLZ_ERR_NONE)); if(errNum == WLZ_ERR_NONE) { for (iwsp=biwsp; iwsp < tiwsp; iwsp++) { if (iwsp->rgtpos <= lastkl) { lastkl = iwsp->rgtpos; } } if (lastkl >= kol1) { itvl->ileft = kol1 - idom->kol1; itvl->iright = lastkl - idom->kol1; if (l == lwas) { nints++; } else { errNum = WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; (j < l) && (errNum == WLZ_ERR_NONE); j++) { errNum = WlzMakeInterval(j,idom,0,NULL); } if(errNum == WLZ_ERR_NONE) { lwas = l; nints = 1; jtvl = itvl; } } itvl++; } kol1 = lastkl+1; } } jumpline: ; } firstfinished: if(errNum != WLZ_ERR_NONE) { WlzFreeObj(obj); if(dstErr) { *dstErr = errNum; } return NULL; } errNum = WlzMakeInterval(lwas,idom,nints,jtvl); for (j = lwas+1; (j <= lastln) && (errNum == WLZ_ERR_NONE); j++) { errNum = WlzMakeInterval(j,idom,0,NULL); } if(errNum != WLZ_ERR_NONE) { WlzFreeObj(obj); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } /* * standardise the interval list (remove leading and trailing * empty lines, set kol1 so that at least one interval commences * at zero, set lastkl correctly) */ (void )WlzStandardIntervalDomain(idom); /* check for error or empty */ nints = WlzIntervalCount(idom, &errNum); if( nints < 0 ){ /* error */ WlzFreeObj(obj); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } else if( nints == 0 ){ /* empty object */ WlzFreeObj(obj); AlcFree((void *) biwsp); return WlzMakeEmpty(dstErr); } if (uvt != 0) { WlzGreyType grey_type; if( (gwsp = (WlzGreyWSpace *) AlcMalloc (n * sizeof (WlzGreyWSpace))) == NULL ){ WlzFreeObj(obj); AlcFree((void *) biwsp); errNum = WLZ_ERR_MEM_ALLOC; if(dstErr) { *dstErr = errNum; } return NULL; } /* construct an empty "ragged-rectangle" (type 1 or 2) greytable choosing the grey-value type from the first object in the list */ backg = WlzGetBackground(objs[0], &errNum); if(errNum == WLZ_ERR_NONE) { grey_type = WlzGreyTableTypeToGreyType(objs[0]->values.core->type, &errNum); } if(errNum == WLZ_ERR_NONE) { type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, grey_type, &errNum); } if((errNum != WLZ_ERR_NONE) || (values.v = WlzNewValueTb(obj, type, backg, &errNum)) == NULL ){ WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } obj->values = WlzAssignValues(values, &errNum); if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } /* * fill the grey table with mean of grey values. */ /* initialise the work-spaces and check pixel type */ errNum = WlzInitGreyScan(obj, &niwsp, &ngwsp); iwsp = biwsp; for (i=0; (i < n) && (errNum == WLZ_ERR_NONE); i++) { errNum = WlzInitGreyScan(objs[i], iwsp, &gwsp[i]); if(errNum == WLZ_ERR_NONE) { errNum = WlzNextGreyInterval(iwsp++); } if( gwsp[i].pixeltype != grey_type ){ errNum = WLZ_ERR_GREY_TYPE; } } if(errNum != WLZ_ERR_NONE) { WlzFreeObj( obj ); AlcFree((void *) gwsp); AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return NULL; } while (WlzNextGreyInterval(&niwsp) == WLZ_ERR_NONE) { l = niwsp.linpos; greyptr = ngwsp.u_grintptr; switch( ngwsp.pixeltype ){ case WLZ_GREY_INT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.inv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.inv += *(gwsp[i].u_grintptr.inp + k - iwsp->lftpos); } *greyptr.inp = gv.inv / n; greyptr.inp++; } break; case WLZ_GREY_SHORT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.shv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.shv += *(gwsp[i].u_grintptr.shp + k - iwsp->lftpos); } *greyptr.shp = (short )(gv.shv / n); greyptr.shp++; } break; case WLZ_GREY_UBYTE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.ubv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.ubv += *(gwsp[i].u_grintptr.ubp + k - iwsp->lftpos); } *greyptr.ubp = (WlzUByte )(gv.ubv / n); greyptr.ubp++; } break; case WLZ_GREY_FLOAT: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.flv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.flv += *(gwsp[i].u_grintptr.flp + k - iwsp->lftpos); } *greyptr.flp = gv.flv / n; greyptr.flp++; } break; case WLZ_GREY_DOUBLE: for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.dbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.dbv += *(gwsp[i].u_grintptr.dbp + k - iwsp->lftpos); } *greyptr.dbp = gv.dbv / n; greyptr.dbp++; } break; case WLZ_GREY_RGBA: /* RGBA to be done again RAB */ for (k = niwsp.lftpos; k <= niwsp.rgtpos; k++) { gv.rgbv = 0; for (iwsp=biwsp,i=0; iwsp<tiwsp; iwsp++,i++) { while(iwsp->linrmn >= 0 && (iwsp->linpos < l || (iwsp->linpos == l && iwsp->rgtpos < k))){ (void )WlzNextGreyInterval(iwsp); } gv.rgbv += *(gwsp[i].u_grintptr.rgbp + k - iwsp->lftpos); } *greyptr.rgbp = gv.rgbv / n; greyptr.rgbp++; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } AlcFree((void *) gwsp); } AlcFree((void *) biwsp); if(dstErr) { *dstErr = errNum; } return obj; }