1 package org.opentrafficsim.draw;
2
3 import java.awt.Color;
4 import java.util.Arrays;
5
6 import org.djutils.exceptions.Throw;
7 import org.opentrafficsim.base.logger.Logger;
8
9
10
11
12
13
14
15
16
17
18
19 public class BoundsPaintScale implements ColorPaintScale
20 {
21
22
23 private final double[] bounds;
24
25
26 private final Color[] boundColors;
27
28
29 private final Color notApplicable;
30
31
32
33
34
35
36
37 public BoundsPaintScale(final double[] bounds, final Color[] boundColors) throws IllegalArgumentException
38 {
39 this(bounds, boundColors, Color.BLACK);
40 }
41
42
43
44
45
46
47
48
49 public BoundsPaintScale(final double[] bounds, final Color[] boundColors, final Color notApplicable)
50 throws IllegalArgumentException
51 {
52 Throw.when(bounds.length < 2, IllegalArgumentException.class, "bounds must have >= 2 entries");
53 Throw.when(bounds.length != boundColors.length, IllegalArgumentException.class,
54 "bounds must have same length as boundColors");
55 this.bounds = new double[bounds.length];
56 this.boundColors = new Color[bounds.length];
57
58
59 for (int nextBound = 0; nextBound < bounds.length; nextBound++)
60 {
61
62 double currentLowest = Double.POSITIVE_INFINITY;
63 int bestIndex = -1;
64 int index;
65 for (index = 0; index < bounds.length; index++)
66 {
67 if (bounds[index] < currentLowest && (nextBound == 0 || bounds[index] > this.bounds[nextBound - 1]))
68 {
69 bestIndex = index;
70 currentLowest = bounds[index];
71 }
72 }
73 Throw.when(bestIndex < 0, IllegalArgumentException.class, "duplicate value in bounds");
74 this.bounds[nextBound] = bounds[bestIndex];
75 this.boundColors[nextBound] = boundColors[bestIndex];
76 }
77 this.notApplicable = notApplicable;
78 }
79
80 @Override
81 public Color getPaint(final double value)
82 {
83 if (Double.isNaN(value))
84 {
85 return this.notApplicable;
86 }
87 if (value < this.bounds[0])
88 {
89 return this.boundColors[0];
90 }
91 if (value > this.bounds[this.bounds.length - 1])
92 {
93 return this.boundColors[this.bounds.length - 1];
94 }
95 int index;
96 for (index = 0; index < this.bounds.length - 1; index++)
97 {
98 if (value < this.bounds[index + 1])
99 {
100 break;
101 }
102 }
103 final double ratio;
104 if (index >= this.bounds.length - 1)
105 {
106 index = this.bounds.length - 2;
107 ratio = 1.0;
108 }
109 else
110 {
111 ratio = (value - this.bounds[index]) / (this.bounds[index + 1] - this.bounds[index]);
112 }
113 if (Double.isInfinite(ratio))
114 {
115 Logger.ots().error("Interpolation value for color is infinite based on {} in {} obtaining index {}.", value,
116 this.bounds, index);
117 }
118 Color mix = ColorInterpolator.interpolateColor(this.boundColors[index], this.boundColors[index + 1], ratio);
119 return mix;
120 }
121
122 @Override
123 public final double getLowerBound()
124 {
125 return this.bounds[0];
126 }
127
128 @Override
129 public final double getUpperBound()
130 {
131 return this.bounds[this.bounds.length - 1];
132 }
133
134
135
136
137
138 public double[] getBounds()
139 {
140 return Arrays.copyOf(this.bounds, this.bounds.length);
141 }
142
143
144
145
146
147 public Color[] getBoundColors()
148 {
149 return Arrays.copyOf(this.boundColors, this.boundColors.length);
150 }
151
152 @Override
153 public String toString()
154 {
155 return "BoundsPaintScale [bounds=" + Arrays.toString(this.bounds) + ", boundColors=" + Arrays.toString(this.boundColors)
156 + "]";
157 }
158
159 }