001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2022, by David Gilbert and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ---------------- 028 * MeterNeedle.java 029 * ---------------- 030 * (C) Copyright 2002-2021, by the Australian Antarctic Division and 031 * Contributors. 032 * 033 * Original Author: Bryan Scott (for the Australian Antarctic Division); 034 * Contributor(s): David Gilbert; 035 * Nicolas Brodu (for Astrium and EADS Corporate Research 036 * Center); 037 * 038 */ 039 040package org.jfree.chart.plot.compass; 041 042import java.awt.BasicStroke; 043import java.awt.Color; 044import java.awt.Graphics2D; 045import java.awt.Paint; 046import java.awt.Shape; 047import java.awt.Stroke; 048import java.awt.geom.AffineTransform; 049import java.awt.geom.Point2D; 050import java.awt.geom.Rectangle2D; 051import java.io.IOException; 052import java.io.ObjectInputStream; 053import java.io.ObjectOutputStream; 054import java.io.Serializable; 055import java.util.Objects; 056 057import org.jfree.chart.internal.HashUtils; 058import org.jfree.chart.internal.PaintUtils; 059import org.jfree.chart.internal.SerialUtils; 060 061/** 062 * The base class used to represent the needle on a 063 * {@link org.jfree.chart.plot.CompassPlot}. 064 */ 065public abstract class MeterNeedle implements Serializable { 066 067 /** For serialization. */ 068 private static final long serialVersionUID = 5203064851510951052L; 069 070 /** The outline paint. */ 071 private transient Paint outlinePaint = Color.BLACK; 072 073 /** The outline stroke. */ 074 private transient Stroke outlineStroke = new BasicStroke(2); 075 076 /** The fill paint. */ 077 private transient Paint fillPaint = null; 078 079 /** The highlight paint. */ 080 private transient Paint highlightPaint = null; 081 082 /** The size. */ 083 private int size = 5; 084 085 /** Scalar to apply to locate the rotation x point. */ 086 private double rotateX = 0.5; 087 088 /** Scalar to apply to locate the rotation y point. */ 089 private double rotateY = 0.5; 090 091 /** A transform. */ 092 protected static AffineTransform transform = new AffineTransform(); 093 094 /** 095 * Creates a new needle. 096 */ 097 public MeterNeedle() { 098 this(null, null, null); 099 } 100 101 /** 102 * Creates a new needle. 103 * 104 * @param outline the outline paint ({@code null} permitted). 105 * @param fill the fill paint ({@code null} permitted). 106 * @param highlight the highlight paint ({@code null} permitted). 107 */ 108 public MeterNeedle(Paint outline, Paint fill, Paint highlight) { 109 this.fillPaint = fill; 110 this.highlightPaint = highlight; 111 this.outlinePaint = outline; 112 } 113 114 /** 115 * Returns the outline paint. 116 * 117 * @return The outline paint. 118 */ 119 public Paint getOutlinePaint() { 120 return this.outlinePaint; 121 } 122 123 /** 124 * Sets the outline paint. 125 * 126 * @param p the new paint. 127 */ 128 public void setOutlinePaint(Paint p) { 129 if (p != null) { 130 this.outlinePaint = p; 131 } 132 } 133 134 /** 135 * Returns the outline stroke. 136 * 137 * @return The outline stroke. 138 */ 139 public Stroke getOutlineStroke() { 140 return this.outlineStroke; 141 } 142 143 /** 144 * Sets the outline stroke. 145 * 146 * @param s the new stroke. 147 */ 148 public void setOutlineStroke(Stroke s) { 149 if (s != null) { 150 this.outlineStroke = s; 151 } 152 } 153 154 /** 155 * Returns the fill paint. 156 * 157 * @return The fill paint. 158 */ 159 public Paint getFillPaint() { 160 return this.fillPaint; 161 } 162 163 /** 164 * Sets the fill paint. 165 * 166 * @param p the fill paint. 167 */ 168 public void setFillPaint(Paint p) { 169 if (p != null) { 170 this.fillPaint = p; 171 } 172 } 173 174 /** 175 * Returns the highlight paint. 176 * 177 * @return The highlight paint. 178 */ 179 public Paint getHighlightPaint() { 180 return this.highlightPaint; 181 } 182 183 /** 184 * Sets the highlight paint. 185 * 186 * @param p the highlight paint. 187 */ 188 public void setHighlightPaint(Paint p) { 189 if (p != null) { 190 this.highlightPaint = p; 191 } 192 } 193 194 /** 195 * Returns the scalar used for determining the rotation x value. 196 * 197 * @return The x rotate scalar. 198 */ 199 public double getRotateX() { 200 return this.rotateX; 201 } 202 203 /** 204 * Sets the rotateX value. 205 * 206 * @param x the new value. 207 */ 208 public void setRotateX(double x) { 209 this.rotateX = x; 210 } 211 212 /** 213 * Sets the rotateY value. 214 * 215 * @param y the new value. 216 */ 217 public void setRotateY(double y) { 218 this.rotateY = y; 219 } 220 221 /** 222 * Returns the scalar used for determining the rotation y value. 223 * 224 * @return The y rotate scalar. 225 */ 226 public double getRotateY() { 227 return this.rotateY; 228 } 229 230 /** 231 * Draws the needle. 232 * 233 * @param g2 the graphics device. 234 * @param plotArea the plot area. 235 */ 236 public void draw(Graphics2D g2, Rectangle2D plotArea) { 237 draw(g2, plotArea, 0); 238 } 239 240 /** 241 * Draws the needle. 242 * 243 * @param g2 the graphics device. 244 * @param plotArea the plot area. 245 * @param angle the angle. 246 */ 247 public void draw(Graphics2D g2, Rectangle2D plotArea, double angle) { 248 Point2D.Double pt = new Point2D.Double(); 249 pt.setLocation(plotArea.getMinX() + this.rotateX * plotArea.getWidth(), 250 plotArea.getMinY() + this.rotateY * plotArea.getHeight()); 251 draw(g2, plotArea, pt, angle); 252 } 253 254 /** 255 * Draws the needle. 256 * 257 * @param g2 the graphics device. 258 * @param plotArea the plot area. 259 * @param rotate the rotation point. 260 * @param angle the angle. 261 */ 262 public void draw(Graphics2D g2, Rectangle2D plotArea, Point2D rotate, 263 double angle) { 264 265 Paint savePaint = g2.getColor(); 266 Stroke saveStroke = g2.getStroke(); 267 268 drawNeedle(g2, plotArea, rotate, Math.toRadians(angle)); 269 270 g2.setStroke(saveStroke); 271 g2.setPaint(savePaint); 272 } 273 274 /** 275 * Draws the needle. 276 * 277 * @param g2 the graphics device. 278 * @param plotArea the plot area. 279 * @param rotate the rotation point. 280 * @param angle the angle. 281 */ 282 protected abstract void drawNeedle(Graphics2D g2, Rectangle2D plotArea, 283 Point2D rotate, double angle); 284 285 /** 286 * Displays a shape. 287 * 288 * @param g2 the graphics device. 289 * @param shape the shape. 290 */ 291 protected void defaultDisplay(Graphics2D g2, Shape shape) { 292 if (this.fillPaint != null) { 293 g2.setPaint(this.fillPaint); 294 g2.fill(shape); 295 } 296 297 if (this.outlinePaint != null) { 298 g2.setStroke(this.outlineStroke); 299 g2.setPaint(this.outlinePaint); 300 g2.draw(shape); 301 } 302 } 303 304 /** 305 * Returns the size. 306 * 307 * @return The size. 308 */ 309 public int getSize() { 310 return this.size; 311 } 312 313 /** 314 * Sets the size. 315 * 316 * @param pixels the new size. 317 */ 318 public void setSize(int pixels) { 319 this.size = pixels; 320 } 321 322 /** 323 * Returns the transform. 324 * 325 * @return The transform. 326 */ 327 public AffineTransform getTransform() { 328 return MeterNeedle.transform; 329 } 330 331 /** 332 * Tests another object for equality with this object. 333 * 334 * @param obj the object to test ({@code null} permitted). 335 * 336 * @return A boolean. 337 */ 338 @Override 339 public boolean equals(Object obj) { 340 if (obj == this) { 341 return true; 342 } 343 if (!(obj instanceof MeterNeedle)) { 344 return false; 345 } 346 MeterNeedle that = (MeterNeedle) obj; 347 if (!PaintUtils.equal(this.outlinePaint, that.outlinePaint)) { 348 return false; 349 } 350 if (!Objects.equals(this.outlineStroke, that.outlineStroke)) { 351 return false; 352 } 353 if (!PaintUtils.equal(this.fillPaint, that.fillPaint)) { 354 return false; 355 } 356 if (!PaintUtils.equal(this.highlightPaint, that.highlightPaint)) { 357 return false; 358 } 359 if (this.size != that.size) { 360 return false; 361 } 362 if (this.rotateX != that.rotateX) { 363 return false; 364 } 365 if (this.rotateY != that.rotateY) { 366 return false; 367 } 368 return true; 369 } 370 371 /** 372 * Returns a hash code for this instance. 373 * 374 * @return A hash code. 375 */ 376 @Override 377 public int hashCode() { 378 int result = HashUtils.hashCode(193, this.fillPaint); 379 result = HashUtils.hashCode(result, this.highlightPaint); 380 result = HashUtils.hashCode(result, this.outlinePaint); 381 result = HashUtils.hashCode(result, this.outlineStroke); 382 result = HashUtils.hashCode(result, this.rotateX); 383 result = HashUtils.hashCode(result, this.rotateY); 384 result = HashUtils.hashCode(result, this.size); 385 return result; 386 } 387 388 /** 389 * Provides serialization support. 390 * 391 * @param stream the output stream. 392 * 393 * @throws IOException if there is an I/O error. 394 */ 395 private void writeObject(ObjectOutputStream stream) throws IOException { 396 stream.defaultWriteObject(); 397 SerialUtils.writeStroke(this.outlineStroke, stream); 398 SerialUtils.writePaint(this.outlinePaint, stream); 399 SerialUtils.writePaint(this.fillPaint, stream); 400 SerialUtils.writePaint(this.highlightPaint, stream); 401 } 402 403 /** 404 * Provides serialization support. 405 * 406 * @param stream the input stream. 407 * 408 * @throws IOException if there is an I/O error. 409 * @throws ClassNotFoundException if there is a classpath problem. 410 */ 411 private void readObject(ObjectInputStream stream) 412 throws IOException, ClassNotFoundException { 413 stream.defaultReadObject(); 414 this.outlineStroke = SerialUtils.readStroke(stream); 415 this.outlinePaint = SerialUtils.readPaint(stream); 416 this.fillPaint = SerialUtils.readPaint(stream); 417 this.highlightPaint = SerialUtils.readPaint(stream); 418 } 419 420}