1 // Copyright 2005 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS-IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Original author: ericv@google.com (Eric Veach) 16 // Converted to D: madric@gmail.com (Vijay Nayar) 17 18 module s2.s2metrics; 19 20 // The following are various constants that describe the shapes and sizes of 21 // S2Cells (see s2coords.h and s2cell_id.h). They are useful for deciding 22 // which cell level to use in order to satisfy a given condition (e.g. that 23 // cell vertices must be no further than "x" apart). All of the raw constants 24 // are differential quantities; you can use the GetValue(level) method to 25 // compute the corresponding length or area on the unit sphere for cells at a 26 // given level. The minimum and maximum bounds are valid for cells at all 27 // levels, but they may be somewhat conservative for very large cells 28 // (e.g. face cells). 29 30 import s2coords = s2.s2coords; 31 import algorithm = std.algorithm; 32 import math = std.math; 33 import s2.util.math.s2const; 34 35 // Defines a cell metric of the given dimension (1 == length, 2 == area). 36 struct Metric(int DimV) { 37 private: 38 immutable double _deriv; 39 40 public: 41 this(double deriv) { 42 _deriv = deriv; 43 } 44 45 // The "deriv" value of a metric is a derivative, and must be multiplied by 46 // a length or area in (s,t)-space to get a useful value. 47 @property 48 double deriv() const { 49 return _deriv; 50 } 51 52 // Return the value of a metric for cells at the given level. The value is 53 // either a length or an area on the unit sphere, depending on the 54 // particular metric. 55 double getValue(int level) const { 56 return math.ldexp(_deriv, -DimV * level); 57 } 58 59 // Return the level at which the metric has approximately the given 60 // value. For example, S2::kAvgEdge.GetClosestLevel(0.1) returns the 61 // level at which the average cell edge length is approximately 0.1. 62 // The return value is always a valid level. 63 int getClosestLevel(double value) const { 64 return getLevelForMaxValue((DimV == 1 ? math.SQRT2 : 2) * value); 65 } 66 67 // Return the minimum level such that the metric is at most the given 68 // value, or S2CellId::kMaxLevel if there is no such level. For example, 69 // S2::kMaxDiag.GetLevelForMaxValue(0.1) returns the minimum level such 70 // that all cell diagonal lengths are 0.1 or smaller. The return value 71 // is always a valid level. 72 int getLevelForMaxValue(double value) const 73 out (level) { 74 assert(level == s2coords.MAX_CELL_LEVEL || getValue(level) <= value); 75 assert(level == 0 || getValue(level - 1) > value); 76 } do { 77 if (value <= 0) { 78 return s2coords.MAX_CELL_LEVEL; 79 } 80 81 // This code is equivalent to computing a floating-point "level" 82 // value and rounding up. ilogb() returns the exponent corresponding to a 83 // fraction in the range [1,2). 84 int level = math.ilogb(value / _deriv); 85 level = algorithm.max(0, algorithm.min(s2coords.MAX_CELL_LEVEL, -(level >> (DimV - 1)))); 86 return level; 87 } 88 89 // Return the maximum level such that the metric is at least the given 90 // value, or zero if there is no such level. For example, 91 // S2::kMinWidth.GetLevelForMinValue(0.1) returns the maximum level such 92 // that all cells have a minimum width of 0.1 or larger. The return value 93 // is always a valid level. 94 int getLevelForMinValue(double value) const 95 out (level) { 96 assert(level == 0 || getValue(level) >= value); 97 assert(level == s2coords.MAX_CELL_LEVEL || getValue(level + 1) < value); 98 } do { 99 if (value <= 0) { 100 return s2coords.MAX_CELL_LEVEL; 101 } 102 103 // This code is equivalent to computing a floating-point "level" 104 // value and rounding down. 105 int level = math.ilogb(_deriv / value); 106 level = algorithm.max(0, algorithm.min(s2coords.MAX_CELL_LEVEL, level >> (DimV - 1))); 107 return level; 108 } 109 } 110 111 alias LengthMetric = Metric!1; 112 alias AreaMetric = Metric!2; 113 114 version = S2_QUADRATIC_PROJECTION; 115 116 // Each cell is bounded by four planes passing through its four edges and 117 // the center of the sphere. These metrics relate to the angle between each 118 // pair of opposite bounding planes, or equivalently, between the planes 119 // corresponding to two different s-values or two different t-values. For 120 // example, the maximum angle between opposite bounding planes for a cell at 121 // level k is kMaxAngleSpan.GetValue(k), and the average angle span for all 122 // cells at level k is approximately kAvgAngleSpan.GetValue(k). 123 version (S2_LINEAR_PROJECTION) { 124 immutable LengthMetric MIN_ANGLE_SPAN = LengthMetric(1.0); // 1.000 125 immutable LengthMetric MAX_ANGLE_SPAN = LengthMetric(2.0); // 2.000 126 } 127 version (S2_TAN_PROJECTION) { 128 immutable LengthMetric MIN_ANGLE_SPAN = LengthMetric(M_PI / 2); // 1.571 129 immutable LengthMetric MAX_ANGLE_SPAN = LengthMetric(M_PI / 2); // 1.571 130 } 131 version (S2_QUADRATIC_PROJECTION) { 132 immutable LengthMetric MIN_ANGLE_SPAN = LengthMetric(4.0 / 3); // 1.333 133 immutable LengthMetric MAX_ANGLE_SPAN = LengthMetric(1.704897179199218452); // 1.705 134 } 135 136 // This is true for all projections. 137 immutable LengthMetric AVG_ANGLE_SPAN = LengthMetric(M_PI / 2); // 1.571 138 139 // The width of geometric figure is defined as the distance between two 140 // parallel bounding lines in a given direction. For cells, the minimum 141 // width is always attained between two opposite edges, and the maximum 142 // width is attained between two opposite vertices. However, for our 143 // purposes we redefine the width of a cell as the perpendicular distance 144 // between a pair of opposite edges. A cell therefore has two widths, one 145 // in each direction. The minimum width according to this definition agrees 146 // with the classic geometric one, but the maximum width is different. (The 147 // maximum geometric width corresponds to kMaxDiag defined below.) 148 // 149 // For a cell at level k, the distance between opposite edges is at least 150 // kMinWidth.GetValue(k) and at most kMaxWidth.GetValue(k). The average 151 // width in both directions for all cells at level k is approximately 152 // kAvgWidth.GetValue(k). 153 // 154 // The width is useful for bounding the minimum or maximum distance from a 155 // point on one edge of a cell to the closest point on the opposite edge. 156 // For example, this is useful when "growing" regions by a fixed distance. 157 // 158 // Note that because S2Cells are not usually rectangles, the minimum width of 159 // a cell is generally smaller than its minimum edge length. (The interior 160 // angles of an S2Cell range from 60 to 120 degrees.) 161 version (S2_LINEAR_PROJECTION) { 162 immutable LengthMetric MIN_WIDTH = LengthMetric(math.sqrt(2.0 / 3)); // 0.816 163 immutable LengthMetric AVG_WIDTH = LengthMetric(1.411459345844456965); // 1.411 164 } 165 166 version (S2_TAN_PROJECTION) { 167 immutable LengthMetric MIN_WIDTH = LengthMetric(M_PI / (2 * math.sqrt(2.0))); // 1.111 168 immutable LengthMetric AVG_WIDTH = LengthMetric(1.437318638925160885); // 1.437 169 } 170 171 version (S2_QUADRATIC_PROJECTION) { 172 immutable LengthMetric MIN_WIDTH = LengthMetric(2 * math.sqrt(2.0) / 3); // 0.943 173 immutable LengthMetric AVG_WIDTH = LengthMetric(1.434523672886099389); // 1.435 174 } 175 176 // This is true for all projections. 177 immutable LengthMetric MAX_WIDTH = LengthMetric(MAX_ANGLE_SPAN.deriv()); 178 179 // The minimum edge length of any cell at level k is at least 180 // kMinEdge.GetValue(k), and the maximum is at most kMaxEdge.GetValue(k). 181 // The average edge length is approximately kAvgEdge.GetValue(k). 182 // 183 // The edge length metrics can also be used to bound the minimum, maximum, 184 // or average distance from the center of one cell to the center of one of 185 // its edge neighbors. In particular, it can be used to bound the distance 186 // between adjacent cell centers along the space-filling Hilbert curve for 187 // cells at any given level. 188 version (S2_LINEAR_PROJECTION) { 189 immutable LengthMetric MIN_EDGE = LengthMetric(2 * math.sqrt(2.0) / 3); // 0.943 190 immutable LengthMetric AVG_EDGE = LengthMetric(1.440034192955603643); // 1.440 191 } 192 version (S2_TAN_PROJECTION) { 193 immutable LengthMetric MIN_EDGE = LengthMetric(M_PI / (2 * math.sqrt(2.0))); // 1.111 194 immutable LengthMetric AVG_EDGE = LengthMetric(1.461667032546739266); // 1.462 195 } 196 version (S2_QUADRATIC_PROJECTION) { 197 immutable LengthMetric MIN_EDGE = LengthMetric(2 * math.sqrt(2.0) / 3); // 0.943 198 immutable LengthMetric AVG_EDGE = LengthMetric(1.459213746386106062); // 1.459 199 } 200 // This is true for all projections. 201 immutable LengthMetric MAX_EDGE = LengthMetric(MAX_ANGLE_SPAN.deriv()); 202 203 // The minimum diagonal length of any cell at level k is at least 204 // kMinDiag.GetValue(k), and the maximum is at most kMaxDiag.GetValue(k). 205 // The average diagonal length is approximately kAvgDiag.GetValue(k). 206 // 207 // The maximum diagonal also happens to be the maximum diameter of any cell, 208 // and also the maximum geometric width (see the discussion above). So for 209 // example, the distance from an arbitrary point to the closest cell center 210 // at a given level is at most half the maximum diagonal length. 211 version (S2_LINEAR_PROJECTION) { 212 immutable LengthMetric MIN_DIAG = LengthMetric(2 * math.sqrt(2.0) / 3); // 0.943 213 immutable LengthMetric MAX_DIAG = LengthMetric(2 * math.sqrt(2.0)); // 2.828 214 immutable LengthMetric AVG_DIAG = LengthMetric(2.031817866418812674); // 2.032 215 } 216 version (S2_TAN_PROJECTION) { 217 immutable LengthMetric MIN_DIAG = LengthMetric(M_PI * math.sqrt(2.0) / 3); // 1.481 218 immutable LengthMetric MAX_DIAG = LengthMetric(M_PI * math.sqrt(2.0 / 3)); // 2.565 219 immutable LengthMetric AVG_DIAG = LengthMetric(2.063623197195635753); // 2.064 220 } 221 version (S2_QUADRATIC_PROJECTION) { 222 immutable LengthMetric MIN_DIAG = LengthMetric(8 * math.sqrt(2.0) / 9); // 1.257 223 immutable LengthMetric MAX_DIAG = LengthMetric(2.438654594434021032); // 2.439 224 immutable LengthMetric AVG_DIAG = LengthMetric(2.060422738998471683); // 2.060 225 } 226 227 // The minimum area of any cell at level k is at least kMinArea.GetValue(k), 228 // and the maximum is at most kMaxArea.GetValue(k). The average area of all 229 // cells at level k is exactly kAvgArea.GetValue(k). 230 version (S2_LINEAR_PROJECTION) { 231 immutable AreaMetric MIN_AREA = AreaMetric(4 / (3 * math.sqrt(3))); // 0.770 232 immutable AreaMetric MAX_AREA = AreaMetric(4); // 4.000 233 } 234 version (S2_TAN_PROJECTION) { 235 immutable AreaMetric MIN_AREA = AreaMetric((M_PI*M_PI) / (4*math.sqrt(2.0))); // 1.745 236 immutable AreaMetric MAX_AREA = AreaMetric(M_PI * M_PI / 4); // 2.467 237 } 238 version (S2_QUADRATIC_PROJECTION) { 239 immutable AreaMetric MIN_AREA = AreaMetric(8 * math.sqrt(2.0) / 9); // 1.257 240 immutable AreaMetric MAX_AREA = AreaMetric(2.635799256963161491); // 2.636 241 } 242 immutable AreaMetric AVG_AREA = AreaMetric(4 * M_PI / 6); // 2.094 243 244 // This is the maximum edge aspect ratio over all cells at any level, where 245 // the edge aspect ratio of a cell is defined as the ratio of its longest 246 // edge length to its shortest edge length. 247 version (S2_LINEAR_PROJECTION) { 248 immutable double MAX_EDGE_ASPECT = math.sqrt(2); // 1.414 249 } 250 version (S2_TAN_PROJECTION) { 251 immutable double MAX_EDGE_ASPECT = math.sqrt(2); // 1.414 252 } 253 version (S2_QUADRATIC_PROJECTION) { 254 immutable double MAX_EDGE_ASPECT = 1.442615274452682920; // 1.443 255 } 256 257 // This is the maximum diagonal aspect ratio over all cells at any level, 258 // where the diagonal aspect ratio of a cell is defined as the ratio of its 259 // longest diagonal length to its shortest diagonal length. 260 immutable double MAX_DIAG_ASPECT = math.sqrt(3.0); // 1.732