001/** 002 * 003 */ 004package plugins.kernel.roi.descriptor.measure; 005 006import icy.math.UnitUtil.UnitPrefix; 007import icy.roi.ROI; 008import icy.roi.ROI3D; 009import icy.roi.ROIDescriptor; 010import icy.sequence.Sequence; 011import icy.sequence.SequenceEvent; 012import icy.sequence.SequenceEvent.SequenceEventSourceType; 013import icy.util.StringUtil; 014 015/** 016 * Volume ROI descriptor class (see {@link ROIDescriptor}) 017 * 018 * @author Stephane 019 */ 020public class ROIVolumeDescriptor extends ROIDescriptor 021{ 022 public static final String ID = "Volume"; 023 024 public ROIVolumeDescriptor() 025 { 026 super(ID, "Volume", Double.class); 027 } 028 029 @Override 030 public String getDescription() 031 { 032 return "Volume"; 033 } 034 035 @Override 036 public String getUnit(Sequence sequence) 037 { 038 if (sequence != null) 039 return sequence.getBestPixelSizeUnit(3, 3).toString() + "m3"; 040 041 return UnitPrefix.MICRO.toString() + "m3"; 042 } 043 044 @Override 045 public boolean needRecompute(SequenceEvent change) 046 { 047 final SequenceEventSourceType sourceType = change.getSourceType(); 048 049 if (sourceType == SequenceEventSourceType.SEQUENCE_DATA) 050 return true; 051 if (sourceType == SequenceEventSourceType.SEQUENCE_META) 052 { 053 final String metaName = (String) change.getSource(); 054 055 return StringUtil.isEmpty(metaName) || StringUtil.equals(metaName, Sequence.ID_PIXEL_SIZE_X) 056 || StringUtil.equals(metaName, Sequence.ID_PIXEL_SIZE_Y) 057 || StringUtil.equals(metaName, Sequence.ID_PIXEL_SIZE_Z); 058 } 059 060 return false; 061 } 062 063 @Override 064 public Object compute(ROI roi, Sequence sequence) throws UnsupportedOperationException 065 { 066 return Double.valueOf(computeVolume(roi, sequence)); 067 } 068 069 /** 070 * Computes and returns the volume expressed in the unit of the descriptor (see {@link #getUnit(Sequence)}) for the 071 * specified ROI.<br> 072 * It may thrown an <code>UnsupportedOperationException</code> if the operation is not supported for that ROI. 073 * 074 * @param roi 075 * the ROI on which we want to compute the volume 076 * @param sequence 077 * an optional sequence where the pixel size can be retrieved 078 * @return the volume expressed in the unit of the descriptor (see {@link #getUnit(Sequence)}) 079 * @throws UnsupportedOperationException 080 * if the operation is not supported for this ROI 081 */ 082 public static double computeVolume(ROI roi, Sequence sequence) throws UnsupportedOperationException 083 { 084 return computeVolume(ROIInteriorDescriptor.computeInterior(roi), roi, sequence); 085 } 086 087 /** 088 * Computes and returns the volume from a given number of interior points expressed in the 089 * unit of the descriptor (see {@link #getUnit(Sequence)}) for the specified sequence and ROI.<br> 090 * It may returns <code>Double.Nan</code> if the operation is not supported for that ROI. 091 * 092 * @param interiorPoints 093 * the number of interior points (override the ROI value) 094 * @param roi 095 * the ROI we want to compute the volume 096 * @param sequence 097 * the input sequence used to retrieve operation unit by using pixel size 098 * information. 099 * @return the volume expressed in the unit of the descriptor (see {@link #getUnit(Sequence)}) 100 * @throws UnsupportedOperationException 101 * if the operation is not supported for this ROI 102 */ 103 public static double computeVolume(double interiorPoints, ROI roi, Sequence sequence) 104 throws UnsupportedOperationException 105 { 106 try 107 { 108 // we restrict to ROI3D only 109 if (!(roi instanceof ROI3D)) 110 throw new UnsupportedOperationException(); 111 112 return ROIInteriorDescriptor.computeInterior(interiorPoints, roi, sequence, 3); 113 } 114 catch (UnsupportedOperationException e) 115 { 116 throw new UnsupportedOperationException("Can't process " + ID + " calculation for ROI: '" + roi.getName() 117 + "'"); 118 } 119 } 120}