summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
blob: fbcf9afb289123aef633012273f131276b4b8908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package com.mapbox.mapboxsdk.utils;

import android.graphics.PointF;
import android.support.annotation.Nullable;

// TODO Remove this class if we finally include it within MAS 3.x (GeoJSON)
public class MathUtils {

  /**
   * Test a value in specified range, returning minimum if it's below, and maximum if it's above
   *
   * @param value Value to test
   * @param min   Minimum value of range
   * @param max   Maximum value of range
   * @return value if it's between min and max, min if it's below, max if it's above
   */
  public static double clamp(double value, double min, double max) {
    return Math.max(min, Math.min(max, value));
  }

  /**
   * Test a value in specified range, returning minimum if it's below, and maximum if it's above
   *
   * @param value Value to test
   * @param min   Minimum value of range
   * @param max   Maximum value of range
   * @return value if it's between min and max, min if it's below, max if it's above
   */
  public static float clamp(float value, float min, float max) {
    return Math.max(min, Math.min(max, value));
  }

  /**
   * Constrains value to the given range (including min, excluding max) via modular arithmetic.
   * <p>
   * Same formula as used in Core GL (wrap.hpp)
   * std::fmod((std::fmod((value - min), d) + d), d) + min;
   *
   * @param value Value to wrap
   * @param min   Minimum value
   * @param max   Maximum value
   * @return Wrapped value
   */
  public static double wrap(double value, double min, double max) {
    double delta = max - min;

    double firstMod = (value - min) % delta;
    double secondMod = (firstMod + delta) % delta;

    return secondMod + min;
  }

  /**
   * Look for the intersection point of two segments, if exist.
   *
   * @param point0 first point of the first segment
   * @param point1 second point of the first segment
   * @param point2 first point of the second segment
   * @param point3 second point of the second segment
   * @return intersection point, if exists
   */
  @Nullable
  public static PointF findSegmentsIntersection(PointF point0, PointF point1, PointF point2, PointF point3) {
    // Java port of one of the algorithms discussed in https://stackoverflow.com/questions/563198/
    float dx1 = point1.x - point0.x;
    float dy1 = point1.y - point0.y;
    float dx2 = point3.x - point2.x;
    float dy2 = point3.y - point2.y;
    float dx3 = point0.x - point2.x;
    float dy3 = point0.y - point2.y;

    float d = dx1 * dy2 - dx2 * dy1;

    if (d != 0) {
      float s = dx1 * dy3 - dx3 * dy1;
      if ((s <= 0 && d < 0 && s >= d) || (s >= 0 && d > 0 && s <= d)) {
        float t = dx2 * dy3 - dx3 * dy2;
        if ((t <= 0 && d < 0 && t > d) || (t >= 0 && d > 0 && t < d)) {
          t = t / d;
          return new PointF(point0.x + t * dx1, point0.y + t * dy1);
        }
      }
    }
    return null;
  }

  /**
   * Returns a distance between two points.
   *
   * @param point0 first point
   * @param point1 second point
   * @return distance in pixels
   */
  public static float distance(PointF point0, PointF point1) {
    return (float) Math.sqrt(Math.pow(point1.x - point0.x, 2) + Math.pow(point1.y - point0.y, 2));
  }

  /**
   * Rounds a number.
   * @param value original value
   * @param precision expected precision
   * @return rounded number
   */
  public static double round(double value, int precision) {
    int scale = (int) Math.pow(10, precision);
    return (double) Math.round(value * scale) / scale;
  }
}