View Javadoc
1 /* ------------------------------------------------------------------- 2 GeoVISTA Center (Penn State, Dept. of Geography) 3 Java source file for the class VisualClassifier 4 Copyright (c), 2002, GeoVISTA Center 5 All Rights Reserved. 6 Original Author: Frank Hardisty 7 $Author: hardisty $ 8 $Id: VisualClassifier.java,v 1.5 2003/07/18 18:15:48 hardisty Exp $ 9 $Date: 2003/07/18 18:15:48 $ 10 Reference: Document no: 11 ___ ___ 12 ------------------------------------------------------------------- * 13 14 */ 15 16 17 package edu.psu.geovista.symbolization; 18 19 //import edu.psu.geovista.ui.panel.*; 20 import java.awt.*; 21 import java.awt.event.*; 22 import java.awt.geom.*; 23 import java.awt.image.*; 24 import java.util.*; 25 26 import javax.swing.*; 27 import javax.swing.event.*; 28 29 import edu.psu.geovista.classification.*; 30 import edu.psu.geovista.ui.event.*; 31 import edu.psu.geovista.common.event.*; 32 import edu.psu.geovista.common.color.Pallet; 33 34 //import javax.swing.colorchooser.*; 35 36 //public class VisualClassifier extends JPanel implements ActionListener { 37 public class VisualClassifier extends JPanel implements ActionListener, ComponentListener, 38 PalletListener{ 39 //Jin Chen: for extending purpose, change private to protected for following fields: 40 // symbolizationPanel,colors,dataColors,colorerLinear,colorClasser,classPick 41 protected ColorRampPicker symbolizationPanel; 42 //XXX in future, we want to support much beyond colors. 43 protected transient Color[] colors; 44 protected transient Color[] dataColors; 45 private transient Shape[] symbols; 46 47 public transient boolean[] anchored; 48 49 private transient double[] data; 50 private transient int[] classificationIndex; 51 52 53 transient private int nClasses; 54 transient private int nSymbols; 55 transient private boolean update; 56 transient private boolean interpolate; 57 transient private boolean setupFinished; 58 59 private transient JCheckBox updateBox; 60 private transient JCheckBox interpolateBox; 61 public static final String COMMAND_COLORS_CHANGED = "colors"; 62 public static final String COMMAND_BEAN_REGISTERED = "hi!"; 63 64 private int currOrientation = this.X_AXIS; 65 public static final int X_AXIS = 0; 66 public static final int Y_AXIS = 1; 67 public transient boolean orientationInParentIsX = false; 68 69 70 protected ColorSymbolizerLinear colorerLinear; 71 protected ColorSymbolClassificationSimple colorClasser; 72 73 protected ClassifierPicker classPick; 74 75 private transient TexturePaint texPaint; 76 private transient int oldIndication = 0; 77 78 79 public VisualClassifier() { 80 super(); 81 this.addComponentListener(this); 82 this.colorClasser = new ColorSymbolClassificationSimple(); 83 this.colorerLinear = new ColorSymbolizerLinear(); 84 this.setupFinished = false; 85 this.nClasses = ColorRampPicker.DEFAULT_NUM_SWATCHES; 86 this.update = true; 87 this.interpolate = true; 88 89 this.classPick = new ClassifierPicker(); 90 classPick.addActionListener(this); 91 92 this.makeSymbolizationPanel(); 93 this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 94 this.add(classPick); 95 this.setVariableChooserMode(ClassifierPicker.VARIABLE_CHOOSER_MODE_ACTIVE); 96 //this.add(classificationPanel); 97 this.add(symbolizationPanel); 98 this.setupFinished = true; 99 this.makeColors(); 100 this.setPreferredSize(new Dimension(300,40)); 101 /* 102 int prefHeight = (int)this.classPick.getPreferredSize().getHeight(); 103 prefHeight = prefHeight + (int)this.symbolizationPanel.getPreferredSize().getHeight(); 104 int prefWidth = (int)this.classPick.getPreferredSize().getWidth(); 105 if (prefWidth > (int)this.symbolizationPanel.getPreferredSize().getWidth()) { 106 prefWidth = (int)this.symbolizationPanel.getPreferredSize().getWidth(); //take the smaller one 107 } 108 this.setPreferredSize(new Dimension(prefWidth, prefHeight)); 109 */ 110 this.revalidate(); 111 this.makeTexPaint(); 112 } 113 114 private void makeTexPaint(){ 115 116 int texSize = 4; 117 Rectangle2D.Float rect = new Rectangle2D.Float(0,0,texSize,texSize); 118 BufferedImage buff = new BufferedImage(texSize,texSize,BufferedImage.TYPE_INT_ARGB); 119 Graphics2D g2 = buff.createGraphics(); 120 Color trans = new Color(0,0,0,0); //clear black 121 g2.setColor(trans); 122 g2.fillRect(0,0,texSize,texSize); 123 g2.setColor(Color.blue); 124 g2.drawLine(0,0,32,32); 125 126 texPaint = new TexturePaint(buff,rect); 127 128 } 129 private void makeSymbolizationPanel() { 130 symbolizationPanel = new ColorRampPicker(); 131 this.add(symbolizationPanel); 132 symbolizationPanel.addActionListener(this); 133 } 134 135 private void makeColors(){ 136 Color[] pickerColors = this.symbolizationPanel.getColors(); 137 boolean[] pickerAnchors = this.symbolizationPanel.getAnchored(); 138 //now we interpolate...linearly 139 int nPicks = pickerColors.length; 140 double picksPerColor = (double)nPicks/(double)this.nClasses; 141 if (this.colors == null){ 142 this.colors = new Color[nClasses]; 143 } else if (this.colors.length != nClasses) { 144 this.colors = new Color[nClasses]; 145 } 146 147 for (int i = 0; i < nClasses; i++) { 148 double whichColor = (double)i * picksPerColor; 149 int index = (int)Math.floor(whichColor); 150 //System.out.println("i = " + i + "index = " + index); 151 this.colors[i] = pickerColors[index]; 152 153 } 154 if (this.interpolate) { 155 //for each lock in the picker, find the class that is closest. 156 double colorsPerPick = (double)(this.nClasses-1)/(double)(nPicks-1); 157 //int[] newAnchors = new int[pickerAnchors.length]; 158 Vector newAnchors = new Vector(); 159 for (int i = 0; i < pickerAnchors.length; i++) { 160 double whichClass = (double)i * colorsPerPick; 161 int aClass = (int)Math.round(whichClass); 162 if (pickerAnchors[i]){ 163 Integer Ind = new Integer(aClass); 164 newAnchors.add(Ind); 165 } 166 } 167 168 boolean[] colorAnchors = new boolean[nClasses]; 169 if (newAnchors.size() > 2) { 170 for (Enumeration e = newAnchors.elements() ; e.hasMoreElements() ;) { 171 Integer ind = (Integer)e.nextElement(); 172 colorAnchors[ind.intValue()] = true; 173 } 174 175 colorAnchors[0] = true; 176 colorAnchors[colorAnchors.length -1] = true; 177 } else if (newAnchors.size() == 2) { 178 colorAnchors[0] = true; 179 colorAnchors[colorAnchors.length -1] = true; 180 } else if (newAnchors.size() == 1) { 181 colorAnchors[0] = true; 182 } 183 //now find those durn colors! 184 this.symbolizationPanel.getRamp().rampColors(this.colors,colorAnchors); 185 this.colorerLinear.setRampingColors(this.colors); 186 this.colorerLinear.setAnchors(colorAnchors); 187 this.colorClasser.setColorer(this.colorerLinear); 188 }//end if interpolate 189 } 190 public Color[] findDataColors(){ 191 if (this.classPick.getDataSet() == null){ 192 return null; 193 } 194 int currVar = this.classPick.getCurrVariableIndex(); 195 Classifier classer = this.classPick.getClasser(); 196 double[] data = this.classPick.getDataSet().getNumericDataAsDouble(currVar); 197 int[] classedData = classer.classify(data,classPick.getNClasses()); 198 if (this.dataColors == null || this.dataColors.length != classedData.length){ 199 this.dataColors = new Color[classedData.length]; 200 } 201 this.colors = this.symbolizationPanel.getColors(); 202 for (int i = 0; i < classedData.length; i++){ 203 int aClass = classedData[i]; 204 if (aClass < 0) aClass = 0;//$$$ egregious hack 205 Color c = this.colors[aClass]; 206 this.dataColors[i] = c; 207 } 208 return this.dataColors; 209 } 210 211 212 /*** Listens to the check boxen. */ 213 class CheckBoxListener implements ItemListener { 214 public void itemStateChanged(ItemEvent e) { 215 if (e.getSource().equals(VisualClassifier.this.updateBox)){ 216 if (e.getStateChange() == ItemEvent.SELECTED && VisualClassifier.this.setupFinished){ 217 VisualClassifier.this.update = true; 218 VisualClassifier.this.makeColors(); 219 VisualClassifier.this.fireActionPerformed(VisualClassifier.COMMAND_COLORS_CHANGED); 220 VisualClassifier.this.fireColorClassifierPerformed(); 221 VisualClassifier.this.fireColorArrayChanged(); 222 223 } else if (e.getStateChange() == ItemEvent.DESELECTED){ 224 225 VisualClassifier.this.update = false; 226 } 227 } else if (e.getSource().equals(VisualClassifier.this.interpolateBox)){ 228 if (e.getStateChange() == ItemEvent.SELECTED && VisualClassifier.this.setupFinished){ 229 VisualClassifier.this.interpolate = true; 230 VisualClassifier.this.makeColors(); 231 VisualClassifier.this.fireActionPerformed(VisualClassifier.COMMAND_COLORS_CHANGED); 232 VisualClassifier.this.fireColorClassifierPerformed(); 233 VisualClassifier.this.fireColorArrayChanged(); 234 235 } else if (e.getStateChange() == ItemEvent.DESELECTED){ 236 VisualClassifier.this.interpolate = false; 237 VisualClassifier.this.makeColors(); 238 VisualClassifier.this.fireActionPerformed(VisualClassifier.COMMAND_COLORS_CHANGED); 239 VisualClassifier.this.fireColorClassifierPerformed(); 240 VisualClassifier.this.fireColorArrayChanged(); 241 } 242 } 243 } 244 } 245 class SliderListener implements ChangeListener { 246 public void stateChanged(ChangeEvent e) { 247 JSlider source = (JSlider)e.getSource(); 248 //if (!source.getValueIsAdjusting()) { 249 250 int fps = (int)source.getValue(); 251 if (fps == 0) { 252 //if (!frozen) stopAnimation(); 253 } else { 254 VisualClassifier.this.symbolizationPanel.setNSwatches(fps); 255 VisualClassifier.this.nClasses = fps; 256 VisualClassifier.this.makeColors(); 257 VisualClassifier.this.fireActionPerformed(VisualClassifier.COMMAND_COLORS_CHANGED); 258 VisualClassifier.this.fireColorClassifierPerformed(); 259 VisualClassifier.this.fireColorArrayChanged(); 260 } 261 //} 262 } 263 } 264 public ColorRampPicker getSymbolizationPanel() { 265 return symbolizationPanel; 266 } 267 public void setSymbolizationPanel(ColorRampPicker symbolizationPanel) { 268 this.symbolizationPanel = symbolizationPanel; 269 this.makeColors(); 270 System.out.println("VC, settingSymbolizationPanel"); 271 } 272 public ColorSymbolClassification getColorSymbolClassification(){ 273 return this.colorClasser; 274 } 275 public void setColorSymbolClassification(ColorSymbolClassification colorClasser){ 276 this.colorClasser = (ColorSymbolClassificationSimple)colorClasser; 277 } 278 279 public ColorSymbolizer getColorSymbolizer(){ 280 System.out.println("VC, gettingColorSymbolizer"); 281 return this.colorerLinear; 282 } 283 284 285 286 public void setColorSymbolizer(ColorSymbolizer colorerLinear){ 287 this.colorerLinear = (ColorSymbolizerLinear)colorerLinear; 288 } 289 290 public Color[] getColorForObservations(){ 291 return this.findDataColors(); 292 } 293 public Color[] getColors() { 294 //System.out.println("VC, gettingColors"); 295 this.colors = this.symbolizationPanel.getColors(); 296 return this.colors; 297 } 298 299 public void setColors(Color[] colors) { 300 this.colors = colors; 301 } 302 303 public void palletChanged(PalletEvent e){ 304 Pallet pal = e.getPallet(); 305 int maxColors = pal.getRecommendedMaxLength(); 306 System.out.println("max colors = " + maxColors); 307 308 //we can't go over the max, or it blows null exceptions 309 //so, we interpolate.... 310 311 int numClasses = this.classPick.getNClasses(); 312 Color[] cols = null; 313 if (numClasses <= maxColors){ 314 cols = pal.getColors(numClasses); 315 } else { 316 //we have more colors wanted than the pallet can give us 317 //todo: make this work 318 //this.assignColors 319 cols = pal.getColors(numClasses); 320 } 321 322 323 this.setColors(cols); 324 this.symbolizationPanel.setColors(cols); 325 this.revalidate(); 326 this.repaint(); 327 } 328 329 private Color[] assignColors(Color[] currColors, int numWanted){ 330 Color[] newColors = new Color[numWanted]; 331 332 return newColors; 333 } 334 public void actionPerformed(ActionEvent e) { 335 String command = e.getActionCommand(); 336 if (command == ColorRampPicker.COMMAND_SWATCH_COLOR_CHANGED){ 337 this.makeColors(); 338 this.fireActionPerformed(this.COMMAND_COLORS_CHANGED); 339 this.fireColorClassifierPerformed(); 340 VisualClassifier.this.fireColorArrayChanged(); 341 } else if (command == this.classPick.COMMAND_CLASSES_CHANGED) { 342 int nClasses = this.classPick.getNClasses(); 343 this.symbolizationPanel.setNSwatches(nClasses); 344 this.nClasses = nClasses; 345 this.makeColors(); 346 this.fireActionPerformed(this.COMMAND_COLORS_CHANGED); 347 this.fireColorClassifierPerformed(); 348 VisualClassifier.this.fireColorArrayChanged(); 349 } else if (command == this.classPick.COMMAND_SELECTED_VARIABLE_CHANGED) { 350 351 this.fireActionPerformed(this.classPick.COMMAND_SELECTED_VARIABLE_CHANGED); 352 this.fireColorArrayChanged(); 353 } else if (command == this.classPick.COMMAND_SELECTED_CLASSIFIER_CHANGED) { 354 //this.colorClasser.setColorer(this.colorerLinear); 355 this.colorClasser.setClasser(this.classPick.getClasser()); 356 fireColorClassifierPerformed(); 357 VisualClassifier.this.fireColorArrayChanged(); 358 } 359 360 //need to pass this along, if we are a FoldupPanel 361 //super.actionPerformed(e); 362 } 363 //start component event handling 364 //note: this class only listens to itself 365 public void componentHidden(ComponentEvent e) {} 366 367 public void componentMoved(ComponentEvent e) {} 368 369 public void componentShown(ComponentEvent e) {} 370 371 public void componentResized(ComponentEvent e) { 372 double pickPrefWidth = this.classPick.getPreferredSize().getWidth(); 373 374 int prefWidth = (int)(pickPrefWidth * 1.5); 375 if (this.getWidth() >= prefWidth) { 376 this.changeOrientation(this.X_AXIS); 377 } else { 378 this.changeOrientation(this.Y_AXIS); 379 } 380 381 } 382 //end component event handling 383 384 public void changeOrientation(int orientation){ 385 if (orientation == this.currOrientation) { 386 return; 387 } else if (orientation == this.X_AXIS) { 388 Component[] comps = new Component[this.getComponentCount()]; 389 for (int i = 0; i < this.getComponentCount(); i++) { 390 comps[i] = this.getComponent(i); 391 } 392 this.setLayout(new BoxLayout(this,BoxLayout.X_AXIS)); 393 for (int i = 0; i < this.getComponentCount(); i++) { 394 this.add(comps[i]); 395 } 396 this.currOrientation = this.X_AXIS; 397 this.setPreferredSize(new Dimension(300,20)); 398 this.revalidate(); 399 } else if (orientation == this.Y_AXIS) { 400 Component[] comps = new Component[this.getComponentCount()]; 401 for (int i = 0; i < this.getComponentCount(); i++) { 402 comps[i] = this.getComponent(i); 403 } 404 this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); 405 for (int i = 0; i < this.getComponentCount(); i++) { 406 this.add(comps[i]); 407 } 408 this.currOrientation = this.Y_AXIS; 409 this.setPreferredSize(new Dimension(300,40)); 410 this.revalidate(); 411 } 412 413 } 414 415 /*** 416 * implements ColorArrayListener 417 */ 418 public void addColorArrayListener(ColorArrayListener l) { 419 listenerList.add(ColorArrayListener.class, l); 420 //this.fireColorArrayChanged(); //so that if any class registers 421 422 //it gets an event 423 } 424 425 /*** 426 * removes an ColorArrayListener from the component 427 */ 428 public void removeColorArrayListener(ColorArrayListener l) { 429 listenerList.remove(ColorArrayListener.class, l); 430 } 431 432 /*** 433 * Notify all listeners that have registered interest for 434 * notification on this event type. The event instance 435 * is lazily created using the parameters passed into 436 * the fire method. 437 * @see EventListenerList 438 */ 439 private void fireColorArrayChanged() { 440 // Guaranteed to return a non-null array 441 Object[] listeners = listenerList.getListenerList(); 442 ColorArrayEvent e = null; 443 444 // Process the listeners last to first, notifying 445 // those that are interested in this event 446 for (int i = listeners.length - 2; i >= 0; i -= 2) { 447 if (listeners[i] == ColorArrayListener.class) { 448 // Lazily create the event: 449 if (e == null) { 450 e = new ColorArrayEvent(this, this.findDataColors()); 451 } 452 453 ((ColorArrayListener) listeners[i + 1]).colorArrayChanged(e); 454 } 455 } //next i 456 } 457 //} 458 /*** 459 * implements ColorClassifierListener 460 */ 461 public void addColorClassifierListener (ColorClassifierListener l) { 462 listenerList.add(ColorClassifierListener.class, l); 463 this.fireColorClassifierPerformed();//so that if any class registers 464 //it gets an event 465 } 466 467 /*** 468 * removes an ColorClassifierListener from the component 469 */ 470 public void removeColorClassifierListener (ColorClassifierListener l) { 471 listenerList.remove(ColorClassifierListener.class, l); 472 } 473 /*** 474 * Notify all listeners that have registered interest for 475 * notification on this event type. The event instance 476 * is lazily created using the parameters passed into 477 * the fire method. 478 * @see EventListenerList 479 */ 480 private void fireColorClassifierPerformed () { 481 if (update) { 482 // Guaranteed to return a non-null array 483 Object[] listeners = listenerList.getListenerList(); 484 ColorClassifierEvent e = null; 485 // Process the listeners last to first, notifying 486 // those that are interested in this event 487 for (int i = listeners.length - 2; i >= 0; i -= 2) { 488 if (listeners[i] == ColorClassifierListener.class) { 489 // Lazily create the event: 490 if (e == null) { 491 e = new ColorClassifierEvent(this,this.getColorSymbolClassification()); 492 } 493 if (this.orientationInParentIsX == true){ 494 e.setOrientation(e.SOURCE_ORIENTATION_X); 495 }else { 496 e.setOrientation(e.SOURCE_ORIENTATION_Y); 497 } 498 ((ColorClassifierListener)listeners[i + 1]).colorClassifierChanged(e); 499 } 500 }//next i 501 }//end if 502 } 503 /*** 504 * implements ActionListener 505 */ 506 public void addActionListener (ActionListener l) { 507 listenerList.add(ActionListener.class, l); 508 this.fireActionPerformed(this.COMMAND_BEAN_REGISTERED); 509 } 510 511 /*** 512 * removes an ActionListener from the component 513 */ 514 public void removeActionListener (ActionListener l) { 515 listenerList.remove(ActionListener.class, l); 516 } 517 /*** 518 * Notify all listeners that have registered interest for 519 * notification on this event type. The event instance 520 * is lazily created using the parameters passed into 521 * the fire method. 522 * @see EventListenerList 523 */ 524 private void fireActionPerformed (String command) { 525 if (update) { 526 // Guaranteed to return a non-null array 527 Object[] listeners = listenerList.getListenerList(); 528 ActionEvent e = null; 529 // Process the listeners last to first, notifying 530 // those that are interested in this event 531 for (int i = listeners.length - 2; i >= 0; i -= 2) { 532 if (listeners[i] == ActionListener.class) { 533 // Lazily create the event: 534 if (e == null) { 535 e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, command); 536 } 537 ((ActionListener)listeners[i + 1]).actionPerformed(e); 538 } 539 }//next i 540 }//end if 541 } 542 543 public void setIndicatedClass(int indicClass) { 544 //clear old indication 545 //if it still exists 546 if (this.oldIndication < this.symbolizationPanel.getPanSet().length) { 547 this.symbolizationPanel.getPanSet()[this.oldIndication].setTexPaint(null); 548 } 549 550 if (indicClass < 0) { //used for null or out of range indication 551 this.repaint(); //clear old indication 552 return; 553 } 554 if (indicClass >= this.symbolizationPanel.getPanSet().length) { 555 this.repaint(); //clear old indication 556 return; 557 } 558 559 this.symbolizationPanel.getPanSet()[indicClass].setTexPaint(this.texPaint); 560 //System.out.println("bivarviz, indicated swatch = " + indicSwatch); 561 this.oldIndication = indicClass; 562 this.repaint(); 563 } 564 public boolean[] getAnchored() { 565 return anchored; 566 } 567 public void setAnchored(boolean[] anchored) { 568 this.anchored = anchored; 569 } 570 public int[] getClassificationIndex() { 571 return classificationIndex; 572 } 573 public void setClassificationIndex(int[] classificationIndex) { 574 this.classificationIndex = classificationIndex; 575 } 576 public ClassifierPicker getClassPick() { 577 return classPick; 578 } 579 public void setClassPick(ClassifierPicker classPick) { 580 this.classPick = classPick; 581 } 582 public ColorSymbolClassificationSimple getColorClasser() { 583 return colorClasser; 584 } 585 public void setColorClasser(ColorSymbolClassificationSimple colorClasser) { 586 this.colorClasser = colorClasser; 587 } 588 public ColorSymbolizerLinear getColorerLinear() { 589 return colorerLinear; 590 } 591 public void setColorerLinear(ColorSymbolizerLinear colorerLinear) { 592 this.colorerLinear = colorerLinear; 593 } 594 public int getCurrOrientation() { 595 return currOrientation; 596 } 597 public void setCurrOrientation(int currOrientation) { 598 this.currOrientation = currOrientation; 599 } 600 public int getVariableChooserMode() { 601 return this.classPick.getVariableChooserMode(); 602 } 603 public void setVariableChooserMode(int variableChooserMode) { 604 if (this.classPick.getVariableChooserMode() != variableChooserMode) { 605 this.classPick.setVariableChooserMode(variableChooserMode); 606 607 } 608 } 609 610 public void setCurrVariableIndex(int index){ 611 this.classPick.setCurrVariableIndex(index); 612 } 613 614 public void setData(Object[] data) { 615 this.classPick.setData(data); 616 } 617 public int getCurrVariableIndex() { 618 return this.classPick.getCurrVariableIndex(); 619 } 620 621 public void setHighColor(Color c){ 622 this.symbolizationPanel.setHighColor(c); 623 } 624 public void setOrientationInParentIsX(boolean orientationInParentIsX) { 625 this.orientationInParentIsX = orientationInParentIsX; 626 } 627 628 }

This page was automatically generated by Maven