Coverage Report - org.jfree.data.som.SOMDataset
 
Classes in this File Line Coverage Branch Coverage Complexity
SOMDataset
100%
106/106
100%
25/25
3
SOMDataset$SOMDatasetIterator
100%
12/12
100%
2/2
3
 
 1  
 /* ======================================================================= 
 2  
  * A visualisation library extension for JFreeChart. Please see JFreeChart
 3  
  * for further information.
 4  
  * =======================================================================
 5  
  * Copyright (C) 2006  University of Helsinki, Department of Computer Science
 6  
  *
 7  
  * This library is free software; you can redistribute it and/or
 8  
  * modify it under the terms of the GNU Lesser General Public
 9  
  * License as published by the Free Software Foundation; either
 10  
  * version 2.1 of the License, or (at your option) any later version.
 11  
  *
 12  
  * This library is distributed in the hope that it will be useful,
 13  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  
  * Lesser General Public License for more details.
 16  
  *
 17  
  * You should have received a copy of the GNU Lesser General Public
 18  
  * License along with this library; if not, write to the Free Software
 19  
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 20  
  * -----------------------------
 21  
  * Contact:  ohtu@cs.helsinki.fi
 22  
  * -----------------------------
 23  
  *
 24  
  */
 25  
 
 26  
 
 27  
 package org.jfree.data.som;
 28  
 
 29  
 import java.util.*;
 30  
 import java.awt.Color;
 31  
 import java.io.Serializable;
 32  
 
 33  
 import org.jfree.data.general.AbstractDataset;
 34  
 
 35  
 
 36  
 /**
 37  
  * A dataset for dealing with SOM-map-cells.
 38  
  *
 39  
  * @author  viski-project, Department of Computer Science, Univ. Helsinki
 40  
  */
 41  
 public class SOMDataset extends AbstractDataset implements Cloneable, Serializable {
 42  
 
 43  
     /** Datastorage. */
 44  
     protected SOMDataItem[][] data;
 45  
 
 46  
     /**
 47  
      * Creates a new SOMDataset with given columns and rows.
 48  
      * 
 49  
      * @param columns  the number of columns.
 50  
      * @param rows  the number of rows.
 51  
      * @throws IllegalArgumentException If columns <= 0 or rows <= 0
 52  
      */
 53  65
     public SOMDataset(int columns, int rows) throws IllegalArgumentException {
 54  65
         if (columns <= 0)
 55  5
             throw new IllegalArgumentException("Non-positive column count given to SOMDataset");
 56  60
         if (rows <= 0)
 57  2
             throw new IllegalArgumentException("Non-positive row count given to SOMDataset");
 58  58
         data = new SOMDataItem[columns][rows];
 59  58
     }
 60  
 
 61  
     /**
 62  
      * Returns the value at a specific (x,y) point in the datamatrix.
 63  
      *
 64  
      * @return  A SOMDataItem.
 65  
      * @throws IndexOutOfBoundsException
 66  
      */
 67  
     public SOMDataItem getValue(int x, int y) throws IndexOutOfBoundsException {
 68  446
         return data[x][y];
 69  
     }
 70  
 
 71  
     /**
 72  
      * Returns the number of columns in a SOMDataset.
 73  
      *
 74  
      * @return  The number of columns.
 75  
      */
 76  
     public int getColumnCount() {
 77  305
         return data.length;
 78  
     }
 79  
 
 80  
     /**
 81  
      * Returns the number of rows in a SOMDataset.
 82  
      *
 83  
      * @return  The number of rows.
 84  
      */
 85  
     public int getRowCount() {
 86  327
         return data[0].length;
 87  
     }
 88  
 
 89  
     /**
 90  
      * Creates a new SOMDataItem from the params and adds it to the dataset.
 91  
      *
 92  
      * @param x  the x-coordinate to add to in the matrix.
 93  
      * @param y  the y-coordinate to add to in the matrix.
 94  
      * @param color  the color of the dataitem.
 95  
      * @param description  the textual description of the dataitem.
 96  
      * @param neuronWeights  the numerical data of the dataitem.
 97  
      *
 98  
      * @throws IndexOutOfBoundsException
 99  
      */
 100  
     public void addValue(int x, int y, Color color, String[] description, double[] neuronWeights) throws IndexOutOfBoundsException {
 101  142
         data[x][y] = new SOMDataItem(color, description, neuronWeights);
 102  133
     }
 103  
 
 104  
     /**
 105  
      * Adds a SOMDataItem to the dataset.
 106  
      *
 107  
      * @param x  the x-coordinate to add to in the matrix.
 108  
      * @param y  the y-coordinate to add to in the matrix.
 109  
      * @param item  the SOMDataItem to add.
 110  
      *
 111  
      * @throws IndexOutOfBoundsException
 112  
      * @throws NullPointerException
 113  
      */
 114  
     public void addValue(int x, int y, SOMDataItem item) throws IndexOutOfBoundsException {
 115  4
         if (item == null)
 116  1
             throw new NullPointerException("item given to addValue was null.");
 117  3
         data[x][y] = item;
 118  3
     }
 119  
 
 120  
     /**
 121  
      * Returns the neighbours of a dataitem in a {@link List}-object. 
 122  
      * The distances are Euclidean distances
 123  
      * between the RGB-values of this data item and all other data items.
 124  
      *
 125  
      * @param x  the x-coordinate in the matrix to start the search from.
 126  
      * @param y  the y-coordinate in the matrix to start the search from.
 127  
      * @param maxDistance  the distance between a neighbour (ie. similar color) and a non-neighbour
 128  
      * @param includeCenter  Include the item at (x,y) in the list
 129  
      *
 130  
      * @return The list of neighbours.
 131  
      * @throws IndexOutOfBoundsException
 132  
      * @throws IllegalArgumentException If maxDistance < 0
 133  
      */
 134  
     public List getNeighbors(int x, int y, int maxDistance, boolean includeCenter)
 135  
     throws IndexOutOfBoundsException, IllegalArgumentException {
 136  22
         SOMDataItem center = getValue(x, y);
 137  
         
 138  22
         return getNeighbors(center, maxDistance, includeCenter);
 139  
     }
 140  
 
 141  
     /**
 142  
      * Returns the neighbours of a dataitem in a {@link List}-object. 
 143  
      * The distances are Euclidean distances
 144  
      * between the RGB-values of this data item and all other data items.
 145  
      *
 146  
      * @param center the cell to which all other cells are compared
 147  
      * @param maxDistance  the distance between a neighbour (ie. similar color) and a non-neighbour
 148  
      * @param includeCenter  Include center in the list
 149  
      *
 150  
      * @return The list of neighbours.
 151  
      * @throws NullPointerException If center is null.
 152  
      * @throws IllegalArgumentException If maxDistance < 0.
 153  
      */
 154  
     public List getNeighbors(SOMDataItem center, int maxDistance, boolean includeCenter) 
 155  
     throws IllegalArgumentException, NullPointerException {
 156  24
         if (center == null)
 157  1
             throw new NullPointerException("center given to getNeighbors() was null");
 158  23
         if (maxDistance < 0)
 159  2
             throw new IllegalArgumentException("maxDistance given to getNeighbors() was negative.");
 160  21
         Color centerColor = center.getColor();
 161  21
         LinkedList list = new LinkedList();
 162  
 
 163  21
         Iterator i = new SOMDatasetIterator(this);
 164  107
         while (i.hasNext()) {
 165  86
             SOMDataItem item = (SOMDataItem) i.next();
 166  86
             if (includeCenter || item != center) {
 167  74
                 double diff = colorDistance(item.getColor(), centerColor);
 168  74
                 if (diff <= maxDistance)
 169  43
                     list.add(item);
 170  
             }
 171  86
         }
 172  
 
 173  21
         return list;
 174  
     }
 175  
 
 176  
     /**
 177  
      * This method calculates the distance between two sets of integer color-values.
 178  
      *
 179  
      * @return  The difference in color-values.
 180  
      */
 181  
     private double colorDistance(Color color1, Color color2) {
 182  74
         int r1 = color1.getRed();
 183  74
         int g1 = color1.getGreen();
 184  74
         int b1 = color1.getBlue();
 185  
 
 186  74
         int r2 = color2.getRed();
 187  74
         int g2 = color2.getGreen();
 188  74
         int b2 = color2.getBlue();
 189  
 
 190  74
         return Math.sqrt((r1-r2)*(r1-r2)+(g1-g2)*(g1-g2)+(b1-b2)*(b1-b2));
 191  
     }
 192  
     
 193  
     /**
 194  
      * Returns a {@link List} of {@link SOMDataItem} objects the are contained
 195  
      * inside the rectangle defined by two {@link SOMDataItem} objects.
 196  
      *
 197  
      * @param item1 corner of the rectangle
 198  
      * @param item2 corner of the rectangle
 199  
      *
 200  
      * @return The list of {@link SOMDataItem}s inside the area.
 201  
      * @throws NullPointerException If item1 == null or item2 == null
 202  
      * @throws IllegalArgumentException If item1 or item2 do not belong to this dataset.
 203  
      */
 204  
     public List getArea(SOMDataItem item1, SOMDataItem item2) 
 205  
     throws IllegalArgumentException, NullPointerException {
 206  12
         if (item1 == null || item2 == null)
 207  2
             throw new NullPointerException("item1 or item2 given to getArea() was null");
 208  10
         int[] xy1 = getCoordinates(item1);
 209  10
         int[] xy2 = getCoordinates(item2);
 210  
         
 211  10
         if (xy1 == null || xy2 == null)
 212  2
             throw new IllegalArgumentException();
 213  
         
 214  8
         int width = Math.abs(xy1[0] - xy2[0]) + 1;
 215  8
         int height = Math.abs(xy1[1] - xy2[1]) + 1;
 216  8
         int startX = Math.min(xy1[0], xy2[0]);
 217  8
         int startY = Math.min(xy1[1], xy2[1]);
 218  8
         LinkedList list = new LinkedList();
 219  
         
 220  23
         for (int y=0; y < height; ++y) {
 221  41
             for (int x=0; x < width; ++x) {
 222  26
                 list.add(this.data[startX + x][startY + y]);
 223  
             }
 224  
         }
 225  
         
 226  8
         return list;
 227  
     }
 228  
     
 229  
     /**
 230  
      * Returns the coordinates of a SOMDataItem.
 231  
      *
 232  
      * @param item  the item whose coordinates we want.
 233  
      * 
 234  
      * @return  The coordinates.
 235  
      */
 236  
     private int[] getCoordinates(SOMDataItem item) {
 237  20
         int[] xy = new int[2];
 238  
         
 239  33
         for (int y=0; y < this.data[0].length; ++y) {
 240  66
             for (int x=0; x < this.data.length; ++x) {
 241  53
                 if (item == this.data[x][y]) {
 242  18
                     xy[0] = x;
 243  18
                     xy[1] = y;
 244  18
                     return xy;
 245  
                 }
 246  
             }
 247  
         }
 248  
         
 249  2
         return null;
 250  
     }
 251  
     
 252  
     /**
 253  
      * This method changes the color hue of all dataitems in a dataset for
 254  
      * given amount, negative or positive. The  color-values of each dataitem
 255  
      * are retrieved, changed and new rgb-values are calculated and set.
 256  
      *
 257  
      * @param angle  the amount to increase the hue angle.
 258  
      * @throws IllegalArgumentException If Math.abs(angle) >= 360.
 259  
      */
 260  
     public void changeHueValues(int angle) 
 261  
     throws IllegalArgumentException {
 262  12
         if (Math.abs(angle) > 360)
 263  2
             throw new IllegalArgumentException("angle value given to changeHueValues() was not in [-360,360].");
 264  10
         Iterator i = new SOMDatasetIterator(this);
 265  54
         while (i.hasNext()) {
 266  44
             SOMDataItem item = (SOMDataItem)i.next();
 267  
             
 268  44
             if (item != null) {
 269  44
                 Color c = item.getColor();
 270  44
                 float[] hsb = Color.RGBtoHSB(
 271  
                         c.getRed(),
 272  
                         c.getGreen(),
 273  
                         c.getBlue(),
 274  
                         null);
 275  
                 
 276  44
                 hsb[0] += angle/360.0 + 1.0;
 277  44
                 hsb[0] %= 1.0;
 278  44
                 item.setColor(Color.getHSBColor(hsb[0], hsb[1], hsb[2]));
 279  
             }
 280  44
         }
 281  10
     }
 282  
 
 283  
     /**
 284  
      * This method returns an iterator that iterates all it's dataitems
 285  
      *
 286  
      * @return iterator
 287  
      */
 288  
     public Iterator iterator() {
 289  24
         return new SOMDatasetIterator(this);
 290  
     }
 291  
     
 292  
     /**
 293  
      * Deselects all the dataitems in this SOMDataset.
 294  
      */
 295  
     public void deselectAll() {
 296  12
         Iterator i = iterator();
 297  76
         while (i.hasNext()) {
 298  65
             SOMDataItem item = (SOMDataItem)i.next();
 299  65
             item.setSelected(false);
 300  64
         }
 301  11
     }
 302  
     
 303  
     /**
 304  
      * An inner class to deal with SOMDataItem-objects in the SOMDataset. This
 305  
      * class implements the {@link Iterator} interface
 306  
      */
 307  
     private class SOMDatasetIterator implements Iterator {
 308  
         private SOMDataset dataset;
 309  
         private int x;
 310  
         private int y;
 311  
 
 312  
         /**
 313  
          * Creates a new SOMDatasetIterator for a dataset.
 314  
          *
 315  
          * @param dataset  the SOMDataset to be iterated.
 316  
          */
 317  55
         public SOMDatasetIterator(SOMDataset dataset) {
 318  55
             this.dataset = dataset;
 319  55
             this.x = 0;
 320  55
             this.y = 0;
 321  55
         }
 322  
             
 323  
         /**
 324  
          * Returns false, if the pointer already is at the last item.
 325  
          *
 326  
          * @return  A boolean.
 327  
          */
 328  
         public boolean hasNext() {
 329  266
             return !((this.y == this.dataset.getRowCount()) && (this.x == 0));
 330  
         }
 331  
 
 332  
         /**
 333  
          * Moves the pointer to the next item.
 334  
          *
 335  
          * @return  The SOMDataItem.
 336  
          * @throws  NoSuchElementException
 337  
          */
 338  
         public Object next() {
 339  
             SOMDataItem item;
 340  230
             item = this.dataset.getValue(this.x++, this.y);
 341  
 //            if (item == null)
 342  
 //                throw new NoSuchElementException();
 343  
 
 344  230
             this.x %= this.dataset.getColumnCount();
 345  230
             if (this.x == 0)
 346  116
                 this.y++;
 347  
             
 348  230
             return item;
 349  
         }
 350  
 
 351  
         /**
 352  
          * Should remove an item from the iteration list.
 353  
          * This method does nothing.
 354  
          */
 355  
         public void remove() throws UnsupportedOperationException {
 356  1
             throw new UnsupportedOperationException("SOMDataset iterators do not implement remove().");
 357  
         }
 358  
 
 359  
     }
 360  
     
 361  
     /**
 362  
      * Tests if this object is equal to another.
 363  
      *
 364  
      * @param obj  the other object.
 365  
      *
 366  
      * @return A boolean.
 367  
      */
 368  
     public boolean equals(Object obj) {
 369  12
         if (obj == this) {
 370  5
             return true;
 371  
         }
 372  
 
 373  7
         if (!(obj instanceof SOMDataset)) {
 374  1
             return false;
 375  
         }
 376  6
         SOMDataset that = (SOMDataset) obj;
 377  6
         int cols = this.getColumnCount();
 378  6
         int rows = this.getRowCount();
 379  6
         if (that.getColumnCount() != cols ||
 380  
                 that.getRowCount() != rows) {
 381  2
             return false;
 382  
         }
 383  
 
 384  4
         Iterator i1 = this.iterator();
 385  4
         Iterator i2 = that.iterator();
 386  14
         while (i1.hasNext()) {
 387  11
             SOMDataItem item1 = (SOMDataItem)i1.next();
 388  11
             SOMDataItem item2 = (SOMDataItem)i2.next();
 389  11
             if (item1 == null && item2 == null) {
 390  
                 ;
 391  2
             }
 392  9
             else if (item1 == null || item2 == null || 
 393  
                      item1.equals(item2) == false)
 394  1
                 return false;
 395  10
         }
 396  
         
 397  3
         return true;
 398  
     }
 399  
     
 400  
     /**
 401  
      * Returns a clone of the dataset.
 402  
      * 
 403  
      * @return A clone.
 404  
      * 
 405  
      * @throws CloneNotSupportedException This class will not throw this 
 406  
      *         exception, but subclasses (if any) might.
 407  
      */
 408  
     public Object clone() throws CloneNotSupportedException {
 409  1
         SOMDataset clone = (SOMDataset) super.clone();
 410  1
         clone.data = (SOMDataItem[][]) this.data.clone();
 411  1
         return clone;    
 412  
     }
 413  
     
 414  
 }
 415