View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.perf.impl.chart;
33  
34  import java.awt.Color;
35  import java.awt.Paint;
36  import java.io.Serializable;
37  import org.jfree.chart.renderer.PaintScale;
38  import org.jfree.chart.util.PublicCloneable;
39  import org.spf4j.base.CloneFailedException;
40  
41  /**
42   * A paint scale that returns shades of gray.
43   *
44   * @since 1.0.4
45   */
46  public final class InverseGrayScale
47          implements PaintScale, PublicCloneable, Serializable {
48  
49      private static final long serialVersionUID = 1L;
50  
51      /** The lower bound. */
52      private final double lowerBound;
53  
54      /** The upper bound. */
55      private final double upperBound;
56  
57      /**
58       * The alpha transparency (0-255).
59       *
60       * @since 1.0.13
61       */
62      private final int alpha;
63  
64      /**
65       * Creates a new <code>GrayPaintScale</code> instance with default values.
66       */
67      public InverseGrayScale() {
68          this(0.0, 1.0);
69      }
70  
71      /**
72       * Creates a new paint scale for values in the specified range.
73       *
74       * @param lowerBound  the lower bound.
75       * @param upperBound  the upper bound.
76       *
77       * @throws IllegalArgumentException if <code>lowerBound</code> is not
78       *       less than <code>upperBound</code>.
79       */
80      public InverseGrayScale(final double lowerBound, final double upperBound) {
81          this(lowerBound, upperBound, 255);
82      }
83  
84      /**
85       * Creates a new paint scale for values in the specified range.
86       *
87       * @param lowerBound  the lower bound.
88       * @param upperBound  the upper bound.
89       * @param alpha  the alpha transparency (0-255).
90       *
91       * @throws IllegalArgumentException if <code>lowerBound</code> is not
92       *       less than <code>upperBound</code>, or <code>alpha</code> is not in
93       *       the range 0 to 255.
94       *
95       * @since 1.0.13
96       */
97      public InverseGrayScale(final double lowerBound, final double upperBound, final int alpha) {
98          if (lowerBound >= upperBound) {
99              throw new IllegalArgumentException(
100                     "Requires " + lowerBound + " < " + upperBound + '.');
101         }
102         if (alpha < 0 || alpha > 255) {
103             throw new IllegalArgumentException(
104                     "Requires alpha in the range 0 to 255. and not " + alpha);
105 
106         }
107         this.lowerBound = lowerBound;
108         this.upperBound = upperBound;
109         this.alpha = alpha;
110     }
111 
112     /**
113      * Returns the lower bound.
114      *
115      * @return The lower bound.
116      *
117      * @see #getUpperBound()
118      */
119     @Override
120     public double getLowerBound() {
121         return this.lowerBound;
122     }
123 
124     /**
125      * Returns the upper bound.
126      *
127      * @return The upper bound.
128      *
129      * @see #getLowerBound()
130      */
131     @Override
132     public double getUpperBound() {
133         return this.upperBound;
134     }
135 
136     /**
137      * Returns the alpha transparency that was specified in the constructor.
138      *
139      * @return The alpha transparency (in the range 0 to 255).
140      *
141      * @since 1.0.13
142      */
143     public int getAlpha() {
144         return this.alpha;
145     }
146 
147     /**
148      * Returns a paint for the specified value.
149      *
150      * @param value  the value (must be within the range specified by the
151      *         lower and upper bounds for the scale).
152      *
153      * @return A paint for the specified value.
154      */
155     @Override
156     public Paint getPaint(final double value) {
157         double v = Math.max(value, this.lowerBound);
158         v = Math.min(v, this.upperBound);
159         int g;
160         if (value >= 1) {
161             g = 240 -  (int) ((v - this.lowerBound) / (this.upperBound
162                 - this.lowerBound) * 240.0);
163         } else {
164             g = 255 -  (int) ((v - this.lowerBound) / (this.upperBound
165                 - this.lowerBound) * 15.0);
166         }
167         // FIXME:  it probably makes sense to allocate an array of 256 Colors
168         // and lazily populate this array...
169 
170         return new Color(g, g, g, this.alpha);
171     }
172 
173     @Override
174     public boolean equals(final Object obj) {
175         if (obj == null) {
176             return false;
177         }
178         if (getClass() != obj.getClass()) {
179             return false;
180         }
181         final InverseGrayScale other = (InverseGrayScale) obj;
182         if (Double.doubleToLongBits(this.lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
183             return false;
184         }
185         if (Double.doubleToLongBits(this.upperBound) != Double.doubleToLongBits(other.upperBound)) {
186             return false;
187         }
188         return this.alpha == other.alpha;
189     }
190 
191     @Override
192     public int hashCode() {
193         int hash = 3;
194         hash = 97 * hash
195                 + (int) (Double.doubleToLongBits(this.lowerBound) ^ (Double.doubleToLongBits(this.lowerBound) >>> 32));
196         hash = 97 * hash
197                 + (int) (Double.doubleToLongBits(this.upperBound) ^ (Double.doubleToLongBits(this.upperBound) >>> 32));
198         return  97 * hash + this.alpha;
199     }
200 
201 
202 
203     /**
204      * Returns a clone of this <code>GrayPaintScale</code> instance.
205      *
206      * @return A clone.
207      *
208      */
209     @Override
210     public InverseGrayScale clone() {
211         try {
212             return (InverseGrayScale) super.clone();
213         } catch (CloneNotSupportedException ex) {
214            throw new CloneFailedException("Failed cloning " + this,  ex);
215         }
216     }
217 
218     @Override
219     public String toString() {
220         return "InverseGrayScale{" + "lowerBound=" + lowerBound + ", upperBound=" + upperBound
221                 + ", alpha=" + alpha + '}';
222     }
223 
224 }