Package: XYPlotter$DataBundle
XYPlotter$DataBundle
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
XYPlotter.DataBundle(int[], Color) |
|
|
|
|
|
||||||||||||||||||||
getColor() |
|
|
|
|
|
||||||||||||||||||||
getData() |
|
|
|
|
|
Coverage
1: /*
2: * *********************************************************************************************************************
3: *
4: * Mistral: open source imaging engine
5: * http://tidalwave.it/projects/mistral
6: *
7: * Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/mistral-src
23: * git clone https://github.com/tidalwave-it/mistral-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.mistral.example.histogramviewer;
28:
29: import java.util.ArrayList;
30: import java.util.HashMap;
31: import java.util.List;
32: import java.util.Map;
33: import java.awt.Color;
34: import java.awt.Graphics;
35: import java.awt.Graphics2D;
36: import java.awt.RenderingHints;
37: import java.awt.image.BufferedImage;
38: import javax.swing.JComponent;
39: import it.tidalwave.image.render.Overlay;
40:
41: /***********************************************************************************************************************
42: *
43: * @author Fabrizio Giudici
44: *
45: **********************************************************************************************************************/
46: public class XYPlotter extends JComponent
47: {
48: static class DataBundle
49: {
50: private int[] data;
51:
52: private Color color;
53:
54: public DataBundle (final int[] data, final Color color)
55: {
56: this.data = data;
57: this.color = color;
58: }
59:
60: public int[] getData()
61: {
62: return data;
63: }
64:
65: public Color getColor()
66: {
67: return color;
68: }
69: }
70:
71: private Map dataMap = new HashMap();
72:
73: private List dataList = new ArrayList(); // needed to keep the order
74:
75: private int max;
76:
77: private int min;
78:
79: private BufferedImage buffer;
80:
81: private Overlay overlay;
82:
83: public static final int LINEAR = 0;
84:
85: public static final int LOG = 1;
86:
87: private int xMode = LINEAR;
88:
89: private int logXBands = 2;
90:
91: private boolean area = false;
92:
93: public XYPlotter()
94: {
95: setOpaque(false);
96: }
97:
98: /*******************************************************************************************************************
99: *
100: *
101: *
102: ******************************************************************************************************************/
103: public void setXAxisLinear()
104: {
105: this.xMode = LINEAR;
106: }
107:
108: /*******************************************************************************************************************
109: *
110: * @param logXBands
111: *
112: ******************************************************************************************************************/
113: public void setXAxisLogarithmic (final int logXBands)
114: {
115: this.logXBands = logXBands;
116: this.xMode = LOG;
117: }
118:
119: /*******************************************************************************************************************
120: *
121: *
122: *
123: ******************************************************************************************************************/
124: public void setAreaPlot()
125: {
126: area = true;
127: }
128:
129: /*******************************************************************************************************************
130: *
131: * @return
132: *
133: ******************************************************************************************************************/
134: public boolean isXAxisLogarithmic()
135: {
136: return xMode == LOG;
137: }
138:
139: /*******************************************************************************************************************
140: *
141: *
142: *
143: ******************************************************************************************************************/
144: public void clearData()
145: {
146: dataList.clear();
147: dataMap.clear();
148: min = Integer.MAX_VALUE;
149: max = Integer.MIN_VALUE;
150: buffer = null;
151: }
152:
153: /*******************************************************************************************************************
154: *
155: * @param key
156: * @param data
157: * @param color
158: *
159: ******************************************************************************************************************/
160: public void addUnsignedData (final Object key, final short[] data, final Color color)
161: {
162: final var data2 = new int[data.length];
163:
164: for (var i = 0; i < data.length; i++)
165: {
166: data2[i] = data[i] & 0xffff;
167: }
168:
169: addData(key, data2, color);
170: }
171:
172: /*******************************************************************************************************************
173: *
174: * @param key
175: * @param data
176: * @param color
177: *
178: ******************************************************************************************************************/
179: public void addData (final Object key, final int[] data, final Color color)
180: {
181: buffer = null;
182: final var myData = new int[data.length];
183: System.arraycopy(data, 0, myData, 0, data.length);
184:
185: for (final var d : myData)
186: {
187: max = Math.max(max, d);
188: min = Math.min(min, d);
189: }
190:
191: dataMap.put(key, new DataBundle(myData, color));
192: dataList.add(key);
193:
194: if (isVisible())
195: {
196: repaint();
197: }
198:
199: // System.err.println("Data: " + data.length + " max: " + max + " min: " + min);
200: }
201:
202: /*******************************************************************************************************************
203: *
204: * {@inheritDoc}
205: *
206: ******************************************************************************************************************/
207: @Override
208: public void paint (final Graphics g)
209: {
210: if ((buffer == null) || (buffer.getWidth() != getWidth()) || (buffer.getHeight() != getHeight()))
211: {
212: buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
213: Graphics2D g2 = null;
214:
215: try
216: {
217: g2 = (Graphics2D)buffer.getGraphics();
218:
219: if (!area)
220: {
221: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
222: }
223:
224: else
225: {
226: //g2.setComposite(AlphaComposite.Xor);
227: }
228:
229: plot(g2);
230: }
231:
232: finally
233: {
234: g2.dispose();
235: }
236: }
237:
238: if (buffer != null)
239: {
240: g.drawImage(buffer, 0, 0, null);
241: }
242:
243: else
244: {
245: plot(g);
246: }
247: }
248:
249: /*******************************************************************************************************************
250: *
251: * Sets an overlay to overimpose to the image.
252: *
253: * @param overlay the overlay
254: *
255: ******************************************************************************************************************/
256: public void setOverlay (final Overlay overlay)
257: {
258: this.overlay = overlay;
259: }
260:
261: /*******************************************************************************************************************
262: *
263: * @param g
264: *
265: ******************************************************************************************************************/
266: private void plot (final Graphics g)
267: {
268: final var g2 = (Graphics2D)g.create();
269:
270: try
271: {
272: final var width = getSize().width;
273: final var height = getSize().height;
274:
275: g.setColor(new Color(0, 0, 0, 0));
276: g.fillRect(0, 0, width, height);
277:
278: if (overlay != null)
279: {
280: // overlay.paint(g, getBounds());
281: }
282:
283: var xMin = 0;
284: double f = 0;
285:
286: if (xMode == LOG)
287: {
288: final var xMinNorm = 1 / Math.pow(2, logXBands);
289: f = 1.0 / (logXBands * Math.log(2));
290: xMin = (int)Math.round(xMinNorm * width);
291: }
292:
293: else if (xMode == LINEAR)
294: {
295: xMin = 0;
296: }
297:
298: var yMax = Integer.MIN_VALUE;
299:
300: for (final var key : dataList)
301: {
302: final var dataBundle = (DataBundle)dataMap.get(key);
303: final var data = dataBundle.getData();
304:
305: for (var i = xMin; i < data.length; i++)
306: {
307: yMax = Math.max(yMax, data[i]);
308: }
309: }
310:
311: final var yScale = (double)height / (double)yMax;
312:
313: for (var o : dataMap.values())
314: {
315: final var dataBundle = (DataBundle)o;
316: g.setColor(dataBundle.getColor());
317: final var data = dataBundle.getData();
318: final var mask = dataBundle.getColor().getRGB();
319:
320: var first = true;
321: final var length = data.length;
322: final var xScale = (double)width / (double)length;
323: int prevX = 0, prevY = 0;
324:
325: for (var i = xMin; i < length; i++)
326: {
327: var x = 0;
328:
329: if (xMode == LINEAR)
330: {
331: x = (int)Math.round(i * xScale);
332: }
333:
334: else if (xMode == LOG)
335: {
336: var xNorm = (double)i / (double)length;
337: xNorm = 1 + Math.log(xNorm) * f;
338: x = (int)Math.round(xNorm * width);
339: }
340:
341: final var y = height - (int)Math.round(data[i] * yScale);
342:
343: if (!first)
344: {
345: if (!area)
346: {
347: g.drawLine(prevX, prevY, x, y);
348: }
349:
350: else
351: {
352: for (var xx = prevX; xx < x; xx++)
353: {
354: for (var yy = y; yy < height; yy++)
355: {
356: final var rgb = buffer.getRGB(xx, yy);
357: buffer.setRGB(xx, yy, rgb | mask);
358: }
359:
360: //g.drawLine(x, height, x, y);
361: }
362: }
363: }
364:
365: prevX = x;
366: prevY = y;
367: first = false;
368: }
369: }
370: }
371:
372: finally
373: {
374: g2.dispose();
375: }
376: }
377: }