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