View Javadoc

1   /* OpenLogViewer
2    *
3    * Copyright 2011
4    *
5    * This file is part of the OpenLogViewer project.
6    *
7    * OpenLogViewer software is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * OpenLogViewer software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with any OpenLogViewer software.  If not, see http://www.gnu.org/licenses/
19   *
20   * I ask that if you make any changes to this file you fork the code on github.com!
21   *
22   */
23  package org.diyefi.openlogviewer.graphing;
24  
25  import java.awt.Color;
26  import java.awt.Graphics;
27  import java.awt.Graphics2D;
28  import java.awt.event.HierarchyBoundsListener;
29  import java.awt.event.HierarchyEvent;
30  import java.beans.PropertyChangeEvent;
31  import java.beans.PropertyChangeListener;
32  
33  import javax.swing.JPanel;
34  import org.diyefi.openlogviewer.OpenLogViewer;
35  import org.diyefi.openlogviewer.genericlog.GenericDataElement;
36  import org.diyefi.openlogviewer.utils.MathUtils;
37  
38  /**
39   * SingleGraphPanel is a JPanel that uses a transparent background.
40   * The graph trace is drawn to this panel and used in conjunction with a JLayeredPane
41   * to give the appearance of all the graph traces drawn together.
42   *
43   * This layer listens for window resizes and property changes.
44   * @author Bryan Harris and Ben Fenner
45   */
46  public class SingleGraphPanel extends JPanel implements HierarchyBoundsListener, PropertyChangeListener {
47  	private static final long serialVersionUID = 1L;
48  
49  	private static final double GRAPH_TRACE_SIZE_AS_PERCENTAGE_OF_TOTAL_GRAPH_SIZE = 0.95;
50  	private GenericDataElement GDE;
51  	private double[] dataPointsToDisplay;
52  	private double[][] dataPointRangeInfo;
53  	private int availableDataRecords;
54  	private int graphBeginningIndex;
55  	private int graphEndingIndex;
56  
57  	public SingleGraphPanel() {
58  		this.setOpaque(false);
59  		this.setLayout(null);
60  		this.GDE = null;
61  		dataPointsToDisplay = null;
62  		dataPointRangeInfo = null;
63  		graphBeginningIndex = Integer.MIN_VALUE;
64  		graphEndingIndex = Integer.MIN_VALUE;
65  	}
66  
67  	@Override
68  	public void ancestorMoved(final HierarchyEvent e) {
69  	}
70  
71  	@Override
72  	public final void ancestorResized(final HierarchyEvent e) {
73  		if (e.getID() == HierarchyEvent.ANCESTOR_RESIZED) {
74  			sizeGraph();
75  		}
76  	}
77  
78  	@Override
79  	public final void propertyChange(final PropertyChangeEvent evt) {
80  		if (evt.getPropertyName().equalsIgnoreCase("Split")) {
81  			sizeGraph();
82  		}
83  	}
84  
85  	@Override
86  	public final void paint(final Graphics g) { // overridden paint because there will be no other painting other than this
87  		boolean zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
88  		if (zoomedOut) {
89  			initGraphZoomedOut();
90  		} else {
91  			initGraphZoomed();
92  		}
93  
94  		if (hasDataPointToDisplay()) {
95  			paintDataPointsAndTraces(g);
96  		}
97  	}
98  
99  	private void paintDataPointsAndTraces(final Graphics g) {
100 		// Setup graphics stuff
101 		final Graphics2D g2d = (Graphics2D) g;
102 		g2d.setColor(GDE.getDisplayColor());
103 
104 		// Initialize current, previous and next graph trace data points
105 		double leftOfTraceData = -Double.MAX_VALUE;
106 		double traceData = -Double.MAX_VALUE;
107 		double rightOfTraceData = dataPointsToDisplay[0];
108 
109 		// Initialize designated visible graph trace status markers
110 		boolean atTraceBeginning = false;
111 		boolean insideTrace = false;
112 		boolean atTraceEnd = false;
113 
114 		// Initialize and setup data point screen location stuff
115 		final boolean zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
116 		int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
117 		if (zoomedOut) {
118 			zoom = 1;
119 		}
120 		final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
121 		final double offset = (graphPosition % 1) * zoom;
122 		int screenPositionXCoord = -EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT;
123 		if (!zoomedOut) {
124 			screenPositionXCoord = -(int) Math.round(offset) - (EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_IN * zoom); // Ugly cast/invert here too
125 		}
126 		int screenPositionYCoord = Integer.MIN_VALUE;
127 		int nextScreenPositionYCoord = getScreenPositionYCoord(rightOfTraceData, GDE.getDisplayMinValue(), GDE.getDisplayMaxValue());
128 
129 		// Draw data points and trace lines from left to right including one off screen to the right
130 		for (int i = 0; i < dataPointsToDisplay.length; i++) {
131 			// Setup current, previous and next graph trace data points
132 			if (i > 0) {
133 				leftOfTraceData = dataPointsToDisplay[i - 1];
134 			} else {
135 				leftOfTraceData = -Double.MAX_VALUE;
136 			}
137 
138 			traceData = dataPointsToDisplay[i];
139 
140 			if (i + 1 < dataPointsToDisplay.length) {
141 				rightOfTraceData = dataPointsToDisplay[i + 1];
142 			} else {
143 				rightOfTraceData = -Double.MAX_VALUE;
144 			}
145 
146 			// Setup data point screen location stuff
147 			screenPositionYCoord = nextScreenPositionYCoord;
148 			nextScreenPositionYCoord = getScreenPositionYCoord(rightOfTraceData, GDE.getDisplayMinValue(), GDE.getDisplayMaxValue());
149 
150 			// Draw beginning and end markers
151 			if (i == graphBeginningIndex || i == graphEndingIndex) {
152 				g2d.drawLine(screenPositionXCoord - 2, screenPositionYCoord - 1, screenPositionXCoord - 2, screenPositionYCoord + 1);
153 				g2d.drawLine(screenPositionXCoord - 1, screenPositionYCoord + 2, screenPositionXCoord + 1, screenPositionYCoord + 2);
154 				g2d.drawLine(screenPositionXCoord - 1, screenPositionYCoord - 2, screenPositionXCoord + 1, screenPositionYCoord - 2);
155 				g2d.drawLine(screenPositionXCoord + 2, screenPositionYCoord - 1, screenPositionXCoord + 2, screenPositionYCoord + 1);
156 			}
157 
158 			// Setup graph states
159 			if (leftOfTraceData == -Double.MAX_VALUE && traceData != -Double.MAX_VALUE) {
160 				// At the beginning of the portion of the graph trace designated for display
161 				atTraceBeginning = true;
162 				insideTrace = true;
163 			}
164 
165 			if (traceData != -Double.MAX_VALUE && rightOfTraceData == -Double.MAX_VALUE) {
166 				// At the end of the portion of the graph trace designated for display
167 				atTraceEnd = true;
168 			}
169 
170 			// Draw data point
171 			if (!zoomedOut && zoom > 5) {
172 				// Draw fat data point
173 				if (atTraceBeginning) {
174 					if (traceData != rightOfTraceData) {
175 						// fillRect() is 95% faster than fillOval() for a 3x3 square on Ben's dev machine
176 						g2d.fillRect(screenPositionXCoord - 1, screenPositionYCoord - 1, 3, 3);
177 					}
178 				} else if (atTraceEnd) {
179 					if (traceData != leftOfTraceData) {
180 						// fillRect() is 95% faster than fillOval() for a 3x3 square on Ben's dev machine
181 						g2d.fillRect(screenPositionXCoord - 1, screenPositionYCoord - 1, 3, 3);
182 					}
183 				} else if (insideTrace) {
184 					if (traceData != leftOfTraceData || traceData != rightOfTraceData) {
185 						// fillRect() is 95% faster than fillOval() for a 3x3 square on Ben's dev machine
186 						g2d.fillRect(screenPositionXCoord - 1, screenPositionYCoord - 1, 3, 3);
187 					}
188 				}
189 			} else if (insideTrace) {
190 				// Draw small data point
191 				// drawLine() is 33% faster than fillRect() for a single pixel on Ben's dev machine
192 				g2d.drawLine(screenPositionXCoord, screenPositionYCoord, screenPositionXCoord, screenPositionYCoord);
193 			}
194 
195 			// Draw graph trace line
196 			if (insideTrace && !atTraceEnd) {
197 				g2d.drawLine(screenPositionXCoord, screenPositionYCoord, screenPositionXCoord + zoom, nextScreenPositionYCoord);
198 			}
199 
200 			// Reset graph states
201 			if (atTraceEnd) {
202 				insideTrace = false;
203 				atTraceEnd = false;
204 			}
205 			atTraceBeginning = false;
206 
207 			// Move to the right in preparation of drawing more
208 			screenPositionXCoord += zoom;
209 		}
210 	}
211 
212 	private int getScreenPositionYCoord(final Double traceData, final double minValue, final double maxValue) {
213 		int point = 0;
214 		final int height = (int) (this.getHeight() * GRAPH_TRACE_SIZE_AS_PERCENTAGE_OF_TOTAL_GRAPH_SIZE);
215 		if (maxValue != minValue) {
216 			point = (int) (height - (height * ((traceData - minValue) / (maxValue - minValue))));
217 		}
218 		return point;
219 	}
220 
221 	private boolean hasDataPointToDisplay() {
222 		boolean result = false;
223 		if ((dataPointsToDisplay != null) && (dataPointsToDisplay.length > 0)) {
224 			result = true;
225 		}
226 		return result;
227 	}
228 
229 	/**
230 	 * this is where the GDE is referenced and the graph gets initialized for the first time
231 	 * @param GDE
232 	 */
233 	public final void setData(final GenericDataElement GDE) {
234 		this.GDE = GDE;
235 		this.availableDataRecords = GDE.size() + 1; // Size is currently position, this will need cleaning up later, leave it to me.
236 		// The main thing is to take away 10 calls to the GDE per view on something that is fairly static and cache it internally
237 		sizeGraph();
238 	}
239 
240 	public final GenericDataElement getData() {
241 		return GDE;
242 	}
243 
244 	/**
245 	 * Used for InfoLayer to get the data from the single graphs for data under the mouse
246 	 *
247 	 * @param pointerDistanceFromCenter
248 	 * @return Double representation of info at the mouse cursor line which snaps to data points or null if no data under cursor
249 	 */
250 	public final String getMouseInfo(final int cursorPosition) {
251 		boolean zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
252 		String info = "-.-";
253 		if (zoomedOut) {
254 			info = getMouseInfoZoomedOut(cursorPosition);
255 		} else {
256 			info = getMouseInfoZoomed(cursorPosition);
257 		}
258 
259 		return info;
260 	}
261 
262 	/**
263 	 * Used for InfoLayer to get the data from the single graphs for data under the mouse when not zoomed out
264 	 *
265 	 * @param pointerDistanceFromCenter
266 	 * @return Double representation of info at the mouse cursor line which snaps to data points or null if no data under cursor
267 	 */
268 	private final String getMouseInfoZoomed(final int cursorPosition) {
269 		String result = "-.-";
270 		final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
271 		final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
272 		final double offset = (graphPosition % 1) * zoom;
273 		final int cursorPositionPlusOffset = cursorPosition + (int) offset;
274 		double numSnapsFromLeft = ((double) cursorPositionPlusOffset / (double) zoom);
275 		numSnapsFromLeft = Math.round(numSnapsFromLeft);
276 		final int dataLocation = (int) graphPosition + (int) numSnapsFromLeft;
277 		if ((dataLocation >= 0) && (dataLocation < availableDataRecords)) {
278 			double data = GDE.get(dataLocation);
279 			data = MathUtils.roundToSignificantFigures(data, 6);
280 			result = Double.toString(data);
281 			if (result.length() > 8) {
282 				result = result.substring(0, 8);
283 			}
284 		}
285 		return result;
286 	}
287 
288 	/**
289 	 * Used for InfoLayer to get the data from the single graphs for data under the mouse when zoomed out
290 	 *
291 	 * @param pointerDistanceFromCenter
292 	 * @return Double representation of info at the mouse cursor line which snaps to data points or null if no data under cursor
293 	 */
294 	private final String getMouseInfoZoomedOut(int cursorPosition) {
295 		String result = "-.- | -.- | -.-";
296 		if ((cursorPosition >= 0) && (cursorPosition < dataPointRangeInfo.length)) {
297 			double minData = dataPointRangeInfo[cursorPosition + EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT][0];
298 			double meanData = dataPointRangeInfo[cursorPosition + EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT][1];
299 			double maxData = dataPointRangeInfo[cursorPosition + EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT][2];
300 			if (minData != -Double.MAX_VALUE) {
301 				minData = MathUtils.roundToSignificantFigures(minData, 6);
302 				maxData = MathUtils.roundToSignificantFigures(maxData, 6);
303 				String resultMin = Double.toString(minData);
304 				String resultMax = Double.toString(maxData);
305 				if (resultMin.length() > 8) {
306 					resultMin = resultMin.substring(0, 8);
307 				}
308 				if (resultMax.length() > 8) {
309 					resultMax = resultMax.substring(0, 8);
310 				}
311 				meanData = MathUtils.roundToSignificantFigures(meanData, 6);
312 				String resultMean = Double.toString(meanData);
313 				if (resultMin.length() > resultMax.length() && resultMin.length() < resultMean.length()) {
314 					meanData = MathUtils.roundToSignificantFigures(meanData, resultMin.length() - 2);
315 					resultMean = resultMean.substring(0, resultMin.length());
316 				} else if (resultMax.length() < resultMean.length()) {
317 					meanData = MathUtils.roundToSignificantFigures(meanData, resultMax.length() - 2);
318 					resultMean = resultMean.substring(0, resultMax.length());
319 				}
320 
321 				result = resultMin + " | " + resultMean + " | " + resultMax;
322 			}
323 		}
324 		return result;
325 	}
326 
327 	public final Color getColor() {
328 		return GDE.getDisplayColor();
329 	}
330 
331 	public final void setColor(final Color c) {
332 		GDE.setDisplayColor(c);
333 	}
334 
335 	/**
336 	 * initialize the graph any time you need to paint
337 	 */
338 	public final void initGraphZoomed() {
339 		if (GDE != null) {
340 			final int graphPosition = (int)OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
341 			int graphWindowWidth = OpenLogViewer.getInstance().getEntireGraphingPanel().getWidth();
342 			final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
343 			int numberOfPointsThatFitInDisplay = graphWindowWidth / zoom;
344 			numberOfPointsThatFitInDisplay += EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_IN;
345 			numberOfPointsThatFitInDisplay += EntireGraphingPanel.RIGHT_OFFSCREEN_POINTS_ZOOMED_IN;
346 			dataPointsToDisplay = new double[numberOfPointsThatFitInDisplay];
347 			int position = graphPosition - EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_IN;
348 
349 			// Reset start/end indices.
350 			graphBeginningIndex = Integer.MIN_VALUE;
351 			graphEndingIndex = Integer.MIN_VALUE;
352 
353 			// Setup data points.
354 			for (int i = 0; i < numberOfPointsThatFitInDisplay; i++) {
355 				if (position >= 0 && position < availableDataRecords) {
356 					dataPointsToDisplay[i] = GDE.get(position);
357 
358 					// Set start/end indices.
359 					if (position == 0) {
360 						graphBeginningIndex = i;
361 					}
362 
363 					if (position == availableDataRecords - 1) {
364 						graphEndingIndex = i;
365 					}
366 
367 				} else {
368 					dataPointsToDisplay[i] = -Double.MAX_VALUE;
369 				}
370 				position++;
371 			}
372 		}
373 	}
374 
375 	/**
376 	 * initialize the graph any time you need to paint
377 	 */
378 	public final void initGraphZoomedOut() {
379 		if (GDE != null) {
380 			final int graphPosition = (int)OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
381 			int graphWindowWidth = OpenLogViewer.getInstance().getEntireGraphingPanel().getWidth();
382 			final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
383 			final int position = graphPosition - (EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT * zoom);
384 			dataPointsToDisplay = new double[graphWindowWidth + EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT + EntireGraphingPanel.RIGHT_OFFSCREEN_POINTS_ZOOMED_OUT];
385 			dataPointRangeInfo = new double[dataPointsToDisplay.length][3];
386 			final int numberOfRealPointsThatFitInDisplay = (graphWindowWidth * zoom)
387 					+ (EntireGraphingPanel.LEFT_OFFSCREEN_POINTS_ZOOMED_OUT * zoom)
388 					+ (EntireGraphingPanel.RIGHT_OFFSCREEN_POINTS_ZOOMED_OUT * zoom);
389 			final int rightGraphPosition = position + numberOfRealPointsThatFitInDisplay;
390 
391 			// Reset start/end indices.
392 			graphBeginningIndex = Integer.MIN_VALUE;
393 			graphEndingIndex = Integer.MIN_VALUE;
394 
395 			/*
396 			* Setup data points.
397 			*
398 			* The data point to display is calculated by taking the average of
399 			* the data point spread and comparing it to the previous calculated
400 			* data point. If the average is higher, then the highest value of
401 			* the data spread is used. If the average is lower, then the lowest
402 			* value of the data point spread is used.
403 			*
404 			* In other words, if the graph is trending upward, the peak is used.
405 			* If the graph is trending downward, the valley is used.
406 			* This keeps the peaks and valleys intact and the middle stuff is
407 			* lost. This maintains the general shape of the graph, and assumes
408 			* that local peaks and valleys are the most interesting parts of the
409 			* graph to display.
410 			*/
411 			int nextAarrayIndex = 0;
412 			double leftOfNewData = GDE.get(0);
413 			if (position > 0 && position < availableDataRecords) {
414 				leftOfNewData = GDE.get(position);
415 			}
416 
417 			if (zoom < (availableDataRecords / 2)) {
418 
419 				for (int i = position; i < rightGraphPosition; i += zoom) {
420 
421 					if (i >= 0 && i < availableDataRecords) {
422 						double minData = Double.MAX_VALUE;
423 						double maxData = -Double.MAX_VALUE;
424 						double newData = 0.0;
425 						double acummulateData = 0.0;
426 						int divisor = 0;
427 
428 						for (int j = 0; j < zoom; j++) {
429 							int gdeIndex = i + j;
430 							if (gdeIndex >= 0 && gdeIndex < availableDataRecords) {
431 								newData = GDE.get(gdeIndex);
432 								acummulateData += newData;
433 								divisor++;
434 								if (newData < minData) {
435 									minData = newData;
436 								}
437 
438 								if (newData > maxData) {
439 									maxData = newData;
440 								}
441 
442 								// Set start/end indices.
443 								if (graphBeginningIndex == Integer.MIN_VALUE && (gdeIndex >= 0 && gdeIndex < zoom)) {
444 									graphBeginningIndex = nextAarrayIndex;
445 								}
446 
447 								if (gdeIndex == availableDataRecords - 1) {
448 									graphEndingIndex = nextAarrayIndex;
449 								}
450 
451 							}
452 						}
453 						double averageData = acummulateData / divisor;
454 						if (averageData > leftOfNewData) {
455 							dataPointsToDisplay[nextAarrayIndex] = maxData;
456 							leftOfNewData = maxData;
457 						} else if (averageData < leftOfNewData) {
458 							dataPointsToDisplay[nextAarrayIndex] = minData;
459 							leftOfNewData = minData;
460 						} else {
461 							dataPointsToDisplay[nextAarrayIndex] = averageData;
462 							leftOfNewData = averageData;
463 						}
464 						dataPointRangeInfo[nextAarrayIndex][0] = minData;
465 						dataPointRangeInfo[nextAarrayIndex][1] = averageData;
466 						dataPointRangeInfo[nextAarrayIndex][2] = maxData;
467 						nextAarrayIndex++;
468 					} else {
469 						dataPointsToDisplay[nextAarrayIndex] = -Double.MAX_VALUE;
470 						dataPointRangeInfo[nextAarrayIndex][0] = -Double.MAX_VALUE;
471 						dataPointRangeInfo[nextAarrayIndex][1] = -Double.MAX_VALUE;
472 						dataPointRangeInfo[nextAarrayIndex][2] = -Double.MAX_VALUE;
473 						nextAarrayIndex++;
474 					}
475 				}
476 			} else {
477 
478 				/*
479 				* Setup data points when extremely zoomed out.
480 				*
481 				* If the zoom value is higher than the entire length of
482 				* available data then it is possible for the normal algorithm
483 				* to skip over the data completely when sweeping across the
484 				* screen from left to right in zoom steps. If zoom reaches
485 				* that high of a value, then use this alternative algorithm
486 				* instead.
487 				*
488 				*/
489 
490 				// Fill in null data points until zero position is reached.
491 				for (int i = position; i < 0; i += zoom) {
492 					dataPointsToDisplay[nextAarrayIndex] = -Double.MAX_VALUE;
493 					dataPointRangeInfo[nextAarrayIndex][0] = -Double.MAX_VALUE;
494 					dataPointRangeInfo[nextAarrayIndex][1] = -Double.MAX_VALUE;
495 					dataPointRangeInfo[nextAarrayIndex][2] = -Double.MAX_VALUE;
496 					nextAarrayIndex++;
497 				}
498 
499 				// Find min/mean/max of entire available data and place at position zero.
500 				double minData = Double.MAX_VALUE;
501 				double maxData = -Double.MAX_VALUE;
502 				double newData = 0.0;
503 				double acummulateData = 0.0;
504 				int divisor = 0;
505 				for (int i = 0; i < availableDataRecords; i++) {
506 					newData = GDE.get(i);
507 					acummulateData += newData;
508 					divisor++;
509 					if (newData < minData) {
510 						minData = newData;
511 					}
512 
513 					if (newData > maxData) {
514 						maxData = newData;
515 					}
516 				}
517 				double averageData = acummulateData / divisor;
518 				dataPointsToDisplay[nextAarrayIndex] = averageData;
519 				dataPointRangeInfo[nextAarrayIndex][0] = minData;
520 				dataPointRangeInfo[nextAarrayIndex][1] = averageData;
521 				dataPointRangeInfo[nextAarrayIndex][2] = maxData;
522 
523 				// Set start/end indices.
524 				graphBeginningIndex = nextAarrayIndex;
525 				graphEndingIndex = nextAarrayIndex;
526 
527 				nextAarrayIndex++;
528 
529 				// Fill in the rest of the array with null data points.
530 				for (int i = zoom * 2; i < rightGraphPosition; i += zoom) {
531 					dataPointsToDisplay[nextAarrayIndex] = -Double.MAX_VALUE;
532 					dataPointRangeInfo[nextAarrayIndex][0] = -Double.MAX_VALUE;
533 					dataPointRangeInfo[nextAarrayIndex][1] = -Double.MAX_VALUE;
534 					dataPointRangeInfo[nextAarrayIndex][2] = -Double.MAX_VALUE;
535 					nextAarrayIndex++;
536 				}
537 			}
538 		}
539 	}
540 
541 	/**
542 	 * maintains the size of the graph when applying divisions
543 	 */
544 	public final void sizeGraph() {
545 		final MultiGraphLayeredPane lg = OpenLogViewer.getInstance().getMultiGraphLayeredPane();
546 		int wherePixel = 0;
547 		if (lg.getTotalSplits() > 1) {
548 			if (GDE.getSplitNumber() <= lg.getTotalSplits()) {
549 				wherePixel += lg.getHeight() / lg.getTotalSplits() * GDE.getSplitNumber() - (lg.getHeight() / lg.getTotalSplits());
550 			} else {
551 				wherePixel += lg.getHeight() / lg.getTotalSplits() * lg.getTotalSplits() - (lg.getHeight() / lg.getTotalSplits());
552 			}
553 		}
554 
555 		this.setBounds(0, wherePixel, lg.getWidth(), lg.getHeight() / (lg.getTotalSplits()));
556 		final boolean zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
557 		if (zoomedOut) {
558 			initGraphZoomedOut();
559 		} else {
560 			initGraphZoomed();
561 		}
562 	}
563 
564 	/**
565 	 * Graph total size
566 	 * @return GDE.size()
567 	 */
568 	public final int graphSize() {
569 		return availableDataRecords;
570 	}
571 }