/*! * \ingroup WlzBoundary * \brief Return a domain object corresponding to the input boundary object. * * \return Domain object corresponding to the input boundary, NULL on error. * \param boundary Input boundary object. * \param fillMode Fill mode for the individual polyline boundaries. If the input object is a genuine boundary object then there will be no self-intersecting polylines and <tt> fillMode = WLZ_SIMPLE_FILL </tt> is appropriate. See WlzPolyToObj(). * \param dstErr Error return * \par Source: * WlzBoundToObj.c */ WlzObject *WlzBoundaryToObj( WlzObject *boundary, WlzPolyFillMode fillMode, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL, *tmpObj; WlzDomain domain, *domains, *bnddmns; WlzValues values; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object */ if( boundary == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( boundary->type ){ case WLZ_3D_DOMAINOBJ: /* check plane domain */ if( boundary->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else { switch( boundary->domain.p->type ){ case WLZ_PLANEDOMAIN_BOUNDLIST: if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, boundary->domain.p->plane1, boundary->domain.p->lastpl, boundary->domain.p->line1, boundary->domain.p->lastln, boundary->domain.p->kol1, boundary->domain.p->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = boundary->domain.p->voxel_size[0]; domain.p->voxel_size[1] = boundary->domain.p->voxel_size[1]; domain.p->voxel_size[2] = boundary->domain.p->voxel_size[2]; domains = domain.p->domains; bnddmns = boundary->domain.p->domains; for(p=domain.p->plane1; p <= domain.p->lastpl; p++, domains++, bnddmns++){ if( (*bnddmns).poly ){ if((tmpObj = WlzBoundToObj((*bnddmns).b, fillMode, &errNum)) != NULL){ *domains = WlzAssignDomain(tmpObj->domain, NULL); WlzFreeObj(tmpObj); } else { WlzFreePlaneDomain(domain.p); domain.p = NULL; break; } } } if( domain.p ){ values.core = NULL; if( (rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) == NULL ){ WlzFreePlaneDomain(domain.p); } } } break; case WLZ_EMPTY_DOMAIN: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } break; case WLZ_BOUNDLIST: return WlzBoundToObj(boundary->domain.b, fillMode, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzBoundaryToObj(boundary->values.obj, fillMode, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, boundary->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzBoundary * \brief Convert the input boundary list to a domain object. Use WlzBoundaryToObj if conversion of a 3D stack of boundary list is required or if the boundary is available as a first class object. * * \return Domain object corresponding to the input boundary domain, NULL on error. * \param bound Input boundary list domain. * \param fillMode Polyline fill mode, see WlzPolyToObj(). * \param dstNum Error return. * \par Source: * WlzBoundToObj.c */ WlzObject *WlzBoundToObj( WlzBoundList *bound, WlzPolyFillMode fillMode, WlzErrorNum *dstNum) { WlzObject *obj, *selfobj = NULL, *nextobj, *downobj; WlzErrorNum errNum=WLZ_ERR_NONE; /* check input */ if( bound == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } /* find object corresponding to the current boundary */ if( errNum == WLZ_ERR_NONE ){ if( bound->poly != NULL ){ selfobj = WlzPolyToObj(bound->poly, fillMode, &errNum); } else { selfobj = NULL; } } if( (errNum == WLZ_ERR_NONE) && (selfobj != NULL) && (bound->type != WLZ_BOUNDLIST_PIECE) && (fillMode != WLZ_VERTEX_FILL) ){ obj = WlzErosion(selfobj, WLZ_4_CONNECTED, &errNum); WlzFreeObj(selfobj); selfobj = obj; } /* add object corresponding to next */ if( (errNum == WLZ_ERR_NONE) && bound->next ){ nextobj = WlzBoundToObj(bound->next, fillMode, &errNum); if( selfobj == NULL ){ selfobj = nextobj; } else { if( (errNum == WLZ_ERR_NONE) && (nextobj != NULL) ){ obj = WlzUnion2(selfobj, nextobj, &errNum); WlzFreeObj(nextobj); WlzFreeObj(selfobj); selfobj = obj; } } } /* remove object corresponding to down */ if( (errNum == WLZ_ERR_NONE) && bound->down ){ downobj = WlzBoundToObj(bound->down, fillMode, &errNum); if( downobj != NULL ){ if( selfobj != NULL ){ if( fillMode != WLZ_VERTEX_FILL ){ obj = WlzDiffDomain(selfobj, downobj, &errNum); } else { obj = WlzUnion2(selfobj, downobj, &errNum); } WlzFreeObj(selfobj); selfobj = obj; } WlzFreeObj(downobj); } } /* return object */ if( dstNum ){ *dstNum = errNum; } return(selfobj); }
/*! * \return New Woolz object without holes or NULL on error. * \ingroup WlzDomainOps * \brief Fills the holes in the given object's domain (which are by * definition not connected to the outside). When the given * object's domain has more than one component part, the * object should first be labeled, this function should then be * called for each of the labeled parts and then the union of * the filled domains should be formed. * \param srcObj Given 3D domain object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDomainFill3D( WlzObject *srcObj, WlzErrorNum *dstErr) { int nPln = 0; WlzObject *bndObj = NULL, *filObj = NULL, *gvnObj = NULL, *sedObj = NULL, *shlObj = NULL; WlzPixelV zeroV; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; nullVal.core = NULL; zeroV.type = WLZ_GREY_UBYTE; zeroV.v.ubv = 0; if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_3D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { gvnObj = WlzMakeMain(srcObj->type, srcObj->domain, nullVal, NULL, NULL, &errNum); } /* Create a then shell 1 voxel thick just inside the given objects's * domain. */ if(errNum == WLZ_ERR_NONE) { WlzObject *difObj = NULL; difObj = WlzAssignObject( WlzBoundaryDomain(gvnObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzIBox3 clipBox; /* Clip the dilated shell domain to make sure it stays within the * bounding box of the given object then all planes will align. */ clipBox.xMin = gvnObj->domain.p->kol1; clipBox.yMin = gvnObj->domain.p->line1; clipBox.zMin = gvnObj->domain.p->plane1; clipBox.xMax = gvnObj->domain.p->lastkl; clipBox.yMax = gvnObj->domain.p->lastln; clipBox.zMax = gvnObj->domain.p->lastpl; shlObj = WlzAssignObject( WlzClipObjToBox3D(difObj, clipBox, &errNum), NULL); } (void )WlzFreeObj(difObj); } /* Make sure that the bounding box of the thin shell domain fits it and * that it's first and last planes have interrvals. */ if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(shlObj->domain.p, NULL); } /* Create a value table for the shell object with values set to zero. */ if(errNum == WLZ_ERR_NONE) { WlzValues val; WlzObjectType tType; tType = WlzGreyTableType(WLZ_GREY_TAB_INTL, WLZ_GREY_UBYTE, NULL); val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, zeroV, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { int p; nPln = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; shlObj->values = WlzAssignValues(val, NULL); #ifdef _OPENMP #pragma omp parallel for shared(shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain dom2; WlzErrorNum errNum2; dom2 = shlObj->domain.p->domains[p]; if(dom2.core) { WlzValues val2; WlzObject *shlObj2; shlObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { val2.i = WlzMakeIntervalValues(tType, shlObj2, zeroV, &errNum2); /* WlzMakeIntervalValues() sets all values to zero. */ } if(errNum2 == WLZ_ERR_NONE) { shlObj->values.vox->values[p] = WlzAssignValues(val2, NULL); } (void )WlzFreeObj(shlObj2); if(errNum2 == WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if((errNum == WLZ_ERR_NONE) && (errNum2 != WLZ_ERR_NONE)) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } } } /* Compute the (plane-wise) boundary list for the given object. */ if(errNum == WLZ_ERR_NONE) { bndObj = WlzObjToBoundary(gvnObj, 0, &errNum); } /* Sweep down through the boundary object setting the values of * those voxels in the shell object to a non zero value when they * correspond to top level boundaries. */ if(errNum == WLZ_ERR_NONE) { int p; #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain iDom2; WlzValues iVal2; WlzObject *iObj2 = NULL; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; iDom2 = shlObj->domain.p->domains[p]; iVal2 = shlObj->values.vox->values[p]; iObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, iDom2, iVal2, NULL, NULL, &errNum2); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(iObj2, &errNum2); } if(errNum2 == WLZ_ERR_NONE) { WlzBoundList *bnd, *bnd2; bnd2 = bDom2.b; for(bnd = bnd2; bnd != NULL; bnd = bnd->next) { if(bnd->poly != NULL) { WlzPolygonDomain *ply; ply = bnd->poly; if(ply) { int i; WlzIVertex2 *vtx; vtx = ply->vtx; for(i = 0; i < ply->nvertices; ++i) { WlzGreyValueGet(gVWSp, 0, vtx[i].vtY, vtx[i].vtX); *(gVWSp->gPtr[0].ubp) = 255; } } } } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(iObj2); WlzGreyValueFreeWSp(gVWSp); } } } } /* Threshold the shell object, throwing away all but where the voxels * are set to create a seed domain. Then remove the value table from * the shell object and free it as it's no longer needed. */ if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; WlzPixelV tV; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(shlObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { sedObj = WlzAssignObject( WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(tObj); tObj = NULL; if(errNum == WLZ_ERR_NONE) { tObj = WlzAssignObject( WlzMakeMain(shlObj->type, shlObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(shlObj); shlObj = NULL; if(errNum == WLZ_ERR_NONE) { shlObj = tObj; tObj = NULL; } (void )WlzFreeObj(tObj); #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-00.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } /* Label the shell domain using 26-connectivity in 3D and then * keep only those component objects which intersect the seed domain. * Then free the shell and seed domains replacing the shell domain * with the union of the intersecting labeled component objects. * Finaly free the intersecting component objects, keeping only the * new shell domain. */ if(errNum == WLZ_ERR_NONE) { int i, j, nCSObj = 0; WlzIBox3 bBox; WlzObject **csObj = NULL; bBox = WlzBoundingBox3I(shlObj, &errNum); if(errNum == WLZ_ERR_NONE) { int maxCSObj; maxCSObj = ((bBox.xMax - bBox.xMin + 1) * (bBox.yMax - bBox.yMin + 1) * (bBox.zMax - bBox.zMin + 1)) / 8; if(maxCSObj < 8) { maxCSObj = 8; } errNum = WlzLabel(shlObj, &nCSObj, &csObj, maxCSObj, 0, WLZ_26_CONNECTED); } if(errNum == WLZ_ERR_NONE) { for(i = 0; i < nCSObj; ++i) { if(!WlzHasIntersection(csObj[i], sedObj, &errNum)) { (void )WlzFreeObj(csObj[i]); csObj[i] = NULL; } } } if(errNum == WLZ_ERR_NONE) { /* Squeeze out any NULL objects reseting their number.*/ for(i = 0, j = 0; i < nCSObj; ++i) { if(csObj[i]) { csObj[j++] = csObj[i]; } } nCSObj = j; } if(errNum == WLZ_ERR_NONE) { WlzObject *iObj = NULL, *uObj = NULL; uObj = WlzAssignObject( WlzUnionN(nCSObj, csObj, 0, &errNum), NULL); iObj = WlzAssignObject( WlzIntersect2(uObj, shlObj, &errNum), NULL); (void )WlzFreeObj(uObj); (void )WlzFreeObj(shlObj); shlObj = iObj; #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-01.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } if(csObj) { for(i = 0; i < nCSObj; ++i) { (void )WlzFreeObj(csObj[i]); } (void )AlcFree(csObj); } } /* Sweep down through the boundary lists again creating new boundary lists * which do not have boundaries that do not intersect the new shell domain. * Then create a new filled object from these boundary lists. */ if(errNum == WLZ_ERR_NONE) { int p, nPlnFil; WlzDomain filDom; nPlnFil = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; filDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, shlObj->domain.p->line1, shlObj->domain.p->lastln, shlObj->domain.p->kol1, shlObj->domain.p->lastkl, &errNum); #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPlnFil; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain sDom2; WlzObject *fObj2 = NULL; WlzBoundList *newBnd = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; sDom2 = shlObj->domain.p->domains[p]; if(sDom2.core) { newBnd = WlzDomFill3DDoBound2D(bDom2.b, sDom2, &errNum2); if(newBnd != NULL) { fObj2 = WlzBoundToObj(newBnd, WLZ_SIMPLE_FILL, &errNum2); (void )WlzFreeBoundList(newBnd); } if(errNum2 == WLZ_ERR_NONE) { if(fObj2) { filDom.p->domains[p] = WlzAssignDomain(fObj2->domain, NULL); } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(fObj2); } } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(filDom.p, NULL); } if(errNum == WLZ_ERR_NONE) { WlzObject *tObj0 = NULL, *tObj1 = NULL; /* Put back any isolated voxels this function has removed. */ tObj0 = WlzAssignObject( WlzMakeMain(srcObj->type, filDom, nullVal, NULL, NULL, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { tObj1 = WlzUnion2(gvnObj, tObj0, &errNum); } if(errNum == WLZ_ERR_NONE) { filObj = WlzMakeMain(tObj1->type, tObj1->domain, nullVal, NULL, NULL, &errNum); } (void )WlzFreeObj(tObj0); (void )WlzFreeObj(tObj1); } } (void )WlzFreeObj(bndObj); (void )WlzFreeObj(gvnObj); (void )WlzFreeObj(shlObj); (void )WlzFreeObj(sedObj); if((errNum != WLZ_ERR_NONE) && (filObj != NULL)) { (void )WlzFreeObj(filObj); filObj = NULL; } if(dstErr) { *dstErr = errNum; } return(filObj); }
/*! * \ingroup WlzValuesUtils * \brief Set the value maskVal within the domain given by the * mask object. The mask object can be a 2D, 3D, polygon * or boundary object. A 3D mask with a 2D object is an * error. A 2D mask with a 3D object will be applied to * each plane in turn. * * \return New object with the same domain as the input object but with values in the intersection with the mask domain set to the mask value. NULL on error. * \param obj Input object * \param mask Mask object. * \param maskVal mask value. * \param dstErr Error return. * \par Source: * WlzGreyMask.c */ WlzObject *WlzGreyMask( WlzObject *obj, WlzObject *mask, WlzPixelV maskVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpMask, *obj1; WlzValues values; WlzPixelV tmpMaskval; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; int i; WlzErrorNum errNum=WLZ_ERR_NONE; /* check obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } break; case WLZ_3D_DOMAINOBJ: return WlzGreyMask3d(obj, mask, maskVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyMask(obj->values.obj, mask, maskVal, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the mask */ if( errNum == WLZ_ERR_NONE ){ if( mask == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( mask->type ){ case WLZ_2D_DOMAINOBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: tmpMask = WlzMakeMain(WLZ_2D_DOMAINOBJ, mask->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeMain(WLZ_2D_DOMAINOBJ, obj->domain, obj->values, NULL, NULL, dstErr); case WLZ_2D_POLYGON: tmpMask = WlzPolyToObj(mask->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: tmpMask = WlzBoundToObj(mask->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if( errNum == WLZ_ERR_NONE ){ tmpMask = WlzAssignObject(tmpMask, NULL); } } } /* copy input obj and setvalues in the intersection */ if(errNum == WLZ_ERR_NONE){ if((rtnObj = WlzNewGrey(obj, &errNum)) != NULL){ if((obj1 = WlzIntersect2(obj, tmpMask, &errNum)) != NULL){ obj1->values = WlzAssignValues(rtnObj->values, NULL); errNum = WlzInitGreyScan(obj1, &iwsp, &gwsp); WlzValueConvertPixel(&tmpMaskval, maskVal, gwsp.pixeltype); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)){ gptr = gwsp.u_grintptr; switch( gwsp.pixeltype ){ case WLZ_GREY_INT: for(i=0; i<iwsp.colrmn; i++, gptr.inp++){ *gptr.inp = tmpMaskval.v.inv; } break; case WLZ_GREY_SHORT: for(i=0; i<iwsp.colrmn; i++, gptr.shp++){ *gptr.shp = tmpMaskval.v.shv; } break; case WLZ_GREY_UBYTE: for(i=0; i<iwsp.colrmn; i++, gptr.ubp++){ *gptr.ubp = tmpMaskval.v.ubv; } break; case WLZ_GREY_FLOAT: for(i=0; i<iwsp.colrmn; i++, gptr.flp++){ *gptr.flp = tmpMaskval.v.flv; } break; case WLZ_GREY_DOUBLE: for(i=0; i<iwsp.colrmn; i++, gptr.dbp++){ *gptr.dbp = tmpMaskval.v.dbv; } break; case WLZ_GREY_RGBA: for(i=0; i<iwsp.colrmn; i++, gptr.rgbp++){ *gptr.rgbp = tmpMaskval.v.rgbv; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } WlzFreeObj(tmpMask); } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \ingroup WlzValuesUtils * \brief * * \return New object with the same domain <tt>tmpl</tt> but values in the intersection with <tt>obj</tt> set to those of the object. Returns NULL on error. * \param obj Input object to which the template is applied * \param tmpl Template object * \param tmplVal Template value for regions in the template not in the original object * \param dstErr Error return. * \par Source: * WlzGreyTemplate.c */ WlzObject *WlzGreyTemplate( WlzObject *obj, WlzObject *tmpl, WlzPixelV tmplVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzPixelV bckgrnd; WlzObjectType type; WlzGreyType gtype=WLZ_GREY_UBYTE; WlzIntervalWSpace iwsp1, iwsp2; WlzGreyWSpace gwsp1, gwsp2; int size; WlzErrorNum errNum = WLZ_ERR_NONE; /* check obj */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } else { bckgrnd = WlzGetBackground(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.core->type, NULL); } break; case WLZ_3D_DOMAINOBJ: return WlzGreyTemplate3d(obj, tmpl, tmplVal, dstErr); case WLZ_TRANS_OBJ: if((values.obj = WlzGreyTemplate(obj->values.obj, tmpl, tmplVal, &errNum)) != NULL){ return WlzMakeMain(WLZ_TRANS_OBJ, obj->domain, values, NULL, NULL, dstErr); } break; case WLZ_EMPTY_OBJ: bckgrnd.type = WLZ_GREY_UBYTE; bckgrnd.v.ubv = 0; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* check the template */ if( errNum == WLZ_ERR_NONE ){ if( tmpl == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( tmpl->type ){ case WLZ_2D_DOMAINOBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->domain, values, NULL, NULL, &errNum); break; case WLZ_TRANS_OBJ: rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, tmpl->values.obj->domain, values, NULL, NULL, &errNum); break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); case WLZ_2D_POLYGON: rtnObj = WlzPolyToObj(tmpl->domain.poly, WLZ_SIMPLE_FILL, &errNum); break; case WLZ_BOUNDLIST: rtnObj = WlzBoundToObj(tmpl->domain.b, WLZ_SIMPLE_FILL, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* attach a value table to the template and set to the template value, note the background is set to the input object or zero if empty */ if( errNum == WLZ_ERR_NONE ){ type = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gtype, NULL); if((values.v = WlzNewValueTb(rtnObj, type, bckgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); errNum = WlzGreySetValue(rtnObj, tmplVal); } } /* copy input obj values within the intersection */ if( errNum == WLZ_ERR_NONE ){ if((obj->type != WLZ_EMPTY_OBJ) ){ if( (obj1 = WlzIntersect2(obj, rtnObj, &errNum)) ){ obj1->values = WlzAssignValues(rtnObj->values, NULL); obj2 = WlzMakeMain(obj1->type, obj1->domain, obj->values, NULL, NULL, NULL); errNum = WlzInitGreyScan(obj1, &iwsp1, &gwsp1); errNum = WlzInitGreyScan(obj2, &iwsp2, &gwsp2); switch( gwsp1.pixeltype ){ case WLZ_GREY_INT: size = sizeof(int); break; case WLZ_GREY_SHORT: size = sizeof(short); break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte); break; case WLZ_GREY_FLOAT: size = sizeof(float); break; case WLZ_GREY_DOUBLE: size = sizeof(double); break; case WLZ_GREY_RGBA: size = sizeof(WlzUInt); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp1)) == WLZ_ERR_NONE)){ (void) WlzNextGreyInterval(&iwsp2); memcpy((void *) gwsp1.u_grintptr.inp, (const void *) gwsp2.u_grintptr.inp, size * iwsp1.colrmn); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzFreeObj(obj2); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
static WlzObject *WlzGreyTemplate3d( WlzObject *obj, WlzObject *tmpl, WlzPixelV tmplVal, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzObject *tmpObj = NULL, *obj1 = NULL, *obj2 = NULL; WlzDomain domain, *domains; WlzValues values, *valuess; WlzPlaneDomain *pdom; int p; WlzErrorNum errNum=WLZ_ERR_NONE; /* check the object - it is non-NULL and 3D but the domain needs checking */ if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else { switch( obj->domain.p->type ){ case WLZ_2D_DOMAINOBJ: /* check there is a valuetable */ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTableIsTiled(obj->values.core->type) ){ errNum = WLZ_ERR_VALUES_TYPE; } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* check the template and create the return object */ if( errNum == WLZ_ERR_NONE ){ if( tmpl == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { values.core = NULL; switch( tmpl->type ){ case WLZ_2D_DOMAINOBJ: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(tmpl->domain, NULL); } rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_2D_POLYGON: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; obj1 = WlzPolyToObj(tmpl->domain.poly, WLZ_SIMPLE_FILL, &errNum); for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_BOUNDLIST: pdom = obj->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; obj1 = WlzBoundToObj(tmpl->domain.b, WLZ_SIMPLE_FILL, &errNum); for(p=pdom->plane1; p <= pdom->lastpl; p++){ domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_3D_DOMAINOBJ: if( tmpl->domain.p ){ switch( tmpl->domain.p->type ){ case WLZ_2D_DOMAINOBJ: domain.p = tmpl->domain.p; break; case WLZ_PLANEDOMAIN_POLYGON: case WLZ_PLANEDOMAIN_CONV_HULL: pdom = tmpl->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ if( pdom->domains[p-pdom->plane1].core ){ obj1 = WlzPolyToObj(pdom->domains[p-pdom->plane1].poly, WLZ_SIMPLE_FILL, &errNum); domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); } values.core = NULL; rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; case WLZ_PLANEDOMAIN_BOUNDLIST: pdom = tmpl->domain.p; if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, pdom->plane1, pdom->lastpl, pdom->line1, pdom->lastpl, pdom->kol1, pdom->lastkl, &errNum)) != NULL){ domain.p->voxel_size[0] = pdom->voxel_size[0]; domain.p->voxel_size[1] = pdom->voxel_size[1]; domain.p->voxel_size[2] = pdom->voxel_size[2]; for(p=pdom->plane1; p <= pdom->lastpl; p++){ if( pdom->domains[p-pdom->plane1].core ){ obj1 = WlzBoundToObj(pdom->domains[p-pdom->plane1].b, WLZ_SIMPLE_FILL, &errNum); domain.p->domains[p - pdom->plane1] = WlzAssignDomain(obj1->domain, NULL); } WlzFreeObj(obj1); } values.core = NULL; rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } if( errNum == WLZ_ERR_NONE ){ rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } } /* now we have a 3D obj and 3D template so run through the template and map values as required, note we must check that all the valuetables have the same type ie switch to obj type if necessary */ if( errNum == WLZ_ERR_NONE ){ WlzDomain *objDoms; WlzValues *objVals; WlzGreyType gtype=WLZ_GREY_UBYTE; /* attach a voxel table with empty values list */ values.vox = WlzMakeVoxelValueTb(obj->values.vox->type, rtnObj->domain.p->plane1, rtnObj->domain.p->lastpl, obj->values.vox->bckgrnd, NULL, NULL); rtnObj->values = WlzAssignValues(values, NULL); /* set some local variables */ pdom = rtnObj->domain.p; domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; objDoms = obj->domain.p->domains; objVals = obj->values.vox->values; /* calculate the new valuetables */ for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if(((*domains).core)){ if((p >= obj->domain.p->plane1) && (p <= obj->domain.p->lastpl) && (objDoms[p - obj->domain.p->plane1].core) ){ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, objDoms[p - obj->domain.p->plane1], objVals[p - obj->domain.p->plane1], NULL, NULL, NULL); gtype = WlzGreyTableTypeToGreyType(tmpObj->values.core->type, NULL); } else { tmpObj = WlzMakeEmpty(NULL); } tmpObj = WlzAssignObject(tmpObj, NULL); values.core = NULL; obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, values, NULL, NULL, NULL), NULL); if((obj2 = WlzGreyTemplate(tmpObj, obj1, tmplVal, &errNum)) != NULL){ *valuess = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); WlzFreeObj(tmpObj); } } /* now check all valuetables have the same grey type */ domains = rtnObj->domain.p->domains; valuess = rtnObj->values.vox->values; for(p=pdom->plane1; p <= pdom->lastpl; p++, domains++, valuess++){ if((*domains).core && (WlzGreyTableTypeToGreyType((*valuess).core->type, NULL) != gtype)){ obj1 = WlzAssignObject( WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *valuess, NULL, NULL, NULL), NULL); if((obj2 = WlzConvertPix(obj1, gtype, &errNum)) != NULL){ /* substitute the valuetable in the voxel table array */ WlzFreeValues(*valuess); *valuess = WlzAssignValues(obj2->values, NULL); WlzFreeObj(obj2); } WlzFreeObj(obj1); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }