1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.diyefi.openlogviewer.graphing;
24
25 import java.awt.Color;
26 import java.awt.FontMetrics;
27 import java.awt.Graphics;
28 import java.awt.Graphics2D;
29 import java.math.BigDecimal;
30 import java.math.MathContext;
31
32 import javax.swing.JPanel;
33
34 import org.diyefi.openlogviewer.OpenLogViewer;
35 import org.diyefi.openlogviewer.genericlog.GenericLog;
36
37 public class GraphPositionPanel extends JPanel {
38 private static final long serialVersionUID = 1L;
39
40 private GenericLog genLog;
41 private Color majorGraduationColor;
42 private Color positionDataColor;
43 private Color backgroundColor;
44 private boolean[] validSnappingPositions;
45 private double[] graduationSpacingMultiplier;
46 private double majorGraduationSpacing;
47
48 public GraphPositionPanel() {
49 super();
50 init();
51 }
52
53 private void init() {
54 this.setOpaque(true);
55 this.setLayout(null);
56 majorGraduationColor = Color.GRAY;
57 positionDataColor = majorGraduationColor;
58 backgroundColor = Color.BLACK;
59 validSnappingPositions = new boolean[this.getWidth()];
60 graduationSpacingMultiplier = new double[] {2.0, 2.5, 2.0};
61 setGraduationSpacing();
62 }
63
64 @Override
65 public final void paint(final Graphics g) {
66 if (!this.getSize().equals(this.getParent().getSize())) {
67 this.setSize(this.getParent().getSize());
68 }
69 setGraduationSpacing();
70 final Graphics2D g2d = (Graphics2D) g;
71 g2d.setColor(backgroundColor);
72 g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
73 if (genLog == null) {
74 paintPositionBar(g2d, false);
75 } else {
76 if (genLog.getLogStatus() == GenericLog.LOG_LOADING) {
77 paintPositionBar(g2d, false);
78 } else if (genLog.getLogStatus() == GenericLog.LOG_LOADED) {
79 final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
80 final boolean zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
81 paintPositionBar(g2d, zoomedOut);
82 paintPositionData(g2d, zoomedOut);
83 if(!zoomedOut && zoom > 1){
84 setupMouseCursorLineSnappingPositions();
85 }
86 }
87 }
88 }
89
90 private void paintPositionBar(final Graphics2D g2d, final boolean zoomedOut) {
91 final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
92 final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
93 double offset = 0;
94 if(zoomedOut){
95 offset = majorGraduationSpacing / zoom;
96 } else {
97 offset = majorGraduationSpacing * zoom;
98 }
99 offset = Math.round(offset);
100 g2d.setColor(majorGraduationColor);
101
102
103 double nextPositionMarker = getFirstPositionMarkerPlacement();
104
105
106 double position = graphPosition - majorGraduationSpacing;
107 for (int i = -(int)offset; i < this.getWidth() + (int)offset; i++) {
108 if (position >= nextPositionMarker){
109 g2d.drawLine(i, 0, i, 6);
110 nextPositionMarker += majorGraduationSpacing;
111 }
112 if(zoomedOut){
113 position += zoom;
114 } else {
115 position += (1.0 / zoom);
116 }
117 }
118 g2d.drawLine(0, 0, this.getWidth(), 0);
119 }
120
121 private void paintPositionData(final Graphics2D g2d, final boolean zoomedOut) {
122 final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
123 final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
124 double offset = 0;
125 if(zoomedOut){
126 offset = majorGraduationSpacing / zoom;
127 } else {
128 offset = majorGraduationSpacing * zoom;
129 }
130 g2d.setColor(positionDataColor);
131 FontMetrics fm = this.getFontMetrics(this.getFont());
132
133
134 double nextPositionMarker = getFirstPositionMarkerPlacement();
135
136
137 double position = graphPosition - majorGraduationSpacing;
138 for (int i = -(int)offset; i < this.getWidth() + (int)offset; i++) {
139 if (position >= nextPositionMarker){
140 String positionDataString = "";
141 BigDecimal positionData = new BigDecimal(nextPositionMarker);
142 if(majorGraduationSpacing > 0.5){
143 positionDataString = positionData.toPlainString();
144 } else {
145 positionDataString = roundDecimalsOnlyToTwoSignificantFigures(positionData);
146 }
147 int stringWidth = fm.stringWidth(positionDataString);
148 g2d.drawString(positionDataString, i - (stringWidth / 2), 18);
149
150 nextPositionMarker += majorGraduationSpacing;
151 }
152 if(zoomedOut){
153 position += zoom;
154 } else {
155 position += (1.0 / zoom);
156 }
157 }
158 }
159
160 private final double getFirstPositionMarkerPlacement(){
161 final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
162
163 double nextPositionMarker = 0.0;
164 if(graphPosition < 0.0){
165 while (nextPositionMarker - graphPosition >= majorGraduationSpacing){
166 nextPositionMarker -= majorGraduationSpacing;
167 }
168 } else {
169 while (nextPositionMarker - graphPosition < 0.0){
170 nextPositionMarker += majorGraduationSpacing;
171 }
172 }
173
174 nextPositionMarker -= majorGraduationSpacing;
175 return nextPositionMarker;
176 }
177
178 private void setupMouseCursorLineSnappingPositions() {
179 validSnappingPositions = new boolean[this.getWidth()];
180 final double graphPosition = OpenLogViewer.getInstance().getEntireGraphingPanel().getGraphPosition();
181 final int zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
182 long count = Math.round(graphPosition * zoom);
183
184
185 for (int i = 0; i < this.getWidth(); i++) {
186 if (count % zoom == 0) {
187 validSnappingPositions[i] = true;
188 }
189 count++;
190 }
191 }
192
193 public final void setLog(final GenericLog log) {
194 genLog = log;
195 repaint();
196 }
197
198 private void setGraduationSpacing() {
199 int zoom = 1;
200 boolean zoomedOut = false;
201 if (OpenLogViewer.getInstance() != null) {
202 zoom = OpenLogViewer.getInstance().getEntireGraphingPanel().getZoom();
203 zoomedOut = OpenLogViewer.getInstance().getEntireGraphingPanel().isZoomedOutBeyondOneToOne();
204 }
205
206 majorGraduationSpacing = 100.0;
207 int count = (int)(Math.log((double)zoom) / Math.log(2.0));
208
209 if (zoomedOut){
210 for (int i = 0; i < count; i++){
211 majorGraduationSpacing *= graduationSpacingMultiplier[i % 3];
212
213 }
214 } else {
215 for (int i = 0; i < count; i++){
216 majorGraduationSpacing /= graduationSpacingMultiplier[i % 3];
217 }
218 }
219 }
220
221 public final int getBestSnappingPosition(final int xMouseCoord) {
222 int bestPosition = 0;
223 if (validSnappingPositions[xMouseCoord]) {
224 bestPosition = xMouseCoord;
225 } else {
226 boolean found = false;
227 final int startPosition = xMouseCoord;
228 for (int distance = 1; !found; distance++) {
229 final int next = startPosition + distance;
230 final int prev = startPosition - distance;
231 if (next > validSnappingPositions.length - 1 || prev < 0) {
232 bestPosition = xMouseCoord;
233 found = true;
234 } else if (validSnappingPositions[next]) {
235 bestPosition = next;
236 found = true;
237 } else if (validSnappingPositions[prev]) {
238 bestPosition = prev;
239 found = true;
240 }
241 }
242 }
243 return bestPosition;
244 }
245
246
247
248
249
250
251
252
253
254 private final String roundDecimalsOnlyToTwoSignificantFigures(final BigDecimal input) {
255 String result = "";
256 int indexOfMostSignificantDigit = 0;
257
258
259 result = input.toPlainString();
260 if(result.substring(0, 1).equalsIgnoreCase("-")){
261 indexOfMostSignificantDigit++;
262 }
263
264
265
266
267 int amountOfIntegerDigits = 0;
268 int amountOfLeadingZerosInDecimalPortion = 0;
269 final int indexOfDecimalPoint = result.indexOf('.');
270 if (indexOfDecimalPoint != -1){
271 amountOfIntegerDigits = result.substring(indexOfMostSignificantDigit, indexOfDecimalPoint).length();
272 boolean done = false;
273 for (int i = indexOfDecimalPoint + 1; i < result.length() && !done; i++){
274 if (result.substring(i, i).equalsIgnoreCase("0")){
275 amountOfLeadingZerosInDecimalPortion++;
276 } else {
277 done = true;
278 }
279 }
280
281 } else {
282 amountOfIntegerDigits = result.substring(indexOfMostSignificantDigit).length();
283
284 }
285 final int amountOfDesiredDecimalDigits = amountOfLeadingZerosInDecimalPortion + 2;
286 final int sigFigs = amountOfIntegerDigits + amountOfDesiredDecimalDigits;
287 BigDecimal roundedInput = input.round(new MathContext(sigFigs));
288 roundedInput = roundedInput.stripTrailingZeros();
289 result = roundedInput.toPlainString();
290
291
292 if (result.indexOf('.') == -1){
293 result = result + ".0";
294 }
295
296
297 if(result.length() > 16){
298 if (result.substring(0, 16).equalsIgnoreCase("-0.0000000000000")
299 || result.substring(0, 15).equalsIgnoreCase("0.0000000000000")){
300 result = "0.0";
301 }
302 }
303
304 return result;
305 }
306 }