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.ROIDescriptor;
010import icy.sequence.Sequence;
011import icy.sequence.SequenceEvent;
012import icy.sequence.SequenceEvent.SequenceEventSourceType;
013import icy.util.StringUtil;
014
015/**
016 * Perimeter ROI descriptor class (see {@link ROIDescriptor})
017 * 
018 * @author Stephane
019 */
020public class ROIPerimeterDescriptor extends ROIDescriptor
021{
022    public static final String ID = "Perimeter";
023
024    public ROIPerimeterDescriptor()
025    {
026        super(ID, "Perimeter", Double.class);
027    }
028
029    @Override
030    public String getDescription()
031    {
032        return "Perimeter";
033    }
034
035    @Override
036    public String getUnit(Sequence sequence)
037    {
038        if (sequence != null)
039            return sequence.getBestPixelSizeUnit(2, 1).toString() + "m";
040
041        return UnitPrefix.MICRO.toString() + "m";
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(computePerimeter(roi, sequence));
067    }
068
069    /**
070     * Computes and returns the perimeter expressed in the unit of the descriptor (see {@link #getUnit(Sequence)}) for
071     * the 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 perimeter
076     * @param sequence
077     *        the sequence from which the pixel size can be retrieved
078     * @return the perimeter 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 computePerimeter(ROI roi, Sequence sequence) throws UnsupportedOperationException
083    {
084        if (sequence == null)
085            throw new UnsupportedOperationException("Cannot compute Perimeter with null Sequence parameter !");
086
087        final UnitPrefix bestUnit = sequence.getBestPixelSizeUnit(2, 1);
088        final double length = roi.getLength(sequence);
089
090        return UnitUtil.getValueInUnit(length, UnitPrefix.MICRO, bestUnit, 1);
091    }
092
093    // /**
094    // * Computes and returns the perimeter from a given number of contour points expressed in the
095    // * unit of the descriptor (see {@link #getUnit(Sequence)}) for the specified sequence and ROI.<br>
096    // * It may returns <code>Double.Nan</code> if the operation is not supported for that ROI.
097    // *
098    // * @param contourPoints
099    // * the number of contour points (override the ROI value)
100    // * @param roi
101    // * the ROI we want to compute the perimeter
102    // * @param sequence
103    // * the input sequence used to retrieve operation unit by using pixel size
104    // * information.
105    // * @return the perimeter
106    // * @throws UnsupportedOperationException
107    // * if the operation is not supported for this ROI
108    // */
109    // static double computePerimeter(double contourPoints, ROI roi, Sequence sequence)
110    // throws UnsupportedOperationException
111    // {
112    // return ROIContourDescriptor.computeContour(contourPoints, roi, sequence, 2);
113    // }
114}