6e1d800181f7b6957c77d3dc539b6bf309baf9b9
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / widgets / Utils.java
1 /*****************************************************************************
2 * Copyright (c) 2007, 2017 Intel Corporation, Ericsson
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Intel Corporation - Initial API and implementation
10 * Ruslan A. Scherbakov, Intel - Initial API and implementation
11 * Alvaro Sanchez-Leon - Udpated for TMF
12 * Patrick Tasse - Refactoring
13 * Marc-Andre Laperle - Add time zone preference
14 *****************************************************************************/
15
16 package org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets;
17
18 import java.text.NumberFormat;
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
21 import java.util.Iterator;
22 import java.util.TimeZone;
23 import java.util.concurrent.TimeUnit;
24
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.graphics.Color;
28 import org.eclipse.swt.graphics.Device;
29 import org.eclipse.swt.graphics.GC;
30 import org.eclipse.swt.graphics.Point;
31 import org.eclipse.swt.graphics.RGB;
32 import org.eclipse.swt.graphics.Rectangle;
33 import org.eclipse.swt.widgets.Display;
34 import org.eclipse.tracecompass.common.core.format.DecimalUnitFormat;
35 import org.eclipse.tracecompass.internal.tmf.ui.Messages;
36 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimePreferences;
37 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
38 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
39
40 /**
41 * General utilities and definitions used by the time graph widget
42 *
43 * @author Alvaro Sanchez-Leon
44 * @author Patrick Tasse
45 */
46 public class Utils {
47
48 private Utils() {
49 }
50
51 /** Time format for dates and timestamp */
52 public enum TimeFormat {
53 /** Relative to the start of the trace */
54 RELATIVE,
55
56 /**
57 * Absolute timestamp (ie, relative to the Unix epoch)
58 */
59 CALENDAR,
60
61 /**
62 * Timestamp displayed as a simple number
63 */
64 NUMBER,
65
66 /**
67 * Timestamp displayed as cycles
68 */
69 CYCLES
70 }
71
72 /**
73 * Timestamp resolution
74 */
75 public static enum Resolution {
76 /** seconds */
77 SECONDS,
78
79 /** milliseconds */
80 MILLISEC,
81
82 /** microseconds */
83 MICROSEC,
84
85 /** nanoseconds */
86 NANOSEC
87 }
88
89 /**
90 * Ellipsis character, used to shorten strings that don't fit in their
91 * target area.
92 *
93 * @since 2.1
94 */
95 public static final String ELLIPSIS = "…"; //$NON-NLS-1$
96
97 private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
98 private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
99 private static final long HOURS_PER_DAY = 24;
100 private static final long MIN_PER_HOUR = 60;
101 private static final long SEC_PER_MIN = 60;
102 private static final long SEC_IN_NS = 1000000000;
103 private static final long MILLISEC_IN_NS = 1000000;
104
105 /**
106 * Update the time and date formats to use the current time zone
107 */
108 public static void updateTimeZone() {
109 TimeZone timeZone = TmfTimePreferences.getTimeZone();
110 TIME_FORMAT.setTimeZone(timeZone);
111 DATE_FORMAT.setTimeZone(timeZone);
112 }
113
114 static Rectangle clone(Rectangle source) {
115 return new Rectangle(source.x, source.y, source.width, source.height);
116 }
117
118 /**
119 * Initialize a Rectangle object to default values (all equal to 0)
120 *
121 * @param rect
122 * The Rectangle to initialize
123 */
124 public static void init(Rectangle rect) {
125 rect.x = 0;
126 rect.y = 0;
127 rect.width = 0;
128 rect.height = 0;
129 }
130
131 /**
132 * Initialize a Rectangle object with all the given values
133 *
134 * @param rect
135 * The Rectangle object to initialize
136 * @param x
137 * The X coordinate
138 * @param y
139 * The Y coordinate
140 * @param width
141 * The width of the rectangle
142 * @param height
143 * The height of the rectangle
144 */
145 public static void init(Rectangle rect, int x, int y, int width, int height) {
146 rect.x = x;
147 rect.y = y;
148 rect.width = width;
149 rect.height = height;
150 }
151
152 /**
153 * Initialize a Rectangle object to another existing Rectangle's values.
154 *
155 * @param rect
156 * The Rectangle to initialize
157 * @param source
158 * The reference Rectangle to copy
159 */
160 public static void init(Rectangle rect, Rectangle source) {
161 rect.x = source.x;
162 rect.y = source.y;
163 rect.width = source.width;
164 rect.height = source.height;
165 }
166
167 /**
168 * Reduce the size of a given rectangle by the given amounts.
169 *
170 * @param rect
171 * The rectangle to modify
172 * @param x
173 * The reduction in width
174 * @param y
175 * The reduction in height
176 */
177 public static void deflate(Rectangle rect, int x, int y) {
178 rect.x += x;
179 rect.y += y;
180 rect.width -= x + x;
181 rect.height -= y + y;
182 }
183
184 /**
185 * Increase the size of a given rectangle by the given amounts.
186 *
187 * @param rect
188 * The rectangle to modify
189 * @param x
190 * The augmentation in width
191 * @param y
192 * The augmentation in height
193 */
194 public static void inflate(Rectangle rect, int x, int y) {
195 rect.x -= x;
196 rect.y -= y;
197 rect.width += x + x;
198 rect.height += y + y;
199 }
200
201 static void dispose(Color col) {
202 if (null != col) {
203 col.dispose();
204 }
205 }
206
207 /**
208 * Get the resulting color from a mix of two existing ones for a given
209 * display.
210 *
211 * @param display
212 * The display device (which might affect the color conversion)
213 * @param c1
214 * The first color
215 * @param c2
216 * The second color
217 * @param w1
218 * The gamma level for color 1
219 * @param w2
220 * The gamma level for color 2
221 * @return The resulting color
222 */
223 public static Color mixColors(Device display, Color c1, Color c2, int w1,
224 int w2) {
225 return new Color(display, (w1 * c1.getRed() + w2 * c2.getRed())
226 / (w1 + w2), (w1 * c1.getGreen() + w2 * c2.getGreen())
227 / (w1 + w2), (w1 * c1.getBlue() + w2 * c2.getBlue())
228 / (w1 + w2));
229 }
230
231 /**
232 * Get the system color with the given ID.
233 *
234 * @param id
235 * The color ID
236 * @return The resulting color
237 */
238 public static Color getSysColor(int id) {
239 Color col = Display.getCurrent().getSystemColor(id);
240 return new Color(col.getDevice(), col.getRGB());
241 }
242
243 /**
244 * Get the resulting color from a mix of two existing ones for the current
245 * display.
246 *
247 * @param col1
248 * The first color
249 * @param col2
250 * The second color
251 * @param w1
252 * The gamma level for color 1
253 * @param w2
254 * The gamma level for color 2
255 * @return The resulting color
256 */
257 public static Color mixColors(Color col1, Color col2, int w1, int w2) {
258 return mixColors(Display.getCurrent(), col1, col2, w1, w2);
259 }
260
261 /**
262 * Get a distinct color from the specified RGB color, based on its
263 * relative luminance.
264 *
265 * @param rgb
266 * An RGB color
267 * @return The black or white system color, whichever is more distinct.
268 * @since 2.4
269 */
270 public static Color getDistinctColor(RGB rgb) {
271 /* Calculate the relative luminance of the color, high value is bright */
272 final int luminanceThreshold = 128;
273 /* Relative luminance (Y) coefficients as defined in ITU.R Rec. 709 */
274 final double redCoefficient = 0.2126;
275 final double greenCoefficient = 0.7152;
276 final double blueCoefficient = 0.0722;
277 int luminance = (int) (redCoefficient * rgb.red + greenCoefficient * rgb.green + blueCoefficient * rgb.blue);
278 /* Use black over bright colors and white over dark colors */
279 return Display.getDefault().getSystemColor(
280 luminance > luminanceThreshold ? SWT.COLOR_BLACK : SWT.COLOR_WHITE);
281 }
282
283 /**
284 * Draw text in a rectangle.
285 *
286 * @param gc
287 * The SWT GC object
288 * @param text
289 * The text to draw
290 * @param rect
291 * The rectangle object which is being drawn
292 * @param transp
293 * If true the background will be transparent
294 * @return The width of the written text
295 */
296 public static int drawText(GC gc, String text, Rectangle rect, boolean transp) {
297 Point size = gc.stringExtent(text);
298 gc.drawText(text, rect.x, rect.y, transp);
299 return size.x;
300 }
301
302 /**
303 * Draw text at a given location.
304 *
305 * @param gc
306 * The SWT GC object
307 * @param text
308 * The text to draw
309 * @param x
310 * The X coordinate of the starting point
311 * @param y
312 * the Y coordinate of the starting point
313 * @param transp
314 * If true the background will be transparent
315 * @return The width of the written text
316 */
317 public static int drawText(GC gc, String text, int x, int y, boolean transp) {
318 Point size = gc.stringExtent(text);
319 gc.drawText(text, x, y, transp);
320 return size.x;
321 }
322
323 /**
324 * Draw text in a rectangle, trimming the text to prevent exceeding the specified width.
325 *
326 * @param gc
327 * The SWT GC object
328 * @param text
329 * The string to be drawn
330 * @param x
331 * The x coordinate of the top left corner of the rectangular area where the text is to be drawn
332 * @param y
333 * The y coordinate of the top left corner of the rectangular area where the text is to be drawn
334 * @param width
335 * The width of the area to be drawn
336 * @param isCentered
337 * If <code>true</code> the text will be centered in the available width if space permits
338 * @param isTransparent
339 * If <code>true</code> the background will be transparent, otherwise it will be opaque
340 * @return The number of characters written
341 * @deprecated Use {@link #drawText(GC, String, int, int, int, int, boolean, boolean)} instead.
342 */
343 @Deprecated
344 public static int drawText(GC gc, String text, int x, int y, int width, boolean isCentered, boolean isTransparent) {
345 if (width < 1) {
346 return 0;
347 }
348
349 int len = text.length();
350 int textWidth = 0;
351 boolean isReallyCentered = isCentered;
352 int realX = x;
353
354 while (len > 0) {
355 textWidth = gc.stringExtent(text.substring(0, len)).x;
356 if (textWidth <= width) {
357 break;
358 }
359 isReallyCentered = false;
360 len--;
361 }
362 if (len > 0) {
363 if (isReallyCentered) {
364 realX += (width - textWidth) / 2;
365 }
366 gc.drawText(text.substring(0, len), realX, y, isTransparent);
367 }
368 return len;
369 }
370
371 /**
372 * Draw text in a rectangle, trimming the text to prevent exceeding the specified width.
373 *
374 * @param gc
375 * The SWT GC object
376 * @param text
377 * The string to be drawn
378 * @param x
379 * The x coordinate of the top left corner of the rectangular area where the text is to be drawn
380 * @param y
381 * The y coordinate of the top left corner of the rectangular area where the text is to be drawn
382 * @param width
383 * The width of the area to be drawn
384 * @param height
385 * The height of the area to be drawn
386 * @param isCentered
387 * If <code>true</code> the text will be centered in the available area if space permits
388 * @param isTransparent
389 * If <code>true</code> the background will be transparent, otherwise it will be opaque
390 * @return The number of characters written
391 * @since 2.0
392 */
393 public static int drawText(GC gc, String text, int x, int y, int width, int height, boolean isCentered, boolean isTransparent) {
394 if (width < 1 || text.isEmpty()) {
395 return 0;
396 }
397
398 String stringToDisplay;
399 int len;
400
401 boolean isCenteredWidth = isCentered;
402 int realX = x;
403 int realY = y;
404
405 /* First check if the whole string fits */
406 Point textExtent = gc.textExtent(text);
407 if (textExtent.x <= width) {
408 len = text.length();
409 stringToDisplay = text;
410 } else {
411 /*
412 * The full string doesn't fit, try to find the longest one with
413 * "..." at the end that does fit.
414 *
415 * Iterate on the string length sizes, starting from 1 going up,
416 * until we find a string that does not fit. Once we do, we keep the
417 * one just before that did fit.
418 */
419 isCenteredWidth = false;
420 int prevLen = 0;
421 len = 1;
422 while (len <= text.length()) {
423 textExtent = gc.textExtent(text.substring(0, len) + ELLIPSIS);
424 if (textExtent.x > width) {
425 /*
426 * Here is the first length that does not fit, the one from
427 * the previous iteration is the one we will use.
428 */
429 len = prevLen;
430 break;
431 }
432 /* This string would fit, try the next one */
433 prevLen = len;
434 len++;
435 }
436 stringToDisplay = text.substring(0, len) + ELLIPSIS;
437 }
438
439 if (len <= 0) {
440 /* Nothing fits, we end up drawing nothing */
441 return 0;
442 }
443
444 if (isCenteredWidth) {
445 realX += (width - textExtent.x) / 2;
446 }
447 if (isCentered) {
448 realY += (height - textExtent.y) / 2 - 1;
449 }
450 gc.drawText(stringToDisplay, realX, realY, isTransparent);
451
452 return len;
453 }
454
455 /**
456 * Formats time in format: MM:SS:NNN
457 *
458 * @param time time
459 * @param format 0: MMMM:ss:nnnnnnnnn, 1: HH:MM:ss MMM.mmmm.nnn
460 * @param resolution the resolution
461 * @return the formatted time
462 */
463 public static String formatTime(long time, TimeFormat format, Resolution resolution) {
464 switch (format) {
465 case CALENDAR:
466 return formatTimeAbs(time, resolution);
467 case NUMBER:
468 return NumberFormat.getInstance().format(time);
469 case CYCLES:
470 return NumberFormat.getInstance().format(time) + Messages.Utils_ClockCyclesUnit;
471 case RELATIVE:
472 default:
473 }
474
475 StringBuffer str = new StringBuffer();
476 long t = time;
477 boolean neg = t < 0;
478 if (neg) {
479 t = -t;
480 str.append('-');
481 }
482
483 long sec = t / SEC_IN_NS;
484 str.append(sec);
485 String ns = formatNs(t, resolution);
486 if (!ns.equals("")) { //$NON-NLS-1$
487 str.append('.');
488 str.append(ns);
489 }
490
491 return str.toString();
492 }
493
494 /**
495 * From input time in nanoseconds, convert to Date format YYYY-MM-dd
496 *
497 * @param absTime
498 * The source time, in ns
499 * @return the formatted date
500 */
501 public static String formatDate(long absTime) {
502 String sdate = DATE_FORMAT.format(new Date(absTime / MILLISEC_IN_NS));
503 return sdate;
504 }
505
506 /**
507 * Formats time in ns to Calendar format: HH:MM:SS MMM.mmm.nnn
508 *
509 * @param time
510 * The source time, in ns
511 * @param res
512 * The resolution to use
513 * @return the formatted time
514 */
515 public static String formatTimeAbs(long time, Resolution res) {
516 StringBuffer str = new StringBuffer();
517
518 // format time from nanoseconds to calendar time HH:MM:SS
519 String stime = TIME_FORMAT.format(new Date(time / MILLISEC_IN_NS));
520 str.append(stime);
521 String ns = formatNs(time, res);
522 if (!ns.isEmpty()) {
523 str.append('.');
524 /*
525 * append the Milliseconds, MicroSeconds and NanoSeconds as
526 * specified in the Resolution
527 */
528 str.append(ns);
529 }
530 return str.toString();
531 }
532
533 /**
534 * Formats time delta
535 *
536 * @param delta
537 * The time delta, in ns
538 * @param format
539 * The time format to use
540 * @param resolution
541 * The resolution to use
542 * @return the formatted time delta
543 */
544 public static String formatDelta(long delta, TimeFormat format, Resolution resolution) {
545 if (format == TimeFormat.CALENDAR) {
546 return formatDeltaAbs(delta, resolution);
547 }
548 return formatTime(delta, format, resolution);
549 }
550
551 /**
552 * Formats time delta in ns to Calendar format, only formatting the years,
553 * days, hours or minutes if necessary.
554 *
555 * @param delta
556 * The time delta, in ns
557 * @param resolution
558 * The resolution to use
559 * @return the formatted time delta
560 */
561 public static String formatDeltaAbs(long delta, Resolution resolution) {
562 StringBuffer str = new StringBuffer();
563 if (delta < 0) {
564 str.append('-');
565 }
566 long ns = Math.abs(delta);
567 long seconds = TimeUnit.NANOSECONDS.toSeconds(ns);
568 long minutes = TimeUnit.NANOSECONDS.toMinutes(ns);
569 long hours = TimeUnit.NANOSECONDS.toHours(ns);
570 long days = TimeUnit.NANOSECONDS.toDays(ns);
571 if (days > 0) {
572 str.append(days);
573 str.append("d "); //$NON-NLS-1$
574 }
575 if (hours > 0) {
576 str.append(hours % HOURS_PER_DAY);
577 str.append("h "); //$NON-NLS-1$
578 }
579 if (minutes > 0) {
580 str.append(minutes % MIN_PER_HOUR);
581 str.append("m "); //$NON-NLS-1$
582 }
583 str.append(seconds % SEC_PER_MIN);
584 str.append('.');
585 // append the ms, us and ns as specified in the resolution
586 str.append(formatNs(delta, resolution));
587 str.append("s"); //$NON-NLS-1$
588 if (seconds == 0) {
589 str.append(" ("); //$NON-NLS-1$
590 str.append(new DecimalUnitFormat(1.0 / SEC_IN_NS).format(delta));
591 str.append("s)"); //$NON-NLS-1$
592 }
593 return str.toString();
594 }
595
596 /**
597 * Obtains the remainder fraction on unit Seconds of the entered value in
598 * nanoseconds. e.g. input: 1241207054171080214 ns The number of fraction
599 * seconds can be obtained by removing the last 9 digits: 1241207054 the
600 * fractional portion of seconds, expressed in ns is: 171080214
601 *
602 * @param srcTime
603 * The source time in ns
604 * @param res
605 * The Resolution to use
606 * @return the formatted nanosec
607 */
608 public static String formatNs(long srcTime, Resolution res) {
609 StringBuffer str = new StringBuffer();
610 long ns = Math.abs(srcTime % SEC_IN_NS);
611 String nanos = Long.toString(ns);
612 str.append("000000000".substring(nanos.length())); //$NON-NLS-1$
613 str.append(nanos);
614
615 if (res == Resolution.MILLISEC) {
616 return str.substring(0, 3);
617 } else if (res == Resolution.MICROSEC) {
618 return str.substring(0, 6);
619 } else if (res == Resolution.NANOSEC) {
620 return str.substring(0, 9);
621 }
622 return ""; //$NON-NLS-1$
623 }
624
625 /**
626 * FIXME Currently does nothing.
627 *
628 * @param opt
629 * The option name
630 * @param def
631 * The option value
632 * @param min
633 * The minimal accepted value
634 * @param max
635 * The maximal accepted value
636 * @return The value that was read
637 */
638 public static int loadIntOption(String opt, int def, int min, int max) {
639 return def;
640 }
641
642 /**
643 * FIXME currently does nothing
644 *
645 * @param opt
646 * The option name
647 * @param val
648 * The option value
649 */
650 public static void saveIntOption(String opt, int val) {
651 }
652
653 static ITimeEvent getFirstEvent(ITimeGraphEntry entry) {
654 if (null == entry || ! entry.hasTimeEvents()) {
655 return null;
656 }
657 Iterator<? extends ITimeEvent> iterator = entry.getTimeEventsIterator();
658 if (iterator != null && iterator.hasNext()) {
659 return iterator.next();
660 }
661 return null;
662 }
663
664 /**
665 * Gets the {@link ITimeEvent} at the given time from the given
666 * {@link ITimeGraphEntry}.
667 *
668 * @param entry
669 * a {@link ITimeGraphEntry}
670 * @param time
671 * a timestamp
672 * @param n
673 * this parameter means: <list> <li>-1: Previous Event</li> <li>
674 * 0: Current Event</li> <li>
675 * 1: Next Event</li> <li>2: Previous Event when located in a non
676 * Event Area </list>
677 * @return a {@link ITimeEvent}, or <code>null</code>.
678 */
679 public static ITimeEvent findEvent(ITimeGraphEntry entry, long time, int n) {
680 if (null == entry || ! entry.hasTimeEvents()) {
681 return null;
682 }
683 Iterator<@NonNull ? extends ITimeEvent> iterator = entry.getTimeEventsIterator();
684 if (iterator == null) {
685 return null;
686 }
687 ITimeEvent nextEvent = null;
688 ITimeEvent currEvent = null;
689 ITimeEvent prevEvent = null;
690
691 while (iterator.hasNext()) {
692 nextEvent = iterator.next();
693 long nextStartTime = nextEvent.getTime();
694
695 if (nextStartTime > time) {
696 break;
697 }
698
699 if (currEvent == null || currEvent.getTime() != nextStartTime ||
700 (nextStartTime != time && currEvent.getDuration() != nextEvent.getDuration())) {
701 prevEvent = currEvent;
702 currEvent = nextEvent;
703 }
704 }
705
706 if (n == -1) { //previous
707 if (currEvent != null && currEvent.getTime() + currEvent.getDuration() >= time) {
708 return prevEvent;
709 }
710 return currEvent;
711 } else if (n == 0) { //current
712 if (currEvent != null && currEvent.getTime() + currEvent.getDuration() >= time) {
713 return currEvent;
714 }
715 return null;
716 } else if (n == 1) { //next
717 if (nextEvent != null && nextEvent.getTime() > time) {
718 return nextEvent;
719 }
720 return null;
721 } else if (n == 2) { //current or previous when in empty space
722 return currEvent;
723 }
724
725 return null;
726 }
727
728 /**
729 * Pretty-print a method signature.
730 *
731 * @param origSig
732 * The original signature
733 * @return The pretty signature
734 */
735 public static String fixMethodSignature(String origSig) {
736 String sig = origSig;
737 int pos = sig.indexOf('(');
738 if (pos >= 0) {
739 String ret = sig.substring(0, pos);
740 sig = sig.substring(pos);
741 sig = sig + " " + ret; //$NON-NLS-1$
742 }
743 return sig;
744 }
745
746 /**
747 * Restore an original method signature from a pretty-printed one.
748 *
749 * @param ppSig
750 * The pretty-printed signature
751 * @return The original method signature
752 */
753 public static String restoreMethodSignature(String ppSig) {
754 String ret = ""; //$NON-NLS-1$
755 String sig = ppSig;
756
757 int pos = sig.indexOf('(');
758 if (pos >= 0) {
759 ret = sig.substring(0, pos);
760 sig = sig.substring(pos + 1);
761 }
762 pos = sig.indexOf(')');
763 if (pos >= 0) {
764 sig = sig.substring(0, pos);
765 }
766 String args[] = sig.split(","); //$NON-NLS-1$
767 StringBuffer result = new StringBuffer("("); //$NON-NLS-1$
768 for (int i = 0; i < args.length; i++) {
769 String arg = args[i].trim();
770 if (arg.length() == 0 && args.length == 1) {
771 break;
772 }
773 result.append(getTypeSignature(arg));
774 }
775 result.append(")").append(getTypeSignature(ret)); //$NON-NLS-1$
776 return result.toString();
777 }
778
779 /**
780 * Get the mangled type information from an array of types.
781 *
782 * @param typeStr
783 * The types to convert. See method implementation for what it
784 * expects.
785 * @return The mangled string of types
786 */
787 public static String getTypeSignature(String typeStr) {
788 int dim = 0;
789 String type = typeStr;
790 for (int j = 0; j < type.length(); j++) {
791 if (type.charAt(j) == '[') {
792 dim++;
793 }
794 }
795 int pos = type.indexOf('[');
796 if (pos >= 0) {
797 type = type.substring(0, pos);
798 }
799 StringBuffer sig = new StringBuffer(""); //$NON-NLS-1$
800 for (int j = 0; j < dim; j++)
801 {
802 sig.append("["); //$NON-NLS-1$
803 }
804 if (type.equals("boolean")) { //$NON-NLS-1$
805 sig.append('Z');
806 } else if (type.equals("byte")) { //$NON-NLS-1$
807 sig.append('B');
808 } else if (type.equals("char")) { //$NON-NLS-1$
809 sig.append('C');
810 } else if (type.equals("short")) { //$NON-NLS-1$
811 sig.append('S');
812 } else if (type.equals("int")) { //$NON-NLS-1$
813 sig.append('I');
814 } else if (type.equals("long")) { //$NON-NLS-1$
815 sig.append('J');
816 } else if (type.equals("float")) { //$NON-NLS-1$
817 sig.append('F');
818 } else if (type.equals("double")) { //$NON-NLS-1$
819 sig.append('D');
820 } else if (type.equals("void")) { //$NON-NLS-1$
821 sig.append('V');
822 }
823 else {
824 sig.append('L').append(type.replace('.', '/')).append(';');
825 }
826 return sig.toString();
827 }
828
829 /**
830 * Compare two doubles together.
831 *
832 * @param d1
833 * First double
834 * @param d2
835 * Second double
836 * @return 1 if they are different, and 0 if they are *exactly* the same.
837 * Because of the way doubles are stored, it's possible for the
838 * same number obtained in two different ways to actually look
839 * different.
840 */
841 public static int compare(double d1, double d2) {
842 if (d1 > d2) {
843 return 1;
844 }
845 if (d1 < d2) {
846 return 1;
847 }
848 return 0;
849 }
850
851 /**
852 * Compare two character strings alphabetically. This is simply a wrapper
853 * around String.compareToIgnoreCase but that will handle cases where
854 * strings can be null
855 *
856 * @param s1
857 * The first string
858 * @param s2
859 * The second string
860 * @return A number below, equal, or greater than zero if the first string
861 * is smaller, equal, or bigger (alphabetically) than the second
862 * one.
863 */
864 public static int compare(String s1, String s2) {
865 if (s1 != null && s2 != null) {
866 return s1.compareToIgnoreCase(s2);
867 }
868 if (s1 != null) {
869 return 1;
870 }
871 if (s2 != null) {
872 return -1;
873 }
874 return 0;
875 }
876
877 /**
878 * Calculates the square of the distance between two points.
879 *
880 * @param x1
881 * x-coordinate of point 1
882 * @param y1
883 * y-coordinate of point 1
884 * @param x2
885 * x-coordinate of point 2
886 * @param y2
887 * y-coordinate of point 2
888 *
889 * @return the square of the distance in pixels^2
890 */
891 public static double distance2(int x1, int y1, int x2, int y2) {
892 int dx = x2 - x1;
893 int dy = y2 - y1;
894 int d2 = dx * dx + dy * dy;
895 return d2;
896 }
897
898 /**
899 * Calculates the distance between a point and a line segment. If the point
900 * is in the perpendicular region between the segment points, return the
901 * distance from the point to its projection on the segment. Otherwise
902 * return the distance from the point to its closest segment point.
903 *
904 * @param px
905 * x-coordinate of the point
906 * @param py
907 * y-coordinate of the point
908 * @param x1
909 * x-coordinate of segment point 1
910 * @param y1
911 * y-coordinate of segment point 1
912 * @param x2
913 * x-coordinate of segment point 2
914 * @param y2
915 * y-coordinate of segment point 2
916 *
917 * @return the distance in pixels
918 */
919 public static double distance(int px, int py, int x1, int y1, int x2, int y2) {
920 double length2 = distance2(x1, y1, x2, y2);
921 if (length2 == 0) {
922 return Math.sqrt(distance2(px, py, x1, y1));
923 }
924 // 'r' is the ratio of the position, between segment point 1 and segment
925 // point 2, of the projection of the point on the segment
926 double r = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / length2;
927 if (r <= 0.0) {
928 // the projection is before segment point 1, return distance from
929 // the point to segment point 1
930 return Math.sqrt(distance2(px, py, x1, y1));
931 }
932 if (r >= 1.0) {
933 // the projection is after segment point 2, return distance from
934 // the point to segment point 2
935 return Math.sqrt(distance2(px, py, x2, y2));
936 }
937 // the projection is between the segment points, return distance from
938 // the point to its projection on the segment
939 int x = (int) (x1 + r * (x2 - x1));
940 int y = (int) (y1 + r * (y2 - y1));
941 return Math.sqrt(distance2(px, py, x, y));
942 }
943 }
This page took 0.052262 seconds and 4 git commands to generate.