• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.geometry;
17 
18 /**
19  * An S2Point represents a point on the unit sphere as a 3D vector. Usually
20  * points are normalized to be unit length, but some methods do not require
21  * this.
22  *
23  */
24 public strictfp class S2Point implements Comparable<S2Point> {
25   // coordinates of the points
26   final double x;
27   final double y;
28   final double z;
29 
S2Point()30   public S2Point() {
31     x = y = z = 0;
32   }
33 
S2Point(double x, double y, double z)34   public S2Point(double x, double y, double z) {
35     this.x = x;
36     this.y = y;
37     this.z = z;
38   }
39 
minus(S2Point p1, S2Point p2)40   public static S2Point minus(S2Point p1, S2Point p2) {
41     return sub(p1, p2);
42   }
43 
neg(S2Point p)44   public static S2Point neg(S2Point p) {
45     return new S2Point(-p.x, -p.y, -p.z);
46   }
47 
norm2()48   public double norm2() {
49     return x * x + y * y + z * z;
50   }
51 
norm()52   public double norm() {
53     return Math.sqrt(norm2());
54   }
55 
crossProd(final S2Point p1, final S2Point p2)56   public static S2Point crossProd(final S2Point p1, final S2Point p2) {
57     return new S2Point(
58         p1.y * p2.z - p1.z * p2.y, p1.z * p2.x - p1.x * p2.z, p1.x * p2.y - p1.y * p2.x);
59   }
60 
add(final S2Point p1, final S2Point p2)61   public static S2Point add(final S2Point p1, final S2Point p2) {
62     return new S2Point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
63   }
64 
sub(final S2Point p1, final S2Point p2)65   public static S2Point sub(final S2Point p1, final S2Point p2) {
66     return new S2Point(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
67   }
68 
dotProd(S2Point that)69   public double dotProd(S2Point that) {
70     return this.x * that.x + this.y * that.y + this.z * that.z;
71   }
72 
mul(final S2Point p, double m)73   public static S2Point mul(final S2Point p, double m) {
74     return new S2Point(m * p.x, m * p.y, m * p.z);
75   }
76 
div(final S2Point p, double m)77   public static S2Point div(final S2Point p, double m) {
78     return new S2Point(p.x / m, p.y / m, p.z / m);
79   }
80 
81   /** return a vector orthogonal to this one */
ortho()82   public S2Point ortho() {
83     int k = largestAbsComponent();
84     S2Point temp;
85     if (k == 1) {
86       temp = new S2Point(1, 0, 0);
87     } else if (k == 2) {
88       temp = new S2Point(0, 1, 0);
89     } else {
90       temp = new S2Point(0, 0, 1);
91     }
92     return S2Point.normalize(crossProd(this, temp));
93   }
94 
95   /** Return the index of the largest component fabs */
largestAbsComponent()96   public int largestAbsComponent() {
97     S2Point temp = fabs(this);
98     if (temp.x > temp.y) {
99       if (temp.x > temp.z) {
100         return 0;
101       } else {
102         return 2;
103       }
104     } else {
105       if (temp.y > temp.z) {
106         return 1;
107       } else {
108         return 2;
109       }
110     }
111   }
112 
fabs(S2Point p)113   public static S2Point fabs(S2Point p) {
114     return new S2Point(Math.abs(p.x), Math.abs(p.y), Math.abs(p.z));
115   }
116 
normalize(S2Point p)117   public static S2Point normalize(S2Point p) {
118     double norm = p.norm();
119     if (norm != 0) {
120       norm = 1.0 / norm;
121     }
122     return S2Point.mul(p, norm);
123   }
124 
get(int axis)125   public double get(int axis) {
126     return (axis == 0) ? x : (axis == 1) ? y : z;
127   }
128 
129   /** Return the angle between two vectors in radians */
angle(S2Point va)130   public double angle(S2Point va) {
131     return Math.atan2(crossProd(this, va).norm(), this.dotProd(va));
132   }
133 
134   /**
135    * Compare two vectors, return true if all their components are within a
136    * difference of margin.
137    */
aequal(S2Point that, double margin)138   boolean aequal(S2Point that, double margin) {
139     return (Math.abs(x - that.x) < margin) && (Math.abs(y - that.y) < margin)
140         && (Math.abs(z - that.z) < margin);
141   }
142 
143   @Override
equals(Object that)144   public boolean equals(Object that) {
145     if (!(that instanceof S2Point)) {
146       return false;
147     }
148     S2Point thatPoint = (S2Point) that;
149     return this.x == thatPoint.x && this.y == thatPoint.y && this.z == thatPoint.z;
150   }
151 
lessThan(S2Point vb)152   public boolean lessThan(S2Point vb) {
153     if (x < vb.x) {
154       return true;
155     }
156     if (vb.x < x) {
157       return false;
158     }
159     if (y < vb.y) {
160       return true;
161     }
162     if (vb.y < y) {
163       return false;
164     }
165     if (z < vb.z) {
166       return true;
167     }
168     return false;
169   }
170 
171   // Required for Comparable
172   @Override
compareTo(S2Point other)173   public int compareTo(S2Point other) {
174     return (lessThan(other) ? -1 : (equals(other) ? 0 : 1));
175   }
176 
177   @Override
toString()178   public String toString() {
179     return "(" + x + ", " + y + ", " + z + ")";
180   }
181 
toDegreesString()182   public String toDegreesString() {
183     S2LatLng s2LatLng = new S2LatLng(this);
184     return "(" + Double.toString(s2LatLng.latDegrees()) + ", "
185         + Double.toString(s2LatLng.lngDegrees()) + ")";
186   }
187 
188   /**
189    * Calcualates hashcode based on stored coordinates. Since we want +0.0 and
190    * -0.0 to be treated the same, we ignore the sign of the coordinates.
191    */
192   @Override
hashCode()193   public int hashCode() {
194     long value = 17;
195     value += 37 * value + Double.doubleToLongBits(Math.abs(x));
196     value += 37 * value + Double.doubleToLongBits(Math.abs(y));
197     value += 37 * value + Double.doubleToLongBits(Math.abs(z));
198     return (int) (value ^ (value >>> 32));
199   }
200 }
201