001    /*
002     * @(#)NaiveHistogram3D   0.6.0   2001/06/28
003     * 
004     * Copyright (c) 2001 Marco Schmidt <marcoschmidt@users.sourceforge.net>
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color.data;
009    
010    import net.sourceforge.jiu.color.data.Histogram3D;
011    
012    /**
013     * A class for a three-dimensional histogram that allocates one <code>int</code> value
014     * per counter at construction time.
015     * This means that a histogram with 8 bits for each channel will have
016     * 2<sup>8 + 8 + 8</sup> = 2<sup>24</sup> = 16,777,216 int values,
017     * making it 64 MB large.
018     *
019     * @author Marco Schmidt
020     */
021    public class NaiveHistogram3D implements
022            Histogram3D
023    {
024            private int[][][] data;
025            private int[] values;
026    
027            /**
028             * Creates a histogram 
029             */
030            public NaiveHistogram3D(int numValuesLevel1, int numValuesLevel2, int numValuesLevel3) throws 
031                    IllegalArgumentException, 
032                    OutOfMemoryError
033            {
034                    if (numValuesLevel1 < 1)
035                    {
036                            throw new IllegalArgumentException("The number of values for " +
037                                    "level 1 must be at least 1; got " + numValuesLevel1);
038                    }
039                    if (numValuesLevel2 < 1)
040                    {
041                            throw new IllegalArgumentException("The number of values for " +
042                                    "level 2 must be at least 1; got " + numValuesLevel2);
043                    }
044                    if (numValuesLevel3 < 1)
045                    {
046                            throw new IllegalArgumentException("The number of values for " +
047                                    "level 3 must be at least 1; got " + numValuesLevel3);
048                    }
049                    values = new int[3];
050                    values[0] = numValuesLevel1;
051                    values[1] = numValuesLevel2;
052                    values[2] = numValuesLevel3;
053                    data = new int[values[0]][][];
054                    for (int i1 = 0; i1 < values[0]; i1++)
055                    {
056                            data[i1] = new int[values[1]][];
057                            for (int i2 = 0; i2 < values[1]; i1++)
058                            {
059                                    data[i1][i2] = new int[values[2]];
060                            }
061                    }
062                    clear();
063            }
064    
065            /**
066             * Creates a histogram with the same number of values for all three dimensions.
067             * Calls {@link NaiveHistogram3D (int, int, int)}, repeating <code>numValues</code>
068             * three times.
069             * @param numValues the number of levels for all three dimensions
070             */
071            public NaiveHistogram3D(int numValues) throws IllegalArgumentException, OutOfMemoryError
072            {
073                    this(numValues, numValues, numValues);
074            }
075    
076            /**
077             * Sets all counters to zero.
078             */
079            public void clear()
080            {
081                    for (int i1 = 0; i1 < values[0]; i1++)
082                            for (int i2 = 0; i2 < values[1]; i2++)
083                                    for (int i3 = 0; i3 < values[2]; i3++)
084                                            data[i1][i2][i3] = 0;
085            }
086    
087            /**
088             * Returns the counter value of (index1, index2, index3).
089             * @param index1 first of the three values forming the threedimensional index
090             * @param index2 second of the three values forming the threedimensional index
091             * @param index3 three of the three values forming the threedimensional index
092             * @return the counter value of the desired index
093             * @throws IllegalArgumentException could be (read: need not necessarily) be 
094             *  thrown if the index formed by the arguments is invalid
095             */
096            public int getEntry(int index1, int index2, int index3) throws
097                    IllegalArgumentException
098            {
099                    try
100                    {
101                            return data[index1][index2][index3];
102                    }
103                    catch (ArrayIndexOutOfBoundsException aioobe)
104                    {
105                            throw new IllegalArgumentException("Not a valid index (" + index1 +
106                                    ", " + index2 + ", " + index3 + ")");
107                    }
108            }
109    
110            public int getMaxValue(int index) throws 
111                    IllegalArgumentException
112            {
113                    if (index >= 0 && index <= 2)
114                    {
115                            return values[index] - 1;
116                    }
117                    else
118                    {
119                            throw new IllegalArgumentException("The index argument must be " +
120                                    "from 0 to 2; got " + index);
121                    }
122            }
123    
124            /**
125             * Returns the number of used entries (those entries with
126             * a counter value larger than zero).
127             * @return number of non-zero counter values
128             */
129            public int getNumUsedEntries()
130            {
131                    int result = 0;
132                    for (int i1 = 0; i1 < values[0]; i1++)
133                            for (int i2 = 0; i2 < values[1]; i2++)
134                                    for (int i3 = 0; i3 < values[2]; i3++)
135                                            if (data[i1][i2][i3] > 0)
136                                                    result++;
137                    return result;
138            }
139    
140            /**
141             * Increases the counter value of (index1, index2, index3) by one.
142             * This method can easily be implemented by the one-liner
143             * <code>setEntry(index1, index2, index3, getEntry(index1, index2, index3) + 1);</code>
144             * However, this method is expected to be faster in some contexts.
145             *
146             * @param index1 first of the three values forming the threedimensional index
147             * @param index2 second of the three values forming the threedimensional index
148             * @param index3 three of the three values forming the threedimensional index
149             * @return the counter value of the desired index
150             * @throws IllegalArgumentException could be (read: need not necessarily) be 
151             *  thrown if the index formed by the arguments is invalid
152             */
153            public void increaseEntry(int index1, int index2, int index3) throws IllegalArgumentException
154            {
155                    try
156                    {
157                            data[index1][index2][index3]++;
158                    }
159                    catch (ArrayIndexOutOfBoundsException aioobe)
160                    {
161                            throw new IllegalArgumentException("Not a valid index (" + index1 +
162                                    ", " + index2 + ", " + index3 + ")");
163                    }
164            }
165    
166            /**
167             * Sets the counter value of (index1, index2, index3) to newValue.
168             *
169             * @param index1 first of the three values forming the threedimensional index
170             * @param index2 second of the three values forming the threedimensional index
171             * @param index3 three of the three values forming the threedimensional index
172             * @param newValue the counter value that is assigned to the argument index
173             * @throws IllegalArgumentException could be (read: need not necessarily) be 
174             *  thrown if the index formed by the first three arguments is invalid
175             */
176            public void setEntry(int index1, int index2, int index3, int newValue) throws IllegalArgumentException
177            {
178                    try
179                    {
180                            data[index1][index2][index3] = newValue;
181                    }
182                    catch (ArrayIndexOutOfBoundsException aioobe)
183                    {
184                            throw new IllegalArgumentException("Not a valid index (" + index1 +
185                                    ", " + index2 + ", " + index3 + ")");
186                    }
187            }
188    }