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