| // Copyright 2005 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| // Author: ericv@google.com (Eric Veach) |
| |
| #include "s2/s2coords.h" |
| |
| #include "s2/util/bits/bits.h" |
| |
| namespace S2 { |
| |
| namespace internal { |
| |
| // Define the "extern" constants in s2coords-internal.h. |
| |
| static_assert(kSwapMask == 0x01 && kInvertMask == 0x02, "masks changed"); |
| |
| // kIJtoPos[orientation][ij] -> pos |
| int const kIJtoPos[4][4] = { |
| // (0,0) (0,1) (1,0) (1,1) |
| {0, 1, 3, 2}, // canonical order |
| {0, 3, 1, 2}, // axes swapped |
| {2, 3, 1, 0}, // bits inverted |
| {2, 1, 3, 0}, // swapped & inverted |
| }; |
| |
| // kPosToIJ[orientation][pos] -> ij |
| int const kPosToIJ[4][4] = { |
| // 0 1 2 3 |
| {0, 1, 3, 2}, // canonical order: (0,0), (0,1), (1,1), (1,0) |
| {0, 2, 3, 1}, // axes swapped: (0,0), (1,0), (1,1), (0,1) |
| {3, 2, 0, 1}, // bits inverted: (1,1), (1,0), (0,0), (0,1) |
| {3, 1, 0, 2}, // swapped & inverted: (1,1), (0,1), (0,0), (1,0) |
| }; |
| |
| // kPosToOrientation[pos] -> orientation_modifier |
| int const kPosToOrientation[4] = { |
| kSwapMask, 0, 0, kInvertMask + kSwapMask, |
| }; |
| |
| int const kFaceUVWFaces[6][3][2] = { |
| {{4, 1}, {5, 2}, {3, 0}}, {{0, 3}, {5, 2}, {4, 1}}, |
| {{0, 3}, {1, 4}, {5, 2}}, {{2, 5}, {1, 4}, {0, 3}}, |
| {{2, 5}, {3, 0}, {1, 4}}, {{4, 1}, {3, 0}, {2, 5}}}; |
| |
| double const kFaceUVWAxes[6][3][3] = { |
| {{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, {{-1, 0, 0}, {0, 0, 1}, {0, 1, 0}}, |
| {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}}, {{0, 0, -1}, {0, -1, 0}, {-1, 0, 0}}, |
| {{0, 0, -1}, {1, 0, 0}, {0, -1, 0}}, {{0, 1, 0}, {1, 0, 0}, {0, 0, -1}}}; |
| |
| } // namespace internal |
| |
| S2Point FaceXYZtoUVW(int face, S2Point const& p) { |
| // The result coordinates are simply the dot products of P with the (u,v,w) |
| // axes for the given face (see kFaceUVWAxes). |
| switch (face) { |
| case 0: |
| return S2Point(p.y(), p.z(), p.x()); |
| case 1: |
| return S2Point(-p.x(), p.z(), p.y()); |
| case 2: |
| return S2Point(-p.x(), -p.y(), p.z()); |
| case 3: |
| return S2Point(-p.z(), -p.y(), -p.x()); |
| case 4: |
| return S2Point(-p.z(), p.x(), -p.y()); |
| default: |
| return S2Point(p.y(), p.x(), -p.z()); |
| } |
| } |
| |
| int XYZtoFaceSiTi(S2Point const& p, |
| int* face, |
| unsigned int* si, |
| unsigned int* ti) { |
| double u, v; |
| *face = XYZtoFaceUV(p, &u, &v); |
| *si = STtoSiTi(UVtoST(u)); |
| *ti = STtoSiTi(UVtoST(v)); |
| // If the levels corresponding to si,ti are not equal, then p is not a cell |
| // center. The si,ti values 0 and kMaxSiTi need to be handled specially |
| // because they do not correspond to cell centers at any valid level; they |
| // are mapped to level -1 by the code below. |
| int level = kMaxCellLevel - Bits::FindLSBSetNonZero(*si | kMaxSiTi); |
| if (level < 0 || |
| level != kMaxCellLevel - Bits::FindLSBSetNonZero(*ti | kMaxSiTi)) { |
| return -1; |
| } |
| DCHECK_LE(level, kMaxCellLevel); |
| // In infinite precision, this test could be changed to ST == SiTi. However, |
| // due to rounding errors, UVtoST(XYZtoFaceUV(FaceUVtoXYZ(STtoUV(...)))) is |
| // not idempotent. On the other hand, center_raw is computed exactly the same |
| // way p was originally computed (if it is indeed the center of an S2Cell): |
| // the comparison can be exact. |
| S2Point center = FaceSiTitoXYZ(*face, *si, *ti).Normalize(); |
| return p == center ? level : -1; |
| } |
| |
| S2Point FaceSiTitoXYZ(int face, unsigned int si, unsigned int ti) { |
| double u = STtoUV(SiTitoST(si)); |
| double v = STtoUV(SiTitoST(ti)); |
| return FaceUVtoXYZ(face, u, v); |
| } |
| |
| } // namespace S2 |