mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 09:32:25 -05:00 
			
		
		
		
	[feature] support processing of (many) more media types (#3090)
* initial work replacing our media decoding / encoding pipeline with ffprobe + ffmpeg
* specify the video codec to use when generating static image from emoji
* update go-storage library (fixes incompatibility after updating go-iotools)
* maintain image aspect ratio when generating a thumbnail for it
* update readme to show go-ffmpreg
* fix a bunch of media tests, move filesize checking to callers of media manager for more flexibility
* remove extra debug from error message
* fix up incorrect function signatures
* update PutFile to just use regular file copy, as changes are file is on separate partition
* fix remaining tests, remove some unneeded tests now we're working with ffmpeg/ffprobe
* update more tests, add more code comments
* add utilities to generate processed emoji / media outputs
* fix remaining tests
* add test for opus media file, add license header to utility cmds
* limit the number of concurrently available ffmpeg / ffprobe instances
* reduce number of instances
* further reduce number of instances
* fix envparsing test with configuration variables
* update docs and configuration with new media-{local,remote}-max-size variables
	
	
This commit is contained in:
		
					parent
					
						
							
								5bc567196b
							
						
					
				
			
			
				commit
				
					
						cde2fb6244
					
				
			
		
					 376 changed files with 8026 additions and 54091 deletions
				
			
		
							
								
								
									
										202
									
								
								vendor/github.com/golang/geo/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/golang/geo/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,202 +0,0 @@ | |||
| 
 | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
| 
 | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
| 
 | ||||
|    Copyright [yyyy] [name of copyright owner] | ||||
| 
 | ||||
|    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. | ||||
							
								
								
									
										20
									
								
								vendor/github.com/golang/geo/r1/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/golang/geo/r1/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,20 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| /* | ||||
| Package r1 implements types and functions for working with geometry in ℝ¹. | ||||
| 
 | ||||
| See ../s2 for a more detailed overview. | ||||
| */ | ||||
| package r1 | ||||
							
								
								
									
										177
									
								
								vendor/github.com/golang/geo/r1/interval.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										177
									
								
								vendor/github.com/golang/geo/r1/interval.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,177 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package r1 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| ) | ||||
| 
 | ||||
| // Interval represents a closed interval on ℝ. | ||||
| // Zero-length intervals (where Lo == Hi) represent single points. | ||||
| // If Lo > Hi then the interval is empty. | ||||
| type Interval struct { | ||||
| 	Lo, Hi float64 | ||||
| } | ||||
| 
 | ||||
| // EmptyInterval returns an empty interval. | ||||
| func EmptyInterval() Interval { return Interval{1, 0} } | ||||
| 
 | ||||
| // IntervalFromPoint returns an interval representing a single point. | ||||
| func IntervalFromPoint(p float64) Interval { return Interval{p, p} } | ||||
| 
 | ||||
| // IsEmpty reports whether the interval is empty. | ||||
| func (i Interval) IsEmpty() bool { return i.Lo > i.Hi } | ||||
| 
 | ||||
| // Equal returns true iff the interval contains the same points as oi. | ||||
| func (i Interval) Equal(oi Interval) bool { | ||||
| 	return i == oi || i.IsEmpty() && oi.IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // Center returns the midpoint of the interval. | ||||
| // It is undefined for empty intervals. | ||||
| func (i Interval) Center() float64 { return 0.5 * (i.Lo + i.Hi) } | ||||
| 
 | ||||
| // Length returns the length of the interval. | ||||
| // The length of an empty interval is negative. | ||||
| func (i Interval) Length() float64 { return i.Hi - i.Lo } | ||||
| 
 | ||||
| // Contains returns true iff the interval contains p. | ||||
| func (i Interval) Contains(p float64) bool { return i.Lo <= p && p <= i.Hi } | ||||
| 
 | ||||
| // ContainsInterval returns true iff the interval contains oi. | ||||
| func (i Interval) ContainsInterval(oi Interval) bool { | ||||
| 	if oi.IsEmpty() { | ||||
| 		return true | ||||
| 	} | ||||
| 	return i.Lo <= oi.Lo && oi.Hi <= i.Hi | ||||
| } | ||||
| 
 | ||||
| // InteriorContains returns true iff the interval strictly contains p. | ||||
| func (i Interval) InteriorContains(p float64) bool { | ||||
| 	return i.Lo < p && p < i.Hi | ||||
| } | ||||
| 
 | ||||
| // InteriorContainsInterval returns true iff the interval strictly contains oi. | ||||
| func (i Interval) InteriorContainsInterval(oi Interval) bool { | ||||
| 	if oi.IsEmpty() { | ||||
| 		return true | ||||
| 	} | ||||
| 	return i.Lo < oi.Lo && oi.Hi < i.Hi | ||||
| } | ||||
| 
 | ||||
| // Intersects returns true iff the interval contains any points in common with oi. | ||||
| func (i Interval) Intersects(oi Interval) bool { | ||||
| 	if i.Lo <= oi.Lo { | ||||
| 		return oi.Lo <= i.Hi && oi.Lo <= oi.Hi // oi.Lo ∈ i and oi is not empty | ||||
| 	} | ||||
| 	return i.Lo <= oi.Hi && i.Lo <= i.Hi // i.Lo ∈ oi and i is not empty | ||||
| } | ||||
| 
 | ||||
| // InteriorIntersects returns true iff the interior of the interval contains any points in common with oi, including the latter's boundary. | ||||
| func (i Interval) InteriorIntersects(oi Interval) bool { | ||||
| 	return oi.Lo < i.Hi && i.Lo < oi.Hi && i.Lo < i.Hi && oi.Lo <= oi.Hi | ||||
| } | ||||
| 
 | ||||
| // Intersection returns the interval containing all points common to i and j. | ||||
| func (i Interval) Intersection(j Interval) Interval { | ||||
| 	// Empty intervals do not need to be special-cased. | ||||
| 	return Interval{ | ||||
| 		Lo: math.Max(i.Lo, j.Lo), | ||||
| 		Hi: math.Min(i.Hi, j.Hi), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddPoint returns the interval expanded so that it contains the given point. | ||||
| func (i Interval) AddPoint(p float64) Interval { | ||||
| 	if i.IsEmpty() { | ||||
| 		return Interval{p, p} | ||||
| 	} | ||||
| 	if p < i.Lo { | ||||
| 		return Interval{p, i.Hi} | ||||
| 	} | ||||
| 	if p > i.Hi { | ||||
| 		return Interval{i.Lo, p} | ||||
| 	} | ||||
| 	return i | ||||
| } | ||||
| 
 | ||||
| // ClampPoint returns the closest point in the interval to the given point "p". | ||||
| // The interval must be non-empty. | ||||
| func (i Interval) ClampPoint(p float64) float64 { | ||||
| 	return math.Max(i.Lo, math.Min(i.Hi, p)) | ||||
| } | ||||
| 
 | ||||
| // Expanded returns an interval that has been expanded on each side by margin. | ||||
| // If margin is negative, then the function shrinks the interval on | ||||
| // each side by margin instead. The resulting interval may be empty. Any | ||||
| // expansion of an empty interval remains empty. | ||||
| func (i Interval) Expanded(margin float64) Interval { | ||||
| 	if i.IsEmpty() { | ||||
| 		return i | ||||
| 	} | ||||
| 	return Interval{i.Lo - margin, i.Hi + margin} | ||||
| } | ||||
| 
 | ||||
| // Union returns the smallest interval that contains this interval and the given interval. | ||||
| func (i Interval) Union(other Interval) Interval { | ||||
| 	if i.IsEmpty() { | ||||
| 		return other | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return i | ||||
| 	} | ||||
| 	return Interval{math.Min(i.Lo, other.Lo), math.Max(i.Hi, other.Hi)} | ||||
| } | ||||
| 
 | ||||
| func (i Interval) String() string { return fmt.Sprintf("[%.7f, %.7f]", i.Lo, i.Hi) } | ||||
| 
 | ||||
| const ( | ||||
| 	// epsilon is a small number that represents a reasonable level of noise between two | ||||
| 	// values that can be considered to be equal. | ||||
| 	epsilon = 1e-15 | ||||
| 	// dblEpsilon is a smaller number for values that require more precision. | ||||
| 	// This is the C++ DBL_EPSILON equivalent. | ||||
| 	dblEpsilon = 2.220446049250313e-16 | ||||
| ) | ||||
| 
 | ||||
| // ApproxEqual reports whether the interval can be transformed into the | ||||
| // given interval by moving each endpoint a small distance. | ||||
| // The empty interval is considered to be positioned arbitrarily on the | ||||
| // real line, so any interval with a small enough length will match | ||||
| // the empty interval. | ||||
| func (i Interval) ApproxEqual(other Interval) bool { | ||||
| 	if i.IsEmpty() { | ||||
| 		return other.Length() <= 2*epsilon | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return i.Length() <= 2*epsilon | ||||
| 	} | ||||
| 	return math.Abs(other.Lo-i.Lo) <= epsilon && | ||||
| 		math.Abs(other.Hi-i.Hi) <= epsilon | ||||
| } | ||||
| 
 | ||||
| // DirectedHausdorffDistance returns the Hausdorff distance to the given interval. For two | ||||
| // intervals x and y, this distance is defined as | ||||
| //     h(x, y) = max_{p in x} min_{q in y} d(p, q). | ||||
| func (i Interval) DirectedHausdorffDistance(other Interval) float64 { | ||||
| 	if i.IsEmpty() { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return math.Inf(1) | ||||
| 	} | ||||
| 	return math.Max(0, math.Max(i.Hi-other.Hi, other.Lo-i.Lo)) | ||||
| } | ||||
							
								
								
									
										20
									
								
								vendor/github.com/golang/geo/r2/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/golang/geo/r2/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,20 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| /* | ||||
| Package r2 implements types and functions for working with geometry in ℝ². | ||||
| 
 | ||||
| See package s2 for a more detailed overview. | ||||
| */ | ||||
| package r2 | ||||
							
								
								
									
										255
									
								
								vendor/github.com/golang/geo/r2/rect.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										255
									
								
								vendor/github.com/golang/geo/r2/rect.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,255 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package r2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| ) | ||||
| 
 | ||||
| // Point represents a point in ℝ². | ||||
| type Point struct { | ||||
| 	X, Y float64 | ||||
| } | ||||
| 
 | ||||
| // Add returns the sum of p and op. | ||||
| func (p Point) Add(op Point) Point { return Point{p.X + op.X, p.Y + op.Y} } | ||||
| 
 | ||||
| // Sub returns the difference of p and op. | ||||
| func (p Point) Sub(op Point) Point { return Point{p.X - op.X, p.Y - op.Y} } | ||||
| 
 | ||||
| // Mul returns the scalar product of p and m. | ||||
| func (p Point) Mul(m float64) Point { return Point{m * p.X, m * p.Y} } | ||||
| 
 | ||||
| // Ortho returns a counterclockwise orthogonal point with the same norm. | ||||
| func (p Point) Ortho() Point { return Point{-p.Y, p.X} } | ||||
| 
 | ||||
| // Dot returns the dot product between p and op. | ||||
| func (p Point) Dot(op Point) float64 { return p.X*op.X + p.Y*op.Y } | ||||
| 
 | ||||
| // Cross returns the cross product of p and op. | ||||
| func (p Point) Cross(op Point) float64 { return p.X*op.Y - p.Y*op.X } | ||||
| 
 | ||||
| // Norm returns the vector's norm. | ||||
| func (p Point) Norm() float64 { return math.Hypot(p.X, p.Y) } | ||||
| 
 | ||||
| // Normalize returns a unit point in the same direction as p. | ||||
| func (p Point) Normalize() Point { | ||||
| 	if p.X == 0 && p.Y == 0 { | ||||
| 		return p | ||||
| 	} | ||||
| 	return p.Mul(1 / p.Norm()) | ||||
| } | ||||
| 
 | ||||
| func (p Point) String() string { return fmt.Sprintf("(%.12f, %.12f)", p.X, p.Y) } | ||||
| 
 | ||||
| // Rect represents a closed axis-aligned rectangle in the (x,y) plane. | ||||
| type Rect struct { | ||||
| 	X, Y r1.Interval | ||||
| } | ||||
| 
 | ||||
| // RectFromPoints constructs a rect that contains the given points. | ||||
| func RectFromPoints(pts ...Point) Rect { | ||||
| 	// Because the default value on interval is 0,0, we need to manually | ||||
| 	// define the interval from the first point passed in as our starting | ||||
| 	// interval, otherwise we end up with the case of passing in | ||||
| 	// Point{0.2, 0.3} and getting the starting Rect of {0, 0.2}, {0, 0.3} | ||||
| 	// instead of the Rect {0.2, 0.2}, {0.3, 0.3} which is not correct. | ||||
| 	if len(pts) == 0 { | ||||
| 		return Rect{} | ||||
| 	} | ||||
| 
 | ||||
| 	r := Rect{ | ||||
| 		X: r1.Interval{Lo: pts[0].X, Hi: pts[0].X}, | ||||
| 		Y: r1.Interval{Lo: pts[0].Y, Hi: pts[0].Y}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, p := range pts[1:] { | ||||
| 		r = r.AddPoint(p) | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // RectFromCenterSize constructs a rectangle with the given center and size. | ||||
| // Both dimensions of size must be non-negative. | ||||
| func RectFromCenterSize(center, size Point) Rect { | ||||
| 	return Rect{ | ||||
| 		r1.Interval{Lo: center.X - size.X/2, Hi: center.X + size.X/2}, | ||||
| 		r1.Interval{Lo: center.Y - size.Y/2, Hi: center.Y + size.Y/2}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // EmptyRect constructs the canonical empty rectangle. Use IsEmpty() to test | ||||
| // for empty rectangles, since they have more than one representation. A Rect{} | ||||
| // is not the same as the EmptyRect. | ||||
| func EmptyRect() Rect { | ||||
| 	return Rect{r1.EmptyInterval(), r1.EmptyInterval()} | ||||
| } | ||||
| 
 | ||||
| // IsValid reports whether the rectangle is valid. | ||||
| // This requires the width to be empty iff the height is empty. | ||||
| func (r Rect) IsValid() bool { | ||||
| 	return r.X.IsEmpty() == r.Y.IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // IsEmpty reports whether the rectangle is empty. | ||||
| func (r Rect) IsEmpty() bool { | ||||
| 	return r.X.IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // Vertices returns all four vertices of the rectangle. Vertices are returned in | ||||
| // CCW direction starting with the lower left corner. | ||||
| func (r Rect) Vertices() [4]Point { | ||||
| 	return [4]Point{ | ||||
| 		{r.X.Lo, r.Y.Lo}, | ||||
| 		{r.X.Hi, r.Y.Lo}, | ||||
| 		{r.X.Hi, r.Y.Hi}, | ||||
| 		{r.X.Lo, r.Y.Hi}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // VertexIJ returns the vertex in direction i along the X-axis (0=left, 1=right) and | ||||
| // direction j along the Y-axis (0=down, 1=up). | ||||
| func (r Rect) VertexIJ(i, j int) Point { | ||||
| 	x := r.X.Lo | ||||
| 	if i == 1 { | ||||
| 		x = r.X.Hi | ||||
| 	} | ||||
| 	y := r.Y.Lo | ||||
| 	if j == 1 { | ||||
| 		y = r.Y.Hi | ||||
| 	} | ||||
| 	return Point{x, y} | ||||
| } | ||||
| 
 | ||||
| // Lo returns the low corner of the rect. | ||||
| func (r Rect) Lo() Point { | ||||
| 	return Point{r.X.Lo, r.Y.Lo} | ||||
| } | ||||
| 
 | ||||
| // Hi returns the high corner of the rect. | ||||
| func (r Rect) Hi() Point { | ||||
| 	return Point{r.X.Hi, r.Y.Hi} | ||||
| } | ||||
| 
 | ||||
| // Center returns the center of the rectangle in (x,y)-space | ||||
| func (r Rect) Center() Point { | ||||
| 	return Point{r.X.Center(), r.Y.Center()} | ||||
| } | ||||
| 
 | ||||
| // Size returns the width and height of this rectangle in (x,y)-space. Empty | ||||
| // rectangles have a negative width and height. | ||||
| func (r Rect) Size() Point { | ||||
| 	return Point{r.X.Length(), r.Y.Length()} | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether the rectangle contains the given point. | ||||
| // Rectangles are closed regions, i.e. they contain their boundary. | ||||
| func (r Rect) ContainsPoint(p Point) bool { | ||||
| 	return r.X.Contains(p.X) && r.Y.Contains(p.Y) | ||||
| } | ||||
| 
 | ||||
| // InteriorContainsPoint returns true iff the given point is contained in the interior | ||||
| // of the region (i.e. the region excluding its boundary). | ||||
| func (r Rect) InteriorContainsPoint(p Point) bool { | ||||
| 	return r.X.InteriorContains(p.X) && r.Y.InteriorContains(p.Y) | ||||
| } | ||||
| 
 | ||||
| // Contains reports whether the rectangle contains the given rectangle. | ||||
| func (r Rect) Contains(other Rect) bool { | ||||
| 	return r.X.ContainsInterval(other.X) && r.Y.ContainsInterval(other.Y) | ||||
| } | ||||
| 
 | ||||
| // InteriorContains reports whether the interior of this rectangle contains all of the | ||||
| // points of the given other rectangle (including its boundary). | ||||
| func (r Rect) InteriorContains(other Rect) bool { | ||||
| 	return r.X.InteriorContainsInterval(other.X) && r.Y.InteriorContainsInterval(other.Y) | ||||
| } | ||||
| 
 | ||||
| // Intersects reports whether this rectangle and the other rectangle have any points in common. | ||||
| func (r Rect) Intersects(other Rect) bool { | ||||
| 	return r.X.Intersects(other.X) && r.Y.Intersects(other.Y) | ||||
| } | ||||
| 
 | ||||
| // InteriorIntersects reports whether the interior of this rectangle intersects | ||||
| // any point (including the boundary) of the given other rectangle. | ||||
| func (r Rect) InteriorIntersects(other Rect) bool { | ||||
| 	return r.X.InteriorIntersects(other.X) && r.Y.InteriorIntersects(other.Y) | ||||
| } | ||||
| 
 | ||||
| // AddPoint expands the rectangle to include the given point. The rectangle is | ||||
| // expanded by the minimum amount possible. | ||||
| func (r Rect) AddPoint(p Point) Rect { | ||||
| 	return Rect{r.X.AddPoint(p.X), r.Y.AddPoint(p.Y)} | ||||
| } | ||||
| 
 | ||||
| // AddRect expands the rectangle to include the given rectangle. This is the | ||||
| // same as replacing the rectangle by the union of the two rectangles, but | ||||
| // is more efficient. | ||||
| func (r Rect) AddRect(other Rect) Rect { | ||||
| 	return Rect{r.X.Union(other.X), r.Y.Union(other.Y)} | ||||
| } | ||||
| 
 | ||||
| // ClampPoint returns the closest point in the rectangle to the given point. | ||||
| // The rectangle must be non-empty. | ||||
| func (r Rect) ClampPoint(p Point) Point { | ||||
| 	return Point{r.X.ClampPoint(p.X), r.Y.ClampPoint(p.Y)} | ||||
| } | ||||
| 
 | ||||
| // Expanded returns a rectangle that has been expanded in the x-direction | ||||
| // by margin.X, and in y-direction by margin.Y. If either margin is empty, | ||||
| // then shrink the interval on the corresponding sides instead. The resulting | ||||
| // rectangle may be empty. Any expansion of an empty rectangle remains empty. | ||||
| func (r Rect) Expanded(margin Point) Rect { | ||||
| 	xx := r.X.Expanded(margin.X) | ||||
| 	yy := r.Y.Expanded(margin.Y) | ||||
| 	if xx.IsEmpty() || yy.IsEmpty() { | ||||
| 		return EmptyRect() | ||||
| 	} | ||||
| 	return Rect{xx, yy} | ||||
| } | ||||
| 
 | ||||
| // ExpandedByMargin returns a Rect that has been expanded by the amount on all sides. | ||||
| func (r Rect) ExpandedByMargin(margin float64) Rect { | ||||
| 	return r.Expanded(Point{margin, margin}) | ||||
| } | ||||
| 
 | ||||
| // Union returns the smallest rectangle containing the union of this rectangle and | ||||
| // the given rectangle. | ||||
| func (r Rect) Union(other Rect) Rect { | ||||
| 	return Rect{r.X.Union(other.X), r.Y.Union(other.Y)} | ||||
| } | ||||
| 
 | ||||
| // Intersection returns the smallest rectangle containing the intersection of this | ||||
| // rectangle and the given rectangle. | ||||
| func (r Rect) Intersection(other Rect) Rect { | ||||
| 	xx := r.X.Intersection(other.X) | ||||
| 	yy := r.Y.Intersection(other.Y) | ||||
| 	if xx.IsEmpty() || yy.IsEmpty() { | ||||
| 		return EmptyRect() | ||||
| 	} | ||||
| 
 | ||||
| 	return Rect{xx, yy} | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual returns true if the x- and y-intervals of the two rectangles are | ||||
| // the same up to the given tolerance. | ||||
| func (r Rect) ApproxEqual(r2 Rect) bool { | ||||
| 	return r.X.ApproxEqual(r2.X) && r.Y.ApproxEqual(r2.Y) | ||||
| } | ||||
| 
 | ||||
| func (r Rect) String() string { return fmt.Sprintf("[Lo%s, Hi%s]", r.Lo(), r.Hi()) } | ||||
							
								
								
									
										20
									
								
								vendor/github.com/golang/geo/r3/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/golang/geo/r3/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,20 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| /* | ||||
| Package r3 implements types and functions for working with geometry in ℝ³. | ||||
| 
 | ||||
| See ../s2 for a more detailed overview. | ||||
| */ | ||||
| package r3 | ||||
							
								
								
									
										198
									
								
								vendor/github.com/golang/geo/r3/precisevector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										198
									
								
								vendor/github.com/golang/geo/r3/precisevector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,198 +0,0 @@ | |||
| // Copyright 2016 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. | ||||
| 
 | ||||
| package r3 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// prec is the number of bits of precision to use for the Float values. | ||||
| 	// To keep things simple, we use the maximum allowable precision on big | ||||
| 	// values. This allows us to handle all values we expect in the s2 library. | ||||
| 	prec = big.MaxPrec | ||||
| ) | ||||
| 
 | ||||
| // define some commonly referenced values. | ||||
| var ( | ||||
| 	precise0 = precInt(0) | ||||
| 	precise1 = precInt(1) | ||||
| ) | ||||
| 
 | ||||
| // precStr wraps the conversion from a string into a big.Float. For results that | ||||
| // actually can be represented exactly, this should only be used on values that | ||||
| // are integer multiples of integer powers of 2. | ||||
| func precStr(s string) *big.Float { | ||||
| 	// Explicitly ignoring the bool return for this usage. | ||||
| 	f, _ := new(big.Float).SetPrec(prec).SetString(s) | ||||
| 	return f | ||||
| } | ||||
| 
 | ||||
| func precInt(i int64) *big.Float { | ||||
| 	return new(big.Float).SetPrec(prec).SetInt64(i) | ||||
| } | ||||
| 
 | ||||
| func precFloat(f float64) *big.Float { | ||||
| 	return new(big.Float).SetPrec(prec).SetFloat64(f) | ||||
| } | ||||
| 
 | ||||
| func precAdd(a, b *big.Float) *big.Float { | ||||
| 	return new(big.Float).SetPrec(prec).Add(a, b) | ||||
| } | ||||
| 
 | ||||
| func precSub(a, b *big.Float) *big.Float { | ||||
| 	return new(big.Float).SetPrec(prec).Sub(a, b) | ||||
| } | ||||
| 
 | ||||
| func precMul(a, b *big.Float) *big.Float { | ||||
| 	return new(big.Float).SetPrec(prec).Mul(a, b) | ||||
| } | ||||
| 
 | ||||
| // PreciseVector represents a point in ℝ³ using high-precision values. | ||||
| // Note that this is NOT a complete implementation because there are some | ||||
| // operations that Vector supports that are not feasible with arbitrary precision | ||||
| // math. (e.g., methods that need division like Normalize, or methods needing a | ||||
| // square root operation such as Norm) | ||||
| type PreciseVector struct { | ||||
| 	X, Y, Z *big.Float | ||||
| } | ||||
| 
 | ||||
| // PreciseVectorFromVector creates a high precision vector from the given Vector. | ||||
| func PreciseVectorFromVector(v Vector) PreciseVector { | ||||
| 	return NewPreciseVector(v.X, v.Y, v.Z) | ||||
| } | ||||
| 
 | ||||
| // NewPreciseVector creates a high precision vector from the given floating point values. | ||||
| func NewPreciseVector(x, y, z float64) PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: precFloat(x), | ||||
| 		Y: precFloat(y), | ||||
| 		Z: precFloat(z), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Vector returns this precise vector converted to a Vector. | ||||
| func (v PreciseVector) Vector() Vector { | ||||
| 	// The accuracy flag is ignored on these conversions back to float64. | ||||
| 	x, _ := v.X.Float64() | ||||
| 	y, _ := v.Y.Float64() | ||||
| 	z, _ := v.Z.Float64() | ||||
| 	return Vector{x, y, z}.Normalize() | ||||
| } | ||||
| 
 | ||||
| // Equal reports whether v and ov are equal. | ||||
| func (v PreciseVector) Equal(ov PreciseVector) bool { | ||||
| 	return v.X.Cmp(ov.X) == 0 && v.Y.Cmp(ov.Y) == 0 && v.Z.Cmp(ov.Z) == 0 | ||||
| } | ||||
| 
 | ||||
| func (v PreciseVector) String() string { | ||||
| 	return fmt.Sprintf("(%10g, %10g, %10g)", v.X, v.Y, v.Z) | ||||
| } | ||||
| 
 | ||||
| // Norm2 returns the square of the norm. | ||||
| func (v PreciseVector) Norm2() *big.Float { return v.Dot(v) } | ||||
| 
 | ||||
| // IsUnit reports whether this vector is of unit length. | ||||
| func (v PreciseVector) IsUnit() bool { | ||||
| 	return v.Norm2().Cmp(precise1) == 0 | ||||
| } | ||||
| 
 | ||||
| // Abs returns the vector with nonnegative components. | ||||
| func (v PreciseVector) Abs() PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: new(big.Float).Abs(v.X), | ||||
| 		Y: new(big.Float).Abs(v.Y), | ||||
| 		Z: new(big.Float).Abs(v.Z), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Add returns the standard vector sum of v and ov. | ||||
| func (v PreciseVector) Add(ov PreciseVector) PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: precAdd(v.X, ov.X), | ||||
| 		Y: precAdd(v.Y, ov.Y), | ||||
| 		Z: precAdd(v.Z, ov.Z), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Sub returns the standard vector difference of v and ov. | ||||
| func (v PreciseVector) Sub(ov PreciseVector) PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: precSub(v.X, ov.X), | ||||
| 		Y: precSub(v.Y, ov.Y), | ||||
| 		Z: precSub(v.Z, ov.Z), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Mul returns the standard scalar product of v and f. | ||||
| func (v PreciseVector) Mul(f *big.Float) PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: precMul(v.X, f), | ||||
| 		Y: precMul(v.Y, f), | ||||
| 		Z: precMul(v.Z, f), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // MulByFloat64 returns the standard scalar product of v and f. | ||||
| func (v PreciseVector) MulByFloat64(f float64) PreciseVector { | ||||
| 	return v.Mul(precFloat(f)) | ||||
| } | ||||
| 
 | ||||
| // Dot returns the standard dot product of v and ov. | ||||
| func (v PreciseVector) Dot(ov PreciseVector) *big.Float { | ||||
| 	return precAdd(precMul(v.X, ov.X), precAdd(precMul(v.Y, ov.Y), precMul(v.Z, ov.Z))) | ||||
| } | ||||
| 
 | ||||
| // Cross returns the standard cross product of v and ov. | ||||
| func (v PreciseVector) Cross(ov PreciseVector) PreciseVector { | ||||
| 	return PreciseVector{ | ||||
| 		X: precSub(precMul(v.Y, ov.Z), precMul(v.Z, ov.Y)), | ||||
| 		Y: precSub(precMul(v.Z, ov.X), precMul(v.X, ov.Z)), | ||||
| 		Z: precSub(precMul(v.X, ov.Y), precMul(v.Y, ov.X)), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // LargestComponent returns the axis that represents the largest component in this vector. | ||||
| func (v PreciseVector) LargestComponent() Axis { | ||||
| 	t := v.Abs() | ||||
| 
 | ||||
| 	if t.X.Cmp(t.Y) > 0 { | ||||
| 		if t.X.Cmp(t.Z) > 0 { | ||||
| 			return XAxis | ||||
| 		} | ||||
| 		return ZAxis | ||||
| 	} | ||||
| 	if t.Y.Cmp(t.Z) > 0 { | ||||
| 		return YAxis | ||||
| 	} | ||||
| 	return ZAxis | ||||
| } | ||||
| 
 | ||||
| // SmallestComponent returns the axis that represents the smallest component in this vector. | ||||
| func (v PreciseVector) SmallestComponent() Axis { | ||||
| 	t := v.Abs() | ||||
| 
 | ||||
| 	if t.X.Cmp(t.Y) < 0 { | ||||
| 		if t.X.Cmp(t.Z) < 0 { | ||||
| 			return XAxis | ||||
| 		} | ||||
| 		return ZAxis | ||||
| 	} | ||||
| 	if t.Y.Cmp(t.Z) < 0 { | ||||
| 		return YAxis | ||||
| 	} | ||||
| 	return ZAxis | ||||
| } | ||||
							
								
								
									
										183
									
								
								vendor/github.com/golang/geo/r3/vector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										183
									
								
								vendor/github.com/golang/geo/r3/vector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,183 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package r3 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Vector represents a point in ℝ³. | ||||
| type Vector struct { | ||||
| 	X, Y, Z float64 | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether v and ov are equal within a small epsilon. | ||||
| func (v Vector) ApproxEqual(ov Vector) bool { | ||||
| 	const epsilon = 1e-16 | ||||
| 	return math.Abs(v.X-ov.X) < epsilon && math.Abs(v.Y-ov.Y) < epsilon && math.Abs(v.Z-ov.Z) < epsilon | ||||
| } | ||||
| 
 | ||||
| func (v Vector) String() string { return fmt.Sprintf("(%0.24f, %0.24f, %0.24f)", v.X, v.Y, v.Z) } | ||||
| 
 | ||||
| // Norm returns the vector's norm. | ||||
| func (v Vector) Norm() float64 { return math.Sqrt(v.Dot(v)) } | ||||
| 
 | ||||
| // Norm2 returns the square of the norm. | ||||
| func (v Vector) Norm2() float64 { return v.Dot(v) } | ||||
| 
 | ||||
| // Normalize returns a unit vector in the same direction as v. | ||||
| func (v Vector) Normalize() Vector { | ||||
| 	n2 := v.Norm2() | ||||
| 	if n2 == 0 { | ||||
| 		return Vector{0, 0, 0} | ||||
| 	} | ||||
| 	return v.Mul(1 / math.Sqrt(n2)) | ||||
| } | ||||
| 
 | ||||
| // IsUnit returns whether this vector is of approximately unit length. | ||||
| func (v Vector) IsUnit() bool { | ||||
| 	const epsilon = 5e-14 | ||||
| 	return math.Abs(v.Norm2()-1) <= epsilon | ||||
| } | ||||
| 
 | ||||
| // Abs returns the vector with nonnegative components. | ||||
| func (v Vector) Abs() Vector { return Vector{math.Abs(v.X), math.Abs(v.Y), math.Abs(v.Z)} } | ||||
| 
 | ||||
| // Add returns the standard vector sum of v and ov. | ||||
| func (v Vector) Add(ov Vector) Vector { return Vector{v.X + ov.X, v.Y + ov.Y, v.Z + ov.Z} } | ||||
| 
 | ||||
| // Sub returns the standard vector difference of v and ov. | ||||
| func (v Vector) Sub(ov Vector) Vector { return Vector{v.X - ov.X, v.Y - ov.Y, v.Z - ov.Z} } | ||||
| 
 | ||||
| // Mul returns the standard scalar product of v and m. | ||||
| func (v Vector) Mul(m float64) Vector { return Vector{m * v.X, m * v.Y, m * v.Z} } | ||||
| 
 | ||||
| // Dot returns the standard dot product of v and ov. | ||||
| func (v Vector) Dot(ov Vector) float64 { return v.X*ov.X + v.Y*ov.Y + v.Z*ov.Z } | ||||
| 
 | ||||
| // Cross returns the standard cross product of v and ov. | ||||
| func (v Vector) Cross(ov Vector) Vector { | ||||
| 	return Vector{ | ||||
| 		v.Y*ov.Z - v.Z*ov.Y, | ||||
| 		v.Z*ov.X - v.X*ov.Z, | ||||
| 		v.X*ov.Y - v.Y*ov.X, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Distance returns the Euclidean distance between v and ov. | ||||
| func (v Vector) Distance(ov Vector) float64 { return v.Sub(ov).Norm() } | ||||
| 
 | ||||
| // Angle returns the angle between v and ov. | ||||
| func (v Vector) Angle(ov Vector) s1.Angle { | ||||
| 	return s1.Angle(math.Atan2(v.Cross(ov).Norm(), v.Dot(ov))) * s1.Radian | ||||
| } | ||||
| 
 | ||||
| // Axis enumerates the 3 axes of ℝ³. | ||||
| type Axis int | ||||
| 
 | ||||
| // The three axes of ℝ³. | ||||
| const ( | ||||
| 	XAxis Axis = iota | ||||
| 	YAxis | ||||
| 	ZAxis | ||||
| ) | ||||
| 
 | ||||
| // Ortho returns a unit vector that is orthogonal to v. | ||||
| // Ortho(-v) = -Ortho(v) for all v. | ||||
| func (v Vector) Ortho() Vector { | ||||
| 	ov := Vector{0.012, 0.0053, 0.00457} | ||||
| 	switch v.LargestComponent() { | ||||
| 	case XAxis: | ||||
| 		ov.Z = 1 | ||||
| 	case YAxis: | ||||
| 		ov.X = 1 | ||||
| 	default: | ||||
| 		ov.Y = 1 | ||||
| 	} | ||||
| 	return v.Cross(ov).Normalize() | ||||
| } | ||||
| 
 | ||||
| // LargestComponent returns the axis that represents the largest component in this vector. | ||||
| func (v Vector) LargestComponent() Axis { | ||||
| 	t := v.Abs() | ||||
| 
 | ||||
| 	if t.X > t.Y { | ||||
| 		if t.X > t.Z { | ||||
| 			return XAxis | ||||
| 		} | ||||
| 		return ZAxis | ||||
| 	} | ||||
| 	if t.Y > t.Z { | ||||
| 		return YAxis | ||||
| 	} | ||||
| 	return ZAxis | ||||
| } | ||||
| 
 | ||||
| // SmallestComponent returns the axis that represents the smallest component in this vector. | ||||
| func (v Vector) SmallestComponent() Axis { | ||||
| 	t := v.Abs() | ||||
| 
 | ||||
| 	if t.X < t.Y { | ||||
| 		if t.X < t.Z { | ||||
| 			return XAxis | ||||
| 		} | ||||
| 		return ZAxis | ||||
| 	} | ||||
| 	if t.Y < t.Z { | ||||
| 		return YAxis | ||||
| 	} | ||||
| 	return ZAxis | ||||
| } | ||||
| 
 | ||||
| // Cmp compares v and ov lexicographically and returns: | ||||
| // | ||||
| //   -1 if v <  ov | ||||
| //    0 if v == ov | ||||
| //   +1 if v >  ov | ||||
| // | ||||
| // This method is based on C++'s std::lexicographical_compare. Two entities | ||||
| // are compared element by element with the given operator. The first mismatch | ||||
| // defines which is less (or greater) than the other. If both have equivalent | ||||
| // values they are lexicographically equal. | ||||
| func (v Vector) Cmp(ov Vector) int { | ||||
| 	if v.X < ov.X { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	if v.X > ov.X { | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// First elements were the same, try the next. | ||||
| 	if v.Y < ov.Y { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	if v.Y > ov.Y { | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// Second elements were the same return the final compare. | ||||
| 	if v.Z < ov.Z { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	if v.Z > ov.Z { | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// Both are equal | ||||
| 	return 0 | ||||
| } | ||||
							
								
								
									
										120
									
								
								vendor/github.com/golang/geo/s1/angle.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/golang/geo/s1/angle.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,120 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s1 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // Angle represents a 1D angle. The internal representation is a double precision | ||||
| // value in radians, so conversion to and from radians is exact. | ||||
| // Conversions between E5, E6, E7, and Degrees are not always | ||||
| // exact. For example, Degrees(3.1) is different from E6(3100000) or E7(31000000). | ||||
| // | ||||
| // The following conversions between degrees and radians are exact: | ||||
| // | ||||
| //       Degree*180 == Radian*math.Pi | ||||
| //   Degree*(180/n) == Radian*(math.Pi/n)     for n == 0..8 | ||||
| // | ||||
| // These identities hold when the arguments are scaled up or down by any power | ||||
| // of 2. Some similar identities are also true, for example, | ||||
| // | ||||
| //   Degree*60 == Radian*(math.Pi/3) | ||||
| // | ||||
| // But be aware that this type of identity does not hold in general. For example, | ||||
| // | ||||
| //   Degree*3 != Radian*(math.Pi/60) | ||||
| // | ||||
| // Similarly, the conversion to radians means that (Angle(x)*Degree).Degrees() | ||||
| // does not always equal x. For example, | ||||
| // | ||||
| //   (Angle(45*n)*Degree).Degrees() == 45*n     for n == 0..8 | ||||
| // | ||||
| // but | ||||
| // | ||||
| //   (60*Degree).Degrees() != 60 | ||||
| // | ||||
| // When testing for equality, you should allow for numerical errors (ApproxEqual) | ||||
| // or convert to discrete E5/E6/E7 values first. | ||||
| type Angle float64 | ||||
| 
 | ||||
| // Angle units. | ||||
| const ( | ||||
| 	Radian Angle = 1 | ||||
| 	Degree       = (math.Pi / 180) * Radian | ||||
| 
 | ||||
| 	E5 = 1e-5 * Degree | ||||
| 	E6 = 1e-6 * Degree | ||||
| 	E7 = 1e-7 * Degree | ||||
| ) | ||||
| 
 | ||||
| // Radians returns the angle in radians. | ||||
| func (a Angle) Radians() float64 { return float64(a) } | ||||
| 
 | ||||
| // Degrees returns the angle in degrees. | ||||
| func (a Angle) Degrees() float64 { return float64(a / Degree) } | ||||
| 
 | ||||
| // round returns the value rounded to nearest as an int32. | ||||
| // This does not match C++ exactly for the case of x.5. | ||||
| func round(val float64) int32 { | ||||
| 	if val < 0 { | ||||
| 		return int32(val - 0.5) | ||||
| 	} | ||||
| 	return int32(val + 0.5) | ||||
| } | ||||
| 
 | ||||
| // InfAngle returns an angle larger than any finite angle. | ||||
| func InfAngle() Angle { | ||||
| 	return Angle(math.Inf(1)) | ||||
| } | ||||
| 
 | ||||
| // isInf reports whether this Angle is infinite. | ||||
| func (a Angle) isInf() bool { | ||||
| 	return math.IsInf(float64(a), 0) | ||||
| } | ||||
| 
 | ||||
| // E5 returns the angle in hundred thousandths of degrees. | ||||
| func (a Angle) E5() int32 { return round(a.Degrees() * 1e5) } | ||||
| 
 | ||||
| // E6 returns the angle in millionths of degrees. | ||||
| func (a Angle) E6() int32 { return round(a.Degrees() * 1e6) } | ||||
| 
 | ||||
| // E7 returns the angle in ten millionths of degrees. | ||||
| func (a Angle) E7() int32 { return round(a.Degrees() * 1e7) } | ||||
| 
 | ||||
| // Abs returns the absolute value of the angle. | ||||
| func (a Angle) Abs() Angle { return Angle(math.Abs(float64(a))) } | ||||
| 
 | ||||
| // Normalized returns an equivalent angle in (-π, π]. | ||||
| func (a Angle) Normalized() Angle { | ||||
| 	rad := math.Remainder(float64(a), 2*math.Pi) | ||||
| 	if rad <= -math.Pi { | ||||
| 		rad = math.Pi | ||||
| 	} | ||||
| 	return Angle(rad) | ||||
| } | ||||
| 
 | ||||
| func (a Angle) String() string { | ||||
| 	return strconv.FormatFloat(a.Degrees(), 'f', 7, 64) // like "%.7f" | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether the two angles are the same up to a small tolerance. | ||||
| func (a Angle) ApproxEqual(other Angle) bool { | ||||
| 	return math.Abs(float64(a)-float64(other)) <= epsilon | ||||
| } | ||||
| 
 | ||||
| // BUG(dsymonds): The major differences from the C++ version are: | ||||
| //   - no unsigned E5/E6/E7 methods | ||||
							
								
								
									
										320
									
								
								vendor/github.com/golang/geo/s1/chordangle.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										320
									
								
								vendor/github.com/golang/geo/s1/chordangle.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,320 +0,0 @@ | |||
| // Copyright 2015 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. | ||||
| 
 | ||||
| package s1 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| ) | ||||
| 
 | ||||
| // ChordAngle represents the angle subtended by a chord (i.e., the straight | ||||
| // line segment connecting two points on the sphere). Its representation | ||||
| // makes it very efficient for computing and comparing distances, but unlike | ||||
| // Angle it is only capable of representing angles between 0 and π radians. | ||||
| // Generally, ChordAngle should only be used in loops where many angles need | ||||
| // to be calculated and compared. Otherwise it is simpler to use Angle. | ||||
| // | ||||
| // ChordAngle loses some accuracy as the angle approaches π radians. | ||||
| // There are several different ways to measure this error, including the | ||||
| // representational error (i.e., how accurately ChordAngle can represent | ||||
| // angles near π radians), the conversion error (i.e., how much precision is | ||||
| // lost when an Angle is converted to an ChordAngle), and the measurement | ||||
| // error (i.e., how accurate the ChordAngle(a, b) constructor is when the | ||||
| // points A and B are separated by angles close to π radians). All of these | ||||
| // errors differ by a small constant factor. | ||||
| // | ||||
| // For the measurement error (which is the largest of these errors and also | ||||
| // the most important in practice), let the angle between A and B be (π - x) | ||||
| // radians, i.e. A and B are within "x" radians of being antipodal. The | ||||
| // corresponding chord length is | ||||
| // | ||||
| //    r = 2 * sin((π - x) / 2) = 2 * cos(x / 2) | ||||
| // | ||||
| // For values of x not close to π the relative error in the squared chord | ||||
| // length is at most 4.5 * dblEpsilon (see MaxPointError below). | ||||
| // The relative error in "r" is thus at most 2.25 * dblEpsilon ~= 5e-16. To | ||||
| // convert this error into an equivalent angle, we have | ||||
| // | ||||
| //    |dr / dx| = sin(x / 2) | ||||
| // | ||||
| // and therefore | ||||
| // | ||||
| //    |dx| = dr / sin(x / 2) | ||||
| //         = 5e-16 * (2 * cos(x / 2)) / sin(x / 2) | ||||
| //         = 1e-15 / tan(x / 2) | ||||
| // | ||||
| // The maximum error is attained when | ||||
| // | ||||
| //    x  = |dx| | ||||
| //       = 1e-15 / tan(x / 2) | ||||
| //      ~= 1e-15 / (x / 2) | ||||
| //      ~= sqrt(2e-15) | ||||
| // | ||||
| // In summary, the measurement error for an angle (π - x) is at most | ||||
| // | ||||
| //    dx  = min(1e-15 / tan(x / 2), sqrt(2e-15)) | ||||
| //      (~= min(2e-15 / x, sqrt(2e-15)) when x is small) | ||||
| // | ||||
| // On the Earth's surface (assuming a radius of 6371km), this corresponds to | ||||
| // the following worst-case measurement errors: | ||||
| // | ||||
| //     Accuracy:             Unless antipodal to within: | ||||
| //     ---------             --------------------------- | ||||
| //     6.4 nanometers        10,000 km (90 degrees) | ||||
| //     1 micrometer          81.2 kilometers | ||||
| //     1 millimeter          81.2 meters | ||||
| //     1 centimeter          8.12 meters | ||||
| //     28.5 centimeters      28.5 centimeters | ||||
| // | ||||
| // The representational and conversion errors referred to earlier are somewhat | ||||
| // smaller than this. For example, maximum distance between adjacent | ||||
| // representable ChordAngle values is only 13.5 cm rather than 28.5 cm. To | ||||
| // see this, observe that the closest representable value to r^2 = 4 is | ||||
| // r^2 =  4 * (1 - dblEpsilon / 2). Thus r = 2 * (1 - dblEpsilon / 4) and | ||||
| // the angle between these two representable values is | ||||
| // | ||||
| //    x  = 2 * acos(r / 2) | ||||
| //       = 2 * acos(1 - dblEpsilon / 4) | ||||
| //      ~= 2 * asin(sqrt(dblEpsilon / 2) | ||||
| //      ~= sqrt(2 * dblEpsilon) | ||||
| //      ~= 2.1e-8 | ||||
| // | ||||
| // which is 13.5 cm on the Earth's surface. | ||||
| // | ||||
| // The worst case rounding error occurs when the value halfway between these | ||||
| // two representable values is rounded up to 4. This halfway value is | ||||
| // r^2 = (4 * (1 - dblEpsilon / 4)), thus r = 2 * (1 - dblEpsilon / 8) and | ||||
| // the worst case rounding error is | ||||
| // | ||||
| //    x  = 2 * acos(r / 2) | ||||
| //       = 2 * acos(1 - dblEpsilon / 8) | ||||
| //      ~= 2 * asin(sqrt(dblEpsilon / 4) | ||||
| //      ~= sqrt(dblEpsilon) | ||||
| //      ~= 1.5e-8 | ||||
| // | ||||
| // which is 9.5 cm on the Earth's surface. | ||||
| type ChordAngle float64 | ||||
| 
 | ||||
| const ( | ||||
| 	// NegativeChordAngle represents a chord angle smaller than the zero angle. | ||||
| 	// The only valid operations on a NegativeChordAngle are comparisons, | ||||
| 	// Angle conversions, and Successor/Predecessor. | ||||
| 	NegativeChordAngle = ChordAngle(-1) | ||||
| 
 | ||||
| 	// RightChordAngle represents a chord angle of 90 degrees (a "right angle"). | ||||
| 	RightChordAngle = ChordAngle(2) | ||||
| 
 | ||||
| 	// StraightChordAngle represents a chord angle of 180 degrees (a "straight angle"). | ||||
| 	// This is the maximum finite chord angle. | ||||
| 	StraightChordAngle = ChordAngle(4) | ||||
| 
 | ||||
| 	// maxLength2 is the square of the maximum length allowed in a ChordAngle. | ||||
| 	maxLength2 = 4.0 | ||||
| ) | ||||
| 
 | ||||
| // ChordAngleFromAngle returns a ChordAngle from the given Angle. | ||||
| func ChordAngleFromAngle(a Angle) ChordAngle { | ||||
| 	if a < 0 { | ||||
| 		return NegativeChordAngle | ||||
| 	} | ||||
| 	if a.isInf() { | ||||
| 		return InfChordAngle() | ||||
| 	} | ||||
| 	l := 2 * math.Sin(0.5*math.Min(math.Pi, a.Radians())) | ||||
| 	return ChordAngle(l * l) | ||||
| } | ||||
| 
 | ||||
| // ChordAngleFromSquaredLength returns a ChordAngle from the squared chord length. | ||||
| // Note that the argument is automatically clamped to a maximum of 4 to | ||||
| // handle possible roundoff errors. The argument must be non-negative. | ||||
| func ChordAngleFromSquaredLength(length2 float64) ChordAngle { | ||||
| 	if length2 > maxLength2 { | ||||
| 		return StraightChordAngle | ||||
| 	} | ||||
| 	return ChordAngle(length2) | ||||
| } | ||||
| 
 | ||||
| // Expanded returns a new ChordAngle that has been adjusted by the given error | ||||
| // bound (which can be positive or negative). Error should be the value | ||||
| // returned by either MaxPointError or MaxAngleError. For example: | ||||
| //    a := ChordAngleFromPoints(x, y) | ||||
| //    a1 := a.Expanded(a.MaxPointError()) | ||||
| func (c ChordAngle) Expanded(e float64) ChordAngle { | ||||
| 	// If the angle is special, don't change it. Otherwise clamp it to the valid range. | ||||
| 	if c.isSpecial() { | ||||
| 		return c | ||||
| 	} | ||||
| 	return ChordAngle(math.Max(0.0, math.Min(maxLength2, float64(c)+e))) | ||||
| } | ||||
| 
 | ||||
| // Angle converts this ChordAngle to an Angle. | ||||
| func (c ChordAngle) Angle() Angle { | ||||
| 	if c < 0 { | ||||
| 		return -1 * Radian | ||||
| 	} | ||||
| 	if c.isInf() { | ||||
| 		return InfAngle() | ||||
| 	} | ||||
| 	return Angle(2 * math.Asin(0.5*math.Sqrt(float64(c)))) | ||||
| } | ||||
| 
 | ||||
| // InfChordAngle returns a chord angle larger than any finite chord angle. | ||||
| // The only valid operations on an InfChordAngle are comparisons, Angle | ||||
| // conversions, and Successor/Predecessor. | ||||
| func InfChordAngle() ChordAngle { | ||||
| 	return ChordAngle(math.Inf(1)) | ||||
| } | ||||
| 
 | ||||
| // isInf reports whether this ChordAngle is infinite. | ||||
| func (c ChordAngle) isInf() bool { | ||||
| 	return math.IsInf(float64(c), 1) | ||||
| } | ||||
| 
 | ||||
| // isSpecial reports whether this ChordAngle is one of the special cases. | ||||
| func (c ChordAngle) isSpecial() bool { | ||||
| 	return c < 0 || c.isInf() | ||||
| } | ||||
| 
 | ||||
| // isValid reports whether this ChordAngle is valid or not. | ||||
| func (c ChordAngle) isValid() bool { | ||||
| 	return (c >= 0 && c <= maxLength2) || c.isSpecial() | ||||
| } | ||||
| 
 | ||||
| // Successor returns the smallest representable ChordAngle larger than this one. | ||||
| // This can be used to convert a "<" comparison to a "<=" comparison. | ||||
| // | ||||
| // Note the following special cases: | ||||
| //   NegativeChordAngle.Successor == 0 | ||||
| //   StraightChordAngle.Successor == InfChordAngle | ||||
| //   InfChordAngle.Successor == InfChordAngle | ||||
| func (c ChordAngle) Successor() ChordAngle { | ||||
| 	if c >= maxLength2 { | ||||
| 		return InfChordAngle() | ||||
| 	} | ||||
| 	if c < 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return ChordAngle(math.Nextafter(float64(c), 10.0)) | ||||
| } | ||||
| 
 | ||||
| // Predecessor returns the largest representable ChordAngle less than this one. | ||||
| // | ||||
| // Note the following special cases: | ||||
| //   InfChordAngle.Predecessor == StraightChordAngle | ||||
| //   ChordAngle(0).Predecessor == NegativeChordAngle | ||||
| //   NegativeChordAngle.Predecessor == NegativeChordAngle | ||||
| func (c ChordAngle) Predecessor() ChordAngle { | ||||
| 	if c <= 0 { | ||||
| 		return NegativeChordAngle | ||||
| 	} | ||||
| 	if c > maxLength2 { | ||||
| 		return StraightChordAngle | ||||
| 	} | ||||
| 
 | ||||
| 	return ChordAngle(math.Nextafter(float64(c), -10.0)) | ||||
| } | ||||
| 
 | ||||
| // MaxPointError returns the maximum error size for a ChordAngle constructed | ||||
| // from 2 Points x and y, assuming that x and y are normalized to within the | ||||
| // bounds guaranteed by s2.Point.Normalize. The error is defined with respect to | ||||
| // the true distance after the points are projected to lie exactly on the sphere. | ||||
| func (c ChordAngle) MaxPointError() float64 { | ||||
| 	// There is a relative error of (2.5*dblEpsilon) when computing the squared | ||||
| 	// distance, plus a relative error of 2 * dblEpsilon, plus an absolute error | ||||
| 	// of (16 * dblEpsilon**2) because the lengths of the input points may differ | ||||
| 	// from 1 by up to (2*dblEpsilon) each. (This is the maximum error in Normalize). | ||||
| 	return 4.5*dblEpsilon*float64(c) + 16*dblEpsilon*dblEpsilon | ||||
| } | ||||
| 
 | ||||
| // MaxAngleError returns the maximum error for a ChordAngle constructed | ||||
| // as an Angle distance. | ||||
| func (c ChordAngle) MaxAngleError() float64 { | ||||
| 	return dblEpsilon * float64(c) | ||||
| } | ||||
| 
 | ||||
| // Add adds the other ChordAngle to this one and returns the resulting value. | ||||
| // This method assumes the ChordAngles are not special. | ||||
| func (c ChordAngle) Add(other ChordAngle) ChordAngle { | ||||
| 	// Note that this method (and Sub) is much more efficient than converting | ||||
| 	// the ChordAngle to an Angle and adding those and converting back. It | ||||
| 	// requires only one square root plus a few additions and multiplications. | ||||
| 
 | ||||
| 	// Optimization for the common case where b is an error tolerance | ||||
| 	// parameter that happens to be set to zero. | ||||
| 	if other == 0 { | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	// Clamp the angle sum to at most 180 degrees. | ||||
| 	if c+other >= maxLength2 { | ||||
| 		return StraightChordAngle | ||||
| 	} | ||||
| 
 | ||||
| 	// Let a and b be the (non-squared) chord lengths, and let c = a+b. | ||||
| 	// Let A, B, and C be the corresponding half-angles (a = 2*sin(A), etc). | ||||
| 	// Then the formula below can be derived from c = 2 * sin(A+B) and the | ||||
| 	// relationships   sin(A+B) = sin(A)*cos(B) + sin(B)*cos(A) | ||||
| 	//                 cos(X) = sqrt(1 - sin^2(X)) | ||||
| 	x := float64(c * (1 - 0.25*other)) | ||||
| 	y := float64(other * (1 - 0.25*c)) | ||||
| 	return ChordAngle(math.Min(maxLength2, x+y+2*math.Sqrt(x*y))) | ||||
| } | ||||
| 
 | ||||
| // Sub subtracts the other ChordAngle from this one and returns the resulting | ||||
| // value. This method assumes the ChordAngles are not special. | ||||
| func (c ChordAngle) Sub(other ChordAngle) ChordAngle { | ||||
| 	if other == 0 { | ||||
| 		return c | ||||
| 	} | ||||
| 	if c <= other { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	x := float64(c * (1 - 0.25*other)) | ||||
| 	y := float64(other * (1 - 0.25*c)) | ||||
| 	return ChordAngle(math.Max(0.0, x+y-2*math.Sqrt(x*y))) | ||||
| } | ||||
| 
 | ||||
| // Sin returns the sine of this chord angle. This method is more efficient | ||||
| // than converting to Angle and performing the computation. | ||||
| func (c ChordAngle) Sin() float64 { | ||||
| 	return math.Sqrt(c.Sin2()) | ||||
| } | ||||
| 
 | ||||
| // Sin2 returns the square of the sine of this chord angle. | ||||
| // It is more efficient than Sin. | ||||
| func (c ChordAngle) Sin2() float64 { | ||||
| 	// Let a be the (non-squared) chord length, and let A be the corresponding | ||||
| 	// half-angle (a = 2*sin(A)). The formula below can be derived from: | ||||
| 	//   sin(2*A) = 2 * sin(A) * cos(A) | ||||
| 	//   cos^2(A) = 1 - sin^2(A) | ||||
| 	// This is much faster than converting to an angle and computing its sine. | ||||
| 	return float64(c * (1 - 0.25*c)) | ||||
| } | ||||
| 
 | ||||
| // Cos returns the cosine of this chord angle. This method is more efficient | ||||
| // than converting to Angle and performing the computation. | ||||
| func (c ChordAngle) Cos() float64 { | ||||
| 	// cos(2*A) = cos^2(A) - sin^2(A) = 1 - 2*sin^2(A) | ||||
| 	return float64(1 - 0.5*c) | ||||
| } | ||||
| 
 | ||||
| // Tan returns the tangent of this chord angle. | ||||
| func (c ChordAngle) Tan() float64 { | ||||
| 	return c.Sin() / c.Cos() | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Differences from C++: | ||||
| //   Helpers to/from E5/E6/E7 | ||||
| //   Helpers to/from degrees and radians directly. | ||||
| //   FastUpperBoundFrom(angle Angle) | ||||
							
								
								
									
										20
									
								
								vendor/github.com/golang/geo/s1/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/golang/geo/s1/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,20 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| /* | ||||
| Package s1 implements types and functions for working with geometry in S¹ (circular geometry). | ||||
| 
 | ||||
| See ../s2 for a more detailed overview. | ||||
| */ | ||||
| package s1 | ||||
							
								
								
									
										462
									
								
								vendor/github.com/golang/geo/s1/interval.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										462
									
								
								vendor/github.com/golang/geo/s1/interval.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,462 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s1 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // An Interval represents a closed interval on a unit circle (also known | ||||
| // as a 1-dimensional sphere). It is capable of representing the empty | ||||
| // interval (containing no points), the full interval (containing all | ||||
| // points), and zero-length intervals (containing a single point). | ||||
| // | ||||
| // Points are represented by the angle they make with the positive x-axis in | ||||
| // the range [-π, π]. An interval is represented by its lower and upper | ||||
| // bounds (both inclusive, since the interval is closed). The lower bound may | ||||
| // be greater than the upper bound, in which case the interval is "inverted" | ||||
| // (i.e. it passes through the point (-1, 0)). | ||||
| // | ||||
| // The point (-1, 0) has two valid representations, π and -π. The | ||||
| // normalized representation of this point is π, so that endpoints | ||||
| // of normal intervals are in the range (-π, π]. We normalize the latter to | ||||
| // the former in IntervalFromEndpoints. However, we take advantage of the point | ||||
| // -π to construct two special intervals: | ||||
| //   The full interval is [-π, π] | ||||
| //   The empty interval is [π, -π]. | ||||
| // | ||||
| // Treat the exported fields as read-only. | ||||
| type Interval struct { | ||||
| 	Lo, Hi float64 | ||||
| } | ||||
| 
 | ||||
| // IntervalFromEndpoints constructs a new interval from endpoints. | ||||
| // Both arguments must be in the range [-π,π]. This function allows inverted intervals | ||||
| // to be created. | ||||
| func IntervalFromEndpoints(lo, hi float64) Interval { | ||||
| 	i := Interval{lo, hi} | ||||
| 	if lo == -math.Pi && hi != math.Pi { | ||||
| 		i.Lo = math.Pi | ||||
| 	} | ||||
| 	if hi == -math.Pi && lo != math.Pi { | ||||
| 		i.Hi = math.Pi | ||||
| 	} | ||||
| 	return i | ||||
| } | ||||
| 
 | ||||
| // IntervalFromPointPair returns the minimal interval containing the two given points. | ||||
| // Both arguments must be in [-π,π]. | ||||
| func IntervalFromPointPair(a, b float64) Interval { | ||||
| 	if a == -math.Pi { | ||||
| 		a = math.Pi | ||||
| 	} | ||||
| 	if b == -math.Pi { | ||||
| 		b = math.Pi | ||||
| 	} | ||||
| 	if positiveDistance(a, b) <= math.Pi { | ||||
| 		return Interval{a, b} | ||||
| 	} | ||||
| 	return Interval{b, a} | ||||
| } | ||||
| 
 | ||||
| // EmptyInterval returns an empty interval. | ||||
| func EmptyInterval() Interval { return Interval{math.Pi, -math.Pi} } | ||||
| 
 | ||||
| // FullInterval returns a full interval. | ||||
| func FullInterval() Interval { return Interval{-math.Pi, math.Pi} } | ||||
| 
 | ||||
| // IsValid reports whether the interval is valid. | ||||
| func (i Interval) IsValid() bool { | ||||
| 	return (math.Abs(i.Lo) <= math.Pi && math.Abs(i.Hi) <= math.Pi && | ||||
| 		!(i.Lo == -math.Pi && i.Hi != math.Pi) && | ||||
| 		!(i.Hi == -math.Pi && i.Lo != math.Pi)) | ||||
| } | ||||
| 
 | ||||
| // IsFull reports whether the interval is full. | ||||
| func (i Interval) IsFull() bool { return i.Lo == -math.Pi && i.Hi == math.Pi } | ||||
| 
 | ||||
| // IsEmpty reports whether the interval is empty. | ||||
| func (i Interval) IsEmpty() bool { return i.Lo == math.Pi && i.Hi == -math.Pi } | ||||
| 
 | ||||
| // IsInverted reports whether the interval is inverted; that is, whether Lo > Hi. | ||||
| func (i Interval) IsInverted() bool { return i.Lo > i.Hi } | ||||
| 
 | ||||
| // Invert returns the interval with endpoints swapped. | ||||
| func (i Interval) Invert() Interval { | ||||
| 	return Interval{i.Hi, i.Lo} | ||||
| } | ||||
| 
 | ||||
| // Center returns the midpoint of the interval. | ||||
| // It is undefined for full and empty intervals. | ||||
| func (i Interval) Center() float64 { | ||||
| 	c := 0.5 * (i.Lo + i.Hi) | ||||
| 	if !i.IsInverted() { | ||||
| 		return c | ||||
| 	} | ||||
| 	if c <= 0 { | ||||
| 		return c + math.Pi | ||||
| 	} | ||||
| 	return c - math.Pi | ||||
| } | ||||
| 
 | ||||
| // Length returns the length of the interval. | ||||
| // The length of an empty interval is negative. | ||||
| func (i Interval) Length() float64 { | ||||
| 	l := i.Hi - i.Lo | ||||
| 	if l >= 0 { | ||||
| 		return l | ||||
| 	} | ||||
| 	l += 2 * math.Pi | ||||
| 	if l > 0 { | ||||
| 		return l | ||||
| 	} | ||||
| 	return -1 | ||||
| } | ||||
| 
 | ||||
| // Assumes p ∈ (-π,π]. | ||||
| func (i Interval) fastContains(p float64) bool { | ||||
| 	if i.IsInverted() { | ||||
| 		return (p >= i.Lo || p <= i.Hi) && !i.IsEmpty() | ||||
| 	} | ||||
| 	return p >= i.Lo && p <= i.Hi | ||||
| } | ||||
| 
 | ||||
| // Contains returns true iff the interval contains p. | ||||
| // Assumes p ∈ [-π,π]. | ||||
| func (i Interval) Contains(p float64) bool { | ||||
| 	if p == -math.Pi { | ||||
| 		p = math.Pi | ||||
| 	} | ||||
| 	return i.fastContains(p) | ||||
| } | ||||
| 
 | ||||
| // ContainsInterval returns true iff the interval contains oi. | ||||
| func (i Interval) ContainsInterval(oi Interval) bool { | ||||
| 	if i.IsInverted() { | ||||
| 		if oi.IsInverted() { | ||||
| 			return oi.Lo >= i.Lo && oi.Hi <= i.Hi | ||||
| 		} | ||||
| 		return (oi.Lo >= i.Lo || oi.Hi <= i.Hi) && !i.IsEmpty() | ||||
| 	} | ||||
| 	if oi.IsInverted() { | ||||
| 		return i.IsFull() || oi.IsEmpty() | ||||
| 	} | ||||
| 	return oi.Lo >= i.Lo && oi.Hi <= i.Hi | ||||
| } | ||||
| 
 | ||||
| // InteriorContains returns true iff the interior of the interval contains p. | ||||
| // Assumes p ∈ [-π,π]. | ||||
| func (i Interval) InteriorContains(p float64) bool { | ||||
| 	if p == -math.Pi { | ||||
| 		p = math.Pi | ||||
| 	} | ||||
| 	if i.IsInverted() { | ||||
| 		return p > i.Lo || p < i.Hi | ||||
| 	} | ||||
| 	return (p > i.Lo && p < i.Hi) || i.IsFull() | ||||
| } | ||||
| 
 | ||||
| // InteriorContainsInterval returns true iff the interior of the interval contains oi. | ||||
| func (i Interval) InteriorContainsInterval(oi Interval) bool { | ||||
| 	if i.IsInverted() { | ||||
| 		if oi.IsInverted() { | ||||
| 			return (oi.Lo > i.Lo && oi.Hi < i.Hi) || oi.IsEmpty() | ||||
| 		} | ||||
| 		return oi.Lo > i.Lo || oi.Hi < i.Hi | ||||
| 	} | ||||
| 	if oi.IsInverted() { | ||||
| 		return i.IsFull() || oi.IsEmpty() | ||||
| 	} | ||||
| 	return (oi.Lo > i.Lo && oi.Hi < i.Hi) || i.IsFull() | ||||
| } | ||||
| 
 | ||||
| // Intersects returns true iff the interval contains any points in common with oi. | ||||
| func (i Interval) Intersects(oi Interval) bool { | ||||
| 	if i.IsEmpty() || oi.IsEmpty() { | ||||
| 		return false | ||||
| 	} | ||||
| 	if i.IsInverted() { | ||||
| 		return oi.IsInverted() || oi.Lo <= i.Hi || oi.Hi >= i.Lo | ||||
| 	} | ||||
| 	if oi.IsInverted() { | ||||
| 		return oi.Lo <= i.Hi || oi.Hi >= i.Lo | ||||
| 	} | ||||
| 	return oi.Lo <= i.Hi && oi.Hi >= i.Lo | ||||
| } | ||||
| 
 | ||||
| // InteriorIntersects returns true iff the interior of the interval contains any points in common with oi, including the latter's boundary. | ||||
| func (i Interval) InteriorIntersects(oi Interval) bool { | ||||
| 	if i.IsEmpty() || oi.IsEmpty() || i.Lo == i.Hi { | ||||
| 		return false | ||||
| 	} | ||||
| 	if i.IsInverted() { | ||||
| 		return oi.IsInverted() || oi.Lo < i.Hi || oi.Hi > i.Lo | ||||
| 	} | ||||
| 	if oi.IsInverted() { | ||||
| 		return oi.Lo < i.Hi || oi.Hi > i.Lo | ||||
| 	} | ||||
| 	return (oi.Lo < i.Hi && oi.Hi > i.Lo) || i.IsFull() | ||||
| } | ||||
| 
 | ||||
| // Compute distance from a to b in [0,2π], in a numerically stable way. | ||||
| func positiveDistance(a, b float64) float64 { | ||||
| 	d := b - a | ||||
| 	if d >= 0 { | ||||
| 		return d | ||||
| 	} | ||||
| 	return (b + math.Pi) - (a - math.Pi) | ||||
| } | ||||
| 
 | ||||
| // Union returns the smallest interval that contains both the interval and oi. | ||||
| func (i Interval) Union(oi Interval) Interval { | ||||
| 	if oi.IsEmpty() { | ||||
| 		return i | ||||
| 	} | ||||
| 	if i.fastContains(oi.Lo) { | ||||
| 		if i.fastContains(oi.Hi) { | ||||
| 			// Either oi ⊂ i, or i ∪ oi is the full interval. | ||||
| 			if i.ContainsInterval(oi) { | ||||
| 				return i | ||||
| 			} | ||||
| 			return FullInterval() | ||||
| 		} | ||||
| 		return Interval{i.Lo, oi.Hi} | ||||
| 	} | ||||
| 	if i.fastContains(oi.Hi) { | ||||
| 		return Interval{oi.Lo, i.Hi} | ||||
| 	} | ||||
| 
 | ||||
| 	// Neither endpoint of oi is in i. Either i ⊂ oi, or i and oi are disjoint. | ||||
| 	if i.IsEmpty() || oi.fastContains(i.Lo) { | ||||
| 		return oi | ||||
| 	} | ||||
| 
 | ||||
| 	// This is the only hard case where we need to find the closest pair of endpoints. | ||||
| 	if positiveDistance(oi.Hi, i.Lo) < positiveDistance(i.Hi, oi.Lo) { | ||||
| 		return Interval{oi.Lo, i.Hi} | ||||
| 	} | ||||
| 	return Interval{i.Lo, oi.Hi} | ||||
| } | ||||
| 
 | ||||
| // Intersection returns the smallest interval that contains the intersection of the interval and oi. | ||||
| func (i Interval) Intersection(oi Interval) Interval { | ||||
| 	if oi.IsEmpty() { | ||||
| 		return EmptyInterval() | ||||
| 	} | ||||
| 	if i.fastContains(oi.Lo) { | ||||
| 		if i.fastContains(oi.Hi) { | ||||
| 			// Either oi ⊂ i, or i and oi intersect twice. Neither are empty. | ||||
| 			// In the first case we want to return i (which is shorter than oi). | ||||
| 			// In the second case one of them is inverted, and the smallest interval | ||||
| 			// that covers the two disjoint pieces is the shorter of i and oi. | ||||
| 			// We thus want to pick the shorter of i and oi in both cases. | ||||
| 			if oi.Length() < i.Length() { | ||||
| 				return oi | ||||
| 			} | ||||
| 			return i | ||||
| 		} | ||||
| 		return Interval{oi.Lo, i.Hi} | ||||
| 	} | ||||
| 	if i.fastContains(oi.Hi) { | ||||
| 		return Interval{i.Lo, oi.Hi} | ||||
| 	} | ||||
| 
 | ||||
| 	// Neither endpoint of oi is in i. Either i ⊂ oi, or i and oi are disjoint. | ||||
| 	if oi.fastContains(i.Lo) { | ||||
| 		return i | ||||
| 	} | ||||
| 	return EmptyInterval() | ||||
| } | ||||
| 
 | ||||
| // AddPoint returns the interval expanded by the minimum amount necessary such | ||||
| // that it contains the given point "p" (an angle in the range [-π, π]). | ||||
| func (i Interval) AddPoint(p float64) Interval { | ||||
| 	if math.Abs(p) > math.Pi { | ||||
| 		return i | ||||
| 	} | ||||
| 	if p == -math.Pi { | ||||
| 		p = math.Pi | ||||
| 	} | ||||
| 	if i.fastContains(p) { | ||||
| 		return i | ||||
| 	} | ||||
| 	if i.IsEmpty() { | ||||
| 		return Interval{p, p} | ||||
| 	} | ||||
| 	if positiveDistance(p, i.Lo) < positiveDistance(i.Hi, p) { | ||||
| 		return Interval{p, i.Hi} | ||||
| 	} | ||||
| 	return Interval{i.Lo, p} | ||||
| } | ||||
| 
 | ||||
| // Define the maximum rounding error for arithmetic operations. Depending on the | ||||
| // platform the mantissa precision may be different than others, so we choose to | ||||
| // use specific values to be consistent across all. | ||||
| // The values come from the C++ implementation. | ||||
| var ( | ||||
| 	// epsilon is a small number that represents a reasonable level of noise between two | ||||
| 	// values that can be considered to be equal. | ||||
| 	epsilon = 1e-15 | ||||
| 	// dblEpsilon is a smaller number for values that require more precision. | ||||
| 	dblEpsilon = 2.220446049e-16 | ||||
| ) | ||||
| 
 | ||||
| // Expanded returns an interval that has been expanded on each side by margin. | ||||
| // If margin is negative, then the function shrinks the interval on | ||||
| // each side by margin instead. The resulting interval may be empty or | ||||
| // full. Any expansion (positive or negative) of a full interval remains | ||||
| // full, and any expansion of an empty interval remains empty. | ||||
| func (i Interval) Expanded(margin float64) Interval { | ||||
| 	if margin >= 0 { | ||||
| 		if i.IsEmpty() { | ||||
| 			return i | ||||
| 		} | ||||
| 		// Check whether this interval will be full after expansion, allowing | ||||
| 		// for a rounding error when computing each endpoint. | ||||
| 		if i.Length()+2*margin+2*dblEpsilon >= 2*math.Pi { | ||||
| 			return FullInterval() | ||||
| 		} | ||||
| 	} else { | ||||
| 		if i.IsFull() { | ||||
| 			return i | ||||
| 		} | ||||
| 		// Check whether this interval will be empty after expansion, allowing | ||||
| 		// for a rounding error when computing each endpoint. | ||||
| 		if i.Length()+2*margin-2*dblEpsilon <= 0 { | ||||
| 			return EmptyInterval() | ||||
| 		} | ||||
| 	} | ||||
| 	result := IntervalFromEndpoints( | ||||
| 		math.Remainder(i.Lo-margin, 2*math.Pi), | ||||
| 		math.Remainder(i.Hi+margin, 2*math.Pi), | ||||
| 	) | ||||
| 	if result.Lo <= -math.Pi { | ||||
| 		result.Lo = math.Pi | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether this interval can be transformed into the given | ||||
| // interval by moving each endpoint by at most ε, without the | ||||
| // endpoints crossing (which would invert the interval). Empty and full | ||||
| // intervals are considered to start at an arbitrary point on the unit circle, | ||||
| // so any interval with (length <= 2*ε) matches the empty interval, and | ||||
| // any interval with (length >= 2*π - 2*ε) matches the full interval. | ||||
| func (i Interval) ApproxEqual(other Interval) bool { | ||||
| 	// Full and empty intervals require special cases because the endpoints | ||||
| 	// are considered to be positioned arbitrarily. | ||||
| 	if i.IsEmpty() { | ||||
| 		return other.Length() <= 2*epsilon | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return i.Length() <= 2*epsilon | ||||
| 	} | ||||
| 	if i.IsFull() { | ||||
| 		return other.Length() >= 2*(math.Pi-epsilon) | ||||
| 	} | ||||
| 	if other.IsFull() { | ||||
| 		return i.Length() >= 2*(math.Pi-epsilon) | ||||
| 	} | ||||
| 
 | ||||
| 	// The purpose of the last test below is to verify that moving the endpoints | ||||
| 	// does not invert the interval, e.g. [-1e20, 1e20] vs. [1e20, -1e20]. | ||||
| 	return (math.Abs(math.Remainder(other.Lo-i.Lo, 2*math.Pi)) <= epsilon && | ||||
| 		math.Abs(math.Remainder(other.Hi-i.Hi, 2*math.Pi)) <= epsilon && | ||||
| 		math.Abs(i.Length()-other.Length()) <= 2*epsilon) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func (i Interval) String() string { | ||||
| 	// like "[%.7f, %.7f]" | ||||
| 	return "[" + strconv.FormatFloat(i.Lo, 'f', 7, 64) + ", " + strconv.FormatFloat(i.Hi, 'f', 7, 64) + "]" | ||||
| } | ||||
| 
 | ||||
| // Complement returns the complement of the interior of the interval. An interval and | ||||
| // its complement have the same boundary but do not share any interior | ||||
| // values. The complement operator is not a bijection, since the complement | ||||
| // of a singleton interval (containing a single value) is the same as the | ||||
| // complement of an empty interval. | ||||
| func (i Interval) Complement() Interval { | ||||
| 	if i.Lo == i.Hi { | ||||
| 		// Singleton. The interval just contains a single point. | ||||
| 		return FullInterval() | ||||
| 	} | ||||
| 	// Handles empty and full. | ||||
| 	return Interval{i.Hi, i.Lo} | ||||
| } | ||||
| 
 | ||||
| // ComplementCenter returns the midpoint of the complement of the interval. For full and empty | ||||
| // intervals, the result is arbitrary. For a singleton interval (containing a | ||||
| // single point), the result is its antipodal point on S1. | ||||
| func (i Interval) ComplementCenter() float64 { | ||||
| 	if i.Lo != i.Hi { | ||||
| 		return i.Complement().Center() | ||||
| 	} | ||||
| 	// Singleton. The interval just contains a single point. | ||||
| 	if i.Hi <= 0 { | ||||
| 		return i.Hi + math.Pi | ||||
| 	} | ||||
| 	return i.Hi - math.Pi | ||||
| } | ||||
| 
 | ||||
| // DirectedHausdorffDistance returns the Hausdorff distance to the given interval. | ||||
| // For two intervals i and y, this distance is defined by | ||||
| //     h(i, y) = max_{p in i} min_{q in y} d(p, q), | ||||
| // where d(.,.) is measured along S1. | ||||
| func (i Interval) DirectedHausdorffDistance(y Interval) Angle { | ||||
| 	if y.ContainsInterval(i) { | ||||
| 		return 0 // This includes the case i is empty. | ||||
| 	} | ||||
| 	if y.IsEmpty() { | ||||
| 		return Angle(math.Pi) // maximum possible distance on s1. | ||||
| 	} | ||||
| 	yComplementCenter := y.ComplementCenter() | ||||
| 	if i.Contains(yComplementCenter) { | ||||
| 		return Angle(positiveDistance(y.Hi, yComplementCenter)) | ||||
| 	} | ||||
| 
 | ||||
| 	// The Hausdorff distance is realized by either two i.Hi endpoints or two | ||||
| 	// i.Lo endpoints, whichever is farther apart. | ||||
| 	hiHi := 0.0 | ||||
| 	if IntervalFromEndpoints(y.Hi, yComplementCenter).Contains(i.Hi) { | ||||
| 		hiHi = positiveDistance(y.Hi, i.Hi) | ||||
| 	} | ||||
| 
 | ||||
| 	loLo := 0.0 | ||||
| 	if IntervalFromEndpoints(yComplementCenter, y.Lo).Contains(i.Lo) { | ||||
| 		loLo = positiveDistance(i.Lo, y.Lo) | ||||
| 	} | ||||
| 
 | ||||
| 	return Angle(math.Max(hiHi, loLo)) | ||||
| } | ||||
| 
 | ||||
| // Project returns the closest point in the interval to the given point p. | ||||
| // The interval must be non-empty. | ||||
| func (i Interval) Project(p float64) float64 { | ||||
| 	if p == -math.Pi { | ||||
| 		p = math.Pi | ||||
| 	} | ||||
| 	if i.fastContains(p) { | ||||
| 		return p | ||||
| 	} | ||||
| 	// Compute distance from p to each endpoint. | ||||
| 	dlo := positiveDistance(p, i.Lo) | ||||
| 	dhi := positiveDistance(i.Hi, p) | ||||
| 	if dlo < dhi { | ||||
| 		return i.Lo | ||||
| 	} | ||||
| 	return i.Hi | ||||
| } | ||||
							
								
								
									
										53
									
								
								vendor/github.com/golang/geo/s2/bits_go18.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/golang/geo/s2/bits_go18.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,53 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| // +build !go1.9 | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file is for the bit manipulation code pre-Go 1.9. | ||||
| 
 | ||||
| // findMSBSetNonZero64 returns the index (between 0 and 63) of the most | ||||
| // significant set bit. Passing zero to this function returns zero. | ||||
| func findMSBSetNonZero64(x uint64) int { | ||||
| 	val := []uint64{0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000} | ||||
| 	shift := []uint64{1, 2, 4, 8, 16, 32} | ||||
| 	var msbPos uint64 | ||||
| 	for i := 5; i >= 0; i-- { | ||||
| 		if x&val[i] != 0 { | ||||
| 			x >>= shift[i] | ||||
| 			msbPos |= shift[i] | ||||
| 		} | ||||
| 	} | ||||
| 	return int(msbPos) | ||||
| } | ||||
| 
 | ||||
| const deBruijn64 = 0x03f79d71b4ca8b09 | ||||
| const digitMask = uint64(1<<64 - 1) | ||||
| 
 | ||||
| var deBruijn64Lookup = []byte{ | ||||
| 	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, | ||||
| 	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, | ||||
| 	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, | ||||
| 	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, | ||||
| } | ||||
| 
 | ||||
| // findLSBSetNonZero64 returns the index (between 0 and 63) of the least | ||||
| // significant set bit. Passing zero to this function returns zero. | ||||
| // | ||||
| // This code comes from trailingZeroBits in https://golang.org/src/math/big/nat.go | ||||
| // which references (Knuth, volume 4, section 7.3.1). | ||||
| func findLSBSetNonZero64(x uint64) int { | ||||
| 	return int(deBruijn64Lookup[((x&-x)*(deBruijn64&digitMask))>>58]) | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/golang/geo/s2/bits_go19.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/golang/geo/s2/bits_go19.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,39 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| // +build go1.9 | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file is for the bit manipulation code post-Go 1.9. | ||||
| 
 | ||||
| import "math/bits" | ||||
| 
 | ||||
| // findMSBSetNonZero64 returns the index (between 0 and 63) of the most | ||||
| // significant set bit. Passing zero to this function return zero. | ||||
| func findMSBSetNonZero64(x uint64) int { | ||||
| 	if x == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return 63 - bits.LeadingZeros64(x) | ||||
| } | ||||
| 
 | ||||
| // findLSBSetNonZero64 returns the index (between 0 and 63) of the least | ||||
| // significant set bit. Passing zero to this function return zero. | ||||
| func findLSBSetNonZero64(x uint64) int { | ||||
| 	if x == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return bits.TrailingZeros64(x) | ||||
| } | ||||
							
								
								
									
										519
									
								
								vendor/github.com/golang/geo/s2/cap.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										519
									
								
								vendor/github.com/golang/geo/s2/cap.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,519 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// centerPoint is the default center for Caps | ||||
| 	centerPoint = PointFromCoords(1.0, 0, 0) | ||||
| ) | ||||
| 
 | ||||
| // Cap represents a disc-shaped region defined by a center and radius. | ||||
| // Technically this shape is called a "spherical cap" (rather than disc) | ||||
| // because it is not planar; the cap represents a portion of the sphere that | ||||
| // has been cut off by a plane. The boundary of the cap is the circle defined | ||||
| // by the intersection of the sphere and the plane. For containment purposes, | ||||
| // the cap is a closed set, i.e. it contains its boundary. | ||||
| // | ||||
| // For the most part, you can use a spherical cap wherever you would use a | ||||
| // disc in planar geometry. The radius of the cap is measured along the | ||||
| // surface of the sphere (rather than the straight-line distance through the | ||||
| // interior). Thus a cap of radius π/2 is a hemisphere, and a cap of radius | ||||
| // π covers the entire sphere. | ||||
| // | ||||
| // The center is a point on the surface of the unit sphere. (Hence the need for | ||||
| // it to be of unit length.) | ||||
| // | ||||
| // A cap can also be defined by its center point and height. The height is the | ||||
| // distance from the center point to the cutoff plane. There is also support for | ||||
| // "empty" and "full" caps, which contain no points and all points respectively. | ||||
| // | ||||
| // Here are some useful relationships between the cap height (h), the cap | ||||
| // radius (r), the maximum chord length from the cap's center (d), and the | ||||
| // radius of cap's base (a). | ||||
| // | ||||
| //     h = 1 - cos(r) | ||||
| //       = 2 * sin^2(r/2) | ||||
| //   d^2 = 2 * h | ||||
| //       = a^2 + h^2 | ||||
| // | ||||
| // The zero value of Cap is an invalid cap. Use EmptyCap to get a valid empty cap. | ||||
| type Cap struct { | ||||
| 	center Point | ||||
| 	radius s1.ChordAngle | ||||
| } | ||||
| 
 | ||||
| // CapFromPoint constructs a cap containing a single point. | ||||
| func CapFromPoint(p Point) Cap { | ||||
| 	return CapFromCenterChordAngle(p, 0) | ||||
| } | ||||
| 
 | ||||
| // CapFromCenterAngle constructs a cap with the given center and angle. | ||||
| func CapFromCenterAngle(center Point, angle s1.Angle) Cap { | ||||
| 	return CapFromCenterChordAngle(center, s1.ChordAngleFromAngle(angle)) | ||||
| } | ||||
| 
 | ||||
| // CapFromCenterChordAngle constructs a cap where the angle is expressed as an | ||||
| // s1.ChordAngle. This constructor is more efficient than using an s1.Angle. | ||||
| func CapFromCenterChordAngle(center Point, radius s1.ChordAngle) Cap { | ||||
| 	return Cap{ | ||||
| 		center: center, | ||||
| 		radius: radius, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CapFromCenterHeight constructs a cap with the given center and height. A | ||||
| // negative height yields an empty cap; a height of 2 or more yields a full cap. | ||||
| // The center should be unit length. | ||||
| func CapFromCenterHeight(center Point, height float64) Cap { | ||||
| 	return CapFromCenterChordAngle(center, s1.ChordAngleFromSquaredLength(2*height)) | ||||
| } | ||||
| 
 | ||||
| // CapFromCenterArea constructs a cap with the given center and surface area. | ||||
| // Note that the area can also be interpreted as the solid angle subtended by the | ||||
| // cap (because the sphere has unit radius). A negative area yields an empty cap; | ||||
| // an area of 4*π or more yields a full cap. | ||||
| func CapFromCenterArea(center Point, area float64) Cap { | ||||
| 	return CapFromCenterChordAngle(center, s1.ChordAngleFromSquaredLength(area/math.Pi)) | ||||
| } | ||||
| 
 | ||||
| // EmptyCap returns a cap that contains no points. | ||||
| func EmptyCap() Cap { | ||||
| 	return CapFromCenterChordAngle(centerPoint, s1.NegativeChordAngle) | ||||
| } | ||||
| 
 | ||||
| // FullCap returns a cap that contains all points. | ||||
| func FullCap() Cap { | ||||
| 	return CapFromCenterChordAngle(centerPoint, s1.StraightChordAngle) | ||||
| } | ||||
| 
 | ||||
| // IsValid reports whether the Cap is considered valid. | ||||
| func (c Cap) IsValid() bool { | ||||
| 	return c.center.Vector.IsUnit() && c.radius <= s1.StraightChordAngle | ||||
| } | ||||
| 
 | ||||
| // IsEmpty reports whether the cap is empty, i.e. it contains no points. | ||||
| func (c Cap) IsEmpty() bool { | ||||
| 	return c.radius < 0 | ||||
| } | ||||
| 
 | ||||
| // IsFull reports whether the cap is full, i.e. it contains all points. | ||||
| func (c Cap) IsFull() bool { | ||||
| 	return c.radius == s1.StraightChordAngle | ||||
| } | ||||
| 
 | ||||
| // Center returns the cap's center point. | ||||
| func (c Cap) Center() Point { | ||||
| 	return c.center | ||||
| } | ||||
| 
 | ||||
| // Height returns the height of the cap. This is the distance from the center | ||||
| // point to the cutoff plane. | ||||
| func (c Cap) Height() float64 { | ||||
| 	return float64(0.5 * c.radius) | ||||
| } | ||||
| 
 | ||||
| // Radius returns the cap radius as an s1.Angle. (Note that the cap angle | ||||
| // is stored internally as a ChordAngle, so this method requires a trigonometric | ||||
| // operation and may yield a slightly different result than the value passed | ||||
| // to CapFromCenterAngle). | ||||
| func (c Cap) Radius() s1.Angle { | ||||
| 	return c.radius.Angle() | ||||
| } | ||||
| 
 | ||||
| // Area returns the surface area of the Cap on the unit sphere. | ||||
| func (c Cap) Area() float64 { | ||||
| 	return 2.0 * math.Pi * math.Max(0, c.Height()) | ||||
| } | ||||
| 
 | ||||
| // Contains reports whether this cap contains the other. | ||||
| func (c Cap) Contains(other Cap) bool { | ||||
| 	// In a set containment sense, every cap contains the empty cap. | ||||
| 	if c.IsFull() || other.IsEmpty() { | ||||
| 		return true | ||||
| 	} | ||||
| 	return c.radius >= ChordAngleBetweenPoints(c.center, other.center).Add(other.radius) | ||||
| } | ||||
| 
 | ||||
| // Intersects reports whether this cap intersects the other cap. | ||||
| // i.e. whether they have any points in common. | ||||
| func (c Cap) Intersects(other Cap) bool { | ||||
| 	if c.IsEmpty() || other.IsEmpty() { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return c.radius.Add(other.radius) >= ChordAngleBetweenPoints(c.center, other.center) | ||||
| } | ||||
| 
 | ||||
| // InteriorIntersects reports whether this caps interior intersects the other cap. | ||||
| func (c Cap) InteriorIntersects(other Cap) bool { | ||||
| 	// Make sure this cap has an interior and the other cap is non-empty. | ||||
| 	if c.radius <= 0 || other.IsEmpty() { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return c.radius.Add(other.radius) > ChordAngleBetweenPoints(c.center, other.center) | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether this cap contains the point. | ||||
| func (c Cap) ContainsPoint(p Point) bool { | ||||
| 	return ChordAngleBetweenPoints(c.center, p) <= c.radius | ||||
| } | ||||
| 
 | ||||
| // InteriorContainsPoint reports whether the point is within the interior of this cap. | ||||
| func (c Cap) InteriorContainsPoint(p Point) bool { | ||||
| 	return c.IsFull() || ChordAngleBetweenPoints(c.center, p) < c.radius | ||||
| } | ||||
| 
 | ||||
| // Complement returns the complement of the interior of the cap. A cap and its | ||||
| // complement have the same boundary but do not share any interior points. | ||||
| // The complement operator is not a bijection because the complement of a | ||||
| // singleton cap (containing a single point) is the same as the complement | ||||
| // of an empty cap. | ||||
| func (c Cap) Complement() Cap { | ||||
| 	if c.IsFull() { | ||||
| 		return EmptyCap() | ||||
| 	} | ||||
| 	if c.IsEmpty() { | ||||
| 		return FullCap() | ||||
| 	} | ||||
| 
 | ||||
| 	return CapFromCenterChordAngle(Point{c.center.Mul(-1)}, s1.StraightChordAngle.Sub(c.radius)) | ||||
| } | ||||
| 
 | ||||
| // CapBound returns a bounding spherical cap. This is not guaranteed to be exact. | ||||
| func (c Cap) CapBound() Cap { | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // RectBound returns a bounding latitude-longitude rectangle. | ||||
| // The bounds are not guaranteed to be tight. | ||||
| func (c Cap) RectBound() Rect { | ||||
| 	if c.IsEmpty() { | ||||
| 		return EmptyRect() | ||||
| 	} | ||||
| 
 | ||||
| 	capAngle := c.Radius().Radians() | ||||
| 	allLongitudes := false | ||||
| 	lat := r1.Interval{ | ||||
| 		Lo: latitude(c.center).Radians() - capAngle, | ||||
| 		Hi: latitude(c.center).Radians() + capAngle, | ||||
| 	} | ||||
| 	lng := s1.FullInterval() | ||||
| 
 | ||||
| 	// Check whether cap includes the south pole. | ||||
| 	if lat.Lo <= -math.Pi/2 { | ||||
| 		lat.Lo = -math.Pi / 2 | ||||
| 		allLongitudes = true | ||||
| 	} | ||||
| 
 | ||||
| 	// Check whether cap includes the north pole. | ||||
| 	if lat.Hi >= math.Pi/2 { | ||||
| 		lat.Hi = math.Pi / 2 | ||||
| 		allLongitudes = true | ||||
| 	} | ||||
| 
 | ||||
| 	if !allLongitudes { | ||||
| 		// Compute the range of longitudes covered by the cap. We use the law | ||||
| 		// of sines for spherical triangles. Consider the triangle ABC where | ||||
| 		// A is the north pole, B is the center of the cap, and C is the point | ||||
| 		// of tangency between the cap boundary and a line of longitude. Then | ||||
| 		// C is a right angle, and letting a,b,c denote the sides opposite A,B,C, | ||||
| 		// we have sin(a)/sin(A) = sin(c)/sin(C), or sin(A) = sin(a)/sin(c). | ||||
| 		// Here "a" is the cap angle, and "c" is the colatitude (90 degrees | ||||
| 		// minus the latitude). This formula also works for negative latitudes. | ||||
| 		// | ||||
| 		// The formula for sin(a) follows from the relationship h = 1 - cos(a). | ||||
| 		sinA := c.radius.Sin() | ||||
| 		sinC := math.Cos(latitude(c.center).Radians()) | ||||
| 		if sinA <= sinC { | ||||
| 			angleA := math.Asin(sinA / sinC) | ||||
| 			lng.Lo = math.Remainder(longitude(c.center).Radians()-angleA, math.Pi*2) | ||||
| 			lng.Hi = math.Remainder(longitude(c.center).Radians()+angleA, math.Pi*2) | ||||
| 		} | ||||
| 	} | ||||
| 	return Rect{lat, lng} | ||||
| } | ||||
| 
 | ||||
| // Equal reports whether this cap is equal to the other cap. | ||||
| func (c Cap) Equal(other Cap) bool { | ||||
| 	return (c.radius == other.radius && c.center == other.center) || | ||||
| 		(c.IsEmpty() && other.IsEmpty()) || | ||||
| 		(c.IsFull() && other.IsFull()) | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether this cap is equal to the other cap within the given tolerance. | ||||
| func (c Cap) ApproxEqual(other Cap) bool { | ||||
| 	const epsilon = 1e-14 | ||||
| 	r2 := float64(c.radius) | ||||
| 	otherR2 := float64(other.radius) | ||||
| 	return c.center.ApproxEqual(other.center) && | ||||
| 		math.Abs(r2-otherR2) <= epsilon || | ||||
| 		c.IsEmpty() && otherR2 <= epsilon || | ||||
| 		other.IsEmpty() && r2 <= epsilon || | ||||
| 		c.IsFull() && otherR2 >= 2-epsilon || | ||||
| 		other.IsFull() && r2 >= 2-epsilon | ||||
| } | ||||
| 
 | ||||
| // AddPoint increases the cap if necessary to include the given point. If this cap is empty, | ||||
| // then the center is set to the point with a zero height. p must be unit-length. | ||||
| func (c Cap) AddPoint(p Point) Cap { | ||||
| 	if c.IsEmpty() { | ||||
| 		c.center = p | ||||
| 		c.radius = 0 | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	// After calling cap.AddPoint(p), cap.Contains(p) must be true. However | ||||
| 	// we don't need to do anything special to achieve this because Contains() | ||||
| 	// does exactly the same distance calculation that we do here. | ||||
| 	if newRad := ChordAngleBetweenPoints(c.center, p); newRad > c.radius { | ||||
| 		c.radius = newRad | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // AddCap increases the cap height if necessary to include the other cap. If this cap is empty, | ||||
| // it is set to the other cap. | ||||
| func (c Cap) AddCap(other Cap) Cap { | ||||
| 	if c.IsEmpty() { | ||||
| 		return other | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	// We round up the distance to ensure that the cap is actually contained. | ||||
| 	// TODO(roberts): Do some error analysis in order to guarantee this. | ||||
| 	dist := ChordAngleBetweenPoints(c.center, other.center).Add(other.radius) | ||||
| 	if newRad := dist.Expanded(dblEpsilon * float64(dist)); newRad > c.radius { | ||||
| 		c.radius = newRad | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // Expanded returns a new cap expanded by the given angle. If the cap is empty, | ||||
| // it returns an empty cap. | ||||
| func (c Cap) Expanded(distance s1.Angle) Cap { | ||||
| 	if c.IsEmpty() { | ||||
| 		return EmptyCap() | ||||
| 	} | ||||
| 	return CapFromCenterChordAngle(c.center, c.radius.Add(s1.ChordAngleFromAngle(distance))) | ||||
| } | ||||
| 
 | ||||
| func (c Cap) String() string { | ||||
| 	return fmt.Sprintf("[Center=%v, Radius=%f]", c.center.Vector, c.Radius().Degrees()) | ||||
| } | ||||
| 
 | ||||
| // radiusToHeight converts an s1.Angle into the height of the cap. | ||||
| func radiusToHeight(r s1.Angle) float64 { | ||||
| 	if r.Radians() < 0 { | ||||
| 		return float64(s1.NegativeChordAngle) | ||||
| 	} | ||||
| 	if r.Radians() >= math.Pi { | ||||
| 		return float64(s1.RightChordAngle) | ||||
| 	} | ||||
| 	return float64(0.5 * s1.ChordAngleFromAngle(r)) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether the cap contains the given cell. | ||||
| func (c Cap) ContainsCell(cell Cell) bool { | ||||
| 	// If the cap does not contain all cell vertices, return false. | ||||
| 	var vertices [4]Point | ||||
| 	for k := 0; k < 4; k++ { | ||||
| 		vertices[k] = cell.Vertex(k) | ||||
| 		if !c.ContainsPoint(vertices[k]) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	// Otherwise, return true if the complement of the cap does not intersect the cell. | ||||
| 	return !c.Complement().intersects(cell, vertices) | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether the cap intersects the cell. | ||||
| func (c Cap) IntersectsCell(cell Cell) bool { | ||||
| 	// If the cap contains any cell vertex, return true. | ||||
| 	var vertices [4]Point | ||||
| 	for k := 0; k < 4; k++ { | ||||
| 		vertices[k] = cell.Vertex(k) | ||||
| 		if c.ContainsPoint(vertices[k]) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return c.intersects(cell, vertices) | ||||
| } | ||||
| 
 | ||||
| // intersects reports whether the cap intersects any point of the cell excluding | ||||
| // its vertices (which are assumed to already have been checked). | ||||
| func (c Cap) intersects(cell Cell, vertices [4]Point) bool { | ||||
| 	// If the cap is a hemisphere or larger, the cell and the complement of the cap | ||||
| 	// are both convex. Therefore since no vertex of the cell is contained, no other | ||||
| 	// interior point of the cell is contained either. | ||||
| 	if c.radius >= s1.RightChordAngle { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// We need to check for empty caps due to the center check just below. | ||||
| 	if c.IsEmpty() { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Optimization: return true if the cell contains the cap center. This allows half | ||||
| 	// of the edge checks below to be skipped. | ||||
| 	if cell.ContainsPoint(c.center) { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	// At this point we know that the cell does not contain the cap center, and the cap | ||||
| 	// does not contain any cell vertex. The only way that they can intersect is if the | ||||
| 	// cap intersects the interior of some edge. | ||||
| 	sin2Angle := c.radius.Sin2() | ||||
| 	for k := 0; k < 4; k++ { | ||||
| 		edge := cell.Edge(k).Vector | ||||
| 		dot := c.center.Vector.Dot(edge) | ||||
| 		if dot > 0 { | ||||
| 			// The center is in the interior half-space defined by the edge. We do not need | ||||
| 			// to consider these edges, since if the cap intersects this edge then it also | ||||
| 			// intersects the edge on the opposite side of the cell, because the center is | ||||
| 			// not contained with the cell. | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// The Norm2() factor is necessary because "edge" is not normalized. | ||||
| 		if dot*dot > sin2Angle*edge.Norm2() { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		// Otherwise, the great circle containing this edge intersects the interior of the cap. We just | ||||
| 		// need to check whether the point of closest approach occurs between the two edge endpoints. | ||||
| 		dir := edge.Cross(c.center.Vector) | ||||
| 		if dir.Dot(vertices[k].Vector) < 0 && dir.Dot(vertices[(k+1)&3].Vector) > 0 { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the Cap. In general the covering | ||||
| // consists of at most 4 cells except for very large caps, which may need | ||||
| // up to 6 cells. The output is not sorted. | ||||
| func (c Cap) CellUnionBound() []CellID { | ||||
| 	// TODO(roberts): The covering could be made quite a bit tighter by mapping | ||||
| 	// the cap to a rectangle in (i,j)-space and finding a covering for that. | ||||
| 
 | ||||
| 	// Find the maximum level such that the cap contains at most one cell vertex | ||||
| 	// and such that CellID.AppendVertexNeighbors() can be called. | ||||
| 	level := MinWidthMetric.MaxLevel(c.Radius().Radians()) - 1 | ||||
| 
 | ||||
| 	// If level < 0, more than three face cells are required. | ||||
| 	if level < 0 { | ||||
| 		cellIDs := make([]CellID, 6) | ||||
| 		for face := 0; face < 6; face++ { | ||||
| 			cellIDs[face] = CellIDFromFace(face) | ||||
| 		} | ||||
| 		return cellIDs | ||||
| 	} | ||||
| 	// The covering consists of the 4 cells at the given level that share the | ||||
| 	// cell vertex that is closest to the cap center. | ||||
| 	return cellIDFromPoint(c.center).VertexNeighbors(level) | ||||
| } | ||||
| 
 | ||||
| // Centroid returns the true centroid of the cap multiplied by its surface area | ||||
| // The result lies on the ray from the origin through the cap's center, but it | ||||
| // is not unit length. Note that if you just want the "surface centroid", i.e. | ||||
| // the normalized result, then it is simpler to call Center. | ||||
| // | ||||
| // The reason for multiplying the result by the cap area is to make it | ||||
| // easier to compute the centroid of more complicated shapes. The centroid | ||||
| // of a union of disjoint regions can be computed simply by adding their | ||||
| // Centroid() results. Caveat: for caps that contain a single point | ||||
| // (i.e., zero radius), this method always returns the origin (0, 0, 0). | ||||
| // This is because shapes with no area don't affect the centroid of a | ||||
| // union whose total area is positive. | ||||
| func (c Cap) Centroid() Point { | ||||
| 	// From symmetry, the centroid of the cap must be somewhere on the line | ||||
| 	// from the origin to the center of the cap on the surface of the sphere. | ||||
| 	// When a sphere is divided into slices of constant thickness by a set of | ||||
| 	// parallel planes, all slices have the same surface area. This implies | ||||
| 	// that the radial component of the centroid is simply the midpoint of the | ||||
| 	// range of radial distances spanned by the cap. That is easily computed | ||||
| 	// from the cap height. | ||||
| 	if c.IsEmpty() { | ||||
| 		return Point{} | ||||
| 	} | ||||
| 	r := 1 - 0.5*c.Height() | ||||
| 	return Point{c.center.Mul(r * c.Area())} | ||||
| } | ||||
| 
 | ||||
| // Union returns the smallest cap which encloses this cap and other. | ||||
| func (c Cap) Union(other Cap) Cap { | ||||
| 	// If the other cap is larger, swap c and other for the rest of the computations. | ||||
| 	if c.radius < other.radius { | ||||
| 		c, other = other, c | ||||
| 	} | ||||
| 
 | ||||
| 	if c.IsFull() || other.IsEmpty() { | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: This calculation would be more efficient using s1.ChordAngles. | ||||
| 	cRadius := c.Radius() | ||||
| 	otherRadius := other.Radius() | ||||
| 	distance := c.center.Distance(other.center) | ||||
| 	if cRadius >= distance+otherRadius { | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	resRadius := 0.5 * (distance + cRadius + otherRadius) | ||||
| 	resCenter := InterpolateAtDistance(0.5*(distance-cRadius+otherRadius), c.center, other.center) | ||||
| 	return CapFromCenterAngle(resCenter, resRadius) | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the Cap. | ||||
| func (c Cap) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	c.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (c Cap) encode(e *encoder) { | ||||
| 	e.writeFloat64(c.center.X) | ||||
| 	e.writeFloat64(c.center.Y) | ||||
| 	e.writeFloat64(c.center.Z) | ||||
| 	e.writeFloat64(float64(c.radius)) | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the Cap. | ||||
| func (c *Cap) Decode(r io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(r)} | ||||
| 	c.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (c *Cap) decode(d *decoder) { | ||||
| 	c.center.X = d.readFloat64() | ||||
| 	c.center.Y = d.readFloat64() | ||||
| 	c.center.Z = d.readFloat64() | ||||
| 	c.radius = s1.ChordAngle(d.readFloat64()) | ||||
| } | ||||
							
								
								
									
										698
									
								
								vendor/github.com/golang/geo/s2/cell.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										698
									
								
								vendor/github.com/golang/geo/s2/cell.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,698 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r2" | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Cell is an S2 region object that represents a cell. Unlike CellIDs, | ||||
| // it supports efficient containment and intersection tests. However, it is | ||||
| // also a more expensive representation. | ||||
| type Cell struct { | ||||
| 	face        int8 | ||||
| 	level       int8 | ||||
| 	orientation int8 | ||||
| 	id          CellID | ||||
| 	uv          r2.Rect | ||||
| } | ||||
| 
 | ||||
| // CellFromCellID constructs a Cell corresponding to the given CellID. | ||||
| func CellFromCellID(id CellID) Cell { | ||||
| 	c := Cell{} | ||||
| 	c.id = id | ||||
| 	f, i, j, o := c.id.faceIJOrientation() | ||||
| 	c.face = int8(f) | ||||
| 	c.level = int8(c.id.Level()) | ||||
| 	c.orientation = int8(o) | ||||
| 	c.uv = ijLevelToBoundUV(i, j, int(c.level)) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // CellFromPoint constructs a cell for the given Point. | ||||
| func CellFromPoint(p Point) Cell { | ||||
| 	return CellFromCellID(cellIDFromPoint(p)) | ||||
| } | ||||
| 
 | ||||
| // CellFromLatLng constructs a cell for the given LatLng. | ||||
| func CellFromLatLng(ll LatLng) Cell { | ||||
| 	return CellFromCellID(CellIDFromLatLng(ll)) | ||||
| } | ||||
| 
 | ||||
| // Face returns the face this cell is on. | ||||
| func (c Cell) Face() int { | ||||
| 	return int(c.face) | ||||
| } | ||||
| 
 | ||||
| // oppositeFace returns the face opposite the given face. | ||||
| func oppositeFace(face int) int { | ||||
| 	return (face + 3) % 6 | ||||
| } | ||||
| 
 | ||||
| // Level returns the level of this cell. | ||||
| func (c Cell) Level() int { | ||||
| 	return int(c.level) | ||||
| } | ||||
| 
 | ||||
| // ID returns the CellID this cell represents. | ||||
| func (c Cell) ID() CellID { | ||||
| 	return c.id | ||||
| } | ||||
| 
 | ||||
| // IsLeaf returns whether this Cell is a leaf or not. | ||||
| func (c Cell) IsLeaf() bool { | ||||
| 	return c.level == maxLevel | ||||
| } | ||||
| 
 | ||||
| // SizeIJ returns the edge length of this cell in (i,j)-space. | ||||
| func (c Cell) SizeIJ() int { | ||||
| 	return sizeIJ(int(c.level)) | ||||
| } | ||||
| 
 | ||||
| // SizeST returns the edge length of this cell in (s,t)-space. | ||||
| func (c Cell) SizeST() float64 { | ||||
| 	return c.id.sizeST(int(c.level)) | ||||
| } | ||||
| 
 | ||||
| // Vertex returns the k-th vertex of the cell (k = 0,1,2,3) in CCW order | ||||
| // (lower left, lower right, upper right, upper left in the UV plane). | ||||
| func (c Cell) Vertex(k int) Point { | ||||
| 	return Point{faceUVToXYZ(int(c.face), c.uv.Vertices()[k].X, c.uv.Vertices()[k].Y).Normalize()} | ||||
| } | ||||
| 
 | ||||
| // Edge returns the inward-facing normal of the great circle passing through | ||||
| // the CCW ordered edge from vertex k to vertex k+1 (mod 4) (for k = 0,1,2,3). | ||||
| func (c Cell) Edge(k int) Point { | ||||
| 	switch k { | ||||
| 	case 0: | ||||
| 		return Point{vNorm(int(c.face), c.uv.Y.Lo).Normalize()} // Bottom | ||||
| 	case 1: | ||||
| 		return Point{uNorm(int(c.face), c.uv.X.Hi).Normalize()} // Right | ||||
| 	case 2: | ||||
| 		return Point{vNorm(int(c.face), c.uv.Y.Hi).Mul(-1.0).Normalize()} // Top | ||||
| 	default: | ||||
| 		return Point{uNorm(int(c.face), c.uv.X.Lo).Mul(-1.0).Normalize()} // Left | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // BoundUV returns the bounds of this cell in (u,v)-space. | ||||
| func (c Cell) BoundUV() r2.Rect { | ||||
| 	return c.uv | ||||
| } | ||||
| 
 | ||||
| // Center returns the direction vector corresponding to the center in | ||||
| // (s,t)-space of the given cell. This is the point at which the cell is | ||||
| // divided into four subcells; it is not necessarily the centroid of the | ||||
| // cell in (u,v)-space or (x,y,z)-space | ||||
| func (c Cell) Center() Point { | ||||
| 	return Point{c.id.rawPoint().Normalize()} | ||||
| } | ||||
| 
 | ||||
| // Children returns the four direct children of this cell in traversal order | ||||
| // and returns true. If this is a leaf cell, or the children could not be created, | ||||
| // false is returned. | ||||
| // The C++ method is called Subdivide. | ||||
| func (c Cell) Children() ([4]Cell, bool) { | ||||
| 	var children [4]Cell | ||||
| 
 | ||||
| 	if c.id.IsLeaf() { | ||||
| 		return children, false | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the cell midpoint in uv-space. | ||||
| 	uvMid := c.id.centerUV() | ||||
| 
 | ||||
| 	// Create four children with the appropriate bounds. | ||||
| 	cid := c.id.ChildBegin() | ||||
| 	for pos := 0; pos < 4; pos++ { | ||||
| 		children[pos] = Cell{ | ||||
| 			face:        c.face, | ||||
| 			level:       c.level + 1, | ||||
| 			orientation: c.orientation ^ int8(posToOrientation[pos]), | ||||
| 			id:          cid, | ||||
| 		} | ||||
| 
 | ||||
| 		// We want to split the cell in half in u and v. To decide which | ||||
| 		// side to set equal to the midpoint value, we look at cell's (i,j) | ||||
| 		// position within its parent. The index for i is in bit 1 of ij. | ||||
| 		ij := posToIJ[c.orientation][pos] | ||||
| 		i := ij >> 1 | ||||
| 		j := ij & 1 | ||||
| 		if i == 1 { | ||||
| 			children[pos].uv.X.Hi = c.uv.X.Hi | ||||
| 			children[pos].uv.X.Lo = uvMid.X | ||||
| 		} else { | ||||
| 			children[pos].uv.X.Lo = c.uv.X.Lo | ||||
| 			children[pos].uv.X.Hi = uvMid.X | ||||
| 		} | ||||
| 		if j == 1 { | ||||
| 			children[pos].uv.Y.Hi = c.uv.Y.Hi | ||||
| 			children[pos].uv.Y.Lo = uvMid.Y | ||||
| 		} else { | ||||
| 			children[pos].uv.Y.Lo = c.uv.Y.Lo | ||||
| 			children[pos].uv.Y.Hi = uvMid.Y | ||||
| 		} | ||||
| 		cid = cid.Next() | ||||
| 	} | ||||
| 	return children, true | ||||
| } | ||||
| 
 | ||||
| // ExactArea returns the area of this cell as accurately as possible. | ||||
| func (c Cell) ExactArea() float64 { | ||||
| 	v0, v1, v2, v3 := c.Vertex(0), c.Vertex(1), c.Vertex(2), c.Vertex(3) | ||||
| 	return PointArea(v0, v1, v2) + PointArea(v0, v2, v3) | ||||
| } | ||||
| 
 | ||||
| // ApproxArea returns the approximate area of this cell. This method is accurate | ||||
| // to within 3% percent for all cell sizes and accurate to within 0.1% for cells | ||||
| // at level 5 or higher (i.e. squares 350km to a side or smaller on the Earth's | ||||
| // surface). It is moderately cheap to compute. | ||||
| func (c Cell) ApproxArea() float64 { | ||||
| 	// All cells at the first two levels have the same area. | ||||
| 	if c.level < 2 { | ||||
| 		return c.AverageArea() | ||||
| 	} | ||||
| 
 | ||||
| 	// First, compute the approximate area of the cell when projected | ||||
| 	// perpendicular to its normal. The cross product of its diagonals gives | ||||
| 	// the normal, and the length of the normal is twice the projected area. | ||||
| 	flatArea := 0.5 * (c.Vertex(2).Sub(c.Vertex(0).Vector). | ||||
| 		Cross(c.Vertex(3).Sub(c.Vertex(1).Vector)).Norm()) | ||||
| 
 | ||||
| 	// Now, compensate for the curvature of the cell surface by pretending | ||||
| 	// that the cell is shaped like a spherical cap. The ratio of the | ||||
| 	// area of a spherical cap to the area of its projected disc turns out | ||||
| 	// to be 2 / (1 + sqrt(1 - r*r)) where r is the radius of the disc. | ||||
| 	// For example, when r=0 the ratio is 1, and when r=1 the ratio is 2. | ||||
| 	// Here we set Pi*r*r == flatArea to find the equivalent disc. | ||||
| 	return flatArea * 2 / (1 + math.Sqrt(1-math.Min(1/math.Pi*flatArea, 1))) | ||||
| } | ||||
| 
 | ||||
| // AverageArea returns the average area of cells at the level of this cell. | ||||
| // This is accurate to within a factor of 1.7. | ||||
| func (c Cell) AverageArea() float64 { | ||||
| 	return AvgAreaMetric.Value(int(c.level)) | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether the intersection of this cell and the other cell is not nil. | ||||
| func (c Cell) IntersectsCell(oc Cell) bool { | ||||
| 	return c.id.Intersects(oc.id) | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether this cell contains the other cell. | ||||
| func (c Cell) ContainsCell(oc Cell) bool { | ||||
| 	return c.id.Contains(oc.id) | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the Cell. | ||||
| func (c Cell) CellUnionBound() []CellID { | ||||
| 	return c.CapBound().CellUnionBound() | ||||
| } | ||||
| 
 | ||||
| // latitude returns the latitude of the cell vertex in radians given by (i,j), | ||||
| // where i and j indicate the Hi (1) or Lo (0) corner. | ||||
| func (c Cell) latitude(i, j int) float64 { | ||||
| 	var u, v float64 | ||||
| 	switch { | ||||
| 	case i == 0 && j == 0: | ||||
| 		u = c.uv.X.Lo | ||||
| 		v = c.uv.Y.Lo | ||||
| 	case i == 0 && j == 1: | ||||
| 		u = c.uv.X.Lo | ||||
| 		v = c.uv.Y.Hi | ||||
| 	case i == 1 && j == 0: | ||||
| 		u = c.uv.X.Hi | ||||
| 		v = c.uv.Y.Lo | ||||
| 	case i == 1 && j == 1: | ||||
| 		u = c.uv.X.Hi | ||||
| 		v = c.uv.Y.Hi | ||||
| 	default: | ||||
| 		panic("i and/or j is out of bounds") | ||||
| 	} | ||||
| 	return latitude(Point{faceUVToXYZ(int(c.face), u, v)}).Radians() | ||||
| } | ||||
| 
 | ||||
| // longitude returns the longitude of the cell vertex in radians given by (i,j), | ||||
| // where i and j indicate the Hi (1) or Lo (0) corner. | ||||
| func (c Cell) longitude(i, j int) float64 { | ||||
| 	var u, v float64 | ||||
| 	switch { | ||||
| 	case i == 0 && j == 0: | ||||
| 		u = c.uv.X.Lo | ||||
| 		v = c.uv.Y.Lo | ||||
| 	case i == 0 && j == 1: | ||||
| 		u = c.uv.X.Lo | ||||
| 		v = c.uv.Y.Hi | ||||
| 	case i == 1 && j == 0: | ||||
| 		u = c.uv.X.Hi | ||||
| 		v = c.uv.Y.Lo | ||||
| 	case i == 1 && j == 1: | ||||
| 		u = c.uv.X.Hi | ||||
| 		v = c.uv.Y.Hi | ||||
| 	default: | ||||
| 		panic("i and/or j is out of bounds") | ||||
| 	} | ||||
| 	return longitude(Point{faceUVToXYZ(int(c.face), u, v)}).Radians() | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	poleMinLat = math.Asin(math.Sqrt(1.0/3)) - 0.5*dblEpsilon | ||||
| ) | ||||
| 
 | ||||
| // RectBound returns the bounding rectangle of this cell. | ||||
| func (c Cell) RectBound() Rect { | ||||
| 	if c.level > 0 { | ||||
| 		// Except for cells at level 0, the latitude and longitude extremes are | ||||
| 		// attained at the vertices.  Furthermore, the latitude range is | ||||
| 		// determined by one pair of diagonally opposite vertices and the | ||||
| 		// longitude range is determined by the other pair. | ||||
| 		// | ||||
| 		// We first determine which corner (i,j) of the cell has the largest | ||||
| 		// absolute latitude.  To maximize latitude, we want to find the point in | ||||
| 		// the cell that has the largest absolute z-coordinate and the smallest | ||||
| 		// absolute x- and y-coordinates.  To do this we look at each coordinate | ||||
| 		// (u and v), and determine whether we want to minimize or maximize that | ||||
| 		// coordinate based on the axis direction and the cell's (u,v) quadrant. | ||||
| 		u := c.uv.X.Lo + c.uv.X.Hi | ||||
| 		v := c.uv.Y.Lo + c.uv.Y.Hi | ||||
| 		var i, j int | ||||
| 		if uAxis(int(c.face)).Z == 0 { | ||||
| 			if u < 0 { | ||||
| 				i = 1 | ||||
| 			} | ||||
| 		} else if u > 0 { | ||||
| 			i = 1 | ||||
| 		} | ||||
| 		if vAxis(int(c.face)).Z == 0 { | ||||
| 			if v < 0 { | ||||
| 				j = 1 | ||||
| 			} | ||||
| 		} else if v > 0 { | ||||
| 			j = 1 | ||||
| 		} | ||||
| 		lat := r1.IntervalFromPoint(c.latitude(i, j)).AddPoint(c.latitude(1-i, 1-j)) | ||||
| 		lng := s1.EmptyInterval().AddPoint(c.longitude(i, 1-j)).AddPoint(c.longitude(1-i, j)) | ||||
| 
 | ||||
| 		// We grow the bounds slightly to make sure that the bounding rectangle | ||||
| 		// contains LatLngFromPoint(P) for any point P inside the loop L defined by the | ||||
| 		// four *normalized* vertices.  Note that normalization of a vector can | ||||
| 		// change its direction by up to 0.5 * dblEpsilon radians, and it is not | ||||
| 		// enough just to add Normalize calls to the code above because the | ||||
| 		// latitude/longitude ranges are not necessarily determined by diagonally | ||||
| 		// opposite vertex pairs after normalization. | ||||
| 		// | ||||
| 		// We would like to bound the amount by which the latitude/longitude of a | ||||
| 		// contained point P can exceed the bounds computed above.  In the case of | ||||
| 		// longitude, the normalization error can change the direction of rounding | ||||
| 		// leading to a maximum difference in longitude of 2 * dblEpsilon.  In | ||||
| 		// the case of latitude, the normalization error can shift the latitude by | ||||
| 		// up to 0.5 * dblEpsilon and the other sources of error can cause the | ||||
| 		// two latitudes to differ by up to another 1.5 * dblEpsilon, which also | ||||
| 		// leads to a maximum difference of 2 * dblEpsilon. | ||||
| 		return Rect{lat, lng}.expanded(LatLng{s1.Angle(2 * dblEpsilon), s1.Angle(2 * dblEpsilon)}).PolarClosure() | ||||
| 	} | ||||
| 
 | ||||
| 	// The 4 cells around the equator extend to +/-45 degrees latitude at the | ||||
| 	// midpoints of their top and bottom edges.  The two cells covering the | ||||
| 	// poles extend down to +/-35.26 degrees at their vertices.  The maximum | ||||
| 	// error in this calculation is 0.5 * dblEpsilon. | ||||
| 	var bound Rect | ||||
| 	switch c.face { | ||||
| 	case 0: | ||||
| 		bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-math.Pi / 4, math.Pi / 4}} | ||||
| 	case 1: | ||||
| 		bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{math.Pi / 4, 3 * math.Pi / 4}} | ||||
| 	case 2: | ||||
| 		bound = Rect{r1.Interval{poleMinLat, math.Pi / 2}, s1.FullInterval()} | ||||
| 	case 3: | ||||
| 		bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{3 * math.Pi / 4, -3 * math.Pi / 4}} | ||||
| 	case 4: | ||||
| 		bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-3 * math.Pi / 4, -math.Pi / 4}} | ||||
| 	default: | ||||
| 		bound = Rect{r1.Interval{-math.Pi / 2, -poleMinLat}, s1.FullInterval()} | ||||
| 	} | ||||
| 
 | ||||
| 	// Finally, we expand the bound to account for the error when a point P is | ||||
| 	// converted to an LatLng to test for containment. (The bound should be | ||||
| 	// large enough so that it contains the computed LatLng of any contained | ||||
| 	// point, not just the infinite-precision version.) We don't need to expand | ||||
| 	// longitude because longitude is calculated via a single call to math.Atan2, | ||||
| 	// which is guaranteed to be semi-monotonic. | ||||
| 	return bound.expanded(LatLng{s1.Angle(dblEpsilon), s1.Angle(0)}) | ||||
| } | ||||
| 
 | ||||
| // CapBound returns the bounding cap of this cell. | ||||
| func (c Cell) CapBound() Cap { | ||||
| 	// We use the cell center in (u,v)-space as the cap axis.  This vector is very close | ||||
| 	// to GetCenter() and faster to compute.  Neither one of these vectors yields the | ||||
| 	// bounding cap with minimal surface area, but they are both pretty close. | ||||
| 	cap := CapFromPoint(Point{faceUVToXYZ(int(c.face), c.uv.Center().X, c.uv.Center().Y).Normalize()}) | ||||
| 	for k := 0; k < 4; k++ { | ||||
| 		cap = cap.AddPoint(c.Vertex(k)) | ||||
| 	} | ||||
| 	return cap | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether this cell contains the given point. Note that | ||||
| // unlike Loop/Polygon, a Cell is considered to be a closed set. This means | ||||
| // that a point on a Cell's edge or vertex belong to the Cell and the relevant | ||||
| // adjacent Cells too. | ||||
| // | ||||
| // If you want every point to be contained by exactly one Cell, | ||||
| // you will need to convert the Cell to a Loop. | ||||
| func (c Cell) ContainsPoint(p Point) bool { | ||||
| 	var uv r2.Point | ||||
| 	var ok bool | ||||
| 	if uv.X, uv.Y, ok = faceXYZToUV(int(c.face), p); !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Expand the (u,v) bound to ensure that | ||||
| 	// | ||||
| 	//   CellFromPoint(p).ContainsPoint(p) | ||||
| 	// | ||||
| 	// is always true. To do this, we need to account for the error when | ||||
| 	// converting from (u,v) coordinates to (s,t) coordinates. In the | ||||
| 	// normal case the total error is at most dblEpsilon. | ||||
| 	return c.uv.ExpandedByMargin(dblEpsilon).ContainsPoint(uv) | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the Cell. | ||||
| func (c Cell) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	c.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (c Cell) encode(e *encoder) { | ||||
| 	c.id.encode(e) | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the Cell. | ||||
| func (c *Cell) Decode(r io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(r)} | ||||
| 	c.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (c *Cell) decode(d *decoder) { | ||||
| 	c.id.decode(d) | ||||
| 	*c = CellFromCellID(c.id) | ||||
| } | ||||
| 
 | ||||
| // vertexChordDist2 returns the squared chord distance from point P to the | ||||
| // given corner vertex specified by the Hi or Lo values of each. | ||||
| func (c Cell) vertexChordDist2(p Point, xHi, yHi bool) s1.ChordAngle { | ||||
| 	x := c.uv.X.Lo | ||||
| 	y := c.uv.Y.Lo | ||||
| 	if xHi { | ||||
| 		x = c.uv.X.Hi | ||||
| 	} | ||||
| 	if yHi { | ||||
| 		y = c.uv.Y.Hi | ||||
| 	} | ||||
| 
 | ||||
| 	return ChordAngleBetweenPoints(p, PointFromCoords(x, y, 1)) | ||||
| } | ||||
| 
 | ||||
| // uEdgeIsClosest reports whether a point P is closer to the interior of the specified | ||||
| // Cell edge (either the lower or upper edge of the Cell) or to the endpoints. | ||||
| func (c Cell) uEdgeIsClosest(p Point, vHi bool) bool { | ||||
| 	u0 := c.uv.X.Lo | ||||
| 	u1 := c.uv.X.Hi | ||||
| 	v := c.uv.Y.Lo | ||||
| 	if vHi { | ||||
| 		v = c.uv.Y.Hi | ||||
| 	} | ||||
| 	// These are the normals to the planes that are perpendicular to the edge | ||||
| 	// and pass through one of its two endpoints. | ||||
| 	dir0 := r3.Vector{v*v + 1, -u0 * v, -u0} | ||||
| 	dir1 := r3.Vector{v*v + 1, -u1 * v, -u1} | ||||
| 	return p.Dot(dir0) > 0 && p.Dot(dir1) < 0 | ||||
| } | ||||
| 
 | ||||
| // vEdgeIsClosest reports whether a point P is closer to the interior of the specified | ||||
| // Cell edge (either the right or left edge of the Cell) or to the endpoints. | ||||
| func (c Cell) vEdgeIsClosest(p Point, uHi bool) bool { | ||||
| 	v0 := c.uv.Y.Lo | ||||
| 	v1 := c.uv.Y.Hi | ||||
| 	u := c.uv.X.Lo | ||||
| 	if uHi { | ||||
| 		u = c.uv.X.Hi | ||||
| 	} | ||||
| 	dir0 := r3.Vector{-u * v0, u*u + 1, -v0} | ||||
| 	dir1 := r3.Vector{-u * v1, u*u + 1, -v1} | ||||
| 	return p.Dot(dir0) > 0 && p.Dot(dir1) < 0 | ||||
| } | ||||
| 
 | ||||
| // edgeDistance reports the distance from a Point P to a given Cell edge. The point | ||||
| // P is given by its dot product, and the uv edge by its normal in the | ||||
| // given coordinate value. | ||||
| func edgeDistance(ij, uv float64) s1.ChordAngle { | ||||
| 	// Let P by the target point and let R be the closest point on the given | ||||
| 	// edge AB.  The desired distance PR can be expressed as PR^2 = PQ^2 + QR^2 | ||||
| 	// where Q is the point P projected onto the plane through the great circle | ||||
| 	// through AB.  We can compute the distance PQ^2 perpendicular to the plane | ||||
| 	// from "dirIJ" (the dot product of the target point P with the edge | ||||
| 	// normal) and the squared length the edge normal (1 + uv**2). | ||||
| 	pq2 := (ij * ij) / (1 + uv*uv) | ||||
| 
 | ||||
| 	// We can compute the distance QR as (1 - OQ) where O is the sphere origin, | ||||
| 	// and we can compute OQ^2 = 1 - PQ^2 using the Pythagorean theorem. | ||||
| 	// (This calculation loses accuracy as angle POQ approaches Pi/2.) | ||||
| 	qr := 1 - math.Sqrt(1-pq2) | ||||
| 	return s1.ChordAngleFromSquaredLength(pq2 + qr*qr) | ||||
| } | ||||
| 
 | ||||
| // distanceInternal reports the distance from the given point to the interior of | ||||
| // the cell if toInterior is true or to the boundary of the cell otherwise. | ||||
| func (c Cell) distanceInternal(targetXYZ Point, toInterior bool) s1.ChordAngle { | ||||
| 	// All calculations are done in the (u,v,w) coordinates of this cell's face. | ||||
| 	target := faceXYZtoUVW(int(c.face), targetXYZ) | ||||
| 
 | ||||
| 	// Compute dot products with all four upward or rightward-facing edge | ||||
| 	// normals. dirIJ is the dot product for the edge corresponding to axis | ||||
| 	// I, endpoint J. For example, dir01 is the right edge of the Cell | ||||
| 	// (corresponding to the upper endpoint of the u-axis). | ||||
| 	dir00 := target.X - target.Z*c.uv.X.Lo | ||||
| 	dir01 := target.X - target.Z*c.uv.X.Hi | ||||
| 	dir10 := target.Y - target.Z*c.uv.Y.Lo | ||||
| 	dir11 := target.Y - target.Z*c.uv.Y.Hi | ||||
| 	inside := true | ||||
| 	if dir00 < 0 { | ||||
| 		inside = false // Target is to the left of the cell | ||||
| 		if c.vEdgeIsClosest(target, false) { | ||||
| 			return edgeDistance(-dir00, c.uv.X.Lo) | ||||
| 		} | ||||
| 	} | ||||
| 	if dir01 > 0 { | ||||
| 		inside = false // Target is to the right of the cell | ||||
| 		if c.vEdgeIsClosest(target, true) { | ||||
| 			return edgeDistance(dir01, c.uv.X.Hi) | ||||
| 		} | ||||
| 	} | ||||
| 	if dir10 < 0 { | ||||
| 		inside = false // Target is below the cell | ||||
| 		if c.uEdgeIsClosest(target, false) { | ||||
| 			return edgeDistance(-dir10, c.uv.Y.Lo) | ||||
| 		} | ||||
| 	} | ||||
| 	if dir11 > 0 { | ||||
| 		inside = false // Target is above the cell | ||||
| 		if c.uEdgeIsClosest(target, true) { | ||||
| 			return edgeDistance(dir11, c.uv.Y.Hi) | ||||
| 		} | ||||
| 	} | ||||
| 	if inside { | ||||
| 		if toInterior { | ||||
| 			return s1.ChordAngle(0) | ||||
| 		} | ||||
| 		// Although you might think of Cells as rectangles, they are actually | ||||
| 		// arbitrary quadrilaterals after they are projected onto the sphere. | ||||
| 		// Therefore the simplest approach is just to find the minimum distance to | ||||
| 		// any of the four edges. | ||||
| 		return minChordAngle(edgeDistance(-dir00, c.uv.X.Lo), | ||||
| 			edgeDistance(dir01, c.uv.X.Hi), | ||||
| 			edgeDistance(-dir10, c.uv.Y.Lo), | ||||
| 			edgeDistance(dir11, c.uv.Y.Hi)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the closest point is one of the four cell vertices. Note that | ||||
| 	// it is *not* trivial to narrow down the candidates based on the edge sign | ||||
| 	// tests above, because (1) the edges don't meet at right angles and (2) | ||||
| 	// there are points on the far side of the sphere that are both above *and* | ||||
| 	// below the cell, etc. | ||||
| 	return minChordAngle(c.vertexChordDist2(target, false, false), | ||||
| 		c.vertexChordDist2(target, true, false), | ||||
| 		c.vertexChordDist2(target, false, true), | ||||
| 		c.vertexChordDist2(target, true, true)) | ||||
| } | ||||
| 
 | ||||
| // Distance reports the distance from the cell to the given point. Returns zero if | ||||
| // the point is inside the cell. | ||||
| func (c Cell) Distance(target Point) s1.ChordAngle { | ||||
| 	return c.distanceInternal(target, true) | ||||
| } | ||||
| 
 | ||||
| // MaxDistance reports the maximum distance from the cell (including its interior) to the | ||||
| // given point. | ||||
| func (c Cell) MaxDistance(target Point) s1.ChordAngle { | ||||
| 	// First check the 4 cell vertices.  If all are within the hemisphere | ||||
| 	// centered around target, the max distance will be to one of these vertices. | ||||
| 	targetUVW := faceXYZtoUVW(int(c.face), target) | ||||
| 	maxDist := maxChordAngle(c.vertexChordDist2(targetUVW, false, false), | ||||
| 		c.vertexChordDist2(targetUVW, true, false), | ||||
| 		c.vertexChordDist2(targetUVW, false, true), | ||||
| 		c.vertexChordDist2(targetUVW, true, true)) | ||||
| 
 | ||||
| 	if maxDist <= s1.RightChordAngle { | ||||
| 		return maxDist | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, find the minimum distance dMin to the antipodal point and the | ||||
| 	// maximum distance will be pi - dMin. | ||||
| 	return s1.StraightChordAngle - c.BoundaryDistance(Point{target.Mul(-1)}) | ||||
| } | ||||
| 
 | ||||
| // BoundaryDistance reports the distance from the cell boundary to the given point. | ||||
| func (c Cell) BoundaryDistance(target Point) s1.ChordAngle { | ||||
| 	return c.distanceInternal(target, false) | ||||
| } | ||||
| 
 | ||||
| // DistanceToEdge returns the minimum distance from the cell to the given edge AB. Returns | ||||
| // zero if the edge intersects the cell interior. | ||||
| func (c Cell) DistanceToEdge(a, b Point) s1.ChordAngle { | ||||
| 	// Possible optimizations: | ||||
| 	//  - Currently the (cell vertex, edge endpoint) distances are computed | ||||
| 	//    twice each, and the length of AB is computed 4 times. | ||||
| 	//  - To fix this, refactor GetDistance(target) so that it skips calculating | ||||
| 	//    the distance to each cell vertex. Instead, compute the cell vertices | ||||
| 	//    and distances in this function, and add a low-level UpdateMinDistance | ||||
| 	//    that allows the XA, XB, and AB distances to be passed in. | ||||
| 	//  - It might also be more efficient to do all calculations in UVW-space, | ||||
| 	//    since this would involve transforming 2 points rather than 4. | ||||
| 
 | ||||
| 	// First, check the minimum distance to the edge endpoints A and B. | ||||
| 	// (This also detects whether either endpoint is inside the cell.) | ||||
| 	minDist := minChordAngle(c.Distance(a), c.Distance(b)) | ||||
| 	if minDist == 0 { | ||||
| 		return minDist | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, check whether the edge crosses the cell boundary. | ||||
| 	crosser := NewChainEdgeCrosser(a, b, c.Vertex(3)) | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		if crosser.ChainCrossingSign(c.Vertex(i)) != DoNotCross { | ||||
| 			return 0 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Finally, check whether the minimum distance occurs between a cell vertex | ||||
| 	// and the interior of the edge AB. (Some of this work is redundant, since | ||||
| 	// it also checks the distance to the endpoints A and B again.) | ||||
| 	// | ||||
| 	// Note that we don't need to check the distance from the interior of AB to | ||||
| 	// the interior of a cell edge, because the only way that this distance can | ||||
| 	// be minimal is if the two edges cross (already checked above). | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		minDist, _ = UpdateMinDistance(c.Vertex(i), a, b, minDist) | ||||
| 	} | ||||
| 	return minDist | ||||
| } | ||||
| 
 | ||||
| // MaxDistanceToEdge returns the maximum distance from the cell (including its interior) | ||||
| // to the given edge AB. | ||||
| func (c Cell) MaxDistanceToEdge(a, b Point) s1.ChordAngle { | ||||
| 	// If the maximum distance from both endpoints to the cell is less than π/2 | ||||
| 	// then the maximum distance from the edge to the cell is the maximum of the | ||||
| 	// two endpoint distances. | ||||
| 	maxDist := maxChordAngle(c.MaxDistance(a), c.MaxDistance(b)) | ||||
| 	if maxDist <= s1.RightChordAngle { | ||||
| 		return maxDist | ||||
| 	} | ||||
| 
 | ||||
| 	return s1.StraightChordAngle - c.DistanceToEdge(Point{a.Mul(-1)}, Point{b.Mul(-1)}) | ||||
| } | ||||
| 
 | ||||
| // DistanceToCell returns the minimum distance from this cell to the given cell. | ||||
| // It returns zero if one cell contains the other. | ||||
| func (c Cell) DistanceToCell(target Cell) s1.ChordAngle { | ||||
| 	// If the cells intersect, the distance is zero.  We use the (u,v) ranges | ||||
| 	// rather than CellID intersects so that cells that share a partial edge or | ||||
| 	// corner are considered to intersect. | ||||
| 	if c.face == target.face && c.uv.Intersects(target.uv) { | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the minimum distance always occurs between a vertex of one | ||||
| 	// cell and an edge of the other cell (including the edge endpoints).  This | ||||
| 	// represents a total of 32 possible (vertex, edge) pairs. | ||||
| 	// | ||||
| 	// TODO(roberts): This could be optimized to be at least 5x faster by pruning | ||||
| 	// the set of possible closest vertex/edge pairs using the faces and (u,v) | ||||
| 	// ranges of both cells. | ||||
| 	var va, vb [4]Point | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		va[i] = c.Vertex(i) | ||||
| 		vb[i] = target.Vertex(i) | ||||
| 	} | ||||
| 	minDist := s1.InfChordAngle() | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		for j := 0; j < 4; j++ { | ||||
| 			minDist, _ = UpdateMinDistance(va[i], vb[j], vb[(j+1)&3], minDist) | ||||
| 			minDist, _ = UpdateMinDistance(vb[i], va[j], va[(j+1)&3], minDist) | ||||
| 		} | ||||
| 	} | ||||
| 	return minDist | ||||
| } | ||||
| 
 | ||||
| // MaxDistanceToCell returns the maximum distance from the cell (including its | ||||
| // interior) to the given target cell. | ||||
| func (c Cell) MaxDistanceToCell(target Cell) s1.ChordAngle { | ||||
| 	// Need to check the antipodal target for intersection with the cell. If it | ||||
| 	// intersects, the distance is the straight ChordAngle. | ||||
| 	// antipodalUV is the transpose of the original UV, interpreted within the opposite face. | ||||
| 	antipodalUV := r2.Rect{target.uv.Y, target.uv.X} | ||||
| 	if int(c.face) == oppositeFace(int(target.face)) && c.uv.Intersects(antipodalUV) { | ||||
| 		return s1.StraightChordAngle | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the maximum distance always occurs between a vertex of one | ||||
| 	// cell and an edge of the other cell (including the edge endpoints).  This | ||||
| 	// represents a total of 32 possible (vertex, edge) pairs. | ||||
| 	// | ||||
| 	// TODO(roberts): When the maximum distance is at most π/2, the maximum is | ||||
| 	// always attained between a pair of vertices, and this could be made much | ||||
| 	// faster by testing each vertex pair once rather than the current 4 times. | ||||
| 	var va, vb [4]Point | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		va[i] = c.Vertex(i) | ||||
| 		vb[i] = target.Vertex(i) | ||||
| 	} | ||||
| 	maxDist := s1.NegativeChordAngle | ||||
| 	for i := 0; i < 4; i++ { | ||||
| 		for j := 0; j < 4; j++ { | ||||
| 			maxDist, _ = UpdateMaxDistance(va[i], vb[j], vb[(j+1)&3], maxDist) | ||||
| 			maxDist, _ = UpdateMaxDistance(vb[i], va[j], va[(j+1)&3], maxDist) | ||||
| 		} | ||||
| 	} | ||||
| 	return maxDist | ||||
| } | ||||
							
								
								
									
										498
									
								
								vendor/github.com/golang/geo/s2/cell_index.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										498
									
								
								vendor/github.com/golang/geo/s2/cell_index.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,498 +0,0 @@ | |||
| // Copyright 2020 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// A special label indicating that the ContentsIterator done is true. | ||||
| 	cellIndexDoneContents = -1 | ||||
| ) | ||||
| 
 | ||||
| // cellIndexNode represents a node in the CellIndex. Cells are organized in a | ||||
| // tree such that the ancestors of a given node contain that node. | ||||
| type cellIndexNode struct { | ||||
| 	cellID CellID | ||||
| 	label  int32 | ||||
| 	parent int32 | ||||
| } | ||||
| 
 | ||||
| // newCellIndexNode returns a node with the appropriate default values. | ||||
| func newCellIndexNode() cellIndexNode { | ||||
| 	return cellIndexNode{ | ||||
| 		cellID: 0, | ||||
| 		label:  cellIndexDoneContents, | ||||
| 		parent: -1, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // A rangeNode represents a range of leaf CellIDs. The range starts at | ||||
| // startID (a leaf cell) and ends at the startID field of the next | ||||
| // rangeNode. contents points to the node of the CellIndex cellTree | ||||
| // representing the cells that overlap this range. | ||||
| type rangeNode struct { | ||||
| 	startID  CellID // First leaf cell contained by this range. | ||||
| 	contents int32  // Contents of this node (an index within the cell tree). | ||||
| } | ||||
| 
 | ||||
| // CellIndexIterator is an iterator that visits the entire set of indexed | ||||
| // (CellID, label) pairs in an unspecified order. | ||||
| type CellIndexIterator struct { | ||||
| 	// TODO(roberts): Implement | ||||
| } | ||||
| 
 | ||||
| // NewCellIndexIterator creates an iterator for the given CellIndex. | ||||
| func NewCellIndexIterator(index *CellIndex) *CellIndexIterator { | ||||
| 	return &CellIndexIterator{} | ||||
| } | ||||
| 
 | ||||
| // CellIndexRangeIterator is an iterator that seeks and iterates over a set of | ||||
| // non-overlapping leaf cell ranges that cover the entire sphere. The indexed | ||||
| // (CellID, label) pairs that intersect the current leaf cell range can be | ||||
| // visited using CellIndexContentsIterator (see below). | ||||
| type CellIndexRangeIterator struct { | ||||
| 	rangeNodes []rangeNode | ||||
| 	pos        int | ||||
| 	nonEmpty   bool | ||||
| } | ||||
| 
 | ||||
| // NewCellIndexRangeIterator creates an iterator for the given CellIndex. | ||||
| // The iterator is initially *unpositioned*; you must call a positioning method | ||||
| // such as Begin() or Seek() before accessing its contents. | ||||
| func NewCellIndexRangeIterator(index *CellIndex) *CellIndexRangeIterator { | ||||
| 	return &CellIndexRangeIterator{ | ||||
| 		rangeNodes: index.rangeNodes, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewCellIndexNonEmptyRangeIterator creates an iterator for the given CellIndex. | ||||
| // The iterator is initially *unpositioned*; you must call a positioning method such as | ||||
| // Begin() or Seek() before accessing its contents. | ||||
| func NewCellIndexNonEmptyRangeIterator(index *CellIndex) *CellIndexRangeIterator { | ||||
| 	return &CellIndexRangeIterator{ | ||||
| 		rangeNodes: index.rangeNodes, | ||||
| 		nonEmpty:   true, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // StartID reports the CellID of the start of the current range of leaf CellIDs. | ||||
| // | ||||
| // If done is true, this returns the last possible CellID. This property means | ||||
| // that most loops do not need to test done explicitly. | ||||
| func (c *CellIndexRangeIterator) StartID() CellID { | ||||
| 	return c.rangeNodes[c.pos].startID | ||||
| } | ||||
| 
 | ||||
| // LimitID reports the non-inclusive end of the current range of leaf CellIDs. | ||||
| // | ||||
| // This assumes the iterator is not done. | ||||
| func (c *CellIndexRangeIterator) LimitID() CellID { | ||||
| 	return c.rangeNodes[c.pos+1].startID | ||||
| } | ||||
| 
 | ||||
| // IsEmpty reports if no (CellID, label) pairs intersect this range. | ||||
| // Also returns true if done() is true. | ||||
| func (c *CellIndexRangeIterator) IsEmpty() bool { | ||||
| 	return c.rangeNodes[c.pos].contents == cellIndexDoneContents | ||||
| } | ||||
| 
 | ||||
| // Begin positions the iterator at the first range of leaf cells (if any). | ||||
| func (c *CellIndexRangeIterator) Begin() { | ||||
| 	c.pos = 0 | ||||
| 	for c.nonEmpty && c.IsEmpty() && !c.Done() { | ||||
| 		c.pos++ | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Prev positions the iterator at the previous entry and reports whether it was not | ||||
| // already positioned at the beginning. | ||||
| func (c *CellIndexRangeIterator) Prev() bool { | ||||
| 	if c.nonEmpty { | ||||
| 		return c.nonEmptyPrev() | ||||
| 	} | ||||
| 	return c.prev() | ||||
| } | ||||
| 
 | ||||
| // prev is used to position the iterator at the previous entry without checking | ||||
| // if nonEmpty is true to prevent unwanted recursion. | ||||
| func (c *CellIndexRangeIterator) prev() bool { | ||||
| 	if c.pos == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	c.pos-- | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Prev positions the iterator at the previous entry, and reports whether it was | ||||
| // already positioned at the beginning. | ||||
| func (c *CellIndexRangeIterator) nonEmptyPrev() bool { | ||||
| 	for c.prev() { | ||||
| 		if !c.IsEmpty() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Return the iterator to its original position. | ||||
| 	if c.IsEmpty() && !c.Done() { | ||||
| 		c.Next() | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Next advances the iterator to the next range of leaf cells. | ||||
| // | ||||
| // This assumes the iterator is not done. | ||||
| func (c *CellIndexRangeIterator) Next() { | ||||
| 	c.pos++ | ||||
| 	for c.nonEmpty && c.IsEmpty() && !c.Done() { | ||||
| 		c.pos++ | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Advance reports if advancing would leave it positioned on a valid range. If | ||||
| // the value would not be valid, the positioning is not changed. | ||||
| func (c *CellIndexRangeIterator) Advance(n int) bool { | ||||
| 	// Note that the last element of rangeNodes is a sentinel value. | ||||
| 	if n >= len(c.rangeNodes)-1-c.pos { | ||||
| 		return false | ||||
| 	} | ||||
| 	c.pos += n | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Finish positions the iterator so that done is true. | ||||
| func (c *CellIndexRangeIterator) Finish() { | ||||
| 	// Note that the last element of rangeNodes is a sentinel value. | ||||
| 	c.pos = len(c.rangeNodes) - 1 | ||||
| } | ||||
| 
 | ||||
| // Done reports if the iterator is positioned beyond the last valid range. | ||||
| func (c *CellIndexRangeIterator) Done() bool { | ||||
| 	return c.pos >= len(c.rangeNodes)-1 | ||||
| } | ||||
| 
 | ||||
| // Seek positions the iterator at the first range with startID >= target. | ||||
| // Such an entry always exists as long as "target" is a valid leaf cell. | ||||
| // | ||||
| // Note that it is valid to access startID even when done is true. | ||||
| func (c *CellIndexRangeIterator) Seek(target CellID) { | ||||
| 	c.pos = sort.Search(len(c.rangeNodes), func(i int) bool { | ||||
| 		return c.rangeNodes[i].startID > target | ||||
| 	}) - 1 | ||||
| 
 | ||||
| 	// Ensure we don't go beyond the beginning. | ||||
| 	if c.pos < 0 { | ||||
| 		c.pos = 0 | ||||
| 	} | ||||
| 
 | ||||
| 	// Nonempty needs to find the next non-empty entry. | ||||
| 	for c.nonEmpty && c.IsEmpty() && !c.Done() { | ||||
| 		// c.Next() | ||||
| 		c.pos++ | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CellIndexContentsIterator is an iterator that visits the (CellID, label) pairs | ||||
| // that cover a set of leaf cell ranges (see CellIndexRangeIterator). Note that | ||||
| // when multiple leaf cell ranges are visited, this iterator only guarantees that | ||||
| // each result will be reported at least once, i.e. duplicate values may be | ||||
| // suppressed. If you want duplicate values to be reported again, be sure to call | ||||
| // Clear first. | ||||
| // | ||||
| // In particular, the implementation guarantees that when multiple leaf | ||||
| // cell ranges are visited in monotonically increasing order, then each | ||||
| // (CellID, label) pair is reported exactly once. | ||||
| type CellIndexContentsIterator struct { | ||||
| 	// The maximum index within the cellTree slice visited during the | ||||
| 	// previous call to StartUnion. This is used to eliminate duplicate | ||||
| 	// values when StartUnion is called multiple times. | ||||
| 	nodeCutoff int32 | ||||
| 
 | ||||
| 	// The maximum index within the cellTree visited during the | ||||
| 	// current call to StartUnion. This is used to update nodeCutoff. | ||||
| 	nextNodeCutoff int32 | ||||
| 
 | ||||
| 	// The value of startID from the previous call to StartUnion. | ||||
| 	// This is used to check whether these values are monotonically | ||||
| 	// increasing. | ||||
| 	prevStartID CellID | ||||
| 
 | ||||
| 	// The cell tree from CellIndex | ||||
| 	cellTree []cellIndexNode | ||||
| 
 | ||||
| 	// A copy of the current node in the cell tree. | ||||
| 	node cellIndexNode | ||||
| } | ||||
| 
 | ||||
| // NewCellIndexContentsIterator returns a new contents iterator. | ||||
| // | ||||
| // Note that the iterator needs to be positioned using StartUnion before | ||||
| // it can be safely used. | ||||
| func NewCellIndexContentsIterator(index *CellIndex) *CellIndexContentsIterator { | ||||
| 	it := &CellIndexContentsIterator{ | ||||
| 		cellTree:       index.cellTree, | ||||
| 		prevStartID:    0, | ||||
| 		nodeCutoff:     -1, | ||||
| 		nextNodeCutoff: -1, | ||||
| 		node:           cellIndexNode{label: cellIndexDoneContents}, | ||||
| 	} | ||||
| 	return it | ||||
| } | ||||
| 
 | ||||
| // Clear clears all state with respect to which range(s) have been visited. | ||||
| func (c *CellIndexContentsIterator) Clear() { | ||||
| 	c.prevStartID = 0 | ||||
| 	c.nodeCutoff = -1 | ||||
| 	c.nextNodeCutoff = -1 | ||||
| 	c.node.label = cellIndexDoneContents | ||||
| } | ||||
| 
 | ||||
| // CellID returns the current CellID. | ||||
| func (c *CellIndexContentsIterator) CellID() CellID { | ||||
| 	return c.node.cellID | ||||
| } | ||||
| 
 | ||||
| // Label returns the current Label. | ||||
| func (c *CellIndexContentsIterator) Label() int32 { | ||||
| 	return c.node.label | ||||
| } | ||||
| 
 | ||||
| // Next advances the iterator to the next (CellID, label) pair covered by the | ||||
| // current leaf cell range. | ||||
| // | ||||
| // This requires the iterator to not be done. | ||||
| func (c *CellIndexContentsIterator) Next() { | ||||
| 	if c.node.parent <= c.nodeCutoff { | ||||
| 		// We have already processed this node and its ancestors. | ||||
| 		c.nodeCutoff = c.nextNodeCutoff | ||||
| 		c.node.label = cellIndexDoneContents | ||||
| 	} else { | ||||
| 		c.node = c.cellTree[c.node.parent] | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Done reports if all (CellID, label) pairs have been visited. | ||||
| func (c *CellIndexContentsIterator) Done() bool { | ||||
| 	return c.node.label == cellIndexDoneContents | ||||
| } | ||||
| 
 | ||||
| // StartUnion positions the ContentsIterator at the first (cell_id, label) pair | ||||
| // that covers the given leaf cell range. Note that when multiple leaf cell | ||||
| // ranges are visited using the same ContentsIterator, duplicate values | ||||
| // may be suppressed. If you don't want this behavior, call Reset() first. | ||||
| func (c *CellIndexContentsIterator) StartUnion(r *CellIndexRangeIterator) { | ||||
| 	if r.StartID() < c.prevStartID { | ||||
| 		c.nodeCutoff = -1 // Can't automatically eliminate duplicates. | ||||
| 	} | ||||
| 	c.prevStartID = r.StartID() | ||||
| 
 | ||||
| 	contents := r.rangeNodes[r.pos].contents | ||||
| 	if contents <= c.nodeCutoff { | ||||
| 		c.node.label = cellIndexDoneContents | ||||
| 	} else { | ||||
| 		c.node = c.cellTree[contents] | ||||
| 	} | ||||
| 
 | ||||
| 	// When visiting ancestors, we can stop as soon as the node index is smaller | ||||
| 	// than any previously visited node index. Because indexes are assigned | ||||
| 	// using a preorder traversal, such nodes are guaranteed to have already | ||||
| 	// been reported. | ||||
| 	c.nextNodeCutoff = contents | ||||
| } | ||||
| 
 | ||||
| // CellIndex stores a collection of (CellID, label) pairs. | ||||
| // | ||||
| // The CellIDs may be overlapping or contain duplicate values. For example, a | ||||
| // CellIndex could store a collection of CellUnions, where each CellUnion | ||||
| // gets its own non-negative int32 label. | ||||
| // | ||||
| // Similar to ShapeIndex and PointIndex which map each stored element to an | ||||
| // identifier, CellIndex stores a label that is typically used to map the | ||||
| // results of queries back to client's specific data. | ||||
| // | ||||
| // The zero value for a CellIndex is sufficient when constructing a CellIndex. | ||||
| // | ||||
| // To build a CellIndex where each Cell has a distinct label, call Add for each | ||||
| // (CellID, label) pair, and then Build the index. For example: | ||||
| // | ||||
| //	// contents is a mapping of an identifier in my system (restaurantID, | ||||
| //	// vehicleID, etc) to a CellID | ||||
| //	var contents = map[int32]CellID{...} | ||||
| // | ||||
| //	for key, val := range contents { | ||||
| //		index.Add(val, key) | ||||
| //	} | ||||
| // | ||||
| //	index.Build() | ||||
| // | ||||
| // There is also a helper method that adds all elements of CellUnion with the | ||||
| // same label: | ||||
| // | ||||
| //     index.AddCellUnion(cellUnion, label) | ||||
| // | ||||
| // Note that the index is not dynamic; the contents of the index cannot be | ||||
| // changed once it has been built. Adding more after calling Build results in | ||||
| // undefined behavior of the index. | ||||
| // | ||||
| // There are several options for retrieving data from the index. The simplest | ||||
| // is to use a built-in method such as IntersectingLabels (which returns | ||||
| // the labels of all cells that intersect a given target CellUnion): | ||||
| // | ||||
| //   labels := index.IntersectingLabels(targetUnion); | ||||
| // | ||||
| // Alternatively, you can use a ClosestCellQuery which computes the cell(s) | ||||
| // that are closest to a given target geometry. | ||||
| // | ||||
| // For example, here is how to find all cells that are closer than | ||||
| // distanceLimit to a given target point: | ||||
| // | ||||
| //	query := NewClosestCellQuery(cellIndex, opts) | ||||
| //	target := NewMinDistanceToPointTarget(targetPoint); | ||||
| //	for result := range query.FindCells(target) { | ||||
| //		// result.Distance() is the distance to the target. | ||||
| //		// result.CellID() is the indexed CellID. | ||||
| //		// result.Label() is the label associated with the CellID. | ||||
| //		DoSomething(targetPoint, result); | ||||
| //	} | ||||
| // | ||||
| // Internally, the index consists of a set of non-overlapping leaf cell ranges | ||||
| // that subdivide the sphere and such that each range intersects a particular | ||||
| // set of (cellID, label) pairs. | ||||
| // | ||||
| // Most clients should use either the methods such as VisitIntersectingCells | ||||
| // and IntersectingLabels, or a helper such as ClosestCellQuery. | ||||
| type CellIndex struct { | ||||
| 	// A tree of (cellID, label) pairs such that if X is an ancestor of Y, then | ||||
| 	// X.cellID contains Y.cellID. The contents of a given range of leaf | ||||
| 	// cells can be represented by pointing to a node of this tree. | ||||
| 	cellTree []cellIndexNode | ||||
| 
 | ||||
| 	// The last element of rangeNodes is a sentinel value, which is necessary | ||||
| 	// in order to represent the range covered by the previous element. | ||||
| 	rangeNodes []rangeNode | ||||
| } | ||||
| 
 | ||||
| // Add adds the given CellID and Label to the index. | ||||
| func (c *CellIndex) Add(id CellID, label int32) { | ||||
| 	if label < 0 { | ||||
| 		panic("labels must be non-negative") | ||||
| 	} | ||||
| 	c.cellTree = append(c.cellTree, cellIndexNode{cellID: id, label: label, parent: -1}) | ||||
| } | ||||
| 
 | ||||
| // AddCellUnion adds all of the elements of the given CellUnion to the index with the same label. | ||||
| func (c *CellIndex) AddCellUnion(cu CellUnion, label int32) { | ||||
| 	if label < 0 { | ||||
| 		panic("labels must be non-negative") | ||||
| 	} | ||||
| 	for _, cell := range cu { | ||||
| 		c.Add(cell, label) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Build builds the index for use. This method should only be called once. | ||||
| func (c *CellIndex) Build() { | ||||
| 	// To build the cell tree and leaf cell ranges, we maintain a stack of | ||||
| 	// (CellID, label) pairs that contain the current leaf cell. This struct | ||||
| 	// represents an instruction to push or pop a (cellID, label) pair. | ||||
| 	// | ||||
| 	// If label >= 0, the (cellID, label) pair is pushed on the stack. | ||||
| 	// If CellID == SentinelCellID, a pair is popped from the stack. | ||||
| 	// Otherwise the stack is unchanged but a rangeNode is still emitted. | ||||
| 
 | ||||
| 	// delta represents an entry in a stack of (CellID, label) pairs used in the | ||||
| 	// construction of the CellIndex structure. | ||||
| 	type delta struct { | ||||
| 		startID CellID | ||||
| 		cellID  CellID | ||||
| 		label   int32 | ||||
| 	} | ||||
| 
 | ||||
| 	deltas := make([]delta, 0, 2*len(c.cellTree)+2) | ||||
| 
 | ||||
| 	// Create two deltas for each (cellID, label) pair: one to add the pair to | ||||
| 	// the stack (at the start of its leaf cell range), and one to remove it from | ||||
| 	// the stack (at the end of its leaf cell range). | ||||
| 	for _, node := range c.cellTree { | ||||
| 		deltas = append(deltas, delta{ | ||||
| 			startID: node.cellID.RangeMin(), | ||||
| 			cellID:  node.cellID, | ||||
| 			label:   node.label, | ||||
| 		}) | ||||
| 		deltas = append(deltas, delta{ | ||||
| 			startID: node.cellID.RangeMax().Next(), | ||||
| 			cellID:  SentinelCellID, | ||||
| 			label:   -1, | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	// We also create two special deltas to ensure that a RangeNode is emitted at | ||||
| 	// the beginning and end of the CellID range. | ||||
| 	deltas = append(deltas, delta{ | ||||
| 		startID: CellIDFromFace(0).ChildBeginAtLevel(maxLevel), | ||||
| 		cellID:  CellID(0), | ||||
| 		label:   -1, | ||||
| 	}) | ||||
| 	deltas = append(deltas, delta{ | ||||
| 		startID: CellIDFromFace(5).ChildEndAtLevel(maxLevel), | ||||
| 		cellID:  CellID(0), | ||||
| 		label:   -1, | ||||
| 	}) | ||||
| 
 | ||||
| 	sort.Slice(deltas, func(i, j int) bool { | ||||
| 		// deltas are sorted first by startID, then in reverse order by cellID, | ||||
| 		// and then by label. This is necessary to ensure that (1) larger cells | ||||
| 		// are pushed on the stack before smaller cells, and (2) cells are popped | ||||
| 		// off the stack before any new cells are added. | ||||
| 
 | ||||
| 		if si, sj := deltas[i].startID, deltas[j].startID; si != sj { | ||||
| 			return si < sj | ||||
| 		} | ||||
| 		if si, sj := deltas[i].cellID, deltas[j].cellID; si != sj { | ||||
| 			return si > sj | ||||
| 		} | ||||
| 		return deltas[i].label < deltas[j].label | ||||
| 	}) | ||||
| 
 | ||||
| 	// Now walk through the deltas to build the leaf cell ranges and cell tree | ||||
| 	// (which is essentially a permanent form of the "stack" described above). | ||||
| 	c.cellTree = nil | ||||
| 	c.rangeNodes = nil | ||||
| 	contents := int32(-1) | ||||
| 	for i := 0; i < len(deltas); { | ||||
| 		startID := deltas[i].startID | ||||
| 		// Process all the deltas associated with the current startID. | ||||
| 		for ; i < len(deltas) && deltas[i].startID == startID; i++ { | ||||
| 			if deltas[i].label >= 0 { | ||||
| 				c.cellTree = append(c.cellTree, cellIndexNode{ | ||||
| 					cellID: deltas[i].cellID, | ||||
| 					label:  deltas[i].label, | ||||
| 					parent: contents}) | ||||
| 				contents = int32(len(c.cellTree) - 1) | ||||
| 			} else if deltas[i].cellID == SentinelCellID { | ||||
| 				contents = c.cellTree[contents].parent | ||||
| 			} | ||||
| 		} | ||||
| 		c.rangeNodes = append(c.rangeNodes, rangeNode{startID, contents}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Differences from C++ | ||||
| // IntersectingLabels | ||||
| // VisitIntersectingCells | ||||
| // CellIndexIterator | ||||
							
								
								
									
										944
									
								
								vendor/github.com/golang/geo/s2/cellid.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										944
									
								
								vendor/github.com/golang/geo/s2/cellid.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,944 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r2" | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // CellID uniquely identifies a cell in the S2 cell decomposition. | ||||
| // The most significant 3 bits encode the face number (0-5). The | ||||
| // remaining 61 bits encode the position of the center of this cell | ||||
| // along the Hilbert curve on that face. The zero value and the value | ||||
| // (1<<64)-1 are invalid cell IDs. The first compares less than any | ||||
| // valid cell ID, the second as greater than any valid cell ID. | ||||
| // | ||||
| // Sequentially increasing cell IDs follow a continuous space-filling curve | ||||
| // over the entire sphere. They have the following properties: | ||||
| // | ||||
| //  - The ID of a cell at level k consists of a 3-bit face number followed | ||||
| //    by k bit pairs that recursively select one of the four children of | ||||
| //    each cell. The next bit is always 1, and all other bits are 0. | ||||
| //    Therefore, the level of a cell is determined by the position of its | ||||
| //    lowest-numbered bit that is turned on (for a cell at level k, this | ||||
| //    position is 2 * (maxLevel - k)). | ||||
| // | ||||
| //  - The ID of a parent cell is at the midpoint of the range of IDs spanned | ||||
| //    by its children (or by its descendants at any level). | ||||
| // | ||||
| // Leaf cells are often used to represent points on the unit sphere, and | ||||
| // this type provides methods for converting directly between these two | ||||
| // representations. For cells that represent 2D regions rather than | ||||
| // discrete point, it is better to use Cells. | ||||
| type CellID uint64 | ||||
| 
 | ||||
| // SentinelCellID is an invalid cell ID guaranteed to be larger than any | ||||
| // valid cell ID. It is used primarily by ShapeIndex. The value is also used | ||||
| // by some S2 types when encoding data. | ||||
| // Note that the sentinel's RangeMin == RangeMax == itself. | ||||
| const SentinelCellID = CellID(^uint64(0)) | ||||
| 
 | ||||
| // sortCellIDs sorts the slice of CellIDs in place. | ||||
| func sortCellIDs(ci []CellID) { | ||||
| 	sort.Sort(cellIDs(ci)) | ||||
| } | ||||
| 
 | ||||
| // cellIDs implements the Sort interface for slices of CellIDs. | ||||
| type cellIDs []CellID | ||||
| 
 | ||||
| func (c cellIDs) Len() int           { return len(c) } | ||||
| func (c cellIDs) Swap(i, j int)      { c[i], c[j] = c[j], c[i] } | ||||
| func (c cellIDs) Less(i, j int) bool { return c[i] < c[j] } | ||||
| 
 | ||||
| // TODO(dsymonds): Some of these constants should probably be exported. | ||||
| const ( | ||||
| 	faceBits = 3 | ||||
| 	numFaces = 6 | ||||
| 
 | ||||
| 	// This is the number of levels needed to specify a leaf cell. | ||||
| 	maxLevel = 30 | ||||
| 
 | ||||
| 	// The extra position bit (61 rather than 60) lets us encode each cell as its | ||||
| 	// Hilbert curve position at the cell center (which is halfway along the | ||||
| 	// portion of the Hilbert curve that fills that cell). | ||||
| 	posBits = 2*maxLevel + 1 | ||||
| 
 | ||||
| 	// The maximum index of a valid leaf cell plus one. The range of valid leaf | ||||
| 	// cell indices is [0..maxSize-1]. | ||||
| 	maxSize = 1 << maxLevel | ||||
| 
 | ||||
| 	wrapOffset = uint64(numFaces) << posBits | ||||
| ) | ||||
| 
 | ||||
| // CellIDFromFacePosLevel returns a cell given its face in the range | ||||
| // [0,5], the 61-bit Hilbert curve position pos within that face, and | ||||
| // the level in the range [0,maxLevel]. The position in the cell ID | ||||
| // will be truncated to correspond to the Hilbert curve position at | ||||
| // the center of the returned cell. | ||||
| func CellIDFromFacePosLevel(face int, pos uint64, level int) CellID { | ||||
| 	return CellID(uint64(face)<<posBits + pos | 1).Parent(level) | ||||
| } | ||||
| 
 | ||||
| // CellIDFromFace returns the cell corresponding to a given S2 cube face. | ||||
| func CellIDFromFace(face int) CellID { | ||||
| 	return CellID((uint64(face) << posBits) + lsbForLevel(0)) | ||||
| } | ||||
| 
 | ||||
| // CellIDFromLatLng returns the leaf cell containing ll. | ||||
| func CellIDFromLatLng(ll LatLng) CellID { | ||||
| 	return cellIDFromPoint(PointFromLatLng(ll)) | ||||
| } | ||||
| 
 | ||||
| // CellIDFromToken returns a cell given a hex-encoded string of its uint64 ID. | ||||
| func CellIDFromToken(s string) CellID { | ||||
| 	if len(s) > 16 { | ||||
| 		return CellID(0) | ||||
| 	} | ||||
| 	n, err := strconv.ParseUint(s, 16, 64) | ||||
| 	if err != nil { | ||||
| 		return CellID(0) | ||||
| 	} | ||||
| 	// Equivalent to right-padding string with zeros to 16 characters. | ||||
| 	if len(s) < 16 { | ||||
| 		n = n << (4 * uint(16-len(s))) | ||||
| 	} | ||||
| 	return CellID(n) | ||||
| } | ||||
| 
 | ||||
| // ToToken returns a hex-encoded string of the uint64 cell id, with leading | ||||
| // zeros included but trailing zeros stripped. | ||||
| func (ci CellID) ToToken() string { | ||||
| 	s := strings.TrimRight(fmt.Sprintf("%016x", uint64(ci)), "0") | ||||
| 	if len(s) == 0 { | ||||
| 		return "X" | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // IsValid reports whether ci represents a valid cell. | ||||
| func (ci CellID) IsValid() bool { | ||||
| 	return ci.Face() < numFaces && (ci.lsb()&0x1555555555555555 != 0) | ||||
| } | ||||
| 
 | ||||
| // Face returns the cube face for this cell ID, in the range [0,5]. | ||||
| func (ci CellID) Face() int { return int(uint64(ci) >> posBits) } | ||||
| 
 | ||||
| // Pos returns the position along the Hilbert curve of this cell ID, in the range [0,2^posBits-1]. | ||||
| func (ci CellID) Pos() uint64 { return uint64(ci) & (^uint64(0) >> faceBits) } | ||||
| 
 | ||||
| // Level returns the subdivision level of this cell ID, in the range [0, maxLevel]. | ||||
| func (ci CellID) Level() int { | ||||
| 	return maxLevel - findLSBSetNonZero64(uint64(ci))>>1 | ||||
| } | ||||
| 
 | ||||
| // IsLeaf returns whether this cell ID is at the deepest level; | ||||
| // that is, the level at which the cells are smallest. | ||||
| func (ci CellID) IsLeaf() bool { return uint64(ci)&1 != 0 } | ||||
| 
 | ||||
| // ChildPosition returns the child position (0..3) of this cell's | ||||
| // ancestor at the given level, relative to its parent.  The argument | ||||
| // should be in the range 1..kMaxLevel.  For example, | ||||
| // ChildPosition(1) returns the position of this cell's level-1 | ||||
| // ancestor within its top-level face cell. | ||||
| func (ci CellID) ChildPosition(level int) int { | ||||
| 	return int(uint64(ci)>>uint64(2*(maxLevel-level)+1)) & 3 | ||||
| } | ||||
| 
 | ||||
| // lsbForLevel returns the lowest-numbered bit that is on for cells at the given level. | ||||
| func lsbForLevel(level int) uint64 { return 1 << uint64(2*(maxLevel-level)) } | ||||
| 
 | ||||
| // Parent returns the cell at the given level, which must be no greater than the current level. | ||||
| func (ci CellID) Parent(level int) CellID { | ||||
| 	lsb := lsbForLevel(level) | ||||
| 	return CellID((uint64(ci) & -lsb) | lsb) | ||||
| } | ||||
| 
 | ||||
| // immediateParent is cheaper than Parent, but assumes !ci.isFace(). | ||||
| func (ci CellID) immediateParent() CellID { | ||||
| 	nlsb := CellID(ci.lsb() << 2) | ||||
| 	return (ci & -nlsb) | nlsb | ||||
| } | ||||
| 
 | ||||
| // isFace returns whether this is a top-level (face) cell. | ||||
| func (ci CellID) isFace() bool { return uint64(ci)&(lsbForLevel(0)-1) == 0 } | ||||
| 
 | ||||
| // lsb returns the least significant bit that is set. | ||||
| func (ci CellID) lsb() uint64 { return uint64(ci) & -uint64(ci) } | ||||
| 
 | ||||
| // Children returns the four immediate children of this cell. | ||||
| // If ci is a leaf cell, it returns four identical cells that are not the children. | ||||
| func (ci CellID) Children() [4]CellID { | ||||
| 	var ch [4]CellID | ||||
| 	lsb := CellID(ci.lsb()) | ||||
| 	ch[0] = ci - lsb + lsb>>2 | ||||
| 	lsb >>= 1 | ||||
| 	ch[1] = ch[0] + lsb | ||||
| 	ch[2] = ch[1] + lsb | ||||
| 	ch[3] = ch[2] + lsb | ||||
| 	return ch | ||||
| } | ||||
| 
 | ||||
| func sizeIJ(level int) int { | ||||
| 	return 1 << uint(maxLevel-level) | ||||
| } | ||||
| 
 | ||||
| // EdgeNeighbors returns the four cells that are adjacent across the cell's four edges. | ||||
| // Edges 0, 1, 2, 3 are in the down, right, up, left directions in the face space. | ||||
| // All neighbors are guaranteed to be distinct. | ||||
| func (ci CellID) EdgeNeighbors() [4]CellID { | ||||
| 	level := ci.Level() | ||||
| 	size := sizeIJ(level) | ||||
| 	f, i, j, _ := ci.faceIJOrientation() | ||||
| 	return [4]CellID{ | ||||
| 		cellIDFromFaceIJWrap(f, i, j-size).Parent(level), | ||||
| 		cellIDFromFaceIJWrap(f, i+size, j).Parent(level), | ||||
| 		cellIDFromFaceIJWrap(f, i, j+size).Parent(level), | ||||
| 		cellIDFromFaceIJWrap(f, i-size, j).Parent(level), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // VertexNeighbors returns the neighboring cellIDs with vertex closest to this cell at the given level. | ||||
| // (Normally there are four neighbors, but the closest vertex may only have three neighbors if it is one of | ||||
| // the 8 cube vertices.) | ||||
| func (ci CellID) VertexNeighbors(level int) []CellID { | ||||
| 	halfSize := sizeIJ(level + 1) | ||||
| 	size := halfSize << 1 | ||||
| 	f, i, j, _ := ci.faceIJOrientation() | ||||
| 
 | ||||
| 	var isame, jsame bool | ||||
| 	var ioffset, joffset int | ||||
| 	if i&halfSize != 0 { | ||||
| 		ioffset = size | ||||
| 		isame = (i + size) < maxSize | ||||
| 	} else { | ||||
| 		ioffset = -size | ||||
| 		isame = (i - size) >= 0 | ||||
| 	} | ||||
| 	if j&halfSize != 0 { | ||||
| 		joffset = size | ||||
| 		jsame = (j + size) < maxSize | ||||
| 	} else { | ||||
| 		joffset = -size | ||||
| 		jsame = (j - size) >= 0 | ||||
| 	} | ||||
| 
 | ||||
| 	results := []CellID{ | ||||
| 		ci.Parent(level), | ||||
| 		cellIDFromFaceIJSame(f, i+ioffset, j, isame).Parent(level), | ||||
| 		cellIDFromFaceIJSame(f, i, j+joffset, jsame).Parent(level), | ||||
| 	} | ||||
| 
 | ||||
| 	if isame || jsame { | ||||
| 		results = append(results, cellIDFromFaceIJSame(f, i+ioffset, j+joffset, isame && jsame).Parent(level)) | ||||
| 	} | ||||
| 
 | ||||
| 	return results | ||||
| } | ||||
| 
 | ||||
| // AllNeighbors returns all neighbors of this cell at the given level. Two | ||||
| // cells X and Y are neighbors if their boundaries intersect but their | ||||
| // interiors do not. In particular, two cells that intersect at a single | ||||
| // point are neighbors. Note that for cells adjacent to a face vertex, the | ||||
| // same neighbor may be returned more than once. There could be up to eight | ||||
| // neighbors including the diagonal ones that share the vertex. | ||||
| // | ||||
| // This requires level >= ci.Level(). | ||||
| func (ci CellID) AllNeighbors(level int) []CellID { | ||||
| 	var neighbors []CellID | ||||
| 
 | ||||
| 	face, i, j, _ := ci.faceIJOrientation() | ||||
| 
 | ||||
| 	// Find the coordinates of the lower left-hand leaf cell. We need to | ||||
| 	// normalize (i,j) to a known position within the cell because level | ||||
| 	// may be larger than this cell's level. | ||||
| 	size := sizeIJ(ci.Level()) | ||||
| 	i &= -size | ||||
| 	j &= -size | ||||
| 
 | ||||
| 	nbrSize := sizeIJ(level) | ||||
| 
 | ||||
| 	// We compute the top-bottom, left-right, and diagonal neighbors in one | ||||
| 	// pass. The loop test is at the end of the loop to avoid 32-bit overflow. | ||||
| 	for k := -nbrSize; ; k += nbrSize { | ||||
| 		var sameFace bool | ||||
| 		if k < 0 { | ||||
| 			sameFace = (j+k >= 0) | ||||
| 		} else if k >= size { | ||||
| 			sameFace = (j+k < maxSize) | ||||
| 		} else { | ||||
| 			sameFace = true | ||||
| 			// Top and bottom neighbors. | ||||
| 			neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+k, j-nbrSize, | ||||
| 				j-size >= 0).Parent(level)) | ||||
| 			neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+k, j+size, | ||||
| 				j+size < maxSize).Parent(level)) | ||||
| 		} | ||||
| 
 | ||||
| 		// Left, right, and diagonal neighbors. | ||||
| 		neighbors = append(neighbors, cellIDFromFaceIJSame(face, i-nbrSize, j+k, | ||||
| 			sameFace && i-size >= 0).Parent(level)) | ||||
| 		neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+size, j+k, | ||||
| 			sameFace && i+size < maxSize).Parent(level)) | ||||
| 
 | ||||
| 		if k >= size { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return neighbors | ||||
| } | ||||
| 
 | ||||
| // RangeMin returns the minimum CellID that is contained within this cell. | ||||
| func (ci CellID) RangeMin() CellID { return CellID(uint64(ci) - (ci.lsb() - 1)) } | ||||
| 
 | ||||
| // RangeMax returns the maximum CellID that is contained within this cell. | ||||
| func (ci CellID) RangeMax() CellID { return CellID(uint64(ci) + (ci.lsb() - 1)) } | ||||
| 
 | ||||
| // Contains returns true iff the CellID contains oci. | ||||
| func (ci CellID) Contains(oci CellID) bool { | ||||
| 	return uint64(ci.RangeMin()) <= uint64(oci) && uint64(oci) <= uint64(ci.RangeMax()) | ||||
| } | ||||
| 
 | ||||
| // Intersects returns true iff the CellID intersects oci. | ||||
| func (ci CellID) Intersects(oci CellID) bool { | ||||
| 	return uint64(oci.RangeMin()) <= uint64(ci.RangeMax()) && uint64(oci.RangeMax()) >= uint64(ci.RangeMin()) | ||||
| } | ||||
| 
 | ||||
| // String returns the string representation of the cell ID in the form "1/3210". | ||||
| func (ci CellID) String() string { | ||||
| 	if !ci.IsValid() { | ||||
| 		return "Invalid: " + strconv.FormatInt(int64(ci), 16) | ||||
| 	} | ||||
| 	var b bytes.Buffer | ||||
| 	b.WriteByte("012345"[ci.Face()]) // values > 5 will have been picked off by !IsValid above | ||||
| 	b.WriteByte('/') | ||||
| 	for level := 1; level <= ci.Level(); level++ { | ||||
| 		b.WriteByte("0123"[ci.ChildPosition(level)]) | ||||
| 	} | ||||
| 	return b.String() | ||||
| } | ||||
| 
 | ||||
| // cellIDFromString returns a CellID from a string in the form "1/3210". | ||||
| func cellIDFromString(s string) CellID { | ||||
| 	level := len(s) - 2 | ||||
| 	if level < 0 || level > maxLevel { | ||||
| 		return CellID(0) | ||||
| 	} | ||||
| 	face := int(s[0] - '0') | ||||
| 	if face < 0 || face > 5 || s[1] != '/' { | ||||
| 		return CellID(0) | ||||
| 	} | ||||
| 	id := CellIDFromFace(face) | ||||
| 	for i := 2; i < len(s); i++ { | ||||
| 		childPos := s[i] - '0' | ||||
| 		if childPos < 0 || childPos > 3 { | ||||
| 			return CellID(0) | ||||
| 		} | ||||
| 		id = id.Children()[childPos] | ||||
| 	} | ||||
| 	return id | ||||
| } | ||||
| 
 | ||||
| // Point returns the center of the s2 cell on the sphere as a Point. | ||||
| // The maximum directional error in Point (compared to the exact | ||||
| // mathematical result) is 1.5 * dblEpsilon radians, and the maximum length | ||||
| // error is 2 * dblEpsilon (the same as Normalize). | ||||
| func (ci CellID) Point() Point { return Point{ci.rawPoint().Normalize()} } | ||||
| 
 | ||||
| // LatLng returns the center of the s2 cell on the sphere as a LatLng. | ||||
| func (ci CellID) LatLng() LatLng { return LatLngFromPoint(Point{ci.rawPoint()}) } | ||||
| 
 | ||||
| // ChildBegin returns the first child in a traversal of the children of this cell, in Hilbert curve order. | ||||
| // | ||||
| //    for ci := c.ChildBegin(); ci != c.ChildEnd(); ci = ci.Next() { | ||||
| //        ... | ||||
| //    } | ||||
| func (ci CellID) ChildBegin() CellID { | ||||
| 	ol := ci.lsb() | ||||
| 	return CellID(uint64(ci) - ol + ol>>2) | ||||
| } | ||||
| 
 | ||||
| // ChildBeginAtLevel returns the first cell in a traversal of children a given level deeper than this cell, in | ||||
| // Hilbert curve order. The given level must be no smaller than the cell's level. | ||||
| // See ChildBegin for example use. | ||||
| func (ci CellID) ChildBeginAtLevel(level int) CellID { | ||||
| 	return CellID(uint64(ci) - ci.lsb() + lsbForLevel(level)) | ||||
| } | ||||
| 
 | ||||
| // ChildEnd returns the first cell after a traversal of the children of this cell in Hilbert curve order. | ||||
| // The returned cell may be invalid. | ||||
| func (ci CellID) ChildEnd() CellID { | ||||
| 	ol := ci.lsb() | ||||
| 	return CellID(uint64(ci) + ol + ol>>2) | ||||
| } | ||||
| 
 | ||||
| // ChildEndAtLevel returns the first cell after the last child in a traversal of children a given level deeper | ||||
| // than this cell, in Hilbert curve order. | ||||
| // The given level must be no smaller than the cell's level. | ||||
| // The returned cell may be invalid. | ||||
| func (ci CellID) ChildEndAtLevel(level int) CellID { | ||||
| 	return CellID(uint64(ci) + ci.lsb() + lsbForLevel(level)) | ||||
| } | ||||
| 
 | ||||
| // Next returns the next cell along the Hilbert curve. | ||||
| // This is expected to be used with ChildBegin and ChildEnd, | ||||
| // or ChildBeginAtLevel and ChildEndAtLevel. | ||||
| func (ci CellID) Next() CellID { | ||||
| 	return CellID(uint64(ci) + ci.lsb()<<1) | ||||
| } | ||||
| 
 | ||||
| // Prev returns the previous cell along the Hilbert curve. | ||||
| func (ci CellID) Prev() CellID { | ||||
| 	return CellID(uint64(ci) - ci.lsb()<<1) | ||||
| } | ||||
| 
 | ||||
| // NextWrap returns the next cell along the Hilbert curve, wrapping from last to | ||||
| // first as necessary. This should not be used with ChildBegin and ChildEnd. | ||||
| func (ci CellID) NextWrap() CellID { | ||||
| 	n := ci.Next() | ||||
| 	if uint64(n) < wrapOffset { | ||||
| 		return n | ||||
| 	} | ||||
| 	return CellID(uint64(n) - wrapOffset) | ||||
| } | ||||
| 
 | ||||
| // PrevWrap returns the previous cell along the Hilbert curve, wrapping around from | ||||
| // first to last as necessary. This should not be used with ChildBegin and ChildEnd. | ||||
| func (ci CellID) PrevWrap() CellID { | ||||
| 	p := ci.Prev() | ||||
| 	if uint64(p) < wrapOffset { | ||||
| 		return p | ||||
| 	} | ||||
| 	return CellID(uint64(p) + wrapOffset) | ||||
| } | ||||
| 
 | ||||
| // AdvanceWrap advances or retreats the indicated number of steps along the | ||||
| // Hilbert curve at the current level and returns the new position. The | ||||
| // position wraps between the first and last faces as necessary. | ||||
| func (ci CellID) AdvanceWrap(steps int64) CellID { | ||||
| 	if steps == 0 { | ||||
| 		return ci | ||||
| 	} | ||||
| 
 | ||||
| 	// We clamp the number of steps if necessary to ensure that we do not | ||||
| 	// advance past the End() or before the Begin() of this level. | ||||
| 	shift := uint(2*(maxLevel-ci.Level()) + 1) | ||||
| 	if steps < 0 { | ||||
| 		if min := -int64(uint64(ci) >> shift); steps < min { | ||||
| 			wrap := int64(wrapOffset >> shift) | ||||
| 			steps %= wrap | ||||
| 			if steps < min { | ||||
| 				steps += wrap | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Unlike Advance(), we don't want to return End(level). | ||||
| 		if max := int64((wrapOffset - uint64(ci)) >> shift); steps > max { | ||||
| 			wrap := int64(wrapOffset >> shift) | ||||
| 			steps %= wrap | ||||
| 			if steps > max { | ||||
| 				steps -= wrap | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If steps is negative, then shifting it left has undefined behavior. | ||||
| 	// Cast to uint64 for a 2's complement answer. | ||||
| 	return CellID(uint64(ci) + (uint64(steps) << shift)) | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the CellID. | ||||
| func (ci CellID) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	ci.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (ci CellID) encode(e *encoder) { | ||||
| 	e.writeUint64(uint64(ci)) | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the CellID. | ||||
| func (ci *CellID) Decode(r io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(r)} | ||||
| 	ci.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (ci *CellID) decode(d *decoder) { | ||||
| 	*ci = CellID(d.readUint64()) | ||||
| } | ||||
| 
 | ||||
| // TODO: the methods below are not exported yet.  Settle on the entire API design | ||||
| // before doing this.  Do we want to mirror the C++ one as closely as possible? | ||||
| 
 | ||||
| // distanceFromBegin returns the number of steps along the Hilbert curve that | ||||
| // this cell is from the first node in the S2 hierarchy at our level. (i.e., | ||||
| // FromFace(0).ChildBeginAtLevel(ci.Level())). This is analogous to Pos(), but | ||||
| // for this cell's level. | ||||
| // The return value is always non-negative. | ||||
| func (ci CellID) distanceFromBegin() int64 { | ||||
| 	return int64(ci >> uint64(2*(maxLevel-ci.Level())+1)) | ||||
| } | ||||
| 
 | ||||
| // rawPoint returns an unnormalized r3 vector from the origin through the center | ||||
| // of the s2 cell on the sphere. | ||||
| func (ci CellID) rawPoint() r3.Vector { | ||||
| 	face, si, ti := ci.faceSiTi() | ||||
| 	return faceUVToXYZ(face, stToUV((0.5/maxSize)*float64(si)), stToUV((0.5/maxSize)*float64(ti))) | ||||
| } | ||||
| 
 | ||||
| // faceSiTi returns the Face/Si/Ti coordinates of the center of the cell. | ||||
| func (ci CellID) faceSiTi() (face int, si, ti uint32) { | ||||
| 	face, i, j, _ := ci.faceIJOrientation() | ||||
| 	delta := 0 | ||||
| 	if ci.IsLeaf() { | ||||
| 		delta = 1 | ||||
| 	} else { | ||||
| 		if (i^(int(ci)>>2))&1 != 0 { | ||||
| 			delta = 2 | ||||
| 		} | ||||
| 	} | ||||
| 	return face, uint32(2*i + delta), uint32(2*j + delta) | ||||
| } | ||||
| 
 | ||||
| // faceIJOrientation uses the global lookupIJ table to unfiddle the bits of ci. | ||||
| func (ci CellID) faceIJOrientation() (f, i, j, orientation int) { | ||||
| 	f = ci.Face() | ||||
| 	orientation = f & swapMask | ||||
| 	nbits := maxLevel - 7*lookupBits // first iteration | ||||
| 
 | ||||
| 	// Each iteration maps 8 bits of the Hilbert curve position into | ||||
| 	// 4 bits of "i" and "j". The lookup table transforms a key of the | ||||
| 	// form "ppppppppoo" to a value of the form "iiiijjjjoo", where the | ||||
| 	// letters [ijpo] represents bits of "i", "j", the Hilbert curve | ||||
| 	// position, and the Hilbert curve orientation respectively. | ||||
| 	// | ||||
| 	// On the first iteration we need to be careful to clear out the bits | ||||
| 	// representing the cube face. | ||||
| 	for k := 7; k >= 0; k-- { | ||||
| 		orientation += (int(uint64(ci)>>uint64(k*2*lookupBits+1)) & ((1 << uint(2*nbits)) - 1)) << 2 | ||||
| 		orientation = lookupIJ[orientation] | ||||
| 		i += (orientation >> (lookupBits + 2)) << uint(k*lookupBits) | ||||
| 		j += ((orientation >> 2) & ((1 << lookupBits) - 1)) << uint(k*lookupBits) | ||||
| 		orientation &= (swapMask | invertMask) | ||||
| 		nbits = lookupBits // following iterations | ||||
| 	} | ||||
| 
 | ||||
| 	// The position of a non-leaf cell at level "n" consists of a prefix of | ||||
| 	// 2*n bits that identifies the cell, followed by a suffix of | ||||
| 	// 2*(maxLevel-n)+1 bits of the form 10*. If n==maxLevel, the suffix is | ||||
| 	// just "1" and has no effect. Otherwise, it consists of "10", followed | ||||
| 	// by (maxLevel-n-1) repetitions of "00", followed by "0". The "10" has | ||||
| 	// no effect, while each occurrence of "00" has the effect of reversing | ||||
| 	// the swapMask bit. | ||||
| 	if ci.lsb()&0x1111111111111110 != 0 { | ||||
| 		orientation ^= swapMask | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // cellIDFromFaceIJ returns a leaf cell given its cube face (range 0..5) and IJ coordinates. | ||||
| func cellIDFromFaceIJ(f, i, j int) CellID { | ||||
| 	// Note that this value gets shifted one bit to the left at the end | ||||
| 	// of the function. | ||||
| 	n := uint64(f) << (posBits - 1) | ||||
| 	// Alternating faces have opposite Hilbert curve orientations; this | ||||
| 	// is necessary in order for all faces to have a right-handed | ||||
| 	// coordinate system. | ||||
| 	bits := f & swapMask | ||||
| 	// Each iteration maps 4 bits of "i" and "j" into 8 bits of the Hilbert | ||||
| 	// curve position.  The lookup table transforms a 10-bit key of the form | ||||
| 	// "iiiijjjjoo" to a 10-bit value of the form "ppppppppoo", where the | ||||
| 	// letters [ijpo] denote bits of "i", "j", Hilbert curve position, and | ||||
| 	// Hilbert curve orientation respectively. | ||||
| 	for k := 7; k >= 0; k-- { | ||||
| 		mask := (1 << lookupBits) - 1 | ||||
| 		bits += ((i >> uint(k*lookupBits)) & mask) << (lookupBits + 2) | ||||
| 		bits += ((j >> uint(k*lookupBits)) & mask) << 2 | ||||
| 		bits = lookupPos[bits] | ||||
| 		n |= uint64(bits>>2) << (uint(k) * 2 * lookupBits) | ||||
| 		bits &= (swapMask | invertMask) | ||||
| 	} | ||||
| 	return CellID(n*2 + 1) | ||||
| } | ||||
| 
 | ||||
| func cellIDFromFaceIJWrap(f, i, j int) CellID { | ||||
| 	// Convert i and j to the coordinates of a leaf cell just beyond the | ||||
| 	// boundary of this face.  This prevents 32-bit overflow in the case | ||||
| 	// of finding the neighbors of a face cell. | ||||
| 	i = clampInt(i, -1, maxSize) | ||||
| 	j = clampInt(j, -1, maxSize) | ||||
| 
 | ||||
| 	// We want to wrap these coordinates onto the appropriate adjacent face. | ||||
| 	// The easiest way to do this is to convert the (i,j) coordinates to (x,y,z) | ||||
| 	// (which yields a point outside the normal face boundary), and then call | ||||
| 	// xyzToFaceUV to project back onto the correct face. | ||||
| 	// | ||||
| 	// The code below converts (i,j) to (si,ti), and then (si,ti) to (u,v) using | ||||
| 	// the linear projection (u=2*s-1 and v=2*t-1).  (The code further below | ||||
| 	// converts back using the inverse projection, s=0.5*(u+1) and t=0.5*(v+1). | ||||
| 	// Any projection would work here, so we use the simplest.)  We also clamp | ||||
| 	// the (u,v) coordinates so that the point is barely outside the | ||||
| 	// [-1,1]x[-1,1] face rectangle, since otherwise the reprojection step | ||||
| 	// (which divides by the new z coordinate) might change the other | ||||
| 	// coordinates enough so that we end up in the wrong leaf cell. | ||||
| 	const scale = 1.0 / maxSize | ||||
| 	limit := math.Nextafter(1, 2) | ||||
| 	u := math.Max(-limit, math.Min(limit, scale*float64((i<<1)+1-maxSize))) | ||||
| 	v := math.Max(-limit, math.Min(limit, scale*float64((j<<1)+1-maxSize))) | ||||
| 
 | ||||
| 	// Find the leaf cell coordinates on the adjacent face, and convert | ||||
| 	// them to a cell id at the appropriate level. | ||||
| 	f, u, v = xyzToFaceUV(faceUVToXYZ(f, u, v)) | ||||
| 	return cellIDFromFaceIJ(f, stToIJ(0.5*(u+1)), stToIJ(0.5*(v+1))) | ||||
| } | ||||
| 
 | ||||
| func cellIDFromFaceIJSame(f, i, j int, sameFace bool) CellID { | ||||
| 	if sameFace { | ||||
| 		return cellIDFromFaceIJ(f, i, j) | ||||
| 	} | ||||
| 	return cellIDFromFaceIJWrap(f, i, j) | ||||
| } | ||||
| 
 | ||||
| // ijToSTMin converts the i- or j-index of a leaf cell to the minimum corresponding | ||||
| // s- or t-value contained by that cell. The argument must be in the range | ||||
| // [0..2**30], i.e. up to one position beyond the normal range of valid leaf | ||||
| // cell indices. | ||||
| func ijToSTMin(i int) float64 { | ||||
| 	return float64(i) / float64(maxSize) | ||||
| } | ||||
| 
 | ||||
| // stToIJ converts value in ST coordinates to a value in IJ coordinates. | ||||
| func stToIJ(s float64) int { | ||||
| 	return clampInt(int(math.Floor(maxSize*s)), 0, maxSize-1) | ||||
| } | ||||
| 
 | ||||
| // cellIDFromPoint returns a leaf cell containing point p. Usually there is | ||||
| // exactly one such cell, but for points along the edge of a cell, any | ||||
| // adjacent cell may be (deterministically) chosen. This is because | ||||
| // s2.CellIDs are considered to be closed sets. The returned cell will | ||||
| // always contain the given point, i.e. | ||||
| // | ||||
| //   CellFromPoint(p).ContainsPoint(p) | ||||
| // | ||||
| // is always true. | ||||
| func cellIDFromPoint(p Point) CellID { | ||||
| 	f, u, v := xyzToFaceUV(r3.Vector{p.X, p.Y, p.Z}) | ||||
| 	i := stToIJ(uvToST(u)) | ||||
| 	j := stToIJ(uvToST(v)) | ||||
| 	return cellIDFromFaceIJ(f, i, j) | ||||
| } | ||||
| 
 | ||||
| // ijLevelToBoundUV returns the bounds in (u,v)-space for the cell at the given | ||||
| // level containing the leaf cell with the given (i,j)-coordinates. | ||||
| func ijLevelToBoundUV(i, j, level int) r2.Rect { | ||||
| 	cellSize := sizeIJ(level) | ||||
| 	xLo := i & -cellSize | ||||
| 	yLo := j & -cellSize | ||||
| 
 | ||||
| 	return r2.Rect{ | ||||
| 		X: r1.Interval{ | ||||
| 			Lo: stToUV(ijToSTMin(xLo)), | ||||
| 			Hi: stToUV(ijToSTMin(xLo + cellSize)), | ||||
| 		}, | ||||
| 		Y: r1.Interval{ | ||||
| 			Lo: stToUV(ijToSTMin(yLo)), | ||||
| 			Hi: stToUV(ijToSTMin(yLo + cellSize)), | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Constants related to the bit mangling in the Cell ID. | ||||
| const ( | ||||
| 	lookupBits = 4 | ||||
| 	swapMask   = 0x01 | ||||
| 	invertMask = 0x02 | ||||
| ) | ||||
| 
 | ||||
| // The following lookup tables are used to convert efficiently between an | ||||
| // (i,j) cell index and the corresponding position along the Hilbert curve. | ||||
| // | ||||
| // lookupPos maps 4 bits of "i", 4 bits of "j", and 2 bits representing the | ||||
| // orientation of the current cell into 8 bits representing the order in which | ||||
| // that subcell is visited by the Hilbert curve, plus 2 bits indicating the | ||||
| // new orientation of the Hilbert curve within that subcell. (Cell | ||||
| // orientations are represented as combination of swapMask and invertMask.) | ||||
| // | ||||
| // lookupIJ is an inverted table used for mapping in the opposite | ||||
| // direction. | ||||
| // | ||||
| // We also experimented with looking up 16 bits at a time (14 bits of position | ||||
| // plus 2 of orientation) but found that smaller lookup tables gave better | ||||
| // performance. (2KB fits easily in the primary cache.) | ||||
| var ( | ||||
| 	ijToPos = [4][4]int{ | ||||
| 		{0, 1, 3, 2}, // canonical order | ||||
| 		{0, 3, 1, 2}, // axes swapped | ||||
| 		{2, 3, 1, 0}, // bits inverted | ||||
| 		{2, 1, 3, 0}, // swapped & inverted | ||||
| 	} | ||||
| 	posToIJ = [4][4]int{ | ||||
| 		{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) | ||||
| 	} | ||||
| 	posToOrientation = [4]int{swapMask, 0, 0, invertMask | swapMask} | ||||
| 	lookupIJ         [1 << (2*lookupBits + 2)]int | ||||
| 	lookupPos        [1 << (2*lookupBits + 2)]int | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	initLookupCell(0, 0, 0, 0, 0, 0) | ||||
| 	initLookupCell(0, 0, 0, swapMask, 0, swapMask) | ||||
| 	initLookupCell(0, 0, 0, invertMask, 0, invertMask) | ||||
| 	initLookupCell(0, 0, 0, swapMask|invertMask, 0, swapMask|invertMask) | ||||
| } | ||||
| 
 | ||||
| // initLookupCell initializes the lookupIJ table at init time. | ||||
| func initLookupCell(level, i, j, origOrientation, pos, orientation int) { | ||||
| 	if level == lookupBits { | ||||
| 		ij := (i << lookupBits) + j | ||||
| 		lookupPos[(ij<<2)+origOrientation] = (pos << 2) + orientation | ||||
| 		lookupIJ[(pos<<2)+origOrientation] = (ij << 2) + orientation | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	level++ | ||||
| 	i <<= 1 | ||||
| 	j <<= 1 | ||||
| 	pos <<= 2 | ||||
| 	r := posToIJ[orientation] | ||||
| 	initLookupCell(level, i+(r[0]>>1), j+(r[0]&1), origOrientation, pos, orientation^posToOrientation[0]) | ||||
| 	initLookupCell(level, i+(r[1]>>1), j+(r[1]&1), origOrientation, pos+1, orientation^posToOrientation[1]) | ||||
| 	initLookupCell(level, i+(r[2]>>1), j+(r[2]&1), origOrientation, pos+2, orientation^posToOrientation[2]) | ||||
| 	initLookupCell(level, i+(r[3]>>1), j+(r[3]&1), origOrientation, pos+3, orientation^posToOrientation[3]) | ||||
| } | ||||
| 
 | ||||
| // CommonAncestorLevel returns the level of the common ancestor of the two S2 CellIDs. | ||||
| func (ci CellID) CommonAncestorLevel(other CellID) (level int, ok bool) { | ||||
| 	bits := uint64(ci ^ other) | ||||
| 	if bits < ci.lsb() { | ||||
| 		bits = ci.lsb() | ||||
| 	} | ||||
| 	if bits < other.lsb() { | ||||
| 		bits = other.lsb() | ||||
| 	} | ||||
| 
 | ||||
| 	msbPos := findMSBSetNonZero64(bits) | ||||
| 	if msbPos > 60 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return (60 - msbPos) >> 1, true | ||||
| } | ||||
| 
 | ||||
| // Advance advances or retreats the indicated number of steps along the | ||||
| // Hilbert curve at the current level, and returns the new position. The | ||||
| // position is never advanced past End() or before Begin(). | ||||
| func (ci CellID) Advance(steps int64) CellID { | ||||
| 	if steps == 0 { | ||||
| 		return ci | ||||
| 	} | ||||
| 
 | ||||
| 	// We clamp the number of steps if necessary to ensure that we do not | ||||
| 	// advance past the End() or before the Begin() of this level. Note that | ||||
| 	// minSteps and maxSteps always fit in a signed 64-bit integer. | ||||
| 	stepShift := uint(2*(maxLevel-ci.Level()) + 1) | ||||
| 	if steps < 0 { | ||||
| 		minSteps := -int64(uint64(ci) >> stepShift) | ||||
| 		if steps < minSteps { | ||||
| 			steps = minSteps | ||||
| 		} | ||||
| 	} else { | ||||
| 		maxSteps := int64((wrapOffset + ci.lsb() - uint64(ci)) >> stepShift) | ||||
| 		if steps > maxSteps { | ||||
| 			steps = maxSteps | ||||
| 		} | ||||
| 	} | ||||
| 	return ci + CellID(steps)<<stepShift | ||||
| } | ||||
| 
 | ||||
| // centerST return the center of the CellID in (s,t)-space. | ||||
| func (ci CellID) centerST() r2.Point { | ||||
| 	_, si, ti := ci.faceSiTi() | ||||
| 	return r2.Point{siTiToST(si), siTiToST(ti)} | ||||
| } | ||||
| 
 | ||||
| // sizeST returns the edge length of this CellID in (s,t)-space at the given level. | ||||
| func (ci CellID) sizeST(level int) float64 { | ||||
| 	return ijToSTMin(sizeIJ(level)) | ||||
| } | ||||
| 
 | ||||
| // boundST returns the bound of this CellID in (s,t)-space. | ||||
| func (ci CellID) boundST() r2.Rect { | ||||
| 	s := ci.sizeST(ci.Level()) | ||||
| 	return r2.RectFromCenterSize(ci.centerST(), r2.Point{s, s}) | ||||
| } | ||||
| 
 | ||||
| // centerUV returns the center of this CellID in (u,v)-space. Note that | ||||
| // the center of the cell is defined as the point at which it is recursively | ||||
| // subdivided into four children; in general, it is not at the midpoint of | ||||
| // the (u,v) rectangle covered by the cell. | ||||
| func (ci CellID) centerUV() r2.Point { | ||||
| 	_, si, ti := ci.faceSiTi() | ||||
| 	return r2.Point{stToUV(siTiToST(si)), stToUV(siTiToST(ti))} | ||||
| } | ||||
| 
 | ||||
| // boundUV returns the bound of this CellID in (u,v)-space. | ||||
| func (ci CellID) boundUV() r2.Rect { | ||||
| 	_, i, j, _ := ci.faceIJOrientation() | ||||
| 	return ijLevelToBoundUV(i, j, ci.Level()) | ||||
| } | ||||
| 
 | ||||
| // expandEndpoint returns a new u-coordinate u' such that the distance from the | ||||
| // line u=u' to the given edge (u,v0)-(u,v1) is exactly the given distance | ||||
| // (which is specified as the sine of the angle corresponding to the distance). | ||||
| func expandEndpoint(u, maxV, sinDist float64) float64 { | ||||
| 	// This is based on solving a spherical right triangle, similar to the | ||||
| 	// calculation in Cap.RectBound. | ||||
| 	// Given an edge of the form (u,v0)-(u,v1), let maxV = max(abs(v0), abs(v1)). | ||||
| 	sinUShift := sinDist * math.Sqrt((1+u*u+maxV*maxV)/(1+u*u)) | ||||
| 	cosUShift := math.Sqrt(1 - sinUShift*sinUShift) | ||||
| 	// The following is an expansion of tan(atan(u) + asin(sinUShift)). | ||||
| 	return (cosUShift*u + sinUShift) / (cosUShift - sinUShift*u) | ||||
| } | ||||
| 
 | ||||
| // expandedByDistanceUV returns a rectangle expanded in (u,v)-space so that it | ||||
| // contains all points within the given distance of the boundary, and return the | ||||
| // smallest such rectangle. If the distance is negative, then instead shrink this | ||||
| // rectangle so that it excludes all points within the given absolute distance | ||||
| // of the boundary. | ||||
| // | ||||
| // Distances are measured *on the sphere*, not in (u,v)-space. For example, | ||||
| // you can use this method to expand the (u,v)-bound of an CellID so that | ||||
| // it contains all points within 5km of the original cell. You can then | ||||
| // test whether a point lies within the expanded bounds like this: | ||||
| // | ||||
| //   if u, v, ok := faceXYZtoUV(face, point); ok && bound.ContainsPoint(r2.Point{u,v}) { ... } | ||||
| // | ||||
| // Limitations: | ||||
| // | ||||
| //  - Because the rectangle is drawn on one of the six cube-face planes | ||||
| //    (i.e., {x,y,z} = +/-1), it can cover at most one hemisphere. This | ||||
| //    limits the maximum amount that a rectangle can be expanded. For | ||||
| //    example, CellID bounds can be expanded safely by at most 45 degrees | ||||
| //    (about 5000 km on the Earth's surface). | ||||
| // | ||||
| //  - The implementation is not exact for negative distances. The resulting | ||||
| //    rectangle will exclude all points within the given distance of the | ||||
| //    boundary but may be slightly smaller than necessary. | ||||
| func expandedByDistanceUV(uv r2.Rect, distance s1.Angle) r2.Rect { | ||||
| 	// Expand each of the four sides of the rectangle just enough to include all | ||||
| 	// points within the given distance of that side. (The rectangle may be | ||||
| 	// expanded by a different amount in (u,v)-space on each side.) | ||||
| 	maxU := math.Max(math.Abs(uv.X.Lo), math.Abs(uv.X.Hi)) | ||||
| 	maxV := math.Max(math.Abs(uv.Y.Lo), math.Abs(uv.Y.Hi)) | ||||
| 	sinDist := math.Sin(float64(distance)) | ||||
| 	return r2.Rect{ | ||||
| 		X: r1.Interval{expandEndpoint(uv.X.Lo, maxV, -sinDist), | ||||
| 			expandEndpoint(uv.X.Hi, maxV, sinDist)}, | ||||
| 		Y: r1.Interval{expandEndpoint(uv.Y.Lo, maxU, -sinDist), | ||||
| 			expandEndpoint(uv.Y.Hi, maxU, sinDist)}} | ||||
| } | ||||
| 
 | ||||
| // MaxTile returns the largest cell with the same RangeMin such that | ||||
| // RangeMax < limit.RangeMin. It returns limit if no such cell exists. | ||||
| // This method can be used to generate a small set of CellIDs that covers | ||||
| // a given range (a tiling). This example shows how to generate a tiling | ||||
| // for a semi-open range of leaf cells [start, limit): | ||||
| // | ||||
| //   for id := start.MaxTile(limit); id != limit; id = id.Next().MaxTile(limit)) { ... } | ||||
| // | ||||
| // Note that in general the cells in the tiling will be of different sizes; | ||||
| // they gradually get larger (near the middle of the range) and then | ||||
| // gradually get smaller as limit is approached. | ||||
| func (ci CellID) MaxTile(limit CellID) CellID { | ||||
| 	start := ci.RangeMin() | ||||
| 	if start >= limit.RangeMin() { | ||||
| 		return limit | ||||
| 	} | ||||
| 
 | ||||
| 	if ci.RangeMax() >= limit { | ||||
| 		// The cell is too large, shrink it. Note that when generating coverings | ||||
| 		// of CellID ranges, this loop usually executes only once. Also because | ||||
| 		// ci.RangeMin() < limit.RangeMin(), we will always exit the loop by the | ||||
| 		// time we reach a leaf cell. | ||||
| 		for { | ||||
| 			ci = ci.Children()[0] | ||||
| 			if ci.RangeMax() < limit { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		return ci | ||||
| 	} | ||||
| 
 | ||||
| 	// The cell may be too small. Grow it if necessary. Note that generally | ||||
| 	// this loop only iterates once. | ||||
| 	for !ci.isFace() { | ||||
| 		parent := ci.immediateParent() | ||||
| 		if parent.RangeMin() != start || parent.RangeMax() >= limit { | ||||
| 			break | ||||
| 		} | ||||
| 		ci = parent | ||||
| 	} | ||||
| 	return ci | ||||
| } | ||||
| 
 | ||||
| // centerFaceSiTi returns the (face, si, ti) coordinates of the center of the cell. | ||||
| // Note that although (si,ti) coordinates span the range [0,2**31] in general, | ||||
| // the cell center coordinates are always in the range [1,2**31-1] and | ||||
| // therefore can be represented using a signed 32-bit integer. | ||||
| func (ci CellID) centerFaceSiTi() (face, si, ti int) { | ||||
| 	// First we compute the discrete (i,j) coordinates of a leaf cell contained | ||||
| 	// within the given cell. Given that cells are represented by the Hilbert | ||||
| 	// curve position corresponding at their center, it turns out that the cell | ||||
| 	// returned by faceIJOrientation is always one of two leaf cells closest | ||||
| 	// to the center of the cell (unless the given cell is a leaf cell itself, | ||||
| 	// in which case there is only one possibility). | ||||
| 	// | ||||
| 	// Given a cell of size s >= 2 (i.e. not a leaf cell), and letting (imin, | ||||
| 	// jmin) be the coordinates of its lower left-hand corner, the leaf cell | ||||
| 	// returned by faceIJOrientation is either (imin + s/2, jmin + s/2) | ||||
| 	// (imin + s/2 - 1, jmin + s/2 - 1). The first case is the one we want. | ||||
| 	// We can distinguish these two cases by looking at the low bit of i or | ||||
| 	// j. In the second case the low bit is one, unless s == 2 (i.e. the | ||||
| 	// level just above leaf cells) in which case the low bit is zero. | ||||
| 	// | ||||
| 	// In the code below, the expression ((i ^ (int(id) >> 2)) & 1) is true | ||||
| 	// if we are in the second case described above. | ||||
| 	face, i, j, _ := ci.faceIJOrientation() | ||||
| 	delta := 0 | ||||
| 	if ci.IsLeaf() { | ||||
| 		delta = 1 | ||||
| 	} else if (int64(i)^(int64(ci)>>2))&1 == 1 { | ||||
| 		delta = 2 | ||||
| 	} | ||||
| 
 | ||||
| 	// Note that (2 * {i,j} + delta) will never overflow a 32-bit integer. | ||||
| 	return face, 2*i + delta, 2*j + delta | ||||
| } | ||||
							
								
								
									
										590
									
								
								vendor/github.com/golang/geo/s2/cellunion.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										590
									
								
								vendor/github.com/golang/geo/s2/cellunion.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,590 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // A CellUnion is a collection of CellIDs. | ||||
| // | ||||
| // It is normalized if it is sorted, and does not contain redundancy. | ||||
| // Specifically, it may not contain the same CellID twice, nor a CellID that | ||||
| // is contained by another, nor the four sibling CellIDs that are children of | ||||
| // a single higher level CellID. | ||||
| // | ||||
| // CellUnions are not required to be normalized, but certain operations will | ||||
| // return different results if they are not (e.g. Contains). | ||||
| type CellUnion []CellID | ||||
| 
 | ||||
| // CellUnionFromRange creates a CellUnion that covers the half-open range | ||||
| // of leaf cells [begin, end). If begin == end the resulting union is empty. | ||||
| // This requires that begin and end are both leaves, and begin <= end. | ||||
| // To create a closed-ended range, pass in end.Next(). | ||||
| func CellUnionFromRange(begin, end CellID) CellUnion { | ||||
| 	// We repeatedly add the largest cell we can. | ||||
| 	var cu CellUnion | ||||
| 	for id := begin.MaxTile(end); id != end; id = id.Next().MaxTile(end) { | ||||
| 		cu = append(cu, id) | ||||
| 	} | ||||
| 	// The output is normalized because the cells are added in order by the iteration. | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // CellUnionFromUnion creates a CellUnion from the union of the given CellUnions. | ||||
| func CellUnionFromUnion(cellUnions ...CellUnion) CellUnion { | ||||
| 	var cu CellUnion | ||||
| 	for _, cellUnion := range cellUnions { | ||||
| 		cu = append(cu, cellUnion...) | ||||
| 	} | ||||
| 	cu.Normalize() | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // CellUnionFromIntersection creates a CellUnion from the intersection of the given CellUnions. | ||||
| func CellUnionFromIntersection(x, y CellUnion) CellUnion { | ||||
| 	var cu CellUnion | ||||
| 
 | ||||
| 	// This is a fairly efficient calculation that uses binary search to skip | ||||
| 	// over sections of both input vectors. It takes constant time if all the | ||||
| 	// cells of x come before or after all the cells of y in CellID order. | ||||
| 	var i, j int | ||||
| 	for i < len(x) && j < len(y) { | ||||
| 		iMin := x[i].RangeMin() | ||||
| 		jMin := y[j].RangeMin() | ||||
| 		if iMin > jMin { | ||||
| 			// Either j.Contains(i) or the two cells are disjoint. | ||||
| 			if x[i] <= y[j].RangeMax() { | ||||
| 				cu = append(cu, x[i]) | ||||
| 				i++ | ||||
| 			} else { | ||||
| 				// Advance j to the first cell possibly contained by x[i]. | ||||
| 				j = y.lowerBound(j+1, len(y), iMin) | ||||
| 				// The previous cell y[j-1] may now contain x[i]. | ||||
| 				if x[i] <= y[j-1].RangeMax() { | ||||
| 					j-- | ||||
| 				} | ||||
| 			} | ||||
| 		} else if jMin > iMin { | ||||
| 			// Identical to the code above with i and j reversed. | ||||
| 			if y[j] <= x[i].RangeMax() { | ||||
| 				cu = append(cu, y[j]) | ||||
| 				j++ | ||||
| 			} else { | ||||
| 				i = x.lowerBound(i+1, len(x), jMin) | ||||
| 				if y[j] <= x[i-1].RangeMax() { | ||||
| 					i-- | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			// i and j have the same RangeMin(), so one contains the other. | ||||
| 			if x[i] < y[j] { | ||||
| 				cu = append(cu, x[i]) | ||||
| 				i++ | ||||
| 			} else { | ||||
| 				cu = append(cu, y[j]) | ||||
| 				j++ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// The output is generated in sorted order. | ||||
| 	cu.Normalize() | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // CellUnionFromIntersectionWithCellID creates a CellUnion from the intersection | ||||
| // of a CellUnion with the given CellID. This can be useful for splitting a | ||||
| // CellUnion into chunks. | ||||
| func CellUnionFromIntersectionWithCellID(x CellUnion, id CellID) CellUnion { | ||||
| 	var cu CellUnion | ||||
| 	if x.ContainsCellID(id) { | ||||
| 		cu = append(cu, id) | ||||
| 		cu.Normalize() | ||||
| 		return cu | ||||
| 	} | ||||
| 
 | ||||
| 	idmax := id.RangeMax() | ||||
| 	for i := x.lowerBound(0, len(x), id.RangeMin()); i < len(x) && x[i] <= idmax; i++ { | ||||
| 		cu = append(cu, x[i]) | ||||
| 	} | ||||
| 
 | ||||
| 	cu.Normalize() | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // CellUnionFromDifference creates a CellUnion from the difference (x - y) | ||||
| // of the given CellUnions. | ||||
| func CellUnionFromDifference(x, y CellUnion) CellUnion { | ||||
| 	// TODO(roberts): This is approximately O(N*log(N)), but could probably | ||||
| 	// use similar techniques as CellUnionFromIntersectionWithCellID to be more efficient. | ||||
| 
 | ||||
| 	var cu CellUnion | ||||
| 	for _, xid := range x { | ||||
| 		cu.cellUnionDifferenceInternal(xid, &y) | ||||
| 	} | ||||
| 
 | ||||
| 	// The output is generated in sorted order, and there should not be any | ||||
| 	// cells that can be merged (provided that both inputs were normalized). | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // The C++ constructor methods FromNormalized and FromVerbatim are not necessary | ||||
| // since they don't call Normalize, and just set the CellIDs directly on the object, | ||||
| // so straight casting is sufficient in Go to replicate this behavior. | ||||
| 
 | ||||
| // IsValid reports whether the cell union is valid, meaning that the CellIDs are | ||||
| // valid, non-overlapping, and sorted in increasing order. | ||||
| func (cu *CellUnion) IsValid() bool { | ||||
| 	for i, cid := range *cu { | ||||
| 		if !cid.IsValid() { | ||||
| 			return false | ||||
| 		} | ||||
| 		if i == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if (*cu)[i-1].RangeMax() >= cid.RangeMin() { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // IsNormalized reports whether the cell union is normalized, meaning that it is | ||||
| // satisfies IsValid and that no four cells have a common parent. | ||||
| // Certain operations such as Contains will return a different | ||||
| // result if the cell union is not normalized. | ||||
| func (cu *CellUnion) IsNormalized() bool { | ||||
| 	for i, cid := range *cu { | ||||
| 		if !cid.IsValid() { | ||||
| 			return false | ||||
| 		} | ||||
| 		if i == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if (*cu)[i-1].RangeMax() >= cid.RangeMin() { | ||||
| 			return false | ||||
| 		} | ||||
| 		if i < 3 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if areSiblings((*cu)[i-3], (*cu)[i-2], (*cu)[i-1], cid) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Normalize normalizes the CellUnion. | ||||
| func (cu *CellUnion) Normalize() { | ||||
| 	sortCellIDs(*cu) | ||||
| 
 | ||||
| 	output := make([]CellID, 0, len(*cu)) // the list of accepted cells | ||||
| 	// Loop invariant: output is a sorted list of cells with no redundancy. | ||||
| 	for _, ci := range *cu { | ||||
| 		// The first two passes here either ignore this new candidate, | ||||
| 		// or remove previously accepted cells that are covered by this candidate. | ||||
| 
 | ||||
| 		// Ignore this cell if it is contained by the previous one. | ||||
| 		// We only need to check the last accepted cell. The ordering of the | ||||
| 		// cells implies containment (but not the converse), and output has no redundancy, | ||||
| 		// so if this candidate is not contained by the last accepted cell | ||||
| 		// then it cannot be contained by any previously accepted cell. | ||||
| 		if len(output) > 0 && output[len(output)-1].Contains(ci) { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Discard any previously accepted cells contained by this one. | ||||
| 		// This could be any contiguous trailing subsequence, but it can't be | ||||
| 		// a discontiguous subsequence because of the containment property of | ||||
| 		// sorted S2 cells mentioned above. | ||||
| 		j := len(output) - 1 // last index to keep | ||||
| 		for j >= 0 { | ||||
| 			if !ci.Contains(output[j]) { | ||||
| 				break | ||||
| 			} | ||||
| 			j-- | ||||
| 		} | ||||
| 		output = output[:j+1] | ||||
| 
 | ||||
| 		// See if the last three cells plus this one can be collapsed. | ||||
| 		// We loop because collapsing three accepted cells and adding a higher level cell | ||||
| 		// could cascade into previously accepted cells. | ||||
| 		for len(output) >= 3 && areSiblings(output[len(output)-3], output[len(output)-2], output[len(output)-1], ci) { | ||||
| 			// Replace four children by their parent cell. | ||||
| 			output = output[:len(output)-3] | ||||
| 			ci = ci.immediateParent() // checked !ci.isFace above | ||||
| 		} | ||||
| 		output = append(output, ci) | ||||
| 	} | ||||
| 	*cu = output | ||||
| } | ||||
| 
 | ||||
| // IntersectsCellID reports whether this CellUnion intersects the given cell ID. | ||||
| func (cu *CellUnion) IntersectsCellID(id CellID) bool { | ||||
| 	// Find index of array item that occurs directly after our probe cell: | ||||
| 	i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] }) | ||||
| 
 | ||||
| 	if i != len(*cu) && (*cu)[i].RangeMin() <= id.RangeMax() { | ||||
| 		return true | ||||
| 	} | ||||
| 	return i != 0 && (*cu)[i-1].RangeMax() >= id.RangeMin() | ||||
| } | ||||
| 
 | ||||
| // ContainsCellID reports whether the CellUnion contains the given cell ID. | ||||
| // Containment is defined with respect to regions, e.g. a cell contains its 4 children. | ||||
| // | ||||
| // CAVEAT: If you have constructed a non-normalized CellUnion, note that groups | ||||
| // of 4 child cells are *not* considered to contain their parent cell. To get | ||||
| // this behavior you must use one of the call Normalize() explicitly. | ||||
| func (cu *CellUnion) ContainsCellID(id CellID) bool { | ||||
| 	// Find index of array item that occurs directly after our probe cell: | ||||
| 	i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] }) | ||||
| 
 | ||||
| 	if i != len(*cu) && (*cu)[i].RangeMin() <= id { | ||||
| 		return true | ||||
| 	} | ||||
| 	return i != 0 && (*cu)[i-1].RangeMax() >= id | ||||
| } | ||||
| 
 | ||||
| // Denormalize replaces this CellUnion with an expanded version of the | ||||
| // CellUnion where any cell whose level is less than minLevel or where | ||||
| // (level - minLevel) is not a multiple of levelMod is replaced by its | ||||
| // children, until either both of these conditions are satisfied or the | ||||
| // maximum level is reached. | ||||
| func (cu *CellUnion) Denormalize(minLevel, levelMod int) { | ||||
| 	var denorm CellUnion | ||||
| 	for _, id := range *cu { | ||||
| 		level := id.Level() | ||||
| 		newLevel := level | ||||
| 		if newLevel < minLevel { | ||||
| 			newLevel = minLevel | ||||
| 		} | ||||
| 		if levelMod > 1 { | ||||
| 			newLevel += (maxLevel - (newLevel - minLevel)) % levelMod | ||||
| 			if newLevel > maxLevel { | ||||
| 				newLevel = maxLevel | ||||
| 			} | ||||
| 		} | ||||
| 		if newLevel == level { | ||||
| 			denorm = append(denorm, id) | ||||
| 		} else { | ||||
| 			end := id.ChildEndAtLevel(newLevel) | ||||
| 			for ci := id.ChildBeginAtLevel(newLevel); ci != end; ci = ci.Next() { | ||||
| 				denorm = append(denorm, ci) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*cu = denorm | ||||
| } | ||||
| 
 | ||||
| // RectBound returns a Rect that bounds this entity. | ||||
| func (cu *CellUnion) RectBound() Rect { | ||||
| 	bound := EmptyRect() | ||||
| 	for _, c := range *cu { | ||||
| 		bound = bound.Union(CellFromCellID(c).RectBound()) | ||||
| 	} | ||||
| 	return bound | ||||
| } | ||||
| 
 | ||||
| // CapBound returns a Cap that bounds this entity. | ||||
| func (cu *CellUnion) CapBound() Cap { | ||||
| 	if len(*cu) == 0 { | ||||
| 		return EmptyCap() | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the approximate centroid of the region. This won't produce the | ||||
| 	// bounding cap of minimal area, but it should be close enough. | ||||
| 	var centroid Point | ||||
| 
 | ||||
| 	for _, ci := range *cu { | ||||
| 		area := AvgAreaMetric.Value(ci.Level()) | ||||
| 		centroid = Point{centroid.Add(ci.Point().Mul(area))} | ||||
| 	} | ||||
| 
 | ||||
| 	if zero := (Point{}); centroid == zero { | ||||
| 		centroid = PointFromCoords(1, 0, 0) | ||||
| 	} else { | ||||
| 		centroid = Point{centroid.Normalize()} | ||||
| 	} | ||||
| 
 | ||||
| 	// Use the centroid as the cap axis, and expand the cap angle so that it | ||||
| 	// contains the bounding caps of all the individual cells.  Note that it is | ||||
| 	// *not* sufficient to just bound all the cell vertices because the bounding | ||||
| 	// cap may be concave (i.e. cover more than one hemisphere). | ||||
| 	c := CapFromPoint(centroid) | ||||
| 	for _, ci := range *cu { | ||||
| 		c = c.AddCap(CellFromCellID(ci).CapBound()) | ||||
| 	} | ||||
| 
 | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether this cell union contains the given cell. | ||||
| func (cu *CellUnion) ContainsCell(c Cell) bool { | ||||
| 	return cu.ContainsCellID(c.id) | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether this cell union intersects the given cell. | ||||
| func (cu *CellUnion) IntersectsCell(c Cell) bool { | ||||
| 	return cu.IntersectsCellID(c.id) | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether this cell union contains the given point. | ||||
| func (cu *CellUnion) ContainsPoint(p Point) bool { | ||||
| 	return cu.ContainsCell(CellFromPoint(p)) | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the CellUnion. | ||||
| func (cu *CellUnion) CellUnionBound() []CellID { | ||||
| 	return cu.CapBound().CellUnionBound() | ||||
| } | ||||
| 
 | ||||
| // LeafCellsCovered reports the number of leaf cells covered by this cell union. | ||||
| // This will be no more than 6*2^60 for the whole sphere. | ||||
| func (cu *CellUnion) LeafCellsCovered() int64 { | ||||
| 	var numLeaves int64 | ||||
| 	for _, c := range *cu { | ||||
| 		numLeaves += 1 << uint64((maxLevel-int64(c.Level()))<<1) | ||||
| 	} | ||||
| 	return numLeaves | ||||
| } | ||||
| 
 | ||||
| // Returns true if the given four cells have a common parent. | ||||
| // This requires that the four CellIDs are distinct. | ||||
| func areSiblings(a, b, c, d CellID) bool { | ||||
| 	// A necessary (but not sufficient) condition is that the XOR of the | ||||
| 	// four cell IDs must be zero. This is also very fast to test. | ||||
| 	if (a ^ b ^ c) != d { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Now we do a slightly more expensive but exact test. First, compute a | ||||
| 	// mask that blocks out the two bits that encode the child position of | ||||
| 	// "id" with respect to its parent, then check that the other three | ||||
| 	// children all agree with "mask". | ||||
| 	mask := d.lsb() << 1 | ||||
| 	mask = ^(mask + (mask << 1)) | ||||
| 	idMasked := (uint64(d) & mask) | ||||
| 	return ((uint64(a)&mask) == idMasked && | ||||
| 		(uint64(b)&mask) == idMasked && | ||||
| 		(uint64(c)&mask) == idMasked && | ||||
| 		!d.isFace()) | ||||
| } | ||||
| 
 | ||||
| // Contains reports whether this CellUnion contains all of the CellIDs of the given CellUnion. | ||||
| func (cu *CellUnion) Contains(o CellUnion) bool { | ||||
| 	// TODO(roberts): Investigate alternatives such as divide-and-conquer | ||||
| 	// or alternating-skip-search that may be significantly faster in both | ||||
| 	// the average and worst case. This applies to Intersects as well. | ||||
| 	for _, id := range o { | ||||
| 		if !cu.ContainsCellID(id) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Intersects reports whether this CellUnion intersects any of the CellIDs of the given CellUnion. | ||||
| func (cu *CellUnion) Intersects(o CellUnion) bool { | ||||
| 	for _, c := range *cu { | ||||
| 		if o.IntersectsCellID(c) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // lowerBound returns the index in this CellUnion to the first element whose value | ||||
| // is not considered to go before the given cell id. (i.e., either it is equivalent | ||||
| // or comes after the given id.) If there is no match, then end is returned. | ||||
| func (cu *CellUnion) lowerBound(begin, end int, id CellID) int { | ||||
| 	for i := begin; i < end; i++ { | ||||
| 		if (*cu)[i] >= id { | ||||
| 			return i | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return end | ||||
| } | ||||
| 
 | ||||
| // cellUnionDifferenceInternal adds the difference between the CellID and the union to | ||||
| // the result CellUnion. If they intersect but the difference is non-empty, it divides | ||||
| // and conquers. | ||||
| func (cu *CellUnion) cellUnionDifferenceInternal(id CellID, other *CellUnion) { | ||||
| 	if !other.IntersectsCellID(id) { | ||||
| 		(*cu) = append((*cu), id) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if !other.ContainsCellID(id) { | ||||
| 		for _, child := range id.Children() { | ||||
| 			cu.cellUnionDifferenceInternal(child, other) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ExpandAtLevel expands this CellUnion by adding a rim of cells at expandLevel | ||||
| // around the unions boundary. | ||||
| // | ||||
| // For each cell c in the union, we add all cells at level | ||||
| // expandLevel that abut c. There are typically eight of those | ||||
| // (four edge-abutting and four sharing a vertex). However, if c is | ||||
| // finer than expandLevel, we add all cells abutting | ||||
| // c.Parent(expandLevel) as well as c.Parent(expandLevel) itself, | ||||
| // as an expandLevel cell rarely abuts a smaller cell. | ||||
| // | ||||
| // Note that the size of the output is exponential in | ||||
| // expandLevel. For example, if expandLevel == 20 and the input | ||||
| // has a cell at level 10, there will be on the order of 4000 | ||||
| // adjacent cells in the output. For most applications the | ||||
| // ExpandByRadius method below is easier to use. | ||||
| func (cu *CellUnion) ExpandAtLevel(level int) { | ||||
| 	var output CellUnion | ||||
| 	levelLsb := lsbForLevel(level) | ||||
| 	for i := len(*cu) - 1; i >= 0; i-- { | ||||
| 		id := (*cu)[i] | ||||
| 		if id.lsb() < levelLsb { | ||||
| 			id = id.Parent(level) | ||||
| 			// Optimization: skip over any cells contained by this one. This is | ||||
| 			// especially important when very small regions are being expanded. | ||||
| 			for i > 0 && id.Contains((*cu)[i-1]) { | ||||
| 				i-- | ||||
| 			} | ||||
| 		} | ||||
| 		output = append(output, id) | ||||
| 		output = append(output, id.AllNeighbors(level)...) | ||||
| 	} | ||||
| 	sortCellIDs(output) | ||||
| 
 | ||||
| 	*cu = output | ||||
| 	cu.Normalize() | ||||
| } | ||||
| 
 | ||||
| // ExpandByRadius expands this CellUnion such that it contains all points whose | ||||
| // distance to the CellUnion is at most minRadius, but do not use cells that | ||||
| // are more than maxLevelDiff levels higher than the largest cell in the input. | ||||
| // The second parameter controls the tradeoff between accuracy and output size | ||||
| // when a large region is being expanded by a small amount (e.g. expanding Canada | ||||
| // by 1km). For example, if maxLevelDiff == 4 the region will always be expanded | ||||
| // by approximately 1/16 the width of its largest cell. Note that in the worst case, | ||||
| // the number of cells in the output can be up to 4 * (1 + 2 ** maxLevelDiff) times | ||||
| // larger than the number of cells in the input. | ||||
| func (cu *CellUnion) ExpandByRadius(minRadius s1.Angle, maxLevelDiff int) { | ||||
| 	minLevel := maxLevel | ||||
| 	for _, cid := range *cu { | ||||
| 		minLevel = minInt(minLevel, cid.Level()) | ||||
| 	} | ||||
| 
 | ||||
| 	// Find the maximum level such that all cells are at least "minRadius" wide. | ||||
| 	radiusLevel := MinWidthMetric.MaxLevel(minRadius.Radians()) | ||||
| 	if radiusLevel == 0 && minRadius.Radians() > MinWidthMetric.Value(0) { | ||||
| 		// The requested expansion is greater than the width of a face cell. | ||||
| 		// The easiest way to handle this is to expand twice. | ||||
| 		cu.ExpandAtLevel(0) | ||||
| 	} | ||||
| 	cu.ExpandAtLevel(minInt(minLevel+maxLevelDiff, radiusLevel)) | ||||
| } | ||||
| 
 | ||||
| // Equal reports whether the two CellUnions are equal. | ||||
| func (cu CellUnion) Equal(o CellUnion) bool { | ||||
| 	if len(cu) != len(o) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for i := 0; i < len(cu); i++ { | ||||
| 		if cu[i] != o[i] { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // AverageArea returns the average area of this CellUnion. | ||||
| // This is accurate to within a factor of 1.7. | ||||
| func (cu *CellUnion) AverageArea() float64 { | ||||
| 	return AvgAreaMetric.Value(maxLevel) * float64(cu.LeafCellsCovered()) | ||||
| } | ||||
| 
 | ||||
| // ApproxArea returns the approximate area of this CellUnion. This method is accurate | ||||
| // to within 3% percent for all cell sizes and accurate to within 0.1% for cells | ||||
| // at level 5 or higher within the union. | ||||
| func (cu *CellUnion) ApproxArea() float64 { | ||||
| 	var area float64 | ||||
| 	for _, id := range *cu { | ||||
| 		area += CellFromCellID(id).ApproxArea() | ||||
| 	} | ||||
| 	return area | ||||
| } | ||||
| 
 | ||||
| // ExactArea returns the area of this CellUnion as accurately as possible. | ||||
| func (cu *CellUnion) ExactArea() float64 { | ||||
| 	var area float64 | ||||
| 	for _, id := range *cu { | ||||
| 		area += CellFromCellID(id).ExactArea() | ||||
| 	} | ||||
| 	return area | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the CellUnion. | ||||
| func (cu *CellUnion) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	cu.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (cu *CellUnion) encode(e *encoder) { | ||||
| 	e.writeInt8(encodingVersion) | ||||
| 	e.writeInt64(int64(len(*cu))) | ||||
| 	for _, ci := range *cu { | ||||
| 		ci.encode(e) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the CellUnion. | ||||
| func (cu *CellUnion) Decode(r io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(r)} | ||||
| 	cu.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (cu *CellUnion) decode(d *decoder) { | ||||
| 	version := d.readInt8() | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if version != encodingVersion { | ||||
| 		d.err = fmt.Errorf("only version %d is supported", encodingVersion) | ||||
| 		return | ||||
| 	} | ||||
| 	n := d.readInt64() | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	const maxCells = 1000000 | ||||
| 	if n > maxCells { | ||||
| 		d.err = fmt.Errorf("too many cells (%d; max is %d)", n, maxCells) | ||||
| 		return | ||||
| 	} | ||||
| 	*cu = make([]CellID, n) | ||||
| 	for i := range *cu { | ||||
| 		(*cu)[i].decode(d) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										133
									
								
								vendor/github.com/golang/geo/s2/centroids.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										133
									
								
								vendor/github.com/golang/geo/s2/centroids.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,133 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| // There are several notions of the "centroid" of a triangle. First, there | ||||
| // is the planar centroid, which is simply the centroid of the ordinary | ||||
| // (non-spherical) triangle defined by the three vertices. Second, there is | ||||
| // the surface centroid, which is defined as the intersection of the three | ||||
| // medians of the spherical triangle. It is possible to show that this | ||||
| // point is simply the planar centroid projected to the surface of the | ||||
| // sphere. Finally, there is the true centroid (mass centroid), which is | ||||
| // defined as the surface integral over the spherical triangle of (x,y,z) | ||||
| // divided by the triangle area. This is the point that the triangle would | ||||
| // rotate around if it was spinning in empty space. | ||||
| // | ||||
| // The best centroid for most purposes is the true centroid. Unlike the | ||||
| // planar and surface centroids, the true centroid behaves linearly as | ||||
| // regions are added or subtracted. That is, if you split a triangle into | ||||
| // pieces and compute the average of their centroids (weighted by triangle | ||||
| // area), the result equals the centroid of the original triangle. This is | ||||
| // not true of the other centroids. | ||||
| // | ||||
| // Also note that the surface centroid may be nowhere near the intuitive | ||||
| // "center" of a spherical triangle. For example, consider the triangle | ||||
| // with vertices A=(1,eps,0), B=(0,0,1), C=(-1,eps,0) (a quarter-sphere). | ||||
| // The surface centroid of this triangle is at S=(0, 2*eps, 1), which is | ||||
| // within a distance of 2*eps of the vertex B. Note that the median from A | ||||
| // (the segment connecting A to the midpoint of BC) passes through S, since | ||||
| // this is the shortest path connecting the two endpoints. On the other | ||||
| // hand, the true centroid is at M=(0, 0.5, 0.5), which when projected onto | ||||
| // the surface is a much more reasonable interpretation of the "center" of | ||||
| // this triangle. | ||||
| // | ||||
| 
 | ||||
| // TrueCentroid returns the true centroid of the spherical triangle ABC | ||||
| // multiplied by the signed area of spherical triangle ABC. The reasons for | ||||
| // multiplying by the signed area are (1) this is the quantity that needs to be | ||||
| // summed to compute the centroid of a union or difference of triangles, and | ||||
| // (2) it's actually easier to calculate this way. All points must have unit length. | ||||
| // | ||||
| // Note that the result of this function is defined to be Point(0, 0, 0) if | ||||
| // the triangle is degenerate. | ||||
| func TrueCentroid(a, b, c Point) Point { | ||||
| 	// Use Distance to get accurate results for small triangles. | ||||
| 	ra := float64(1) | ||||
| 	if sa := float64(b.Distance(c)); sa != 0 { | ||||
| 		ra = sa / math.Sin(sa) | ||||
| 	} | ||||
| 	rb := float64(1) | ||||
| 	if sb := float64(c.Distance(a)); sb != 0 { | ||||
| 		rb = sb / math.Sin(sb) | ||||
| 	} | ||||
| 	rc := float64(1) | ||||
| 	if sc := float64(a.Distance(b)); sc != 0 { | ||||
| 		rc = sc / math.Sin(sc) | ||||
| 	} | ||||
| 
 | ||||
| 	// Now compute a point M such that: | ||||
| 	// | ||||
| 	//  [Ax Ay Az] [Mx]                       [ra] | ||||
| 	//  [Bx By Bz] [My]  = 0.5 * det(A,B,C) * [rb] | ||||
| 	//  [Cx Cy Cz] [Mz]                       [rc] | ||||
| 	// | ||||
| 	// To improve the numerical stability we subtract the first row (A) from the | ||||
| 	// other two rows; this reduces the cancellation error when A, B, and C are | ||||
| 	// very close together. Then we solve it using Cramer's rule. | ||||
| 	// | ||||
| 	// The result is the true centroid of the triangle multiplied by the | ||||
| 	// triangle's area. | ||||
| 	// | ||||
| 	// This code still isn't as numerically stable as it could be. | ||||
| 	// The biggest potential improvement is to compute B-A and C-A more | ||||
| 	// accurately so that (B-A)x(C-A) is always inside triangle ABC. | ||||
| 	x := r3.Vector{a.X, b.X - a.X, c.X - a.X} | ||||
| 	y := r3.Vector{a.Y, b.Y - a.Y, c.Y - a.Y} | ||||
| 	z := r3.Vector{a.Z, b.Z - a.Z, c.Z - a.Z} | ||||
| 	r := r3.Vector{ra, rb - ra, rc - ra} | ||||
| 
 | ||||
| 	return Point{r3.Vector{y.Cross(z).Dot(r), z.Cross(x).Dot(r), x.Cross(y).Dot(r)}.Mul(0.5)} | ||||
| } | ||||
| 
 | ||||
| // EdgeTrueCentroid returns the true centroid of the spherical geodesic edge AB | ||||
| // multiplied by the length of the edge AB. As with triangles, the true centroid | ||||
| // of a collection of line segments may be computed simply by summing the result | ||||
| // of this method for each segment. | ||||
| // | ||||
| // Note that the planar centroid of a line segment is simply 0.5 * (a + b), | ||||
| // while the surface centroid is (a + b).Normalize(). However neither of | ||||
| // these values is appropriate for computing the centroid of a collection of | ||||
| // edges (such as a polyline). | ||||
| // | ||||
| // Also note that the result of this function is defined to be Point(0, 0, 0) | ||||
| // if the edge is degenerate. | ||||
| func EdgeTrueCentroid(a, b Point) Point { | ||||
| 	// The centroid (multiplied by length) is a vector toward the midpoint | ||||
| 	// of the edge, whose length is twice the sine of half the angle between | ||||
| 	// the two vertices. Defining theta to be this angle, we have: | ||||
| 	vDiff := a.Sub(b.Vector) // Length == 2*sin(theta) | ||||
| 	vSum := a.Add(b.Vector)  // Length == 2*cos(theta) | ||||
| 	sin2 := vDiff.Norm2() | ||||
| 	cos2 := vSum.Norm2() | ||||
| 	if cos2 == 0 { | ||||
| 		return Point{} // Ignore antipodal edges. | ||||
| 	} | ||||
| 	return Point{vSum.Mul(math.Sqrt(sin2 / cos2))} // Length == 2*sin(theta) | ||||
| } | ||||
| 
 | ||||
| // PlanarCentroid returns the centroid of the planar triangle ABC. This can be | ||||
| // normalized to unit length to obtain the "surface centroid" of the corresponding | ||||
| // spherical triangle, i.e. the intersection of the three medians. However, note | ||||
| // that for large spherical triangles the surface centroid may be nowhere near | ||||
| // the intuitive "center". | ||||
| func PlanarCentroid(a, b, c Point) Point { | ||||
| 	return Point{a.Add(b.Vector).Add(c.Vector).Mul(1. / 3)} | ||||
| } | ||||
							
								
								
									
										190
									
								
								vendor/github.com/golang/geo/s2/contains_point_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										190
									
								
								vendor/github.com/golang/geo/s2/contains_point_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,190 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // VertexModel defines whether shapes are considered to contain their vertices. | ||||
| // Note that these definitions differ from the ones used by BooleanOperation. | ||||
| // | ||||
| // Note that points other than vertices are never contained by polylines. | ||||
| // If you want need this behavior, use ClosestEdgeQuery's IsDistanceLess | ||||
| // with a suitable distance threshold instead. | ||||
| type VertexModel int | ||||
| 
 | ||||
| const ( | ||||
| 	// VertexModelOpen means no shapes contain their vertices (not even | ||||
| 	// points). Therefore Contains(Point) returns true if and only if the | ||||
| 	// point is in the interior of some polygon. | ||||
| 	VertexModelOpen VertexModel = iota | ||||
| 
 | ||||
| 	// VertexModelSemiOpen means that polygon point containment is defined | ||||
| 	// such that if several polygons tile the region around a vertex, then | ||||
| 	// exactly one of those polygons contains that vertex. Points and | ||||
| 	// polylines still do not contain any vertices. | ||||
| 	VertexModelSemiOpen | ||||
| 
 | ||||
| 	// VertexModelClosed means all shapes contain their vertices (including | ||||
| 	// points and polylines). | ||||
| 	VertexModelClosed | ||||
| ) | ||||
| 
 | ||||
| // ContainsPointQuery determines whether one or more shapes in a ShapeIndex | ||||
| // contain a given Point. The ShapeIndex may contain any number of points, | ||||
| // polylines, and/or polygons (possibly overlapping). Shape boundaries may be | ||||
| // modeled as Open, SemiOpen, or Closed (this affects whether or not shapes are | ||||
| // considered to contain their vertices). | ||||
| // | ||||
| // This type is not safe for concurrent use. | ||||
| // | ||||
| // However, note that if you need to do a large number of point containment | ||||
| // tests, it is more efficient to re-use the query rather than creating a new | ||||
| // one each time. | ||||
| type ContainsPointQuery struct { | ||||
| 	model VertexModel | ||||
| 	index *ShapeIndex | ||||
| 	iter  *ShapeIndexIterator | ||||
| } | ||||
| 
 | ||||
| // NewContainsPointQuery creates a new instance of the ContainsPointQuery for the index | ||||
| // and given vertex model choice. | ||||
| func NewContainsPointQuery(index *ShapeIndex, model VertexModel) *ContainsPointQuery { | ||||
| 	return &ContainsPointQuery{ | ||||
| 		index: index, | ||||
| 		model: model, | ||||
| 		iter:  index.Iterator(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Contains reports whether any shape in the queries index contains the point p | ||||
| // under the queries vertex model (Open, SemiOpen, or Closed). | ||||
| func (q *ContainsPointQuery) Contains(p Point) bool { | ||||
| 	if !q.iter.LocatePoint(p) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	cell := q.iter.IndexCell() | ||||
| 	for _, clipped := range cell.shapes { | ||||
| 		if q.shapeContains(clipped, q.iter.Center(), p) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // shapeContains reports whether the clippedShape from the iterator's center position contains | ||||
| // the given point. | ||||
| func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Point) bool { | ||||
| 	inside := clipped.containsCenter | ||||
| 	numEdges := clipped.numEdges() | ||||
| 	if numEdges <= 0 { | ||||
| 		return inside | ||||
| 	} | ||||
| 
 | ||||
| 	shape := q.index.Shape(clipped.shapeID) | ||||
| 	if shape.Dimension() != 2 { | ||||
| 		// Points and polylines can be ignored unless the vertex model is Closed. | ||||
| 		if q.model != VertexModelClosed { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		// Otherwise, the point is contained if and only if it matches a vertex. | ||||
| 		for _, edgeID := range clipped.edges { | ||||
| 			edge := shape.Edge(edgeID) | ||||
| 			if edge.V0 == p || edge.V1 == p { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Test containment by drawing a line segment from the cell center to the | ||||
| 	// given point and counting edge crossings. | ||||
| 	crosser := NewEdgeCrosser(center, p) | ||||
| 	for _, edgeID := range clipped.edges { | ||||
| 		edge := shape.Edge(edgeID) | ||||
| 		sign := crosser.CrossingSign(edge.V0, edge.V1) | ||||
| 		if sign == DoNotCross { | ||||
| 			continue | ||||
| 		} | ||||
| 		if sign == MaybeCross { | ||||
| 			// For the Open and Closed models, check whether p is a vertex. | ||||
| 			if q.model != VertexModelSemiOpen && (edge.V0 == p || edge.V1 == p) { | ||||
| 				return (q.model == VertexModelClosed) | ||||
| 			} | ||||
| 			// C++ plays fast and loose with the int <-> bool conversions here. | ||||
| 			if VertexCrossing(crosser.a, crosser.b, edge.V0, edge.V1) { | ||||
| 				sign = Cross | ||||
| 			} else { | ||||
| 				sign = DoNotCross | ||||
| 			} | ||||
| 		} | ||||
| 		inside = inside != (sign == Cross) | ||||
| 	} | ||||
| 
 | ||||
| 	return inside | ||||
| } | ||||
| 
 | ||||
| // ShapeContains reports whether the given shape contains the point under this | ||||
| // queries vertex model (Open, SemiOpen, or Closed). | ||||
| // | ||||
| // This requires the shape belongs to this queries index. | ||||
| func (q *ContainsPointQuery) ShapeContains(shape Shape, p Point) bool { | ||||
| 	if !q.iter.LocatePoint(p) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	clipped := q.iter.IndexCell().findByShapeID(q.index.idForShape(shape)) | ||||
| 	if clipped == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return q.shapeContains(clipped, q.iter.Center(), p) | ||||
| } | ||||
| 
 | ||||
| // shapeVisitorFunc is a type of function that can be called against shaped in an index. | ||||
| type shapeVisitorFunc func(shape Shape) bool | ||||
| 
 | ||||
| // visitContainingShapes visits all shapes in the given index that contain the | ||||
| // given point p, terminating early if the given visitor function returns false, | ||||
| // in which case visitContainingShapes returns false. Each shape is | ||||
| // visited at most once. | ||||
| func (q *ContainsPointQuery) visitContainingShapes(p Point, f shapeVisitorFunc) bool { | ||||
| 	// This function returns false only if the algorithm terminates early | ||||
| 	// because the visitor function returned false. | ||||
| 	if !q.iter.LocatePoint(p) { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	cell := q.iter.IndexCell() | ||||
| 	for _, clipped := range cell.shapes { | ||||
| 		if q.shapeContains(clipped, q.iter.Center(), p) && | ||||
| 			!f(q.index.Shape(clipped.shapeID)) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // ContainingShapes returns a slice of all shapes that contain the given point. | ||||
| func (q *ContainsPointQuery) ContainingShapes(p Point) []Shape { | ||||
| 	var shapes []Shape | ||||
| 	q.visitContainingShapes(p, func(shape Shape) bool { | ||||
| 		shapes = append(shapes, shape) | ||||
| 		return true | ||||
| 	}) | ||||
| 	return shapes | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Remaining methods from C++ | ||||
| // type edgeVisitorFunc func(shape ShapeEdge) bool | ||||
| // func (q *ContainsPointQuery) visitIncidentEdges(p Point, v edgeVisitorFunc) bool | ||||
							
								
								
									
										63
									
								
								vendor/github.com/golang/geo/s2/contains_vertex_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/golang/geo/s2/contains_vertex_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,63 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // ContainsVertexQuery is used to track the edges entering and leaving the | ||||
| // given vertex of a Polygon in order to be able to determine if the point is | ||||
| // contained by the Polygon. | ||||
| // | ||||
| // Point containment is defined according to the semi-open boundary model | ||||
| // which means that if several polygons tile the region around a vertex, | ||||
| // then exactly one of those polygons contains that vertex. | ||||
| type ContainsVertexQuery struct { | ||||
| 	target  Point | ||||
| 	edgeMap map[Point]int | ||||
| } | ||||
| 
 | ||||
| // NewContainsVertexQuery returns a new query for the given vertex whose | ||||
| // containment will be determined. | ||||
| func NewContainsVertexQuery(target Point) *ContainsVertexQuery { | ||||
| 	return &ContainsVertexQuery{ | ||||
| 		target:  target, | ||||
| 		edgeMap: make(map[Point]int), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddEdge adds the edge between target and v with the given direction. | ||||
| // (+1 = outgoing, -1 = incoming, 0 = degenerate). | ||||
| func (q *ContainsVertexQuery) AddEdge(v Point, direction int) { | ||||
| 	q.edgeMap[v] += direction | ||||
| } | ||||
| 
 | ||||
| // ContainsVertex reports a +1 if the target vertex is contained, -1 if it is | ||||
| // not contained, and 0 if the incident edges consisted of matched sibling pairs. | ||||
| func (q *ContainsVertexQuery) ContainsVertex() int { | ||||
| 	// Find the unmatched edge that is immediately clockwise from Ortho(P). | ||||
| 	referenceDir := Point{q.target.Ortho()} | ||||
| 
 | ||||
| 	bestPoint := referenceDir | ||||
| 	bestDir := 0 | ||||
| 
 | ||||
| 	for k, v := range q.edgeMap { | ||||
| 		if v == 0 { | ||||
| 			continue // This is a "matched" edge. | ||||
| 		} | ||||
| 		if OrderedCCW(referenceDir, bestPoint, k, q.target) { | ||||
| 			bestPoint = k | ||||
| 			bestDir = v | ||||
| 		} | ||||
| 	} | ||||
| 	return bestDir | ||||
| } | ||||
							
								
								
									
										258
									
								
								vendor/github.com/golang/geo/s2/convex_hull_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										258
									
								
								vendor/github.com/golang/geo/s2/convex_hull_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,258 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| // ConvexHullQuery builds the convex hull of any collection of points, | ||||
| // polylines, loops, and polygons. It returns a single convex loop. | ||||
| // | ||||
| // The convex hull is defined as the smallest convex region on the sphere that | ||||
| // contains all of your input geometry. Recall that a region is "convex" if | ||||
| // for every pair of points inside the region, the straight edge between them | ||||
| // is also inside the region. In our case, a "straight" edge is a geodesic, | ||||
| // i.e. the shortest path on the sphere between two points. | ||||
| // | ||||
| // Containment of input geometry is defined as follows: | ||||
| // | ||||
| //  - Each input loop and polygon is contained by the convex hull exactly | ||||
| //    (i.e., according to Polygon's Contains(Polygon)). | ||||
| // | ||||
| //  - Each input point is either contained by the convex hull or is a vertex | ||||
| //    of the convex hull. (Recall that S2Loops do not necessarily contain their | ||||
| //    vertices.) | ||||
| // | ||||
| //  - For each input polyline, the convex hull contains all of its vertices | ||||
| //    according to the rule for points above. (The definition of convexity | ||||
| //    then ensures that the convex hull also contains the polyline edges.) | ||||
| // | ||||
| // To use this type, call the various Add... methods to add your input geometry, and | ||||
| // then call ConvexHull. Note that ConvexHull does *not* reset the | ||||
| // state; you can continue adding geometry if desired and compute the convex | ||||
| // hull again. If you want to start from scratch, simply create a new | ||||
| // ConvexHullQuery value. | ||||
| // | ||||
| // This implement Andrew's monotone chain algorithm, which is a variant of the | ||||
| // Graham scan (see https://en.wikipedia.org/wiki/Graham_scan). The time | ||||
| // complexity is O(n log n), and the space required is O(n). In fact only the | ||||
| // call to "sort" takes O(n log n) time; the rest of the algorithm is linear. | ||||
| // | ||||
| // Demonstration of the algorithm and code: | ||||
| // en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain | ||||
| // | ||||
| // This type is not safe for concurrent use. | ||||
| type ConvexHullQuery struct { | ||||
| 	bound  Rect | ||||
| 	points []Point | ||||
| } | ||||
| 
 | ||||
| // NewConvexHullQuery creates a new ConvexHullQuery. | ||||
| func NewConvexHullQuery() *ConvexHullQuery { | ||||
| 	return &ConvexHullQuery{ | ||||
| 		bound: EmptyRect(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddPoint adds the given point to the input geometry. | ||||
| func (q *ConvexHullQuery) AddPoint(p Point) { | ||||
| 	q.bound = q.bound.AddPoint(LatLngFromPoint(p)) | ||||
| 	q.points = append(q.points, p) | ||||
| } | ||||
| 
 | ||||
| // AddPolyline adds the given polyline to the input geometry. | ||||
| func (q *ConvexHullQuery) AddPolyline(p *Polyline) { | ||||
| 	q.bound = q.bound.Union(p.RectBound()) | ||||
| 	q.points = append(q.points, (*p)...) | ||||
| } | ||||
| 
 | ||||
| // AddLoop adds the given loop to the input geometry. | ||||
| func (q *ConvexHullQuery) AddLoop(l *Loop) { | ||||
| 	q.bound = q.bound.Union(l.RectBound()) | ||||
| 	if l.isEmptyOrFull() { | ||||
| 		return | ||||
| 	} | ||||
| 	q.points = append(q.points, l.vertices...) | ||||
| } | ||||
| 
 | ||||
| // AddPolygon adds the given polygon to the input geometry. | ||||
| func (q *ConvexHullQuery) AddPolygon(p *Polygon) { | ||||
| 	q.bound = q.bound.Union(p.RectBound()) | ||||
| 	for _, l := range p.loops { | ||||
| 		// Only loops at depth 0 can contribute to the convex hull. | ||||
| 		if l.depth == 0 { | ||||
| 			q.AddLoop(l) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CapBound returns a bounding cap for the input geometry provided. | ||||
| // | ||||
| // Note that this method does not clear the geometry; you can continue | ||||
| // adding to it and call this method again if desired. | ||||
| func (q *ConvexHullQuery) CapBound() Cap { | ||||
| 	// We keep track of a rectangular bound rather than a spherical cap because | ||||
| 	// it is easy to compute a tight bound for a union of rectangles, whereas it | ||||
| 	// is quite difficult to compute a tight bound around a union of caps. | ||||
| 	// Also, polygons and polylines implement CapBound() in terms of | ||||
| 	// RectBound() for this same reason, so it is much better to keep track | ||||
| 	// of a rectangular bound as we go along and convert it at the end. | ||||
| 	// | ||||
| 	// TODO(roberts): We could compute an optimal bound by implementing Welzl's | ||||
| 	// algorithm. However we would still need to have special handling of loops | ||||
| 	// and polygons, since if a loop spans more than 180 degrees in any | ||||
| 	// direction (i.e., if it contains two antipodal points), then it is not | ||||
| 	// enough just to bound its vertices. In this case the only convex bounding | ||||
| 	// cap is FullCap(), and the only convex bounding loop is the full loop. | ||||
| 	return q.bound.CapBound() | ||||
| } | ||||
| 
 | ||||
| // ConvexHull returns a Loop representing the convex hull of the input geometry provided. | ||||
| // | ||||
| // If there is no geometry, this method returns an empty loop containing no | ||||
| // points. | ||||
| // | ||||
| // If the geometry spans more than half of the sphere, this method returns a | ||||
| // full loop containing the entire sphere. | ||||
| // | ||||
| // If the geometry contains 1 or 2 points, or a single edge, this method | ||||
| // returns a very small loop consisting of three vertices (which are a | ||||
| // superset of the input vertices). | ||||
| // | ||||
| // Note that this method does not clear the geometry; you can continue | ||||
| // adding to the query and call this method again. | ||||
| func (q *ConvexHullQuery) ConvexHull() *Loop { | ||||
| 	c := q.CapBound() | ||||
| 	if c.Height() >= 1 { | ||||
| 		// The bounding cap is not convex. The current bounding cap | ||||
| 		// implementation is not optimal, but nevertheless it is likely that the | ||||
| 		// input geometry itself is not contained by any convex polygon. In any | ||||
| 		// case, we need a convex bounding cap to proceed with the algorithm below | ||||
| 		// (in order to construct a point "origin" that is definitely outside the | ||||
| 		// convex hull). | ||||
| 		return FullLoop() | ||||
| 	} | ||||
| 
 | ||||
| 	// Remove duplicates. We need to do this before checking whether there are | ||||
| 	// fewer than 3 points. | ||||
| 	x := make(map[Point]bool) | ||||
| 	r, w := 0, 0 // read/write indexes | ||||
| 	for ; r < len(q.points); r++ { | ||||
| 		if x[q.points[r]] { | ||||
| 			continue | ||||
| 		} | ||||
| 		q.points[w] = q.points[r] | ||||
| 		x[q.points[r]] = true | ||||
| 		w++ | ||||
| 	} | ||||
| 	q.points = q.points[:w] | ||||
| 
 | ||||
| 	// This code implements Andrew's monotone chain algorithm, which is a simple | ||||
| 	// variant of the Graham scan. Rather than sorting by x-coordinate, instead | ||||
| 	// we sort the points in CCW order around an origin O such that all points | ||||
| 	// are guaranteed to be on one side of some geodesic through O. This | ||||
| 	// ensures that as we scan through the points, each new point can only | ||||
| 	// belong at the end of the chain (i.e., the chain is monotone in terms of | ||||
| 	// the angle around O from the starting point). | ||||
| 	origin := Point{c.Center().Ortho()} | ||||
| 	sort.Slice(q.points, func(i, j int) bool { | ||||
| 		return RobustSign(origin, q.points[i], q.points[j]) == CounterClockwise | ||||
| 	}) | ||||
| 
 | ||||
| 	// Special cases for fewer than 3 points. | ||||
| 	switch len(q.points) { | ||||
| 	case 0: | ||||
| 		return EmptyLoop() | ||||
| 	case 1: | ||||
| 		return singlePointLoop(q.points[0]) | ||||
| 	case 2: | ||||
| 		return singleEdgeLoop(q.points[0], q.points[1]) | ||||
| 	} | ||||
| 
 | ||||
| 	// Generate the lower and upper halves of the convex hull. Each half | ||||
| 	// consists of the maximal subset of vertices such that the edge chain | ||||
| 	// makes only left (CCW) turns. | ||||
| 	lower := q.monotoneChain() | ||||
| 
 | ||||
| 	// reverse the points | ||||
| 	for left, right := 0, len(q.points)-1; left < right; left, right = left+1, right-1 { | ||||
| 		q.points[left], q.points[right] = q.points[right], q.points[left] | ||||
| 	} | ||||
| 	upper := q.monotoneChain() | ||||
| 
 | ||||
| 	// Remove the duplicate vertices and combine the chains. | ||||
| 	lower = lower[:len(lower)-1] | ||||
| 	upper = upper[:len(upper)-1] | ||||
| 	lower = append(lower, upper...) | ||||
| 
 | ||||
| 	return LoopFromPoints(lower) | ||||
| } | ||||
| 
 | ||||
| // monotoneChain iterates through the points, selecting the maximal subset of points | ||||
| // such that the edge chain makes only left (CCW) turns. | ||||
| func (q *ConvexHullQuery) monotoneChain() []Point { | ||||
| 	var output []Point | ||||
| 	for _, p := range q.points { | ||||
| 		// Remove any points that would cause the chain to make a clockwise turn. | ||||
| 		for len(output) >= 2 && RobustSign(output[len(output)-2], output[len(output)-1], p) != CounterClockwise { | ||||
| 			output = output[:len(output)-1] | ||||
| 		} | ||||
| 		output = append(output, p) | ||||
| 	} | ||||
| 	return output | ||||
| } | ||||
| 
 | ||||
| // singlePointLoop constructs a 3-vertex polygon consisting of "p" and two nearby | ||||
| // vertices. Note that ContainsPoint(p) may be false for the resulting loop. | ||||
| func singlePointLoop(p Point) *Loop { | ||||
| 	const offset = 1e-15 | ||||
| 	d0 := p.Ortho() | ||||
| 	d1 := p.Cross(d0) | ||||
| 	vertices := []Point{ | ||||
| 		p, | ||||
| 		{p.Add(d0.Mul(offset)).Normalize()}, | ||||
| 		{p.Add(d1.Mul(offset)).Normalize()}, | ||||
| 	} | ||||
| 	return LoopFromPoints(vertices) | ||||
| } | ||||
| 
 | ||||
| // singleEdgeLoop constructs a loop consisting of the two vertices and their midpoint. | ||||
| func singleEdgeLoop(a, b Point) *Loop { | ||||
| 	// If the points are exactly antipodal we return the full loop. | ||||
| 	// | ||||
| 	// Note that we could use the code below even in this case (which would | ||||
| 	// return a zero-area loop that follows the edge AB), except that (1) the | ||||
| 	// direction of AB is defined using symbolic perturbations and therefore is | ||||
| 	// not predictable by ordinary users, and (2) Loop disallows anitpodal | ||||
| 	// adjacent vertices and so we would need to use 4 vertices to define the | ||||
| 	// degenerate loop. (Note that the Loop antipodal vertex restriction is | ||||
| 	// historical and now could easily be removed, however it would still have | ||||
| 	// the problem that the edge direction is not easily predictable.) | ||||
| 	if a.Add(b.Vector) == (r3.Vector{}) { | ||||
| 		return FullLoop() | ||||
| 	} | ||||
| 
 | ||||
| 	// Construct a loop consisting of the two vertices and their midpoint.  We | ||||
| 	// use Interpolate() to ensure that the midpoint is very close to | ||||
| 	// the edge even when its endpoints nearly antipodal. | ||||
| 	vertices := []Point{a, b, Interpolate(0.5, a, b)} | ||||
| 	loop := LoopFromPoints(vertices) | ||||
| 	// The resulting loop may be clockwise, so invert it if necessary. | ||||
| 	loop.Normalize() | ||||
| 	return loop | ||||
| } | ||||
							
								
								
									
										409
									
								
								vendor/github.com/golang/geo/s2/crossing_edge_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										409
									
								
								vendor/github.com/golang/geo/s2/crossing_edge_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,409 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r2" | ||||
| ) | ||||
| 
 | ||||
| // CrossingEdgeQuery is used to find the Edge IDs of Shapes that are crossed by | ||||
| // a given edge(s). | ||||
| // | ||||
| // Note that if you need to query many edges, it is more efficient to declare | ||||
| // a single CrossingEdgeQuery instance and reuse it. | ||||
| // | ||||
| // If you want to find *all* the pairs of crossing edges, it is more efficient to | ||||
| // use the not yet implemented VisitCrossings in shapeutil. | ||||
| type CrossingEdgeQuery struct { | ||||
| 	index *ShapeIndex | ||||
| 
 | ||||
| 	// temporary values used while processing a query. | ||||
| 	a, b r2.Point | ||||
| 	iter *ShapeIndexIterator | ||||
| 
 | ||||
| 	// candidate cells generated when finding crossings. | ||||
| 	cells []*ShapeIndexCell | ||||
| } | ||||
| 
 | ||||
| // NewCrossingEdgeQuery creates a CrossingEdgeQuery for the given index. | ||||
| func NewCrossingEdgeQuery(index *ShapeIndex) *CrossingEdgeQuery { | ||||
| 	c := &CrossingEdgeQuery{ | ||||
| 		index: index, | ||||
| 		iter:  index.Iterator(), | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // Crossings returns the set of edge of the shape S that intersect the given edge AB. | ||||
| // If the CrossingType is Interior, then only intersections at a point interior to both | ||||
| // edges are reported, while if it is CrossingTypeAll then edges that share a vertex | ||||
| // are also reported. | ||||
| func (c *CrossingEdgeQuery) Crossings(a, b Point, shape Shape, crossType CrossingType) []int { | ||||
| 	edges := c.candidates(a, b, shape) | ||||
| 	if len(edges) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	crosser := NewEdgeCrosser(a, b) | ||||
| 	out := 0 | ||||
| 	n := len(edges) | ||||
| 
 | ||||
| 	for in := 0; in < n; in++ { | ||||
| 		b := shape.Edge(edges[in]) | ||||
| 		sign := crosser.CrossingSign(b.V0, b.V1) | ||||
| 		if crossType == CrossingTypeAll && (sign == MaybeCross || sign == Cross) || crossType != CrossingTypeAll && sign == Cross { | ||||
| 			edges[out] = edges[in] | ||||
| 			out++ | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if out < n { | ||||
| 		edges = edges[0:out] | ||||
| 	} | ||||
| 	return edges | ||||
| } | ||||
| 
 | ||||
| // EdgeMap stores a sorted set of edge ids for each shape. | ||||
| type EdgeMap map[Shape][]int | ||||
| 
 | ||||
| // CrossingsEdgeMap returns the set of all edges in the index that intersect the given | ||||
| // edge AB. If crossType is CrossingTypeInterior, then only intersections at a | ||||
| // point interior to both edges are reported, while if it is CrossingTypeAll | ||||
| // then edges that share a vertex are also reported. | ||||
| // | ||||
| // The edges are returned as a mapping from shape to the edges of that shape | ||||
| // that intersect AB. Every returned shape has at least one crossing edge. | ||||
| func (c *CrossingEdgeQuery) CrossingsEdgeMap(a, b Point, crossType CrossingType) EdgeMap { | ||||
| 	edgeMap := c.candidatesEdgeMap(a, b) | ||||
| 	if len(edgeMap) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	crosser := NewEdgeCrosser(a, b) | ||||
| 	for shape, edges := range edgeMap { | ||||
| 		out := 0 | ||||
| 		n := len(edges) | ||||
| 		for in := 0; in < n; in++ { | ||||
| 			edge := shape.Edge(edges[in]) | ||||
| 			sign := crosser.CrossingSign(edge.V0, edge.V1) | ||||
| 			if (crossType == CrossingTypeAll && (sign == MaybeCross || sign == Cross)) || (crossType != CrossingTypeAll && sign == Cross) { | ||||
| 				edgeMap[shape][out] = edges[in] | ||||
| 				out++ | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if out == 0 { | ||||
| 			delete(edgeMap, shape) | ||||
| 		} else { | ||||
| 			if out < n { | ||||
| 				edgeMap[shape] = edgeMap[shape][0:out] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return edgeMap | ||||
| } | ||||
| 
 | ||||
| // candidates returns a superset of the edges of the given shape that intersect | ||||
| // the edge AB. | ||||
| func (c *CrossingEdgeQuery) candidates(a, b Point, shape Shape) []int { | ||||
| 	var edges []int | ||||
| 
 | ||||
| 	// For small loops it is faster to use brute force. The threshold below was | ||||
| 	// determined using benchmarks. | ||||
| 	const maxBruteForceEdges = 27 | ||||
| 	maxEdges := shape.NumEdges() | ||||
| 	if maxEdges <= maxBruteForceEdges { | ||||
| 		edges = make([]int, maxEdges) | ||||
| 		for i := 0; i < maxEdges; i++ { | ||||
| 			edges[i] = i | ||||
| 		} | ||||
| 		return edges | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the set of index cells intersected by the query edge. | ||||
| 	c.getCellsForEdge(a, b) | ||||
| 	if len(c.cells) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Gather all the edges that intersect those cells and sort them. | ||||
| 	// TODO(roberts): Shapes don't track their ID, so we need to range over | ||||
| 	// the index to find the ID manually. | ||||
| 	var shapeID int32 | ||||
| 	for k, v := range c.index.shapes { | ||||
| 		if v == shape { | ||||
| 			shapeID = k | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, cell := range c.cells { | ||||
| 		if cell == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		clipped := cell.findByShapeID(shapeID) | ||||
| 		if clipped == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		edges = append(edges, clipped.edges...) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(c.cells) > 1 { | ||||
| 		edges = uniqueInts(edges) | ||||
| 	} | ||||
| 
 | ||||
| 	return edges | ||||
| } | ||||
| 
 | ||||
| // uniqueInts returns the sorted uniqued values from the given input. | ||||
| func uniqueInts(in []int) []int { | ||||
| 	var edges []int | ||||
| 	m := make(map[int]bool) | ||||
| 	for _, i := range in { | ||||
| 		if m[i] { | ||||
| 			continue | ||||
| 		} | ||||
| 		m[i] = true | ||||
| 		edges = append(edges, i) | ||||
| 	} | ||||
| 	sort.Ints(edges) | ||||
| 	return edges | ||||
| } | ||||
| 
 | ||||
| // candidatesEdgeMap returns a map from shapes to the superse of edges for that | ||||
| // shape that intersect the edge AB. | ||||
| // | ||||
| // CAVEAT: This method may return shapes that have an empty set of candidate edges. | ||||
| // However the return value is non-empty only if at least one shape has a candidate edge. | ||||
| func (c *CrossingEdgeQuery) candidatesEdgeMap(a, b Point) EdgeMap { | ||||
| 	edgeMap := make(EdgeMap) | ||||
| 
 | ||||
| 	// If there are only a few edges then it's faster to use brute force. We | ||||
| 	// only bother with this optimization when there is a single shape. | ||||
| 	if len(c.index.shapes) == 1 { | ||||
| 		// Typically this method is called many times, so it is worth checking | ||||
| 		// whether the edge map is empty or already consists of a single entry for | ||||
| 		// this shape, and skip clearing edge map in that case. | ||||
| 		shape := c.index.Shape(0) | ||||
| 
 | ||||
| 		// Note that we leave the edge map non-empty even if there are no candidates | ||||
| 		// (i.e., there is a single entry with an empty set of edges). | ||||
| 		edgeMap[shape] = c.candidates(a, b, shape) | ||||
| 		return edgeMap | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the set of index cells intersected by the query edge. | ||||
| 	c.getCellsForEdge(a, b) | ||||
| 	if len(c.cells) == 0 { | ||||
| 		return edgeMap | ||||
| 	} | ||||
| 
 | ||||
| 	// Gather all the edges that intersect those cells and sort them. | ||||
| 	for _, cell := range c.cells { | ||||
| 		for _, clipped := range cell.shapes { | ||||
| 			s := c.index.Shape(clipped.shapeID) | ||||
| 			for j := 0; j < clipped.numEdges(); j++ { | ||||
| 				edgeMap[s] = append(edgeMap[s], clipped.edges[j]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(c.cells) > 1 { | ||||
| 		for s, edges := range edgeMap { | ||||
| 			edgeMap[s] = uniqueInts(edges) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return edgeMap | ||||
| } | ||||
| 
 | ||||
| // getCells returns the set of ShapeIndexCells that might contain edges intersecting | ||||
| // the edge AB in the given cell root. This method is used primarily by loop and shapeutil. | ||||
| func (c *CrossingEdgeQuery) getCells(a, b Point, root *PaddedCell) []*ShapeIndexCell { | ||||
| 	aUV, bUV, ok := ClipToFace(a, b, root.id.Face()) | ||||
| 	if ok { | ||||
| 		c.a = aUV | ||||
| 		c.b = bUV | ||||
| 		edgeBound := r2.RectFromPoints(c.a, c.b) | ||||
| 		if root.Bound().Intersects(edgeBound) { | ||||
| 			c.computeCellsIntersected(root, edgeBound) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(c.cells) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return c.cells | ||||
| } | ||||
| 
 | ||||
| // getCellsForEdge populates the cells field to the set of index cells intersected by an edge AB. | ||||
| func (c *CrossingEdgeQuery) getCellsForEdge(a, b Point) { | ||||
| 	c.cells = nil | ||||
| 
 | ||||
| 	segments := FaceSegments(a, b) | ||||
| 	for _, segment := range segments { | ||||
| 		c.a = segment.a | ||||
| 		c.b = segment.b | ||||
| 
 | ||||
| 		// Optimization: rather than always starting the recursive subdivision at | ||||
| 		// the top level face cell, instead we start at the smallest S2CellId that | ||||
| 		// contains the edge (the edge root cell). This typically lets us skip | ||||
| 		// quite a few levels of recursion since most edges are short. | ||||
| 		edgeBound := r2.RectFromPoints(c.a, c.b) | ||||
| 		pcell := PaddedCellFromCellID(CellIDFromFace(segment.face), 0) | ||||
| 		edgeRoot := pcell.ShrinkToFit(edgeBound) | ||||
| 
 | ||||
| 		// Now we need to determine how the edge root cell is related to the cells | ||||
| 		// in the spatial index (cellMap). There are three cases: | ||||
| 		// | ||||
| 		//  1. edgeRoot is an index cell or is contained within an index cell. | ||||
| 		//     In this case we only need to look at the contents of that cell. | ||||
| 		//  2. edgeRoot is subdivided into one or more index cells. In this case | ||||
| 		//     we recursively subdivide to find the cells intersected by AB. | ||||
| 		//  3. edgeRoot does not intersect any index cells. In this case there | ||||
| 		//     is nothing to do. | ||||
| 		relation := c.iter.LocateCellID(edgeRoot) | ||||
| 		if relation == Indexed { | ||||
| 			// edgeRoot is an index cell or is contained by an index cell (case 1). | ||||
| 			c.cells = append(c.cells, c.iter.IndexCell()) | ||||
| 		} else if relation == Subdivided { | ||||
| 			// edgeRoot is subdivided into one or more index cells (case 2). We | ||||
| 			// find the cells intersected by AB using recursive subdivision. | ||||
| 			if !edgeRoot.isFace() { | ||||
| 				pcell = PaddedCellFromCellID(edgeRoot, 0) | ||||
| 			} | ||||
| 			c.computeCellsIntersected(pcell, edgeBound) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // computeCellsIntersected computes the index cells intersected by the current | ||||
| // edge that are descendants of pcell and adds them to this queries set of cells. | ||||
| func (c *CrossingEdgeQuery) computeCellsIntersected(pcell *PaddedCell, edgeBound r2.Rect) { | ||||
| 
 | ||||
| 	c.iter.seek(pcell.id.RangeMin()) | ||||
| 	if c.iter.Done() || c.iter.CellID() > pcell.id.RangeMax() { | ||||
| 		// The index does not contain pcell or any of its descendants. | ||||
| 		return | ||||
| 	} | ||||
| 	if c.iter.CellID() == pcell.id { | ||||
| 		// The index contains this cell exactly. | ||||
| 		c.cells = append(c.cells, c.iter.IndexCell()) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, split the edge among the four children of pcell. | ||||
| 	center := pcell.Middle().Lo() | ||||
| 
 | ||||
| 	if edgeBound.X.Hi < center.X { | ||||
| 		// Edge is entirely contained in the two left children. | ||||
| 		c.clipVAxis(edgeBound, center.Y, 0, pcell) | ||||
| 		return | ||||
| 	} else if edgeBound.X.Lo >= center.X { | ||||
| 		// Edge is entirely contained in the two right children. | ||||
| 		c.clipVAxis(edgeBound, center.Y, 1, pcell) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	childBounds := c.splitUBound(edgeBound, center.X) | ||||
| 	if edgeBound.Y.Hi < center.Y { | ||||
| 		// Edge is entirely contained in the two lower children. | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 0, 0), childBounds[0]) | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 1, 0), childBounds[1]) | ||||
| 	} else if edgeBound.Y.Lo >= center.Y { | ||||
| 		// Edge is entirely contained in the two upper children. | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 0, 1), childBounds[0]) | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 1, 1), childBounds[1]) | ||||
| 	} else { | ||||
| 		// The edge bound spans all four children. The edge itself intersects | ||||
| 		// at most three children (since no padding is being used). | ||||
| 		c.clipVAxis(childBounds[0], center.Y, 0, pcell) | ||||
| 		c.clipVAxis(childBounds[1], center.Y, 1, pcell) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // clipVAxis computes the intersected cells recursively for a given padded cell. | ||||
| // Given either the left (i=0) or right (i=1) side of a padded cell pcell, | ||||
| // determine whether the current edge intersects the lower child, upper child, | ||||
| // or both children, and call c.computeCellsIntersected recursively on those children. | ||||
| // The center is the v-coordinate at the center of pcell. | ||||
| func (c *CrossingEdgeQuery) clipVAxis(edgeBound r2.Rect, center float64, i int, pcell *PaddedCell) { | ||||
| 	if edgeBound.Y.Hi < center { | ||||
| 		// Edge is entirely contained in the lower child. | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 0), edgeBound) | ||||
| 	} else if edgeBound.Y.Lo >= center { | ||||
| 		// Edge is entirely contained in the upper child. | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 1), edgeBound) | ||||
| 	} else { | ||||
| 		// The edge intersects both children. | ||||
| 		childBounds := c.splitVBound(edgeBound, center) | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 0), childBounds[0]) | ||||
| 		c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 1), childBounds[1]) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // splitUBound returns the bound for two children as a result of spliting the | ||||
| // current edge at the given value U. | ||||
| func (c *CrossingEdgeQuery) splitUBound(edgeBound r2.Rect, u float64) [2]r2.Rect { | ||||
| 	v := edgeBound.Y.ClampPoint(interpolateFloat64(u, c.a.X, c.b.X, c.a.Y, c.b.Y)) | ||||
| 	// diag indicates which diagonal of the bounding box is spanned by AB: | ||||
| 	// it is 0 if AB has positive slope, and 1 if AB has negative slope. | ||||
| 	var diag int | ||||
| 	if (c.a.X > c.b.X) != (c.a.Y > c.b.Y) { | ||||
| 		diag = 1 | ||||
| 	} | ||||
| 	return splitBound(edgeBound, 0, diag, u, v) | ||||
| } | ||||
| 
 | ||||
| // splitVBound returns the bound for two children as a result of spliting the | ||||
| // current edge into two child edges at the given value V. | ||||
| func (c *CrossingEdgeQuery) splitVBound(edgeBound r2.Rect, v float64) [2]r2.Rect { | ||||
| 	u := edgeBound.X.ClampPoint(interpolateFloat64(v, c.a.Y, c.b.Y, c.a.X, c.b.X)) | ||||
| 	var diag int | ||||
| 	if (c.a.X > c.b.X) != (c.a.Y > c.b.Y) { | ||||
| 		diag = 1 | ||||
| 	} | ||||
| 	return splitBound(edgeBound, diag, 0, u, v) | ||||
| } | ||||
| 
 | ||||
| // splitBound returns the bounds for the two childrenn as a result of spliting | ||||
| // the current edge into two child edges at the given point (u,v). uEnd and vEnd | ||||
| // indicate which bound endpoints of the first child will be updated. | ||||
| func splitBound(edgeBound r2.Rect, uEnd, vEnd int, u, v float64) [2]r2.Rect { | ||||
| 	var childBounds = [2]r2.Rect{ | ||||
| 		edgeBound, | ||||
| 		edgeBound, | ||||
| 	} | ||||
| 
 | ||||
| 	if uEnd == 1 { | ||||
| 		childBounds[0].X.Lo = u | ||||
| 		childBounds[1].X.Hi = u | ||||
| 	} else { | ||||
| 		childBounds[0].X.Hi = u | ||||
| 		childBounds[1].X.Lo = u | ||||
| 	} | ||||
| 
 | ||||
| 	if vEnd == 1 { | ||||
| 		childBounds[0].Y.Lo = v | ||||
| 		childBounds[1].Y.Hi = v | ||||
| 	} else { | ||||
| 		childBounds[0].Y.Hi = v | ||||
| 		childBounds[1].Y.Lo = v | ||||
| 	} | ||||
| 
 | ||||
| 	return childBounds | ||||
| } | ||||
							
								
								
									
										149
									
								
								vendor/github.com/golang/geo/s2/distance_target.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										149
									
								
								vendor/github.com/golang/geo/s2/distance_target.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,149 +0,0 @@ | |||
| // Copyright 2019 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // The distance interface represents a set of common methods used by algorithms | ||||
| // that compute distances between various S2 types. | ||||
| type distance interface { | ||||
| 	// chordAngle returns this type as a ChordAngle. | ||||
| 	chordAngle() s1.ChordAngle | ||||
| 
 | ||||
| 	// fromChordAngle is used to type convert a ChordAngle to this type. | ||||
| 	// This is to work around needing to be clever in parts of the code | ||||
| 	// where a distanceTarget interface method expects distances, but the | ||||
| 	// user only supplies a ChordAngle, and we need to dynamically cast it | ||||
| 	// to an appropriate distance interface types. | ||||
| 	fromChordAngle(o s1.ChordAngle) distance | ||||
| 
 | ||||
| 	// zero returns a zero distance. | ||||
| 	zero() distance | ||||
| 	// negative returns a value smaller than any valid value. | ||||
| 	negative() distance | ||||
| 	// infinity returns a value larger than any valid value. | ||||
| 	infinity() distance | ||||
| 
 | ||||
| 	// less is similar to the Less method in Sort. To get minimum values, | ||||
| 	// this would be a less than type operation. For maximum, this would | ||||
| 	// be a greater than type operation. | ||||
| 	less(other distance) bool | ||||
| 
 | ||||
| 	// sub subtracts the other value from this one and returns the new value. | ||||
| 	// This is done as a method and not simple mathematical operation to | ||||
| 	// allow closest and furthest to implement this in opposite ways. | ||||
| 	sub(other distance) distance | ||||
| 
 | ||||
| 	// chordAngleBound reports the upper bound on a ChordAngle corresponding | ||||
| 	// to this distance. For example, if distance measures WGS84 ellipsoid | ||||
| 	// distance then the corresponding angle needs to be 0.56% larger. | ||||
| 	chordAngleBound() s1.ChordAngle | ||||
| 
 | ||||
| 	// updateDistance may update the value this distance represents | ||||
| 	// based on the given input. The updated value and a boolean reporting | ||||
| 	// if the value was changed are returned. | ||||
| 	updateDistance(other distance) (distance, bool) | ||||
| } | ||||
| 
 | ||||
| // distanceTarget is an interface that represents a geometric type to which distances | ||||
| // are measured. | ||||
| // | ||||
| // For example, there are implementations that measure distances to a Point, | ||||
| // an Edge, a Cell, a CellUnion, and even to an arbitrary collection of geometry | ||||
| // stored in ShapeIndex. | ||||
| // | ||||
| // The distanceTarget types are provided for the benefit of types that measure | ||||
| // distances and/or find nearby geometry, such as ClosestEdgeQuery, FurthestEdgeQuery, | ||||
| // ClosestPointQuery, and ClosestCellQuery, etc. | ||||
| type distanceTarget interface { | ||||
| 	// capBound returns a Cap that bounds the set of points whose distance to the | ||||
| 	// target is distance.zero(). | ||||
| 	capBound() Cap | ||||
| 
 | ||||
| 	// updateDistanceToPoint updates the distance if the distance to | ||||
| 	// the point P is within than the given dist. | ||||
| 	// The boolean reports if the value was updated. | ||||
| 	updateDistanceToPoint(p Point, dist distance) (distance, bool) | ||||
| 
 | ||||
| 	// updateDistanceToEdge updates the distance if the distance to | ||||
| 	// the edge E is within than the given dist. | ||||
| 	// The boolean reports if the value was updated. | ||||
| 	updateDistanceToEdge(e Edge, dist distance) (distance, bool) | ||||
| 
 | ||||
| 	// updateDistanceToCell updates the distance if the distance to the cell C | ||||
| 	// (including its interior) is within than the given dist. | ||||
| 	// The boolean reports if the value was updated. | ||||
| 	updateDistanceToCell(c Cell, dist distance) (distance, bool) | ||||
| 
 | ||||
| 	// setMaxError potentially updates the value of MaxError, and reports if | ||||
| 	// the specific type supports altering it. Whenever one of the | ||||
| 	// updateDistanceTo... methods above returns true, the returned distance | ||||
| 	// is allowed to be up to maxError larger than the true minimum distance. | ||||
| 	// In other words, it gives this target object permission to terminate its | ||||
| 	// distance calculation as soon as it has determined that (1) the minimum | ||||
| 	// distance is less than minDist and (2) the best possible further | ||||
| 	// improvement is less than maxError. | ||||
| 	// | ||||
| 	// If the target takes advantage of maxError to optimize its distance | ||||
| 	// calculation, this method must return true. (Most target types will | ||||
| 	// default to return false.) | ||||
| 	setMaxError(maxErr s1.ChordAngle) bool | ||||
| 
 | ||||
| 	// maxBruteForceIndexSize reports the maximum number of indexed objects for | ||||
| 	// which it is faster to compute the distance by brute force (e.g., by testing | ||||
| 	// every edge) rather than by using an index. | ||||
| 	// | ||||
| 	// The following method is provided as a convenience for types that compute | ||||
| 	// distances to a collection of indexed geometry, such as ClosestEdgeQuery | ||||
| 	// and ClosestPointQuery. | ||||
| 	// | ||||
| 	// Types that do not support this should return a -1. | ||||
| 	maxBruteForceIndexSize() int | ||||
| 
 | ||||
| 	// distance returns an instance of the underlying distance type this | ||||
| 	// target uses. This is to work around the use of Templates in the C++. | ||||
| 	distance() distance | ||||
| 
 | ||||
| 	// visitContainingShapes finds all polygons in the given index that | ||||
| 	// completely contain a connected component of the target geometry. (For | ||||
| 	// example, if the target consists of 10 points, this method finds | ||||
| 	// polygons that contain any of those 10 points.) For each such polygon, | ||||
| 	// the visit function is called with the Shape of the polygon along with | ||||
| 	// a point of the target geometry that is contained by that polygon. | ||||
| 	// | ||||
| 	// Optionally, any polygon that intersects the target geometry may also be | ||||
| 	// returned.  In other words, this method returns all polygons that | ||||
| 	// contain any connected component of the target, along with an arbitrary | ||||
| 	// subset of the polygons that intersect the target. | ||||
| 	// | ||||
| 	// For example, suppose that the index contains two abutting polygons | ||||
| 	// A and B. If the target consists of two points "a" contained by A and | ||||
| 	// "b" contained by B, then both A and B are returned. But if the target | ||||
| 	// consists of the edge "ab", then any subset of {A, B} could be returned | ||||
| 	// (because both polygons intersect the target but neither one contains | ||||
| 	// the edge "ab"). | ||||
| 	// | ||||
| 	// If the visit function returns false, this method terminates early and | ||||
| 	// returns false as well. Otherwise returns true. | ||||
| 	// | ||||
| 	// NOTE(roberts): This method exists only for the purpose of implementing | ||||
| 	// edgeQuery IncludeInteriors efficiently. | ||||
| 	visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool | ||||
| } | ||||
| 
 | ||||
| // shapePointVisitorFunc defines a type of function the visitContainingShapes can call. | ||||
| type shapePointVisitorFunc func(containingShape Shape, targetPoint Point) bool | ||||
							
								
								
									
										29
									
								
								vendor/github.com/golang/geo/s2/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/golang/geo/s2/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,29 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| /* | ||||
| Package s2 is a library for working with geometry in S² (spherical geometry). | ||||
| 
 | ||||
| Its related packages, parallel to this one, are s1 (operates on S¹), r1 (operates on ℝ¹), | ||||
| r2 (operates on ℝ²) and r3 (operates on ℝ³). | ||||
| 
 | ||||
| This package provides types and functions for the S2 cell hierarchy and coordinate systems. | ||||
| The S2 cell hierarchy is a hierarchical decomposition of the surface of a unit sphere (S²) | ||||
| into ``cells''; it is highly efficient, scales from continental size to under 1 cm² | ||||
| and preserves spatial locality (nearby cells have close IDs). | ||||
| 
 | ||||
| More information including an in-depth introduction to S2 can be found on the | ||||
| S2 website https://s2geometry.io/ | ||||
| */ | ||||
| package s2 | ||||
							
								
								
									
										672
									
								
								vendor/github.com/golang/geo/s2/edge_clipping.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										672
									
								
								vendor/github.com/golang/geo/s2/edge_clipping.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,672 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file contains a collection of methods for: | ||||
| // | ||||
| //   (1) Robustly clipping geodesic edges to the faces of the S2 biunit cube | ||||
| //       (see s2stuv), and | ||||
| // | ||||
| //   (2) Robustly clipping 2D edges against 2D rectangles. | ||||
| // | ||||
| // These functions can be used to efficiently find the set of CellIDs that | ||||
| // are intersected by a geodesic edge (e.g., see CrossingEdgeQuery). | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r2" | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// edgeClipErrorUVCoord is the maximum error in a u- or v-coordinate | ||||
| 	// compared to the exact result, assuming that the points A and B are in | ||||
| 	// the rectangle [-1,1]x[1,1] or slightly outside it (by 1e-10 or less). | ||||
| 	edgeClipErrorUVCoord = 2.25 * dblEpsilon | ||||
| 
 | ||||
| 	// edgeClipErrorUVDist is the maximum distance from a clipped point to | ||||
| 	// the corresponding exact result. It is equal to the error in a single | ||||
| 	// coordinate because at most one coordinate is subject to error. | ||||
| 	edgeClipErrorUVDist = 2.25 * dblEpsilon | ||||
| 
 | ||||
| 	// faceClipErrorRadians is the maximum angle between a returned vertex | ||||
| 	// and the nearest point on the exact edge AB. It is equal to the | ||||
| 	// maximum directional error in PointCross, plus the error when | ||||
| 	// projecting points onto a cube face. | ||||
| 	faceClipErrorRadians = 3 * dblEpsilon | ||||
| 
 | ||||
| 	// faceClipErrorDist is the same angle expressed as a maximum distance | ||||
| 	// in (u,v)-space. In other words, a returned vertex is at most this far | ||||
| 	// from the exact edge AB projected into (u,v)-space. | ||||
| 	faceClipErrorUVDist = 9 * dblEpsilon | ||||
| 
 | ||||
| 	// faceClipErrorUVCoord is the maximum angle between a returned vertex | ||||
| 	// and the nearest point on the exact edge AB expressed as the maximum error | ||||
| 	// in an individual u- or v-coordinate. In other words, for each | ||||
| 	// returned vertex there is a point on the exact edge AB whose u- and | ||||
| 	// v-coordinates differ from the vertex by at most this amount. | ||||
| 	faceClipErrorUVCoord = 9.0 * (1.0 / math.Sqrt2) * dblEpsilon | ||||
| 
 | ||||
| 	// intersectsRectErrorUVDist is the maximum error when computing if a point | ||||
| 	// intersects with a given Rect. If some point of AB is inside the | ||||
| 	// rectangle by at least this distance, the result is guaranteed to be true; | ||||
| 	// if all points of AB are outside the rectangle by at least this distance, | ||||
| 	// the result is guaranteed to be false. This bound assumes that rect is | ||||
| 	// a subset of the rectangle [-1,1]x[-1,1] or extends slightly outside it | ||||
| 	// (e.g., by 1e-10 or less). | ||||
| 	intersectsRectErrorUVDist = 3 * math.Sqrt2 * dblEpsilon | ||||
| ) | ||||
| 
 | ||||
| // ClipToFace returns the (u,v) coordinates for the portion of the edge AB that | ||||
| // intersects the given face, or false if the edge AB does not intersect. | ||||
| // This method guarantees that the clipped vertices lie within the [-1,1]x[-1,1] | ||||
| // cube face rectangle and are within faceClipErrorUVDist of the line AB, but | ||||
| // the results may differ from those produced by FaceSegments. | ||||
| func ClipToFace(a, b Point, face int) (aUV, bUV r2.Point, intersects bool) { | ||||
| 	return ClipToPaddedFace(a, b, face, 0.0) | ||||
| } | ||||
| 
 | ||||
| // ClipToPaddedFace returns the (u,v) coordinates for the portion of the edge AB that | ||||
| // intersects the given face, but rather than clipping to the square [-1,1]x[-1,1] | ||||
| // in (u,v) space, this method clips to [-R,R]x[-R,R] where R=(1+padding). | ||||
| // Padding must be non-negative. | ||||
| func ClipToPaddedFace(a, b Point, f int, padding float64) (aUV, bUV r2.Point, intersects bool) { | ||||
| 	// Fast path: both endpoints are on the given face. | ||||
| 	if face(a.Vector) == f && face(b.Vector) == f { | ||||
| 		au, av := validFaceXYZToUV(f, a.Vector) | ||||
| 		bu, bv := validFaceXYZToUV(f, b.Vector) | ||||
| 		return r2.Point{au, av}, r2.Point{bu, bv}, true | ||||
| 	} | ||||
| 
 | ||||
| 	// Convert everything into the (u,v,w) coordinates of the given face. Note | ||||
| 	// that the cross product *must* be computed in the original (x,y,z) | ||||
| 	// coordinate system because PointCross (unlike the mathematical cross | ||||
| 	// product) can produce different results in different coordinate systems | ||||
| 	// when one argument is a linear multiple of the other, due to the use of | ||||
| 	// symbolic perturbations. | ||||
| 	normUVW := pointUVW(faceXYZtoUVW(f, a.PointCross(b))) | ||||
| 	aUVW := pointUVW(faceXYZtoUVW(f, a)) | ||||
| 	bUVW := pointUVW(faceXYZtoUVW(f, b)) | ||||
| 
 | ||||
| 	// Padding is handled by scaling the u- and v-components of the normal. | ||||
| 	// Letting R=1+padding, this means that when we compute the dot product of | ||||
| 	// the normal with a cube face vertex (such as (-1,-1,1)), we will actually | ||||
| 	// compute the dot product with the scaled vertex (-R,-R,1). This allows | ||||
| 	// methods such as intersectsFace, exitAxis, etc, to handle padding | ||||
| 	// with no further modifications. | ||||
| 	scaleUV := 1 + padding | ||||
| 	scaledN := pointUVW{r3.Vector{X: scaleUV * normUVW.X, Y: scaleUV * normUVW.Y, Z: normUVW.Z}} | ||||
| 	if !scaledN.intersectsFace() { | ||||
| 		return aUV, bUV, false | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(roberts): This is a workaround for extremely small vectors where some | ||||
| 	// loss of precision can occur in Normalize causing underflow. When PointCross | ||||
| 	// is updated to work around this, this can be removed. | ||||
| 	if math.Max(math.Abs(normUVW.X), math.Max(math.Abs(normUVW.Y), math.Abs(normUVW.Z))) < math.Ldexp(1, -511) { | ||||
| 		normUVW = pointUVW{normUVW.Mul(math.Ldexp(1, 563))} | ||||
| 	} | ||||
| 
 | ||||
| 	normUVW = pointUVW{normUVW.Normalize()} | ||||
| 
 | ||||
| 	aTan := pointUVW{normUVW.Cross(aUVW.Vector)} | ||||
| 	bTan := pointUVW{bUVW.Cross(normUVW.Vector)} | ||||
| 
 | ||||
| 	// As described in clipDestination, if the sum of the scores from clipping the two | ||||
| 	// endpoints is 3 or more, then the segment does not intersect this face. | ||||
| 	aUV, aScore := clipDestination(bUVW, aUVW, pointUVW{scaledN.Mul(-1)}, bTan, aTan, scaleUV) | ||||
| 	bUV, bScore := clipDestination(aUVW, bUVW, scaledN, aTan, bTan, scaleUV) | ||||
| 
 | ||||
| 	return aUV, bUV, aScore+bScore < 3 | ||||
| } | ||||
| 
 | ||||
| // ClipEdge returns the portion of the edge defined by AB that is contained by the | ||||
| // given rectangle. If there is no intersection, false is returned and aClip and bClip | ||||
| // are undefined. | ||||
| func ClipEdge(a, b r2.Point, clip r2.Rect) (aClip, bClip r2.Point, intersects bool) { | ||||
| 	// Compute the bounding rectangle of AB, clip it, and then extract the new | ||||
| 	// endpoints from the clipped bound. | ||||
| 	bound := r2.RectFromPoints(a, b) | ||||
| 	if bound, intersects = clipEdgeBound(a, b, clip, bound); !intersects { | ||||
| 		return aClip, bClip, false | ||||
| 	} | ||||
| 	ai := 0 | ||||
| 	if a.X > b.X { | ||||
| 		ai = 1 | ||||
| 	} | ||||
| 	aj := 0 | ||||
| 	if a.Y > b.Y { | ||||
| 		aj = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	return bound.VertexIJ(ai, aj), bound.VertexIJ(1-ai, 1-aj), true | ||||
| } | ||||
| 
 | ||||
| // The three functions below (sumEqual, intersectsFace, intersectsOppositeEdges) | ||||
| // all compare a sum (u + v) to a third value w. They are implemented in such a | ||||
| // way that they produce an exact result even though all calculations are done | ||||
| // with ordinary floating-point operations. Here are the principles on which these | ||||
| // functions are based: | ||||
| // | ||||
| // A. If u + v < w in floating-point, then u + v < w in exact arithmetic. | ||||
| // | ||||
| // B. If u + v < w in exact arithmetic, then at least one of the following | ||||
| //    expressions is true in floating-point: | ||||
| //       u + v < w | ||||
| //       u < w - v | ||||
| //       v < w - u | ||||
| // | ||||
| // Proof: By rearranging terms and substituting ">" for "<", we can assume | ||||
| // that all values are non-negative.  Now clearly "w" is not the smallest | ||||
| // value, so assume WLOG that "u" is the smallest.  We want to show that | ||||
| // u < w - v in floating-point.  If v >= w/2, the calculation of w - v is | ||||
| // exact since the result is smaller in magnitude than either input value, | ||||
| // so the result holds.  Otherwise we have u <= v < w/2 and w - v >= w/2 | ||||
| // (even in floating point), so the result also holds. | ||||
| 
 | ||||
| // sumEqual reports whether u + v == w exactly. | ||||
| func sumEqual(u, v, w float64) bool { | ||||
| 	return (u+v == w) && (u == w-v) && (v == w-u) | ||||
| } | ||||
| 
 | ||||
| // pointUVW represents a Point in (u,v,w) coordinate space of a cube face. | ||||
| type pointUVW Point | ||||
| 
 | ||||
| // intersectsFace reports whether a given directed line L intersects the cube face F. | ||||
| // The line L is defined by its normal N in the (u,v,w) coordinates of F. | ||||
| func (p pointUVW) intersectsFace() bool { | ||||
| 	// L intersects the [-1,1]x[-1,1] square in (u,v) if and only if the dot | ||||
| 	// products of N with the four corner vertices (-1,-1,1), (1,-1,1), (1,1,1), | ||||
| 	// and (-1,1,1) do not all have the same sign. This is true exactly when | ||||
| 	// |Nu| + |Nv| >= |Nw|. The code below evaluates this expression exactly. | ||||
| 	u := math.Abs(p.X) | ||||
| 	v := math.Abs(p.Y) | ||||
| 	w := math.Abs(p.Z) | ||||
| 
 | ||||
| 	// We only need to consider the cases where u or v is the smallest value, | ||||
| 	// since if w is the smallest then both expressions below will have a | ||||
| 	// positive LHS and a negative RHS. | ||||
| 	return (v >= w-u) && (u >= w-v) | ||||
| } | ||||
| 
 | ||||
| // intersectsOppositeEdges reports whether a directed line L intersects two | ||||
| // opposite edges of a cube face F. This includs the case where L passes | ||||
| // exactly through a corner vertex of F. The directed line L is defined | ||||
| // by its normal N in the (u,v,w) coordinates of F. | ||||
| func (p pointUVW) intersectsOppositeEdges() bool { | ||||
| 	// The line L intersects opposite edges of the [-1,1]x[-1,1] (u,v) square if | ||||
| 	// and only exactly two of the corner vertices lie on each side of L. This | ||||
| 	// is true exactly when ||Nu| - |Nv|| >= |Nw|. The code below evaluates this | ||||
| 	// expression exactly. | ||||
| 	u := math.Abs(p.X) | ||||
| 	v := math.Abs(p.Y) | ||||
| 	w := math.Abs(p.Z) | ||||
| 
 | ||||
| 	// If w is the smallest, the following line returns an exact result. | ||||
| 	if math.Abs(u-v) != w { | ||||
| 		return math.Abs(u-v) >= w | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise u - v = w exactly, or w is not the smallest value. In either | ||||
| 	// case the following returns the correct result. | ||||
| 	if u >= v { | ||||
| 		return u-w >= v | ||||
| 	} | ||||
| 	return v-w >= u | ||||
| } | ||||
| 
 | ||||
| // axis represents the possible results of exitAxis. | ||||
| type axis int | ||||
| 
 | ||||
| const ( | ||||
| 	axisU axis = iota | ||||
| 	axisV | ||||
| ) | ||||
| 
 | ||||
| // exitAxis reports which axis the directed line L exits the cube face F on. | ||||
| // The directed line L is represented by its CCW normal N in the (u,v,w) coordinates | ||||
| // of F. It returns axisU if L exits through the u=-1 or u=+1 edge, and axisV if L exits | ||||
| // through the v=-1 or v=+1 edge. Either result is acceptable if L exits exactly | ||||
| // through a corner vertex of the cube face. | ||||
| func (p pointUVW) exitAxis() axis { | ||||
| 	if p.intersectsOppositeEdges() { | ||||
| 		// The line passes through through opposite edges of the face. | ||||
| 		// It exits through the v=+1 or v=-1 edge if the u-component of N has a | ||||
| 		// larger absolute magnitude than the v-component. | ||||
| 		if math.Abs(p.X) >= math.Abs(p.Y) { | ||||
| 			return axisV | ||||
| 		} | ||||
| 		return axisU | ||||
| 	} | ||||
| 
 | ||||
| 	// The line passes through through two adjacent edges of the face. | ||||
| 	// It exits the v=+1 or v=-1 edge if an even number of the components of N | ||||
| 	// are negative. We test this using signbit() rather than multiplication | ||||
| 	// to avoid the possibility of underflow. | ||||
| 	var x, y, z int | ||||
| 	if math.Signbit(p.X) { | ||||
| 		x = 1 | ||||
| 	} | ||||
| 	if math.Signbit(p.Y) { | ||||
| 		y = 1 | ||||
| 	} | ||||
| 	if math.Signbit(p.Z) { | ||||
| 		z = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	if x^y^z == 0 { | ||||
| 		return axisV | ||||
| 	} | ||||
| 	return axisU | ||||
| } | ||||
| 
 | ||||
| // exitPoint returns the UV coordinates of the point where a directed line L (represented | ||||
| // by the CCW normal of this point), exits the cube face this point is derived from along | ||||
| // the given axis. | ||||
| func (p pointUVW) exitPoint(a axis) r2.Point { | ||||
| 	if a == axisU { | ||||
| 		u := -1.0 | ||||
| 		if p.Y > 0 { | ||||
| 			u = 1.0 | ||||
| 		} | ||||
| 		return r2.Point{u, (-u*p.X - p.Z) / p.Y} | ||||
| 	} | ||||
| 
 | ||||
| 	v := -1.0 | ||||
| 	if p.X < 0 { | ||||
| 		v = 1.0 | ||||
| 	} | ||||
| 	return r2.Point{(-v*p.Y - p.Z) / p.X, v} | ||||
| } | ||||
| 
 | ||||
| // clipDestination returns a score which is used to indicate if the clipped edge AB | ||||
| // on the given face intersects the face at all. This function returns the score for | ||||
| // the given endpoint, which is an integer ranging from 0 to 3. If the sum of the scores | ||||
| // from both of the endpoints is 3 or more, then edge AB does not intersect this face. | ||||
| // | ||||
| // First, it clips the line segment AB to find the clipped destination B' on a given | ||||
| // face. (The face is specified implicitly by expressing *all arguments* in the (u,v,w) | ||||
| // coordinates of that face.) Second, it partially computes whether the segment AB | ||||
| // intersects this face at all. The actual condition is fairly complicated, but it | ||||
| // turns out that it can be expressed as a "score" that can be computed independently | ||||
| // when clipping the two endpoints A and B. | ||||
| func clipDestination(a, b, scaledN, aTan, bTan pointUVW, scaleUV float64) (r2.Point, int) { | ||||
| 	var uv r2.Point | ||||
| 
 | ||||
| 	// Optimization: if B is within the safe region of the face, use it. | ||||
| 	maxSafeUVCoord := 1 - faceClipErrorUVCoord | ||||
| 	if b.Z > 0 { | ||||
| 		uv = r2.Point{b.X / b.Z, b.Y / b.Z} | ||||
| 		if math.Max(math.Abs(uv.X), math.Abs(uv.Y)) <= maxSafeUVCoord { | ||||
| 			return uv, 0 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise find the point B' where the line AB exits the face. | ||||
| 	uv = scaledN.exitPoint(scaledN.exitAxis()).Mul(scaleUV) | ||||
| 
 | ||||
| 	p := pointUVW(Point{r3.Vector{uv.X, uv.Y, 1.0}}) | ||||
| 
 | ||||
| 	// Determine if the exit point B' is contained within the segment. We do this | ||||
| 	// by computing the dot products with two inward-facing tangent vectors at A | ||||
| 	// and B. If either dot product is negative, we say that B' is on the "wrong | ||||
| 	// side" of that point. As the point B' moves around the great circle AB past | ||||
| 	// the segment endpoint B, it is initially on the wrong side of B only; as it | ||||
| 	// moves further it is on the wrong side of both endpoints; and then it is on | ||||
| 	// the wrong side of A only. If the exit point B' is on the wrong side of | ||||
| 	// either endpoint, we can't use it; instead the segment is clipped at the | ||||
| 	// original endpoint B. | ||||
| 	// | ||||
| 	// We reject the segment if the sum of the scores of the two endpoints is 3 | ||||
| 	// or more. Here is what that rule encodes: | ||||
| 	//  - If B' is on the wrong side of A, then the other clipped endpoint A' | ||||
| 	//    must be in the interior of AB (otherwise AB' would go the wrong way | ||||
| 	//    around the circle). There is a similar rule for A'. | ||||
| 	//  - If B' is on the wrong side of either endpoint (and therefore we must | ||||
| 	//    use the original endpoint B instead), then it must be possible to | ||||
| 	//    project B onto this face (i.e., its w-coordinate must be positive). | ||||
| 	//    This rule is only necessary to handle certain zero-length edges (A=B). | ||||
| 	score := 0 | ||||
| 	if p.Sub(a.Vector).Dot(aTan.Vector) < 0 { | ||||
| 		score = 2 // B' is on wrong side of A. | ||||
| 	} else if p.Sub(b.Vector).Dot(bTan.Vector) < 0 { | ||||
| 		score = 1 // B' is on wrong side of B. | ||||
| 	} | ||||
| 
 | ||||
| 	if score > 0 { // B' is not in the interior of AB. | ||||
| 		if b.Z <= 0 { | ||||
| 			score = 3 // B cannot be projected onto this face. | ||||
| 		} else { | ||||
| 			uv = r2.Point{b.X / b.Z, b.Y / b.Z} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return uv, score | ||||
| } | ||||
| 
 | ||||
| // updateEndpoint returns the interval with the specified endpoint updated to | ||||
| // the given value. If the value lies beyond the opposite endpoint, nothing is | ||||
| // changed and false is returned. | ||||
| func updateEndpoint(bound r1.Interval, highEndpoint bool, value float64) (r1.Interval, bool) { | ||||
| 	if !highEndpoint { | ||||
| 		if bound.Hi < value { | ||||
| 			return bound, false | ||||
| 		} | ||||
| 		if bound.Lo < value { | ||||
| 			bound.Lo = value | ||||
| 		} | ||||
| 		return bound, true | ||||
| 	} | ||||
| 
 | ||||
| 	if bound.Lo > value { | ||||
| 		return bound, false | ||||
| 	} | ||||
| 	if bound.Hi > value { | ||||
| 		bound.Hi = value | ||||
| 	} | ||||
| 	return bound, true | ||||
| } | ||||
| 
 | ||||
| // clipBoundAxis returns the clipped versions of the bounding intervals for the given | ||||
| // axes for the line segment from (a0,a1) to (b0,b1) so that neither extends beyond the | ||||
| // given clip interval. negSlope is a precomputed helper variable that indicates which | ||||
| // diagonal of the bounding box is spanned by AB; it is false if AB has positive slope, | ||||
| // and true if AB has negative slope. If the clipping interval doesn't overlap the bounds, | ||||
| // false is returned. | ||||
| func clipBoundAxis(a0, b0 float64, bound0 r1.Interval, a1, b1 float64, bound1 r1.Interval, | ||||
| 	negSlope bool, clip r1.Interval) (bound0c, bound1c r1.Interval, updated bool) { | ||||
| 
 | ||||
| 	if bound0.Lo < clip.Lo { | ||||
| 		// If the upper bound is below the clips lower bound, there is nothing to do. | ||||
| 		if bound0.Hi < clip.Lo { | ||||
| 			return bound0, bound1, false | ||||
| 		} | ||||
| 		// narrow the intervals lower bound to the clip bound. | ||||
| 		bound0.Lo = clip.Lo | ||||
| 		if bound1, updated = updateEndpoint(bound1, negSlope, interpolateFloat64(clip.Lo, a0, b0, a1, b1)); !updated { | ||||
| 			return bound0, bound1, false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if bound0.Hi > clip.Hi { | ||||
| 		// If the lower bound is above the clips upper bound, there is nothing to do. | ||||
| 		if bound0.Lo > clip.Hi { | ||||
| 			return bound0, bound1, false | ||||
| 		} | ||||
| 		// narrow the intervals upper bound to the clip bound. | ||||
| 		bound0.Hi = clip.Hi | ||||
| 		if bound1, updated = updateEndpoint(bound1, !negSlope, interpolateFloat64(clip.Hi, a0, b0, a1, b1)); !updated { | ||||
| 			return bound0, bound1, false | ||||
| 		} | ||||
| 	} | ||||
| 	return bound0, bound1, true | ||||
| } | ||||
| 
 | ||||
| // edgeIntersectsRect reports whether the edge defined by AB intersects the | ||||
| // given closed rectangle to within the error bound. | ||||
| func edgeIntersectsRect(a, b r2.Point, r r2.Rect) bool { | ||||
| 	// First check whether the bounds of a Rect around AB intersects the given rect. | ||||
| 	if !r.Intersects(r2.RectFromPoints(a, b)) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise AB intersects the rect if and only if all four vertices of rect | ||||
| 	// do not lie on the same side of the extended line AB. We test this by finding | ||||
| 	// the two vertices of rect with minimum and maximum projections onto the normal | ||||
| 	// of AB, and computing their dot products with the edge normal. | ||||
| 	n := b.Sub(a).Ortho() | ||||
| 
 | ||||
| 	i := 0 | ||||
| 	if n.X >= 0 { | ||||
| 		i = 1 | ||||
| 	} | ||||
| 	j := 0 | ||||
| 	if n.Y >= 0 { | ||||
| 		j = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	max := n.Dot(r.VertexIJ(i, j).Sub(a)) | ||||
| 	min := n.Dot(r.VertexIJ(1-i, 1-j).Sub(a)) | ||||
| 
 | ||||
| 	return (max >= 0) && (min <= 0) | ||||
| } | ||||
| 
 | ||||
| // clippedEdgeBound returns the bounding rectangle of the portion of the edge defined | ||||
| // by AB intersected by clip. The resulting bound may be empty. This is a convenience | ||||
| // function built on top of clipEdgeBound. | ||||
| func clippedEdgeBound(a, b r2.Point, clip r2.Rect) r2.Rect { | ||||
| 	bound := r2.RectFromPoints(a, b) | ||||
| 	if b1, intersects := clipEdgeBound(a, b, clip, bound); intersects { | ||||
| 		return b1 | ||||
| 	} | ||||
| 	return r2.EmptyRect() | ||||
| } | ||||
| 
 | ||||
| // clipEdgeBound clips an edge AB to sequence of rectangles efficiently. | ||||
| // It represents the clipped edges by their bounding boxes rather than as a pair of | ||||
| // endpoints. Specifically, let A'B' be some portion of an edge AB, and let bound be | ||||
| // a tight bound of A'B'. This function returns the bound that is a tight bound | ||||
| // of A'B' intersected with a given rectangle. If A'B' does not intersect clip, | ||||
| // it returns false and the original bound. | ||||
| func clipEdgeBound(a, b r2.Point, clip, bound r2.Rect) (r2.Rect, bool) { | ||||
| 	// negSlope indicates which diagonal of the bounding box is spanned by AB: it | ||||
| 	// is false if AB has positive slope, and true if AB has negative slope. This is | ||||
| 	// used to determine which interval endpoints need to be updated each time | ||||
| 	// the edge is clipped. | ||||
| 	negSlope := (a.X > b.X) != (a.Y > b.Y) | ||||
| 
 | ||||
| 	b0x, b0y, up1 := clipBoundAxis(a.X, b.X, bound.X, a.Y, b.Y, bound.Y, negSlope, clip.X) | ||||
| 	if !up1 { | ||||
| 		return bound, false | ||||
| 	} | ||||
| 	b1y, b1x, up2 := clipBoundAxis(a.Y, b.Y, b0y, a.X, b.X, b0x, negSlope, clip.Y) | ||||
| 	if !up2 { | ||||
| 		return r2.Rect{b0x, b0y}, false | ||||
| 	} | ||||
| 	return r2.Rect{X: b1x, Y: b1y}, true | ||||
| } | ||||
| 
 | ||||
| // interpolateFloat64 returns a value with the same combination of a1 and b1 as the | ||||
| // given value x is of a and b. This function makes the following guarantees: | ||||
| //  - If x == a, then x1 = a1 (exactly). | ||||
| //  - If x == b, then x1 = b1 (exactly). | ||||
| //  - If a <= x <= b, then a1 <= x1 <= b1 (even if a1 == b1). | ||||
| // This requires a != b. | ||||
| func interpolateFloat64(x, a, b, a1, b1 float64) float64 { | ||||
| 	// To get results that are accurate near both A and B, we interpolate | ||||
| 	// starting from the closer of the two points. | ||||
| 	if math.Abs(a-x) <= math.Abs(b-x) { | ||||
| 		return a1 + (b1-a1)*(x-a)/(b-a) | ||||
| 	} | ||||
| 	return b1 + (a1-b1)*(x-b)/(a-b) | ||||
| } | ||||
| 
 | ||||
| // FaceSegment represents an edge AB clipped to an S2 cube face. It is | ||||
| // represented by a face index and a pair of (u,v) coordinates. | ||||
| type FaceSegment struct { | ||||
| 	face int | ||||
| 	a, b r2.Point | ||||
| } | ||||
| 
 | ||||
| // FaceSegments subdivides the given edge AB at every point where it crosses the | ||||
| // boundary between two S2 cube faces and returns the corresponding FaceSegments. | ||||
| // The segments are returned in order from A toward B. The input points must be | ||||
| // unit length. | ||||
| // | ||||
| // This function guarantees that the returned segments form a continuous path | ||||
| // from A to B, and that all vertices are within faceClipErrorUVDist of the | ||||
| // line AB. All vertices lie within the [-1,1]x[-1,1] cube face rectangles. | ||||
| // The results are consistent with Sign, i.e. the edge is well-defined even its | ||||
| // endpoints are antipodal. | ||||
| // TODO(roberts): Extend the implementation of PointCross so that this is true. | ||||
| func FaceSegments(a, b Point) []FaceSegment { | ||||
| 	var segment FaceSegment | ||||
| 
 | ||||
| 	// Fast path: both endpoints are on the same face. | ||||
| 	var aFace, bFace int | ||||
| 	aFace, segment.a.X, segment.a.Y = xyzToFaceUV(a.Vector) | ||||
| 	bFace, segment.b.X, segment.b.Y = xyzToFaceUV(b.Vector) | ||||
| 	if aFace == bFace { | ||||
| 		segment.face = aFace | ||||
| 		return []FaceSegment{segment} | ||||
| 	} | ||||
| 
 | ||||
| 	// Starting at A, we follow AB from face to face until we reach the face | ||||
| 	// containing B. The following code is designed to ensure that we always | ||||
| 	// reach B, even in the presence of numerical errors. | ||||
| 	// | ||||
| 	// First we compute the normal to the plane containing A and B. This normal | ||||
| 	// becomes the ultimate definition of the line AB; it is used to resolve all | ||||
| 	// questions regarding where exactly the line goes. Unfortunately due to | ||||
| 	// numerical errors, the line may not quite intersect the faces containing | ||||
| 	// the original endpoints. We handle this by moving A and/or B slightly if | ||||
| 	// necessary so that they are on faces intersected by the line AB. | ||||
| 	ab := a.PointCross(b) | ||||
| 
 | ||||
| 	aFace, segment.a = moveOriginToValidFace(aFace, a, ab, segment.a) | ||||
| 	bFace, segment.b = moveOriginToValidFace(bFace, b, Point{ab.Mul(-1)}, segment.b) | ||||
| 
 | ||||
| 	// Now we simply follow AB from face to face until we reach B. | ||||
| 	var segments []FaceSegment | ||||
| 	segment.face = aFace | ||||
| 	bSaved := segment.b | ||||
| 
 | ||||
| 	for face := aFace; face != bFace; { | ||||
| 		// Complete the current segment by finding the point where AB | ||||
| 		// exits the current face. | ||||
| 		z := faceXYZtoUVW(face, ab) | ||||
| 		n := pointUVW{z.Vector} | ||||
| 
 | ||||
| 		exitAxis := n.exitAxis() | ||||
| 		segment.b = n.exitPoint(exitAxis) | ||||
| 		segments = append(segments, segment) | ||||
| 
 | ||||
| 		// Compute the next face intersected by AB, and translate the exit | ||||
| 		// point of the current segment into the (u,v) coordinates of the | ||||
| 		// next face. This becomes the first point of the next segment. | ||||
| 		exitXyz := faceUVToXYZ(face, segment.b.X, segment.b.Y) | ||||
| 		face = nextFace(face, segment.b, exitAxis, n, bFace) | ||||
| 		exitUvw := faceXYZtoUVW(face, Point{exitXyz}) | ||||
| 		segment.face = face | ||||
| 		segment.a = r2.Point{exitUvw.X, exitUvw.Y} | ||||
| 	} | ||||
| 	// Finish the last segment. | ||||
| 	segment.b = bSaved | ||||
| 	return append(segments, segment) | ||||
| } | ||||
| 
 | ||||
| // moveOriginToValidFace updates the origin point to a valid face if necessary. | ||||
| // Given a line segment AB whose origin A has been projected onto a given cube | ||||
| // face, determine whether it is necessary to project A onto a different face | ||||
| // instead. This can happen because the normal of the line AB is not computed | ||||
| // exactly, so that the line AB (defined as the set of points perpendicular to | ||||
| // the normal) may not intersect the cube face containing A. Even if it does | ||||
| // intersect the face, the exit point of the line from that face may be on | ||||
| // the wrong side of A (i.e., in the direction away from B). If this happens, | ||||
| // we reproject A onto the adjacent face where the line AB approaches A most | ||||
| // closely. This moves the origin by a small amount, but never more than the | ||||
| // error tolerances. | ||||
| func moveOriginToValidFace(face int, a, ab Point, aUV r2.Point) (int, r2.Point) { | ||||
| 	// Fast path: if the origin is sufficiently far inside the face, it is | ||||
| 	// always safe to use it. | ||||
| 	const maxSafeUVCoord = 1 - faceClipErrorUVCoord | ||||
| 	if math.Max(math.Abs((aUV).X), math.Abs((aUV).Y)) <= maxSafeUVCoord { | ||||
| 		return face, aUV | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise check whether the normal AB even intersects this face. | ||||
| 	z := faceXYZtoUVW(face, ab) | ||||
| 	n := pointUVW{z.Vector} | ||||
| 	if n.intersectsFace() { | ||||
| 		// Check whether the point where the line AB exits this face is on the | ||||
| 		// wrong side of A (by more than the acceptable error tolerance). | ||||
| 		uv := n.exitPoint(n.exitAxis()) | ||||
| 		exit := faceUVToXYZ(face, uv.X, uv.Y) | ||||
| 		aTangent := ab.Normalize().Cross(a.Vector) | ||||
| 
 | ||||
| 		// We can use the given face. | ||||
| 		if exit.Sub(a.Vector).Dot(aTangent) >= -faceClipErrorRadians { | ||||
| 			return face, aUV | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise we reproject A to the nearest adjacent face. (If line AB does | ||||
| 	// not pass through a given face, it must pass through all adjacent faces.) | ||||
| 	var dir int | ||||
| 	if math.Abs((aUV).X) >= math.Abs((aUV).Y) { | ||||
| 		// U-axis | ||||
| 		if aUV.X > 0 { | ||||
| 			dir = 1 | ||||
| 		} | ||||
| 		face = uvwFace(face, 0, dir) | ||||
| 	} else { | ||||
| 		// V-axis | ||||
| 		if aUV.Y > 0 { | ||||
| 			dir = 1 | ||||
| 		} | ||||
| 		face = uvwFace(face, 1, dir) | ||||
| 	} | ||||
| 
 | ||||
| 	aUV.X, aUV.Y = validFaceXYZToUV(face, a.Vector) | ||||
| 	aUV.X = math.Max(-1.0, math.Min(1.0, aUV.X)) | ||||
| 	aUV.Y = math.Max(-1.0, math.Min(1.0, aUV.Y)) | ||||
| 
 | ||||
| 	return face, aUV | ||||
| } | ||||
| 
 | ||||
| // nextFace returns the next face that should be visited by FaceSegments, given that | ||||
| // we have just visited face and we are following the line AB (represented | ||||
| // by its normal N in the (u,v,w) coordinates of that face). The other | ||||
| // arguments include the point where AB exits face, the corresponding | ||||
| // exit axis, and the target face containing the destination point B. | ||||
| func nextFace(face int, exit r2.Point, axis axis, n pointUVW, targetFace int) int { | ||||
| 	// this bit is to work around C++ cleverly casting bools to ints for you. | ||||
| 	exitA := exit.X | ||||
| 	exit1MinusA := exit.Y | ||||
| 
 | ||||
| 	if axis == axisV { | ||||
| 		exitA = exit.Y | ||||
| 		exit1MinusA = exit.X | ||||
| 	} | ||||
| 	exitAPos := 0 | ||||
| 	if exitA > 0 { | ||||
| 		exitAPos = 1 | ||||
| 	} | ||||
| 	exit1MinusAPos := 0 | ||||
| 	if exit1MinusA > 0 { | ||||
| 		exit1MinusAPos = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// We return the face that is adjacent to the exit point along the given | ||||
| 	// axis. If line AB exits *exactly* through a corner of the face, there are | ||||
| 	// two possible next faces. If one is the target face containing B, then | ||||
| 	// we guarantee that we advance to that face directly. | ||||
| 	// | ||||
| 	// The three conditions below check that (1) AB exits approximately through | ||||
| 	// a corner, (2) the adjacent face along the non-exit axis is the target | ||||
| 	// face, and (3) AB exits *exactly* through the corner. (The sumEqual | ||||
| 	// code checks whether the dot product of (u,v,1) and n is exactly zero.) | ||||
| 	if math.Abs(exit1MinusA) == 1 && | ||||
| 		uvwFace(face, int(1-axis), exit1MinusAPos) == targetFace && | ||||
| 		sumEqual(exit.X*n.X, exit.Y*n.Y, -n.Z) { | ||||
| 		return targetFace | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise return the face that is adjacent to the exit point in the | ||||
| 	// direction of the exit axis. | ||||
| 	return uvwFace(face, int(axis), exitAPos) | ||||
| } | ||||
							
								
								
									
										227
									
								
								vendor/github.com/golang/geo/s2/edge_crosser.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										227
									
								
								vendor/github.com/golang/geo/s2/edge_crosser.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,227 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| ) | ||||
| 
 | ||||
| // EdgeCrosser allows edges to be efficiently tested for intersection with a | ||||
| // given fixed edge AB. It is especially efficient when testing for | ||||
| // intersection with an edge chain connecting vertices v0, v1, v2, ... | ||||
| // | ||||
| // Example usage: | ||||
| // | ||||
| //	func CountIntersections(a, b Point, edges []Edge) int { | ||||
| //		count := 0 | ||||
| //		crosser := NewEdgeCrosser(a, b) | ||||
| //		for _, edge := range edges { | ||||
| //			if crosser.CrossingSign(&edge.First, &edge.Second) != DoNotCross { | ||||
| //				count++ | ||||
| //			} | ||||
| //		} | ||||
| //		return count | ||||
| //	} | ||||
| // | ||||
| type EdgeCrosser struct { | ||||
| 	a   Point | ||||
| 	b   Point | ||||
| 	aXb Point | ||||
| 
 | ||||
| 	// To reduce the number of calls to expensiveSign, we compute an | ||||
| 	// outward-facing tangent at A and B if necessary. If the plane | ||||
| 	// perpendicular to one of these tangents separates AB from CD (i.e., one | ||||
| 	// edge on each side) then there is no intersection. | ||||
| 	aTangent Point // Outward-facing tangent at A. | ||||
| 	bTangent Point // Outward-facing tangent at B. | ||||
| 
 | ||||
| 	// The fields below are updated for each vertex in the chain. | ||||
| 	c   Point     // Previous vertex in the vertex chain. | ||||
| 	acb Direction // The orientation of triangle ACB. | ||||
| } | ||||
| 
 | ||||
| // NewEdgeCrosser returns an EdgeCrosser with the fixed edge AB. | ||||
| func NewEdgeCrosser(a, b Point) *EdgeCrosser { | ||||
| 	norm := a.PointCross(b) | ||||
| 	return &EdgeCrosser{ | ||||
| 		a:        a, | ||||
| 		b:        b, | ||||
| 		aXb:      Point{a.Cross(b.Vector)}, | ||||
| 		aTangent: Point{a.Cross(norm.Vector)}, | ||||
| 		bTangent: Point{norm.Cross(b.Vector)}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CrossingSign reports whether the edge AB intersects the edge CD. If any two | ||||
| // vertices from different edges are the same, returns MaybeCross. If either edge | ||||
| // is degenerate (A == B or C == D), returns either DoNotCross or MaybeCross. | ||||
| // | ||||
| // Properties of CrossingSign: | ||||
| // | ||||
| //  (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d) | ||||
| //  (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d) | ||||
| //  (3) CrossingSign(a,b,c,d) == MaybeCross if a==c, a==d, b==c, b==d | ||||
| //  (3) CrossingSign(a,b,c,d) == DoNotCross or MaybeCross if a==b or c==d | ||||
| // | ||||
| // Note that if you want to check an edge against a chain of other edges, | ||||
| // it is slightly more efficient to use the single-argument version | ||||
| // ChainCrossingSign below. | ||||
| func (e *EdgeCrosser) CrossingSign(c, d Point) Crossing { | ||||
| 	if c != e.c { | ||||
| 		e.RestartAt(c) | ||||
| 	} | ||||
| 	return e.ChainCrossingSign(d) | ||||
| } | ||||
| 
 | ||||
| // EdgeOrVertexCrossing reports whether if CrossingSign(c, d) > 0, or AB and | ||||
| // CD share a vertex and VertexCrossing(a, b, c, d) is true. | ||||
| // | ||||
| // This method extends the concept of a "crossing" to the case where AB | ||||
| // and CD have a vertex in common. The two edges may or may not cross, | ||||
| // according to the rules defined in VertexCrossing above. The rules | ||||
| // are designed so that point containment tests can be implemented simply | ||||
| // by counting edge crossings. Similarly, determining whether one edge | ||||
| // chain crosses another edge chain can be implemented by counting. | ||||
| func (e *EdgeCrosser) EdgeOrVertexCrossing(c, d Point) bool { | ||||
| 	if c != e.c { | ||||
| 		e.RestartAt(c) | ||||
| 	} | ||||
| 	return e.EdgeOrVertexChainCrossing(d) | ||||
| } | ||||
| 
 | ||||
| // NewChainEdgeCrosser is a convenience constructor that uses AB as the fixed edge, | ||||
| // and C as the first vertex of the vertex chain (equivalent to calling RestartAt(c)). | ||||
| // | ||||
| // You don't need to use this or any of the chain functions unless you're trying to | ||||
| // squeeze out every last drop of performance. Essentially all you are saving is a test | ||||
| // whether the first vertex of the current edge is the same as the second vertex of the | ||||
| // previous edge. | ||||
| func NewChainEdgeCrosser(a, b, c Point) *EdgeCrosser { | ||||
| 	e := NewEdgeCrosser(a, b) | ||||
| 	e.RestartAt(c) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // RestartAt sets the current point of the edge crosser to be c. | ||||
| // Call this method when your chain 'jumps' to a new place. | ||||
| // The argument must point to a value that persists until the next call. | ||||
| func (e *EdgeCrosser) RestartAt(c Point) { | ||||
| 	e.c = c | ||||
| 	e.acb = -triageSign(e.a, e.b, e.c) | ||||
| } | ||||
| 
 | ||||
| // ChainCrossingSign is like CrossingSign, but uses the last vertex passed to one of | ||||
| // the crossing methods (or RestartAt) as the first vertex of the current edge. | ||||
| func (e *EdgeCrosser) ChainCrossingSign(d Point) Crossing { | ||||
| 	// For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must | ||||
| 	// all be oriented the same way (CW or CCW). We keep the orientation of ACB | ||||
| 	// as part of our state. When each new point D arrives, we compute the | ||||
| 	// orientation of BDA and check whether it matches ACB. This checks whether | ||||
| 	// the points C and D are on opposite sides of the great circle through AB. | ||||
| 
 | ||||
| 	// Recall that triageSign is invariant with respect to rotating its | ||||
| 	// arguments, i.e. ABD has the same orientation as BDA. | ||||
| 	bda := triageSign(e.a, e.b, d) | ||||
| 	if e.acb == -bda && bda != Indeterminate { | ||||
| 		// The most common case -- triangles have opposite orientations. Save the | ||||
| 		// current vertex D as the next vertex C, and also save the orientation of | ||||
| 		// the new triangle ACB (which is opposite to the current triangle BDA). | ||||
| 		e.c = d | ||||
| 		e.acb = -bda | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 	return e.crossingSign(d, bda) | ||||
| } | ||||
| 
 | ||||
| // EdgeOrVertexChainCrossing is like EdgeOrVertexCrossing, but uses the last vertex | ||||
| // passed to one of the crossing methods (or RestartAt) as the first vertex of the current edge. | ||||
| func (e *EdgeCrosser) EdgeOrVertexChainCrossing(d Point) bool { | ||||
| 	// We need to copy e.c since it is clobbered by ChainCrossingSign. | ||||
| 	c := e.c | ||||
| 	switch e.ChainCrossingSign(d) { | ||||
| 	case DoNotCross: | ||||
| 		return false | ||||
| 	case Cross: | ||||
| 		return true | ||||
| 	} | ||||
| 	return VertexCrossing(e.a, e.b, c, d) | ||||
| } | ||||
| 
 | ||||
| // crossingSign handle the slow path of CrossingSign. | ||||
| func (e *EdgeCrosser) crossingSign(d Point, bda Direction) Crossing { | ||||
| 	// Compute the actual result, and then save the current vertex D as the next | ||||
| 	// vertex C, and save the orientation of the next triangle ACB (which is | ||||
| 	// opposite to the current triangle BDA). | ||||
| 	defer func() { | ||||
| 		e.c = d | ||||
| 		e.acb = -bda | ||||
| 	}() | ||||
| 
 | ||||
| 	// At this point, a very common situation is that A,B,C,D are four points on | ||||
| 	// a line such that AB does not overlap CD. (For example, this happens when | ||||
| 	// a line or curve is sampled finely, or when geometry is constructed by | ||||
| 	// computing the union of S2CellIds.) Most of the time, we can determine | ||||
| 	// that AB and CD do not intersect using the two outward-facing | ||||
| 	// tangents at A and B (parallel to AB) and testing whether AB and CD are on | ||||
| 	// opposite sides of the plane perpendicular to one of these tangents. This | ||||
| 	// is moderately expensive but still much cheaper than expensiveSign. | ||||
| 
 | ||||
| 	// The error in RobustCrossProd is insignificant. The maximum error in | ||||
| 	// the call to CrossProd (i.e., the maximum norm of the error vector) is | ||||
| 	// (0.5 + 1/sqrt(3)) * dblEpsilon. The maximum error in each call to | ||||
| 	// DotProd below is dblEpsilon. (There is also a small relative error | ||||
| 	// term that is insignificant because we are comparing the result against a | ||||
| 	// constant that is very close to zero.) | ||||
| 	maxError := (1.5 + 1/math.Sqrt(3)) * dblEpsilon | ||||
| 	if (e.c.Dot(e.aTangent.Vector) > maxError && d.Dot(e.aTangent.Vector) > maxError) || (e.c.Dot(e.bTangent.Vector) > maxError && d.Dot(e.bTangent.Vector) > maxError) { | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, eliminate the cases where two vertices from different edges are | ||||
| 	// equal. (These cases could be handled in the code below, but we would rather | ||||
| 	// avoid calling ExpensiveSign if possible.) | ||||
| 	if e.a == e.c || e.a == d || e.b == e.c || e.b == d { | ||||
| 		return MaybeCross | ||||
| 	} | ||||
| 
 | ||||
| 	// Eliminate the cases where an input edge is degenerate. (Note that in | ||||
| 	// most cases, if CD is degenerate then this method is not even called | ||||
| 	// because acb and bda have different signs.) | ||||
| 	if e.a == e.b || e.c == d { | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise it's time to break out the big guns. | ||||
| 	if e.acb == Indeterminate { | ||||
| 		e.acb = -expensiveSign(e.a, e.b, e.c) | ||||
| 	} | ||||
| 	if bda == Indeterminate { | ||||
| 		bda = expensiveSign(e.a, e.b, d) | ||||
| 	} | ||||
| 
 | ||||
| 	if bda != e.acb { | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 
 | ||||
| 	cbd := -RobustSign(e.c, d, e.b) | ||||
| 	if cbd != e.acb { | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 	dac := RobustSign(e.c, d, e.a) | ||||
| 	if dac != e.acb { | ||||
| 		return DoNotCross | ||||
| 	} | ||||
| 	return Cross | ||||
| } | ||||
							
								
								
									
										396
									
								
								vendor/github.com/golang/geo/s2/edge_crossings.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										396
									
								
								vendor/github.com/golang/geo/s2/edge_crossings.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,396 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// intersectionError can be set somewhat arbitrarily, because the algorithm | ||||
| 	// uses more precision if necessary in order to achieve the specified error. | ||||
| 	// The only strict requirement is that intersectionError >= dblEpsilon | ||||
| 	// radians. However, using a larger error tolerance makes the algorithm more | ||||
| 	// efficient because it reduces the number of cases where exact arithmetic is | ||||
| 	// needed. | ||||
| 	intersectionError = s1.Angle(8 * dblError) | ||||
| 
 | ||||
| 	// intersectionMergeRadius is used to ensure that intersection points that | ||||
| 	// are supposed to be coincident are merged back together into a single | ||||
| 	// vertex. This is required in order for various polygon operations (union, | ||||
| 	// intersection, etc) to work correctly. It is twice the intersection error | ||||
| 	// because two coincident intersection points might have errors in | ||||
| 	// opposite directions. | ||||
| 	intersectionMergeRadius = 2 * intersectionError | ||||
| ) | ||||
| 
 | ||||
| // A Crossing indicates how edges cross. | ||||
| type Crossing int | ||||
| 
 | ||||
| const ( | ||||
| 	// Cross means the edges cross. | ||||
| 	Cross Crossing = iota | ||||
| 	// MaybeCross means two vertices from different edges are the same. | ||||
| 	MaybeCross | ||||
| 	// DoNotCross means the edges do not cross. | ||||
| 	DoNotCross | ||||
| ) | ||||
| 
 | ||||
| func (c Crossing) String() string { | ||||
| 	switch c { | ||||
| 	case Cross: | ||||
| 		return "Cross" | ||||
| 	case MaybeCross: | ||||
| 		return "MaybeCross" | ||||
| 	case DoNotCross: | ||||
| 		return "DoNotCross" | ||||
| 	default: | ||||
| 		return fmt.Sprintf("(BAD CROSSING %d)", c) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CrossingSign reports whether the edge AB intersects the edge CD. | ||||
| // If AB crosses CD at a point that is interior to both edges, Cross is returned. | ||||
| // If any two vertices from different edges are the same it returns MaybeCross. | ||||
| // Otherwise it returns DoNotCross. | ||||
| // If either edge is degenerate (A == B or C == D), the return value is MaybeCross | ||||
| // if two vertices from different edges are the same and DoNotCross otherwise. | ||||
| // | ||||
| // Properties of CrossingSign: | ||||
| // | ||||
| //  (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d) | ||||
| //  (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d) | ||||
| //  (3) CrossingSign(a,b,c,d) == MaybeCross if a==c, a==d, b==c, b==d | ||||
| //  (3) CrossingSign(a,b,c,d) == DoNotCross or MaybeCross if a==b or c==d | ||||
| // | ||||
| // This method implements an exact, consistent perturbation model such | ||||
| // that no three points are ever considered to be collinear. This means | ||||
| // that even if you have 4 points A, B, C, D that lie exactly in a line | ||||
| // (say, around the equator), C and D will be treated as being slightly to | ||||
| // one side or the other of AB. This is done in a way such that the | ||||
| // results are always consistent (see RobustSign). | ||||
| func CrossingSign(a, b, c, d Point) Crossing { | ||||
| 	crosser := NewChainEdgeCrosser(a, b, c) | ||||
| 	return crosser.ChainCrossingSign(d) | ||||
| } | ||||
| 
 | ||||
| // VertexCrossing reports whether two edges "cross" in such a way that point-in-polygon | ||||
| // containment tests can be implemented by counting the number of edge crossings. | ||||
| // | ||||
| // Given two edges AB and CD where at least two vertices are identical | ||||
| // (i.e. CrossingSign(a,b,c,d) == 0), the basic rule is that a "crossing" | ||||
| // occurs if AB is encountered after CD during a CCW sweep around the shared | ||||
| // vertex starting from a fixed reference point. | ||||
| // | ||||
| // Note that according to this rule, if AB crosses CD then in general CD | ||||
| // does not cross AB. However, this leads to the correct result when | ||||
| // counting polygon edge crossings. For example, suppose that A,B,C are | ||||
| // three consecutive vertices of a CCW polygon. If we now consider the edge | ||||
| // crossings of a segment BP as P sweeps around B, the crossing number | ||||
| // changes parity exactly when BP crosses BA or BC. | ||||
| // | ||||
| // Useful properties of VertexCrossing (VC): | ||||
| // | ||||
| //  (1) VC(a,a,c,d) == VC(a,b,c,c) == false | ||||
| //  (2) VC(a,b,a,b) == VC(a,b,b,a) == true | ||||
| //  (3) VC(a,b,c,d) == VC(a,b,d,c) == VC(b,a,c,d) == VC(b,a,d,c) | ||||
| //  (3) If exactly one of a,b equals one of c,d, then exactly one of | ||||
| //      VC(a,b,c,d) and VC(c,d,a,b) is true | ||||
| // | ||||
| // It is an error to call this method with 4 distinct vertices. | ||||
| func VertexCrossing(a, b, c, d Point) bool { | ||||
| 	// If A == B or C == D there is no intersection. We need to check this | ||||
| 	// case first in case 3 or more input points are identical. | ||||
| 	if a == b || c == d { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// If any other pair of vertices is equal, there is a crossing if and only | ||||
| 	// if OrderedCCW indicates that the edge AB is further CCW around the | ||||
| 	// shared vertex O (either A or B) than the edge CD, starting from an | ||||
| 	// arbitrary fixed reference point. | ||||
| 
 | ||||
| 	// Optimization: if AB=CD or AB=DC, we can avoid most of the calculations. | ||||
| 	switch { | ||||
| 	case a == c: | ||||
| 		return (b == d) || OrderedCCW(Point{a.Ortho()}, d, b, a) | ||||
| 	case b == d: | ||||
| 		return OrderedCCW(Point{b.Ortho()}, c, a, b) | ||||
| 	case a == d: | ||||
| 		return (b == c) || OrderedCCW(Point{a.Ortho()}, c, b, a) | ||||
| 	case b == c: | ||||
| 		return OrderedCCW(Point{b.Ortho()}, d, a, b) | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // EdgeOrVertexCrossing is a convenience function that calls CrossingSign to | ||||
| // handle cases where all four vertices are distinct, and VertexCrossing to | ||||
| // handle cases where two or more vertices are the same. This defines a crossing | ||||
| // function such that point-in-polygon containment tests can be implemented | ||||
| // by simply counting edge crossings. | ||||
| func EdgeOrVertexCrossing(a, b, c, d Point) bool { | ||||
| 	switch CrossingSign(a, b, c, d) { | ||||
| 	case DoNotCross: | ||||
| 		return false | ||||
| 	case Cross: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return VertexCrossing(a, b, c, d) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Intersection returns the intersection point of two edges AB and CD that cross | ||||
| // (CrossingSign(a,b,c,d) == Crossing). | ||||
| // | ||||
| // Useful properties of Intersection: | ||||
| // | ||||
| //  (1) Intersection(b,a,c,d) == Intersection(a,b,d,c) == Intersection(a,b,c,d) | ||||
| //  (2) Intersection(c,d,a,b) == Intersection(a,b,c,d) | ||||
| // | ||||
| // The returned intersection point X is guaranteed to be very close to the | ||||
| // true intersection point of AB and CD, even if the edges intersect at a | ||||
| // very small angle. | ||||
| func Intersection(a0, a1, b0, b1 Point) Point { | ||||
| 	// It is difficult to compute the intersection point of two edges accurately | ||||
| 	// when the angle between the edges is very small. Previously we handled | ||||
| 	// this by only guaranteeing that the returned intersection point is within | ||||
| 	// intersectionError of each edge. However, this means that when the edges | ||||
| 	// cross at a very small angle, the computed result may be very far from the | ||||
| 	// true intersection point. | ||||
| 	// | ||||
| 	// Instead this function now guarantees that the result is always within | ||||
| 	// intersectionError of the true intersection. This requires using more | ||||
| 	// sophisticated techniques and in some cases extended precision. | ||||
| 	// | ||||
| 	//  - intersectionStable computes the intersection point using | ||||
| 	//    projection and interpolation, taking care to minimize cancellation | ||||
| 	//    error. | ||||
| 	// | ||||
| 	//  - intersectionExact computes the intersection point using precision | ||||
| 	//    arithmetic and converts the final result back to an Point. | ||||
| 	pt, ok := intersectionStable(a0, a1, b0, b1) | ||||
| 	if !ok { | ||||
| 		pt = intersectionExact(a0, a1, b0, b1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Make sure the intersection point is on the correct side of the sphere. | ||||
| 	// Since all vertices are unit length, and edges are less than 180 degrees, | ||||
| 	// (a0 + a1) and (b0 + b1) both have positive dot product with the | ||||
| 	// intersection point.  We use the sum of all vertices to make sure that the | ||||
| 	// result is unchanged when the edges are swapped or reversed. | ||||
| 	if pt.Dot((a0.Add(a1.Vector)).Add(b0.Add(b1.Vector))) < 0 { | ||||
| 		pt = Point{pt.Mul(-1)} | ||||
| 	} | ||||
| 
 | ||||
| 	return pt | ||||
| } | ||||
| 
 | ||||
| // Computes the cross product of two vectors, normalized to be unit length. | ||||
| // Also returns the length of the cross | ||||
| // product before normalization, which is useful for estimating the amount of | ||||
| // error in the result.  For numerical stability, the vectors should both be | ||||
| // approximately unit length. | ||||
| func robustNormalWithLength(x, y r3.Vector) (r3.Vector, float64) { | ||||
| 	var pt r3.Vector | ||||
| 	// This computes 2 * (x.Cross(y)), but has much better numerical | ||||
| 	// stability when x and y are unit length. | ||||
| 	tmp := x.Sub(y).Cross(x.Add(y)) | ||||
| 	length := tmp.Norm() | ||||
| 	if length != 0 { | ||||
| 		pt = tmp.Mul(1 / length) | ||||
| 	} | ||||
| 	return pt, 0.5 * length // Since tmp == 2 * (x.Cross(y)) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| // intersectionSimple is not used by the C++ so it is skipped here. | ||||
| */ | ||||
| 
 | ||||
| // projection returns the projection of aNorm onto X (x.Dot(aNorm)), and a bound | ||||
| // on the error in the result. aNorm is not necessarily unit length. | ||||
| // | ||||
| // The remaining parameters (the length of aNorm (aNormLen) and the edge endpoints | ||||
| // a0 and a1) allow this dot product to be computed more accurately and efficiently. | ||||
| func projection(x, aNorm r3.Vector, aNormLen float64, a0, a1 Point) (proj, bound float64) { | ||||
| 	// The error in the dot product is proportional to the lengths of the input | ||||
| 	// vectors, so rather than using x itself (a unit-length vector) we use | ||||
| 	// the vectors from x to the closer of the two edge endpoints. This | ||||
| 	// typically reduces the error by a huge factor. | ||||
| 	x0 := x.Sub(a0.Vector) | ||||
| 	x1 := x.Sub(a1.Vector) | ||||
| 	x0Dist2 := x0.Norm2() | ||||
| 	x1Dist2 := x1.Norm2() | ||||
| 
 | ||||
| 	// If both distances are the same, we need to be careful to choose one | ||||
| 	// endpoint deterministically so that the result does not change if the | ||||
| 	// order of the endpoints is reversed. | ||||
| 	var dist float64 | ||||
| 	if x0Dist2 < x1Dist2 || (x0Dist2 == x1Dist2 && x0.Cmp(x1) == -1) { | ||||
| 		dist = math.Sqrt(x0Dist2) | ||||
| 		proj = x0.Dot(aNorm) | ||||
| 	} else { | ||||
| 		dist = math.Sqrt(x1Dist2) | ||||
| 		proj = x1.Dot(aNorm) | ||||
| 	} | ||||
| 
 | ||||
| 	// This calculation bounds the error from all sources: the computation of | ||||
| 	// the normal, the subtraction of one endpoint, and the dot product itself. | ||||
| 	// dblError appears because the input points are assumed to be | ||||
| 	// normalized in double precision. | ||||
| 	// | ||||
| 	// For reference, the bounds that went into this calculation are: | ||||
| 	// ||N'-N|| <= ((1 + 2 * sqrt(3))||N|| + 32 * sqrt(3) * dblError) * epsilon | ||||
| 	// |(A.B)'-(A.B)| <= (1.5 * (A.B) + 1.5 * ||A|| * ||B||) * epsilon | ||||
| 	// ||(X-Y)'-(X-Y)|| <= ||X-Y|| * epsilon | ||||
| 	bound = (((3.5+2*math.Sqrt(3))*aNormLen+32*math.Sqrt(3)*dblError)*dist + 1.5*math.Abs(proj)) * epsilon | ||||
| 	return proj, bound | ||||
| } | ||||
| 
 | ||||
| // compareEdges reports whether (a0,a1) is less than (b0,b1) with respect to a total | ||||
| // ordering on edges that is invariant under edge reversals. | ||||
| func compareEdges(a0, a1, b0, b1 Point) bool { | ||||
| 	if a0.Cmp(a1.Vector) != -1 { | ||||
| 		a0, a1 = a1, a0 | ||||
| 	} | ||||
| 	if b0.Cmp(b1.Vector) != -1 { | ||||
| 		b0, b1 = b1, b0 | ||||
| 	} | ||||
| 	return a0.Cmp(b0.Vector) == -1 || (a0 == b0 && b0.Cmp(b1.Vector) == -1) | ||||
| } | ||||
| 
 | ||||
| // intersectionStable returns the intersection point of the edges (a0,a1) and | ||||
| // (b0,b1) if it can be computed to within an error of at most intersectionError | ||||
| // by this function. | ||||
| // | ||||
| // The intersection point is not guaranteed to have the correct sign because we | ||||
| // choose to use the longest of the two edges first. The sign is corrected by | ||||
| // Intersection. | ||||
| func intersectionStable(a0, a1, b0, b1 Point) (Point, bool) { | ||||
| 	// Sort the two edges so that (a0,a1) is longer, breaking ties in a | ||||
| 	// deterministic way that does not depend on the ordering of the endpoints. | ||||
| 	// This is desirable for two reasons: | ||||
| 	//  - So that the result doesn't change when edges are swapped or reversed. | ||||
| 	//  - It reduces error, since the first edge is used to compute the edge | ||||
| 	//    normal (where a longer edge means less error), and the second edge | ||||
| 	//    is used for interpolation (where a shorter edge means less error). | ||||
| 	aLen2 := a1.Sub(a0.Vector).Norm2() | ||||
| 	bLen2 := b1.Sub(b0.Vector).Norm2() | ||||
| 	if aLen2 < bLen2 || (aLen2 == bLen2 && compareEdges(a0, a1, b0, b1)) { | ||||
| 		return intersectionStableSorted(b0, b1, a0, a1) | ||||
| 	} | ||||
| 	return intersectionStableSorted(a0, a1, b0, b1) | ||||
| } | ||||
| 
 | ||||
| // intersectionStableSorted is a helper function for intersectionStable. | ||||
| // It expects that the edges (a0,a1) and (b0,b1) have been sorted so that | ||||
| // the first edge passed in is longer. | ||||
| func intersectionStableSorted(a0, a1, b0, b1 Point) (Point, bool) { | ||||
| 	var pt Point | ||||
| 
 | ||||
| 	// Compute the normal of the plane through (a0, a1) in a stable way. | ||||
| 	aNorm := a0.Sub(a1.Vector).Cross(a0.Add(a1.Vector)) | ||||
| 	aNormLen := aNorm.Norm() | ||||
| 	bLen := b1.Sub(b0.Vector).Norm() | ||||
| 
 | ||||
| 	// Compute the projection (i.e., signed distance) of b0 and b1 onto the | ||||
| 	// plane through (a0, a1).  Distances are scaled by the length of aNorm. | ||||
| 	b0Dist, b0Error := projection(b0.Vector, aNorm, aNormLen, a0, a1) | ||||
| 	b1Dist, b1Error := projection(b1.Vector, aNorm, aNormLen, a0, a1) | ||||
| 
 | ||||
| 	// The total distance from b0 to b1 measured perpendicularly to (a0,a1) is | ||||
| 	// |b0Dist - b1Dist|.  Note that b0Dist and b1Dist generally have | ||||
| 	// opposite signs because b0 and b1 are on opposite sides of (a0, a1).  The | ||||
| 	// code below finds the intersection point by interpolating along the edge | ||||
| 	// (b0, b1) to a fractional distance of b0Dist / (b0Dist - b1Dist). | ||||
| 	// | ||||
| 	// It can be shown that the maximum error in the interpolation fraction is | ||||
| 	// | ||||
| 	//   (b0Dist * b1Error - b1Dist * b0Error) / (distSum * (distSum - errorSum)) | ||||
| 	// | ||||
| 	// We save ourselves some work by scaling the result and the error bound by | ||||
| 	// "distSum", since the result is normalized to be unit length anyway. | ||||
| 	distSum := math.Abs(b0Dist - b1Dist) | ||||
| 	errorSum := b0Error + b1Error | ||||
| 	if distSum <= errorSum { | ||||
| 		return pt, false // Error is unbounded in this case. | ||||
| 	} | ||||
| 
 | ||||
| 	x := b1.Mul(b0Dist).Sub(b0.Mul(b1Dist)) | ||||
| 	err := bLen*math.Abs(b0Dist*b1Error-b1Dist*b0Error)/ | ||||
| 		(distSum-errorSum) + 2*distSum*epsilon | ||||
| 
 | ||||
| 	// Finally we normalize the result, compute the corresponding error, and | ||||
| 	// check whether the total error is acceptable. | ||||
| 	xLen := x.Norm() | ||||
| 	maxError := intersectionError | ||||
| 	if err > (float64(maxError)-epsilon)*xLen { | ||||
| 		return pt, false | ||||
| 	} | ||||
| 
 | ||||
| 	return Point{x.Mul(1 / xLen)}, true | ||||
| } | ||||
| 
 | ||||
| // intersectionExact returns the intersection point of (a0, a1) and (b0, b1) | ||||
| // using precise arithmetic. Note that the result is not exact because it is | ||||
| // rounded down to double precision at the end. Also, the intersection point | ||||
| // is not guaranteed to have the correct sign (i.e., the return value may need | ||||
| // to be negated). | ||||
| func intersectionExact(a0, a1, b0, b1 Point) Point { | ||||
| 	// Since we are using presice arithmetic, we don't need to worry about | ||||
| 	// numerical stability. | ||||
| 	a0P := r3.PreciseVectorFromVector(a0.Vector) | ||||
| 	a1P := r3.PreciseVectorFromVector(a1.Vector) | ||||
| 	b0P := r3.PreciseVectorFromVector(b0.Vector) | ||||
| 	b1P := r3.PreciseVectorFromVector(b1.Vector) | ||||
| 	aNormP := a0P.Cross(a1P) | ||||
| 	bNormP := b0P.Cross(b1P) | ||||
| 	xP := aNormP.Cross(bNormP) | ||||
| 
 | ||||
| 	// The final Normalize() call is done in double precision, which creates a | ||||
| 	// directional error of up to 2*dblError. (Precise conversion and Normalize() | ||||
| 	// each contribute up to dblError of directional error.) | ||||
| 	x := xP.Vector() | ||||
| 
 | ||||
| 	if x == (r3.Vector{}) { | ||||
| 		// The two edges are exactly collinear, but we still consider them to be | ||||
| 		// "crossing" because of simulation of simplicity. Out of the four | ||||
| 		// endpoints, exactly two lie in the interior of the other edge. Of | ||||
| 		// those two we return the one that is lexicographically smallest. | ||||
| 		x = r3.Vector{10, 10, 10} // Greater than any valid S2Point | ||||
| 
 | ||||
| 		aNorm := Point{aNormP.Vector()} | ||||
| 		bNorm := Point{bNormP.Vector()} | ||||
| 		if OrderedCCW(b0, a0, b1, bNorm) && a0.Cmp(x) == -1 { | ||||
| 			return a0 | ||||
| 		} | ||||
| 		if OrderedCCW(b0, a1, b1, bNorm) && a1.Cmp(x) == -1 { | ||||
| 			return a1 | ||||
| 		} | ||||
| 		if OrderedCCW(a0, b0, a1, aNorm) && b0.Cmp(x) == -1 { | ||||
| 			return b0 | ||||
| 		} | ||||
| 		if OrderedCCW(a0, b1, a1, aNorm) && b1.Cmp(x) == -1 { | ||||
| 			return b1 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return Point{x} | ||||
| } | ||||
							
								
								
									
										408
									
								
								vendor/github.com/golang/geo/s2/edge_distances.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										408
									
								
								vendor/github.com/golang/geo/s2/edge_distances.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,408 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file defines a collection of methods for computing the distance to an edge, | ||||
| // interpolating along an edge, projecting points onto edges, etc. | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // DistanceFromSegment returns the distance of point X from line segment AB. | ||||
| // The points are expected to be normalized. The result is very accurate for small | ||||
| // distances but may have some numerical error if the distance is large | ||||
| // (approximately pi/2 or greater). The case A == B is handled correctly. | ||||
| func DistanceFromSegment(x, a, b Point) s1.Angle { | ||||
| 	var minDist s1.ChordAngle | ||||
| 	minDist, _ = updateMinDistance(x, a, b, minDist, true) | ||||
| 	return minDist.Angle() | ||||
| } | ||||
| 
 | ||||
| // IsDistanceLess reports whether the distance from X to the edge AB is less | ||||
| // than limit. (For less than or equal to, specify limit.Successor()). | ||||
| // This method is faster than DistanceFromSegment(). If you want to | ||||
| // compare against a fixed s1.Angle, you should convert it to an s1.ChordAngle | ||||
| // once and save the value, since this conversion is relatively expensive. | ||||
| func IsDistanceLess(x, a, b Point, limit s1.ChordAngle) bool { | ||||
| 	_, less := UpdateMinDistance(x, a, b, limit) | ||||
| 	return less | ||||
| } | ||||
| 
 | ||||
| // UpdateMinDistance checks if the distance from X to the edge AB is less | ||||
| // than minDist, and if so, returns the updated value and true. | ||||
| // The case A == B is handled correctly. | ||||
| // | ||||
| // Use this method when you want to compute many distances and keep track of | ||||
| // the minimum. It is significantly faster than using DistanceFromSegment | ||||
| // because (1) using s1.ChordAngle is much faster than s1.Angle, and (2) it | ||||
| // can save a lot of work by not actually computing the distance when it is | ||||
| // obviously larger than the current minimum. | ||||
| func UpdateMinDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) { | ||||
| 	return updateMinDistance(x, a, b, minDist, false) | ||||
| } | ||||
| 
 | ||||
| // UpdateMaxDistance checks if the distance from X to the edge AB is greater | ||||
| // than maxDist, and if so, returns the updated value and true. | ||||
| // Otherwise it returns false. The case A == B is handled correctly. | ||||
| func UpdateMaxDistance(x, a, b Point, maxDist s1.ChordAngle) (s1.ChordAngle, bool) { | ||||
| 	dist := maxChordAngle(ChordAngleBetweenPoints(x, a), ChordAngleBetweenPoints(x, b)) | ||||
| 	if dist > s1.RightChordAngle { | ||||
| 		dist, _ = updateMinDistance(Point{x.Mul(-1)}, a, b, dist, true) | ||||
| 		dist = s1.StraightChordAngle - dist | ||||
| 	} | ||||
| 	if maxDist < dist { | ||||
| 		return dist, true | ||||
| 	} | ||||
| 
 | ||||
| 	return maxDist, false | ||||
| } | ||||
| 
 | ||||
| // IsInteriorDistanceLess reports whether the minimum distance from X to the edge | ||||
| // AB is attained at an interior point of AB (i.e., not an endpoint), and that | ||||
| // distance is less than limit. (Specify limit.Successor() for less than or equal to). | ||||
| func IsInteriorDistanceLess(x, a, b Point, limit s1.ChordAngle) bool { | ||||
| 	_, less := UpdateMinInteriorDistance(x, a, b, limit) | ||||
| 	return less | ||||
| } | ||||
| 
 | ||||
| // UpdateMinInteriorDistance reports whether the minimum distance from X to AB | ||||
| // is attained at an interior point of AB (i.e., not an endpoint), and that distance | ||||
| // is less than minDist. If so, the value of minDist is updated and true is returned. | ||||
| // Otherwise it is unchanged and returns false. | ||||
| func UpdateMinInteriorDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) { | ||||
| 	return interiorDist(x, a, b, minDist, false) | ||||
| } | ||||
| 
 | ||||
| // Project returns the point along the edge AB that is closest to the point X. | ||||
| // The fractional distance of this point along the edge AB can be obtained | ||||
| // using DistanceFraction. | ||||
| // | ||||
| // This requires that all points are unit length. | ||||
| func Project(x, a, b Point) Point { | ||||
| 	aXb := a.PointCross(b) | ||||
| 	// Find the closest point to X along the great circle through AB. | ||||
| 	p := x.Sub(aXb.Mul(x.Dot(aXb.Vector) / aXb.Vector.Norm2())) | ||||
| 
 | ||||
| 	// If this point is on the edge AB, then it's the closest point. | ||||
| 	if Sign(aXb, a, Point{p}) && Sign(Point{p}, b, aXb) { | ||||
| 		return Point{p.Normalize()} | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the closest point is either A or B. | ||||
| 	if x.Sub(a.Vector).Norm2() <= x.Sub(b.Vector).Norm2() { | ||||
| 		return a | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| // DistanceFraction returns the distance ratio of the point X along an edge AB. | ||||
| // If X is on the line segment AB, this is the fraction T such | ||||
| // that X == Interpolate(T, A, B). | ||||
| // | ||||
| // This requires that A and B are distinct. | ||||
| func DistanceFraction(x, a, b Point) float64 { | ||||
| 	d0 := x.Angle(a.Vector) | ||||
| 	d1 := x.Angle(b.Vector) | ||||
| 	return float64(d0 / (d0 + d1)) | ||||
| } | ||||
| 
 | ||||
| // Interpolate returns the point X along the line segment AB whose distance from A | ||||
| // is the given fraction "t" of the distance AB. Does NOT require that "t" be | ||||
| // between 0 and 1. Note that all distances are measured on the surface of | ||||
| // the sphere, so this is more complicated than just computing (1-t)*a + t*b | ||||
| // and normalizing the result. | ||||
| func Interpolate(t float64, a, b Point) Point { | ||||
| 	if t == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	if t == 1 { | ||||
| 		return b | ||||
| 	} | ||||
| 	ab := a.Angle(b.Vector) | ||||
| 	return InterpolateAtDistance(s1.Angle(t)*ab, a, b) | ||||
| } | ||||
| 
 | ||||
| // InterpolateAtDistance returns the point X along the line segment AB whose | ||||
| // distance from A is the angle ax. | ||||
| func InterpolateAtDistance(ax s1.Angle, a, b Point) Point { | ||||
| 	aRad := ax.Radians() | ||||
| 
 | ||||
| 	// Use PointCross to compute the tangent vector at A towards B. The | ||||
| 	// result is always perpendicular to A, even if A=B or A=-B, but it is not | ||||
| 	// necessarily unit length. (We effectively normalize it below.) | ||||
| 	normal := a.PointCross(b) | ||||
| 	tangent := normal.Vector.Cross(a.Vector) | ||||
| 
 | ||||
| 	// Now compute the appropriate linear combination of A and "tangent". With | ||||
| 	// infinite precision the result would always be unit length, but we | ||||
| 	// normalize it anyway to ensure that the error is within acceptable bounds. | ||||
| 	// (Otherwise errors can build up when the result of one interpolation is | ||||
| 	// fed into another interpolation.) | ||||
| 	return Point{(a.Mul(math.Cos(aRad)).Add(tangent.Mul(math.Sin(aRad) / tangent.Norm()))).Normalize()} | ||||
| } | ||||
| 
 | ||||
| // minUpdateDistanceMaxError returns the maximum error in the result of | ||||
| // UpdateMinDistance (and the associated functions such as | ||||
| // UpdateMinInteriorDistance, IsDistanceLess, etc), assuming that all | ||||
| // input points are normalized to within the bounds guaranteed by r3.Vector's | ||||
| // Normalize. The error can be added or subtracted from an s1.ChordAngle | ||||
| // using its Expanded method. | ||||
| func minUpdateDistanceMaxError(dist s1.ChordAngle) float64 { | ||||
| 	// There are two cases for the maximum error in UpdateMinDistance(), | ||||
| 	// depending on whether the closest point is interior to the edge. | ||||
| 	return math.Max(minUpdateInteriorDistanceMaxError(dist), dist.MaxPointError()) | ||||
| } | ||||
| 
 | ||||
| // minUpdateInteriorDistanceMaxError returns the maximum error in the result of | ||||
| // UpdateMinInteriorDistance, assuming that all input points are normalized | ||||
| // to within the bounds guaranteed by Point's Normalize. The error can be added | ||||
| // or subtracted from an s1.ChordAngle using its Expanded method. | ||||
| // | ||||
| // Note that accuracy goes down as the distance approaches 0 degrees or 180 | ||||
| // degrees (for different reasons). Near 0 degrees the error is acceptable | ||||
| // for all practical purposes (about 1.2e-15 radians ~= 8 nanometers).  For | ||||
| // exactly antipodal points the maximum error is quite high (0.5 meters), | ||||
| // but this error drops rapidly as the points move away from antipodality | ||||
| // (approximately 1 millimeter for points that are 50 meters from antipodal, | ||||
| // and 1 micrometer for points that are 50km from antipodal). | ||||
| // | ||||
| // TODO(roberts): Currently the error bound does not hold for edges whose endpoints | ||||
| // are antipodal to within about 1e-15 radians (less than 1 micron). This could | ||||
| // be fixed by extending PointCross to use higher precision when necessary. | ||||
| func minUpdateInteriorDistanceMaxError(dist s1.ChordAngle) float64 { | ||||
| 	// If a point is more than 90 degrees from an edge, then the minimum | ||||
| 	// distance is always to one of the endpoints, not to the edge interior. | ||||
| 	if dist >= s1.RightChordAngle { | ||||
| 		return 0.0 | ||||
| 	} | ||||
| 
 | ||||
| 	// This bound includes all source of error, assuming that the input points | ||||
| 	// are normalized. a and b are components of chord length that are | ||||
| 	// perpendicular and parallel to a plane containing the edge respectively. | ||||
| 	b := math.Min(1.0, 0.5*float64(dist)) | ||||
| 	a := math.Sqrt(b * (2 - b)) | ||||
| 	return ((2.5+2*math.Sqrt(3)+8.5*a)*a + | ||||
| 		(2+2*math.Sqrt(3)/3+6.5*(1-b))*b + | ||||
| 		(23+16/math.Sqrt(3))*dblEpsilon) * dblEpsilon | ||||
| } | ||||
| 
 | ||||
| // updateMinDistance computes the distance from a point X to a line segment AB, | ||||
| // and if either the distance was less than the given minDist, or alwaysUpdate is | ||||
| // true, the value and whether it was updated are returned. | ||||
| func updateMinDistance(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) { | ||||
| 	if d, ok := interiorDist(x, a, b, minDist, alwaysUpdate); ok { | ||||
| 		// Minimum distance is attained along the edge interior. | ||||
| 		return d, true | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise the minimum distance is to one of the endpoints. | ||||
| 	xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2() | ||||
| 	dist := s1.ChordAngle(math.Min(xa2, xb2)) | ||||
| 	if !alwaysUpdate && dist >= minDist { | ||||
| 		return minDist, false | ||||
| 	} | ||||
| 	return dist, true | ||||
| } | ||||
| 
 | ||||
| // interiorDist returns the shortest distance from point x to edge ab, assuming | ||||
| // that the closest point to X is interior to AB. If the closest point is not | ||||
| // interior to AB, interiorDist returns (minDist, false). If alwaysUpdate is set to | ||||
| // false, the distance is only updated when the value exceeds certain the given minDist. | ||||
| func interiorDist(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) { | ||||
| 	// Chord distance of x to both end points a and b. | ||||
| 	xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2() | ||||
| 
 | ||||
| 	// The closest point on AB could either be one of the two vertices (the | ||||
| 	// vertex case) or in the interior (the interior case). Let C = A x B. | ||||
| 	// If X is in the spherical wedge extending from A to B around the axis | ||||
| 	// through C, then we are in the interior case. Otherwise we are in the | ||||
| 	// vertex case. | ||||
| 	// | ||||
| 	// Check whether we might be in the interior case. For this to be true, XAB | ||||
| 	// and XBA must both be acute angles. Checking this condition exactly is | ||||
| 	// expensive, so instead we consider the planar triangle ABX (which passes | ||||
| 	// through the sphere's interior). The planar angles XAB and XBA are always | ||||
| 	// less than the corresponding spherical angles, so if we are in the | ||||
| 	// interior case then both of these angles must be acute. | ||||
| 	// | ||||
| 	// We check this by computing the squared edge lengths of the planar | ||||
| 	// triangle ABX, and testing whether angles XAB and XBA are both acute using | ||||
| 	// the law of cosines: | ||||
| 	// | ||||
| 	//            | XA^2 - XB^2 | < AB^2      (*) | ||||
| 	// | ||||
| 	// This test must be done conservatively (taking numerical errors into | ||||
| 	// account) since otherwise we might miss a situation where the true minimum | ||||
| 	// distance is achieved by a point on the edge interior. | ||||
| 	// | ||||
| 	// There are two sources of error in the expression above (*).  The first is | ||||
| 	// that points are not normalized exactly; they are only guaranteed to be | ||||
| 	// within 2 * dblEpsilon of unit length.  Under the assumption that the two | ||||
| 	// sides of (*) are nearly equal, the total error due to normalization errors | ||||
| 	// can be shown to be at most | ||||
| 	// | ||||
| 	//        2 * dblEpsilon * (XA^2 + XB^2 + AB^2) + 8 * dblEpsilon ^ 2 . | ||||
| 	// | ||||
| 	// The other source of error is rounding of results in the calculation of (*). | ||||
| 	// Each of XA^2, XB^2, AB^2 has a maximum relative error of 2.5 * dblEpsilon, | ||||
| 	// plus an additional relative error of 0.5 * dblEpsilon in the final | ||||
| 	// subtraction which we further bound as 0.25 * dblEpsilon * (XA^2 + XB^2 + | ||||
| 	// AB^2) for convenience.  This yields a final error bound of | ||||
| 	// | ||||
| 	//        4.75 * dblEpsilon * (XA^2 + XB^2 + AB^2) + 8 * dblEpsilon ^ 2 . | ||||
| 	ab2 := a.Sub(b.Vector).Norm2() | ||||
| 	maxError := (4.75*dblEpsilon*(xa2+xb2+ab2) + 8*dblEpsilon*dblEpsilon) | ||||
| 	if math.Abs(xa2-xb2) >= ab2+maxError { | ||||
| 		return minDist, false | ||||
| 	} | ||||
| 
 | ||||
| 	// The minimum distance might be to a point on the edge interior. Let R | ||||
| 	// be closest point to X that lies on the great circle through AB. Rather | ||||
| 	// than computing the geodesic distance along the surface of the sphere, | ||||
| 	// instead we compute the "chord length" through the sphere's interior. | ||||
| 	// | ||||
| 	// The squared chord length XR^2 can be expressed as XQ^2 + QR^2, where Q | ||||
| 	// is the point X projected onto the plane through the great circle AB. | ||||
| 	// The distance XQ^2 can be written as (X.C)^2 / |C|^2 where C = A x B. | ||||
| 	// We ignore the QR^2 term and instead use XQ^2 as a lower bound, since it | ||||
| 	// is faster and the corresponding distance on the Earth's surface is | ||||
| 	// accurate to within 1% for distances up to about 1800km. | ||||
| 	c := a.PointCross(b) | ||||
| 	c2 := c.Norm2() | ||||
| 	xDotC := x.Dot(c.Vector) | ||||
| 	xDotC2 := xDotC * xDotC | ||||
| 	if !alwaysUpdate && xDotC2 > c2*float64(minDist) { | ||||
| 		// The closest point on the great circle AB is too far away.  We need to | ||||
| 		// test this using ">" rather than ">=" because the actual minimum bound | ||||
| 		// on the distance is (xDotC2 / c2), which can be rounded differently | ||||
| 		// than the (more efficient) multiplicative test above. | ||||
| 		return minDist, false | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise we do the exact, more expensive test for the interior case. | ||||
| 	// This test is very likely to succeed because of the conservative planar | ||||
| 	// test we did initially. | ||||
| 	// | ||||
| 	// TODO(roberts): Ensure that the errors in test are accurately reflected in the | ||||
| 	// minUpdateInteriorDistanceMaxError. | ||||
| 	cx := c.Cross(x.Vector) | ||||
| 	if a.Sub(x.Vector).Dot(cx) >= 0 || b.Sub(x.Vector).Dot(cx) <= 0 { | ||||
| 		return minDist, false | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the squared chord length XR^2 = XQ^2 + QR^2 (see above). | ||||
| 	// This calculation has good accuracy for all chord lengths since it | ||||
| 	// is based on both the dot product and cross product (rather than | ||||
| 	// deriving one from the other). However, note that the chord length | ||||
| 	// representation itself loses accuracy as the angle approaches π. | ||||
| 	qr := 1 - math.Sqrt(cx.Norm2()/c2) | ||||
| 	dist := s1.ChordAngle((xDotC2 / c2) + (qr * qr)) | ||||
| 
 | ||||
| 	if !alwaysUpdate && dist >= minDist { | ||||
| 		return minDist, false | ||||
| 	} | ||||
| 
 | ||||
| 	return dist, true | ||||
| } | ||||
| 
 | ||||
| // updateEdgePairMinDistance computes the minimum distance between the given | ||||
| // pair of edges. If the two edges cross, the distance is zero. The cases | ||||
| // a0 == a1 and b0 == b1 are handled correctly. | ||||
| func updateEdgePairMinDistance(a0, a1, b0, b1 Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) { | ||||
| 	if minDist == 0 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	if CrossingSign(a0, a1, b0, b1) == Cross { | ||||
| 		minDist = 0 | ||||
| 		return 0, true | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the minimum distance is achieved at an endpoint of at least | ||||
| 	// one of the two edges. We ensure that all four possibilities are always checked. | ||||
| 	// | ||||
| 	// The calculation below computes each of the six vertex-vertex distances | ||||
| 	// twice (this could be optimized). | ||||
| 	var ok1, ok2, ok3, ok4 bool | ||||
| 	minDist, ok1 = UpdateMinDistance(a0, b0, b1, minDist) | ||||
| 	minDist, ok2 = UpdateMinDistance(a1, b0, b1, minDist) | ||||
| 	minDist, ok3 = UpdateMinDistance(b0, a0, a1, minDist) | ||||
| 	minDist, ok4 = UpdateMinDistance(b1, a0, a1, minDist) | ||||
| 	return minDist, ok1 || ok2 || ok3 || ok4 | ||||
| } | ||||
| 
 | ||||
| // updateEdgePairMaxDistance reports the minimum distance between the given pair of edges. | ||||
| // If one edge crosses the antipodal reflection of the other, the distance is pi. | ||||
| func updateEdgePairMaxDistance(a0, a1, b0, b1 Point, maxDist s1.ChordAngle) (s1.ChordAngle, bool) { | ||||
| 	if maxDist == s1.StraightChordAngle { | ||||
| 		return s1.StraightChordAngle, false | ||||
| 	} | ||||
| 	if CrossingSign(a0, a1, Point{b0.Mul(-1)}, Point{b1.Mul(-1)}) == Cross { | ||||
| 		return s1.StraightChordAngle, true | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, the maximum distance is achieved at an endpoint of at least | ||||
| 	// one of the two edges. We ensure that all four possibilities are always checked. | ||||
| 	// | ||||
| 	// The calculation below computes each of the six vertex-vertex distances | ||||
| 	// twice (this could be optimized). | ||||
| 	var ok1, ok2, ok3, ok4 bool | ||||
| 	maxDist, ok1 = UpdateMaxDistance(a0, b0, b1, maxDist) | ||||
| 	maxDist, ok2 = UpdateMaxDistance(a1, b0, b1, maxDist) | ||||
| 	maxDist, ok3 = UpdateMaxDistance(b0, a0, a1, maxDist) | ||||
| 	maxDist, ok4 = UpdateMaxDistance(b1, a0, a1, maxDist) | ||||
| 	return maxDist, ok1 || ok2 || ok3 || ok4 | ||||
| } | ||||
| 
 | ||||
| // EdgePairClosestPoints returns the pair of points (a, b) that achieves the | ||||
| // minimum distance between edges a0a1 and b0b1, where a is a point on a0a1 and | ||||
| // b is a point on b0b1. If the two edges intersect, a and b are both equal to | ||||
| // the intersection point. Handles a0 == a1 and b0 == b1 correctly. | ||||
| func EdgePairClosestPoints(a0, a1, b0, b1 Point) (Point, Point) { | ||||
| 	if CrossingSign(a0, a1, b0, b1) == Cross { | ||||
| 		x := Intersection(a0, a1, b0, b1) | ||||
| 		return x, x | ||||
| 	} | ||||
| 	// We save some work by first determining which vertex/edge pair achieves | ||||
| 	// the minimum distance, and then computing the closest point on that edge. | ||||
| 	var minDist s1.ChordAngle | ||||
| 	var ok bool | ||||
| 
 | ||||
| 	minDist, ok = updateMinDistance(a0, b0, b1, minDist, true) | ||||
| 	closestVertex := 0 | ||||
| 	if minDist, ok = UpdateMinDistance(a1, b0, b1, minDist); ok { | ||||
| 		closestVertex = 1 | ||||
| 	} | ||||
| 	if minDist, ok = UpdateMinDistance(b0, a0, a1, minDist); ok { | ||||
| 		closestVertex = 2 | ||||
| 	} | ||||
| 	if minDist, ok = UpdateMinDistance(b1, a0, a1, minDist); ok { | ||||
| 		closestVertex = 3 | ||||
| 	} | ||||
| 	switch closestVertex { | ||||
| 	case 0: | ||||
| 		return a0, Project(a0, b0, b1) | ||||
| 	case 1: | ||||
| 		return a1, Project(a1, b0, b1) | ||||
| 	case 2: | ||||
| 		return Project(b0, a0, a1), b0 | ||||
| 	case 3: | ||||
| 		return Project(b1, a0, a1), b1 | ||||
| 	default: | ||||
| 		panic("illegal case reached") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										803
									
								
								vendor/github.com/golang/geo/s2/edge_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										803
									
								
								vendor/github.com/golang/geo/s2/edge_query.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,803 +0,0 @@ | |||
| // Copyright 2019 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // EdgeQueryOptions holds the options for controlling how EdgeQuery operates. | ||||
| // | ||||
| // Options can be chained together builder-style: | ||||
| // | ||||
| //	opts = NewClosestEdgeQueryOptions(). | ||||
| //		MaxResults(1). | ||||
| //		DistanceLimit(s1.ChordAngleFromAngle(3 * s1.Degree)). | ||||
| //		MaxError(s1.ChordAngleFromAngle(0.001 * s1.Degree)) | ||||
| //	query = NewClosestEdgeQuery(index, opts) | ||||
| // | ||||
| //  or set individually: | ||||
| // | ||||
| //	opts = NewClosestEdgeQueryOptions() | ||||
| //	opts.IncludeInteriors(true) | ||||
| // | ||||
| // or just inline: | ||||
| // | ||||
| //	query = NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions().MaxResults(3)) | ||||
| // | ||||
| // If you pass a nil as the options you get the default values for the options. | ||||
| type EdgeQueryOptions struct { | ||||
| 	common *queryOptions | ||||
| } | ||||
| 
 | ||||
| // DistanceLimit specifies that only edges whose distance to the target is | ||||
| // within, this distance should be returned.  Edges whose distance is equal | ||||
| // are not returned. To include values that are equal, specify the limit with | ||||
| // the next largest representable distance. i.e. limit.Successor(). | ||||
| func (e *EdgeQueryOptions) DistanceLimit(limit s1.ChordAngle) *EdgeQueryOptions { | ||||
| 	e.common = e.common.DistanceLimit(limit) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // IncludeInteriors specifies whether polygon interiors should be | ||||
| // included when measuring distances. | ||||
| func (e *EdgeQueryOptions) IncludeInteriors(x bool) *EdgeQueryOptions { | ||||
| 	e.common = e.common.IncludeInteriors(x) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // UseBruteForce sets or disables the use of brute force in a query. | ||||
| func (e *EdgeQueryOptions) UseBruteForce(x bool) *EdgeQueryOptions { | ||||
| 	e.common = e.common.UseBruteForce(x) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // MaxError specifies that edges up to dist away than the true | ||||
| // matching edges may be substituted in the result set, as long as such | ||||
| // edges satisfy all the remaining search criteria (such as DistanceLimit). | ||||
| // This option only has an effect if MaxResults is also specified; | ||||
| // otherwise all edges closer than MaxDistance will always be returned. | ||||
| func (e *EdgeQueryOptions) MaxError(dist s1.ChordAngle) *EdgeQueryOptions { | ||||
| 	e.common = e.common.MaxError(dist) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // MaxResults specifies that at most MaxResults edges should be returned. | ||||
| // This must be at least 1. | ||||
| func (e *EdgeQueryOptions) MaxResults(n int) *EdgeQueryOptions { | ||||
| 	e.common = e.common.MaxResults(n) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // NewClosestEdgeQueryOptions returns a set of edge query options suitable | ||||
| // for performing closest edge queries. | ||||
| func NewClosestEdgeQueryOptions() *EdgeQueryOptions { | ||||
| 	return &EdgeQueryOptions{ | ||||
| 		common: newQueryOptions(minDistance(0)), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewFurthestEdgeQueryOptions returns a set of edge query options suitable | ||||
| // for performing furthest edge queries. | ||||
| func NewFurthestEdgeQueryOptions() *EdgeQueryOptions { | ||||
| 	return &EdgeQueryOptions{ | ||||
| 		common: newQueryOptions(maxDistance(0)), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // EdgeQueryResult represents an edge that meets the target criteria for the | ||||
| // query. Note the following special cases: | ||||
| // | ||||
| //  - ShapeID >= 0 && EdgeID < 0 represents the interior of a shape. | ||||
| //    Such results may be returned when the option IncludeInteriors is true. | ||||
| // | ||||
| //  - ShapeID < 0 && EdgeID < 0 is returned to indicate that no edge | ||||
| //    satisfies the requested query options. | ||||
| type EdgeQueryResult struct { | ||||
| 	distance distance | ||||
| 	shapeID  int32 | ||||
| 	edgeID   int32 | ||||
| } | ||||
| 
 | ||||
| // Distance reports the distance between the edge in this shape that satisfied | ||||
| // the query's parameters. | ||||
| func (e EdgeQueryResult) Distance() s1.ChordAngle { return e.distance.chordAngle() } | ||||
| 
 | ||||
| // ShapeID reports the ID of the Shape this result is for. | ||||
| func (e EdgeQueryResult) ShapeID() int32 { return e.shapeID } | ||||
| 
 | ||||
| // EdgeID reports the ID of the edge in the results Shape. | ||||
| func (e EdgeQueryResult) EdgeID() int32 { return e.edgeID } | ||||
| 
 | ||||
| // newEdgeQueryResult returns a result instance with default values. | ||||
| func newEdgeQueryResult(target distanceTarget) EdgeQueryResult { | ||||
| 	return EdgeQueryResult{ | ||||
| 		distance: target.distance().infinity(), | ||||
| 		shapeID:  -1, | ||||
| 		edgeID:   -1, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // IsInterior reports if this result represents the interior of a Shape. | ||||
| func (e EdgeQueryResult) IsInterior() bool { | ||||
| 	return e.shapeID >= 0 && e.edgeID < 0 | ||||
| } | ||||
| 
 | ||||
| // IsEmpty reports if this has no edge that satisfies the given edge query options. | ||||
| // This result is only returned in one special case, namely when FindEdge() does | ||||
| // not find any suitable edges. | ||||
| func (e EdgeQueryResult) IsEmpty() bool { | ||||
| 	return e.shapeID < 0 | ||||
| } | ||||
| 
 | ||||
| // Less reports if this results is less that the other first by distance, | ||||
| // then by (shapeID, edgeID). This is used for sorting. | ||||
| func (e EdgeQueryResult) Less(other EdgeQueryResult) bool { | ||||
| 	if e.distance.chordAngle() != other.distance.chordAngle() { | ||||
| 		return e.distance.less(other.distance) | ||||
| 	} | ||||
| 	if e.shapeID != other.shapeID { | ||||
| 		return e.shapeID < other.shapeID | ||||
| 	} | ||||
| 	return e.edgeID < other.edgeID | ||||
| } | ||||
| 
 | ||||
| // EdgeQuery is used to find the edge(s) between two geometries that match a | ||||
| // given set of options. It is flexible enough so that it can be adapted to | ||||
| // compute maximum distances and even potentially Hausdorff distances. | ||||
| // | ||||
| // By using the appropriate options, this type can answer questions such as: | ||||
| // | ||||
| //  - Find the minimum distance between two geometries A and B. | ||||
| //  - Find all edges of geometry A that are within a distance D of geometry B. | ||||
| //  - Find the k edges of geometry A that are closest to a given point P. | ||||
| // | ||||
| // You can also specify whether polygons should include their interiors (i.e., | ||||
| // if a point is contained by a polygon, should the distance be zero or should | ||||
| // it be measured to the polygon boundary?) | ||||
| // | ||||
| // The input geometries may consist of any number of points, polylines, and | ||||
| // polygons (collectively referred to as "shapes"). Shapes do not need to be | ||||
| // disjoint; they may overlap or intersect arbitrarily. The implementation is | ||||
| // designed to be fast for both simple and complex geometries. | ||||
| type EdgeQuery struct { | ||||
| 	index  *ShapeIndex | ||||
| 	opts   *queryOptions | ||||
| 	target distanceTarget | ||||
| 
 | ||||
| 	// True if opts.maxError must be subtracted from ShapeIndex cell distances | ||||
| 	// in order to ensure that such distances are measured conservatively. This | ||||
| 	// is true only if the target takes advantage of maxError in order to | ||||
| 	// return faster results, and 0 < maxError < distanceLimit. | ||||
| 	useConservativeCellDistance bool | ||||
| 
 | ||||
| 	// The decision about whether to use the brute force algorithm is based on | ||||
| 	// counting the total number of edges in the index. However if the index | ||||
| 	// contains a large number of shapes, this in itself might take too long. | ||||
| 	// So instead we only count edges up to (maxBruteForceIndexSize() + 1) | ||||
| 	// for the current target type (stored as indexNumEdgesLimit). | ||||
| 	indexNumEdges      int | ||||
| 	indexNumEdgesLimit int | ||||
| 
 | ||||
| 	// The distance beyond which we can safely ignore further candidate edges. | ||||
| 	// (Candidates that are exactly at the limit are ignored; this is more | ||||
| 	// efficient for UpdateMinDistance and should not affect clients since | ||||
| 	// distance measurements have a small amount of error anyway.) | ||||
| 	// | ||||
| 	// Initially this is the same as the maximum distance specified by the user, | ||||
| 	// but it can also be updated by the algorithm (see maybeAddResult). | ||||
| 	distanceLimit distance | ||||
| 
 | ||||
| 	// The current set of results of the query. | ||||
| 	results []EdgeQueryResult | ||||
| 
 | ||||
| 	// This field is true when duplicates must be avoided explicitly. This | ||||
| 	// is achieved by maintaining a separate set keyed by (shapeID, edgeID) | ||||
| 	// only, and checking whether each edge is in that set before computing the | ||||
| 	// distance to it. | ||||
| 	avoidDuplicates bool | ||||
| 
 | ||||
| 	// testedEdges tracks the set of shape and edges that have already been tested. | ||||
| 	testedEdges map[ShapeEdgeID]uint32 | ||||
| 
 | ||||
| 	// For the optimized algorihm we precompute the top-level CellIDs that | ||||
| 	// will be added to the priority queue. There can be at most 6 of these | ||||
| 	// cells. Essentially this is just a covering of the indexed edges, except | ||||
| 	// that we also store pointers to the corresponding ShapeIndexCells to | ||||
| 	// reduce the number of index seeks required. | ||||
| 	indexCovering []CellID | ||||
| 	indexCells    []*ShapeIndexCell | ||||
| 
 | ||||
| 	// The algorithm maintains a priority queue of unprocessed CellIDs, sorted | ||||
| 	// in increasing order of distance from the target. | ||||
| 	queue *queryQueue | ||||
| 
 | ||||
| 	iter                *ShapeIndexIterator | ||||
| 	maxDistanceCovering []CellID | ||||
| 	initialCells        []CellID | ||||
| } | ||||
| 
 | ||||
| // NewClosestEdgeQuery returns an EdgeQuery that is used for finding the | ||||
| // closest edge(s) to a given Point, Edge, Cell, or geometry collection. | ||||
| // | ||||
| // You can find either the k closest edges, or all edges within a given | ||||
| // radius, or both (i.e., the k closest edges up to a given maximum radius). | ||||
| // E.g. to find all the edges within 5 kilometers, set the DistanceLimit in | ||||
| // the options. | ||||
| // | ||||
| // By default *all* edges are returned, so you should always specify either | ||||
| // MaxResults or DistanceLimit options or both. | ||||
| // | ||||
| // Note that by default, distances are measured to the boundary and interior | ||||
| // of polygons. For example, if a point is inside a polygon then its distance | ||||
| // is zero. To change this behavior, set the IncludeInteriors option to false. | ||||
| // | ||||
| // If you only need to test whether the distance is above or below a given | ||||
| // threshold (e.g., 10 km), you can use the IsDistanceLess() method.  This is | ||||
| // much faster than actually calculating the distance with FindEdge, | ||||
| // since the implementation can stop as soon as it can prove that the minimum | ||||
| // distance is either above or below the threshold. | ||||
| func NewClosestEdgeQuery(index *ShapeIndex, opts *EdgeQueryOptions) *EdgeQuery { | ||||
| 	if opts == nil { | ||||
| 		opts = NewClosestEdgeQueryOptions() | ||||
| 	} | ||||
| 	e := &EdgeQuery{ | ||||
| 		testedEdges: make(map[ShapeEdgeID]uint32), | ||||
| 		index:       index, | ||||
| 		opts:        opts.common, | ||||
| 		queue:       newQueryQueue(), | ||||
| 	} | ||||
| 
 | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // NewFurthestEdgeQuery returns an EdgeQuery that is used for finding the | ||||
| // furthest edge(s) to a given Point, Edge, Cell, or geometry collection. | ||||
| // | ||||
| // The furthest edge is defined as the one which maximizes the | ||||
| // distance from any point on that edge to any point on the target geometry. | ||||
| // | ||||
| // Similar to the example in NewClosestEdgeQuery, to find the 5 furthest edges | ||||
| // from a given Point: | ||||
| func NewFurthestEdgeQuery(index *ShapeIndex, opts *EdgeQueryOptions) *EdgeQuery { | ||||
| 	if opts == nil { | ||||
| 		opts = NewFurthestEdgeQueryOptions() | ||||
| 	} | ||||
| 	e := &EdgeQuery{ | ||||
| 		testedEdges: make(map[ShapeEdgeID]uint32), | ||||
| 		index:       index, | ||||
| 		opts:        opts.common, | ||||
| 		queue:       newQueryQueue(), | ||||
| 	} | ||||
| 
 | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // Reset resets the state of this EdgeQuery. | ||||
| func (e *EdgeQuery) Reset() { | ||||
| 	e.indexNumEdges = 0 | ||||
| 	e.indexNumEdgesLimit = 0 | ||||
| 	e.indexCovering = nil | ||||
| 	e.indexCells = nil | ||||
| } | ||||
| 
 | ||||
| // FindEdges returns the edges for the given target that satisfy the current options. | ||||
| // | ||||
| // Note that if opts.IncludeInteriors is true, the results may include some | ||||
| // entries with edge_id == -1. This indicates that the target intersects | ||||
| // the indexed polygon with the given ShapeID. | ||||
| func (e *EdgeQuery) FindEdges(target distanceTarget) []EdgeQueryResult { | ||||
| 	return e.findEdges(target, e.opts) | ||||
| } | ||||
| 
 | ||||
| // Distance reports the distance to the target. If the index or target is empty, | ||||
| // returns the EdgeQuery's maximal sentinel. | ||||
| // | ||||
| // Use IsDistanceLess()/IsDistanceGreater() if you only want to compare the | ||||
| // distance against a threshold value, since it is often much faster. | ||||
| func (e *EdgeQuery) Distance(target distanceTarget) s1.ChordAngle { | ||||
| 	return e.findEdge(target, e.opts).Distance() | ||||
| } | ||||
| 
 | ||||
| // IsDistanceLess reports if the distance to target is less than the given limit. | ||||
| // | ||||
| // This method is usually much faster than Distance(), since it is much | ||||
| // less work to determine whether the minimum distance is above or below a | ||||
| // threshold than it is to calculate the actual minimum distance. | ||||
| // | ||||
| // If you wish to check if the distance is less than or equal to the limit, use: | ||||
| // | ||||
| //	query.IsDistanceLess(target, limit.Successor()) | ||||
| // | ||||
| func (e *EdgeQuery) IsDistanceLess(target distanceTarget, limit s1.ChordAngle) bool { | ||||
| 	opts := e.opts | ||||
| 	opts = opts.MaxResults(1). | ||||
| 		DistanceLimit(limit). | ||||
| 		MaxError(s1.StraightChordAngle) | ||||
| 	return !e.findEdge(target, opts).IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // IsDistanceGreater reports if the distance to target is greater than limit. | ||||
| // | ||||
| // This method is usually much faster than Distance, since it is much | ||||
| // less work to determine whether the maximum distance is above or below a | ||||
| // threshold than it is to calculate the actual maximum distance. | ||||
| // If you wish to check if the distance is less than or equal to the limit, use: | ||||
| // | ||||
| //	query.IsDistanceGreater(target, limit.Predecessor()) | ||||
| // | ||||
| func (e *EdgeQuery) IsDistanceGreater(target distanceTarget, limit s1.ChordAngle) bool { | ||||
| 	return e.IsDistanceLess(target, limit) | ||||
| } | ||||
| 
 | ||||
| // IsConservativeDistanceLessOrEqual reports if the distance to target is less | ||||
| // or equal to the limit, where the limit has been expanded by the maximum error | ||||
| // for the distance calculation. | ||||
| // | ||||
| // For example, suppose that we want to test whether two geometries might | ||||
| // intersect each other after they are snapped together using Builder | ||||
| // (using the IdentitySnapFunction with a given "snap radius").  Since | ||||
| // Builder uses exact distance predicates (s2predicates), we need to | ||||
| // measure the distance between the two geometries conservatively.  If the | ||||
| // distance is definitely greater than "snap radius", then the geometries | ||||
| // are guaranteed to not intersect after snapping. | ||||
| func (e *EdgeQuery) IsConservativeDistanceLessOrEqual(target distanceTarget, limit s1.ChordAngle) bool { | ||||
| 	return e.IsDistanceLess(target, limit.Expanded(minUpdateDistanceMaxError(limit))) | ||||
| } | ||||
| 
 | ||||
| // IsConservativeDistanceGreaterOrEqual reports if the distance to the target is greater | ||||
| // than or equal to the given limit with some small tolerance. | ||||
| func (e *EdgeQuery) IsConservativeDistanceGreaterOrEqual(target distanceTarget, limit s1.ChordAngle) bool { | ||||
| 	return e.IsDistanceGreater(target, limit.Expanded(-minUpdateDistanceMaxError(limit))) | ||||
| } | ||||
| 
 | ||||
| // findEdges returns the closest edges to the given target that satisfy the given options. | ||||
| // | ||||
| // Note that if opts.includeInteriors is true, the results may include some | ||||
| // entries with edgeID == -1. This indicates that the target intersects the | ||||
| // indexed polygon with the given shapeID. | ||||
| func (e *EdgeQuery) findEdges(target distanceTarget, opts *queryOptions) []EdgeQueryResult { | ||||
| 	e.findEdgesInternal(target, opts) | ||||
| 	// TODO(roberts): Revisit this if there is a heap or other sorted and | ||||
| 	// uniquing datastructure we can use instead of just a slice. | ||||
| 	e.results = sortAndUniqueResults(e.results) | ||||
| 	if len(e.results) > e.opts.maxResults { | ||||
| 		e.results = e.results[:e.opts.maxResults] | ||||
| 	} | ||||
| 	return e.results | ||||
| } | ||||
| 
 | ||||
| func sortAndUniqueResults(results []EdgeQueryResult) []EdgeQueryResult { | ||||
| 	if len(results) <= 1 { | ||||
| 		return results | ||||
| 	} | ||||
| 	sort.Slice(results, func(i, j int) bool { return results[i].Less(results[j]) }) | ||||
| 	j := 0 | ||||
| 	for i := 1; i < len(results); i++ { | ||||
| 		if results[j] == results[i] { | ||||
| 			continue | ||||
| 		} | ||||
| 		j++ | ||||
| 		results[j] = results[i] | ||||
| 	} | ||||
| 	return results[:j+1] | ||||
| } | ||||
| 
 | ||||
| // findEdge is a convenience method that returns exactly one edge, and if no | ||||
| // edges satisfy the given search criteria, then a default Result is returned. | ||||
| // | ||||
| // This is primarily to ease the usage of a number of the methods in the DistanceTargets | ||||
| // and in EdgeQuery. | ||||
| func (e *EdgeQuery) findEdge(target distanceTarget, opts *queryOptions) EdgeQueryResult { | ||||
| 	opts.MaxResults(1) | ||||
| 	e.findEdges(target, opts) | ||||
| 	if len(e.results) > 0 { | ||||
| 		return e.results[0] | ||||
| 	} | ||||
| 
 | ||||
| 	return newEdgeQueryResult(target) | ||||
| } | ||||
| 
 | ||||
| // findEdgesInternal does the actual work for find edges that match the given options. | ||||
| func (e *EdgeQuery) findEdgesInternal(target distanceTarget, opts *queryOptions) { | ||||
| 	e.target = target | ||||
| 	e.opts = opts | ||||
| 
 | ||||
| 	e.testedEdges = make(map[ShapeEdgeID]uint32) | ||||
| 	e.distanceLimit = target.distance().fromChordAngle(opts.distanceLimit) | ||||
| 	e.results = make([]EdgeQueryResult, 0) | ||||
| 
 | ||||
| 	if e.distanceLimit == target.distance().zero() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if opts.includeInteriors { | ||||
| 		shapeIDs := map[int32]struct{}{} | ||||
| 		e.target.visitContainingShapes(e.index, func(containingShape Shape, targetPoint Point) bool { | ||||
| 			shapeIDs[e.index.idForShape(containingShape)] = struct{}{} | ||||
| 			return len(shapeIDs) < opts.maxResults | ||||
| 		}) | ||||
| 		for shapeID := range shapeIDs { | ||||
| 			e.addResult(EdgeQueryResult{target.distance().zero(), shapeID, -1}) | ||||
| 		} | ||||
| 
 | ||||
| 		if e.distanceLimit == target.distance().zero() { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If maxError > 0 and the target takes advantage of this, then we may | ||||
| 	// need to adjust the distance estimates to ShapeIndex cells to ensure | ||||
| 	// that they are always a lower bound on the true distance. For example, | ||||
| 	// suppose max_distance == 100, maxError == 30, and we compute the distance | ||||
| 	// to the target from some cell C0 as d(C0) == 80. Then because the target | ||||
| 	// takes advantage of maxError, the true distance could be as low as 50. | ||||
| 	// In order not to miss edges contained by such cells, we need to subtract | ||||
| 	// maxError from the distance estimates. This behavior is controlled by | ||||
| 	// the useConservativeCellDistance flag. | ||||
| 	// | ||||
| 	// However there is one important case where this adjustment is not | ||||
| 	// necessary, namely when distanceLimit < maxError, This is because | ||||
| 	// maxError only affects the algorithm once at least maxEdges edges | ||||
| 	// have been found that satisfy the given distance limit. At that point, | ||||
| 	// maxError is subtracted from distanceLimit in order to ensure that | ||||
| 	// any further matches are closer by at least that amount. But when | ||||
| 	// distanceLimit < maxError, this reduces the distance limit to 0, | ||||
| 	// i.e. all remaining candidate cells and edges can safely be discarded. | ||||
| 	// (This is how IsDistanceLess() and friends are implemented.) | ||||
| 	targetUsesMaxError := opts.maxError != target.distance().zero().chordAngle() && | ||||
| 		e.target.setMaxError(opts.maxError) | ||||
| 
 | ||||
| 	// Note that we can't compare maxError and distanceLimit directly | ||||
| 	// because one is a Delta and one is a Distance. Instead we subtract them. | ||||
| 	e.useConservativeCellDistance = targetUsesMaxError && | ||||
| 		(e.distanceLimit == target.distance().infinity() || | ||||
| 			target.distance().zero().less(e.distanceLimit.sub(target.distance().fromChordAngle(opts.maxError)))) | ||||
| 
 | ||||
| 	// Use the brute force algorithm if the index is small enough. To avoid | ||||
| 	// spending too much time counting edges when there are many shapes, we stop | ||||
| 	// counting once there are too many edges. We may need to recount the edges | ||||
| 	// if we later see a target with a larger brute force edge threshold. | ||||
| 	minOptimizedEdges := e.target.maxBruteForceIndexSize() + 1 | ||||
| 	if minOptimizedEdges > e.indexNumEdgesLimit && e.indexNumEdges >= e.indexNumEdgesLimit { | ||||
| 		e.indexNumEdges = e.index.NumEdgesUpTo(minOptimizedEdges) | ||||
| 		e.indexNumEdgesLimit = minOptimizedEdges | ||||
| 	} | ||||
| 
 | ||||
| 	if opts.useBruteForce || e.indexNumEdges < minOptimizedEdges { | ||||
| 		// The brute force algorithm already considers each edge exactly once. | ||||
| 		e.avoidDuplicates = false | ||||
| 		e.findEdgesBruteForce() | ||||
| 	} else { | ||||
| 		// If the target takes advantage of maxError then we need to avoid | ||||
| 		// duplicate edges explicitly. (Otherwise it happens automatically.) | ||||
| 		e.avoidDuplicates = targetUsesMaxError && opts.maxResults > 1 | ||||
| 		e.findEdgesOptimized() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) addResult(r EdgeQueryResult) { | ||||
| 	e.results = append(e.results, r) | ||||
| 	if e.opts.maxResults == 1 { | ||||
| 		// Optimization for the common case where only the closest edge is wanted. | ||||
| 		e.distanceLimit = r.distance.sub(e.target.distance().fromChordAngle(e.opts.maxError)) | ||||
| 	} | ||||
| 	// TODO(roberts): Add the other if/else cases when a different data structure | ||||
| 	// is used for the results. | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) maybeAddResult(shape Shape, edgeID int32) { | ||||
| 	if _, ok := e.testedEdges[ShapeEdgeID{e.index.idForShape(shape), edgeID}]; e.avoidDuplicates && !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	edge := shape.Edge(int(edgeID)) | ||||
| 	dist := e.distanceLimit | ||||
| 
 | ||||
| 	if dist, ok := e.target.updateDistanceToEdge(edge, dist); ok { | ||||
| 		e.addResult(EdgeQueryResult{dist, e.index.idForShape(shape), edgeID}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) findEdgesBruteForce() { | ||||
| 	// Range over all shapes in the index. Does order matter here? if so | ||||
| 	// switch to for i = 0 .. n? | ||||
| 	for _, shape := range e.index.shapes { | ||||
| 		// TODO(roberts): can this happen if we are only ranging over current entries? | ||||
| 		if shape == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		for edgeID := int32(0); edgeID < int32(shape.NumEdges()); edgeID++ { | ||||
| 			e.maybeAddResult(shape, edgeID) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) findEdgesOptimized() { | ||||
| 	e.initQueue() | ||||
| 	// Repeatedly find the closest Cell to "target" and either split it into | ||||
| 	// its four children or process all of its edges. | ||||
| 	for e.queue.size() > 0 { | ||||
| 		// We need to copy the top entry before removing it, and we need to | ||||
| 		// remove it before adding any new entries to the queue. | ||||
| 		entry := e.queue.pop() | ||||
| 
 | ||||
| 		if !entry.distance.less(e.distanceLimit) { | ||||
| 			e.queue.reset() // Clear any remaining entries. | ||||
| 			break | ||||
| 		} | ||||
| 		// If this is already known to be an index cell, just process it. | ||||
| 		if entry.indexCell != nil { | ||||
| 			e.processEdges(entry) | ||||
| 			continue | ||||
| 		} | ||||
| 		// Otherwise split the cell into its four children.  Before adding a | ||||
| 		// child back to the queue, we first check whether it is empty.  We do | ||||
| 		// this in two seek operations rather than four by seeking to the key | ||||
| 		// between children 0 and 1 and to the key between children 2 and 3. | ||||
| 		id := entry.id | ||||
| 		ch := id.Children() | ||||
| 		e.iter.seek(ch[1].RangeMin()) | ||||
| 
 | ||||
| 		if !e.iter.Done() && e.iter.CellID() <= ch[1].RangeMax() { | ||||
| 			e.processOrEnqueueCell(ch[1]) | ||||
| 		} | ||||
| 		if e.iter.Prev() && e.iter.CellID() >= id.RangeMin() { | ||||
| 			e.processOrEnqueueCell(ch[0]) | ||||
| 		} | ||||
| 
 | ||||
| 		e.iter.seek(ch[3].RangeMin()) | ||||
| 		if !e.iter.Done() && e.iter.CellID() <= id.RangeMax() { | ||||
| 			e.processOrEnqueueCell(ch[3]) | ||||
| 		} | ||||
| 		if e.iter.Prev() && e.iter.CellID() >= ch[2].RangeMin() { | ||||
| 			e.processOrEnqueueCell(ch[2]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) processOrEnqueueCell(id CellID) { | ||||
| 	if e.iter.CellID() == id { | ||||
| 		e.processOrEnqueue(id, e.iter.IndexCell()) | ||||
| 	} else { | ||||
| 		e.processOrEnqueue(id, nil) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) initQueue() { | ||||
| 	if len(e.indexCovering) == 0 { | ||||
| 		// We delay iterator initialization until now to make queries on very | ||||
| 		// small indexes a bit faster (i.e., where brute force is used). | ||||
| 		e.iter = NewShapeIndexIterator(e.index) | ||||
| 	} | ||||
| 
 | ||||
| 	// Optimization: if the user is searching for just the closest edge, and the | ||||
| 	// center of the target's bounding cap happens to intersect an index cell, | ||||
| 	// then we try to limit the search region to a small disc by first | ||||
| 	// processing the edges in that cell.  This sets distance_limit_ based on | ||||
| 	// the closest edge in that cell, which we can then use to limit the search | ||||
| 	// area.  This means that the cell containing "target" will be processed | ||||
| 	// twice, but in general this is still faster. | ||||
| 	// | ||||
| 	// TODO(roberts): Even if the cap center is not contained, we could still | ||||
| 	// process one or both of the adjacent index cells in CellID order, | ||||
| 	// provided that those cells are closer than distanceLimit. | ||||
| 	cb := e.target.capBound() | ||||
| 	if cb.IsEmpty() { | ||||
| 		return // Empty target. | ||||
| 	} | ||||
| 
 | ||||
| 	if e.opts.maxResults == 1 && e.iter.LocatePoint(cb.Center()) { | ||||
| 		e.processEdges(&queryQueueEntry{ | ||||
| 			distance:  e.target.distance().zero(), | ||||
| 			id:        e.iter.CellID(), | ||||
| 			indexCell: e.iter.IndexCell(), | ||||
| 		}) | ||||
| 		// Skip the rest of the algorithm if we found an intersecting edge. | ||||
| 		if e.distanceLimit == e.target.distance().zero() { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if len(e.indexCovering) == 0 { | ||||
| 		e.initCovering() | ||||
| 	} | ||||
| 	if e.distanceLimit == e.target.distance().infinity() { | ||||
| 		// Start with the precomputed index covering. | ||||
| 		for i := range e.indexCovering { | ||||
| 			e.processOrEnqueue(e.indexCovering[i], e.indexCells[i]) | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Compute a covering of the search disc and intersect it with the | ||||
| 		// precomputed index covering. | ||||
| 		coverer := &RegionCoverer{MaxCells: 4, LevelMod: 1, MaxLevel: maxLevel} | ||||
| 
 | ||||
| 		radius := cb.Radius() + e.distanceLimit.chordAngleBound().Angle() | ||||
| 		searchCB := CapFromCenterAngle(cb.Center(), radius) | ||||
| 		maxDistCover := coverer.FastCovering(searchCB) | ||||
| 		e.initialCells = CellUnionFromIntersection(e.indexCovering, maxDistCover) | ||||
| 
 | ||||
| 		// Now we need to clean up the initial cells to ensure that they all | ||||
| 		// contain at least one cell of the ShapeIndex. (Some may not intersect | ||||
| 		// the index at all, while other may be descendants of an index cell.) | ||||
| 		i, j := 0, 0 | ||||
| 		for i < len(e.initialCells) { | ||||
| 			idI := e.initialCells[i] | ||||
| 			// Find the top-level cell that contains this initial cell. | ||||
| 			for e.indexCovering[j].RangeMax() < idI { | ||||
| 				j++ | ||||
| 			} | ||||
| 
 | ||||
| 			idJ := e.indexCovering[j] | ||||
| 			if idI == idJ { | ||||
| 				// This initial cell is one of the top-level cells.  Use the | ||||
| 				// precomputed ShapeIndexCell pointer to avoid an index seek. | ||||
| 				e.processOrEnqueue(idJ, e.indexCells[j]) | ||||
| 				i++ | ||||
| 				j++ | ||||
| 			} else { | ||||
| 				// This initial cell is a proper descendant of a top-level cell. | ||||
| 				// Check how it is related to the cells of the ShapeIndex. | ||||
| 				r := e.iter.LocateCellID(idI) | ||||
| 				if r == Indexed { | ||||
| 					// This cell is a descendant of an index cell. | ||||
| 					// Enqueue it and skip any other initial cells | ||||
| 					// that are also descendants of this cell. | ||||
| 					e.processOrEnqueue(e.iter.CellID(), e.iter.IndexCell()) | ||||
| 					lastID := e.iter.CellID().RangeMax() | ||||
| 					for i < len(e.initialCells) && e.initialCells[i] <= lastID { | ||||
| 						i++ | ||||
| 					} | ||||
| 				} else { | ||||
| 					// Enqueue the cell only if it contains at least one index cell. | ||||
| 					if r == Subdivided { | ||||
| 						e.processOrEnqueue(idI, nil) | ||||
| 					} | ||||
| 					i++ | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeQuery) initCovering() { | ||||
| 	// Find the range of Cells spanned by the index and choose a level such | ||||
| 	// that the entire index can be covered with just a few cells. These are | ||||
| 	// the "top-level" cells. There are two cases: | ||||
| 	// | ||||
| 	//  - If the index spans more than one face, then there is one top-level cell | ||||
| 	// per spanned face, just big enough to cover the index cells on that face. | ||||
| 	// | ||||
| 	//  - If the index spans only one face, then we find the smallest cell "C" | ||||
| 	// that covers the index cells on that face (just like the case above). | ||||
| 	// Then for each of the 4 children of "C", if the child contains any index | ||||
| 	// cells then we create a top-level cell that is big enough to just fit | ||||
| 	// those index cells (i.e., shrinking the child as much as possible to fit | ||||
| 	// its contents). This essentially replicates what would happen if we | ||||
| 	// started with "C" as the top-level cell, since "C" would immediately be | ||||
| 	// split, except that we take the time to prune the children further since | ||||
| 	// this will save work on every subsequent query. | ||||
| 	e.indexCovering = make([]CellID, 0, 6) | ||||
| 
 | ||||
| 	// TODO(roberts): Use a single iterator below and save position | ||||
| 	// information using pair {CellID, ShapeIndexCell}. | ||||
| 	next := NewShapeIndexIterator(e.index, IteratorBegin) | ||||
| 	last := NewShapeIndexIterator(e.index, IteratorEnd) | ||||
| 	last.Prev() | ||||
| 	if next.CellID() != last.CellID() { | ||||
| 		// The index has at least two cells. Choose a level such that the entire | ||||
| 		// index can be spanned with at most 6 cells (if the index spans multiple | ||||
| 		// faces) or 4 cells (it the index spans a single face). | ||||
| 		level, ok := next.CellID().CommonAncestorLevel(last.CellID()) | ||||
| 		if !ok { | ||||
| 			level = 0 | ||||
| 		} else { | ||||
| 			level++ | ||||
| 		} | ||||
| 
 | ||||
| 		// Visit each potential top-level cell except the last (handled below). | ||||
| 		lastID := last.CellID().Parent(level) | ||||
| 		for id := next.CellID().Parent(level); id != lastID; id = id.Next() { | ||||
| 			// Skip any top-level cells that don't contain any index cells. | ||||
| 			if id.RangeMax() < next.CellID() { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Find the range of index cells contained by this top-level cell and | ||||
| 			// then shrink the cell if necessary so that it just covers them. | ||||
| 			cellFirst := next.clone() | ||||
| 			next.seek(id.RangeMax().Next()) | ||||
| 			cellLast := next.clone() | ||||
| 			cellLast.Prev() | ||||
| 			e.addInitialRange(cellFirst, cellLast) | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	e.addInitialRange(next, last) | ||||
| } | ||||
| 
 | ||||
| // addInitialRange adds an entry to the indexCovering and indexCells that covers the given | ||||
| // inclusive range of cells. | ||||
| // | ||||
| // This requires that first and last cells have a common ancestor. | ||||
| func (e *EdgeQuery) addInitialRange(first, last *ShapeIndexIterator) { | ||||
| 	if first.CellID() == last.CellID() { | ||||
| 		// The range consists of a single index cell. | ||||
| 		e.indexCovering = append(e.indexCovering, first.CellID()) | ||||
| 		e.indexCells = append(e.indexCells, first.IndexCell()) | ||||
| 	} else { | ||||
| 		// Add the lowest common ancestor of the given range. | ||||
| 		level, _ := first.CellID().CommonAncestorLevel(last.CellID()) | ||||
| 		e.indexCovering = append(e.indexCovering, first.CellID().Parent(level)) | ||||
| 		e.indexCells = append(e.indexCells, nil) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // processEdges processes all the edges of the given index cell. | ||||
| func (e *EdgeQuery) processEdges(entry *queryQueueEntry) { | ||||
| 	for _, clipped := range entry.indexCell.shapes { | ||||
| 		shape := e.index.Shape(clipped.shapeID) | ||||
| 		for j := 0; j < clipped.numEdges(); j++ { | ||||
| 			e.maybeAddResult(shape, int32(clipped.edges[j])) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // processOrEnqueue the given cell id and indexCell. | ||||
| func (e *EdgeQuery) processOrEnqueue(id CellID, indexCell *ShapeIndexCell) { | ||||
| 	if indexCell != nil { | ||||
| 		// If this index cell has only a few edges, then it is faster to check | ||||
| 		// them directly rather than computing the minimum distance to the Cell | ||||
| 		// and inserting it into the queue. | ||||
| 		const minEdgesToEnqueue = 10 | ||||
| 		numEdges := indexCell.numEdges() | ||||
| 		if numEdges == 0 { | ||||
| 			return | ||||
| 		} | ||||
| 		if numEdges < minEdgesToEnqueue { | ||||
| 			// Set "distance" to zero to avoid the expense of computing it. | ||||
| 			e.processEdges(&queryQueueEntry{ | ||||
| 				distance:  e.target.distance().zero(), | ||||
| 				id:        id, | ||||
| 				indexCell: indexCell, | ||||
| 			}) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise compute the minimum distance to any point in the cell and add | ||||
| 	// it to the priority queue. | ||||
| 	cell := CellFromCellID(id) | ||||
| 	dist := e.distanceLimit | ||||
| 	var ok bool | ||||
| 	if dist, ok = e.target.updateDistanceToCell(cell, dist); !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	if e.useConservativeCellDistance { | ||||
| 		// Ensure that "distance" is a lower bound on the true distance to the cell. | ||||
| 		dist = dist.sub(e.target.distance().fromChordAngle(e.opts.maxError)) | ||||
| 	} | ||||
| 
 | ||||
| 	e.queue.push(&queryQueueEntry{ | ||||
| 		distance:  dist, | ||||
| 		id:        id, | ||||
| 		indexCell: indexCell, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Remaining pieces | ||||
| // GetEdge | ||||
| // Project | ||||
							
								
								
									
										291
									
								
								vendor/github.com/golang/geo/s2/edge_tessellator.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										291
									
								
								vendor/github.com/golang/geo/s2/edge_tessellator.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,291 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/golang/geo/r2" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Tessellation is implemented by subdividing the edge until the estimated | ||||
| // maximum error is below the given tolerance. Estimating error is a hard | ||||
| // problem, especially when the only methods available are point evaluation of | ||||
| // the projection and its inverse. (These are the only methods that | ||||
| // Projection provides, which makes it easier and less error-prone to | ||||
| // implement new projections.) | ||||
| // | ||||
| // One technique that significantly increases robustness is to treat the | ||||
| // geodesic and projected edges as parametric curves rather than geometric ones. | ||||
| // Given a spherical edge AB and a projection p:S2->R2, let f(t) be the | ||||
| // normalized arc length parametrization of AB and let g(t) be the normalized | ||||
| // arc length parameterization of the projected edge p(A)p(B). (In other words, | ||||
| // f(0)=A, f(1)=B, g(0)=p(A), g(1)=p(B).)  We now define the geometric error as | ||||
| // the maximum distance from the point p^-1(g(t)) to the geodesic edge AB for | ||||
| // any t in [0,1], where p^-1 denotes the inverse projection. In other words, | ||||
| // the geometric error is the maximum distance from any point on the projected | ||||
| // edge (mapped back onto the sphere) to the geodesic edge AB. On the other | ||||
| // hand we define the parametric error as the maximum distance between the | ||||
| // points f(t) and p^-1(g(t)) for any t in [0,1], i.e. the maximum distance | ||||
| // (measured on the sphere) between the geodesic and projected points at the | ||||
| // same interpolation fraction t. | ||||
| // | ||||
| // The easiest way to estimate the parametric error is to simply evaluate both | ||||
| // edges at their midpoints and measure the distance between them (the "midpoint | ||||
| // method"). This is very fast and works quite well for most edges, however it | ||||
| // has one major drawback: it doesn't handle points of inflection (i.e., points | ||||
| // where the curvature changes sign). For example, edges in the Mercator and | ||||
| // Plate Carree projections always curve towards the equator relative to the | ||||
| // corresponding geodesic edge, so in these projections there is a point of | ||||
| // inflection whenever the projected edge crosses the equator. The worst case | ||||
| // occurs when the edge endpoints have different longitudes but the same | ||||
| // absolute latitude, since in that case the error is non-zero but the edges | ||||
| // have exactly the same midpoint (on the equator). | ||||
| // | ||||
| // One solution to this problem is to split the input edges at all inflection | ||||
| // points (i.e., along the equator in the case of the Mercator and Plate Carree | ||||
| // projections). However for general projections these inflection points can | ||||
| // occur anywhere on the sphere (e.g., consider the Transverse Mercator | ||||
| // projection). This could be addressed by adding methods to the S2Projection | ||||
| // interface to split edges at inflection points but this would make it harder | ||||
| // and more error-prone to implement new projections. | ||||
| // | ||||
| // Another problem with this approach is that the midpoint method sometimes | ||||
| // underestimates the true error even when edges do not cross the equator. | ||||
| // For the Plate Carree and Mercator projections, the midpoint method can | ||||
| // underestimate the error by up to 3%. | ||||
| // | ||||
| // Both of these problems can be solved as follows. We assume that the error | ||||
| // can be modeled as a convex combination of two worst-case functions, one | ||||
| // where the error is maximized at the edge midpoint and another where the | ||||
| // error is *minimized* (i.e., zero) at the edge midpoint. For example, we | ||||
| // could choose these functions as: | ||||
| // | ||||
| //    E1(x) = 1 - x^2 | ||||
| //    E2(x) = x * (1 - x^2) | ||||
| // | ||||
| // where for convenience we use an interpolation parameter "x" in the range | ||||
| // [-1, 1] rather than the original "t" in the range [0, 1]. Note that both | ||||
| // error functions must have roots at x = {-1, 1} since the error must be zero | ||||
| // at the edge endpoints. E1 is simply a parabola whose maximum value is 1 | ||||
| // attained at x = 0, while E2 is a cubic with an additional root at x = 0, | ||||
| // and whose maximum value is 2 * sqrt(3) / 9 attained at x = 1 / sqrt(3). | ||||
| // | ||||
| // Next, it is convenient to scale these functions so that the both have a | ||||
| // maximum value of 1. E1 already satisfies this requirement, and we simply | ||||
| // redefine E2 as | ||||
| // | ||||
| //   E2(x) = x * (1 - x^2) / (2 * sqrt(3) / 9) | ||||
| // | ||||
| // Now define x0 to be the point where these two functions intersect, i.e. the | ||||
| // point in the range (-1, 1) where E1(x0) = E2(x0). This value has the very | ||||
| // convenient property that if we evaluate the actual error E(x0), then the | ||||
| // maximum error on the entire interval [-1, 1] is bounded by | ||||
| // | ||||
| //   E(x) <= E(x0) / E1(x0) | ||||
| // | ||||
| // since whether the error is modeled using E1 or E2, the resulting function | ||||
| // has the same maximum value (namely E(x0) / E1(x0)). If it is modeled as | ||||
| // some other convex combination of E1 and E2, the maximum value can only | ||||
| // decrease. | ||||
| // | ||||
| // Finally, since E2 is not symmetric about the y-axis, we must also allow for | ||||
| // the possibility that the error is a convex combination of E1 and -E2. This | ||||
| // can be handled by evaluating the error at E(-x0) as well, and then | ||||
| // computing the final error bound as | ||||
| // | ||||
| //   E(x) <= max(E(x0), E(-x0)) / E1(x0) . | ||||
| // | ||||
| // Effectively, this method is simply evaluating the error at two points about | ||||
| // 1/3 and 2/3 of the way along the edges, and then scaling the maximum of | ||||
| // these two errors by a constant factor. Intuitively, the reason this works | ||||
| // is that if the two edges cross somewhere in the interior, then at least one | ||||
| // of these points will be far from the crossing. | ||||
| // | ||||
| // The actual algorithm implemented below has some additional refinements. | ||||
| // First, edges longer than 90 degrees are always subdivided; this avoids | ||||
| // various unusual situations that can happen with very long edges, and there | ||||
| // is really no reason to avoid adding vertices to edges that are so long. | ||||
| // | ||||
| // Second, the error function E1 above needs to be modified to take into | ||||
| // account spherical distortions. (It turns out that spherical distortions are | ||||
| // beneficial in the case of E2, i.e. they only make its error estimates | ||||
| // slightly more conservative.)  To do this, we model E1 as the maximum error | ||||
| // in a Plate Carree edge of length 90 degrees or less. This turns out to be | ||||
| // an edge from 45:-90 to 45:90 (in lat:lng format). The corresponding error | ||||
| // as a function of "x" in the range [-1, 1] can be computed as the distance | ||||
| // between the Plate Caree edge point (45, 90 * x) and the geodesic | ||||
| // edge point (90 - 45 * abs(x), 90 * sgn(x)). Using the Haversine formula, | ||||
| // the corresponding function E1 (normalized to have a maximum value of 1) is: | ||||
| // | ||||
| //   E1(x) = | ||||
| //     asin(sqrt(sin(Pi / 8 * (1 - x)) ^ 2 + | ||||
| //               sin(Pi / 4 * (1 - x)) ^ 2 * cos(Pi / 4) * sin(Pi / 4 * x))) / | ||||
| //     asin(sqrt((1 - 1 / sqrt(2)) / 2)) | ||||
| // | ||||
| // Note that this function does not need to be evaluated at runtime, it | ||||
| // simply affects the calculation of the value x0 where E1(x0) = E2(x0) | ||||
| // and the corresponding scaling factor C = 1 / E1(x0). | ||||
| // | ||||
| // ------------------------------------------------------------------ | ||||
| // | ||||
| // In the case of the Mercator and Plate Carree projections this strategy | ||||
| // produces a conservative upper bound (verified using 10 million random | ||||
| // edges). Furthermore the bound is nearly tight; the scaling constant is | ||||
| // C = 1.19289, whereas the maximum observed value was 1.19254. | ||||
| // | ||||
| // Compared to the simpler midpoint evaluation method, this strategy requires | ||||
| // more function evaluations (currently twice as many, but with a smarter | ||||
| // tessellation algorithm it will only be 50% more). It also results in a | ||||
| // small amount of additional tessellation (about 1.5%) compared to the | ||||
| // midpoint method, but this is due almost entirely to the fact that the | ||||
| // midpoint method does not yield conservative error estimates. | ||||
| // | ||||
| // For random edges with a tolerance of 1 meter, the expected amount of | ||||
| // overtessellation is as follows: | ||||
| // | ||||
| //                   Midpoint Method    Cubic Method | ||||
| //   Plate Carree               1.8%            3.0% | ||||
| //   Mercator                  15.8%           17.4% | ||||
| 
 | ||||
| const ( | ||||
| 	// tessellationInterpolationFraction is the fraction at which the two edges | ||||
| 	// are evaluated in order to measure the error between them. (Edges are | ||||
| 	// evaluated at two points measured this fraction from either end.) | ||||
| 	tessellationInterpolationFraction = 0.31215691082248312 | ||||
| 	tessellationScaleFactor           = 0.83829992569888509 | ||||
| 
 | ||||
| 	// minTessellationTolerance is the minimum supported tolerance (which | ||||
| 	// corresponds to a distance less than 1 micrometer on the Earth's | ||||
| 	// surface, but is still much larger than the expected projection and | ||||
| 	// interpolation errors). | ||||
| 	minTessellationTolerance s1.Angle = 1e-13 | ||||
| ) | ||||
| 
 | ||||
| // EdgeTessellator converts an edge in a given projection (e.g., Mercator) into | ||||
| // a chain of spherical geodesic edges such that the maximum distance between | ||||
| // the original edge and the geodesic edge chain is at most the requested | ||||
| // tolerance. Similarly, it can convert a spherical geodesic edge into a chain | ||||
| // of edges in a given 2D projection such that the maximum distance between the | ||||
| // geodesic edge and the chain of projected edges is at most the requested tolerance. | ||||
| // | ||||
| //   Method      | Input                  | Output | ||||
| //   ------------|------------------------|----------------------- | ||||
| //   Projected   | S2 geodesics           | Planar projected edges | ||||
| //   Unprojected | Planar projected edges | S2 geodesics | ||||
| type EdgeTessellator struct { | ||||
| 	projection Projection | ||||
| 
 | ||||
| 	// The given tolerance scaled by a constant fraction so that it can be | ||||
| 	// compared against the result returned by estimateMaxError. | ||||
| 	scaledTolerance s1.ChordAngle | ||||
| } | ||||
| 
 | ||||
| // NewEdgeTessellator creates a new edge tessellator for the given projection and tolerance. | ||||
| func NewEdgeTessellator(p Projection, tolerance s1.Angle) *EdgeTessellator { | ||||
| 	return &EdgeTessellator{ | ||||
| 		projection:      p, | ||||
| 		scaledTolerance: s1.ChordAngleFromAngle(maxAngle(tolerance, minTessellationTolerance)), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AppendProjected converts the spherical geodesic edge AB to a chain of planar edges | ||||
| // in the given projection and returns the corresponding vertices. | ||||
| // | ||||
| // If the given projection has one or more coordinate axes that wrap, then | ||||
| // every vertex's coordinates will be as close as possible to the previous | ||||
| // vertex's coordinates. Note that this may yield vertices whose | ||||
| // coordinates are outside the usual range. For example, tessellating the | ||||
| // edge (0:170, 0:-170) (in lat:lng notation) yields (0:170, 0:190). | ||||
| func (e *EdgeTessellator) AppendProjected(a, b Point, vertices []r2.Point) []r2.Point { | ||||
| 	pa := e.projection.Project(a) | ||||
| 	if len(vertices) == 0 { | ||||
| 		vertices = []r2.Point{pa} | ||||
| 	} else { | ||||
| 		pa = e.projection.WrapDestination(vertices[len(vertices)-1], pa) | ||||
| 	} | ||||
| 
 | ||||
| 	pb := e.projection.Project(b) | ||||
| 	return e.appendProjected(pa, a, pb, b, vertices) | ||||
| } | ||||
| 
 | ||||
| // appendProjected splits a geodesic edge AB as necessary and returns the | ||||
| // projected vertices appended to the given vertices. | ||||
| // | ||||
| // The maximum recursion depth is (math.Pi / minTessellationTolerance) < 45 | ||||
| func (e *EdgeTessellator) appendProjected(pa r2.Point, a Point, pbIn r2.Point, b Point, vertices []r2.Point) []r2.Point { | ||||
| 	pb := e.projection.WrapDestination(pa, pbIn) | ||||
| 	if e.estimateMaxError(pa, a, pb, b) <= e.scaledTolerance { | ||||
| 		return append(vertices, pb) | ||||
| 	} | ||||
| 
 | ||||
| 	mid := Point{a.Add(b.Vector).Normalize()} | ||||
| 	pmid := e.projection.WrapDestination(pa, e.projection.Project(mid)) | ||||
| 	vertices = e.appendProjected(pa, a, pmid, mid, vertices) | ||||
| 	return e.appendProjected(pmid, mid, pb, b, vertices) | ||||
| } | ||||
| 
 | ||||
| // AppendUnprojected converts the planar edge AB in the given projection to a chain of | ||||
| // spherical geodesic edges and returns the vertices. | ||||
| // | ||||
| // Note that to construct a Loop, you must eliminate the duplicate first and last | ||||
| // vertex. Note also that if the given projection involves coordinate wrapping | ||||
| // (e.g. across the 180 degree meridian) then the first and last vertices may not | ||||
| // be exactly the same. | ||||
| func (e *EdgeTessellator) AppendUnprojected(pa, pb r2.Point, vertices []Point) []Point { | ||||
| 	a := e.projection.Unproject(pa) | ||||
| 	b := e.projection.Unproject(pb) | ||||
| 
 | ||||
| 	if len(vertices) == 0 { | ||||
| 		vertices = []Point{a} | ||||
| 	} | ||||
| 
 | ||||
| 	// Note that coordinate wrapping can create a small amount of error. For | ||||
| 	// example in the edge chain "0:-175, 0:179, 0:-177", the first edge is | ||||
| 	// transformed into "0:-175, 0:-181" while the second is transformed into | ||||
| 	// "0:179, 0:183". The two coordinate pairs for the middle vertex | ||||
| 	// ("0:-181" and "0:179") may not yield exactly the same S2Point. | ||||
| 	return e.appendUnprojected(pa, a, pb, b, vertices) | ||||
| } | ||||
| 
 | ||||
| // appendUnprojected interpolates a projected edge and appends the corresponding | ||||
| // points on the sphere. | ||||
| func (e *EdgeTessellator) appendUnprojected(pa r2.Point, a Point, pbIn r2.Point, b Point, vertices []Point) []Point { | ||||
| 	pb := e.projection.WrapDestination(pa, pbIn) | ||||
| 	if e.estimateMaxError(pa, a, pb, b) <= e.scaledTolerance { | ||||
| 		return append(vertices, b) | ||||
| 	} | ||||
| 
 | ||||
| 	pmid := e.projection.Interpolate(0.5, pa, pb) | ||||
| 	mid := e.projection.Unproject(pmid) | ||||
| 
 | ||||
| 	vertices = e.appendUnprojected(pa, a, pmid, mid, vertices) | ||||
| 	return e.appendUnprojected(pmid, mid, pb, b, vertices) | ||||
| } | ||||
| 
 | ||||
| func (e *EdgeTessellator) estimateMaxError(pa r2.Point, a Point, pb r2.Point, b Point) s1.ChordAngle { | ||||
| 	// See the algorithm description at the top of this file. | ||||
| 	// We always tessellate edges longer than 90 degrees on the sphere, since the | ||||
| 	// approximation below is not robust enough to handle such edges. | ||||
| 	if a.Dot(b.Vector) < -1e-14 { | ||||
| 		return s1.InfChordAngle() | ||||
| 	} | ||||
| 	t1 := tessellationInterpolationFraction | ||||
| 	t2 := 1 - tessellationInterpolationFraction | ||||
| 	mid1 := Interpolate(t1, a, b) | ||||
| 	mid2 := Interpolate(t2, a, b) | ||||
| 	pmid1 := e.projection.Unproject(e.projection.Interpolate(t1, pa, pb)) | ||||
| 	pmid2 := e.projection.Unproject(e.projection.Interpolate(t2, pa, pb)) | ||||
| 	return maxChordAngle(ChordAngleBetweenPoints(mid1, pmid1), ChordAngleBetweenPoints(mid2, pmid2)) | ||||
| } | ||||
							
								
								
									
										224
									
								
								vendor/github.com/golang/geo/s2/encode.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										224
									
								
								vendor/github.com/golang/geo/s2/encode.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,224 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"math" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// encodingVersion is the current version of the encoding | ||||
| 	// format that is compatible with C++ and other S2 libraries. | ||||
| 	encodingVersion = int8(1) | ||||
| 
 | ||||
| 	// encodingCompressedVersion is the current version of the | ||||
| 	// compressed format. | ||||
| 	encodingCompressedVersion = int8(4) | ||||
| ) | ||||
| 
 | ||||
| // encoder handles the specifics of encoding for S2 types. | ||||
| type encoder struct { | ||||
| 	w   io.Writer // the real writer passed to Encode | ||||
| 	err error | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeUvarint(x uint64) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var buf [binary.MaxVarintLen64]byte | ||||
| 	n := binary.PutUvarint(buf[:], x) | ||||
| 	_, e.err = e.w.Write(buf[:n]) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeBool(x bool) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var val int8 | ||||
| 	if x { | ||||
| 		val = 1 | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, val) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeInt8(x int8) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeInt16(x int16) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeInt32(x int32) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeInt64(x int64) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeUint8(x uint8) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, e.err = e.w.Write([]byte{x}) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeUint32(x uint32) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeUint64(x uint64) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeFloat32(x float32) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| func (e *encoder) writeFloat64(x float64) { | ||||
| 	if e.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.err = binary.Write(e.w, binary.LittleEndian, x) | ||||
| } | ||||
| 
 | ||||
| type byteReader interface { | ||||
| 	io.Reader | ||||
| 	io.ByteReader | ||||
| } | ||||
| 
 | ||||
| // byteReaderAdapter embellishes an io.Reader with a ReadByte method, | ||||
| // so that it implements the io.ByteReader interface. | ||||
| type byteReaderAdapter struct { | ||||
| 	io.Reader | ||||
| } | ||||
| 
 | ||||
| func (b byteReaderAdapter) ReadByte() (byte, error) { | ||||
| 	buf := []byte{0} | ||||
| 	_, err := io.ReadFull(b, buf) | ||||
| 	return buf[0], err | ||||
| } | ||||
| 
 | ||||
| func asByteReader(r io.Reader) byteReader { | ||||
| 	if br, ok := r.(byteReader); ok { | ||||
| 		return br | ||||
| 	} | ||||
| 	return byteReaderAdapter{r} | ||||
| } | ||||
| 
 | ||||
| type decoder struct { | ||||
| 	r   byteReader // the real reader passed to Decode | ||||
| 	err error | ||||
| 	buf []byte | ||||
| } | ||||
| 
 | ||||
| // Get a buffer of size 8, to avoid allocating over and over. | ||||
| func (d *decoder) buffer() []byte { | ||||
| 	if d.buf == nil { | ||||
| 		d.buf = make([]byte, 8) | ||||
| 	} | ||||
| 	return d.buf | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readBool() (x bool) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var val int8 | ||||
| 	d.err = binary.Read(d.r, binary.LittleEndian, &val) | ||||
| 	return val == 1 | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readInt8() (x int8) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d.err = binary.Read(d.r, binary.LittleEndian, &x) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readInt64() (x int64) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d.err = binary.Read(d.r, binary.LittleEndian, &x) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readUint8() (x uint8) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	x, d.err = d.r.ReadByte() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readUint32() (x uint32) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d.err = binary.Read(d.r, binary.LittleEndian, &x) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readUint64() (x uint64) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d.err = binary.Read(d.r, binary.LittleEndian, &x) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readFloat64() float64 { | ||||
| 	if d.err != nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	buf := d.buffer() | ||||
| 	_, d.err = io.ReadFull(d.r, buf) | ||||
| 	return math.Float64frombits(binary.LittleEndian.Uint64(buf)) | ||||
| } | ||||
| 
 | ||||
| func (d *decoder) readUvarint() (x uint64) { | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	x, d.err = binary.ReadUvarint(d.r) | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										143
									
								
								vendor/github.com/golang/geo/s2/interleave.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/golang/geo/s2/interleave.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,143 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| /* | ||||
| The lookup table below can convert a sequence of interleaved 8 bits into | ||||
| non-interleaved 4 bits. The table can convert both odd and even bits at the | ||||
| same time, and lut[x & 0x55] converts the even bits (bits 0, 2, 4 and 6), | ||||
| while lut[x & 0xaa] converts the odd bits (bits 1, 3, 5 and 7). | ||||
| 
 | ||||
| The lookup table below was generated using the following python code: | ||||
| 
 | ||||
| 	def deinterleave(bits): | ||||
| 	  if bits == 0: return 0 | ||||
| 	  if bits < 4: return 1 | ||||
| 	  return deinterleave(bits / 4) * 2 + deinterleave(bits & 3) | ||||
| 
 | ||||
| 	for i in range(256): print "0x%x," % deinterleave(i), | ||||
| */ | ||||
| var deinterleaveLookup = [256]uint32{ | ||||
| 	0x0, 0x1, 0x1, 0x1, 0x2, 0x3, 0x3, 0x3, | ||||
| 	0x2, 0x3, 0x3, 0x3, 0x2, 0x3, 0x3, 0x3, | ||||
| 	0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7, | ||||
| 	0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7, | ||||
| 	0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7, | ||||
| 	0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7, | ||||
| 	0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7, | ||||
| 	0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7, | ||||
| 
 | ||||
| 	0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 
 | ||||
| 	0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 
 | ||||
| 	0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf, | ||||
| 	0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf, | ||||
| } | ||||
| 
 | ||||
| // deinterleaveUint32 decodes the interleaved values. | ||||
| func deinterleaveUint32(code uint64) (uint32, uint32) { | ||||
| 	x := (deinterleaveLookup[code&0x55]) | | ||||
| 		(deinterleaveLookup[(code>>8)&0x55] << 4) | | ||||
| 		(deinterleaveLookup[(code>>16)&0x55] << 8) | | ||||
| 		(deinterleaveLookup[(code>>24)&0x55] << 12) | | ||||
| 		(deinterleaveLookup[(code>>32)&0x55] << 16) | | ||||
| 		(deinterleaveLookup[(code>>40)&0x55] << 20) | | ||||
| 		(deinterleaveLookup[(code>>48)&0x55] << 24) | | ||||
| 		(deinterleaveLookup[(code>>56)&0x55] << 28) | ||||
| 	y := (deinterleaveLookup[code&0xaa]) | | ||||
| 		(deinterleaveLookup[(code>>8)&0xaa] << 4) | | ||||
| 		(deinterleaveLookup[(code>>16)&0xaa] << 8) | | ||||
| 		(deinterleaveLookup[(code>>24)&0xaa] << 12) | | ||||
| 		(deinterleaveLookup[(code>>32)&0xaa] << 16) | | ||||
| 		(deinterleaveLookup[(code>>40)&0xaa] << 20) | | ||||
| 		(deinterleaveLookup[(code>>48)&0xaa] << 24) | | ||||
| 		(deinterleaveLookup[(code>>56)&0xaa] << 28) | ||||
| 	return x, y | ||||
| } | ||||
| 
 | ||||
| var interleaveLookup = [256]uint64{ | ||||
| 	0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, | ||||
| 	0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, | ||||
| 	0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, | ||||
| 	0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, | ||||
| 	0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, | ||||
| 	0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, | ||||
| 	0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, | ||||
| 	0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, | ||||
| 
 | ||||
| 	0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, | ||||
| 	0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, | ||||
| 	0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, | ||||
| 	0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, | ||||
| 	0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, | ||||
| 	0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, | ||||
| 	0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, | ||||
| 	0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, | ||||
| 
 | ||||
| 	0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, | ||||
| 	0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, | ||||
| 	0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, | ||||
| 	0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, | ||||
| 	0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, | ||||
| 	0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, | ||||
| 	0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, | ||||
| 	0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, | ||||
| 
 | ||||
| 	0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, | ||||
| 	0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, | ||||
| 	0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, | ||||
| 	0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, | ||||
| 	0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, | ||||
| 	0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, | ||||
| 	0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, | ||||
| 	0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555, | ||||
| } | ||||
| 
 | ||||
| // interleaveUint32 interleaves the given arguments into the return value. | ||||
| // | ||||
| // The 0-bit in val0 will be the 0-bit in the return value. | ||||
| // The 0-bit in val1 will be the 1-bit in the return value. | ||||
| // The 1-bit of val0 will be the 2-bit in the return value, and so on. | ||||
| func interleaveUint32(x, y uint32) uint64 { | ||||
| 	return (interleaveLookup[x&0xff]) | | ||||
| 		(interleaveLookup[(x>>8)&0xff] << 16) | | ||||
| 		(interleaveLookup[(x>>16)&0xff] << 32) | | ||||
| 		(interleaveLookup[x>>24] << 48) | | ||||
| 		(interleaveLookup[y&0xff] << 1) | | ||||
| 		(interleaveLookup[(y>>8)&0xff] << 17) | | ||||
| 		(interleaveLookup[(y>>16)&0xff] << 33) | | ||||
| 		(interleaveLookup[y>>24] << 49) | ||||
| } | ||||
							
								
								
									
										101
									
								
								vendor/github.com/golang/geo/s2/latlng.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										101
									
								
								vendor/github.com/golang/geo/s2/latlng.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,101 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	northPoleLat = s1.Angle(math.Pi/2) * s1.Radian | ||||
| 	southPoleLat = -northPoleLat | ||||
| ) | ||||
| 
 | ||||
| // LatLng represents a point on the unit sphere as a pair of angles. | ||||
| type LatLng struct { | ||||
| 	Lat, Lng s1.Angle | ||||
| } | ||||
| 
 | ||||
| // LatLngFromDegrees returns a LatLng for the coordinates given in degrees. | ||||
| func LatLngFromDegrees(lat, lng float64) LatLng { | ||||
| 	return LatLng{s1.Angle(lat) * s1.Degree, s1.Angle(lng) * s1.Degree} | ||||
| } | ||||
| 
 | ||||
| // IsValid returns true iff the LatLng is normalized, with Lat ∈ [-π/2,π/2] and Lng ∈ [-π,π]. | ||||
| func (ll LatLng) IsValid() bool { | ||||
| 	return math.Abs(ll.Lat.Radians()) <= math.Pi/2 && math.Abs(ll.Lng.Radians()) <= math.Pi | ||||
| } | ||||
| 
 | ||||
| // Normalized returns the normalized version of the LatLng, | ||||
| // with Lat clamped to [-π/2,π/2] and Lng wrapped in [-π,π]. | ||||
| func (ll LatLng) Normalized() LatLng { | ||||
| 	lat := ll.Lat | ||||
| 	if lat > northPoleLat { | ||||
| 		lat = northPoleLat | ||||
| 	} else if lat < southPoleLat { | ||||
| 		lat = southPoleLat | ||||
| 	} | ||||
| 	lng := s1.Angle(math.Remainder(ll.Lng.Radians(), 2*math.Pi)) * s1.Radian | ||||
| 	return LatLng{lat, lng} | ||||
| } | ||||
| 
 | ||||
| func (ll LatLng) String() string { return fmt.Sprintf("[%v, %v]", ll.Lat, ll.Lng) } | ||||
| 
 | ||||
| // Distance returns the angle between two LatLngs. | ||||
| func (ll LatLng) Distance(ll2 LatLng) s1.Angle { | ||||
| 	// Haversine formula, as used in C++ S2LatLng::GetDistance. | ||||
| 	lat1, lat2 := ll.Lat.Radians(), ll2.Lat.Radians() | ||||
| 	lng1, lng2 := ll.Lng.Radians(), ll2.Lng.Radians() | ||||
| 	dlat := math.Sin(0.5 * (lat2 - lat1)) | ||||
| 	dlng := math.Sin(0.5 * (lng2 - lng1)) | ||||
| 	x := dlat*dlat + dlng*dlng*math.Cos(lat1)*math.Cos(lat2) | ||||
| 	return s1.Angle(2*math.Atan2(math.Sqrt(x), math.Sqrt(math.Max(0, 1-x)))) * s1.Radian | ||||
| } | ||||
| 
 | ||||
| // NOTE(mikeperrow): The C++ implementation publicly exposes latitude/longitude | ||||
| // functions. Let's see if that's really necessary before exposing the same functionality. | ||||
| 
 | ||||
| func latitude(p Point) s1.Angle { | ||||
| 	return s1.Angle(math.Atan2(p.Z, math.Sqrt(p.X*p.X+p.Y*p.Y))) * s1.Radian | ||||
| } | ||||
| 
 | ||||
| func longitude(p Point) s1.Angle { | ||||
| 	return s1.Angle(math.Atan2(p.Y, p.X)) * s1.Radian | ||||
| } | ||||
| 
 | ||||
| // PointFromLatLng returns an Point for the given LatLng. | ||||
| // The maximum error in the result is 1.5 * dblEpsilon. (This does not | ||||
| // include the error of converting degrees, E5, E6, or E7 into radians.) | ||||
| func PointFromLatLng(ll LatLng) Point { | ||||
| 	phi := ll.Lat.Radians() | ||||
| 	theta := ll.Lng.Radians() | ||||
| 	cosphi := math.Cos(phi) | ||||
| 	return Point{r3.Vector{math.Cos(theta) * cosphi, math.Sin(theta) * cosphi, math.Sin(phi)}} | ||||
| } | ||||
| 
 | ||||
| // LatLngFromPoint returns an LatLng for a given Point. | ||||
| func LatLngFromPoint(p Point) LatLng { | ||||
| 	return LatLng{latitude(p), longitude(p)} | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether the latitude and longitude of the two LatLngs | ||||
| // are the same up to a small tolerance. | ||||
| func (ll LatLng) ApproxEqual(other LatLng) bool { | ||||
| 	return ll.Lat.ApproxEqual(other.Lat) && ll.Lng.ApproxEqual(other.Lng) | ||||
| } | ||||
							
								
								
									
										175
									
								
								vendor/github.com/golang/geo/s2/lexicon.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										175
									
								
								vendor/github.com/golang/geo/s2/lexicon.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,175 +0,0 @@ | |||
| // Copyright 2020 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"hash/adler32" | ||||
| 	"math" | ||||
| 	"sort" | ||||
| ) | ||||
| 
 | ||||
| // TODO(roberts): If any of these are worth making public, change the | ||||
| // method signatures and type names. | ||||
| 
 | ||||
| // emptySetID represents the last ID that will ever be generated. | ||||
| // (Non-negative IDs are reserved for singleton sets.) | ||||
| var emptySetID = int32(math.MinInt32) | ||||
| 
 | ||||
| // idSetLexicon compactly represents a set of non-negative | ||||
| // integers such as array indices ("ID sets"). It is especially suitable when | ||||
| // either (1) there are many duplicate sets, or (2) there are many singleton | ||||
| // or empty sets. See also sequenceLexicon. | ||||
| // | ||||
| // Each distinct ID set is mapped to a 32-bit integer. Empty and singleton | ||||
| // sets take up no additional space; the set itself is represented | ||||
| // by the unique ID assigned to the set. Duplicate sets are automatically | ||||
| // eliminated. Note also that ID sets are referred to using 32-bit integers | ||||
| // rather than pointers. | ||||
| type idSetLexicon struct { | ||||
| 	idSets *sequenceLexicon | ||||
| } | ||||
| 
 | ||||
| func newIDSetLexicon() *idSetLexicon { | ||||
| 	return &idSetLexicon{ | ||||
| 		idSets: newSequenceLexicon(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // add adds the given set of integers to the lexicon if it is not already | ||||
| // present, and return the unique ID for this set. The values are automatically | ||||
| // sorted and duplicates are removed. | ||||
| // | ||||
| // The primary difference between this and sequenceLexicon are: | ||||
| // 1. Empty and singleton sets are represented implicitly; they use no space. | ||||
| // 2. Sets are represented rather than sequences; the ordering of values is | ||||
| //    not important and duplicates are removed. | ||||
| // 3. The values must be 32-bit non-negative integers only. | ||||
| func (l *idSetLexicon) add(ids ...int32) int32 { | ||||
| 	// Empty sets have a special ID chosen not to conflict with other IDs. | ||||
| 	if len(ids) == 0 { | ||||
| 		return emptySetID | ||||
| 	} | ||||
| 
 | ||||
| 	// Singleton sets are represented by their element. | ||||
| 	if len(ids) == 1 { | ||||
| 		return ids[0] | ||||
| 	} | ||||
| 
 | ||||
| 	// Canonicalize the set by sorting and removing duplicates. | ||||
| 	// | ||||
| 	// Creates a new slice in order to not alter the supplied values. | ||||
| 	set := uniqueInt32s(ids) | ||||
| 
 | ||||
| 	// Non-singleton sets are represented by the bitwise complement of the ID | ||||
| 	// returned by the sequenceLexicon | ||||
| 	return ^l.idSets.add(set) | ||||
| } | ||||
| 
 | ||||
| // idSet returns the set of integers corresponding to an ID returned by add. | ||||
| func (l *idSetLexicon) idSet(setID int32) []int32 { | ||||
| 	if setID >= 0 { | ||||
| 		return []int32{setID} | ||||
| 	} | ||||
| 	if setID == emptySetID { | ||||
| 		return []int32{} | ||||
| 	} | ||||
| 
 | ||||
| 	return l.idSets.sequence(^setID) | ||||
| } | ||||
| 
 | ||||
| func (l *idSetLexicon) clear() { | ||||
| 	l.idSets.clear() | ||||
| } | ||||
| 
 | ||||
| // sequenceLexicon compactly represents a sequence of values (e.g., tuples). | ||||
| // It automatically eliminates duplicates slices, and maps the remaining | ||||
| // sequences to sequentially increasing integer IDs. See also idSetLexicon. | ||||
| // | ||||
| // Each distinct sequence is mapped to a 32-bit integer. | ||||
| type sequenceLexicon struct { | ||||
| 	values []int32 | ||||
| 	begins []uint32 | ||||
| 
 | ||||
| 	// idSet is a mapping of a sequence hash to sequence index in the lexicon. | ||||
| 	idSet map[uint32]int32 | ||||
| } | ||||
| 
 | ||||
| func newSequenceLexicon() *sequenceLexicon { | ||||
| 	return &sequenceLexicon{ | ||||
| 		begins: []uint32{0}, | ||||
| 		idSet:  make(map[uint32]int32), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // clears all data from the lexicon. | ||||
| func (l *sequenceLexicon) clear() { | ||||
| 	l.values = nil | ||||
| 	l.begins = []uint32{0} | ||||
| 	l.idSet = make(map[uint32]int32) | ||||
| } | ||||
| 
 | ||||
| // add adds the given value to the lexicon if it is not already present, and | ||||
| // returns its ID. IDs are assigned sequentially starting from zero. | ||||
| func (l *sequenceLexicon) add(ids []int32) int32 { | ||||
| 	if id, ok := l.idSet[hashSet(ids)]; ok { | ||||
| 		return id | ||||
| 	} | ||||
| 	for _, v := range ids { | ||||
| 		l.values = append(l.values, v) | ||||
| 	} | ||||
| 	l.begins = append(l.begins, uint32(len(l.values))) | ||||
| 
 | ||||
| 	id := int32(len(l.begins)) - 2 | ||||
| 	l.idSet[hashSet(ids)] = id | ||||
| 
 | ||||
| 	return id | ||||
| } | ||||
| 
 | ||||
| // sequence returns the original sequence of values for the given ID. | ||||
| func (l *sequenceLexicon) sequence(id int32) []int32 { | ||||
| 	return l.values[l.begins[id]:l.begins[id+1]] | ||||
| } | ||||
| 
 | ||||
| // size reports the number of value sequences in the lexicon. | ||||
| func (l *sequenceLexicon) size() int { | ||||
| 	// Subtract one because the list of begins starts out with the first element set to 0. | ||||
| 	return len(l.begins) - 1 | ||||
| } | ||||
| 
 | ||||
| // hash returns a hash of this sequence of int32s. | ||||
| func hashSet(s []int32) uint32 { | ||||
| 	// TODO(roberts): We just need a way to nicely hash all the values down to | ||||
| 	// a 32-bit value. To ensure no unnecessary dependencies we use the core | ||||
| 	// library types available to do this. Is there a better option? | ||||
| 	a := adler32.New() | ||||
| 	binary.Write(a, binary.LittleEndian, s) | ||||
| 	return a.Sum32() | ||||
| } | ||||
| 
 | ||||
| // uniqueInt32s returns the sorted and uniqued set of int32s from the input. | ||||
| func uniqueInt32s(in []int32) []int32 { | ||||
| 	var vals []int32 | ||||
| 	m := make(map[int32]bool) | ||||
| 	for _, i := range in { | ||||
| 		if m[i] { | ||||
| 			continue | ||||
| 		} | ||||
| 		m[i] = true | ||||
| 		vals = append(vals, i) | ||||
| 	} | ||||
| 	sort.Slice(vals, func(i, j int) bool { return vals[i] < vals[j] }) | ||||
| 	return vals | ||||
| } | ||||
							
								
								
									
										1833
									
								
								vendor/github.com/golang/geo/s2/loop.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1833
									
								
								vendor/github.com/golang/geo/s2/loop.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										127
									
								
								vendor/github.com/golang/geo/s2/matrix3x3.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										127
									
								
								vendor/github.com/golang/geo/s2/matrix3x3.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,127 +0,0 @@ | |||
| // Copyright 2015 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| // matrix3x3 represents a traditional 3x3 matrix of floating point values. | ||||
| // This is not a full fledged matrix. It only contains the pieces needed | ||||
| // to satisfy the computations done within the s2 package. | ||||
| type matrix3x3 [3][3]float64 | ||||
| 
 | ||||
| // col returns the given column as a Point. | ||||
| func (m *matrix3x3) col(col int) Point { | ||||
| 	return Point{r3.Vector{m[0][col], m[1][col], m[2][col]}} | ||||
| } | ||||
| 
 | ||||
| // row returns the given row as a Point. | ||||
| func (m *matrix3x3) row(row int) Point { | ||||
| 	return Point{r3.Vector{m[row][0], m[row][1], m[row][2]}} | ||||
| } | ||||
| 
 | ||||
| // setCol sets the specified column to the value in the given Point. | ||||
| func (m *matrix3x3) setCol(col int, p Point) *matrix3x3 { | ||||
| 	m[0][col] = p.X | ||||
| 	m[1][col] = p.Y | ||||
| 	m[2][col] = p.Z | ||||
| 
 | ||||
| 	return m | ||||
| } | ||||
| 
 | ||||
| // setRow sets the specified row to the value in the given Point. | ||||
| func (m *matrix3x3) setRow(row int, p Point) *matrix3x3 { | ||||
| 	m[row][0] = p.X | ||||
| 	m[row][1] = p.Y | ||||
| 	m[row][2] = p.Z | ||||
| 
 | ||||
| 	return m | ||||
| } | ||||
| 
 | ||||
| // scale multiplies the matrix by the given value. | ||||
| func (m *matrix3x3) scale(f float64) *matrix3x3 { | ||||
| 	return &matrix3x3{ | ||||
| 		[3]float64{f * m[0][0], f * m[0][1], f * m[0][2]}, | ||||
| 		[3]float64{f * m[1][0], f * m[1][1], f * m[1][2]}, | ||||
| 		[3]float64{f * m[2][0], f * m[2][1], f * m[2][2]}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // mul returns the multiplication of m by the Point p and converts the | ||||
| // resulting 1x3 matrix into a Point. | ||||
| func (m *matrix3x3) mul(p Point) Point { | ||||
| 	return Point{r3.Vector{ | ||||
| 		m[0][0]*p.X + m[0][1]*p.Y + m[0][2]*p.Z, | ||||
| 		m[1][0]*p.X + m[1][1]*p.Y + m[1][2]*p.Z, | ||||
| 		m[2][0]*p.X + m[2][1]*p.Y + m[2][2]*p.Z, | ||||
| 	}} | ||||
| } | ||||
| 
 | ||||
| // det returns the determinant of this matrix. | ||||
| func (m *matrix3x3) det() float64 { | ||||
| 	//      | a  b  c | | ||||
| 	//  det | d  e  f | = aei + bfg + cdh - ceg - bdi - afh | ||||
| 	//      | g  h  i | | ||||
| 	return m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] + m[0][2]*m[1][0]*m[2][1] - | ||||
| 		m[0][2]*m[1][1]*m[2][0] - m[0][1]*m[1][0]*m[2][2] - m[0][0]*m[1][2]*m[2][1] | ||||
| } | ||||
| 
 | ||||
| // transpose reflects the matrix along its diagonal and returns the result. | ||||
| func (m *matrix3x3) transpose() *matrix3x3 { | ||||
| 	m[0][1], m[1][0] = m[1][0], m[0][1] | ||||
| 	m[0][2], m[2][0] = m[2][0], m[0][2] | ||||
| 	m[1][2], m[2][1] = m[2][1], m[1][2] | ||||
| 
 | ||||
| 	return m | ||||
| } | ||||
| 
 | ||||
| // String formats the matrix into an easier to read layout. | ||||
| func (m *matrix3x3) String() string { | ||||
| 	return fmt.Sprintf("[ %0.4f %0.4f %0.4f ] [ %0.4f %0.4f %0.4f ] [ %0.4f %0.4f %0.4f ]", | ||||
| 		m[0][0], m[0][1], m[0][2], | ||||
| 		m[1][0], m[1][1], m[1][2], | ||||
| 		m[2][0], m[2][1], m[2][2], | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| // getFrame returns the orthonormal frame for the given point on the unit sphere. | ||||
| func getFrame(p Point) matrix3x3 { | ||||
| 	// Given the point p on the unit sphere, extend this into a right-handed | ||||
| 	// coordinate frame of unit-length column vectors m = (x,y,z).  Note that | ||||
| 	// the vectors (x,y) are an orthonormal frame for the tangent space at point p, | ||||
| 	// while p itself is an orthonormal frame for the normal space at p. | ||||
| 	m := matrix3x3{} | ||||
| 	m.setCol(2, p) | ||||
| 	m.setCol(1, Point{p.Ortho()}) | ||||
| 	m.setCol(0, Point{m.col(1).Cross(p.Vector)}) | ||||
| 	return m | ||||
| } | ||||
| 
 | ||||
| // toFrame returns the coordinates of the given point with respect to its orthonormal basis m. | ||||
| // The resulting point q satisfies the identity (m * q == p). | ||||
| func toFrame(m matrix3x3, p Point) Point { | ||||
| 	// The inverse of an orthonormal matrix is its transpose. | ||||
| 	return m.transpose().mul(p) | ||||
| } | ||||
| 
 | ||||
| // fromFrame returns the coordinates of the given point in standard axis-aligned basis | ||||
| // from its orthonormal basis m. | ||||
| // The resulting point p satisfies the identity (p == m * q). | ||||
| func fromFrame(m matrix3x3, q Point) Point { | ||||
| 	return m.mul(q) | ||||
| } | ||||
							
								
								
									
										306
									
								
								vendor/github.com/golang/geo/s2/max_distance_targets.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										306
									
								
								vendor/github.com/golang/geo/s2/max_distance_targets.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,306 +0,0 @@ | |||
| // Copyright 2019 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // maxDistance implements distance as the supplementary distance (Pi - x) to find | ||||
| // results that are the furthest using the distance related algorithms. | ||||
| type maxDistance s1.ChordAngle | ||||
| 
 | ||||
| func (m maxDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) } | ||||
| func (m maxDistance) zero() distance            { return maxDistance(s1.StraightChordAngle) } | ||||
| func (m maxDistance) negative() distance        { return maxDistance(s1.InfChordAngle()) } | ||||
| func (m maxDistance) infinity() distance        { return maxDistance(s1.NegativeChordAngle) } | ||||
| func (m maxDistance) less(other distance) bool  { return m.chordAngle() > other.chordAngle() } | ||||
| func (m maxDistance) sub(other distance) distance { | ||||
| 	return maxDistance(m.chordAngle() + other.chordAngle()) | ||||
| } | ||||
| func (m maxDistance) chordAngleBound() s1.ChordAngle { | ||||
| 	return s1.StraightChordAngle - m.chordAngle() | ||||
| } | ||||
| func (m maxDistance) updateDistance(dist distance) (distance, bool) { | ||||
| 	if dist.less(m) { | ||||
| 		m = maxDistance(dist.chordAngle()) | ||||
| 		return m, true | ||||
| 	} | ||||
| 	return m, false | ||||
| } | ||||
| 
 | ||||
| func (m maxDistance) fromChordAngle(o s1.ChordAngle) distance { | ||||
| 	return maxDistance(o) | ||||
| } | ||||
| 
 | ||||
| // MaxDistanceToPointTarget is used for computing the maximum distance to a Point. | ||||
| type MaxDistanceToPointTarget struct { | ||||
| 	point Point | ||||
| 	dist  distance | ||||
| } | ||||
| 
 | ||||
| // NewMaxDistanceToPointTarget returns a new target for the given Point. | ||||
| func NewMaxDistanceToPointTarget(point Point) *MaxDistanceToPointTarget { | ||||
| 	m := maxDistance(0) | ||||
| 	return &MaxDistanceToPointTarget{point: point, dist: &m} | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) capBound() Cap { | ||||
| 	return CapFromCenterChordAngle(Point{m.point.Mul(-1)}, (s1.ChordAngle(0))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(ChordAngleBetweenPoints(p, m.point))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	if d, ok := UpdateMaxDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(maxDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(cell.MaxDistance(m.point))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// For furthest points, we visit the polygons whose interior contains | ||||
| 	// the antipode of the target point. These are the polygons whose | ||||
| 	// distance to the target is maxDistance.zero() | ||||
| 	q := NewContainsPointQuery(index, VertexModelSemiOpen) | ||||
| 	return q.visitContainingShapes(Point{m.point.Mul(-1)}, func(shape Shape) bool { | ||||
| 		return v(shape, m.point) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MaxDistanceToPointTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MaxDistanceToPointTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // MaxDistanceToEdgeTarget is used for computing the maximum distance to an Edge. | ||||
| type MaxDistanceToEdgeTarget struct { | ||||
| 	e    Edge | ||||
| 	dist distance | ||||
| } | ||||
| 
 | ||||
| // NewMaxDistanceToEdgeTarget returns a new target for the given Edge. | ||||
| func NewMaxDistanceToEdgeTarget(e Edge) *MaxDistanceToEdgeTarget { | ||||
| 	m := maxDistance(0) | ||||
| 	return &MaxDistanceToEdgeTarget{e: e, dist: m} | ||||
| } | ||||
| 
 | ||||
| // capBound returns a Cap that bounds the antipode of the target. (This | ||||
| // is the set of points whose maxDistance to the target is maxDistance.zero) | ||||
| func (m *MaxDistanceToEdgeTarget) capBound() Cap { | ||||
| 	// The following computes a radius equal to half the edge length in an | ||||
| 	// efficient and numerically stable way. | ||||
| 	d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1)) | ||||
| 	r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2)) | ||||
| 	return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Mul(-1).Normalize()}, s1.ChordAngleFromSquaredLength(r2)) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	if d, ok := UpdateMaxDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(maxDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	if d, ok := updateEdgePairMaxDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(maxDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(cell.MaxDistanceToEdge(m.e.V0, m.e.V1))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// We only need to test one edge point. That is because the method *must* | ||||
| 	// visit a polygon if it fully contains the target, and *is allowed* to | ||||
| 	// visit a polygon if it intersects the target. If the tested vertex is not | ||||
| 	// contained, we know the full edge is not contained; if the tested vertex is | ||||
| 	// contained, then the edge either is fully contained (must be visited) or it | ||||
| 	// intersects (is allowed to be visited). We visit the center of the edge so | ||||
| 	// that edge AB gives identical results to BA. | ||||
| 	target := NewMaxDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}) | ||||
| 	return target.visitContainingShapes(index, v) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MaxDistanceToEdgeTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MaxDistanceToEdgeTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // MaxDistanceToCellTarget is used for computing the maximum distance to a Cell. | ||||
| type MaxDistanceToCellTarget struct { | ||||
| 	cell Cell | ||||
| 	dist distance | ||||
| } | ||||
| 
 | ||||
| // NewMaxDistanceToCellTarget returns a new target for the given Cell. | ||||
| func NewMaxDistanceToCellTarget(cell Cell) *MaxDistanceToCellTarget { | ||||
| 	m := maxDistance(0) | ||||
| 	return &MaxDistanceToCellTarget{cell: cell, dist: m} | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) capBound() Cap { | ||||
| 	c := m.cell.CapBound() | ||||
| 	return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius()) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(m.cell.MaxDistance(p))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(m.cell.MaxDistanceToEdge(edge.V0, edge.V1))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(maxDistance(m.cell.MaxDistanceToCell(cell))) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// We only need to check one point here - cell center is simplest. | ||||
| 	// See comment at MaxDistanceToEdgeTarget's visitContainingShapes. | ||||
| 	target := NewMaxDistanceToPointTarget(m.cell.Center()) | ||||
| 	return target.visitContainingShapes(index, v) | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MaxDistanceToCellTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MaxDistanceToCellTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // MaxDistanceToShapeIndexTarget is used for computing the maximum distance to a ShapeIndex. | ||||
| type MaxDistanceToShapeIndexTarget struct { | ||||
| 	index *ShapeIndex | ||||
| 	query *EdgeQuery | ||||
| 	dist  distance | ||||
| } | ||||
| 
 | ||||
| // NewMaxDistanceToShapeIndexTarget returns a new target for the given ShapeIndex. | ||||
| func NewMaxDistanceToShapeIndexTarget(index *ShapeIndex) *MaxDistanceToShapeIndexTarget { | ||||
| 	m := maxDistance(0) | ||||
| 	return &MaxDistanceToShapeIndexTarget{ | ||||
| 		index: index, | ||||
| 		dist:  m, | ||||
| 		query: NewFurthestEdgeQuery(index, NewFurthestEdgeQueryOptions()), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // capBound returns a Cap that bounds the antipode of the target. This | ||||
| // is the set of points whose maxDistance to the target is maxDistance.zero() | ||||
| func (m *MaxDistanceToShapeIndexTarget) capBound() Cap { | ||||
| 	// TODO(roberts): Depends on ShapeIndexRegion | ||||
| 	// c := makeShapeIndexRegion(m.index).CapBound() | ||||
| 	// return CapFromCenterRadius(Point{c.Center.Mul(-1)}, c.Radius()) | ||||
| 	panic("not implemented yet") | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMaxDistanceToPointTarget(p) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMaxDistanceToEdgeTarget(edge) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMaxDistanceToCellTarget(cell) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| // visitContainingShapes returns the polygons containing the antipodal | ||||
| // reflection of *any* connected component for target types consisting of | ||||
| // multiple connected components. It is sufficient to test containment of | ||||
| // one vertex per connected component, since this allows us to also return | ||||
| // any polygon whose boundary has distance.zero() to the target. | ||||
| func (m *MaxDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// It is sufficient to find the set of chain starts in the target index | ||||
| 	// (i.e., one vertex per connected component of edges) that are contained by | ||||
| 	// the query index, except for one special case to handle full polygons. | ||||
| 	// | ||||
| 	// TODO(roberts): Do this by merge-joining the two ShapeIndexes and share | ||||
| 	// the code with BooleanOperation. | ||||
| 	for _, shape := range m.index.shapes { | ||||
| 		numChains := shape.NumChains() | ||||
| 		// Shapes that don't have any edges require a special case (below). | ||||
| 		testedPoint := false | ||||
| 		for c := 0; c < numChains; c++ { | ||||
| 			chain := shape.Chain(c) | ||||
| 			if chain.Length == 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			testedPoint = true | ||||
| 			target := NewMaxDistanceToPointTarget(shape.ChainEdge(c, 0).V0) | ||||
| 			if !target.visitContainingShapes(index, v) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 		if !testedPoint { | ||||
| 			// Special case to handle full polygons. | ||||
| 			ref := shape.ReferencePoint() | ||||
| 			if !ref.Contained { | ||||
| 				continue | ||||
| 			} | ||||
| 			target := NewMaxDistanceToPointTarget(ref.Point) | ||||
| 			if !target.visitContainingShapes(index, v) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (m *MaxDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool { | ||||
| 	m.query.opts.maxError = maxErr | ||||
| 	return true | ||||
| } | ||||
| func (m *MaxDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 30 } | ||||
| func (m *MaxDistanceToShapeIndexTarget) distance() distance          { return m.dist } | ||||
| func (m *MaxDistanceToShapeIndexTarget) setIncludeInteriors(b bool) { | ||||
| 	m.query.opts.includeInteriors = b | ||||
| } | ||||
| func (m *MaxDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b } | ||||
| 
 | ||||
| // TODO(roberts): Remaining methods | ||||
| // | ||||
| // func (m *MaxDistanceToShapeIndexTarget) capBound() Cap { | ||||
| // CellUnionTarget | ||||
							
								
								
									
										164
									
								
								vendor/github.com/golang/geo/s2/metric.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										164
									
								
								vendor/github.com/golang/geo/s2/metric.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,164 +0,0 @@ | |||
| // Copyright 2015 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file implements functions for various S2 measurements. | ||||
| 
 | ||||
| import "math" | ||||
| 
 | ||||
| // A Metric is a measure for cells. It is used to describe the shape and size | ||||
| // of cells. They are useful for deciding which cell level to use in order to | ||||
| // satisfy a given condition (e.g. that cell vertices must be no further than | ||||
| // "x" apart). You can use the Value(level) method to compute the corresponding | ||||
| // length or area on the unit sphere for cells at a given level. The minimum | ||||
| // and maximum bounds are valid for cells at all levels, but they may be | ||||
| // somewhat conservative for very large cells (e.g. face cells). | ||||
| type Metric struct { | ||||
| 	// Dim is either 1 or 2, for a 1D or 2D metric respectively. | ||||
| 	Dim int | ||||
| 	// Deriv is the scaling factor for the metric. | ||||
| 	Deriv float64 | ||||
| } | ||||
| 
 | ||||
| // Defined metrics. | ||||
| // Of the projection methods defined in C++, Go only supports the quadratic projection. | ||||
| 
 | ||||
| // Each cell is bounded by four planes passing through its four edges and | ||||
| // the center of the sphere. These metrics relate to the angle between each | ||||
| // pair of opposite bounding planes, or equivalently, between the planes | ||||
| // corresponding to two different s-values or two different t-values. | ||||
| var ( | ||||
| 	MinAngleSpanMetric = Metric{1, 4.0 / 3} | ||||
| 	AvgAngleSpanMetric = Metric{1, math.Pi / 2} | ||||
| 	MaxAngleSpanMetric = Metric{1, 1.704897179199218452} | ||||
| ) | ||||
| 
 | ||||
| // The width of geometric figure is defined as the distance between two | ||||
| // parallel bounding lines in a given direction. For cells, the minimum | ||||
| // width is always attained between two opposite edges, and the maximum | ||||
| // width is attained between two opposite vertices. However, for our | ||||
| // purposes we redefine the width of a cell as the perpendicular distance | ||||
| // between a pair of opposite edges. A cell therefore has two widths, one | ||||
| // in each direction. The minimum width according to this definition agrees | ||||
| // with the classic geometric one, but the maximum width is different. (The | ||||
| // maximum geometric width corresponds to MaxDiag defined below.) | ||||
| // | ||||
| // The average width in both directions for all cells at level k is approximately | ||||
| // AvgWidthMetric.Value(k). | ||||
| // | ||||
| // The width is useful for bounding the minimum or maximum distance from a | ||||
| // point on one edge of a cell to the closest point on the opposite edge. | ||||
| // For example, this is useful when growing regions by a fixed distance. | ||||
| var ( | ||||
| 	MinWidthMetric = Metric{1, 2 * math.Sqrt2 / 3} | ||||
| 	AvgWidthMetric = Metric{1, 1.434523672886099389} | ||||
| 	MaxWidthMetric = Metric{1, MaxAngleSpanMetric.Deriv} | ||||
| ) | ||||
| 
 | ||||
| // The edge length metrics can be used to bound the minimum, maximum, | ||||
| // or average distance from the center of one cell to the center of one of | ||||
| // its edge neighbors. In particular, it can be used to bound the distance | ||||
| // between adjacent cell centers along the space-filling Hilbert curve for | ||||
| // cells at any given level. | ||||
| var ( | ||||
| 	MinEdgeMetric = Metric{1, 2 * math.Sqrt2 / 3} | ||||
| 	AvgEdgeMetric = Metric{1, 1.459213746386106062} | ||||
| 	MaxEdgeMetric = Metric{1, MaxAngleSpanMetric.Deriv} | ||||
| 
 | ||||
| 	// MaxEdgeAspect is the maximum edge aspect ratio over all cells at any level, | ||||
| 	// where the edge aspect ratio of a cell is defined as the ratio of its longest | ||||
| 	// edge length to its shortest edge length. | ||||
| 	MaxEdgeAspect = 1.442615274452682920 | ||||
| 
 | ||||
| 	MinAreaMetric = Metric{2, 8 * math.Sqrt2 / 9} | ||||
| 	AvgAreaMetric = Metric{2, 4 * math.Pi / 6} | ||||
| 	MaxAreaMetric = Metric{2, 2.635799256963161491} | ||||
| ) | ||||
| 
 | ||||
| // The maximum diagonal is also the maximum diameter of any cell, | ||||
| // and also the maximum geometric width (see the comment for widths). For | ||||
| // example, the distance from an arbitrary point to the closest cell center | ||||
| // at a given level is at most half the maximum diagonal length. | ||||
| var ( | ||||
| 	MinDiagMetric = Metric{1, 8 * math.Sqrt2 / 9} | ||||
| 	AvgDiagMetric = Metric{1, 2.060422738998471683} | ||||
| 	MaxDiagMetric = Metric{1, 2.438654594434021032} | ||||
| 
 | ||||
| 	// MaxDiagAspect is the maximum diagonal aspect ratio over all cells at any | ||||
| 	// level, where the diagonal aspect ratio of a cell is defined as the ratio | ||||
| 	// of its longest diagonal length to its shortest diagonal length. | ||||
| 	MaxDiagAspect = math.Sqrt(3) | ||||
| ) | ||||
| 
 | ||||
| // Value returns the value of the metric at the given level. | ||||
| func (m Metric) Value(level int) float64 { | ||||
| 	return math.Ldexp(m.Deriv, -m.Dim*level) | ||||
| } | ||||
| 
 | ||||
| // MinLevel returns the minimum level such that the metric is at most | ||||
| // the given value, or maxLevel (30) if there is no such level. | ||||
| // | ||||
| // For example, MinLevel(0.1) returns the minimum level such that all cell diagonal | ||||
| // lengths are 0.1 or smaller. The returned value is always a valid level. | ||||
| // | ||||
| // In C++, this is called GetLevelForMaxValue. | ||||
| func (m Metric) MinLevel(val float64) int { | ||||
| 	if val < 0 { | ||||
| 		return maxLevel | ||||
| 	} | ||||
| 
 | ||||
| 	level := -(math.Ilogb(val/m.Deriv) >> uint(m.Dim-1)) | ||||
| 	if level > maxLevel { | ||||
| 		level = maxLevel | ||||
| 	} | ||||
| 	if level < 0 { | ||||
| 		level = 0 | ||||
| 	} | ||||
| 	return level | ||||
| } | ||||
| 
 | ||||
| // MaxLevel returns the maximum level such that the metric is at least | ||||
| // the given value, or zero if there is no such level. | ||||
| // | ||||
| // For example, MaxLevel(0.1) returns the maximum level such that all cells have a | ||||
| // minimum width of 0.1 or larger. The returned value is always a valid level. | ||||
| // | ||||
| // In C++, this is called GetLevelForMinValue. | ||||
| func (m Metric) MaxLevel(val float64) int { | ||||
| 	if val <= 0 { | ||||
| 		return maxLevel | ||||
| 	} | ||||
| 
 | ||||
| 	level := math.Ilogb(m.Deriv/val) >> uint(m.Dim-1) | ||||
| 	if level > maxLevel { | ||||
| 		level = maxLevel | ||||
| 	} | ||||
| 	if level < 0 { | ||||
| 		level = 0 | ||||
| 	} | ||||
| 	return level | ||||
| } | ||||
| 
 | ||||
| // ClosestLevel returns the level at which the metric has approximately the given | ||||
| // value. The return value is always a valid level. For example, | ||||
| // AvgEdgeMetric.ClosestLevel(0.1) returns the level at which the average cell edge | ||||
| // length is approximately 0.1. | ||||
| func (m Metric) ClosestLevel(val float64) int { | ||||
| 	x := math.Sqrt2 | ||||
| 	if m.Dim == 2 { | ||||
| 		x = 2 | ||||
| 	} | ||||
| 	return m.MinLevel(x * val) | ||||
| } | ||||
							
								
								
									
										362
									
								
								vendor/github.com/golang/geo/s2/min_distance_targets.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										362
									
								
								vendor/github.com/golang/geo/s2/min_distance_targets.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,362 +0,0 @@ | |||
| // Copyright 2019 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // minDistance implements distance interface to find closest distance types. | ||||
| type minDistance s1.ChordAngle | ||||
| 
 | ||||
| func (m minDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) } | ||||
| func (m minDistance) zero() distance            { return minDistance(0) } | ||||
| func (m minDistance) negative() distance        { return minDistance(s1.NegativeChordAngle) } | ||||
| func (m minDistance) infinity() distance        { return minDistance(s1.InfChordAngle()) } | ||||
| func (m minDistance) less(other distance) bool  { return m.chordAngle() < other.chordAngle() } | ||||
| func (m minDistance) sub(other distance) distance { | ||||
| 	return minDistance(m.chordAngle() - other.chordAngle()) | ||||
| } | ||||
| func (m minDistance) chordAngleBound() s1.ChordAngle { | ||||
| 	return m.chordAngle().Expanded(m.chordAngle().MaxAngleError()) | ||||
| } | ||||
| 
 | ||||
| // updateDistance updates its own value if the other value is less() than it is, | ||||
| // and reports if it updated. | ||||
| func (m minDistance) updateDistance(dist distance) (distance, bool) { | ||||
| 	if dist.less(m) { | ||||
| 		m = minDistance(dist.chordAngle()) | ||||
| 		return m, true | ||||
| 	} | ||||
| 	return m, false | ||||
| } | ||||
| 
 | ||||
| func (m minDistance) fromChordAngle(o s1.ChordAngle) distance { | ||||
| 	return minDistance(o) | ||||
| } | ||||
| 
 | ||||
| // MinDistanceToPointTarget is a type for computing the minimum distance to a Point. | ||||
| type MinDistanceToPointTarget struct { | ||||
| 	point Point | ||||
| 	dist  distance | ||||
| } | ||||
| 
 | ||||
| // NewMinDistanceToPointTarget returns a new target for the given Point. | ||||
| func NewMinDistanceToPointTarget(point Point) *MinDistanceToPointTarget { | ||||
| 	m := minDistance(0) | ||||
| 	return &MinDistanceToPointTarget{point: point, dist: &m} | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) capBound() Cap { | ||||
| 	return CapFromCenterChordAngle(m.point, s1.ChordAngle(0)) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	var ok bool | ||||
| 	dist, ok = dist.updateDistance(minDistance(ChordAngleBetweenPoints(p, m.point))) | ||||
| 	return dist, ok | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	if d, ok := UpdateMinDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(minDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	var ok bool | ||||
| 	dist, ok = dist.updateDistance(minDistance(cell.Distance(m.point))) | ||||
| 	return dist, ok | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// For furthest points, we visit the polygons whose interior contains | ||||
| 	// the antipode of the target point. These are the polygons whose | ||||
| 	// distance to the target is maxDistance.zero() | ||||
| 	q := NewContainsPointQuery(index, VertexModelSemiOpen) | ||||
| 	return q.visitContainingShapes(m.point, func(shape Shape) bool { | ||||
| 		return v(shape, m.point) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MinDistanceToPointTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MinDistanceToPointTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| // MinDistanceToEdgeTarget is a type for computing the minimum distance to an Edge. | ||||
| type MinDistanceToEdgeTarget struct { | ||||
| 	e    Edge | ||||
| 	dist distance | ||||
| } | ||||
| 
 | ||||
| // NewMinDistanceToEdgeTarget returns a new target for the given Edge. | ||||
| func NewMinDistanceToEdgeTarget(e Edge) *MinDistanceToEdgeTarget { | ||||
| 	m := minDistance(0) | ||||
| 	return &MinDistanceToEdgeTarget{e: e, dist: m} | ||||
| } | ||||
| 
 | ||||
| // capBound returns a Cap that bounds the antipode of the target. (This | ||||
| // is the set of points whose maxDistance to the target is maxDistance.zero) | ||||
| func (m *MinDistanceToEdgeTarget) capBound() Cap { | ||||
| 	// The following computes a radius equal to half the edge length in an | ||||
| 	// efficient and numerically stable way. | ||||
| 	d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1)) | ||||
| 	r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2)) | ||||
| 	return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}, s1.ChordAngleFromSquaredLength(r2)) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	if d, ok := UpdateMinDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(minDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	if d, ok := updateEdgePairMinDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok { | ||||
| 		dist, _ = dist.updateDistance(minDistance(d)) | ||||
| 		return dist, true | ||||
| 	} | ||||
| 	return dist, false | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(minDistance(cell.DistanceToEdge(m.e.V0, m.e.V1))) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// We test the center of the edge in order to ensure that edge targets AB | ||||
| 	// and BA yield identical results (which is not guaranteed by the API but | ||||
| 	// users might expect).  Other options would be to test both endpoints, or | ||||
| 	// return different results for AB and BA in some cases. | ||||
| 	target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}) | ||||
| 	return target.visitContainingShapes(index, v) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MinDistanceToEdgeTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MinDistanceToEdgeTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| // MinDistanceToCellTarget is a type for computing the minimum distance to a Cell. | ||||
| type MinDistanceToCellTarget struct { | ||||
| 	cell Cell | ||||
| 	dist distance | ||||
| } | ||||
| 
 | ||||
| // NewMinDistanceToCellTarget returns a new target for the given Cell. | ||||
| func NewMinDistanceToCellTarget(cell Cell) *MinDistanceToCellTarget { | ||||
| 	m := minDistance(0) | ||||
| 	return &MinDistanceToCellTarget{cell: cell, dist: m} | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellTarget) capBound() Cap { | ||||
| 	return m.cell.CapBound() | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(minDistance(m.cell.Distance(p))) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(minDistance(m.cell.DistanceToEdge(edge.V0, edge.V1))) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	return dist.updateDistance(minDistance(m.cell.DistanceToCell(cell))) | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// The simplest approach is simply to return the polygons that contain the | ||||
| 	// cell center.  Alternatively, if the index cell is smaller than the target | ||||
| 	// cell then we could return all polygons that are present in the | ||||
| 	// shapeIndexCell, but since the index is built conservatively this may | ||||
| 	// include some polygons that don't quite intersect the cell.  So we would | ||||
| 	// either need to recheck for intersection more accurately, or weaken the | ||||
| 	// VisitContainingShapes contract so that it only guarantees approximate | ||||
| 	// intersection, neither of which seems like a good tradeoff. | ||||
| 	target := NewMinDistanceToPointTarget(m.cell.Center()) | ||||
| 	return target.visitContainingShapes(index, v) | ||||
| } | ||||
| func (m *MinDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false } | ||||
| func (m *MinDistanceToCellTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MinDistanceToCellTarget) distance() distance                    { return m.dist } | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| /* | ||||
| // MinDistanceToCellUnionTarget is a type for computing the minimum distance to a CellUnion. | ||||
| type MinDistanceToCellUnionTarget struct { | ||||
| 	cu    CellUnion | ||||
| 	query *ClosestCellQuery | ||||
| 	dist  distance | ||||
| } | ||||
| 
 | ||||
| // NewMinDistanceToCellUnionTarget returns a new target for the given CellUnion. | ||||
| func NewMinDistanceToCellUnionTarget(cu CellUnion) *MinDistanceToCellUnionTarget { | ||||
| 	m := minDistance(0) | ||||
| 	return &MinDistanceToCellUnionTarget{cu: cu, dist: m} | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellUnionTarget) capBound() Cap { | ||||
| 	return m.cu.CapBound() | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellUnionTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	m.query.opts.DistanceLimit = dist.chordAngle() | ||||
| 	target := NewMinDistanceToPointTarget(p) | ||||
| 	r := m.query.findEdge(target) | ||||
| 	if r.ShapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return minDistance(r.Distance), true | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToCellUnionTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// We test the center of the edge in order to ensure that edge targets AB | ||||
| 	// and BA yield identical results (which is not guaranteed by the API but | ||||
| 	// users might expect).  Other options would be to test both endpoints, or | ||||
| 	// return different results for AB and BA in some cases. | ||||
| 	target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}) | ||||
| 	return target.visitContainingShapes(index, v) | ||||
| } | ||||
| func (m *MinDistanceToCellUnionTarget) setMaxError(maxErr s1.ChordAngle) bool { | ||||
| 	m.query.opts.MaxError = maxErr | ||||
| 	return true | ||||
| } | ||||
| func (m *MinDistanceToCellUnionTarget) maxBruteForceIndexSize() int           { return 30 } | ||||
| func (m *MinDistanceToCellUnionTarget) distance() distance                    { return m.dist } | ||||
| */ | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| // MinDistanceToShapeIndexTarget is a type for computing the minimum distance to a ShapeIndex. | ||||
| type MinDistanceToShapeIndexTarget struct { | ||||
| 	index *ShapeIndex | ||||
| 	query *EdgeQuery | ||||
| 	dist  distance | ||||
| } | ||||
| 
 | ||||
| // NewMinDistanceToShapeIndexTarget returns a new target for the given ShapeIndex. | ||||
| func NewMinDistanceToShapeIndexTarget(index *ShapeIndex) *MinDistanceToShapeIndexTarget { | ||||
| 	m := minDistance(0) | ||||
| 	return &MinDistanceToShapeIndexTarget{ | ||||
| 		index: index, | ||||
| 		dist:  m, | ||||
| 		query: NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions()), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToShapeIndexTarget) capBound() Cap { | ||||
| 	// TODO(roberts): Depends on ShapeIndexRegion existing. | ||||
| 	// c := makeS2ShapeIndexRegion(m.index).CapBound() | ||||
| 	// return CapFromCenterRadius(Point{c.Center.Mul(-1)}, c.Radius()) | ||||
| 	panic("not implemented yet") | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMinDistanceToPointTarget(p) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMinDistanceToEdgeTarget(edge) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) { | ||||
| 	m.query.opts.distanceLimit = dist.chordAngle() | ||||
| 	target := NewMinDistanceToCellTarget(cell) | ||||
| 	r := m.query.findEdge(target, m.query.opts) | ||||
| 	if r.shapeID < 0 { | ||||
| 		return dist, false | ||||
| 	} | ||||
| 	return r.distance, true | ||||
| } | ||||
| 
 | ||||
| // For target types consisting of multiple connected components (such as this one), | ||||
| // this method should return the polygons containing the antipodal reflection of | ||||
| // *any* connected component. (It is sufficient to test containment of one vertex per | ||||
| // connected component, since this allows us to also return any polygon whose | ||||
| // boundary has distance.zero() to the target.) | ||||
| func (m *MinDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool { | ||||
| 	// It is sufficient to find the set of chain starts in the target index | ||||
| 	// (i.e., one vertex per connected component of edges) that are contained by | ||||
| 	// the query index, except for one special case to handle full polygons. | ||||
| 	// | ||||
| 	// TODO(roberts): Do this by merge-joining the two ShapeIndexes. | ||||
| 	for _, shape := range m.index.shapes { | ||||
| 		numChains := shape.NumChains() | ||||
| 		// Shapes that don't have any edges require a special case (below). | ||||
| 		testedPoint := false | ||||
| 		for c := 0; c < numChains; c++ { | ||||
| 			chain := shape.Chain(c) | ||||
| 			if chain.Length == 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			testedPoint = true | ||||
| 			target := NewMinDistanceToPointTarget(shape.ChainEdge(c, 0).V0) | ||||
| 			if !target.visitContainingShapes(index, v) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 		if !testedPoint { | ||||
| 			// Special case to handle full polygons. | ||||
| 			ref := shape.ReferencePoint() | ||||
| 			if !ref.Contained { | ||||
| 				continue | ||||
| 			} | ||||
| 			target := NewMinDistanceToPointTarget(ref.Point) | ||||
| 			if !target.visitContainingShapes(index, v) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (m *MinDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool { | ||||
| 	m.query.opts.maxError = maxErr | ||||
| 	return true | ||||
| } | ||||
| func (m *MinDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 25 } | ||||
| func (m *MinDistanceToShapeIndexTarget) distance() distance          { return m.dist } | ||||
| func (m *MinDistanceToShapeIndexTarget) setIncludeInteriors(b bool) { | ||||
| 	m.query.opts.includeInteriors = b | ||||
| } | ||||
| func (m *MinDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b } | ||||
| 
 | ||||
| // TODO(roberts): Remaining methods | ||||
| // | ||||
| // func (m *MinDistanceToShapeIndexTarget) capBound() Cap { | ||||
| // CellUnionTarget | ||||
							
								
								
									
										88
									
								
								vendor/github.com/golang/geo/s2/nthderivative.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/golang/geo/s2/nthderivative.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,88 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // nthDerivativeCoder provides Nth Derivative Coding. | ||||
| //   (In signal processing disciplines, this is known as N-th Delta Coding.) | ||||
| // | ||||
| // Good for varint coding integer sequences with polynomial trends. | ||||
| // | ||||
| // Instead of coding a sequence of values directly, code its nth-order discrete | ||||
| // derivative.  Overflow in integer addition and subtraction makes this a | ||||
| // lossless transform. | ||||
| // | ||||
| //                                       constant     linear      quadratic | ||||
| //                                        trend       trend         trend | ||||
| //                                      /        \  /        \  /           \_ | ||||
| // input                               |0  0  0  0  1  2  3  4  9  16  25  36 | ||||
| // 0th derivative(identity)            |0  0  0  0  1  2  3  4  9  16  25  36 | ||||
| // 1st derivative(delta coding)        |   0  0  0  1  1  1  1  5   7   9  11 | ||||
| // 2nd derivative(linear prediction)   |      0  0  1  0  0  0  4   2   2   2 | ||||
| //                                      ------------------------------------- | ||||
| //                                      0  1  2  3  4  5  6  7  8   9  10  11 | ||||
| //                                                  n in sequence | ||||
| // | ||||
| // Higher-order codings can break even or be detrimental on other sequences. | ||||
| // | ||||
| //                                           random            oscillating | ||||
| //                                      /               \  /                  \_ | ||||
| // input                               |5  9  6  1   8  8  2 -2   4  -4   6  -6 | ||||
| // 0th derivative(identity)            |5  9  6  1   8  8  2 -2   4  -4   6  -6 | ||||
| // 1st derivative(delta coding)        |   4 -3 -5   7  0 -6 -4   6  -8  10 -12 | ||||
| // 2nd derivative(linear prediction)   |     -7 -2  12 -7 -6  2  10 -14  18 -22 | ||||
| //                                      --------------------------------------- | ||||
| //                                      0  1  2  3  4   5  6  7   8   9  10  11 | ||||
| //                                                  n in sequence | ||||
| // | ||||
| // Note that the nth derivative isn't available until sequence item n.  Earlier | ||||
| // values are coded at lower order.  For the above table, read 5 4 -7 -2 12 ... | ||||
| type nthDerivativeCoder struct { | ||||
| 	n, m   int | ||||
| 	memory [10]int32 | ||||
| } | ||||
| 
 | ||||
| // newNthDerivativeCoder returns a new coder, where n is the derivative order of the encoder (the N in NthDerivative). | ||||
| // n must be within [0,10]. | ||||
| func newNthDerivativeCoder(n int) *nthDerivativeCoder { | ||||
| 	c := &nthDerivativeCoder{n: n} | ||||
| 	if n < 0 || n > len(c.memory) { | ||||
| 		panic("unsupported n. Must be within [0,10].") | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| func (c *nthDerivativeCoder) encode(k int32) int32 { | ||||
| 	for i := 0; i < c.m; i++ { | ||||
| 		delta := k - c.memory[i] | ||||
| 		c.memory[i] = k | ||||
| 		k = delta | ||||
| 	} | ||||
| 	if c.m < c.n { | ||||
| 		c.memory[c.m] = k | ||||
| 		c.m++ | ||||
| 	} | ||||
| 	return k | ||||
| } | ||||
| 
 | ||||
| func (c *nthDerivativeCoder) decode(k int32) int32 { | ||||
| 	if c.m < c.n { | ||||
| 		c.m++ | ||||
| 	} | ||||
| 	for i := c.m - 1; i >= 0; i-- { | ||||
| 		c.memory[i] += k | ||||
| 		k = c.memory[i] | ||||
| 	} | ||||
| 	return k | ||||
| } | ||||
							
								
								
									
										252
									
								
								vendor/github.com/golang/geo/s2/paddedcell.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										252
									
								
								vendor/github.com/golang/geo/s2/paddedcell.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,252 +0,0 @@ | |||
| // Copyright 2016 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r2" | ||||
| ) | ||||
| 
 | ||||
| // PaddedCell represents a Cell whose (u,v)-range has been expanded on | ||||
| // all sides by a given amount of "padding". Unlike Cell, its methods and | ||||
| // representation are optimized for clipping edges against Cell boundaries | ||||
| // to determine which cells are intersected by a given set of edges. | ||||
| type PaddedCell struct { | ||||
| 	id          CellID | ||||
| 	padding     float64 | ||||
| 	bound       r2.Rect | ||||
| 	middle      r2.Rect // A rect in (u, v)-space that belongs to all four children. | ||||
| 	iLo, jLo    int     // Minimum (i,j)-coordinates of this cell before padding | ||||
| 	orientation int     // Hilbert curve orientation of this cell. | ||||
| 	level       int | ||||
| } | ||||
| 
 | ||||
| // PaddedCellFromCellID constructs a padded cell with the given padding. | ||||
| func PaddedCellFromCellID(id CellID, padding float64) *PaddedCell { | ||||
| 	p := &PaddedCell{ | ||||
| 		id:      id, | ||||
| 		padding: padding, | ||||
| 		middle:  r2.EmptyRect(), | ||||
| 	} | ||||
| 
 | ||||
| 	// Fast path for constructing a top-level face (the most common case). | ||||
| 	if id.isFace() { | ||||
| 		limit := padding + 1 | ||||
| 		p.bound = r2.Rect{r1.Interval{-limit, limit}, r1.Interval{-limit, limit}} | ||||
| 		p.middle = r2.Rect{r1.Interval{-padding, padding}, r1.Interval{-padding, padding}} | ||||
| 		p.orientation = id.Face() & 1 | ||||
| 		return p | ||||
| 	} | ||||
| 
 | ||||
| 	_, p.iLo, p.jLo, p.orientation = id.faceIJOrientation() | ||||
| 	p.level = id.Level() | ||||
| 	p.bound = ijLevelToBoundUV(p.iLo, p.jLo, p.level).ExpandedByMargin(padding) | ||||
| 	ijSize := sizeIJ(p.level) | ||||
| 	p.iLo &= -ijSize | ||||
| 	p.jLo &= -ijSize | ||||
| 
 | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // PaddedCellFromParentIJ constructs the child of parent with the given (i,j) index. | ||||
| // The four child cells have indices of (0,0), (0,1), (1,0), (1,1), where the i and j | ||||
| // indices correspond to increasing u- and v-values respectively. | ||||
| func PaddedCellFromParentIJ(parent *PaddedCell, i, j int) *PaddedCell { | ||||
| 	// Compute the position and orientation of the child incrementally from the | ||||
| 	// orientation of the parent. | ||||
| 	pos := ijToPos[parent.orientation][2*i+j] | ||||
| 
 | ||||
| 	p := &PaddedCell{ | ||||
| 		id:          parent.id.Children()[pos], | ||||
| 		padding:     parent.padding, | ||||
| 		bound:       parent.bound, | ||||
| 		orientation: parent.orientation ^ posToOrientation[pos], | ||||
| 		level:       parent.level + 1, | ||||
| 		middle:      r2.EmptyRect(), | ||||
| 	} | ||||
| 
 | ||||
| 	ijSize := sizeIJ(p.level) | ||||
| 	p.iLo = parent.iLo + i*ijSize | ||||
| 	p.jLo = parent.jLo + j*ijSize | ||||
| 
 | ||||
| 	// For each child, one corner of the bound is taken directly from the parent | ||||
| 	// while the diagonally opposite corner is taken from middle(). | ||||
| 	middle := parent.Middle() | ||||
| 	if i == 1 { | ||||
| 		p.bound.X.Lo = middle.X.Lo | ||||
| 	} else { | ||||
| 		p.bound.X.Hi = middle.X.Hi | ||||
| 	} | ||||
| 	if j == 1 { | ||||
| 		p.bound.Y.Lo = middle.Y.Lo | ||||
| 	} else { | ||||
| 		p.bound.Y.Hi = middle.Y.Hi | ||||
| 	} | ||||
| 
 | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // CellID returns the CellID this padded cell represents. | ||||
| func (p PaddedCell) CellID() CellID { | ||||
| 	return p.id | ||||
| } | ||||
| 
 | ||||
| // Padding returns the amount of padding on this cell. | ||||
| func (p PaddedCell) Padding() float64 { | ||||
| 	return p.padding | ||||
| } | ||||
| 
 | ||||
| // Level returns the level this cell is at. | ||||
| func (p PaddedCell) Level() int { | ||||
| 	return p.level | ||||
| } | ||||
| 
 | ||||
| // Center returns the center of this cell. | ||||
| func (p PaddedCell) Center() Point { | ||||
| 	ijSize := sizeIJ(p.level) | ||||
| 	si := uint32(2*p.iLo + ijSize) | ||||
| 	ti := uint32(2*p.jLo + ijSize) | ||||
| 	return Point{faceSiTiToXYZ(p.id.Face(), si, ti).Normalize()} | ||||
| } | ||||
| 
 | ||||
| // Middle returns the rectangle in the middle of this cell that belongs to | ||||
| // all four of its children in (u,v)-space. | ||||
| func (p *PaddedCell) Middle() r2.Rect { | ||||
| 	// We compute this field lazily because it is not needed the majority of the | ||||
| 	// time (i.e., for cells where the recursion terminates). | ||||
| 	if p.middle.IsEmpty() { | ||||
| 		ijSize := sizeIJ(p.level) | ||||
| 		u := stToUV(siTiToST(uint32(2*p.iLo + ijSize))) | ||||
| 		v := stToUV(siTiToST(uint32(2*p.jLo + ijSize))) | ||||
| 		p.middle = r2.Rect{ | ||||
| 			r1.Interval{u - p.padding, u + p.padding}, | ||||
| 			r1.Interval{v - p.padding, v + p.padding}, | ||||
| 		} | ||||
| 	} | ||||
| 	return p.middle | ||||
| } | ||||
| 
 | ||||
| // Bound returns the bounds for this cell in (u,v)-space including padding. | ||||
| func (p PaddedCell) Bound() r2.Rect { | ||||
| 	return p.bound | ||||
| } | ||||
| 
 | ||||
| // ChildIJ returns the (i,j) coordinates for the child cell at the given traversal | ||||
| // position. The traversal position corresponds to the order in which child | ||||
| // cells are visited by the Hilbert curve. | ||||
| func (p PaddedCell) ChildIJ(pos int) (i, j int) { | ||||
| 	ij := posToIJ[p.orientation][pos] | ||||
| 	return ij >> 1, ij & 1 | ||||
| } | ||||
| 
 | ||||
| // EntryVertex return the vertex where the space-filling curve enters this cell. | ||||
| func (p PaddedCell) EntryVertex() Point { | ||||
| 	// The curve enters at the (0,0) vertex unless the axis directions are | ||||
| 	// reversed, in which case it enters at the (1,1) vertex. | ||||
| 	i := p.iLo | ||||
| 	j := p.jLo | ||||
| 	if p.orientation&invertMask != 0 { | ||||
| 		ijSize := sizeIJ(p.level) | ||||
| 		i += ijSize | ||||
| 		j += ijSize | ||||
| 	} | ||||
| 	return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()} | ||||
| } | ||||
| 
 | ||||
| // ExitVertex returns the vertex where the space-filling curve exits this cell. | ||||
| func (p PaddedCell) ExitVertex() Point { | ||||
| 	// The curve exits at the (1,0) vertex unless the axes are swapped or | ||||
| 	// inverted but not both, in which case it exits at the (0,1) vertex. | ||||
| 	i := p.iLo | ||||
| 	j := p.jLo | ||||
| 	ijSize := sizeIJ(p.level) | ||||
| 	if p.orientation == 0 || p.orientation == swapMask+invertMask { | ||||
| 		i += ijSize | ||||
| 	} else { | ||||
| 		j += ijSize | ||||
| 	} | ||||
| 	return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()} | ||||
| } | ||||
| 
 | ||||
| // ShrinkToFit returns the smallest CellID that contains all descendants of this | ||||
| // padded cell whose bounds intersect the given rect. For algorithms that use | ||||
| // recursive subdivision to find the cells that intersect a particular object, this | ||||
| // method can be used to skip all of the initial subdivision steps where only | ||||
| // one child needs to be expanded. | ||||
| // | ||||
| // Note that this method is not the same as returning the smallest cell that contains | ||||
| // the intersection of this cell with rect. Because of the padding, even if one child | ||||
| // completely contains rect it is still possible that a neighboring child may also | ||||
| // intersect the given rect. | ||||
| // | ||||
| // The provided Rect must intersect the bounds of this cell. | ||||
| func (p *PaddedCell) ShrinkToFit(rect r2.Rect) CellID { | ||||
| 	// Quick rejection test: if rect contains the center of this cell along | ||||
| 	// either axis, then no further shrinking is possible. | ||||
| 	if p.level == 0 { | ||||
| 		// Fast path (most calls to this function start with a face cell). | ||||
| 		if rect.X.Contains(0) || rect.Y.Contains(0) { | ||||
| 			return p.id | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ijSize := sizeIJ(p.level) | ||||
| 	if rect.X.Contains(stToUV(siTiToST(uint32(2*p.iLo+ijSize)))) || | ||||
| 		rect.Y.Contains(stToUV(siTiToST(uint32(2*p.jLo+ijSize)))) { | ||||
| 		return p.id | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise we expand rect by the given padding on all sides and find | ||||
| 	// the range of coordinates that it spans along the i- and j-axes. We then | ||||
| 	// compute the highest bit position at which the min and max coordinates | ||||
| 	// differ. This corresponds to the first cell level at which at least two | ||||
| 	// children intersect rect. | ||||
| 
 | ||||
| 	// Increase the padding to compensate for the error in uvToST. | ||||
| 	// (The constant below is a provable upper bound on the additional error.) | ||||
| 	padded := rect.ExpandedByMargin(p.padding + 1.5*dblEpsilon) | ||||
| 	iMin, jMin := p.iLo, p.jLo // Min i- or j- coordinate spanned by padded | ||||
| 	var iXor, jXor int         // XOR of the min and max i- or j-coordinates | ||||
| 
 | ||||
| 	if iMin < stToIJ(uvToST(padded.X.Lo)) { | ||||
| 		iMin = stToIJ(uvToST(padded.X.Lo)) | ||||
| 	} | ||||
| 	if a, b := p.iLo+ijSize-1, stToIJ(uvToST(padded.X.Hi)); a <= b { | ||||
| 		iXor = iMin ^ a | ||||
| 	} else { | ||||
| 		iXor = iMin ^ b | ||||
| 	} | ||||
| 
 | ||||
| 	if jMin < stToIJ(uvToST(padded.Y.Lo)) { | ||||
| 		jMin = stToIJ(uvToST(padded.Y.Lo)) | ||||
| 	} | ||||
| 	if a, b := p.jLo+ijSize-1, stToIJ(uvToST(padded.Y.Hi)); a <= b { | ||||
| 		jXor = jMin ^ a | ||||
| 	} else { | ||||
| 		jXor = jMin ^ b | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the highest bit position where the two i- or j-endpoints differ, | ||||
| 	// and then choose the cell level that includes both of these endpoints. So | ||||
| 	// if both pairs of endpoints are equal we choose maxLevel; if they differ | ||||
| 	// only at bit 0, we choose (maxLevel - 1), and so on. | ||||
| 	levelMSB := uint64(((iXor | jXor) << 1) + 1) | ||||
| 	level := maxLevel - findMSBSetNonZero64(levelMSB) | ||||
| 	if level <= p.level { | ||||
| 		return p.id | ||||
| 	} | ||||
| 
 | ||||
| 	return cellIDFromFaceIJ(p.id.Face(), iMin, jMin).Parent(level) | ||||
| } | ||||
							
								
								
									
										258
									
								
								vendor/github.com/golang/geo/s2/point.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										258
									
								
								vendor/github.com/golang/geo/s2/point.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,258 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Point represents a point on the unit sphere as a normalized 3D vector. | ||||
| // Fields should be treated as read-only. Use one of the factory methods for creation. | ||||
| type Point struct { | ||||
| 	r3.Vector | ||||
| } | ||||
| 
 | ||||
| // sortPoints sorts the slice of Points in place. | ||||
| func sortPoints(e []Point) { | ||||
| 	sort.Sort(points(e)) | ||||
| } | ||||
| 
 | ||||
| // points implements the Sort interface for slices of Point. | ||||
| type points []Point | ||||
| 
 | ||||
| func (p points) Len() int           { return len(p) } | ||||
| func (p points) Swap(i, j int)      { p[i], p[j] = p[j], p[i] } | ||||
| func (p points) Less(i, j int) bool { return p[i].Cmp(p[j].Vector) == -1 } | ||||
| 
 | ||||
| // PointFromCoords creates a new normalized point from coordinates. | ||||
| // | ||||
| // This always returns a valid point. If the given coordinates can not be normalized | ||||
| // the origin point will be returned. | ||||
| // | ||||
| // This behavior is different from the C++ construction of a S2Point from coordinates | ||||
| // (i.e. S2Point(x, y, z)) in that in C++ they do not Normalize. | ||||
| func PointFromCoords(x, y, z float64) Point { | ||||
| 	if x == 0 && y == 0 && z == 0 { | ||||
| 		return OriginPoint() | ||||
| 	} | ||||
| 	return Point{r3.Vector{x, y, z}.Normalize()} | ||||
| } | ||||
| 
 | ||||
| // OriginPoint returns a unique "origin" on the sphere for operations that need a fixed | ||||
| // reference point. In particular, this is the "point at infinity" used for | ||||
| // point-in-polygon testing (by counting the number of edge crossings). | ||||
| // | ||||
| // It should *not* be a point that is commonly used in edge tests in order | ||||
| // to avoid triggering code to handle degenerate cases (this rules out the | ||||
| // north and south poles). It should also not be on the boundary of any | ||||
| // low-level S2Cell for the same reason. | ||||
| func OriginPoint() Point { | ||||
| 	return Point{r3.Vector{-0.0099994664350250197, 0.0025924542609324121, 0.99994664350250195}} | ||||
| } | ||||
| 
 | ||||
| // PointCross returns a Point that is orthogonal to both p and op. This is similar to | ||||
| // p.Cross(op) (the true cross product) except that it does a better job of | ||||
| // ensuring orthogonality when the Point is nearly parallel to op, it returns | ||||
| // a non-zero result even when p == op or p == -op and the result is a Point. | ||||
| // | ||||
| // It satisfies the following properties (f == PointCross): | ||||
| // | ||||
| //   (1) f(p, op) != 0 for all p, op | ||||
| //   (2) f(op,p) == -f(p,op) unless p == op or p == -op | ||||
| //   (3) f(-p,op) == -f(p,op) unless p == op or p == -op | ||||
| //   (4) f(p,-op) == -f(p,op) unless p == op or p == -op | ||||
| func (p Point) PointCross(op Point) Point { | ||||
| 	// NOTE(dnadasi): In the C++ API the equivalent method here was known as "RobustCrossProd", | ||||
| 	// but PointCross more accurately describes how this method is used. | ||||
| 	x := p.Add(op.Vector).Cross(op.Sub(p.Vector)) | ||||
| 
 | ||||
| 	// Compare exactly to the 0 vector. | ||||
| 	if x == (r3.Vector{}) { | ||||
| 		// The only result that makes sense mathematically is to return zero, but | ||||
| 		// we find it more convenient to return an arbitrary orthogonal vector. | ||||
| 		return Point{p.Ortho()} | ||||
| 	} | ||||
| 
 | ||||
| 	return Point{x} | ||||
| } | ||||
| 
 | ||||
| // OrderedCCW returns true if the edges OA, OB, and OC are encountered in that | ||||
| // order while sweeping CCW around the point O. | ||||
| // | ||||
| // You can think of this as testing whether A <= B <= C with respect to the | ||||
| // CCW ordering around O that starts at A, or equivalently, whether B is | ||||
| // contained in the range of angles (inclusive) that starts at A and extends | ||||
| // CCW to C. Properties: | ||||
| // | ||||
| //  (1) If OrderedCCW(a,b,c,o) && OrderedCCW(b,a,c,o), then a == b | ||||
| //  (2) If OrderedCCW(a,b,c,o) && OrderedCCW(a,c,b,o), then b == c | ||||
| //  (3) If OrderedCCW(a,b,c,o) && OrderedCCW(c,b,a,o), then a == b == c | ||||
| //  (4) If a == b or b == c, then OrderedCCW(a,b,c,o) is true | ||||
| //  (5) Otherwise if a == c, then OrderedCCW(a,b,c,o) is false | ||||
| func OrderedCCW(a, b, c, o Point) bool { | ||||
| 	sum := 0 | ||||
| 	if RobustSign(b, o, a) != Clockwise { | ||||
| 		sum++ | ||||
| 	} | ||||
| 	if RobustSign(c, o, b) != Clockwise { | ||||
| 		sum++ | ||||
| 	} | ||||
| 	if RobustSign(a, o, c) == CounterClockwise { | ||||
| 		sum++ | ||||
| 	} | ||||
| 	return sum >= 2 | ||||
| } | ||||
| 
 | ||||
| // Distance returns the angle between two points. | ||||
| func (p Point) Distance(b Point) s1.Angle { | ||||
| 	return p.Vector.Angle(b.Vector) | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether the two points are similar enough to be equal. | ||||
| func (p Point) ApproxEqual(other Point) bool { | ||||
| 	return p.approxEqual(other, s1.Angle(epsilon)) | ||||
| } | ||||
| 
 | ||||
| // approxEqual reports whether the two points are within the given epsilon. | ||||
| func (p Point) approxEqual(other Point, eps s1.Angle) bool { | ||||
| 	return p.Vector.Angle(other.Vector) <= eps | ||||
| } | ||||
| 
 | ||||
| // ChordAngleBetweenPoints constructs a ChordAngle corresponding to the distance | ||||
| // between the two given points. The points must be unit length. | ||||
| func ChordAngleBetweenPoints(x, y Point) s1.ChordAngle { | ||||
| 	return s1.ChordAngle(math.Min(4.0, x.Sub(y.Vector).Norm2())) | ||||
| } | ||||
| 
 | ||||
| // regularPoints generates a slice of points shaped as a regular polygon with | ||||
| // the numVertices vertices, all located on a circle of the specified angular radius | ||||
| // around the center. The radius is the actual distance from center to each vertex. | ||||
| func regularPoints(center Point, radius s1.Angle, numVertices int) []Point { | ||||
| 	return regularPointsForFrame(getFrame(center), radius, numVertices) | ||||
| } | ||||
| 
 | ||||
| // regularPointsForFrame generates a slice of points shaped as a regular polygon | ||||
| // with numVertices vertices, all on a circle of the specified angular radius around | ||||
| // the center. The radius is the actual distance from the center to each vertex. | ||||
| func regularPointsForFrame(frame matrix3x3, radius s1.Angle, numVertices int) []Point { | ||||
| 	// We construct the loop in the given frame coordinates, with the center at | ||||
| 	// (0, 0, 1). For a loop of radius r, the loop vertices have the form | ||||
| 	// (x, y, z) where x^2 + y^2 = sin(r) and z = cos(r). The distance on the | ||||
| 	// sphere (arc length) from each vertex to the center is acos(cos(r)) = r. | ||||
| 	z := math.Cos(radius.Radians()) | ||||
| 	r := math.Sin(radius.Radians()) | ||||
| 	radianStep := 2 * math.Pi / float64(numVertices) | ||||
| 	var vertices []Point | ||||
| 
 | ||||
| 	for i := 0; i < numVertices; i++ { | ||||
| 		angle := float64(i) * radianStep | ||||
| 		p := Point{r3.Vector{r * math.Cos(angle), r * math.Sin(angle), z}} | ||||
| 		vertices = append(vertices, Point{fromFrame(frame, p).Normalize()}) | ||||
| 	} | ||||
| 
 | ||||
| 	return vertices | ||||
| } | ||||
| 
 | ||||
| // CapBound returns a bounding cap for this point. | ||||
| func (p Point) CapBound() Cap { | ||||
| 	return CapFromPoint(p) | ||||
| } | ||||
| 
 | ||||
| // RectBound returns a bounding latitude-longitude rectangle from this point. | ||||
| func (p Point) RectBound() Rect { | ||||
| 	return RectFromLatLng(LatLngFromPoint(p)) | ||||
| } | ||||
| 
 | ||||
| // ContainsCell returns false as Points do not contain any other S2 types. | ||||
| func (p Point) ContainsCell(c Cell) bool { return false } | ||||
| 
 | ||||
| // IntersectsCell reports whether this Point intersects the given cell. | ||||
| func (p Point) IntersectsCell(c Cell) bool { | ||||
| 	return c.ContainsPoint(p) | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports if this Point contains the other Point. | ||||
| // (This method is named to satisfy the Region interface.) | ||||
| func (p Point) ContainsPoint(other Point) bool { | ||||
| 	return p.Contains(other) | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the Point. | ||||
| func (p Point) CellUnionBound() []CellID { | ||||
| 	return p.CapBound().CellUnionBound() | ||||
| } | ||||
| 
 | ||||
| // Contains reports if this Point contains the other Point. | ||||
| // (This method matches all other s2 types where the reflexive Contains | ||||
| // method does not contain the type's name.) | ||||
| func (p Point) Contains(other Point) bool { return p == other } | ||||
| 
 | ||||
| // Encode encodes the Point. | ||||
| func (p Point) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	p.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (p Point) encode(e *encoder) { | ||||
| 	e.writeInt8(encodingVersion) | ||||
| 	e.writeFloat64(p.X) | ||||
| 	e.writeFloat64(p.Y) | ||||
| 	e.writeFloat64(p.Z) | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the Point. | ||||
| func (p *Point) Decode(r io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(r)} | ||||
| 	p.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (p *Point) decode(d *decoder) { | ||||
| 	version := d.readInt8() | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if version != encodingVersion { | ||||
| 		d.err = fmt.Errorf("only version %d is supported", encodingVersion) | ||||
| 		return | ||||
| 	} | ||||
| 	p.X = d.readFloat64() | ||||
| 	p.Y = d.readFloat64() | ||||
| 	p.Z = d.readFloat64() | ||||
| } | ||||
| 
 | ||||
| // Rotate the given point about the given axis by the given angle. p and | ||||
| // axis must be unit length; angle has no restrictions (e.g., it can be | ||||
| // positive, negative, greater than 360 degrees, etc). | ||||
| func Rotate(p, axis Point, angle s1.Angle) Point { | ||||
| 	// Let M be the plane through P that is perpendicular to axis, and let | ||||
| 	// center be the point where M intersects axis. We construct a | ||||
| 	// right-handed orthogonal frame (dx, dy, center) such that dx is the | ||||
| 	// vector from center to P, and dy has the same length as dx. The | ||||
| 	// result can then be expressed as (cos(angle)*dx + sin(angle)*dy + center). | ||||
| 	center := axis.Mul(p.Dot(axis.Vector)) | ||||
| 	dx := p.Sub(center) | ||||
| 	dy := axis.Cross(p.Vector) | ||||
| 	// Mathematically the result is unit length, but normalization is necessary | ||||
| 	// to ensure that numerical errors don't accumulate. | ||||
| 	return Point{dx.Mul(math.Cos(angle.Radians())).Add(dy.Mul(math.Sin(angle.Radians()))).Add(center).Normalize()} | ||||
| } | ||||
							
								
								
									
										149
									
								
								vendor/github.com/golang/geo/s2/point_measures.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										149
									
								
								vendor/github.com/golang/geo/s2/point_measures.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,149 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // PointArea returns the area of triangle ABC. This method combines two different | ||||
| // algorithms to get accurate results for both large and small triangles. | ||||
| // The maximum error is about 5e-15 (about 0.25 square meters on the Earth's | ||||
| // surface), the same as GirardArea below, but unlike that method it is | ||||
| // also accurate for small triangles. Example: when the true area is 100 | ||||
| // square meters, PointArea yields an error about 1 trillion times smaller than | ||||
| // GirardArea. | ||||
| // | ||||
| // All points should be unit length, and no two points should be antipodal. | ||||
| // The area is always positive. | ||||
| func PointArea(a, b, c Point) float64 { | ||||
| 	// This method is based on l'Huilier's theorem, | ||||
| 	// | ||||
| 	//   tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2)) | ||||
| 	// | ||||
| 	// where E is the spherical excess of the triangle (i.e. its area), | ||||
| 	//       a, b, c are the side lengths, and | ||||
| 	//       s is the semiperimeter (a + b + c) / 2. | ||||
| 	// | ||||
| 	// The only significant source of error using l'Huilier's method is the | ||||
| 	// cancellation error of the terms (s-a), (s-b), (s-c). This leads to a | ||||
| 	// *relative* error of about 1e-16 * s / min(s-a, s-b, s-c). This compares | ||||
| 	// to a relative error of about 1e-15 / E using Girard's formula, where E is | ||||
| 	// the true area of the triangle. Girard's formula can be even worse than | ||||
| 	// this for very small triangles, e.g. a triangle with a true area of 1e-30 | ||||
| 	// might evaluate to 1e-5. | ||||
| 	// | ||||
| 	// So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where | ||||
| 	// dmin = min(s-a, s-b, s-c). This basically includes all triangles | ||||
| 	// except for extremely long and skinny ones. | ||||
| 	// | ||||
| 	// Since we don't know E, we would like a conservative upper bound on | ||||
| 	// the triangle area in terms of s and dmin. It's possible to show that | ||||
| 	// E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1). | ||||
| 	// Using this, it's easy to show that we should always use l'Huilier's | ||||
| 	// method if dmin >= k2 * s^5, where k2 is about 1e-2. Furthermore, | ||||
| 	// if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where | ||||
| 	// k3 is about 0.1. Since the best case error using Girard's formula | ||||
| 	// is about 1e-15, this means that we shouldn't even consider it unless | ||||
| 	// s >= 3e-4 or so. | ||||
| 	sa := float64(b.Angle(c.Vector)) | ||||
| 	sb := float64(c.Angle(a.Vector)) | ||||
| 	sc := float64(a.Angle(b.Vector)) | ||||
| 	s := 0.5 * (sa + sb + sc) | ||||
| 	if s >= 3e-4 { | ||||
| 		// Consider whether Girard's formula might be more accurate. | ||||
| 		dmin := s - math.Max(sa, math.Max(sb, sc)) | ||||
| 		if dmin < 1e-2*s*s*s*s*s { | ||||
| 			// This triangle is skinny enough to use Girard's formula. | ||||
| 			area := GirardArea(a, b, c) | ||||
| 			if dmin < s*0.1*area { | ||||
| 				return area | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Use l'Huilier's formula. | ||||
| 	return 4 * math.Atan(math.Sqrt(math.Max(0.0, math.Tan(0.5*s)*math.Tan(0.5*(s-sa))* | ||||
| 		math.Tan(0.5*(s-sb))*math.Tan(0.5*(s-sc))))) | ||||
| } | ||||
| 
 | ||||
| // GirardArea returns the area of the triangle computed using Girard's formula. | ||||
| // All points should be unit length, and no two points should be antipodal. | ||||
| // | ||||
| // This method is about twice as fast as PointArea() but has poor relative | ||||
| // accuracy for small triangles. The maximum error is about 5e-15 (about | ||||
| // 0.25 square meters on the Earth's surface) and the average error is about | ||||
| // 1e-15. These bounds apply to triangles of any size, even as the maximum | ||||
| // edge length of the triangle approaches 180 degrees. But note that for | ||||
| // such triangles, tiny perturbations of the input points can change the | ||||
| // true mathematical area dramatically. | ||||
| func GirardArea(a, b, c Point) float64 { | ||||
| 	// This is equivalent to the usual Girard's formula but is slightly more | ||||
| 	// accurate, faster to compute, and handles a == b == c without a special | ||||
| 	// case. PointCross is necessary to get good accuracy when two of | ||||
| 	// the input points are very close together. | ||||
| 	ab := a.PointCross(b) | ||||
| 	bc := b.PointCross(c) | ||||
| 	ac := a.PointCross(c) | ||||
| 
 | ||||
| 	area := float64(ab.Angle(ac.Vector) - ab.Angle(bc.Vector) + bc.Angle(ac.Vector)) | ||||
| 	if area < 0 { | ||||
| 		area = 0 | ||||
| 	} | ||||
| 	return area | ||||
| } | ||||
| 
 | ||||
| // SignedArea returns a positive value for counterclockwise triangles and a negative | ||||
| // value otherwise (similar to PointArea). | ||||
| func SignedArea(a, b, c Point) float64 { | ||||
| 	return float64(RobustSign(a, b, c)) * PointArea(a, b, c) | ||||
| } | ||||
| 
 | ||||
| // Angle returns the interior angle at the vertex B in the triangle ABC. The | ||||
| // return value is always in the range [0, pi]. All points should be | ||||
| // normalized. Ensures that Angle(a,b,c) == Angle(c,b,a) for all a,b,c. | ||||
| // | ||||
| // The angle is undefined if A or C is diametrically opposite from B, and | ||||
| // becomes numerically unstable as the length of edge AB or BC approaches | ||||
| // 180 degrees. | ||||
| func Angle(a, b, c Point) s1.Angle { | ||||
| 	// PointCross is necessary to get good accuracy when two of the input | ||||
| 	// points are very close together. | ||||
| 	return a.PointCross(b).Angle(c.PointCross(b).Vector) | ||||
| } | ||||
| 
 | ||||
| // TurnAngle returns the exterior angle at vertex B in the triangle ABC. The | ||||
| // return value is positive if ABC is counterclockwise and negative otherwise. | ||||
| // If you imagine an ant walking from A to B to C, this is the angle that the | ||||
| // ant turns at vertex B (positive = left = CCW, negative = right = CW). | ||||
| // This quantity is also known as the "geodesic curvature" at B. | ||||
| // | ||||
| // Ensures that TurnAngle(a,b,c) == -TurnAngle(c,b,a) for all distinct | ||||
| // a,b,c. The result is undefined if (a == b || b == c), but is either | ||||
| // -Pi or Pi if (a == c). All points should be normalized. | ||||
| func TurnAngle(a, b, c Point) s1.Angle { | ||||
| 	// We use PointCross to get good accuracy when two points are very | ||||
| 	// close together, and RobustSign to ensure that the sign is correct for | ||||
| 	// turns that are close to 180 degrees. | ||||
| 	angle := a.PointCross(b).Angle(b.PointCross(c).Vector) | ||||
| 
 | ||||
| 	// Don't return RobustSign * angle because it is legal to have (a == c). | ||||
| 	if RobustSign(a, b, c) == CounterClockwise { | ||||
| 		return angle | ||||
| 	} | ||||
| 	return -angle | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/github.com/golang/geo/s2/point_vector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/golang/geo/s2/point_vector.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,42 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // Shape interface enforcement | ||||
| var ( | ||||
| 	_ Shape = (*PointVector)(nil) | ||||
| ) | ||||
| 
 | ||||
| // PointVector is a Shape representing a set of Points. Each point | ||||
| // is represented as a degenerate edge with the same starting and ending | ||||
| // vertices. | ||||
| // | ||||
| // This type is useful for adding a collection of points to an ShapeIndex. | ||||
| // | ||||
| // Its methods are on *PointVector due to implementation details of ShapeIndex. | ||||
| type PointVector []Point | ||||
| 
 | ||||
| func (p *PointVector) NumEdges() int                     { return len(*p) } | ||||
| func (p *PointVector) Edge(i int) Edge                   { return Edge{(*p)[i], (*p)[i]} } | ||||
| func (p *PointVector) ReferencePoint() ReferencePoint    { return OriginReferencePoint(false) } | ||||
| func (p *PointVector) NumChains() int                    { return len(*p) } | ||||
| func (p *PointVector) Chain(i int) Chain                 { return Chain{i, 1} } | ||||
| func (p *PointVector) ChainEdge(i, j int) Edge           { return Edge{(*p)[i], (*p)[j]} } | ||||
| func (p *PointVector) ChainPosition(e int) ChainPosition { return ChainPosition{e, 0} } | ||||
| func (p *PointVector) Dimension() int                    { return 0 } | ||||
| func (p *PointVector) IsEmpty() bool                     { return defaultShapeIsEmpty(p) } | ||||
| func (p *PointVector) IsFull() bool                      { return defaultShapeIsFull(p) } | ||||
| func (p *PointVector) typeTag() typeTag                  { return typeTagPointVector } | ||||
| func (p *PointVector) privateInterface()                 {} | ||||
							
								
								
									
										319
									
								
								vendor/github.com/golang/geo/s2/pointcompression.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										319
									
								
								vendor/github.com/golang/geo/s2/pointcompression.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,319 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| // maxEncodedVertices is the maximum number of vertices, in a row, to be encoded or decoded. | ||||
| // On decode, this defends against malicious encodings that try and have us exceed RAM. | ||||
| const maxEncodedVertices = 50000000 | ||||
| 
 | ||||
| // xyzFaceSiTi represents the The XYZ and face,si,ti coordinates of a Point | ||||
| // and, if this point is equal to the center of a Cell, the level of this cell | ||||
| // (-1 otherwise). This is used for Loops and Polygons to store data in a more | ||||
| // compressed format. | ||||
| type xyzFaceSiTi struct { | ||||
| 	xyz    Point | ||||
| 	face   int | ||||
| 	si, ti uint32 | ||||
| 	level  int | ||||
| } | ||||
| 
 | ||||
| const derivativeEncodingOrder = 2 | ||||
| 
 | ||||
| func appendFace(faces []faceRun, face int) []faceRun { | ||||
| 	if len(faces) == 0 || faces[len(faces)-1].face != face { | ||||
| 		return append(faces, faceRun{face, 1}) | ||||
| 	} | ||||
| 	faces[len(faces)-1].count++ | ||||
| 	return faces | ||||
| } | ||||
| 
 | ||||
| // encodePointsCompressed uses an optimized compressed format to encode the given values. | ||||
| func encodePointsCompressed(e *encoder, vertices []xyzFaceSiTi, level int) { | ||||
| 	var faces []faceRun | ||||
| 	for _, v := range vertices { | ||||
| 		faces = appendFace(faces, v.face) | ||||
| 	} | ||||
| 	encodeFaces(e, faces) | ||||
| 
 | ||||
| 	type piQi struct { | ||||
| 		pi, qi uint32 | ||||
| 	} | ||||
| 	verticesPiQi := make([]piQi, len(vertices)) | ||||
| 	for i, v := range vertices { | ||||
| 		verticesPiQi[i] = piQi{siTitoPiQi(v.si, level), siTitoPiQi(v.ti, level)} | ||||
| 	} | ||||
| 	piCoder, qiCoder := newNthDerivativeCoder(derivativeEncodingOrder), newNthDerivativeCoder(derivativeEncodingOrder) | ||||
| 	for i, v := range verticesPiQi { | ||||
| 		f := encodePointCompressed | ||||
| 		if i == 0 { | ||||
| 			// The first point will be just the (pi, qi) coordinates | ||||
| 			// of the Point. NthDerivativeCoder will not save anything | ||||
| 			// in that case, so we encode in fixed format rather than varint | ||||
| 			// to avoid the varint overhead. | ||||
| 			f = encodeFirstPointFixedLength | ||||
| 		} | ||||
| 		f(e, v.pi, v.qi, level, piCoder, qiCoder) | ||||
| 	} | ||||
| 
 | ||||
| 	var offCenter []int | ||||
| 	for i, v := range vertices { | ||||
| 		if v.level != level { | ||||
| 			offCenter = append(offCenter, i) | ||||
| 		} | ||||
| 	} | ||||
| 	e.writeUvarint(uint64(len(offCenter))) | ||||
| 	for _, idx := range offCenter { | ||||
| 		e.writeUvarint(uint64(idx)) | ||||
| 		e.writeFloat64(vertices[idx].xyz.X) | ||||
| 		e.writeFloat64(vertices[idx].xyz.Y) | ||||
| 		e.writeFloat64(vertices[idx].xyz.Z) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func encodeFirstPointFixedLength(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) { | ||||
| 	// Do not ZigZagEncode the first point, since it cannot be negative. | ||||
| 	codedPi, codedQi := piCoder.encode(int32(pi)), qiCoder.encode(int32(qi)) | ||||
| 	// Interleave to reduce overhead from two partial bytes to one. | ||||
| 	interleaved := interleaveUint32(uint32(codedPi), uint32(codedQi)) | ||||
| 
 | ||||
| 	// Write as little endian. | ||||
| 	bytesRequired := (level + 7) / 8 * 2 | ||||
| 	for i := 0; i < bytesRequired; i++ { | ||||
| 		e.writeUint8(uint8(interleaved)) | ||||
| 		interleaved >>= 8 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // encodePointCompressed encodes points into e. | ||||
| // Given a sequence of Points assumed to be the center of level-k cells, | ||||
| // compresses it into a stream using the following method: | ||||
| // - decompose the points into (face, si, ti) tuples. | ||||
| // - run-length encode the faces, combining face number and count into a | ||||
| //     varint32. See the faceRun struct. | ||||
| // - right shift the (si, ti) to remove the part that's constant for all cells | ||||
| //     of level-k. The result is called the (pi, qi) space. | ||||
| // - 2nd derivative encode the pi and qi sequences (linear prediction) | ||||
| // - zig-zag encode all derivative values but the first, which cannot be | ||||
| //     negative | ||||
| // - interleave the zig-zag encoded values | ||||
| // - encode the first interleaved value in a fixed length encoding | ||||
| //     (varint would make this value larger) | ||||
| // - encode the remaining interleaved values as varint64s, as the | ||||
| //     derivative encoding should make the values small. | ||||
| // In addition, provides a lossless method to compress a sequence of points even | ||||
| // if some points are not the center of level-k cells. These points are stored | ||||
| // exactly, using 3 double precision values, after the above encoded string, | ||||
| // together with their index in the sequence (this leads to some redundancy - it | ||||
| // is expected that only a small fraction of the points are not cell centers). | ||||
| // | ||||
| // To encode leaf cells, this requires 8 bytes for the first vertex plus | ||||
| // an average of 3.8 bytes for each additional vertex, when computed on | ||||
| // Google's geographic repository. | ||||
| func encodePointCompressed(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) { | ||||
| 	// ZigZagEncode, as varint requires the maximum number of bytes for | ||||
| 	// negative numbers. | ||||
| 	zzPi := zigzagEncode(piCoder.encode(int32(pi))) | ||||
| 	zzQi := zigzagEncode(qiCoder.encode(int32(qi))) | ||||
| 	// Interleave to reduce overhead from two partial bytes to one. | ||||
| 	interleaved := interleaveUint32(zzPi, zzQi) | ||||
| 	e.writeUvarint(interleaved) | ||||
| } | ||||
| 
 | ||||
| type faceRun struct { | ||||
| 	face, count int | ||||
| } | ||||
| 
 | ||||
| func decodeFaceRun(d *decoder) faceRun { | ||||
| 	faceAndCount := d.readUvarint() | ||||
| 	ret := faceRun{ | ||||
| 		face:  int(faceAndCount % numFaces), | ||||
| 		count: int(faceAndCount / numFaces), | ||||
| 	} | ||||
| 	if ret.count <= 0 && d.err == nil { | ||||
| 		d.err = errors.New("non-positive count for face run") | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func decodeFaces(numVertices int, d *decoder) []faceRun { | ||||
| 	var frs []faceRun | ||||
| 	for nparsed := 0; nparsed < numVertices; { | ||||
| 		fr := decodeFaceRun(d) | ||||
| 		if d.err != nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 		frs = append(frs, fr) | ||||
| 		nparsed += fr.count | ||||
| 	} | ||||
| 	return frs | ||||
| } | ||||
| 
 | ||||
| // encodeFaceRun encodes each faceRun as a varint64 with value numFaces * count + face. | ||||
| func encodeFaceRun(e *encoder, fr faceRun) { | ||||
| 	// It isn't necessary to encode the number of faces left for the last run, | ||||
| 	// but since this would only help if there were more than 21 faces, it will | ||||
| 	// be a small overall savings, much smaller than the bound encoding. | ||||
| 	coded := numFaces*uint64(fr.count) + uint64(fr.face) | ||||
| 	e.writeUvarint(coded) | ||||
| } | ||||
| 
 | ||||
| func encodeFaces(e *encoder, frs []faceRun) { | ||||
| 	for _, fr := range frs { | ||||
| 		encodeFaceRun(e, fr) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type facesIterator struct { | ||||
| 	faces []faceRun | ||||
| 	// How often have we yet shown the current face? | ||||
| 	numCurrentFaceShown int | ||||
| 	curFace             int | ||||
| } | ||||
| 
 | ||||
| func (fi *facesIterator) next() (ok bool) { | ||||
| 	if len(fi.faces) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	fi.curFace = fi.faces[0].face | ||||
| 	fi.numCurrentFaceShown++ | ||||
| 
 | ||||
| 	// Advance fs if needed. | ||||
| 	if fi.faces[0].count <= fi.numCurrentFaceShown { | ||||
| 		fi.faces = fi.faces[1:] | ||||
| 		fi.numCurrentFaceShown = 0 | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func decodePointsCompressed(d *decoder, level int, target []Point) { | ||||
| 	faces := decodeFaces(len(target), d) | ||||
| 
 | ||||
| 	piCoder := newNthDerivativeCoder(derivativeEncodingOrder) | ||||
| 	qiCoder := newNthDerivativeCoder(derivativeEncodingOrder) | ||||
| 
 | ||||
| 	iter := facesIterator{faces: faces} | ||||
| 	for i := range target { | ||||
| 		decodeFn := decodePointCompressed | ||||
| 		if i == 0 { | ||||
| 			decodeFn = decodeFirstPointFixedLength | ||||
| 		} | ||||
| 		pi, qi := decodeFn(d, level, piCoder, qiCoder) | ||||
| 		if ok := iter.next(); !ok && d.err == nil { | ||||
| 			d.err = fmt.Errorf("ran out of faces at target %d", i) | ||||
| 			return | ||||
| 		} | ||||
| 		target[i] = Point{facePiQitoXYZ(iter.curFace, pi, qi, level)} | ||||
| 	} | ||||
| 
 | ||||
| 	numOffCenter := int(d.readUvarint()) | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if numOffCenter > len(target) { | ||||
| 		d.err = fmt.Errorf("numOffCenter = %d, should be at most len(target) = %d", numOffCenter, len(target)) | ||||
| 		return | ||||
| 	} | ||||
| 	for i := 0; i < numOffCenter; i++ { | ||||
| 		idx := int(d.readUvarint()) | ||||
| 		if d.err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if idx >= len(target) { | ||||
| 			d.err = fmt.Errorf("off center index = %d, should be < len(target) = %d", idx, len(target)) | ||||
| 			return | ||||
| 		} | ||||
| 		target[idx].X = d.readFloat64() | ||||
| 		target[idx].Y = d.readFloat64() | ||||
| 		target[idx].Z = d.readFloat64() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func decodeFirstPointFixedLength(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) { | ||||
| 	bytesToRead := (level + 7) / 8 * 2 | ||||
| 	var interleaved uint64 | ||||
| 	for i := 0; i < bytesToRead; i++ { | ||||
| 		rr := d.readUint8() | ||||
| 		interleaved |= (uint64(rr) << uint(i*8)) | ||||
| 	} | ||||
| 
 | ||||
| 	piCoded, qiCoded := deinterleaveUint32(interleaved) | ||||
| 
 | ||||
| 	return uint32(piCoder.decode(int32(piCoded))), uint32(qiCoder.decode(int32(qiCoded))) | ||||
| } | ||||
| 
 | ||||
| func zigzagEncode(x int32) uint32 { | ||||
| 	return (uint32(x) << 1) ^ uint32(x>>31) | ||||
| } | ||||
| 
 | ||||
| func zigzagDecode(x uint32) int32 { | ||||
| 	return int32((x >> 1) ^ uint32((int32(x&1)<<31)>>31)) | ||||
| } | ||||
| 
 | ||||
| func decodePointCompressed(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) { | ||||
| 	interleavedZigZagEncodedDerivPiQi := d.readUvarint() | ||||
| 	piZigzag, qiZigzag := deinterleaveUint32(interleavedZigZagEncodedDerivPiQi) | ||||
| 	return uint32(piCoder.decode(zigzagDecode(piZigzag))), uint32(qiCoder.decode(zigzagDecode(qiZigzag))) | ||||
| } | ||||
| 
 | ||||
| // We introduce a new coordinate system (pi, qi), which is (si, ti) | ||||
| // with the bits that are constant for cells of that level shifted | ||||
| // off to the right. | ||||
| // si = round(s * 2^31) | ||||
| // pi = si >> (31 - level) | ||||
| //    = floor(s * 2^level) | ||||
| // If the point has been snapped to the level, the bits that are | ||||
| // shifted off will be a 1 in the msb, then 0s after that, so the | ||||
| // fractional part discarded by the cast is (close to) 0.5. | ||||
| 
 | ||||
| // stToPiQi returns the value transformed to the PiQi coordinate space. | ||||
| func stToPiQi(s float64, level uint) uint32 { | ||||
| 	return uint32(s * float64(int(1)<<level)) | ||||
| } | ||||
| 
 | ||||
| // siTiToPiQi returns the value transformed into the PiQi coordinate spade. | ||||
| // encodeFirstPointFixedLength encodes the return value using level bits, | ||||
| // so we clamp si to the range [0, 2**level - 1] before trying to encode | ||||
| // it. This is okay because if si == maxSiTi, then it is not a cell center | ||||
| // anyway and will be encoded separately as an off-center point. | ||||
| func siTitoPiQi(siTi uint32, level int) uint32 { | ||||
| 	s := uint(siTi) | ||||
| 	const max = maxSiTi - 1 | ||||
| 	if s > max { | ||||
| 		s = max | ||||
| 	} | ||||
| 
 | ||||
| 	return uint32(s >> (maxLevel + 1 - uint(level))) | ||||
| } | ||||
| 
 | ||||
| // piQiToST returns the value transformed to ST space. | ||||
| func piQiToST(pi uint32, level int) float64 { | ||||
| 	// We want to recover the position at the center of the cell. If the point | ||||
| 	// was snapped to the center of the cell, then math.Modf(s * 2^level) == 0.5. | ||||
| 	// Inverting STtoPiQi gives: | ||||
| 	// s = (pi + 0.5) / 2^level. | ||||
| 	return (float64(pi) + 0.5) / float64(int(1)<<uint(level)) | ||||
| } | ||||
| 
 | ||||
| func facePiQitoXYZ(face int, pi, qi uint32, level int) r3.Vector { | ||||
| 	return faceUVToXYZ(face, stToUV(piQiToST(pi, level)), stToUV(piQiToST(qi, level))).Normalize() | ||||
| } | ||||
							
								
								
									
										1213
									
								
								vendor/github.com/golang/geo/s2/polygon.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1213
									
								
								vendor/github.com/golang/geo/s2/polygon.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										589
									
								
								vendor/github.com/golang/geo/s2/polyline.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										589
									
								
								vendor/github.com/golang/geo/s2/polyline.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,589 +0,0 @@ | |||
| // Copyright 2016 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Polyline represents a sequence of zero or more vertices connected by | ||||
| // straight edges (geodesics). Edges of length 0 and 180 degrees are not | ||||
| // allowed, i.e. adjacent vertices should not be identical or antipodal. | ||||
| type Polyline []Point | ||||
| 
 | ||||
| // PolylineFromLatLngs creates a new Polyline from the given LatLngs. | ||||
| func PolylineFromLatLngs(points []LatLng) *Polyline { | ||||
| 	p := make(Polyline, len(points)) | ||||
| 	for k, v := range points { | ||||
| 		p[k] = PointFromLatLng(v) | ||||
| 	} | ||||
| 	return &p | ||||
| } | ||||
| 
 | ||||
| // Reverse reverses the order of the Polyline vertices. | ||||
| func (p *Polyline) Reverse() { | ||||
| 	for i := 0; i < len(*p)/2; i++ { | ||||
| 		(*p)[i], (*p)[len(*p)-i-1] = (*p)[len(*p)-i-1], (*p)[i] | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Length returns the length of this Polyline. | ||||
| func (p *Polyline) Length() s1.Angle { | ||||
| 	var length s1.Angle | ||||
| 
 | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		length += (*p)[i-1].Distance((*p)[i]) | ||||
| 	} | ||||
| 	return length | ||||
| } | ||||
| 
 | ||||
| // Centroid returns the true centroid of the polyline multiplied by the length of the | ||||
| // polyline. The result is not unit length, so you may wish to normalize it. | ||||
| // | ||||
| // Scaling by the Polyline length makes it easy to compute the centroid | ||||
| // of several Polylines (by simply adding up their centroids). | ||||
| func (p *Polyline) Centroid() Point { | ||||
| 	var centroid Point | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		// The centroid (multiplied by length) is a vector toward the midpoint | ||||
| 		// of the edge, whose length is twice the sin of half the angle between | ||||
| 		// the two vertices. Defining theta to be this angle, we have: | ||||
| 		vSum := (*p)[i-1].Add((*p)[i].Vector)  // Length == 2*cos(theta) | ||||
| 		vDiff := (*p)[i-1].Sub((*p)[i].Vector) // Length == 2*sin(theta) | ||||
| 
 | ||||
| 		// Length == 2*sin(theta) | ||||
| 		centroid = Point{centroid.Add(vSum.Mul(math.Sqrt(vDiff.Norm2() / vSum.Norm2())))} | ||||
| 	} | ||||
| 	return centroid | ||||
| } | ||||
| 
 | ||||
| // Equal reports whether the given Polyline is exactly the same as this one. | ||||
| func (p *Polyline) Equal(b *Polyline) bool { | ||||
| 	if len(*p) != len(*b) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for i, v := range *p { | ||||
| 		if v != (*b)[i] { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether two polylines have the same number of vertices, | ||||
| // and corresponding vertex pairs are separated by no more the standard margin. | ||||
| func (p *Polyline) ApproxEqual(o *Polyline) bool { | ||||
| 	return p.approxEqual(o, s1.Angle(epsilon)) | ||||
| } | ||||
| 
 | ||||
| // approxEqual reports whether two polylines are equal within the given margin. | ||||
| func (p *Polyline) approxEqual(o *Polyline, maxError s1.Angle) bool { | ||||
| 	if len(*p) != len(*o) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for offset, val := range *p { | ||||
| 		if !val.approxEqual((*o)[offset], maxError) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // CapBound returns the bounding Cap for this Polyline. | ||||
| func (p *Polyline) CapBound() Cap { | ||||
| 	return p.RectBound().CapBound() | ||||
| } | ||||
| 
 | ||||
| // RectBound returns the bounding Rect for this Polyline. | ||||
| func (p *Polyline) RectBound() Rect { | ||||
| 	rb := NewRectBounder() | ||||
| 	for _, v := range *p { | ||||
| 		rb.AddPoint(v) | ||||
| 	} | ||||
| 	return rb.RectBound() | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether this Polyline contains the given Cell. Always returns false | ||||
| // because "containment" is not numerically well-defined except at the Polyline vertices. | ||||
| func (p *Polyline) ContainsCell(cell Cell) bool { | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether this Polyline intersects the given Cell. | ||||
| func (p *Polyline) IntersectsCell(cell Cell) bool { | ||||
| 	if len(*p) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// We only need to check whether the cell contains vertex 0 for correctness, | ||||
| 	// but these tests are cheap compared to edge crossings so we might as well | ||||
| 	// check all the vertices. | ||||
| 	for _, v := range *p { | ||||
| 		if cell.ContainsPoint(v) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	cellVertices := []Point{ | ||||
| 		cell.Vertex(0), | ||||
| 		cell.Vertex(1), | ||||
| 		cell.Vertex(2), | ||||
| 		cell.Vertex(3), | ||||
| 	} | ||||
| 
 | ||||
| 	for j := 0; j < 4; j++ { | ||||
| 		crosser := NewChainEdgeCrosser(cellVertices[j], cellVertices[(j+1)&3], (*p)[0]) | ||||
| 		for i := 1; i < len(*p); i++ { | ||||
| 			if crosser.ChainCrossingSign((*p)[i]) != DoNotCross { | ||||
| 				// There is a proper crossing, or two vertices were the same. | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint returns false since Polylines are not closed. | ||||
| func (p *Polyline) ContainsPoint(point Point) bool { | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the Polyline. | ||||
| func (p *Polyline) CellUnionBound() []CellID { | ||||
| 	return p.CapBound().CellUnionBound() | ||||
| } | ||||
| 
 | ||||
| // NumEdges returns the number of edges in this shape. | ||||
| func (p *Polyline) NumEdges() int { | ||||
| 	if len(*p) == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return len(*p) - 1 | ||||
| } | ||||
| 
 | ||||
| // Edge returns endpoints for the given edge index. | ||||
| func (p *Polyline) Edge(i int) Edge { | ||||
| 	return Edge{(*p)[i], (*p)[i+1]} | ||||
| } | ||||
| 
 | ||||
| // ReferencePoint returns the default reference point with negative containment because Polylines are not closed. | ||||
| func (p *Polyline) ReferencePoint() ReferencePoint { | ||||
| 	return OriginReferencePoint(false) | ||||
| } | ||||
| 
 | ||||
| // NumChains reports the number of contiguous edge chains in this Polyline. | ||||
| func (p *Polyline) NumChains() int { | ||||
| 	return minInt(1, p.NumEdges()) | ||||
| } | ||||
| 
 | ||||
| // Chain returns the i-th edge Chain in the Shape. | ||||
| func (p *Polyline) Chain(chainID int) Chain { | ||||
| 	return Chain{0, p.NumEdges()} | ||||
| } | ||||
| 
 | ||||
| // ChainEdge returns the j-th edge of the i-th edge Chain. | ||||
| func (p *Polyline) ChainEdge(chainID, offset int) Edge { | ||||
| 	return Edge{(*p)[offset], (*p)[offset+1]} | ||||
| } | ||||
| 
 | ||||
| // ChainPosition returns a pair (i, j) such that edgeID is the j-th edge | ||||
| func (p *Polyline) ChainPosition(edgeID int) ChainPosition { | ||||
| 	return ChainPosition{0, edgeID} | ||||
| } | ||||
| 
 | ||||
| // Dimension returns the dimension of the geometry represented by this Polyline. | ||||
| func (p *Polyline) Dimension() int { return 1 } | ||||
| 
 | ||||
| // IsEmpty reports whether this shape contains no points. | ||||
| func (p *Polyline) IsEmpty() bool { return defaultShapeIsEmpty(p) } | ||||
| 
 | ||||
| // IsFull reports whether this shape contains all points on the sphere. | ||||
| func (p *Polyline) IsFull() bool { return defaultShapeIsFull(p) } | ||||
| 
 | ||||
| func (p *Polyline) typeTag() typeTag { return typeTagPolyline } | ||||
| 
 | ||||
| func (p *Polyline) privateInterface() {} | ||||
| 
 | ||||
| // findEndVertex reports the maximal end index such that the line segment between | ||||
| // the start index and this one such that the line segment between these two | ||||
| // vertices passes within the given tolerance of all interior vertices, in order. | ||||
| func findEndVertex(p Polyline, tolerance s1.Angle, index int) int { | ||||
| 	// The basic idea is to keep track of the "pie wedge" of angles | ||||
| 	// from the starting vertex such that a ray from the starting | ||||
| 	// vertex at that angle will pass through the discs of radius | ||||
| 	// tolerance centered around all vertices processed so far. | ||||
| 	// | ||||
| 	// First we define a coordinate frame for the tangent and normal | ||||
| 	// spaces at the starting vertex. Essentially this means picking | ||||
| 	// three orthonormal vectors X,Y,Z such that X and Y span the | ||||
| 	// tangent plane at the starting vertex, and Z is up. We use | ||||
| 	// the coordinate frame to define a mapping from 3D direction | ||||
| 	// vectors to a one-dimensional ray angle in the range (-π, | ||||
| 	// π]. The angle of a direction vector is computed by | ||||
| 	// transforming it into the X,Y,Z basis, and then calculating | ||||
| 	// atan2(y,x). This mapping allows us to represent a wedge of | ||||
| 	// angles as a 1D interval. Since the interval wraps around, we | ||||
| 	// represent it as an Interval, i.e. an interval on the unit | ||||
| 	// circle. | ||||
| 	origin := p[index] | ||||
| 	frame := getFrame(origin) | ||||
| 
 | ||||
| 	// As we go along, we keep track of the current wedge of angles | ||||
| 	// and the distance to the last vertex (which must be | ||||
| 	// non-decreasing). | ||||
| 	currentWedge := s1.FullInterval() | ||||
| 	var lastDistance s1.Angle | ||||
| 
 | ||||
| 	for index++; index < len(p); index++ { | ||||
| 		candidate := p[index] | ||||
| 		distance := origin.Distance(candidate) | ||||
| 
 | ||||
| 		// We don't allow simplification to create edges longer than | ||||
| 		// 90 degrees, to avoid numeric instability as lengths | ||||
| 		// approach 180 degrees. We do need to allow for original | ||||
| 		// edges longer than 90 degrees, though. | ||||
| 		if distance > math.Pi/2 && lastDistance > 0 { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// Vertices must be in increasing order along the ray, except | ||||
| 		// for the initial disc around the origin. | ||||
| 		if distance < lastDistance && lastDistance > tolerance { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		lastDistance = distance | ||||
| 
 | ||||
| 		// Points that are within the tolerance distance of the origin | ||||
| 		// do not constrain the ray direction, so we can ignore them. | ||||
| 		if distance <= tolerance { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// If the current wedge of angles does not contain the angle | ||||
| 		// to this vertex, then stop right now. Note that the wedge | ||||
| 		// of possible ray angles is not necessarily empty yet, but we | ||||
| 		// can't continue unless we are willing to backtrack to the | ||||
| 		// last vertex that was contained within the wedge (since we | ||||
| 		// don't create new vertices). This would be more complicated | ||||
| 		// and also make the worst-case running time more than linear. | ||||
| 		direction := toFrame(frame, candidate) | ||||
| 		center := math.Atan2(direction.Y, direction.X) | ||||
| 		if !currentWedge.Contains(center) { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// To determine how this vertex constrains the possible ray | ||||
| 		// angles, consider the triangle ABC where A is the origin, B | ||||
| 		// is the candidate vertex, and C is one of the two tangent | ||||
| 		// points between A and the spherical cap of radius | ||||
| 		// tolerance centered at B. Then from the spherical law of | ||||
| 		// sines, sin(a)/sin(A) = sin(c)/sin(C), where a and c are | ||||
| 		// the lengths of the edges opposite A and C. In our case C | ||||
| 		// is a 90 degree angle, therefore A = asin(sin(a) / sin(c)). | ||||
| 		// Angle A is the half-angle of the allowable wedge. | ||||
| 		halfAngle := math.Asin(math.Sin(tolerance.Radians()) / math.Sin(distance.Radians())) | ||||
| 		target := s1.IntervalFromPointPair(center, center).Expanded(halfAngle) | ||||
| 		currentWedge = currentWedge.Intersection(target) | ||||
| 	} | ||||
| 
 | ||||
| 	// We break out of the loop when we reach a vertex index that | ||||
| 	// can't be included in the line segment, so back up by one | ||||
| 	// vertex. | ||||
| 	return index - 1 | ||||
| } | ||||
| 
 | ||||
| // SubsampleVertices returns a subsequence of vertex indices such that the | ||||
| // polyline connecting these vertices is never further than the given tolerance from | ||||
| // the original polyline. Provided the first and last vertices are distinct, | ||||
| // they are always preserved; if they are not, the subsequence may contain | ||||
| // only a single index. | ||||
| // | ||||
| // Some useful properties of the algorithm: | ||||
| // | ||||
| //  - It runs in linear time. | ||||
| // | ||||
| //  - The output always represents a valid polyline. In particular, adjacent | ||||
| //    output vertices are never identical or antipodal. | ||||
| // | ||||
| //  - The method is not optimal, but it tends to produce 2-3% fewer | ||||
| //    vertices than the Douglas-Peucker algorithm with the same tolerance. | ||||
| // | ||||
| //  - The output is parametrically equivalent to the original polyline to | ||||
| //    within the given tolerance. For example, if a polyline backtracks on | ||||
| //    itself and then proceeds onwards, the backtracking will be preserved | ||||
| //    (to within the given tolerance). This is different than the | ||||
| //    Douglas-Peucker algorithm which only guarantees geometric equivalence. | ||||
| func (p *Polyline) SubsampleVertices(tolerance s1.Angle) []int { | ||||
| 	var result []int | ||||
| 
 | ||||
| 	if len(*p) < 1 { | ||||
| 		return result | ||||
| 	} | ||||
| 
 | ||||
| 	result = append(result, 0) | ||||
| 	clampedTolerance := s1.Angle(math.Max(tolerance.Radians(), 0)) | ||||
| 
 | ||||
| 	for index := 0; index+1 < len(*p); { | ||||
| 		nextIndex := findEndVertex(*p, clampedTolerance, index) | ||||
| 		// Don't create duplicate adjacent vertices. | ||||
| 		if (*p)[nextIndex] != (*p)[index] { | ||||
| 			result = append(result, nextIndex) | ||||
| 		} | ||||
| 		index = nextIndex | ||||
| 	} | ||||
| 
 | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the Polyline. | ||||
| func (p Polyline) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	p.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (p Polyline) encode(e *encoder) { | ||||
| 	e.writeInt8(encodingVersion) | ||||
| 	e.writeUint32(uint32(len(p))) | ||||
| 	for _, v := range p { | ||||
| 		e.writeFloat64(v.X) | ||||
| 		e.writeFloat64(v.Y) | ||||
| 		e.writeFloat64(v.Z) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Decode decodes the polyline. | ||||
| func (p *Polyline) Decode(r io.Reader) error { | ||||
| 	d := decoder{r: asByteReader(r)} | ||||
| 	p.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (p *Polyline) decode(d decoder) { | ||||
| 	version := d.readInt8() | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if int(version) != int(encodingVersion) { | ||||
| 		d.err = fmt.Errorf("can't decode version %d; my version: %d", version, encodingVersion) | ||||
| 		return | ||||
| 	} | ||||
| 	nvertices := d.readUint32() | ||||
| 	if d.err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if nvertices > maxEncodedVertices { | ||||
| 		d.err = fmt.Errorf("too many vertices (%d; max is %d)", nvertices, maxEncodedVertices) | ||||
| 		return | ||||
| 	} | ||||
| 	*p = make([]Point, nvertices) | ||||
| 	for i := range *p { | ||||
| 		(*p)[i].X = d.readFloat64() | ||||
| 		(*p)[i].Y = d.readFloat64() | ||||
| 		(*p)[i].Z = d.readFloat64() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Project returns a point on the polyline that is closest to the given point, | ||||
| // and the index of the next vertex after the projected point. The | ||||
| // value of that index is always in the range [1, len(polyline)]. | ||||
| // The polyline must not be empty. | ||||
| func (p *Polyline) Project(point Point) (Point, int) { | ||||
| 	if len(*p) == 1 { | ||||
| 		// If there is only one vertex, it is always closest to any given point. | ||||
| 		return (*p)[0], 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// Initial value larger than any possible distance on the unit sphere. | ||||
| 	minDist := 10 * s1.Radian | ||||
| 	minIndex := -1 | ||||
| 
 | ||||
| 	// Find the line segment in the polyline that is closest to the point given. | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		if dist := DistanceFromSegment(point, (*p)[i-1], (*p)[i]); dist < minDist { | ||||
| 			minDist = dist | ||||
| 			minIndex = i | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the point on the segment found that is closest to the point given. | ||||
| 	closest := Project(point, (*p)[minIndex-1], (*p)[minIndex]) | ||||
| 	if closest == (*p)[minIndex] { | ||||
| 		minIndex++ | ||||
| 	} | ||||
| 
 | ||||
| 	return closest, minIndex | ||||
| } | ||||
| 
 | ||||
| // IsOnRight reports whether the point given is on the right hand side of the | ||||
| // polyline, using a naive definition of "right-hand-sideness" where the point | ||||
| // is on the RHS of the polyline iff the point is on the RHS of the line segment | ||||
| // in the polyline which it is closest to. | ||||
| // The polyline must have at least 2 vertices. | ||||
| func (p *Polyline) IsOnRight(point Point) bool { | ||||
| 	// If the closest point C is an interior vertex of the polyline, let B and D | ||||
| 	// be the previous and next vertices. The given point P is on the right of | ||||
| 	// the polyline (locally) if B, P, D are ordered CCW around vertex C. | ||||
| 	closest, next := p.Project(point) | ||||
| 	if closest == (*p)[next-1] && next > 1 && next < len(*p) { | ||||
| 		if point == (*p)[next-1] { | ||||
| 			// Polyline vertices are not on the RHS. | ||||
| 			return false | ||||
| 		} | ||||
| 		return OrderedCCW((*p)[next-2], point, (*p)[next], (*p)[next-1]) | ||||
| 	} | ||||
| 	// Otherwise, the closest point C is incident to exactly one polyline edge. | ||||
| 	// We test the point P against that edge. | ||||
| 	if next == len(*p) { | ||||
| 		next-- | ||||
| 	} | ||||
| 	return Sign(point, (*p)[next], (*p)[next-1]) | ||||
| } | ||||
| 
 | ||||
| // Validate checks whether this is a valid polyline or not. | ||||
| func (p *Polyline) Validate() error { | ||||
| 	// All vertices must be unit length. | ||||
| 	for i, pt := range *p { | ||||
| 		if !pt.IsUnit() { | ||||
| 			return fmt.Errorf("vertex %d is not unit length", i) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Adjacent vertices must not be identical or antipodal. | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		prev, cur := (*p)[i-1], (*p)[i] | ||||
| 		if prev == cur { | ||||
| 			return fmt.Errorf("vertices %d and %d are identical", i-1, i) | ||||
| 		} | ||||
| 		if prev == (Point{cur.Mul(-1)}) { | ||||
| 			return fmt.Errorf("vertices %d and %d are antipodal", i-1, i) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Intersects reports whether this polyline intersects the given polyline. If | ||||
| // the polylines share a vertex they are considered to be intersecting. When a | ||||
| // polyline endpoint is the only intersection with the other polyline, the | ||||
| // function may return true or false arbitrarily. | ||||
| // | ||||
| // The running time is quadratic in the number of vertices. | ||||
| func (p *Polyline) Intersects(o *Polyline) bool { | ||||
| 	if len(*p) == 0 || len(*o) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	if !p.RectBound().Intersects(o.RectBound()) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(roberts): Use ShapeIndex here. | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		crosser := NewChainEdgeCrosser((*p)[i-1], (*p)[i], (*o)[0]) | ||||
| 		for j := 1; j < len(*o); j++ { | ||||
| 			if crosser.ChainCrossingSign((*o)[j]) != DoNotCross { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Interpolate returns the point whose distance from vertex 0 along the polyline is | ||||
| // the given fraction of the polyline's total length, and the index of | ||||
| // the next vertex after the interpolated point P. Fractions less than zero | ||||
| // or greater than one are clamped. The return value is unit length. The cost of | ||||
| // this function is currently linear in the number of vertices. | ||||
| // | ||||
| // This method allows the caller to easily construct a given suffix of the | ||||
| // polyline by concatenating P with the polyline vertices starting at that next | ||||
| // vertex. Note that P is guaranteed to be different than the point at the next | ||||
| // vertex, so this will never result in a duplicate vertex. | ||||
| // | ||||
| // The polyline must not be empty. Note that if fraction >= 1.0, then the next | ||||
| // vertex will be set to len(p) (indicating that no vertices from the polyline | ||||
| // need to be appended). The value of the next vertex is always between 1 and | ||||
| // len(p). | ||||
| // | ||||
| // This method can also be used to construct a prefix of the polyline, by | ||||
| // taking the polyline vertices up to next vertex-1 and appending the | ||||
| // returned point P if it is different from the last vertex (since in this | ||||
| // case there is no guarantee of distinctness). | ||||
| func (p *Polyline) Interpolate(fraction float64) (Point, int) { | ||||
| 	// We intentionally let the (fraction >= 1) case fall through, since | ||||
| 	// we need to handle it in the loop below in any case because of | ||||
| 	// possible roundoff errors. | ||||
| 	if fraction <= 0 { | ||||
| 		return (*p)[0], 1 | ||||
| 	} | ||||
| 	target := s1.Angle(fraction) * p.Length() | ||||
| 
 | ||||
| 	for i := 1; i < len(*p); i++ { | ||||
| 		length := (*p)[i-1].Distance((*p)[i]) | ||||
| 		if target < length { | ||||
| 			// This interpolates with respect to arc length rather than | ||||
| 			// straight-line distance, and produces a unit-length result. | ||||
| 			result := InterpolateAtDistance(target, (*p)[i-1], (*p)[i]) | ||||
| 
 | ||||
| 			// It is possible that (result == vertex(i)) due to rounding errors. | ||||
| 			if result == (*p)[i] { | ||||
| 				return result, i + 1 | ||||
| 			} | ||||
| 			return result, i | ||||
| 		} | ||||
| 		target -= length | ||||
| 	} | ||||
| 
 | ||||
| 	return (*p)[len(*p)-1], len(*p) | ||||
| } | ||||
| 
 | ||||
| // Uninterpolate is the inverse operation of Interpolate. Given a point on the | ||||
| // polyline, it returns the ratio of the distance to the point from the | ||||
| // beginning of the polyline over the length of the polyline. The return | ||||
| // value is always betwen 0 and 1 inclusive. | ||||
| // | ||||
| // The polyline should not be empty.  If it has fewer than 2 vertices, the | ||||
| // return value is zero. | ||||
| func (p *Polyline) Uninterpolate(point Point, nextVertex int) float64 { | ||||
| 	if len(*p) < 2 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	var sum s1.Angle | ||||
| 	for i := 1; i < nextVertex; i++ { | ||||
| 		sum += (*p)[i-1].Distance((*p)[i]) | ||||
| 	} | ||||
| 	lengthToPoint := sum + (*p)[nextVertex-1].Distance(point) | ||||
| 	for i := nextVertex; i < len(*p); i++ { | ||||
| 		sum += (*p)[i-1].Distance((*p)[i]) | ||||
| 	} | ||||
| 	// The ratio can be greater than 1.0 due to rounding errors or because the | ||||
| 	// point is not exactly on the polyline. | ||||
| 	return minFloat64(1.0, float64(lengthToPoint/sum)) | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Differences from C++. | ||||
| // NearlyCoversPolyline | ||||
| // InitToSnapped | ||||
| // InitToSimplified | ||||
| // SnapLevel | ||||
| // encode/decode compressed | ||||
							
								
								
									
										53
									
								
								vendor/github.com/golang/geo/s2/polyline_measures.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/golang/geo/s2/polyline_measures.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,53 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file defines various measures for polylines on the sphere. These are | ||||
| // low-level methods that work directly with arrays of Points. They are used to | ||||
| // implement the methods in various other measures files. | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // polylineLength returns the length of the given Polyline. | ||||
| // It returns 0 for polylines with fewer than two vertices. | ||||
| func polylineLength(p []Point) s1.Angle { | ||||
| 	var length s1.Angle | ||||
| 
 | ||||
| 	for i := 1; i < len(p); i++ { | ||||
| 		length += p[i-1].Distance(p[i]) | ||||
| 	} | ||||
| 	return length | ||||
| } | ||||
| 
 | ||||
| // polylineCentroid returns the true centroid of the polyline multiplied by the | ||||
| // length of the polyline. The result is not unit length, so you may wish to | ||||
| // normalize it. | ||||
| // | ||||
| // Scaling by the Polyline length makes it easy to compute the centroid | ||||
| // of several Polylines (by simply adding up their centroids). | ||||
| // | ||||
| // Note that for degenerate Polylines (e.g., AA) this returns Point(0, 0, 0). | ||||
| // (This answer is correct; the result of this function is a line integral over | ||||
| // the polyline, whose value is always zero if the polyline is degenerate.) | ||||
| func polylineCentroid(p []Point) Point { | ||||
| 	var centroid r3.Vector | ||||
| 	for i := 1; i < len(p); i++ { | ||||
| 		centroid = centroid.Add(EdgeTrueCentroid(p[i-1], p[i]).Vector) | ||||
| 	} | ||||
| 	return Point{centroid} | ||||
| } | ||||
							
								
								
									
										701
									
								
								vendor/github.com/golang/geo/s2/predicates.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										701
									
								
								vendor/github.com/golang/geo/s2/predicates.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,701 +0,0 @@ | |||
| // Copyright 2016 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // This file contains various predicates that are guaranteed to produce | ||||
| // correct, consistent results. They are also relatively efficient. This is | ||||
| // achieved by computing conservative error bounds and falling back to high | ||||
| // precision or even exact arithmetic when the result is uncertain. Such | ||||
| // predicates are useful in implementing robust algorithms. | ||||
| // | ||||
| // See also EdgeCrosser, which implements various exact | ||||
| // edge-crossing predicates more efficiently than can be done here. | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// If any other machine architectures need to be suppported, these next three | ||||
| 	// values will need to be updated. | ||||
| 
 | ||||
| 	// epsilon is a small number that represents a reasonable level of noise between two | ||||
| 	// values that can be considered to be equal. | ||||
| 	epsilon = 1e-15 | ||||
| 	// dblEpsilon is a smaller number for values that require more precision. | ||||
| 	// This is the C++ DBL_EPSILON equivalent. | ||||
| 	dblEpsilon = 2.220446049250313e-16 | ||||
| 	// dblError is the C++ value for S2 rounding_epsilon(). | ||||
| 	dblError = 1.110223024625156e-16 | ||||
| 
 | ||||
| 	// maxDeterminantError is the maximum error in computing (AxB).C where all vectors | ||||
| 	// are unit length. Using standard inequalities, it can be shown that | ||||
| 	// | ||||
| 	//  fl(AxB) = AxB + D where |D| <= (|AxB| + (2/sqrt(3))*|A|*|B|) * e | ||||
| 	// | ||||
| 	// where "fl()" denotes a calculation done in floating-point arithmetic, | ||||
| 	// |x| denotes either absolute value or the L2-norm as appropriate, and | ||||
| 	// e is a reasonably small value near the noise level of floating point | ||||
| 	// number accuracy. Similarly, | ||||
| 	// | ||||
| 	//  fl(B.C) = B.C + d where |d| <= (|B.C| + 2*|B|*|C|) * e . | ||||
| 	// | ||||
| 	// Applying these bounds to the unit-length vectors A,B,C and neglecting | ||||
| 	// relative error (which does not affect the sign of the result), we get | ||||
| 	// | ||||
| 	//  fl((AxB).C) = (AxB).C + d where |d| <= (3 + 2/sqrt(3)) * e | ||||
| 	maxDeterminantError = 1.8274 * dblEpsilon | ||||
| 
 | ||||
| 	// detErrorMultiplier is the factor to scale the magnitudes by when checking | ||||
| 	// for the sign of set of points with certainty. Using a similar technique to | ||||
| 	// the one used for maxDeterminantError, the error is at most: | ||||
| 	// | ||||
| 	//   |d| <= (3 + 6/sqrt(3)) * |A-C| * |B-C| * e | ||||
| 	// | ||||
| 	// If the determinant magnitude is larger than this value then we know | ||||
| 	// its sign with certainty. | ||||
| 	detErrorMultiplier = 3.2321 * dblEpsilon | ||||
| ) | ||||
| 
 | ||||
| // Direction is an indication of the ordering of a set of points. | ||||
| type Direction int | ||||
| 
 | ||||
| // These are the three options for the direction of a set of points. | ||||
| const ( | ||||
| 	Clockwise        Direction = -1 | ||||
| 	Indeterminate    Direction = 0 | ||||
| 	CounterClockwise Direction = 1 | ||||
| ) | ||||
| 
 | ||||
| // newBigFloat constructs a new big.Float with maximum precision. | ||||
| func newBigFloat() *big.Float { return new(big.Float).SetPrec(big.MaxPrec) } | ||||
| 
 | ||||
| // Sign returns true if the points A, B, C are strictly counterclockwise, | ||||
| // and returns false if the points are clockwise or collinear (i.e. if they are all | ||||
| // contained on some great circle). | ||||
| // | ||||
| // Due to numerical errors, situations may arise that are mathematically | ||||
| // impossible, e.g. ABC may be considered strictly CCW while BCA is not. | ||||
| // However, the implementation guarantees the following: | ||||
| // | ||||
| // If Sign(a,b,c), then !Sign(c,b,a) for all a,b,c. | ||||
| func Sign(a, b, c Point) bool { | ||||
| 	// NOTE(dnadasi): In the C++ API the equivalent method here was known as "SimpleSign". | ||||
| 
 | ||||
| 	// We compute the signed volume of the parallelepiped ABC. The usual | ||||
| 	// formula for this is (A ⨯ B) · C, but we compute it here using (C ⨯ A) · B | ||||
| 	// in order to ensure that ABC and CBA are not both CCW. This follows | ||||
| 	// from the following identities (which are true numerically, not just | ||||
| 	// mathematically): | ||||
| 	// | ||||
| 	//     (1) x ⨯ y == -(y ⨯ x) | ||||
| 	//     (2) -x · y == -(x · y) | ||||
| 	return c.Cross(a.Vector).Dot(b.Vector) > 0 | ||||
| } | ||||
| 
 | ||||
| // RobustSign returns a Direction representing the ordering of the points. | ||||
| // CounterClockwise is returned if the points are in counter-clockwise order, | ||||
| // Clockwise for clockwise, and Indeterminate if any two points are the same (collinear), | ||||
| // or the sign could not completely be determined. | ||||
| // | ||||
| // This function has additional logic to make sure that the above properties hold even | ||||
| // when the three points are coplanar, and to deal with the limitations of | ||||
| // floating-point arithmetic. | ||||
| // | ||||
| // RobustSign satisfies the following conditions: | ||||
| // | ||||
| //  (1) RobustSign(a,b,c) == Indeterminate if and only if a == b, b == c, or c == a | ||||
| //  (2) RobustSign(b,c,a) == RobustSign(a,b,c) for all a,b,c | ||||
| //  (3) RobustSign(c,b,a) == -RobustSign(a,b,c) for all a,b,c | ||||
| // | ||||
| // In other words: | ||||
| // | ||||
| //  (1) The result is Indeterminate if and only if two points are the same. | ||||
| //  (2) Rotating the order of the arguments does not affect the result. | ||||
| //  (3) Exchanging any two arguments inverts the result. | ||||
| // | ||||
| // On the other hand, note that it is not true in general that | ||||
| // RobustSign(-a,b,c) == -RobustSign(a,b,c), or any similar identities | ||||
| // involving antipodal points. | ||||
| func RobustSign(a, b, c Point) Direction { | ||||
| 	sign := triageSign(a, b, c) | ||||
| 	if sign == Indeterminate { | ||||
| 		sign = expensiveSign(a, b, c) | ||||
| 	} | ||||
| 	return sign | ||||
| } | ||||
| 
 | ||||
| // stableSign reports the direction sign of the points in a numerically stable way. | ||||
| // Unlike triageSign, this method can usually compute the correct determinant sign | ||||
| // even when all three points are as collinear as possible. For example if three | ||||
| // points are spaced 1km apart along a random line on the Earth's surface using | ||||
| // the nearest representable points, there is only a 0.4% chance that this method | ||||
| // will not be able to find the determinant sign. The probability of failure | ||||
| // decreases as the points get closer together; if the collinear points are 1 meter | ||||
| // apart, the failure rate drops to 0.0004%. | ||||
| // | ||||
| // This method could be extended to also handle nearly-antipodal points, but antipodal | ||||
| // points are rare in practice so it seems better to simply fall back to | ||||
| // exact arithmetic in that case. | ||||
| func stableSign(a, b, c Point) Direction { | ||||
| 	ab := b.Sub(a.Vector) | ||||
| 	ab2 := ab.Norm2() | ||||
| 	bc := c.Sub(b.Vector) | ||||
| 	bc2 := bc.Norm2() | ||||
| 	ca := a.Sub(c.Vector) | ||||
| 	ca2 := ca.Norm2() | ||||
| 
 | ||||
| 	// Now compute the determinant ((A-C)x(B-C)).C, where the vertices have been | ||||
| 	// cyclically permuted if necessary so that AB is the longest edge. (This | ||||
| 	// minimizes the magnitude of cross product.)  At the same time we also | ||||
| 	// compute the maximum error in the determinant. | ||||
| 
 | ||||
| 	// The two shortest edges, pointing away from their common point. | ||||
| 	var e1, e2, op r3.Vector | ||||
| 	if ab2 >= bc2 && ab2 >= ca2 { | ||||
| 		// AB is the longest edge. | ||||
| 		e1, e2, op = ca, bc, c.Vector | ||||
| 	} else if bc2 >= ca2 { | ||||
| 		// BC is the longest edge. | ||||
| 		e1, e2, op = ab, ca, a.Vector | ||||
| 	} else { | ||||
| 		// CA is the longest edge. | ||||
| 		e1, e2, op = bc, ab, b.Vector | ||||
| 	} | ||||
| 
 | ||||
| 	det := -e1.Cross(e2).Dot(op) | ||||
| 	maxErr := detErrorMultiplier * math.Sqrt(e1.Norm2()*e2.Norm2()) | ||||
| 
 | ||||
| 	// If the determinant isn't zero, within maxErr, we know definitively the point ordering. | ||||
| 	if det > maxErr { | ||||
| 		return CounterClockwise | ||||
| 	} | ||||
| 	if det < -maxErr { | ||||
| 		return Clockwise | ||||
| 	} | ||||
| 	return Indeterminate | ||||
| } | ||||
| 
 | ||||
| // triageSign returns the direction sign of the points. It returns Indeterminate if two | ||||
| // points are identical or the result is uncertain. Uncertain cases can be resolved, if | ||||
| // desired, by calling expensiveSign. | ||||
| // | ||||
| // The purpose of this method is to allow additional cheap tests to be done without | ||||
| // calling expensiveSign. | ||||
| func triageSign(a, b, c Point) Direction { | ||||
| 	det := a.Cross(b.Vector).Dot(c.Vector) | ||||
| 	if det > maxDeterminantError { | ||||
| 		return CounterClockwise | ||||
| 	} | ||||
| 	if det < -maxDeterminantError { | ||||
| 		return Clockwise | ||||
| 	} | ||||
| 	return Indeterminate | ||||
| } | ||||
| 
 | ||||
| // expensiveSign reports the direction sign of the points. It returns Indeterminate | ||||
| // if two of the input points are the same. It uses multiple-precision arithmetic | ||||
| // to ensure that its results are always self-consistent. | ||||
| func expensiveSign(a, b, c Point) Direction { | ||||
| 	// Return Indeterminate if and only if two points are the same. | ||||
| 	// This ensures RobustSign(a,b,c) == Indeterminate if and only if a == b, b == c, or c == a. | ||||
| 	// ie. Property 1 of RobustSign. | ||||
| 	if a == b || b == c || c == a { | ||||
| 		return Indeterminate | ||||
| 	} | ||||
| 
 | ||||
| 	// Next we try recomputing the determinant still using floating-point | ||||
| 	// arithmetic but in a more precise way. This is more expensive than the | ||||
| 	// simple calculation done by triageSign, but it is still *much* cheaper | ||||
| 	// than using arbitrary-precision arithmetic. This optimization is able to | ||||
| 	// compute the correct determinant sign in virtually all cases except when | ||||
| 	// the three points are truly collinear (e.g., three points on the equator). | ||||
| 	detSign := stableSign(a, b, c) | ||||
| 	if detSign != Indeterminate { | ||||
| 		return detSign | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise fall back to exact arithmetic and symbolic permutations. | ||||
| 	return exactSign(a, b, c, true) | ||||
| } | ||||
| 
 | ||||
| // exactSign reports the direction sign of the points computed using high-precision | ||||
| // arithmetic and/or symbolic perturbations. | ||||
| func exactSign(a, b, c Point, perturb bool) Direction { | ||||
| 	// Sort the three points in lexicographic order, keeping track of the sign | ||||
| 	// of the permutation. (Each exchange inverts the sign of the determinant.) | ||||
| 	permSign := CounterClockwise | ||||
| 	pa := &a | ||||
| 	pb := &b | ||||
| 	pc := &c | ||||
| 	if pa.Cmp(pb.Vector) > 0 { | ||||
| 		pa, pb = pb, pa | ||||
| 		permSign = -permSign | ||||
| 	} | ||||
| 	if pb.Cmp(pc.Vector) > 0 { | ||||
| 		pb, pc = pc, pb | ||||
| 		permSign = -permSign | ||||
| 	} | ||||
| 	if pa.Cmp(pb.Vector) > 0 { | ||||
| 		pa, pb = pb, pa | ||||
| 		permSign = -permSign | ||||
| 	} | ||||
| 
 | ||||
| 	// Construct multiple-precision versions of the sorted points and compute | ||||
| 	// their precise 3x3 determinant. | ||||
| 	xa := r3.PreciseVectorFromVector(pa.Vector) | ||||
| 	xb := r3.PreciseVectorFromVector(pb.Vector) | ||||
| 	xc := r3.PreciseVectorFromVector(pc.Vector) | ||||
| 	xbCrossXc := xb.Cross(xc) | ||||
| 	det := xa.Dot(xbCrossXc) | ||||
| 
 | ||||
| 	// The precision of big.Float is high enough that the result should always | ||||
| 	// be exact enough (no rounding was performed). | ||||
| 
 | ||||
| 	// If the exact determinant is non-zero, we're done. | ||||
| 	detSign := Direction(det.Sign()) | ||||
| 	if detSign == Indeterminate && perturb { | ||||
| 		// Otherwise, we need to resort to symbolic perturbations to resolve the | ||||
| 		// sign of the determinant. | ||||
| 		detSign = symbolicallyPerturbedSign(xa, xb, xc, xbCrossXc) | ||||
| 	} | ||||
| 	return permSign * detSign | ||||
| } | ||||
| 
 | ||||
| // symbolicallyPerturbedSign reports the sign of the determinant of three points | ||||
| // A, B, C under a model where every possible Point is slightly perturbed by | ||||
| // a unique infinitesmal amount such that no three perturbed points are | ||||
| // collinear and no four points are coplanar. The perturbations are so small | ||||
| // that they do not change the sign of any determinant that was non-zero | ||||
| // before the perturbations, and therefore can be safely ignored unless the | ||||
| // determinant of three points is exactly zero (using multiple-precision | ||||
| // arithmetic). This returns CounterClockwise or Clockwise according to the | ||||
| // sign of the determinant after the symbolic perturbations are taken into account. | ||||
| // | ||||
| // Since the symbolic perturbation of a given point is fixed (i.e., the | ||||
| // perturbation is the same for all calls to this method and does not depend | ||||
| // on the other two arguments), the results of this method are always | ||||
| // self-consistent. It will never return results that would correspond to an | ||||
| // impossible configuration of non-degenerate points. | ||||
| // | ||||
| // This requires that the 3x3 determinant of A, B, C must be exactly zero. | ||||
| // And the points must be distinct, with A < B < C in lexicographic order. | ||||
| // | ||||
| // Reference: | ||||
| //   "Simulation of Simplicity" (Edelsbrunner and Muecke, ACM Transactions on | ||||
| //   Graphics, 1990). | ||||
| // | ||||
| func symbolicallyPerturbedSign(a, b, c, bCrossC r3.PreciseVector) Direction { | ||||
| 	// This method requires that the points are sorted in lexicographically | ||||
| 	// increasing order. This is because every possible Point has its own | ||||
| 	// symbolic perturbation such that if A < B then the symbolic perturbation | ||||
| 	// for A is much larger than the perturbation for B. | ||||
| 	// | ||||
| 	// Alternatively, we could sort the points in this method and keep track of | ||||
| 	// the sign of the permutation, but it is more efficient to do this before | ||||
| 	// converting the inputs to the multi-precision representation, and this | ||||
| 	// also lets us re-use the result of the cross product B x C. | ||||
| 	// | ||||
| 	// Every input coordinate x[i] is assigned a symbolic perturbation dx[i]. | ||||
| 	// We then compute the sign of the determinant of the perturbed points, | ||||
| 	// i.e. | ||||
| 	//               | a.X+da.X  a.Y+da.Y  a.Z+da.Z | | ||||
| 	//               | b.X+db.X  b.Y+db.Y  b.Z+db.Z | | ||||
| 	//               | c.X+dc.X  c.Y+dc.Y  c.Z+dc.Z | | ||||
| 	// | ||||
| 	// The perturbations are chosen such that | ||||
| 	// | ||||
| 	//   da.Z > da.Y > da.X > db.Z > db.Y > db.X > dc.Z > dc.Y > dc.X | ||||
| 	// | ||||
| 	// where each perturbation is so much smaller than the previous one that we | ||||
| 	// don't even need to consider it unless the coefficients of all previous | ||||
| 	// perturbations are zero. In fact, it is so small that we don't need to | ||||
| 	// consider it unless the coefficient of all products of the previous | ||||
| 	// perturbations are zero. For example, we don't need to consider the | ||||
| 	// coefficient of db.Y unless the coefficient of db.Z *da.X is zero. | ||||
| 	// | ||||
| 	// The follow code simply enumerates the coefficients of the perturbations | ||||
| 	// (and products of perturbations) that appear in the determinant above, in | ||||
| 	// order of decreasing perturbation magnitude. The first non-zero | ||||
| 	// coefficient determines the sign of the result. The easiest way to | ||||
| 	// enumerate the coefficients in the correct order is to pretend that each | ||||
| 	// perturbation is some tiny value "eps" raised to a power of two: | ||||
| 	// | ||||
| 	// eps**     1      2      4      8     16     32     64    128    256 | ||||
| 	//        da.Z   da.Y   da.X   db.Z   db.Y   db.X   dc.Z   dc.Y   dc.X | ||||
| 	// | ||||
| 	// Essentially we can then just count in binary and test the corresponding | ||||
| 	// subset of perturbations at each step. So for example, we must test the | ||||
| 	// coefficient of db.Z*da.X before db.Y because eps**12 > eps**16. | ||||
| 	// | ||||
| 	// Of course, not all products of these perturbations appear in the | ||||
| 	// determinant above, since the determinant only contains the products of | ||||
| 	// elements in distinct rows and columns. Thus we don't need to consider | ||||
| 	// da.Z*da.Y, db.Y *da.Y, etc. Furthermore, sometimes different pairs of | ||||
| 	// perturbations have the same coefficient in the determinant; for example, | ||||
| 	// da.Y*db.X and db.Y*da.X have the same coefficient (c.Z). Therefore | ||||
| 	// we only need to test this coefficient the first time we encounter it in | ||||
| 	// the binary order above (which will be db.Y*da.X). | ||||
| 	// | ||||
| 	// The sequence of tests below also appears in Table 4-ii of the paper | ||||
| 	// referenced above, if you just want to look it up, with the following | ||||
| 	// translations: [a,b,c] -> [i,j,k] and [0,1,2] -> [1,2,3]. Also note that | ||||
| 	// some of the signs are different because the opposite cross product is | ||||
| 	// used (e.g., B x C rather than C x B). | ||||
| 
 | ||||
| 	detSign := bCrossC.Z.Sign() // da.Z | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = bCrossC.Y.Sign() // da.Y | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = bCrossC.X.Sign() // da.X | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 
 | ||||
| 	detSign = newBigFloat().Sub(newBigFloat().Mul(c.X, a.Y), newBigFloat().Mul(c.Y, a.X)).Sign() // db.Z | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = c.X.Sign() // db.Z * da.Y | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = -(c.Y.Sign()) // db.Z * da.X | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 
 | ||||
| 	detSign = newBigFloat().Sub(newBigFloat().Mul(c.Z, a.X), newBigFloat().Mul(c.X, a.Z)).Sign() // db.Y | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = c.Z.Sign() // db.Y * da.X | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 
 | ||||
| 	// The following test is listed in the paper, but it is redundant because | ||||
| 	// the previous tests guarantee that C == (0, 0, 0). | ||||
| 	// (c.Y*a.Z - c.Z*a.Y).Sign() // db.X | ||||
| 
 | ||||
| 	detSign = newBigFloat().Sub(newBigFloat().Mul(a.X, b.Y), newBigFloat().Mul(a.Y, b.X)).Sign() // dc.Z | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = -(b.X.Sign()) // dc.Z * da.Y | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = b.Y.Sign() // dc.Z * da.X | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	detSign = a.X.Sign() // dc.Z * db.Y | ||||
| 	if detSign != 0 { | ||||
| 		return Direction(detSign) | ||||
| 	} | ||||
| 	return CounterClockwise // dc.Z * db.Y * da.X | ||||
| } | ||||
| 
 | ||||
| // CompareDistances returns -1, 0, or +1 according to whether AX < BX, A == B, | ||||
| // or AX > BX respectively. Distances are measured with respect to the positions | ||||
| // of X, A, and B as though they were reprojected to lie exactly on the surface of | ||||
| // the unit sphere. Furthermore, this method uses symbolic perturbations to | ||||
| // ensure that the result is non-zero whenever A != B, even when AX == BX | ||||
| // exactly, or even when A and B project to the same point on the sphere. | ||||
| // Such results are guaranteed to be self-consistent, i.e. if AB < BC and | ||||
| // BC < AC, then AB < AC. | ||||
| func CompareDistances(x, a, b Point) int { | ||||
| 	// We start by comparing distances using dot products (i.e., cosine of the | ||||
| 	// angle), because (1) this is the cheapest technique, and (2) it is valid | ||||
| 	// over the entire range of possible angles. (We can only use the sin^2 | ||||
| 	// technique if both angles are less than 90 degrees or both angles are | ||||
| 	// greater than 90 degrees.) | ||||
| 	sign := triageCompareCosDistances(x, a, b) | ||||
| 	if sign != 0 { | ||||
| 		return sign | ||||
| 	} | ||||
| 
 | ||||
| 	// Optimization for (a == b) to avoid falling back to exact arithmetic. | ||||
| 	if a == b { | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	// It is much better numerically to compare distances using cos(angle) if | ||||
| 	// the distances are near 90 degrees and sin^2(angle) if the distances are | ||||
| 	// near 0 or 180 degrees. We only need to check one of the two angles when | ||||
| 	// making this decision because the fact that the test above failed means | ||||
| 	// that angles "a" and "b" are very close together. | ||||
| 	cosAX := a.Dot(x.Vector) | ||||
| 	if cosAX > 1/math.Sqrt2 { | ||||
| 		// Angles < 45 degrees. | ||||
| 		sign = triageCompareSin2Distances(x, a, b) | ||||
| 	} else if cosAX < -1/math.Sqrt2 { | ||||
| 		// Angles > 135 degrees. sin^2(angle) is decreasing in this range. | ||||
| 		sign = -triageCompareSin2Distances(x, a, b) | ||||
| 	} | ||||
| 	// C++ adds an additional check here using 80-bit floats. | ||||
| 	// This is skipped in Go because we only have 32 and 64 bit floats. | ||||
| 
 | ||||
| 	if sign != 0 { | ||||
| 		return sign | ||||
| 	} | ||||
| 
 | ||||
| 	sign = exactCompareDistances(r3.PreciseVectorFromVector(x.Vector), r3.PreciseVectorFromVector(a.Vector), r3.PreciseVectorFromVector(b.Vector)) | ||||
| 	if sign != 0 { | ||||
| 		return sign | ||||
| 	} | ||||
| 	return symbolicCompareDistances(x, a, b) | ||||
| } | ||||
| 
 | ||||
| // cosDistance returns cos(XY) where XY is the angle between X and Y, and the | ||||
| // maximum error amount in the result. This requires X and Y be normalized. | ||||
| func cosDistance(x, y Point) (cos, err float64) { | ||||
| 	cos = x.Dot(y.Vector) | ||||
| 	return cos, 9.5*dblError*math.Abs(cos) + 1.5*dblError | ||||
| } | ||||
| 
 | ||||
| // sin2Distance returns sin**2(XY), where XY is the angle between X and Y, | ||||
| // and the maximum error amount in the result. This requires X and Y be normalized. | ||||
| func sin2Distance(x, y Point) (sin2, err float64) { | ||||
| 	// The (x-y).Cross(x+y) trick eliminates almost all of error due to x | ||||
| 	// and y being not quite unit length. This method is extremely accurate | ||||
| 	// for small distances; the *relative* error in the result is O(dblError) for | ||||
| 	// distances as small as dblError. | ||||
| 	n := x.Sub(y.Vector).Cross(x.Add(y.Vector)) | ||||
| 	sin2 = 0.25 * n.Norm2() | ||||
| 	err = ((21+4*math.Sqrt(3))*dblError*sin2 + | ||||
| 		32*math.Sqrt(3)*dblError*dblError*math.Sqrt(sin2) + | ||||
| 		768*dblError*dblError*dblError*dblError) | ||||
| 	return sin2, err | ||||
| } | ||||
| 
 | ||||
| // triageCompareCosDistances returns -1, 0, or +1 according to whether AX < BX, | ||||
| // A == B, or AX > BX by comparing the distances between them using cosDistance. | ||||
| func triageCompareCosDistances(x, a, b Point) int { | ||||
| 	cosAX, cosAXerror := cosDistance(a, x) | ||||
| 	cosBX, cosBXerror := cosDistance(b, x) | ||||
| 	diff := cosAX - cosBX | ||||
| 	err := cosAXerror + cosBXerror | ||||
| 	if diff > err { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	if diff < -err { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // triageCompareSin2Distances returns -1, 0, or +1 according to whether AX < BX, | ||||
| // A == B, or AX > BX by comparing the distances between them using sin2Distance. | ||||
| func triageCompareSin2Distances(x, a, b Point) int { | ||||
| 	sin2AX, sin2AXerror := sin2Distance(a, x) | ||||
| 	sin2BX, sin2BXerror := sin2Distance(b, x) | ||||
| 	diff := sin2AX - sin2BX | ||||
| 	err := sin2AXerror + sin2BXerror | ||||
| 	if diff > err { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if diff < -err { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // exactCompareDistances returns -1, 0, or 1 after comparing using the values as | ||||
| // PreciseVectors. | ||||
| func exactCompareDistances(x, a, b r3.PreciseVector) int { | ||||
| 	// This code produces the same result as though all points were reprojected | ||||
| 	// to lie exactly on the surface of the unit sphere. It is based on testing | ||||
| 	// whether x.Dot(a.Normalize()) < x.Dot(b.Normalize()), reformulated | ||||
| 	// so that it can be evaluated using exact arithmetic. | ||||
| 	cosAX := x.Dot(a) | ||||
| 	cosBX := x.Dot(b) | ||||
| 
 | ||||
| 	// If the two values have different signs, we need to handle that case now | ||||
| 	// before squaring them below. | ||||
| 	aSign := cosAX.Sign() | ||||
| 	bSign := cosBX.Sign() | ||||
| 	if aSign != bSign { | ||||
| 		// If cos(AX) > cos(BX), then AX < BX. | ||||
| 		if aSign > bSign { | ||||
| 			return -1 | ||||
| 		} | ||||
| 		return 1 | ||||
| 	} | ||||
| 	cosAX2 := newBigFloat().Mul(cosAX, cosAX) | ||||
| 	cosBX2 := newBigFloat().Mul(cosBX, cosBX) | ||||
| 	cmp := newBigFloat().Sub(cosBX2.Mul(cosBX2, a.Norm2()), cosAX2.Mul(cosAX2, b.Norm2())) | ||||
| 	return aSign * cmp.Sign() | ||||
| } | ||||
| 
 | ||||
| // symbolicCompareDistances returns -1, 0, or +1 given three points such that AX == BX | ||||
| // (exactly) according to whether AX < BX, AX == BX, or AX > BX after symbolic | ||||
| // perturbations are taken into account. | ||||
| func symbolicCompareDistances(x, a, b Point) int { | ||||
| 	// Our symbolic perturbation strategy is based on the following model. | ||||
| 	// Similar to "simulation of simplicity", we assign a perturbation to every | ||||
| 	// point such that if A < B, then the symbolic perturbation for A is much, | ||||
| 	// much larger than the symbolic perturbation for B. We imagine that | ||||
| 	// rather than projecting every point to lie exactly on the unit sphere, | ||||
| 	// instead each point is positioned on its own tiny pedestal that raises it | ||||
| 	// just off the surface of the unit sphere. This means that the distance AX | ||||
| 	// is actually the true distance AX plus the (symbolic) heights of the | ||||
| 	// pedestals for A and X. The pedestals are infinitesmally thin, so they do | ||||
| 	// not affect distance measurements except at the two endpoints. If several | ||||
| 	// points project to exactly the same point on the unit sphere, we imagine | ||||
| 	// that they are placed on separate pedestals placed close together, where | ||||
| 	// the distance between pedestals is much, much less than the height of any | ||||
| 	// pedestal. (There are a finite number of Points, and therefore a finite | ||||
| 	// number of pedestals, so this is possible.) | ||||
| 	// | ||||
| 	// If A < B, then A is on a higher pedestal than B, and therefore AX > BX. | ||||
| 	switch a.Cmp(b.Vector) { | ||||
| 	case -1: | ||||
| 		return 1 | ||||
| 	case 1: | ||||
| 		return -1 | ||||
| 	default: | ||||
| 		return 0 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// ca45Degrees is a predefined ChordAngle representing (approximately) 45 degrees. | ||||
| 	ca45Degrees = s1.ChordAngleFromSquaredLength(2 - math.Sqrt2) | ||||
| ) | ||||
| 
 | ||||
| // CompareDistance returns -1, 0, or +1 according to whether the distance XY is | ||||
| // respectively less than, equal to, or greater than the provided chord angle. Distances are measured | ||||
| // with respect to the positions of all points as though they are projected to lie | ||||
| // exactly on the surface of the unit sphere. | ||||
| func CompareDistance(x, y Point, r s1.ChordAngle) int { | ||||
| 	// As with CompareDistances, we start by comparing dot products because | ||||
| 	// the sin^2 method is only valid when the distance XY and the limit "r" are | ||||
| 	// both less than 90 degrees. | ||||
| 	sign := triageCompareCosDistance(x, y, float64(r)) | ||||
| 	if sign != 0 { | ||||
| 		return sign | ||||
| 	} | ||||
| 
 | ||||
| 	// Unlike with CompareDistances, it's not worth using the sin^2 method | ||||
| 	// when the distance limit is near 180 degrees because the ChordAngle | ||||
| 	// representation itself has has a rounding error of up to 2e-8 radians for | ||||
| 	// distances near 180 degrees. | ||||
| 	if r < ca45Degrees { | ||||
| 		sign = triageCompareSin2Distance(x, y, float64(r)) | ||||
| 		if sign != 0 { | ||||
| 			return sign | ||||
| 		} | ||||
| 	} | ||||
| 	return exactCompareDistance(r3.PreciseVectorFromVector(x.Vector), r3.PreciseVectorFromVector(y.Vector), big.NewFloat(float64(r)).SetPrec(big.MaxPrec)) | ||||
| } | ||||
| 
 | ||||
| // triageCompareCosDistance returns -1, 0, or +1 according to whether the distance XY is | ||||
| // less than, equal to, or greater than r2 respectively using cos distance. | ||||
| func triageCompareCosDistance(x, y Point, r2 float64) int { | ||||
| 	cosXY, cosXYError := cosDistance(x, y) | ||||
| 	cosR := 1.0 - 0.5*r2 | ||||
| 	cosRError := 2.0 * dblError * cosR | ||||
| 	diff := cosXY - cosR | ||||
| 	err := cosXYError + cosRError | ||||
| 	if diff > err { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	if diff < -err { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // triageCompareSin2Distance returns -1, 0, or +1 according to whether the distance XY is | ||||
| // less than, equal to, or greater than r2 respectively using sin^2 distance. | ||||
| func triageCompareSin2Distance(x, y Point, r2 float64) int { | ||||
| 	// Only valid for distance limits < 90 degrees. | ||||
| 	sin2XY, sin2XYError := sin2Distance(x, y) | ||||
| 	sin2R := r2 * (1.0 - 0.25*r2) | ||||
| 	sin2RError := 3.0 * dblError * sin2R | ||||
| 	diff := sin2XY - sin2R | ||||
| 	err := sin2XYError + sin2RError | ||||
| 	if diff > err { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if diff < -err { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	bigOne  = big.NewFloat(1.0).SetPrec(big.MaxPrec) | ||||
| 	bigHalf = big.NewFloat(0.5).SetPrec(big.MaxPrec) | ||||
| ) | ||||
| 
 | ||||
| // exactCompareDistance returns -1, 0, or +1 after comparing using PreciseVectors. | ||||
| func exactCompareDistance(x, y r3.PreciseVector, r2 *big.Float) int { | ||||
| 	// This code produces the same result as though all points were reprojected | ||||
| 	// to lie exactly on the surface of the unit sphere.  It is based on | ||||
| 	// comparing the cosine of the angle XY (when both points are projected to | ||||
| 	// lie exactly on the sphere) to the given threshold. | ||||
| 	cosXY := x.Dot(y) | ||||
| 	cosR := newBigFloat().Sub(bigOne, newBigFloat().Mul(bigHalf, r2)) | ||||
| 
 | ||||
| 	// If the two values have different signs, we need to handle that case now | ||||
| 	// before squaring them below. | ||||
| 	xySign := cosXY.Sign() | ||||
| 	rSign := cosR.Sign() | ||||
| 	if xySign != rSign { | ||||
| 		if xySign > rSign { | ||||
| 			return -1 | ||||
| 		} | ||||
| 		return 1 // If cos(XY) > cos(r), then XY < r. | ||||
| 	} | ||||
| 	cmp := newBigFloat().Sub( | ||||
| 		newBigFloat().Mul( | ||||
| 			newBigFloat().Mul(cosR, cosR), newBigFloat().Mul(x.Norm2(), y.Norm2())), | ||||
| 		newBigFloat().Mul(cosXY, cosXY)) | ||||
| 	return xySign * cmp.Sign() | ||||
| } | ||||
| 
 | ||||
| // TODO(roberts): Differences from C++ | ||||
| // CompareEdgeDistance | ||||
| // CompareEdgeDirections | ||||
| // EdgeCircumcenterSign | ||||
| // GetVoronoiSiteExclusion | ||||
| // GetClosestVertex | ||||
| // TriageCompareLineSin2Distance | ||||
| // TriageCompareLineCos2Distance | ||||
| // TriageCompareLineDistance | ||||
| // TriageCompareEdgeDistance | ||||
| // ExactCompareLineDistance | ||||
| // ExactCompareEdgeDistance | ||||
| // TriageCompareEdgeDirections | ||||
| // ExactCompareEdgeDirections | ||||
| // ArePointsAntipodal | ||||
| // ArePointsLinearlyDependent | ||||
| // GetCircumcenter | ||||
| // TriageEdgeCircumcenterSign | ||||
| // ExactEdgeCircumcenterSign | ||||
| // UnperturbedSign | ||||
| // SymbolicEdgeCircumcenterSign | ||||
| // ExactVoronoiSiteExclusion | ||||
							
								
								
									
										241
									
								
								vendor/github.com/golang/geo/s2/projections.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										241
									
								
								vendor/github.com/golang/geo/s2/projections.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,241 +0,0 @@ | |||
| // Copyright 2018 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r2" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Projection defines an interface for different ways of mapping between s2 and r2 Points. | ||||
| // It can also define the coordinate wrapping behavior along each axis. | ||||
| type Projection interface { | ||||
| 	// Project converts a point on the sphere to a projected 2D point. | ||||
| 	Project(p Point) r2.Point | ||||
| 
 | ||||
| 	// Unproject converts a projected 2D point to a point on the sphere. | ||||
| 	// | ||||
| 	// If wrapping is defined for a given axis (see below), then this method | ||||
| 	// should accept any real number for the corresponding coordinate. | ||||
| 	Unproject(p r2.Point) Point | ||||
| 
 | ||||
| 	// FromLatLng is a convenience function equivalent to Project(LatLngToPoint(ll)), | ||||
| 	// but the implementation is more efficient. | ||||
| 	FromLatLng(ll LatLng) r2.Point | ||||
| 
 | ||||
| 	// ToLatLng is a convenience function equivalent to LatLngFromPoint(Unproject(p)), | ||||
| 	// but the implementation is more efficient. | ||||
| 	ToLatLng(p r2.Point) LatLng | ||||
| 
 | ||||
| 	// Interpolate returns the point obtained by interpolating the given | ||||
| 	// fraction of the distance along the line from A to B. | ||||
| 	// Fractions < 0 or > 1 result in extrapolation instead. | ||||
| 	Interpolate(f float64, a, b r2.Point) r2.Point | ||||
| 
 | ||||
| 	// WrapDistance reports the coordinate wrapping distance along each axis. | ||||
| 	// If this value is non-zero for a given axis, the coordinates are assumed | ||||
| 	// to "wrap" with the given period. For example, if WrapDistance.Y == 360 | ||||
| 	// then (x, y) and (x, y + 360) should map to the same Point. | ||||
| 	// | ||||
| 	// This information is used to ensure that edges takes the shortest path | ||||
| 	// between two given points. For example, if coordinates represent | ||||
| 	// (latitude, longitude) pairs in degrees and WrapDistance().Y == 360, | ||||
| 	// then the edge (5:179, 5:-179) would be interpreted as spanning 2 degrees | ||||
| 	// of longitude rather than 358 degrees. | ||||
| 	// | ||||
| 	// If a given axis does not wrap, its WrapDistance should be set to zero. | ||||
| 	WrapDistance() r2.Point | ||||
| 
 | ||||
| 	// WrapDestination that wraps the coordinates of B if necessary in order to | ||||
| 	// obtain the shortest edge AB. For example, suppose that A = [170, 20], | ||||
| 	// B = [-170, 20], and the projection wraps so that [x, y] == [x + 360, y]. | ||||
| 	// Then this function would return [190, 20] for point B (reducing the edge | ||||
| 	// length in the "x" direction from 340 to 20). | ||||
| 	WrapDestination(a, b r2.Point) r2.Point | ||||
| 
 | ||||
| 	// We do not support implementations of this interface outside this package. | ||||
| 	privateInterface() | ||||
| } | ||||
| 
 | ||||
| // PlateCarreeProjection defines the "plate carree" (square plate) projection, | ||||
| // which converts points on the sphere to (longitude, latitude) pairs. | ||||
| // Coordinates can be scaled so that they represent radians, degrees, etc, but | ||||
| // the projection is always centered around (latitude=0, longitude=0). | ||||
| // | ||||
| // Note that (x, y) coordinates are backwards compared to the usual (latitude, | ||||
| // longitude) ordering, in order to match the usual convention for graphs in | ||||
| // which "x" is horizontal and "y" is vertical. | ||||
| type PlateCarreeProjection struct { | ||||
| 	xWrap       float64 | ||||
| 	toRadians   float64 // Multiplier to convert coordinates to radians. | ||||
| 	fromRadians float64 // Multiplier to convert coordinates from radians. | ||||
| } | ||||
| 
 | ||||
| // NewPlateCarreeProjection constructs a plate carree projection where the | ||||
| // x-coordinates (lng) span [-xScale, xScale] and the y coordinates (lat) | ||||
| // span [-xScale/2, xScale/2]. For example if xScale==180 then the x | ||||
| // range is [-180, 180] and the y range is [-90, 90]. | ||||
| // | ||||
| // By default coordinates are expressed in radians, i.e. the x range is | ||||
| // [-Pi, Pi] and the y range is [-Pi/2, Pi/2]. | ||||
| func NewPlateCarreeProjection(xScale float64) Projection { | ||||
| 	return &PlateCarreeProjection{ | ||||
| 		xWrap:       2 * xScale, | ||||
| 		toRadians:   math.Pi / xScale, | ||||
| 		fromRadians: xScale / math.Pi, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Project converts a point on the sphere to a projected 2D point. | ||||
| func (p *PlateCarreeProjection) Project(pt Point) r2.Point { | ||||
| 	return p.FromLatLng(LatLngFromPoint(pt)) | ||||
| } | ||||
| 
 | ||||
| // Unproject converts a projected 2D point to a point on the sphere. | ||||
| func (p *PlateCarreeProjection) Unproject(pt r2.Point) Point { | ||||
| 	return PointFromLatLng(p.ToLatLng(pt)) | ||||
| } | ||||
| 
 | ||||
| // FromLatLng returns the LatLng projected into an R2 Point. | ||||
| func (p *PlateCarreeProjection) FromLatLng(ll LatLng) r2.Point { | ||||
| 	return r2.Point{ | ||||
| 		X: p.fromRadians * ll.Lng.Radians(), | ||||
| 		Y: p.fromRadians * ll.Lat.Radians(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ToLatLng returns the LatLng projected from the given R2 Point. | ||||
| func (p *PlateCarreeProjection) ToLatLng(pt r2.Point) LatLng { | ||||
| 	return LatLng{ | ||||
| 		Lat: s1.Angle(p.toRadians * pt.Y), | ||||
| 		Lng: s1.Angle(p.toRadians * math.Remainder(pt.X, p.xWrap)), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Interpolate returns the point obtained by interpolating the given | ||||
| // fraction of the distance along the line from A to B. | ||||
| func (p *PlateCarreeProjection) Interpolate(f float64, a, b r2.Point) r2.Point { | ||||
| 	return a.Mul(1 - f).Add(b.Mul(f)) | ||||
| } | ||||
| 
 | ||||
| // WrapDistance reports the coordinate wrapping distance along each axis. | ||||
| func (p *PlateCarreeProjection) WrapDistance() r2.Point { | ||||
| 	return r2.Point{p.xWrap, 0} | ||||
| } | ||||
| 
 | ||||
| // WrapDestination wraps the points if needed to get the shortest edge. | ||||
| func (p *PlateCarreeProjection) WrapDestination(a, b r2.Point) r2.Point { | ||||
| 	return wrapDestination(a, b, p.WrapDistance) | ||||
| } | ||||
| 
 | ||||
| func (p *PlateCarreeProjection) privateInterface() {} | ||||
| 
 | ||||
| // MercatorProjection defines the spherical Mercator projection. Google Maps | ||||
| // uses this projection together with WGS84 coordinates, in which case it is | ||||
| // known as the "Web Mercator" projection (see Wikipedia). This class makes | ||||
| // no assumptions regarding the coordinate system of its input points, but | ||||
| // simply applies the spherical Mercator projection to them. | ||||
| // | ||||
| // The Mercator projection is finite in width (x) but infinite in height (y). | ||||
| // "x" corresponds to longitude, and spans a finite range such as [-180, 180] | ||||
| // (with coordinate wrapping), while "y" is a function of latitude and spans | ||||
| // an infinite range. (As "y" coordinates get larger, points get closer to | ||||
| // the north pole but never quite reach it.) The north and south poles have | ||||
| // infinite "y" values. (Note that this will cause problems if you tessellate | ||||
| // a Mercator edge where one endpoint is a pole. If you need to do this, clip | ||||
| // the edge first so that the "y" coordinate is no more than about 5 * maxX.) | ||||
| type MercatorProjection struct { | ||||
| 	xWrap       float64 | ||||
| 	toRadians   float64 // Multiplier to convert coordinates to radians. | ||||
| 	fromRadians float64 // Multiplier to convert coordinates from radians. | ||||
| } | ||||
| 
 | ||||
| // NewMercatorProjection constructs a Mercator projection with the given maximum | ||||
| // longitude axis value corresponding to a range of [-maxLng, maxLng]. | ||||
| // The horizontal and vertical axes are scaled equally. | ||||
| func NewMercatorProjection(maxLng float64) Projection { | ||||
| 	return &MercatorProjection{ | ||||
| 		xWrap:       2 * maxLng, | ||||
| 		toRadians:   math.Pi / maxLng, | ||||
| 		fromRadians: maxLng / math.Pi, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Project converts a point on the sphere to a projected 2D point. | ||||
| func (p *MercatorProjection) Project(pt Point) r2.Point { | ||||
| 	return p.FromLatLng(LatLngFromPoint(pt)) | ||||
| } | ||||
| 
 | ||||
| // Unproject converts a projected 2D point to a point on the sphere. | ||||
| func (p *MercatorProjection) Unproject(pt r2.Point) Point { | ||||
| 	return PointFromLatLng(p.ToLatLng(pt)) | ||||
| } | ||||
| 
 | ||||
| // FromLatLng returns the LatLng projected into an R2 Point. | ||||
| func (p *MercatorProjection) FromLatLng(ll LatLng) r2.Point { | ||||
| 	// This formula is more accurate near zero than the log(tan()) version. | ||||
| 	// Note that latitudes of +/- 90 degrees yield "y" values of +/- infinity. | ||||
| 	sinPhi := math.Sin(float64(ll.Lat)) | ||||
| 	y := 0.5 * math.Log((1+sinPhi)/(1-sinPhi)) | ||||
| 	return r2.Point{p.fromRadians * float64(ll.Lng), p.fromRadians * y} | ||||
| } | ||||
| 
 | ||||
| // ToLatLng returns the LatLng projected from the given R2 Point. | ||||
| func (p *MercatorProjection) ToLatLng(pt r2.Point) LatLng { | ||||
| 	// This formula is more accurate near zero than the atan(exp()) version. | ||||
| 	x := p.toRadians * math.Remainder(pt.X, p.xWrap) | ||||
| 	k := math.Exp(2 * p.toRadians * pt.Y) | ||||
| 	var y float64 | ||||
| 	if math.IsInf(k, 0) { | ||||
| 		y = math.Pi / 2 | ||||
| 	} else { | ||||
| 		y = math.Asin((k - 1) / (k + 1)) | ||||
| 	} | ||||
| 	return LatLng{s1.Angle(y), s1.Angle(x)} | ||||
| } | ||||
| 
 | ||||
| // Interpolate returns the point obtained by interpolating the given | ||||
| // fraction of the distance along the line from A to B. | ||||
| func (p *MercatorProjection) Interpolate(f float64, a, b r2.Point) r2.Point { | ||||
| 	return a.Mul(1 - f).Add(b.Mul(f)) | ||||
| } | ||||
| 
 | ||||
| // WrapDistance reports the coordinate wrapping distance along each axis. | ||||
| func (p *MercatorProjection) WrapDistance() r2.Point { | ||||
| 	return r2.Point{p.xWrap, 0} | ||||
| } | ||||
| 
 | ||||
| // WrapDestination wraps the points if needed to get the shortest edge. | ||||
| func (p *MercatorProjection) WrapDestination(a, b r2.Point) r2.Point { | ||||
| 	return wrapDestination(a, b, p.WrapDistance) | ||||
| } | ||||
| 
 | ||||
| func (p *MercatorProjection) privateInterface() {} | ||||
| 
 | ||||
| func wrapDestination(a, b r2.Point, wrapDistance func() r2.Point) r2.Point { | ||||
| 	wrap := wrapDistance() | ||||
| 	x := b.X | ||||
| 	y := b.Y | ||||
| 	// The code below ensures that "b" is unmodified unless wrapping is required. | ||||
| 	if wrap.X > 0 && math.Abs(x-a.X) > 0.5*wrap.X { | ||||
| 		x = a.X + math.Remainder(x-a.X, wrap.X) | ||||
| 	} | ||||
| 	if wrap.Y > 0 && math.Abs(y-a.Y) > 0.5*wrap.Y { | ||||
| 		y = a.Y + math.Remainder(y-a.Y, wrap.Y) | ||||
| 	} | ||||
| 	return r2.Point{x, y} | ||||
| } | ||||
							
								
								
									
										93
									
								
								vendor/github.com/golang/geo/s2/query_entry.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										93
									
								
								vendor/github.com/golang/geo/s2/query_entry.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,93 +0,0 @@ | |||
| // Copyright 2020 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import "container/heap" | ||||
| 
 | ||||
| // A queryQueueEntry stores CellIDs and distance from a target. It is used by the | ||||
| // different S2 Query types to efficiently build their internal priority queue | ||||
| // in the optimized algorithm implementations. | ||||
| type queryQueueEntry struct { | ||||
| 	// A lower bound on the distance from the target to ID. This is the key | ||||
| 	// of the priority queue. | ||||
| 	distance distance | ||||
| 
 | ||||
| 	// The cell being queued. | ||||
| 	id CellID | ||||
| 
 | ||||
| 	// If the CellID belongs to a ShapeIndex, this field stores the | ||||
| 	// corresponding ShapeIndexCell. Otherwise ID is a proper ancestor of | ||||
| 	// one or more ShapeIndexCells and this field stores is nil. | ||||
| 	indexCell *ShapeIndexCell | ||||
| } | ||||
| 
 | ||||
| // queryQueue is used by the optimized algorithm to maintain a priority queue of | ||||
| // unprocessed CellIDs, sorted in increasing order of distance from the target. | ||||
| type queryQueue struct { | ||||
| 	queue queryPQ | ||||
| } | ||||
| 
 | ||||
| // newQueryQueue returns a new initialized queryQueue. | ||||
| func newQueryQueue() *queryQueue { | ||||
| 	q := &queryQueue{ | ||||
| 		queue: make(queryPQ, 0), | ||||
| 	} | ||||
| 	heap.Init(&q.queue) | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // push adds the given entry to the top of this queue. | ||||
| func (q *queryQueue) push(e *queryQueueEntry) { | ||||
| 	heap.Push(&q.queue, e) | ||||
| } | ||||
| 
 | ||||
| // pop returns the top element of this queue. | ||||
| func (q *queryQueue) pop() *queryQueueEntry { | ||||
| 	return heap.Pop(&q.queue).(*queryQueueEntry) | ||||
| } | ||||
| 
 | ||||
| func (q *queryQueue) size() int { | ||||
| 	return q.queue.Len() | ||||
| } | ||||
| 
 | ||||
| func (q *queryQueue) reset() { | ||||
| 	q.queue = q.queue[:0] | ||||
| } | ||||
| 
 | ||||
| // queryPQ is a priority queue that implements the heap interface. | ||||
| type queryPQ []*queryQueueEntry | ||||
| 
 | ||||
| func (q queryPQ) Len() int { return len(q) } | ||||
| func (q queryPQ) Less(i, j int) bool { | ||||
| 	return q[i].distance.less(q[j].distance) | ||||
| } | ||||
| 
 | ||||
| // Swap swaps the two entries. | ||||
| func (q queryPQ) Swap(i, j int) { | ||||
| 	q[i], q[j] = q[j], q[i] | ||||
| } | ||||
| 
 | ||||
| // Push adds the given entry to the queue. | ||||
| func (q *queryPQ) Push(x interface{}) { | ||||
| 	item := x.(*queryQueueEntry) | ||||
| 	*q = append(*q, item) | ||||
| } | ||||
| 
 | ||||
| // Pop returns the top element of the queue. | ||||
| func (q *queryPQ) Pop() interface{} { | ||||
| 	item := (*q)[len(*q)-1] | ||||
| 	*q = (*q)[:len(*q)-1] | ||||
| 	return item | ||||
| } | ||||
							
								
								
									
										196
									
								
								vendor/github.com/golang/geo/s2/query_options.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										196
									
								
								vendor/github.com/golang/geo/s2/query_options.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,196 +0,0 @@ | |||
| // Copyright 2019 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| const maxQueryResults = math.MaxInt32 | ||||
| 
 | ||||
| // queryOptions represents the set of all configurable parameters used by all of | ||||
| // the Query types. Most of these fields have non-zero defaults, so initialization | ||||
| // is handled within each Query type. All of the exported methods accept user | ||||
| // supplied sets of options to set or adjust as necessary. | ||||
| // | ||||
| // Several of the defaults depend on the distance interface type being used | ||||
| // (e.g. minDistance, maxDistance, etc.) | ||||
| // | ||||
| // If a user sets an option value that a given query type doesn't use, it is ignored. | ||||
| type queryOptions struct { | ||||
| 	// maxResults specifies that at most MaxResults edges should be returned. | ||||
| 	// This must be at least 1. | ||||
| 	// | ||||
| 	// The default value is to return all results. | ||||
| 	maxResults int | ||||
| 
 | ||||
| 	// distanceLimit specifies that only edges whose distance to the target is | ||||
| 	// within this distance should be returned. | ||||
| 	// | ||||
| 	// Note that edges whose distance is exactly equal to this are | ||||
| 	// not returned. In most cases this doesn't matter (since distances are | ||||
| 	// not computed exactly in the first place), but if such edges are needed | ||||
| 	// then you can retrieve them by specifying the distance as the next | ||||
| 	// largest representable distance. i.e. distanceLimit.Successor(). | ||||
| 	// | ||||
| 	// The default value is the infinity value, such that all results will be | ||||
| 	// returned. | ||||
| 	distanceLimit s1.ChordAngle | ||||
| 
 | ||||
| 	// maxError specifies that edges up to MaxError further away than the true | ||||
| 	// closest edges may be substituted in the result set, as long as such | ||||
| 	// edges satisfy all the remaining search criteria (such as DistanceLimit). | ||||
| 	// This option only has an effect if MaxResults is also specified; | ||||
| 	// otherwise all edges closer than MaxDistance will always be returned. | ||||
| 	// | ||||
| 	// Note that this does not affect how the distance between edges is | ||||
| 	// computed; it simply gives the algorithm permission to stop the search | ||||
| 	// early as soon as the best possible improvement drops below MaxError. | ||||
| 	// | ||||
| 	// This can be used to implement distance predicates efficiently. For | ||||
| 	// example, to determine whether the minimum distance is less than D, set | ||||
| 	// MaxResults == 1 and MaxDistance == MaxError == D. This causes | ||||
| 	// the algorithm to terminate as soon as it finds any edge whose distance | ||||
| 	// is less than D, rather than continuing to search for an edge that is | ||||
| 	// even closer. | ||||
| 	// | ||||
| 	// The default value is zero. | ||||
| 	maxError s1.ChordAngle | ||||
| 
 | ||||
| 	// includeInteriors specifies that polygon interiors should be included | ||||
| 	// when measuring distances. In other words, polygons that contain the target | ||||
| 	// should have a distance of zero. (For targets consisting of multiple connected | ||||
| 	// components, the distance is zero if any component is contained.) This | ||||
| 	// is indicated in the results by returning a (ShapeID, EdgeID) pair | ||||
| 	// with EdgeID == -1, i.e. this value denotes the polygons's interior. | ||||
| 	// | ||||
| 	// Note that for efficiency, any polygon that intersects the target may or | ||||
| 	// may not have an EdgeID == -1 result. Such results are optional | ||||
| 	// because in that case the distance to the polygon is already zero. | ||||
| 	// | ||||
| 	// The default value is true. | ||||
| 	includeInteriors bool | ||||
| 
 | ||||
| 	// specifies that distances should be computed by examining every edge | ||||
| 	// rather than using the ShapeIndex. | ||||
| 	// | ||||
| 	// TODO(roberts): When optimized is implemented, update the default to false. | ||||
| 	// The default value is true. | ||||
| 	useBruteForce bool | ||||
| 
 | ||||
| 	// region specifies that results must intersect the given Region. | ||||
| 	// | ||||
| 	// Note that if you want to set the region to a disc around a target | ||||
| 	// point, it is faster to use a PointTarget with distanceLimit set | ||||
| 	// instead. You can also set a distance limit and also require that results | ||||
| 	// lie within a given rectangle. | ||||
| 	// | ||||
| 	// The default is nil (no region limits). | ||||
| 	region Region | ||||
| } | ||||
| 
 | ||||
| // UseBruteForce sets or disables the use of brute force in a query. | ||||
| func (q *queryOptions) UseBruteForce(x bool) *queryOptions { | ||||
| 	q.useBruteForce = x | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // IncludeInteriors specifies whether polygon interiors should be | ||||
| // included when measuring distances. | ||||
| func (q *queryOptions) IncludeInteriors(x bool) *queryOptions { | ||||
| 	q.includeInteriors = x | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // MaxError specifies that edges up to dist away than the true | ||||
| // matching edges may be substituted in the result set, as long as such | ||||
| // edges satisfy all the remaining search criteria (such as DistanceLimit). | ||||
| // This option only has an effect if MaxResults is also specified; | ||||
| // otherwise all edges closer than MaxDistance will always be returned. | ||||
| func (q *queryOptions) MaxError(x s1.ChordAngle) *queryOptions { | ||||
| 	q.maxError = x | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // MaxResults specifies that at most MaxResults edges should be returned. | ||||
| // This must be at least 1. | ||||
| func (q *queryOptions) MaxResults(x int) *queryOptions { | ||||
| 	// TODO(roberts): What should be done if the value is <= 0? | ||||
| 	q.maxResults = int(x) | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // DistanceLimit specifies that only edges whose distance to the target is | ||||
| // within, this distance should be returned. Edges whose distance is equal | ||||
| // are not returned. | ||||
| // | ||||
| // To include values that are equal, specify the limit with the next largest | ||||
| // representable distance such as limit.Successor(), or set the option with | ||||
| // Furthest/ClosestInclusiveDistanceLimit. | ||||
| func (q *queryOptions) DistanceLimit(x s1.ChordAngle) *queryOptions { | ||||
| 	q.distanceLimit = x | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // ClosestInclusiveDistanceLimit sets the distance limit such that results whose | ||||
| // distance is exactly equal to the limit are also returned. | ||||
| func (q *queryOptions) ClosestInclusiveDistanceLimit(limit s1.ChordAngle) *queryOptions { | ||||
| 	q.distanceLimit = limit.Successor() | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // FurthestInclusiveDistanceLimit sets the distance limit such that results whose | ||||
| // distance is exactly equal to the limit are also returned. | ||||
| func (q *queryOptions) FurthestInclusiveDistanceLimit(limit s1.ChordAngle) *queryOptions { | ||||
| 	q.distanceLimit = limit.Predecessor() | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // ClosestConservativeDistanceLimit sets the distance limit such that results | ||||
| // also incorporates the error in distance calculations. This ensures that all | ||||
| // edges whose true distance is less than or equal to limit will be returned | ||||
| // (along with some edges whose true distance is slightly greater). | ||||
| // | ||||
| // Algorithms that need to do exact distance comparisons can use this | ||||
| // option to find a set of candidate edges that can then be filtered | ||||
| // further (e.g., using CompareDistance). | ||||
| func (q *queryOptions) ClosestConservativeDistanceLimit(limit s1.ChordAngle) *queryOptions { | ||||
| 	q.distanceLimit = limit.Expanded(minUpdateDistanceMaxError(limit)) | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // FurthestConservativeDistanceLimit sets the distance limit such that results | ||||
| // also incorporates the error in distance calculations. This ensures that all | ||||
| // edges whose true distance is greater than or equal to limit will be returned | ||||
| // (along with some edges whose true distance is slightly less). | ||||
| func (q *queryOptions) FurthestConservativeDistanceLimit(limit s1.ChordAngle) *queryOptions { | ||||
| 	q.distanceLimit = limit.Expanded(-minUpdateDistanceMaxError(limit)) | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| // newQueryOptions returns a set of options using the given distance type | ||||
| // with the proper default values. | ||||
| func newQueryOptions(d distance) *queryOptions { | ||||
| 	return &queryOptions{ | ||||
| 		maxResults:       maxQueryResults, | ||||
| 		distanceLimit:    d.infinity().chordAngle(), | ||||
| 		maxError:         0, | ||||
| 		includeInteriors: true, | ||||
| 		useBruteForce:    false, | ||||
| 		region:           nil, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										710
									
								
								vendor/github.com/golang/geo/s2/rect.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										710
									
								
								vendor/github.com/golang/geo/s2/rect.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,710 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // Rect represents a closed latitude-longitude rectangle. | ||||
| type Rect struct { | ||||
| 	Lat r1.Interval | ||||
| 	Lng s1.Interval | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	validRectLatRange = r1.Interval{-math.Pi / 2, math.Pi / 2} | ||||
| 	validRectLngRange = s1.FullInterval() | ||||
| ) | ||||
| 
 | ||||
| // EmptyRect returns the empty rectangle. | ||||
| func EmptyRect() Rect { return Rect{r1.EmptyInterval(), s1.EmptyInterval()} } | ||||
| 
 | ||||
| // FullRect returns the full rectangle. | ||||
| func FullRect() Rect { return Rect{validRectLatRange, validRectLngRange} } | ||||
| 
 | ||||
| // RectFromLatLng constructs a rectangle containing a single point p. | ||||
| func RectFromLatLng(p LatLng) Rect { | ||||
| 	return Rect{ | ||||
| 		Lat: r1.Interval{p.Lat.Radians(), p.Lat.Radians()}, | ||||
| 		Lng: s1.Interval{p.Lng.Radians(), p.Lng.Radians()}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // RectFromCenterSize constructs a rectangle with the given size and center. | ||||
| // center needs to be normalized, but size does not. The latitude | ||||
| // interval of the result is clamped to [-90,90] degrees, and the longitude | ||||
| // interval of the result is FullRect() if and only if the longitude size is | ||||
| // 360 degrees or more. | ||||
| // | ||||
| // Examples of clamping (in degrees): | ||||
| //   center=(80,170),  size=(40,60)   -> lat=[60,90],   lng=[140,-160] | ||||
| //   center=(10,40),   size=(210,400) -> lat=[-90,90],  lng=[-180,180] | ||||
| //   center=(-90,180), size=(20,50)   -> lat=[-90,-80], lng=[155,-155] | ||||
| func RectFromCenterSize(center, size LatLng) Rect { | ||||
| 	half := LatLng{size.Lat / 2, size.Lng / 2} | ||||
| 	return RectFromLatLng(center).expanded(half) | ||||
| } | ||||
| 
 | ||||
| // IsValid returns true iff the rectangle is valid. | ||||
| // This requires Lat ⊆ [-π/2,π/2] and Lng ⊆ [-π,π], and Lat = ∅ iff Lng = ∅ | ||||
| func (r Rect) IsValid() bool { | ||||
| 	return math.Abs(r.Lat.Lo) <= math.Pi/2 && | ||||
| 		math.Abs(r.Lat.Hi) <= math.Pi/2 && | ||||
| 		r.Lng.IsValid() && | ||||
| 		r.Lat.IsEmpty() == r.Lng.IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // IsEmpty reports whether the rectangle is empty. | ||||
| func (r Rect) IsEmpty() bool { return r.Lat.IsEmpty() } | ||||
| 
 | ||||
| // IsFull reports whether the rectangle is full. | ||||
| func (r Rect) IsFull() bool { return r.Lat.Equal(validRectLatRange) && r.Lng.IsFull() } | ||||
| 
 | ||||
| // IsPoint reports whether the rectangle is a single point. | ||||
| func (r Rect) IsPoint() bool { return r.Lat.Lo == r.Lat.Hi && r.Lng.Lo == r.Lng.Hi } | ||||
| 
 | ||||
| // Vertex returns the i-th vertex of the rectangle (i = 0,1,2,3) in CCW order | ||||
| // (lower left, lower right, upper right, upper left). | ||||
| func (r Rect) Vertex(i int) LatLng { | ||||
| 	var lat, lng float64 | ||||
| 
 | ||||
| 	switch i { | ||||
| 	case 0: | ||||
| 		lat = r.Lat.Lo | ||||
| 		lng = r.Lng.Lo | ||||
| 	case 1: | ||||
| 		lat = r.Lat.Lo | ||||
| 		lng = r.Lng.Hi | ||||
| 	case 2: | ||||
| 		lat = r.Lat.Hi | ||||
| 		lng = r.Lng.Hi | ||||
| 	case 3: | ||||
| 		lat = r.Lat.Hi | ||||
| 		lng = r.Lng.Lo | ||||
| 	} | ||||
| 	return LatLng{s1.Angle(lat) * s1.Radian, s1.Angle(lng) * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // Lo returns one corner of the rectangle. | ||||
| func (r Rect) Lo() LatLng { | ||||
| 	return LatLng{s1.Angle(r.Lat.Lo) * s1.Radian, s1.Angle(r.Lng.Lo) * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // Hi returns the other corner of the rectangle. | ||||
| func (r Rect) Hi() LatLng { | ||||
| 	return LatLng{s1.Angle(r.Lat.Hi) * s1.Radian, s1.Angle(r.Lng.Hi) * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // Center returns the center of the rectangle. | ||||
| func (r Rect) Center() LatLng { | ||||
| 	return LatLng{s1.Angle(r.Lat.Center()) * s1.Radian, s1.Angle(r.Lng.Center()) * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // Size returns the size of the Rect. | ||||
| func (r Rect) Size() LatLng { | ||||
| 	return LatLng{s1.Angle(r.Lat.Length()) * s1.Radian, s1.Angle(r.Lng.Length()) * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // Area returns the surface area of the Rect. | ||||
| func (r Rect) Area() float64 { | ||||
| 	if r.IsEmpty() { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	capDiff := math.Abs(math.Sin(r.Lat.Hi) - math.Sin(r.Lat.Lo)) | ||||
| 	return r.Lng.Length() * capDiff | ||||
| } | ||||
| 
 | ||||
| // AddPoint increases the size of the rectangle to include the given point. | ||||
| func (r Rect) AddPoint(ll LatLng) Rect { | ||||
| 	if !ll.IsValid() { | ||||
| 		return r | ||||
| 	} | ||||
| 	return Rect{ | ||||
| 		Lat: r.Lat.AddPoint(ll.Lat.Radians()), | ||||
| 		Lng: r.Lng.AddPoint(ll.Lng.Radians()), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // expanded returns a rectangle that has been expanded by margin.Lat on each side | ||||
| // in the latitude direction, and by margin.Lng on each side in the longitude | ||||
| // direction. If either margin is negative, then it shrinks the rectangle on | ||||
| // the corresponding sides instead. The resulting rectangle may be empty. | ||||
| // | ||||
| // The latitude-longitude space has the topology of a cylinder. Longitudes | ||||
| // "wrap around" at +/-180 degrees, while latitudes are clamped to range [-90, 90]. | ||||
| // This means that any expansion (positive or negative) of the full longitude range | ||||
| // remains full (since the "rectangle" is actually a continuous band around the | ||||
| // cylinder), while expansion of the full latitude range remains full only if the | ||||
| // margin is positive. | ||||
| // | ||||
| // If either the latitude or longitude interval becomes empty after | ||||
| // expansion by a negative margin, the result is empty. | ||||
| // | ||||
| // Note that if an expanded rectangle contains a pole, it may not contain | ||||
| // all possible lat/lng representations of that pole, e.g., both points [π/2,0] | ||||
| // and [π/2,1] represent the same pole, but they might not be contained by the | ||||
| // same Rect. | ||||
| // | ||||
| // If you are trying to grow a rectangle by a certain distance on the | ||||
| // sphere (e.g. 5km), refer to the ExpandedByDistance() C++ method implementation | ||||
| // instead. | ||||
| func (r Rect) expanded(margin LatLng) Rect { | ||||
| 	lat := r.Lat.Expanded(margin.Lat.Radians()) | ||||
| 	lng := r.Lng.Expanded(margin.Lng.Radians()) | ||||
| 
 | ||||
| 	if lat.IsEmpty() || lng.IsEmpty() { | ||||
| 		return EmptyRect() | ||||
| 	} | ||||
| 
 | ||||
| 	return Rect{ | ||||
| 		Lat: lat.Intersection(validRectLatRange), | ||||
| 		Lng: lng, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r Rect) String() string { return fmt.Sprintf("[Lo%v, Hi%v]", r.Lo(), r.Hi()) } | ||||
| 
 | ||||
| // PolarClosure returns the rectangle unmodified if it does not include either pole. | ||||
| // If it includes either pole, PolarClosure returns an expansion of the rectangle along | ||||
| // the longitudinal range to include all possible representations of the contained poles. | ||||
| func (r Rect) PolarClosure() Rect { | ||||
| 	if r.Lat.Lo == -math.Pi/2 || r.Lat.Hi == math.Pi/2 { | ||||
| 		return Rect{r.Lat, s1.FullInterval()} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // Union returns the smallest Rect containing the union of this rectangle and the given rectangle. | ||||
| func (r Rect) Union(other Rect) Rect { | ||||
| 	return Rect{ | ||||
| 		Lat: r.Lat.Union(other.Lat), | ||||
| 		Lng: r.Lng.Union(other.Lng), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Intersection returns the smallest rectangle containing the intersection of | ||||
| // this rectangle and the given rectangle. Note that the region of intersection | ||||
| // may consist of two disjoint rectangles, in which case a single rectangle | ||||
| // spanning both of them is returned. | ||||
| func (r Rect) Intersection(other Rect) Rect { | ||||
| 	lat := r.Lat.Intersection(other.Lat) | ||||
| 	lng := r.Lng.Intersection(other.Lng) | ||||
| 
 | ||||
| 	if lat.IsEmpty() || lng.IsEmpty() { | ||||
| 		return EmptyRect() | ||||
| 	} | ||||
| 	return Rect{lat, lng} | ||||
| } | ||||
| 
 | ||||
| // Intersects reports whether this rectangle and the other have any points in common. | ||||
| func (r Rect) Intersects(other Rect) bool { | ||||
| 	return r.Lat.Intersects(other.Lat) && r.Lng.Intersects(other.Lng) | ||||
| } | ||||
| 
 | ||||
| // CapBound returns a cap that contains Rect. | ||||
| func (r Rect) CapBound() Cap { | ||||
| 	// We consider two possible bounding caps, one whose axis passes | ||||
| 	// through the center of the lat-long rectangle and one whose axis | ||||
| 	// is the north or south pole.  We return the smaller of the two caps. | ||||
| 
 | ||||
| 	if r.IsEmpty() { | ||||
| 		return EmptyCap() | ||||
| 	} | ||||
| 
 | ||||
| 	var poleZ, poleAngle float64 | ||||
| 	if r.Lat.Hi+r.Lat.Lo < 0 { | ||||
| 		// South pole axis yields smaller cap. | ||||
| 		poleZ = -1 | ||||
| 		poleAngle = math.Pi/2 + r.Lat.Hi | ||||
| 	} else { | ||||
| 		poleZ = 1 | ||||
| 		poleAngle = math.Pi/2 - r.Lat.Lo | ||||
| 	} | ||||
| 	poleCap := CapFromCenterAngle(Point{r3.Vector{0, 0, poleZ}}, s1.Angle(poleAngle)*s1.Radian) | ||||
| 
 | ||||
| 	// For bounding rectangles that span 180 degrees or less in longitude, the | ||||
| 	// maximum cap size is achieved at one of the rectangle vertices.  For | ||||
| 	// rectangles that are larger than 180 degrees, we punt and always return a | ||||
| 	// bounding cap centered at one of the two poles. | ||||
| 	if math.Remainder(r.Lng.Hi-r.Lng.Lo, 2*math.Pi) >= 0 && r.Lng.Hi-r.Lng.Lo < 2*math.Pi { | ||||
| 		midCap := CapFromPoint(PointFromLatLng(r.Center())).AddPoint(PointFromLatLng(r.Lo())).AddPoint(PointFromLatLng(r.Hi())) | ||||
| 		if midCap.Height() < poleCap.Height() { | ||||
| 			return midCap | ||||
| 		} | ||||
| 	} | ||||
| 	return poleCap | ||||
| } | ||||
| 
 | ||||
| // RectBound returns itself. | ||||
| func (r Rect) RectBound() Rect { | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // Contains reports whether this Rect contains the other Rect. | ||||
| func (r Rect) Contains(other Rect) bool { | ||||
| 	return r.Lat.ContainsInterval(other.Lat) && r.Lng.ContainsInterval(other.Lng) | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether the given Cell is contained by this Rect. | ||||
| func (r Rect) ContainsCell(c Cell) bool { | ||||
| 	// A latitude-longitude rectangle contains a cell if and only if it contains | ||||
| 	// the cell's bounding rectangle. This test is exact from a mathematical | ||||
| 	// point of view, assuming that the bounds returned by Cell.RectBound() | ||||
| 	// are tight. However, note that there can be a loss of precision when | ||||
| 	// converting between representations -- for example, if an s2.Cell is | ||||
| 	// converted to a polygon, the polygon's bounding rectangle may not contain | ||||
| 	// the cell's bounding rectangle. This has some slightly unexpected side | ||||
| 	// effects; for instance, if one creates an s2.Polygon from an s2.Cell, the | ||||
| 	// polygon will contain the cell, but the polygon's bounding box will not. | ||||
| 	return r.Contains(c.RectBound()) | ||||
| } | ||||
| 
 | ||||
| // ContainsLatLng reports whether the given LatLng is within the Rect. | ||||
| func (r Rect) ContainsLatLng(ll LatLng) bool { | ||||
| 	if !ll.IsValid() { | ||||
| 		return false | ||||
| 	} | ||||
| 	return r.Lat.Contains(ll.Lat.Radians()) && r.Lng.Contains(ll.Lng.Radians()) | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether the given Point is within the Rect. | ||||
| func (r Rect) ContainsPoint(p Point) bool { | ||||
| 	return r.ContainsLatLng(LatLngFromPoint(p)) | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the Rect. | ||||
| func (r Rect) CellUnionBound() []CellID { | ||||
| 	return r.CapBound().CellUnionBound() | ||||
| } | ||||
| 
 | ||||
| // intersectsLatEdge reports whether the edge AB intersects the given edge of constant | ||||
| // latitude. Requires the points to have unit length. | ||||
| func intersectsLatEdge(a, b Point, lat s1.Angle, lng s1.Interval) bool { | ||||
| 	// Unfortunately, lines of constant latitude are curves on | ||||
| 	// the sphere. They can intersect a straight edge in 0, 1, or 2 points. | ||||
| 
 | ||||
| 	// First, compute the normal to the plane AB that points vaguely north. | ||||
| 	z := Point{a.PointCross(b).Normalize()} | ||||
| 	if z.Z < 0 { | ||||
| 		z = Point{z.Mul(-1)} | ||||
| 	} | ||||
| 
 | ||||
| 	// Extend this to an orthonormal frame (x,y,z) where x is the direction | ||||
| 	// where the great circle through AB achieves its maximium latitude. | ||||
| 	y := Point{z.PointCross(PointFromCoords(0, 0, 1)).Normalize()} | ||||
| 	x := y.Cross(z.Vector) | ||||
| 
 | ||||
| 	// Compute the angle "theta" from the x-axis (in the x-y plane defined | ||||
| 	// above) where the great circle intersects the given line of latitude. | ||||
| 	sinLat := math.Sin(float64(lat)) | ||||
| 	if math.Abs(sinLat) >= x.Z { | ||||
| 		// The great circle does not reach the given latitude. | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	cosTheta := sinLat / x.Z | ||||
| 	sinTheta := math.Sqrt(1 - cosTheta*cosTheta) | ||||
| 	theta := math.Atan2(sinTheta, cosTheta) | ||||
| 
 | ||||
| 	// The candidate intersection points are located +/- theta in the x-y | ||||
| 	// plane. For an intersection to be valid, we need to check that the | ||||
| 	// intersection point is contained in the interior of the edge AB and | ||||
| 	// also that it is contained within the given longitude interval "lng". | ||||
| 
 | ||||
| 	// Compute the range of theta values spanned by the edge AB. | ||||
| 	abTheta := s1.IntervalFromPointPair( | ||||
| 		math.Atan2(a.Dot(y.Vector), a.Dot(x)), | ||||
| 		math.Atan2(b.Dot(y.Vector), b.Dot(x))) | ||||
| 
 | ||||
| 	if abTheta.Contains(theta) { | ||||
| 		// Check if the intersection point is also in the given lng interval. | ||||
| 		isect := x.Mul(cosTheta).Add(y.Mul(sinTheta)) | ||||
| 		if lng.Contains(math.Atan2(isect.Y, isect.X)) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if abTheta.Contains(-theta) { | ||||
| 		// Check if the other intersection point is also in the given lng interval. | ||||
| 		isect := x.Mul(cosTheta).Sub(y.Mul(sinTheta)) | ||||
| 		if lng.Contains(math.Atan2(isect.Y, isect.X)) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // intersectsLngEdge reports whether the edge AB intersects the given edge of constant | ||||
| // longitude. Requires the points to have unit length. | ||||
| func intersectsLngEdge(a, b Point, lat r1.Interval, lng s1.Angle) bool { | ||||
| 	// The nice thing about edges of constant longitude is that | ||||
| 	// they are straight lines on the sphere (geodesics). | ||||
| 	return CrossingSign(a, b, PointFromLatLng(LatLng{s1.Angle(lat.Lo), lng}), | ||||
| 		PointFromLatLng(LatLng{s1.Angle(lat.Hi), lng})) == Cross | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether this rectangle intersects the given cell. This is an | ||||
| // exact test and may be fairly expensive. | ||||
| func (r Rect) IntersectsCell(c Cell) bool { | ||||
| 	// First we eliminate the cases where one region completely contains the | ||||
| 	// other. Once these are disposed of, then the regions will intersect | ||||
| 	// if and only if their boundaries intersect. | ||||
| 	if r.IsEmpty() { | ||||
| 		return false | ||||
| 	} | ||||
| 	if r.ContainsPoint(Point{c.id.rawPoint()}) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if c.ContainsPoint(PointFromLatLng(r.Center())) { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	// Quick rejection test (not required for correctness). | ||||
| 	if !r.Intersects(c.RectBound()) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Precompute the cell vertices as points and latitude-longitudes. We also | ||||
| 	// check whether the Cell contains any corner of the rectangle, or | ||||
| 	// vice-versa, since the edge-crossing tests only check the edge interiors. | ||||
| 	vertices := [4]Point{} | ||||
| 	latlngs := [4]LatLng{} | ||||
| 
 | ||||
| 	for i := range vertices { | ||||
| 		vertices[i] = c.Vertex(i) | ||||
| 		latlngs[i] = LatLngFromPoint(vertices[i]) | ||||
| 		if r.ContainsLatLng(latlngs[i]) { | ||||
| 			return true | ||||
| 		} | ||||
| 		if c.ContainsPoint(PointFromLatLng(r.Vertex(i))) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Now check whether the boundaries intersect. Unfortunately, a | ||||
| 	// latitude-longitude rectangle does not have straight edges: two edges | ||||
| 	// are curved, and at least one of them is concave. | ||||
| 	for i := range vertices { | ||||
| 		edgeLng := s1.IntervalFromEndpoints(latlngs[i].Lng.Radians(), latlngs[(i+1)&3].Lng.Radians()) | ||||
| 		if !r.Lng.Intersects(edgeLng) { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		a := vertices[i] | ||||
| 		b := vertices[(i+1)&3] | ||||
| 		if edgeLng.Contains(r.Lng.Lo) && intersectsLngEdge(a, b, r.Lat, s1.Angle(r.Lng.Lo)) { | ||||
| 			return true | ||||
| 		} | ||||
| 		if edgeLng.Contains(r.Lng.Hi) && intersectsLngEdge(a, b, r.Lat, s1.Angle(r.Lng.Hi)) { | ||||
| 			return true | ||||
| 		} | ||||
| 		if intersectsLatEdge(a, b, s1.Angle(r.Lat.Lo), r.Lng) { | ||||
| 			return true | ||||
| 		} | ||||
| 		if intersectsLatEdge(a, b, s1.Angle(r.Lat.Hi), r.Lng) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Encode encodes the Rect. | ||||
| func (r Rect) Encode(w io.Writer) error { | ||||
| 	e := &encoder{w: w} | ||||
| 	r.encode(e) | ||||
| 	return e.err | ||||
| } | ||||
| 
 | ||||
| func (r Rect) encode(e *encoder) { | ||||
| 	e.writeInt8(encodingVersion) | ||||
| 	e.writeFloat64(r.Lat.Lo) | ||||
| 	e.writeFloat64(r.Lat.Hi) | ||||
| 	e.writeFloat64(r.Lng.Lo) | ||||
| 	e.writeFloat64(r.Lng.Hi) | ||||
| } | ||||
| 
 | ||||
| // Decode decodes a rectangle. | ||||
| func (r *Rect) Decode(rd io.Reader) error { | ||||
| 	d := &decoder{r: asByteReader(rd)} | ||||
| 	r.decode(d) | ||||
| 	return d.err | ||||
| } | ||||
| 
 | ||||
| func (r *Rect) decode(d *decoder) { | ||||
| 	if version := d.readUint8(); int8(version) != encodingVersion && d.err == nil { | ||||
| 		d.err = fmt.Errorf("can't decode version %d; my version: %d", version, encodingVersion) | ||||
| 		return | ||||
| 	} | ||||
| 	r.Lat.Lo = d.readFloat64() | ||||
| 	r.Lat.Hi = d.readFloat64() | ||||
| 	r.Lng.Lo = d.readFloat64() | ||||
| 	r.Lng.Hi = d.readFloat64() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DistanceToLatLng returns the minimum distance (measured along the surface of the sphere) | ||||
| // from a given point to the rectangle (both its boundary and its interior). | ||||
| // If r is empty, the result is meaningless. | ||||
| // The latlng must be valid. | ||||
| func (r Rect) DistanceToLatLng(ll LatLng) s1.Angle { | ||||
| 	if r.Lng.Contains(float64(ll.Lng)) { | ||||
| 		return maxAngle(0, ll.Lat-s1.Angle(r.Lat.Hi), s1.Angle(r.Lat.Lo)-ll.Lat) | ||||
| 	} | ||||
| 
 | ||||
| 	i := s1.IntervalFromEndpoints(r.Lng.Hi, r.Lng.ComplementCenter()) | ||||
| 	rectLng := r.Lng.Lo | ||||
| 	if i.Contains(float64(ll.Lng)) { | ||||
| 		rectLng = r.Lng.Hi | ||||
| 	} | ||||
| 
 | ||||
| 	lo := LatLng{s1.Angle(r.Lat.Lo) * s1.Radian, s1.Angle(rectLng) * s1.Radian} | ||||
| 	hi := LatLng{s1.Angle(r.Lat.Hi) * s1.Radian, s1.Angle(rectLng) * s1.Radian} | ||||
| 	return DistanceFromSegment(PointFromLatLng(ll), PointFromLatLng(lo), PointFromLatLng(hi)) | ||||
| } | ||||
| 
 | ||||
| // DirectedHausdorffDistance returns the directed Hausdorff distance (measured along the | ||||
| // surface of the sphere) to the given Rect. The directed Hausdorff | ||||
| // distance from rectangle A to rectangle B is given by | ||||
| //     h(A, B) = max_{p in A} min_{q in B} d(p, q). | ||||
| func (r Rect) DirectedHausdorffDistance(other Rect) s1.Angle { | ||||
| 	if r.IsEmpty() { | ||||
| 		return 0 * s1.Radian | ||||
| 	} | ||||
| 	if other.IsEmpty() { | ||||
| 		return math.Pi * s1.Radian | ||||
| 	} | ||||
| 
 | ||||
| 	lng := r.Lng.DirectedHausdorffDistance(other.Lng) | ||||
| 	return directedHausdorffDistance(lng, r.Lat, other.Lat) | ||||
| } | ||||
| 
 | ||||
| // HausdorffDistance returns the undirected Hausdorff distance (measured along the | ||||
| // surface of the sphere) to the given Rect. | ||||
| // The Hausdorff distance between rectangle A and rectangle B is given by | ||||
| //     H(A, B) = max{h(A, B), h(B, A)}. | ||||
| func (r Rect) HausdorffDistance(other Rect) s1.Angle { | ||||
| 	return maxAngle(r.DirectedHausdorffDistance(other), | ||||
| 		other.DirectedHausdorffDistance(r)) | ||||
| } | ||||
| 
 | ||||
| // ApproxEqual reports whether the latitude and longitude intervals of the two rectangles | ||||
| // are the same up to a small tolerance. | ||||
| func (r Rect) ApproxEqual(other Rect) bool { | ||||
| 	return r.Lat.ApproxEqual(other.Lat) && r.Lng.ApproxEqual(other.Lng) | ||||
| } | ||||
| 
 | ||||
| // directedHausdorffDistance returns the directed Hausdorff distance | ||||
| // from one longitudinal edge spanning latitude range 'a' to the other | ||||
| // longitudinal edge spanning latitude range 'b', with their longitudinal | ||||
| // difference given by 'lngDiff'. | ||||
| func directedHausdorffDistance(lngDiff s1.Angle, a, b r1.Interval) s1.Angle { | ||||
| 	// By symmetry, we can assume a's longitude is 0 and b's longitude is | ||||
| 	// lngDiff. Call b's two endpoints bLo and bHi. Let H be the hemisphere | ||||
| 	// containing a and delimited by the longitude line of b. The Voronoi diagram | ||||
| 	// of b on H has three edges (portions of great circles) all orthogonal to b | ||||
| 	// and meeting at bLo cross bHi. | ||||
| 	// E1: (bLo, bLo cross bHi) | ||||
| 	// E2: (bHi, bLo cross bHi) | ||||
| 	// E3: (-bMid, bLo cross bHi), where bMid is the midpoint of b | ||||
| 	// | ||||
| 	// They subdivide H into three Voronoi regions. Depending on how longitude 0 | ||||
| 	// (which contains edge a) intersects these regions, we distinguish two cases: | ||||
| 	// Case 1: it intersects three regions. This occurs when lngDiff <= π/2. | ||||
| 	// Case 2: it intersects only two regions. This occurs when lngDiff > π/2. | ||||
| 	// | ||||
| 	// In the first case, the directed Hausdorff distance to edge b can only be | ||||
| 	// realized by the following points on a: | ||||
| 	// A1: two endpoints of a. | ||||
| 	// A2: intersection of a with the equator, if b also intersects the equator. | ||||
| 	// | ||||
| 	// In the second case, the directed Hausdorff distance to edge b can only be | ||||
| 	// realized by the following points on a: | ||||
| 	// B1: two endpoints of a. | ||||
| 	// B2: intersection of a with E3 | ||||
| 	// B3: farthest point from bLo to the interior of D, and farthest point from | ||||
| 	//     bHi to the interior of U, if any, where D (resp. U) is the portion | ||||
| 	//     of edge a below (resp. above) the intersection point from B2. | ||||
| 
 | ||||
| 	if lngDiff < 0 { | ||||
| 		panic("impossible: negative lngDiff") | ||||
| 	} | ||||
| 	if lngDiff > math.Pi { | ||||
| 		panic("impossible: lngDiff > Pi") | ||||
| 	} | ||||
| 
 | ||||
| 	if lngDiff == 0 { | ||||
| 		return s1.Angle(a.DirectedHausdorffDistance(b)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Assumed longitude of b. | ||||
| 	bLng := lngDiff | ||||
| 	// Two endpoints of b. | ||||
| 	bLo := PointFromLatLng(LatLng{s1.Angle(b.Lo), bLng}) | ||||
| 	bHi := PointFromLatLng(LatLng{s1.Angle(b.Hi), bLng}) | ||||
| 
 | ||||
| 	// Cases A1 and B1. | ||||
| 	aLo := PointFromLatLng(LatLng{s1.Angle(a.Lo), 0}) | ||||
| 	aHi := PointFromLatLng(LatLng{s1.Angle(a.Hi), 0}) | ||||
| 	maxDistance := maxAngle( | ||||
| 		DistanceFromSegment(aLo, bLo, bHi), | ||||
| 		DistanceFromSegment(aHi, bLo, bHi)) | ||||
| 
 | ||||
| 	if lngDiff <= math.Pi/2 { | ||||
| 		// Case A2. | ||||
| 		if a.Contains(0) && b.Contains(0) { | ||||
| 			maxDistance = maxAngle(maxDistance, lngDiff) | ||||
| 		} | ||||
| 		return maxDistance | ||||
| 	} | ||||
| 
 | ||||
| 	// Case B2. | ||||
| 	p := bisectorIntersection(b, bLng) | ||||
| 	pLat := LatLngFromPoint(p).Lat | ||||
| 	if a.Contains(float64(pLat)) { | ||||
| 		maxDistance = maxAngle(maxDistance, p.Angle(bLo.Vector)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Case B3. | ||||
| 	if pLat > s1.Angle(a.Lo) { | ||||
| 		intDist, ok := interiorMaxDistance(r1.Interval{a.Lo, math.Min(float64(pLat), a.Hi)}, bLo) | ||||
| 		if ok { | ||||
| 			maxDistance = maxAngle(maxDistance, intDist) | ||||
| 		} | ||||
| 	} | ||||
| 	if pLat < s1.Angle(a.Hi) { | ||||
| 		intDist, ok := interiorMaxDistance(r1.Interval{math.Max(float64(pLat), a.Lo), a.Hi}, bHi) | ||||
| 		if ok { | ||||
| 			maxDistance = maxAngle(maxDistance, intDist) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return maxDistance | ||||
| } | ||||
| 
 | ||||
| // interiorMaxDistance returns the max distance from a point b to the segment spanning latitude range | ||||
| // aLat on longitude 0 if the max occurs in the interior of aLat. Otherwise, returns (0, false). | ||||
| func interiorMaxDistance(aLat r1.Interval, b Point) (a s1.Angle, ok bool) { | ||||
| 	// Longitude 0 is in the y=0 plane. b.X >= 0 implies that the maximum | ||||
| 	// does not occur in the interior of aLat. | ||||
| 	if aLat.IsEmpty() || b.X >= 0 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 
 | ||||
| 	// Project b to the y=0 plane. The antipodal of the normalized projection is | ||||
| 	// the point at which the maxium distance from b occurs, if it is contained | ||||
| 	// in aLat. | ||||
| 	intersectionPoint := PointFromCoords(-b.X, 0, -b.Z) | ||||
| 	if !aLat.InteriorContains(float64(LatLngFromPoint(intersectionPoint).Lat)) { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return b.Angle(intersectionPoint.Vector), true | ||||
| } | ||||
| 
 | ||||
| // bisectorIntersection return the intersection of longitude 0 with the bisector of an edge | ||||
| // on longitude 'lng' and spanning latitude range 'lat'. | ||||
| func bisectorIntersection(lat r1.Interval, lng s1.Angle) Point { | ||||
| 	lng = s1.Angle(math.Abs(float64(lng))) | ||||
| 	latCenter := s1.Angle(lat.Center()) | ||||
| 
 | ||||
| 	// A vector orthogonal to the bisector of the given longitudinal edge. | ||||
| 	orthoBisector := LatLng{latCenter - math.Pi/2, lng} | ||||
| 	if latCenter < 0 { | ||||
| 		orthoBisector = LatLng{-latCenter - math.Pi/2, lng - math.Pi} | ||||
| 	} | ||||
| 
 | ||||
| 	// A vector orthogonal to longitude 0. | ||||
| 	orthoLng := Point{r3.Vector{0, -1, 0}} | ||||
| 
 | ||||
| 	return orthoLng.PointCross(PointFromLatLng(orthoBisector)) | ||||
| } | ||||
| 
 | ||||
| // Centroid returns the true centroid of the given Rect multiplied by its | ||||
| // surface area. The result is not unit length, so you may want to normalize it. | ||||
| // Note that in general the centroid is *not* at the center of the rectangle, and | ||||
| // in fact it may not even be contained by the rectangle. (It is the "center of | ||||
| // mass" of the rectangle viewed as subset of the unit sphere, i.e. it is the | ||||
| // point in space about which this curved shape would rotate.) | ||||
| // | ||||
| // The reason for multiplying the result by the rectangle area is to make it | ||||
| // easier to compute the centroid of more complicated shapes. The centroid | ||||
| // of a union of disjoint regions can be computed simply by adding their | ||||
| // Centroid results. | ||||
| func (r Rect) Centroid() Point { | ||||
| 	// When a sphere is divided into slices of constant thickness by a set | ||||
| 	// of parallel planes, all slices have the same surface area. This | ||||
| 	// implies that the z-component of the centroid is simply the midpoint | ||||
| 	// of the z-interval spanned by the Rect. | ||||
| 	// | ||||
| 	// Similarly, it is easy to see that the (x,y) of the centroid lies in | ||||
| 	// the plane through the midpoint of the rectangle's longitude interval. | ||||
| 	// We only need to determine the distance "d" of this point from the | ||||
| 	// z-axis. | ||||
| 	// | ||||
| 	// Let's restrict our attention to a particular z-value. In this | ||||
| 	// z-plane, the Rect is a circular arc. The centroid of this arc | ||||
| 	// lies on a radial line through the midpoint of the arc, and at a | ||||
| 	// distance from the z-axis of | ||||
| 	// | ||||
| 	//     r * (sin(alpha) / alpha) | ||||
| 	// | ||||
| 	// where r = sqrt(1-z^2) is the radius of the arc, and "alpha" is half | ||||
| 	// of the arc length (i.e., the arc covers longitudes [-alpha, alpha]). | ||||
| 	// | ||||
| 	// To find the centroid distance from the z-axis for the entire | ||||
| 	// rectangle, we just need to integrate over the z-interval. This gives | ||||
| 	// | ||||
| 	//    d = Integrate[sqrt(1-z^2)*sin(alpha)/alpha, z1..z2] / (z2 - z1) | ||||
| 	// | ||||
| 	// where [z1, z2] is the range of z-values covered by the rectangle. | ||||
| 	// This simplifies to | ||||
| 	// | ||||
| 	//    d = sin(alpha)/(2*alpha*(z2-z1))*(z2*r2 - z1*r1 + theta2 - theta1) | ||||
| 	// | ||||
| 	// where [theta1, theta2] is the latitude interval, z1=sin(theta1), | ||||
| 	// z2=sin(theta2), r1=cos(theta1), and r2=cos(theta2). | ||||
| 	// | ||||
| 	// Finally, we want to return not the centroid itself, but the centroid | ||||
| 	// scaled by the area of the rectangle. The area of the rectangle is | ||||
| 	// | ||||
| 	//    A = 2 * alpha * (z2 - z1) | ||||
| 	// | ||||
| 	// which fortunately appears in the denominator of "d". | ||||
| 
 | ||||
| 	if r.IsEmpty() { | ||||
| 		return Point{} | ||||
| 	} | ||||
| 
 | ||||
| 	z1 := math.Sin(r.Lat.Lo) | ||||
| 	z2 := math.Sin(r.Lat.Hi) | ||||
| 	r1 := math.Cos(r.Lat.Lo) | ||||
| 	r2 := math.Cos(r.Lat.Hi) | ||||
| 
 | ||||
| 	alpha := 0.5 * r.Lng.Length() | ||||
| 	r0 := math.Sin(alpha) * (r2*z2 - r1*z1 + r.Lat.Length()) | ||||
| 	lng := r.Lng.Center() | ||||
| 	z := alpha * (z2 + z1) * (z2 - z1) // scaled by the area | ||||
| 
 | ||||
| 	return Point{r3.Vector{r0 * math.Cos(lng), r0 * math.Sin(lng), z}} | ||||
| } | ||||
| 
 | ||||
| // BUG: The major differences from the C++ version are: | ||||
| //  - Get*Distance, Vertex, InteriorContains(LatLng|Rect|Point) | ||||
							
								
								
									
										352
									
								
								vendor/github.com/golang/geo/s2/rect_bounder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										352
									
								
								vendor/github.com/golang/geo/s2/rect_bounder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,352 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r1" | ||||
| 	"github.com/golang/geo/r3" | ||||
| 	"github.com/golang/geo/s1" | ||||
| ) | ||||
| 
 | ||||
| // RectBounder is used to compute a bounding rectangle that contains all edges | ||||
| // defined by a vertex chain (v0, v1, v2, ...). All vertices must be unit length. | ||||
| // Note that the bounding rectangle of an edge can be larger than the bounding | ||||
| // rectangle of its endpoints, e.g. consider an edge that passes through the North Pole. | ||||
| // | ||||
| // The bounds are calculated conservatively to account for numerical errors | ||||
| // when points are converted to LatLngs. More precisely, this function | ||||
| // guarantees the following: | ||||
| // Let L be a closed edge chain (Loop) such that the interior of the loop does | ||||
| // not contain either pole. Now if P is any point such that L.ContainsPoint(P), | ||||
| // then RectBound(L).ContainsPoint(LatLngFromPoint(P)). | ||||
| type RectBounder struct { | ||||
| 	// The previous vertex in the chain. | ||||
| 	a Point | ||||
| 	// The previous vertex latitude longitude. | ||||
| 	aLL   LatLng | ||||
| 	bound Rect | ||||
| } | ||||
| 
 | ||||
| // NewRectBounder returns a new instance of a RectBounder. | ||||
| func NewRectBounder() *RectBounder { | ||||
| 	return &RectBounder{ | ||||
| 		bound: EmptyRect(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // maxErrorForTests returns the maximum error in RectBound provided that the | ||||
| // result does not include either pole. It is only used for testing purposes | ||||
| func (r *RectBounder) maxErrorForTests() LatLng { | ||||
| 	// The maximum error in the latitude calculation is | ||||
| 	//    3.84 * dblEpsilon   for the PointCross calculation | ||||
| 	//    0.96 * dblEpsilon   for the Latitude calculation | ||||
| 	//    5    * dblEpsilon   added by AddPoint/RectBound to compensate for error | ||||
| 	//    ----------------- | ||||
| 	//    9.80 * dblEpsilon   maximum error in result | ||||
| 	// | ||||
| 	// The maximum error in the longitude calculation is dblEpsilon. RectBound | ||||
| 	// does not do any expansion because this isn't necessary in order to | ||||
| 	// bound the *rounded* longitudes of contained points. | ||||
| 	return LatLng{10 * dblEpsilon * s1.Radian, 1 * dblEpsilon * s1.Radian} | ||||
| } | ||||
| 
 | ||||
| // AddPoint adds the given point to the chain. The Point must be unit length. | ||||
| func (r *RectBounder) AddPoint(b Point) { | ||||
| 	bLL := LatLngFromPoint(b) | ||||
| 
 | ||||
| 	if r.bound.IsEmpty() { | ||||
| 		r.a = b | ||||
| 		r.aLL = bLL | ||||
| 		r.bound = r.bound.AddPoint(bLL) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// First compute the cross product N = A x B robustly. This is the normal | ||||
| 	// to the great circle through A and B. We don't use RobustSign | ||||
| 	// since that method returns an arbitrary vector orthogonal to A if the two | ||||
| 	// vectors are proportional, and we want the zero vector in that case. | ||||
| 	n := r.a.Sub(b.Vector).Cross(r.a.Add(b.Vector)) // N = 2 * (A x B) | ||||
| 
 | ||||
| 	// The relative error in N gets large as its norm gets very small (i.e., | ||||
| 	// when the two points are nearly identical or antipodal). We handle this | ||||
| 	// by choosing a maximum allowable error, and if the error is greater than | ||||
| 	// this we fall back to a different technique. Since it turns out that | ||||
| 	// the other sources of error in converting the normal to a maximum | ||||
| 	// latitude add up to at most 1.16 * dblEpsilon, and it is desirable to | ||||
| 	// have the total error be a multiple of dblEpsilon, we have chosen to | ||||
| 	// limit the maximum error in the normal to be 3.84 * dblEpsilon. | ||||
| 	// It is possible to show that the error is less than this when | ||||
| 	// | ||||
| 	// n.Norm() >= 8 * sqrt(3) / (3.84 - 0.5 - sqrt(3)) * dblEpsilon | ||||
| 	//          = 1.91346e-15 (about 8.618 * dblEpsilon) | ||||
| 	nNorm := n.Norm() | ||||
| 	if nNorm < 1.91346e-15 { | ||||
| 		// A and B are either nearly identical or nearly antipodal (to within | ||||
| 		// 4.309 * dblEpsilon, or about 6 nanometers on the earth's surface). | ||||
| 		if r.a.Dot(b.Vector) < 0 { | ||||
| 			// The two points are nearly antipodal. The easiest solution is to | ||||
| 			// assume that the edge between A and B could go in any direction | ||||
| 			// around the sphere. | ||||
| 			r.bound = FullRect() | ||||
| 		} else { | ||||
| 			// The two points are nearly identical (to within 4.309 * dblEpsilon). | ||||
| 			// In this case we can just use the bounding rectangle of the points, | ||||
| 			// since after the expansion done by GetBound this Rect is | ||||
| 			// guaranteed to include the (lat,lng) values of all points along AB. | ||||
| 			r.bound = r.bound.Union(RectFromLatLng(r.aLL).AddPoint(bLL)) | ||||
| 		} | ||||
| 		r.a = b | ||||
| 		r.aLL = bLL | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute the longitude range spanned by AB. | ||||
| 	lngAB := s1.EmptyInterval().AddPoint(r.aLL.Lng.Radians()).AddPoint(bLL.Lng.Radians()) | ||||
| 	if lngAB.Length() >= math.Pi-2*dblEpsilon { | ||||
| 		// The points lie on nearly opposite lines of longitude to within the | ||||
| 		// maximum error of the calculation. The easiest solution is to assume | ||||
| 		// that AB could go on either side of the pole. | ||||
| 		lngAB = s1.FullInterval() | ||||
| 	} | ||||
| 
 | ||||
| 	// Next we compute the latitude range spanned by the edge AB. We start | ||||
| 	// with the range spanning the two endpoints of the edge: | ||||
| 	latAB := r1.IntervalFromPoint(r.aLL.Lat.Radians()).AddPoint(bLL.Lat.Radians()) | ||||
| 
 | ||||
| 	// This is the desired range unless the edge AB crosses the plane | ||||
| 	// through N and the Z-axis (which is where the great circle through A | ||||
| 	// and B attains its minimum and maximum latitudes). To test whether AB | ||||
| 	// crosses this plane, we compute a vector M perpendicular to this | ||||
| 	// plane and then project A and B onto it. | ||||
| 	m := n.Cross(r3.Vector{0, 0, 1}) | ||||
| 	mA := m.Dot(r.a.Vector) | ||||
| 	mB := m.Dot(b.Vector) | ||||
| 
 | ||||
| 	// We want to test the signs of "mA" and "mB", so we need to bound | ||||
| 	// the error in these calculations. It is possible to show that the | ||||
| 	// total error is bounded by | ||||
| 	// | ||||
| 	// (1 + sqrt(3)) * dblEpsilon * nNorm + 8 * sqrt(3) * (dblEpsilon**2) | ||||
| 	//   = 6.06638e-16 * nNorm + 6.83174e-31 | ||||
| 
 | ||||
| 	mError := 6.06638e-16*nNorm + 6.83174e-31 | ||||
| 	if mA*mB < 0 || math.Abs(mA) <= mError || math.Abs(mB) <= mError { | ||||
| 		// Minimum/maximum latitude *may* occur in the edge interior. | ||||
| 		// | ||||
| 		// The maximum latitude is 90 degrees minus the latitude of N. We | ||||
| 		// compute this directly using atan2 in order to get maximum accuracy | ||||
| 		// near the poles. | ||||
| 		// | ||||
| 		// Our goal is compute a bound that contains the computed latitudes of | ||||
| 		// all S2Points P that pass the point-in-polygon containment test. | ||||
| 		// There are three sources of error we need to consider: | ||||
| 		// - the directional error in N (at most 3.84 * dblEpsilon) | ||||
| 		// - converting N to a maximum latitude | ||||
| 		// - computing the latitude of the test point P | ||||
| 		// The latter two sources of error are at most 0.955 * dblEpsilon | ||||
| 		// individually, but it is possible to show by a more complex analysis | ||||
| 		// that together they can add up to at most 1.16 * dblEpsilon, for a | ||||
| 		// total error of 5 * dblEpsilon. | ||||
| 		// | ||||
| 		// We add 3 * dblEpsilon to the bound here, and GetBound() will pad | ||||
| 		// the bound by another 2 * dblEpsilon. | ||||
| 		maxLat := math.Min( | ||||
| 			math.Atan2(math.Sqrt(n.X*n.X+n.Y*n.Y), math.Abs(n.Z))+3*dblEpsilon, | ||||
| 			math.Pi/2) | ||||
| 
 | ||||
| 		// In order to get tight bounds when the two points are close together, | ||||
| 		// we also bound the min/max latitude relative to the latitudes of the | ||||
| 		// endpoints A and B. First we compute the distance between A and B, | ||||
| 		// and then we compute the maximum change in latitude between any two | ||||
| 		// points along the great circle that are separated by this distance. | ||||
| 		// This gives us a latitude change "budget". Some of this budget must | ||||
| 		// be spent getting from A to B; the remainder bounds the round-trip | ||||
| 		// distance (in latitude) from A or B to the min or max latitude | ||||
| 		// attained along the edge AB. | ||||
| 		latBudget := 2 * math.Asin(0.5*(r.a.Sub(b.Vector)).Norm()*math.Sin(maxLat)) | ||||
| 		maxDelta := 0.5*(latBudget-latAB.Length()) + dblEpsilon | ||||
| 
 | ||||
| 		// Test whether AB passes through the point of maximum latitude or | ||||
| 		// minimum latitude. If the dot product(s) are small enough then the | ||||
| 		// result may be ambiguous. | ||||
| 		if mA <= mError && mB >= -mError { | ||||
| 			latAB.Hi = math.Min(maxLat, latAB.Hi+maxDelta) | ||||
| 		} | ||||
| 		if mB <= mError && mA >= -mError { | ||||
| 			latAB.Lo = math.Max(-maxLat, latAB.Lo-maxDelta) | ||||
| 		} | ||||
| 	} | ||||
| 	r.a = b | ||||
| 	r.aLL = bLL | ||||
| 	r.bound = r.bound.Union(Rect{latAB, lngAB}) | ||||
| } | ||||
| 
 | ||||
| // RectBound returns the bounding rectangle of the edge chain that connects the | ||||
| // vertices defined so far. This bound satisfies the guarantee made | ||||
| // above, i.e. if the edge chain defines a Loop, then the bound contains | ||||
| // the LatLng coordinates of all Points contained by the loop. | ||||
| func (r *RectBounder) RectBound() Rect { | ||||
| 	return r.bound.expanded(LatLng{s1.Angle(2 * dblEpsilon), 0}).PolarClosure() | ||||
| } | ||||
| 
 | ||||
| // ExpandForSubregions expands a bounding Rect so that it is guaranteed to | ||||
| // contain the bounds of any subregion whose bounds are computed using | ||||
| // ComputeRectBound. For example, consider a loop L that defines a square. | ||||
| // GetBound ensures that if a point P is contained by this square, then | ||||
| // LatLngFromPoint(P) is contained by the bound. But now consider a diamond | ||||
| // shaped loop S contained by L. It is possible that GetBound returns a | ||||
| // *larger* bound for S than it does for L, due to rounding errors. This | ||||
| // method expands the bound for L so that it is guaranteed to contain the | ||||
| // bounds of any subregion S. | ||||
| // | ||||
| // More precisely, if L is a loop that does not contain either pole, and S | ||||
| // is a loop such that L.Contains(S), then | ||||
| // | ||||
| //   ExpandForSubregions(L.RectBound).Contains(S.RectBound). | ||||
| // | ||||
| func ExpandForSubregions(bound Rect) Rect { | ||||
| 	// Empty bounds don't need expansion. | ||||
| 	if bound.IsEmpty() { | ||||
| 		return bound | ||||
| 	} | ||||
| 
 | ||||
| 	// First we need to check whether the bound B contains any nearly-antipodal | ||||
| 	// points (to within 4.309 * dblEpsilon). If so then we need to return | ||||
| 	// FullRect, since the subregion might have an edge between two | ||||
| 	// such points, and AddPoint returns Full for such edges. Note that | ||||
| 	// this can happen even if B is not Full for example, consider a loop | ||||
| 	// that defines a 10km strip straddling the equator extending from | ||||
| 	// longitudes -100 to +100 degrees. | ||||
| 	// | ||||
| 	// It is easy to check whether B contains any antipodal points, but checking | ||||
| 	// for nearly-antipodal points is trickier. Essentially we consider the | ||||
| 	// original bound B and its reflection through the origin B', and then test | ||||
| 	// whether the minimum distance between B and B' is less than 4.309 * dblEpsilon. | ||||
| 
 | ||||
| 	// lngGap is a lower bound on the longitudinal distance between B and its | ||||
| 	// reflection B'. (2.5 * dblEpsilon is the maximum combined error of the | ||||
| 	// endpoint longitude calculations and the Length call.) | ||||
| 	lngGap := math.Max(0, math.Pi-bound.Lng.Length()-2.5*dblEpsilon) | ||||
| 
 | ||||
| 	// minAbsLat is the minimum distance from B to the equator (if zero or | ||||
| 	// negative, then B straddles the equator). | ||||
| 	minAbsLat := math.Max(bound.Lat.Lo, -bound.Lat.Hi) | ||||
| 
 | ||||
| 	// latGapSouth and latGapNorth measure the minimum distance from B to the | ||||
| 	// south and north poles respectively. | ||||
| 	latGapSouth := math.Pi/2 + bound.Lat.Lo | ||||
| 	latGapNorth := math.Pi/2 - bound.Lat.Hi | ||||
| 
 | ||||
| 	if minAbsLat >= 0 { | ||||
| 		// The bound B does not straddle the equator. In this case the minimum | ||||
| 		// distance is between one endpoint of the latitude edge in B closest to | ||||
| 		// the equator and the other endpoint of that edge in B'. The latitude | ||||
| 		// distance between these two points is 2*minAbsLat, and the longitude | ||||
| 		// distance is lngGap. We could compute the distance exactly using the | ||||
| 		// Haversine formula, but then we would need to bound the errors in that | ||||
| 		// calculation. Since we only need accuracy when the distance is very | ||||
| 		// small (close to 4.309 * dblEpsilon), we substitute the Euclidean | ||||
| 		// distance instead. This gives us a right triangle XYZ with two edges of | ||||
| 		// length x = 2*minAbsLat and y ~= lngGap. The desired distance is the | ||||
| 		// length of the third edge z, and we have | ||||
| 		// | ||||
| 		//         z  ~=  sqrt(x^2 + y^2)  >=  (x + y) / sqrt(2) | ||||
| 		// | ||||
| 		// Therefore the region may contain nearly antipodal points only if | ||||
| 		// | ||||
| 		//  2*minAbsLat + lngGap  <  sqrt(2) * 4.309 * dblEpsilon | ||||
| 		//                        ~= 1.354e-15 | ||||
| 		// | ||||
| 		// Note that because the given bound B is conservative, minAbsLat and | ||||
| 		// lngGap are both lower bounds on their true values so we do not need | ||||
| 		// to make any adjustments for their errors. | ||||
| 		if 2*minAbsLat+lngGap < 1.354e-15 { | ||||
| 			return FullRect() | ||||
| 		} | ||||
| 	} else if lngGap >= math.Pi/2 { | ||||
| 		// B spans at most Pi/2 in longitude. The minimum distance is always | ||||
| 		// between one corner of B and the diagonally opposite corner of B'. We | ||||
| 		// use the same distance approximation that we used above; in this case | ||||
| 		// we have an obtuse triangle XYZ with two edges of length x = latGapSouth | ||||
| 		// and y = latGapNorth, and angle Z >= Pi/2 between them. We then have | ||||
| 		// | ||||
| 		//         z  >=  sqrt(x^2 + y^2)  >=  (x + y) / sqrt(2) | ||||
| 		// | ||||
| 		// Unlike the case above, latGapSouth and latGapNorth are not lower bounds | ||||
| 		// (because of the extra addition operation, and because math.Pi/2 is not | ||||
| 		// exactly equal to Pi/2); they can exceed their true values by up to | ||||
| 		// 0.75 * dblEpsilon. Putting this all together, the region may contain | ||||
| 		// nearly antipodal points only if | ||||
| 		// | ||||
| 		//   latGapSouth + latGapNorth  <  (sqrt(2) * 4.309 + 1.5) * dblEpsilon | ||||
| 		//                              ~= 1.687e-15 | ||||
| 		if latGapSouth+latGapNorth < 1.687e-15 { | ||||
| 			return FullRect() | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Otherwise we know that (1) the bound straddles the equator and (2) its | ||||
| 		// width in longitude is at least Pi/2. In this case the minimum | ||||
| 		// distance can occur either between a corner of B and the diagonally | ||||
| 		// opposite corner of B' (as in the case above), or between a corner of B | ||||
| 		// and the opposite longitudinal edge reflected in B'. It is sufficient | ||||
| 		// to only consider the corner-edge case, since this distance is also a | ||||
| 		// lower bound on the corner-corner distance when that case applies. | ||||
| 
 | ||||
| 		// Consider the spherical triangle XYZ where X is a corner of B with | ||||
| 		// minimum absolute latitude, Y is the closest pole to X, and Z is the | ||||
| 		// point closest to X on the opposite longitudinal edge of B'. This is a | ||||
| 		// right triangle (Z = Pi/2), and from the spherical law of sines we have | ||||
| 		// | ||||
| 		//     sin(z) / sin(Z)  =  sin(y) / sin(Y) | ||||
| 		//     sin(maxLatGap) / 1  =  sin(dMin) / sin(lngGap) | ||||
| 		//     sin(dMin)  =  sin(maxLatGap) * sin(lngGap) | ||||
| 		// | ||||
| 		// where "maxLatGap" = max(latGapSouth, latGapNorth) and "dMin" is the | ||||
| 		// desired minimum distance. Now using the facts that sin(t) >= (2/Pi)*t | ||||
| 		// for 0 <= t <= Pi/2, that we only need an accurate approximation when | ||||
| 		// at least one of "maxLatGap" or lngGap is extremely small (in which | ||||
| 		// case sin(t) ~= t), and recalling that "maxLatGap" has an error of up | ||||
| 		// to 0.75 * dblEpsilon, we want to test whether | ||||
| 		// | ||||
| 		//   maxLatGap * lngGap  <  (4.309 + 0.75) * (Pi/2) * dblEpsilon | ||||
| 		//                       ~= 1.765e-15 | ||||
| 		if math.Max(latGapSouth, latGapNorth)*lngGap < 1.765e-15 { | ||||
| 			return FullRect() | ||||
| 		} | ||||
| 	} | ||||
| 	// Next we need to check whether the subregion might contain any edges that | ||||
| 	// span (math.Pi - 2 * dblEpsilon) radians or more in longitude, since AddPoint | ||||
| 	// sets the longitude bound to Full in that case. This corresponds to | ||||
| 	// testing whether (lngGap <= 0) in lngExpansion below. | ||||
| 
 | ||||
| 	// Otherwise, the maximum latitude error in AddPoint is 4.8 * dblEpsilon. | ||||
| 	// In the worst case, the errors when computing the latitude bound for a | ||||
| 	// subregion could go in the opposite direction as the errors when computing | ||||
| 	// the bound for the original region, so we need to double this value. | ||||
| 	// (More analysis shows that it's okay to round down to a multiple of | ||||
| 	// dblEpsilon.) | ||||
| 	// | ||||
| 	// For longitude, we rely on the fact that atan2 is correctly rounded and | ||||
| 	// therefore no additional bounds expansion is necessary. | ||||
| 
 | ||||
| 	latExpansion := 9 * dblEpsilon | ||||
| 	lngExpansion := 0.0 | ||||
| 	if lngGap <= 0 { | ||||
| 		lngExpansion = math.Pi | ||||
| 	} | ||||
| 	return bound.expanded(LatLng{s1.Angle(latExpansion), s1.Angle(lngExpansion)}).PolarClosure() | ||||
| } | ||||
							
								
								
									
										71
									
								
								vendor/github.com/golang/geo/s2/region.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/golang/geo/s2/region.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,71 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // A Region represents a two-dimensional region on the unit sphere. | ||||
| // | ||||
| // The purpose of this interface is to allow complex regions to be | ||||
| // approximated as simpler regions. The interface is restricted to methods | ||||
| // that are useful for computing approximations. | ||||
| type Region interface { | ||||
| 	// CapBound returns a bounding spherical cap. This is not guaranteed to be exact. | ||||
| 	CapBound() Cap | ||||
| 
 | ||||
| 	// RectBound returns a bounding latitude-longitude rectangle that contains | ||||
| 	// the region. The bounds are not guaranteed to be tight. | ||||
| 	RectBound() Rect | ||||
| 
 | ||||
| 	// ContainsCell reports whether the region completely contains the given region. | ||||
| 	// It returns false if containment could not be determined. | ||||
| 	ContainsCell(c Cell) bool | ||||
| 
 | ||||
| 	// IntersectsCell reports whether the region intersects the given cell or | ||||
| 	// if intersection could not be determined. It returns false if the region | ||||
| 	// does not intersect. | ||||
| 	IntersectsCell(c Cell) bool | ||||
| 
 | ||||
| 	// ContainsPoint reports whether the region contains the given point or not. | ||||
| 	// The point should be unit length, although some implementations may relax | ||||
| 	// this restriction. | ||||
| 	ContainsPoint(p Point) bool | ||||
| 
 | ||||
| 	// CellUnionBound returns a small collection of CellIDs whose union covers | ||||
| 	// the region. The cells are not sorted, may have redundancies (such as cells | ||||
| 	// that contain other cells), and may cover much more area than necessary. | ||||
| 	// | ||||
| 	// This method is not intended for direct use by client code. Clients | ||||
| 	// should typically use Covering, which has options to control the size and | ||||
| 	// accuracy of the covering. Alternatively, if you want a fast covering and | ||||
| 	// don't care about accuracy, consider calling FastCovering (which returns a | ||||
| 	// cleaned-up version of the covering computed by this method). | ||||
| 	// | ||||
| 	// CellUnionBound implementations should attempt to return a small | ||||
| 	// covering (ideally 4 cells or fewer) that covers the region and can be | ||||
| 	// computed quickly. The result is used by RegionCoverer as a starting | ||||
| 	// point for further refinement. | ||||
| 	CellUnionBound() []CellID | ||||
| } | ||||
| 
 | ||||
| // Enforce Region interface satisfaction. | ||||
| var ( | ||||
| 	_ Region = Cap{} | ||||
| 	_ Region = Cell{} | ||||
| 	_ Region = (*CellUnion)(nil) | ||||
| 	_ Region = (*Loop)(nil) | ||||
| 	_ Region = Point{} | ||||
| 	_ Region = (*Polygon)(nil) | ||||
| 	_ Region = (*Polyline)(nil) | ||||
| 	_ Region = Rect{} | ||||
| ) | ||||
							
								
								
									
										615
									
								
								vendor/github.com/golang/geo/s2/regioncoverer.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										615
									
								
								vendor/github.com/golang/geo/s2/regioncoverer.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,615 +0,0 @@ | |||
| // Copyright 2015 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"container/heap" | ||||
| 	"sort" | ||||
| ) | ||||
| 
 | ||||
| // RegionCoverer allows arbitrary regions to be approximated as unions of cells (CellUnion). | ||||
| // This is useful for implementing various sorts of search and precomputation operations. | ||||
| // | ||||
| // Typical usage: | ||||
| // | ||||
| //	rc := &s2.RegionCoverer{MaxLevel: 30, MaxCells: 5} | ||||
| //	r := s2.Region(CapFromCenterArea(center, area)) | ||||
| //	covering := rc.Covering(r) | ||||
| // | ||||
| // This yields a CellUnion of at most 5 cells that is guaranteed to cover the | ||||
| // given region (a disc-shaped region on the sphere). | ||||
| // | ||||
| // For covering, only cells where (level - MinLevel) is a multiple of LevelMod will be used. | ||||
| // This effectively allows the branching factor of the S2 CellID hierarchy to be increased. | ||||
| // Currently the only parameter values allowed are 1, 2, or 3, corresponding to | ||||
| // branching factors of 4, 16, and 64 respectively. | ||||
| // | ||||
| // Note the following: | ||||
| // | ||||
| //  - MinLevel takes priority over MaxCells, i.e. cells below the given level will | ||||
| //    never be used even if this causes a large number of cells to be returned. | ||||
| // | ||||
| //  - For any setting of MaxCells, up to 6 cells may be returned if that | ||||
| //    is the minimum number of cells required (e.g. if the region intersects | ||||
| //    all six face cells).  Up to 3 cells may be returned even for very tiny | ||||
| //    convex regions if they happen to be located at the intersection of | ||||
| //    three cube faces. | ||||
| // | ||||
| //  - For any setting of MaxCells, an arbitrary number of cells may be | ||||
| //    returned if MinLevel is too high for the region being approximated. | ||||
| // | ||||
| //  - If MaxCells is less than 4, the area of the covering may be | ||||
| //    arbitrarily large compared to the area of the original region even if | ||||
| //    the region is convex (e.g. a Cap or Rect). | ||||
| // | ||||
| // The approximation algorithm is not optimal but does a pretty good job in | ||||
| // practice. The output does not always use the maximum number of cells | ||||
| // allowed, both because this would not always yield a better approximation, | ||||
| // and because MaxCells is a limit on how much work is done exploring the | ||||
| // possible covering as well as a limit on the final output size. | ||||
| // | ||||
| // Because it is an approximation algorithm, one should not rely on the | ||||
| // stability of the output. In particular, the output of the covering algorithm | ||||
| // may change across different versions of the library. | ||||
| // | ||||
| // One can also generate interior coverings, which are sets of cells which | ||||
| // are entirely contained within a region. Interior coverings can be | ||||
| // empty, even for non-empty regions, if there are no cells that satisfy | ||||
| // the provided constraints and are contained by the region. Note that for | ||||
| // performance reasons, it is wise to specify a MaxLevel when computing | ||||
| // interior coverings - otherwise for regions with small or zero area, the | ||||
| // algorithm may spend a lot of time subdividing cells all the way to leaf | ||||
| // level to try to find contained cells. | ||||
| type RegionCoverer struct { | ||||
| 	MinLevel int // the minimum cell level to be used. | ||||
| 	MaxLevel int // the maximum cell level to be used. | ||||
| 	LevelMod int // the LevelMod to be used. | ||||
| 	MaxCells int // the maximum desired number of cells in the approximation. | ||||
| } | ||||
| 
 | ||||
| // NewRegionCoverer returns a region coverer with the appropriate defaults. | ||||
| func NewRegionCoverer() *RegionCoverer { | ||||
| 	return &RegionCoverer{ | ||||
| 		MinLevel: 0, | ||||
| 		MaxLevel: maxLevel, | ||||
| 		LevelMod: 1, | ||||
| 		MaxCells: 8, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type coverer struct { | ||||
| 	minLevel         int // the minimum cell level to be used. | ||||
| 	maxLevel         int // the maximum cell level to be used. | ||||
| 	levelMod         int // the LevelMod to be used. | ||||
| 	maxCells         int // the maximum desired number of cells in the approximation. | ||||
| 	region           Region | ||||
| 	result           CellUnion | ||||
| 	pq               priorityQueue | ||||
| 	interiorCovering bool | ||||
| } | ||||
| 
 | ||||
| type candidate struct { | ||||
| 	cell        Cell | ||||
| 	terminal    bool         // Cell should not be expanded further. | ||||
| 	numChildren int          // Number of children that intersect the region. | ||||
| 	children    []*candidate // Actual size may be 0, 4, 16, or 64 elements. | ||||
| 	priority    int          // Priority of the candidate. | ||||
| } | ||||
| 
 | ||||
| type priorityQueue []*candidate | ||||
| 
 | ||||
| func (pq priorityQueue) Len() int { | ||||
| 	return len(pq) | ||||
| } | ||||
| 
 | ||||
| func (pq priorityQueue) Less(i, j int) bool { | ||||
| 	// We want Pop to give us the highest, not lowest, priority so we use greater than here. | ||||
| 	return pq[i].priority > pq[j].priority | ||||
| } | ||||
| 
 | ||||
| func (pq priorityQueue) Swap(i, j int) { | ||||
| 	pq[i], pq[j] = pq[j], pq[i] | ||||
| } | ||||
| 
 | ||||
| func (pq *priorityQueue) Push(x interface{}) { | ||||
| 	item := x.(*candidate) | ||||
| 	*pq = append(*pq, item) | ||||
| } | ||||
| 
 | ||||
| func (pq *priorityQueue) Pop() interface{} { | ||||
| 	item := (*pq)[len(*pq)-1] | ||||
| 	*pq = (*pq)[:len(*pq)-1] | ||||
| 	return item | ||||
| } | ||||
| 
 | ||||
| func (pq *priorityQueue) Reset() { | ||||
| 	*pq = (*pq)[:0] | ||||
| } | ||||
| 
 | ||||
| // newCandidate returns a new candidate with no children if the cell intersects the given region. | ||||
| // The candidate is marked as terminal if it should not be expanded further. | ||||
| func (c *coverer) newCandidate(cell Cell) *candidate { | ||||
| 	if !c.region.IntersectsCell(cell) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	cand := &candidate{cell: cell} | ||||
| 	level := int(cell.level) | ||||
| 	if level >= c.minLevel { | ||||
| 		if c.interiorCovering { | ||||
| 			if c.region.ContainsCell(cell) { | ||||
| 				cand.terminal = true | ||||
| 			} else if level+c.levelMod > c.maxLevel { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} else if level+c.levelMod > c.maxLevel || c.region.ContainsCell(cell) { | ||||
| 			cand.terminal = true | ||||
| 		} | ||||
| 	} | ||||
| 	return cand | ||||
| } | ||||
| 
 | ||||
| // expandChildren populates the children of the candidate by expanding the given number of | ||||
| // levels from the given cell.  Returns the number of children that were marked "terminal". | ||||
| func (c *coverer) expandChildren(cand *candidate, cell Cell, numLevels int) int { | ||||
| 	numLevels-- | ||||
| 	var numTerminals int | ||||
| 	last := cell.id.ChildEnd() | ||||
| 	for ci := cell.id.ChildBegin(); ci != last; ci = ci.Next() { | ||||
| 		childCell := CellFromCellID(ci) | ||||
| 		if numLevels > 0 { | ||||
| 			if c.region.IntersectsCell(childCell) { | ||||
| 				numTerminals += c.expandChildren(cand, childCell, numLevels) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if child := c.newCandidate(childCell); child != nil { | ||||
| 			cand.children = append(cand.children, child) | ||||
| 			cand.numChildren++ | ||||
| 			if child.terminal { | ||||
| 				numTerminals++ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return numTerminals | ||||
| } | ||||
| 
 | ||||
| // addCandidate adds the given candidate to the result if it is marked as "terminal", | ||||
| // otherwise expands its children and inserts it into the priority queue. | ||||
| // Passing an argument of nil does nothing. | ||||
| func (c *coverer) addCandidate(cand *candidate) { | ||||
| 	if cand == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if cand.terminal { | ||||
| 		c.result = append(c.result, cand.cell.id) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Expand one level at a time until we hit minLevel to ensure that we don't skip over it. | ||||
| 	numLevels := c.levelMod | ||||
| 	level := int(cand.cell.level) | ||||
| 	if level < c.minLevel { | ||||
| 		numLevels = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	numTerminals := c.expandChildren(cand, cand.cell, numLevels) | ||||
| 	maxChildrenShift := uint(2 * c.levelMod) | ||||
| 	if cand.numChildren == 0 { | ||||
| 		return | ||||
| 	} else if !c.interiorCovering && numTerminals == 1<<maxChildrenShift && level >= c.minLevel { | ||||
| 		// Optimization: add the parent cell rather than all of its children. | ||||
| 		// We can't do this for interior coverings, since the children just | ||||
| 		// intersect the region, but may not be contained by it - we need to | ||||
| 		// subdivide them further. | ||||
| 		cand.terminal = true | ||||
| 		c.addCandidate(cand) | ||||
| 	} else { | ||||
| 		// We negate the priority so that smaller absolute priorities are returned | ||||
| 		// first. The heuristic is designed to refine the largest cells first, | ||||
| 		// since those are where we have the largest potential gain. Among cells | ||||
| 		// of the same size, we prefer the cells with the fewest children. | ||||
| 		// Finally, among cells with equal numbers of children we prefer those | ||||
| 		// with the smallest number of children that cannot be refined further. | ||||
| 		cand.priority = -(((level<<maxChildrenShift)+cand.numChildren)<<maxChildrenShift + numTerminals) | ||||
| 		heap.Push(&c.pq, cand) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // adjustLevel returns the reduced "level" so that it satisfies levelMod. Levels smaller than minLevel | ||||
| // are not affected (since cells at these levels are eventually expanded). | ||||
| func (c *coverer) adjustLevel(level int) int { | ||||
| 	if c.levelMod > 1 && level > c.minLevel { | ||||
| 		level -= (level - c.minLevel) % c.levelMod | ||||
| 	} | ||||
| 	return level | ||||
| } | ||||
| 
 | ||||
| // adjustCellLevels ensures that all cells with level > minLevel also satisfy levelMod, | ||||
| // by replacing them with an ancestor if necessary. Cell levels smaller | ||||
| // than minLevel are not modified (see AdjustLevel). The output is | ||||
| // then normalized to ensure that no redundant cells are present. | ||||
| func (c *coverer) adjustCellLevels(cells *CellUnion) { | ||||
| 	if c.levelMod == 1 { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var out int | ||||
| 	for _, ci := range *cells { | ||||
| 		level := ci.Level() | ||||
| 		newLevel := c.adjustLevel(level) | ||||
| 		if newLevel != level { | ||||
| 			ci = ci.Parent(newLevel) | ||||
| 		} | ||||
| 		if out > 0 && (*cells)[out-1].Contains(ci) { | ||||
| 			continue | ||||
| 		} | ||||
| 		for out > 0 && ci.Contains((*cells)[out-1]) { | ||||
| 			out-- | ||||
| 		} | ||||
| 		(*cells)[out] = ci | ||||
| 		out++ | ||||
| 	} | ||||
| 	*cells = (*cells)[:out] | ||||
| } | ||||
| 
 | ||||
| // initialCandidates computes a set of initial candidates that cover the given region. | ||||
| func (c *coverer) initialCandidates() { | ||||
| 	// Optimization: start with a small (usually 4 cell) covering of the region's bounding cap. | ||||
| 	temp := &RegionCoverer{MaxLevel: c.maxLevel, LevelMod: 1, MaxCells: minInt(4, c.maxCells)} | ||||
| 
 | ||||
| 	cells := temp.FastCovering(c.region) | ||||
| 	c.adjustCellLevels(&cells) | ||||
| 	for _, ci := range cells { | ||||
| 		c.addCandidate(c.newCandidate(CellFromCellID(ci))) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // coveringInternal generates a covering and stores it in result. | ||||
| // Strategy: Start with the 6 faces of the cube.  Discard any | ||||
| // that do not intersect the shape.  Then repeatedly choose the | ||||
| // largest cell that intersects the shape and subdivide it. | ||||
| // | ||||
| // result contains the cells that will be part of the output, while pq | ||||
| // contains cells that we may still subdivide further. Cells that are | ||||
| // entirely contained within the region are immediately added to the output, | ||||
| // while cells that do not intersect the region are immediately discarded. | ||||
| // Therefore pq only contains cells that partially intersect the region. | ||||
| // Candidates are prioritized first according to cell size (larger cells | ||||
| // first), then by the number of intersecting children they have (fewest | ||||
| // children first), and then by the number of fully contained children | ||||
| // (fewest children first). | ||||
| func (c *coverer) coveringInternal(region Region) { | ||||
| 	c.region = region | ||||
| 
 | ||||
| 	c.initialCandidates() | ||||
| 	for c.pq.Len() > 0 && (!c.interiorCovering || len(c.result) < c.maxCells) { | ||||
| 		cand := heap.Pop(&c.pq).(*candidate) | ||||
| 
 | ||||
| 		// For interior covering we keep subdividing no matter how many children | ||||
| 		// candidate has. If we reach MaxCells before expanding all children, | ||||
| 		// we will just use some of them. | ||||
| 		// For exterior covering we cannot do this, because result has to cover the | ||||
| 		// whole region, so all children have to be used. | ||||
| 		// candidate.numChildren == 1 case takes care of the situation when we | ||||
| 		// already have more than MaxCells in result (minLevel is too high). | ||||
| 		// Subdividing of the candidate with one child does no harm in this case. | ||||
| 		if c.interiorCovering || int(cand.cell.level) < c.minLevel || cand.numChildren == 1 || len(c.result)+c.pq.Len()+cand.numChildren <= c.maxCells { | ||||
| 			for _, child := range cand.children { | ||||
| 				if !c.interiorCovering || len(c.result) < c.maxCells { | ||||
| 					c.addCandidate(child) | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			cand.terminal = true | ||||
| 			c.addCandidate(cand) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	c.pq.Reset() | ||||
| 	c.region = nil | ||||
| 
 | ||||
| 	// Rather than just returning the raw list of cell ids, we construct a cell | ||||
| 	// union and then denormalize it. This has the effect of replacing four | ||||
| 	// child cells with their parent whenever this does not violate the covering | ||||
| 	// parameters specified (min_level, level_mod, etc). This significantly | ||||
| 	// reduces the number of cells returned in many cases, and it is cheap | ||||
| 	// compared to computing the covering in the first place. | ||||
| 	c.result.Normalize() | ||||
| 	if c.minLevel > 0 || c.levelMod > 1 { | ||||
| 		c.result.Denormalize(c.minLevel, c.levelMod) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // newCoverer returns an instance of coverer. | ||||
| func (rc *RegionCoverer) newCoverer() *coverer { | ||||
| 	return &coverer{ | ||||
| 		minLevel: maxInt(0, minInt(maxLevel, rc.MinLevel)), | ||||
| 		maxLevel: maxInt(0, minInt(maxLevel, rc.MaxLevel)), | ||||
| 		levelMod: maxInt(1, minInt(3, rc.LevelMod)), | ||||
| 		maxCells: rc.MaxCells, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Covering returns a CellUnion that covers the given region and satisfies the various restrictions. | ||||
| func (rc *RegionCoverer) Covering(region Region) CellUnion { | ||||
| 	covering := rc.CellUnion(region) | ||||
| 	covering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod))) | ||||
| 	return covering | ||||
| } | ||||
| 
 | ||||
| // InteriorCovering returns a CellUnion that is contained within the given region and satisfies the various restrictions. | ||||
| func (rc *RegionCoverer) InteriorCovering(region Region) CellUnion { | ||||
| 	intCovering := rc.InteriorCellUnion(region) | ||||
| 	intCovering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod))) | ||||
| 	return intCovering | ||||
| } | ||||
| 
 | ||||
| // CellUnion returns a normalized CellUnion that covers the given region and | ||||
| // satisfies the restrictions except for minLevel and levelMod. These criteria | ||||
| // cannot be satisfied using a cell union because cell unions are | ||||
| // automatically normalized by replacing four child cells with their parent | ||||
| // whenever possible. (Note that the list of cell ids passed to the CellUnion | ||||
| // constructor does in fact satisfy all the given restrictions.) | ||||
| func (rc *RegionCoverer) CellUnion(region Region) CellUnion { | ||||
| 	c := rc.newCoverer() | ||||
| 	c.coveringInternal(region) | ||||
| 	cu := c.result | ||||
| 	cu.Normalize() | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // InteriorCellUnion returns a normalized CellUnion that is contained within the given region and | ||||
| // satisfies the restrictions except for minLevel and levelMod. These criteria | ||||
| // cannot be satisfied using a cell union because cell unions are | ||||
| // automatically normalized by replacing four child cells with their parent | ||||
| // whenever possible. (Note that the list of cell ids passed to the CellUnion | ||||
| // constructor does in fact satisfy all the given restrictions.) | ||||
| func (rc *RegionCoverer) InteriorCellUnion(region Region) CellUnion { | ||||
| 	c := rc.newCoverer() | ||||
| 	c.interiorCovering = true | ||||
| 	c.coveringInternal(region) | ||||
| 	cu := c.result | ||||
| 	cu.Normalize() | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // FastCovering returns a CellUnion that covers the given region similar to Covering, | ||||
| // except that this method is much faster and the coverings are not as tight. | ||||
| // All of the usual parameters are respected (MaxCells, MinLevel, MaxLevel, and LevelMod), | ||||
| // except that the implementation makes no attempt to take advantage of large values of | ||||
| // MaxCells.  (A small number of cells will always be returned.) | ||||
| // | ||||
| // This function is useful as a starting point for algorithms that | ||||
| // recursively subdivide cells. | ||||
| func (rc *RegionCoverer) FastCovering(region Region) CellUnion { | ||||
| 	c := rc.newCoverer() | ||||
| 	cu := CellUnion(region.CellUnionBound()) | ||||
| 	c.normalizeCovering(&cu) | ||||
| 	return cu | ||||
| } | ||||
| 
 | ||||
| // IsCanonical reports whether the given CellUnion represents a valid covering | ||||
| // that conforms to the current covering parameters.  In particular: | ||||
| // | ||||
| //  - All CellIDs must be valid. | ||||
| // | ||||
| //  - CellIDs must be sorted and non-overlapping. | ||||
| // | ||||
| //  - CellID levels must satisfy MinLevel, MaxLevel, and LevelMod. | ||||
| // | ||||
| //  - If the covering has more than MaxCells, there must be no two cells with | ||||
| //    a common ancestor at MinLevel or higher. | ||||
| // | ||||
| //  - There must be no sequence of cells that could be replaced by an | ||||
| //    ancestor (i.e. with LevelMod == 1, the 4 child cells of a parent). | ||||
| func (rc *RegionCoverer) IsCanonical(covering CellUnion) bool { | ||||
| 	return rc.newCoverer().isCanonical(covering) | ||||
| } | ||||
| 
 | ||||
| // normalizeCovering normalizes the "covering" so that it conforms to the | ||||
| // current covering parameters (maxCells, minLevel, maxLevel, and levelMod). | ||||
| // This method makes no attempt to be optimal. In particular, if | ||||
| // minLevel > 0 or levelMod > 1 then it may return more than the | ||||
| // desired number of cells even when this isn't necessary. | ||||
| // | ||||
| // Note that when the covering parameters have their default values, almost | ||||
| // all of the code in this function is skipped. | ||||
| func (c *coverer) normalizeCovering(covering *CellUnion) { | ||||
| 	// If any cells are too small, or don't satisfy levelMod, then replace them with ancestors. | ||||
| 	if c.maxLevel < maxLevel || c.levelMod > 1 { | ||||
| 		for i, ci := range *covering { | ||||
| 			level := ci.Level() | ||||
| 			newLevel := c.adjustLevel(minInt(level, c.maxLevel)) | ||||
| 			if newLevel != level { | ||||
| 				(*covering)[i] = ci.Parent(newLevel) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Sort the cells and simplify them. | ||||
| 	covering.Normalize() | ||||
| 
 | ||||
| 	// Make sure that the covering satisfies minLevel and levelMod, | ||||
| 	// possibly at the expense of satisfying MaxCells. | ||||
| 	if c.minLevel > 0 || c.levelMod > 1 { | ||||
| 		covering.Denormalize(c.minLevel, c.levelMod) | ||||
| 	} | ||||
| 
 | ||||
| 	// If there are too many cells and the covering is very large, use the | ||||
| 	// RegionCoverer to compute a new covering. (This avoids possible O(n^2) | ||||
| 	// behavior of the simpler algorithm below.) | ||||
| 	excess := len(*covering) - c.maxCells | ||||
| 	if excess <= 0 || c.isCanonical(*covering) { | ||||
| 		return | ||||
| 	} | ||||
| 	if excess*len(*covering) > 10000 { | ||||
| 		rc := NewRegionCoverer() | ||||
| 		(*covering) = rc.Covering(covering) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// If there are still too many cells, then repeatedly replace two adjacent | ||||
| 	// cells in CellID order by their lowest common ancestor. | ||||
| 	for len(*covering) > c.maxCells { | ||||
| 		bestIndex := -1 | ||||
| 		bestLevel := -1 | ||||
| 		for i := 0; i+1 < len(*covering); i++ { | ||||
| 			level, ok := (*covering)[i].CommonAncestorLevel((*covering)[i+1]) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			level = c.adjustLevel(level) | ||||
| 			if level > bestLevel { | ||||
| 				bestLevel = level | ||||
| 				bestIndex = i | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if bestLevel < c.minLevel { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// Replace all cells contained by the new ancestor cell. | ||||
| 		id := (*covering)[bestIndex].Parent(bestLevel) | ||||
| 		(*covering) = c.replaceCellsWithAncestor(*covering, id) | ||||
| 
 | ||||
| 		// Now repeatedly check whether all children of the parent cell are | ||||
| 		// present, in which case we can replace those cells with their parent. | ||||
| 		for bestLevel > c.minLevel { | ||||
| 			bestLevel -= c.levelMod | ||||
| 			id = id.Parent(bestLevel) | ||||
| 			if !c.containsAllChildren(*covering, id) { | ||||
| 				break | ||||
| 			} | ||||
| 			(*covering) = c.replaceCellsWithAncestor(*covering, id) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // isCanonical reports whether the covering is canonical. | ||||
| func (c *coverer) isCanonical(covering CellUnion) bool { | ||||
| 	trueMax := c.maxLevel | ||||
| 	if c.levelMod != 1 { | ||||
| 		trueMax = c.maxLevel - (c.maxLevel-c.minLevel)%c.levelMod | ||||
| 	} | ||||
| 	tooManyCells := len(covering) > c.maxCells | ||||
| 	sameParentCount := 1 | ||||
| 
 | ||||
| 	prevID := CellID(0) | ||||
| 	for _, id := range covering { | ||||
| 		if !id.IsValid() { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		// Check that the CellID level is acceptable. | ||||
| 		level := id.Level() | ||||
| 		if level < c.minLevel || level > trueMax { | ||||
| 			return false | ||||
| 		} | ||||
| 		if c.levelMod > 1 && (level-c.minLevel)%c.levelMod != 0 { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		if prevID != 0 { | ||||
| 			// Check that cells are sorted and non-overlapping. | ||||
| 			if prevID.RangeMax() >= id.RangeMin() { | ||||
| 				return false | ||||
| 			} | ||||
| 
 | ||||
| 			lev, ok := id.CommonAncestorLevel(prevID) | ||||
| 			// If there are too many cells, check that no pair of adjacent cells | ||||
| 			// could be replaced by an ancestor. | ||||
| 			if tooManyCells && (ok && lev >= c.minLevel) { | ||||
| 				return false | ||||
| 			} | ||||
| 
 | ||||
| 			// Check that there are no sequences of (4 ** level_mod) cells that all | ||||
| 			// have the same parent (considering only multiples of "level_mod"). | ||||
| 			pLevel := level - c.levelMod | ||||
| 			if pLevel < c.minLevel || level != prevID.Level() || | ||||
| 				id.Parent(pLevel) != prevID.Parent(pLevel) { | ||||
| 				sameParentCount = 1 | ||||
| 			} else { | ||||
| 				sameParentCount++ | ||||
| 				if sameParentCount == 1<<uint(2*c.levelMod) { | ||||
| 					return false | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		prevID = id | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (c *coverer) containsAllChildren(covering []CellID, id CellID) bool { | ||||
| 	pos := sort.Search(len(covering), func(i int) bool { return (covering)[i] >= id.RangeMin() }) | ||||
| 	level := id.Level() + c.levelMod | ||||
| 	for child := id.ChildBeginAtLevel(level); child != id.ChildEndAtLevel(level); child = child.Next() { | ||||
| 		if pos == len(covering) || covering[pos] != child { | ||||
| 			return false | ||||
| 		} | ||||
| 		pos++ | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // replaceCellsWithAncestor replaces all descendants of the given id in covering | ||||
| // with id. This requires the covering contains at least one descendant of id. | ||||
| func (c *coverer) replaceCellsWithAncestor(covering []CellID, id CellID) []CellID { | ||||
| 	begin := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMin() }) | ||||
| 	end := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMax() }) | ||||
| 
 | ||||
| 	return append(append(covering[:begin], id), covering[end:]...) | ||||
| } | ||||
| 
 | ||||
| // SimpleRegionCovering returns a set of cells at the given level that cover | ||||
| // the connected region and a starting point on the boundary or inside the | ||||
| // region. The cells are returned in arbitrary order. | ||||
| // | ||||
| // Note that this method is not faster than the regular Covering | ||||
| // method for most region types, such as Cap or Polygon, and in fact it | ||||
| // can be much slower when the output consists of a large number of cells. | ||||
| // Currently it can be faster at generating coverings of long narrow regions | ||||
| // such as polylines, but this may change in the future. | ||||
| func SimpleRegionCovering(region Region, start Point, level int) []CellID { | ||||
| 	return FloodFillRegionCovering(region, cellIDFromPoint(start).Parent(level)) | ||||
| } | ||||
| 
 | ||||
| // FloodFillRegionCovering returns all edge-connected cells at the same level as | ||||
| // the given CellID that intersect the given region, in arbitrary order. | ||||
| func FloodFillRegionCovering(region Region, start CellID) []CellID { | ||||
| 	var output []CellID | ||||
| 	all := map[CellID]bool{ | ||||
| 		start: true, | ||||
| 	} | ||||
| 	frontier := []CellID{start} | ||||
| 	for len(frontier) > 0 { | ||||
| 		id := frontier[len(frontier)-1] | ||||
| 		frontier = frontier[:len(frontier)-1] | ||||
| 		if !region.IntersectsCell(CellFromCellID(id)) { | ||||
| 			continue | ||||
| 		} | ||||
| 		output = append(output, id) | ||||
| 		for _, nbr := range id.EdgeNeighbors() { | ||||
| 			if !all[nbr] { | ||||
| 				all[nbr] = true | ||||
| 				frontier = append(frontier, nbr) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return output | ||||
| } | ||||
							
								
								
									
										66
									
								
								vendor/github.com/golang/geo/s2/regionunion.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/golang/geo/s2/regionunion.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,66 +0,0 @@ | |||
| // Copyright 2020 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // A RegionUnion represents a union of possibly overlapping regions. | ||||
| // It is convenient for computing a covering of a set of regions. | ||||
| type RegionUnion []Region | ||||
| 
 | ||||
| // CapBound returns a bounding cap for this RegionUnion. | ||||
| func (ru RegionUnion) CapBound() Cap { return ru.RectBound().CapBound() } | ||||
| 
 | ||||
| // RectBound returns a bounding latitude-longitude rectangle for this RegionUnion. | ||||
| func (ru RegionUnion) RectBound() Rect { | ||||
| 	ret := EmptyRect() | ||||
| 	for _, reg := range ru { | ||||
| 		ret = ret.Union(reg.RectBound()) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| // ContainsCell reports whether the given Cell is contained by this RegionUnion. | ||||
| func (ru RegionUnion) ContainsCell(c Cell) bool { | ||||
| 	for _, reg := range ru { | ||||
| 		if reg.ContainsCell(c) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // IntersectsCell reports whether this RegionUnion intersects the given cell. | ||||
| func (ru RegionUnion) IntersectsCell(c Cell) bool { | ||||
| 	for _, reg := range ru { | ||||
| 		if reg.IntersectsCell(c) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // ContainsPoint reports whether this RegionUnion contains the Point. | ||||
| func (ru RegionUnion) ContainsPoint(p Point) bool { | ||||
| 	for _, reg := range ru { | ||||
| 		if reg.ContainsPoint(p) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // CellUnionBound computes a covering of the RegionUnion. | ||||
| func (ru RegionUnion) CellUnionBound() []CellID { | ||||
| 	return ru.CapBound().CellUnionBound() | ||||
| } | ||||
							
								
								
									
										263
									
								
								vendor/github.com/golang/geo/s2/shape.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										263
									
								
								vendor/github.com/golang/geo/s2/shape.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,263 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"sort" | ||||
| ) | ||||
| 
 | ||||
| // Edge represents a geodesic edge consisting of two vertices. Zero-length edges are | ||||
| // allowed, and can be used to represent points. | ||||
| type Edge struct { | ||||
| 	V0, V1 Point | ||||
| } | ||||
| 
 | ||||
| // Cmp compares the two edges using the underlying Points Cmp method and returns | ||||
| // | ||||
| //   -1 if e <  other | ||||
| //    0 if e == other | ||||
| //   +1 if e >  other | ||||
| // | ||||
| // The two edges are compared by first vertex, and then by the second vertex. | ||||
| func (e Edge) Cmp(other Edge) int { | ||||
| 	if v0cmp := e.V0.Cmp(other.V0.Vector); v0cmp != 0 { | ||||
| 		return v0cmp | ||||
| 	} | ||||
| 	return e.V1.Cmp(other.V1.Vector) | ||||
| } | ||||
| 
 | ||||
| // sortEdges sorts the slice of Edges in place. | ||||
| func sortEdges(e []Edge) { | ||||
| 	sort.Sort(edges(e)) | ||||
| } | ||||
| 
 | ||||
| // edges implements the Sort interface for slices of Edge. | ||||
| type edges []Edge | ||||
| 
 | ||||
| func (e edges) Len() int           { return len(e) } | ||||
| func (e edges) Swap(i, j int)      { e[i], e[j] = e[j], e[i] } | ||||
| func (e edges) Less(i, j int) bool { return e[i].Cmp(e[j]) == -1 } | ||||
| 
 | ||||
| // ShapeEdgeID is a unique identifier for an Edge within an ShapeIndex, | ||||
| // consisting of a (shapeID, edgeID) pair. | ||||
| type ShapeEdgeID struct { | ||||
| 	ShapeID int32 | ||||
| 	EdgeID  int32 | ||||
| } | ||||
| 
 | ||||
| // Cmp compares the two ShapeEdgeIDs and returns | ||||
| // | ||||
| //   -1 if s <  other | ||||
| //    0 if s == other | ||||
| //   +1 if s >  other | ||||
| // | ||||
| // The two are compared first by shape id and then by edge id. | ||||
| func (s ShapeEdgeID) Cmp(other ShapeEdgeID) int { | ||||
| 	switch { | ||||
| 	case s.ShapeID < other.ShapeID: | ||||
| 		return -1 | ||||
| 	case s.ShapeID > other.ShapeID: | ||||
| 		return 1 | ||||
| 	} | ||||
| 	switch { | ||||
| 	case s.EdgeID < other.EdgeID: | ||||
| 		return -1 | ||||
| 	case s.EdgeID > other.EdgeID: | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // ShapeEdge represents a ShapeEdgeID with the two endpoints of that Edge. | ||||
| type ShapeEdge struct { | ||||
| 	ID   ShapeEdgeID | ||||
| 	Edge Edge | ||||
| } | ||||
| 
 | ||||
| // Chain represents a range of edge IDs corresponding to a chain of connected | ||||
| // edges, specified as a (start, length) pair. The chain is defined to consist of | ||||
| // edge IDs {start, start + 1, ..., start + length - 1}. | ||||
| type Chain struct { | ||||
| 	Start, Length int | ||||
| } | ||||
| 
 | ||||
| // ChainPosition represents the position of an edge within a given edge chain, | ||||
| // specified as a (chainID, offset) pair. Chains are numbered sequentially | ||||
| // starting from zero, and offsets are measured from the start of each chain. | ||||
| type ChainPosition struct { | ||||
| 	ChainID, Offset int | ||||
| } | ||||
| 
 | ||||
| // A ReferencePoint consists of a point and a boolean indicating whether the point | ||||
| // is contained by a particular shape. | ||||
| type ReferencePoint struct { | ||||
| 	Point     Point | ||||
| 	Contained bool | ||||
| } | ||||
| 
 | ||||
| // OriginReferencePoint returns a ReferencePoint with the given value for | ||||
| // contained and the origin point. It should be used when all points or no | ||||
| // points are contained. | ||||
| func OriginReferencePoint(contained bool) ReferencePoint { | ||||
| 	return ReferencePoint{Point: OriginPoint(), Contained: contained} | ||||
| } | ||||
| 
 | ||||
| // typeTag is a 32-bit tag that can be used to identify the type of an encoded | ||||
| // Shape. All encodable types have a non-zero type tag. The tag associated with | ||||
| type typeTag uint32 | ||||
| 
 | ||||
| const ( | ||||
| 	// Indicates that a given Shape type cannot be encoded. | ||||
| 	typeTagNone        typeTag = 0 | ||||
| 	typeTagPolygon     typeTag = 1 | ||||
| 	typeTagPolyline    typeTag = 2 | ||||
| 	typeTagPointVector typeTag = 3 | ||||
| 	typeTagLaxPolyline typeTag = 4 | ||||
| 	typeTagLaxPolygon  typeTag = 5 | ||||
| 
 | ||||
| 	// The minimum allowable tag for future user-defined Shape types. | ||||
| 	typeTagMinUser typeTag = 8192 | ||||
| ) | ||||
| 
 | ||||
| // Shape represents polygonal geometry in a flexible way. It is organized as a | ||||
| // collection of edges that optionally defines an interior. All geometry | ||||
| // represented by a given Shape must have the same dimension, which means that | ||||
| // an Shape can represent either a set of points, a set of polylines, or a set | ||||
| // of polygons. | ||||
| // | ||||
| // Shape is defined as an interface in order to give clients control over the | ||||
| // underlying data representation. Sometimes an Shape does not have any data of | ||||
| // its own, but instead wraps some other type. | ||||
| // | ||||
| // Shape operations are typically defined on a ShapeIndex rather than | ||||
| // individual shapes. An ShapeIndex is simply a collection of Shapes, | ||||
| // possibly of different dimensions (e.g. 10 points and 3 polygons), organized | ||||
| // into a data structure for efficient edge access. | ||||
| // | ||||
| // The edges of a Shape are indexed by a contiguous range of edge IDs | ||||
| // starting at 0. The edges are further subdivided into chains, where each | ||||
| // chain consists of a sequence of edges connected end-to-end (a polyline). | ||||
| // For example, a Shape representing two polylines AB and CDE would have | ||||
| // three edges (AB, CD, DE) grouped into two chains: (AB) and (CD, DE). | ||||
| // Similarly, an Shape representing 5 points would have 5 chains consisting | ||||
| // of one edge each. | ||||
| // | ||||
| // Shape has methods that allow edges to be accessed either using the global | ||||
| // numbering (edge ID) or within a particular chain. The global numbering is | ||||
| // sufficient for most purposes, but the chain representation is useful for | ||||
| // certain algorithms such as intersection (see BooleanOperation). | ||||
| type Shape interface { | ||||
| 	// NumEdges returns the number of edges in this shape. | ||||
| 	NumEdges() int | ||||
| 
 | ||||
| 	// Edge returns the edge for the given edge index. | ||||
| 	Edge(i int) Edge | ||||
| 
 | ||||
| 	// ReferencePoint returns an arbitrary reference point for the shape. (The | ||||
| 	// containment boolean value must be false for shapes that do not have an interior.) | ||||
| 	// | ||||
| 	// This reference point may then be used to compute the containment of other | ||||
| 	// points by counting edge crossings. | ||||
| 	ReferencePoint() ReferencePoint | ||||
| 
 | ||||
| 	// NumChains reports the number of contiguous edge chains in the shape. | ||||
| 	// For example, a shape whose edges are [AB, BC, CD, AE, EF] would consist | ||||
| 	// of two chains (AB,BC,CD and AE,EF). Every chain is assigned a chain Id | ||||
| 	// numbered sequentially starting from zero. | ||||
| 	// | ||||
| 	// Note that it is always acceptable to implement this method by returning | ||||
| 	// NumEdges, i.e. every chain consists of a single edge, but this may | ||||
| 	// reduce the efficiency of some algorithms. | ||||
| 	NumChains() int | ||||
| 
 | ||||
| 	// Chain returns the range of edge IDs corresponding to the given edge chain. | ||||
| 	// Edge chains must form contiguous, non-overlapping ranges that cover | ||||
| 	// the entire range of edge IDs. This is spelled out more formally below: | ||||
| 	// | ||||
| 	//  0 <= i < NumChains() | ||||
| 	//  Chain(i).length > 0, for all i | ||||
| 	//  Chain(0).start == 0 | ||||
| 	//  Chain(i).start + Chain(i).length == Chain(i+1).start, for i < NumChains()-1 | ||||
| 	//  Chain(i).start + Chain(i).length == NumEdges(), for i == NumChains()-1 | ||||
| 	Chain(chainID int) Chain | ||||
| 
 | ||||
| 	// ChainEdgeReturns the edge at offset "offset" within edge chain "chainID". | ||||
| 	// Equivalent to "shape.Edge(shape.Chain(chainID).start + offset)" | ||||
| 	// but more efficient. | ||||
| 	ChainEdge(chainID, offset int) Edge | ||||
| 
 | ||||
| 	// ChainPosition finds the chain containing the given edge, and returns the | ||||
| 	// position of that edge as a ChainPosition(chainID, offset) pair. | ||||
| 	// | ||||
| 	//  shape.Chain(pos.chainID).start + pos.offset == edgeID | ||||
| 	//  shape.Chain(pos.chainID+1).start > edgeID | ||||
| 	// | ||||
| 	// where pos == shape.ChainPosition(edgeID). | ||||
| 	ChainPosition(edgeID int) ChainPosition | ||||
| 
 | ||||
| 	// Dimension returns the dimension of the geometry represented by this shape, | ||||
| 	// either 0, 1 or 2 for point, polyline and polygon geometry respectively. | ||||
| 	// | ||||
| 	//  0 - Point geometry. Each point is represented as a degenerate edge. | ||||
| 	// | ||||
| 	//  1 - Polyline geometry. Polyline edges may be degenerate. A shape may | ||||
| 	//      represent any number of polylines. Polylines edges may intersect. | ||||
| 	// | ||||
| 	//  2 - Polygon geometry. Edges should be oriented such that the polygon | ||||
| 	//      interior is always on the left. In theory the edges may be returned | ||||
| 	//      in any order, but typically the edges are organized as a collection | ||||
| 	//      of edge chains where each chain represents one polygon loop. | ||||
| 	//      Polygons may have degeneracies (e.g., degenerate edges or sibling | ||||
| 	//      pairs consisting of an edge and its corresponding reversed edge). | ||||
| 	//      A polygon loop may also be full (containing all points on the | ||||
| 	//      sphere); by convention this is represented as a chain with no edges. | ||||
| 	//      (See laxPolygon for details.) | ||||
| 	// | ||||
| 	// This method allows degenerate geometry of different dimensions | ||||
| 	// to be distinguished, e.g. it allows a point to be distinguished from a | ||||
| 	// polyline or polygon that has been simplified to a single point. | ||||
| 	Dimension() int | ||||
| 
 | ||||
| 	// IsEmpty reports whether the Shape contains no points. (Note that the full | ||||
| 	// polygon is represented as a chain with zero edges.) | ||||
| 	IsEmpty() bool | ||||
| 
 | ||||
| 	// IsFull reports whether the Shape contains all points on the sphere. | ||||
| 	IsFull() bool | ||||
| 
 | ||||
| 	// typeTag returns a value that can be used to identify the type of an | ||||
| 	// encoded Shape. | ||||
| 	typeTag() typeTag | ||||
| 
 | ||||
| 	// We do not support implementations of this interface outside this package. | ||||
| 	privateInterface() | ||||
| } | ||||
| 
 | ||||
| // defaultShapeIsEmpty reports whether this shape contains no points. | ||||
| func defaultShapeIsEmpty(s Shape) bool { | ||||
| 	return s.NumEdges() == 0 && (s.Dimension() != 2 || s.NumChains() == 0) | ||||
| } | ||||
| 
 | ||||
| // defaultShapeIsFull reports whether this shape contains all points on the sphere. | ||||
| func defaultShapeIsFull(s Shape) bool { | ||||
| 	return s.NumEdges() == 0 && s.Dimension() == 2 && s.NumChains() > 0 | ||||
| } | ||||
| 
 | ||||
| // A minimal check for types that should satisfy the Shape interface. | ||||
| var ( | ||||
| 	_ Shape = &Loop{} | ||||
| 	_ Shape = &Polygon{} | ||||
| 	_ Shape = &Polyline{} | ||||
| ) | ||||
							
								
								
									
										1526
									
								
								vendor/github.com/golang/geo/s2/shapeindex.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1526
									
								
								vendor/github.com/golang/geo/s2/shapeindex.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										228
									
								
								vendor/github.com/golang/geo/s2/shapeutil.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										228
									
								
								vendor/github.com/golang/geo/s2/shapeutil.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,228 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // CrossingType defines different ways of reporting edge intersections. | ||||
| type CrossingType int | ||||
| 
 | ||||
| const ( | ||||
| 	// CrossingTypeInterior reports intersections that occur at a point | ||||
| 	// interior to both edges (i.e., not at a vertex). | ||||
| 	CrossingTypeInterior CrossingType = iota | ||||
| 
 | ||||
| 	// CrossingTypeAll reports all intersections, even those where two edges | ||||
| 	// intersect only because they share a common vertex. | ||||
| 	CrossingTypeAll | ||||
| 
 | ||||
| 	// CrossingTypeNonAdjacent reports all intersections except for pairs of | ||||
| 	// the form (AB, BC) where both edges are from the same ShapeIndex. | ||||
| 	CrossingTypeNonAdjacent | ||||
| ) | ||||
| 
 | ||||
| // rangeIterator is a wrapper over ShapeIndexIterator with extra methods | ||||
| // that are useful for merging the contents of two or more ShapeIndexes. | ||||
| type rangeIterator struct { | ||||
| 	it *ShapeIndexIterator | ||||
| 	// The min and max leaf cell ids covered by the current cell. If done() is | ||||
| 	// true, these methods return a value larger than any valid cell id. | ||||
| 	rangeMin CellID | ||||
| 	rangeMax CellID | ||||
| } | ||||
| 
 | ||||
| // newRangeIterator creates a new rangeIterator positioned at the first cell of the given index. | ||||
| func newRangeIterator(index *ShapeIndex) *rangeIterator { | ||||
| 	r := &rangeIterator{ | ||||
| 		it: index.Iterator(), | ||||
| 	} | ||||
| 	r.refresh() | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| func (r *rangeIterator) cellID() CellID             { return r.it.CellID() } | ||||
| func (r *rangeIterator) indexCell() *ShapeIndexCell { return r.it.IndexCell() } | ||||
| func (r *rangeIterator) next()                      { r.it.Next(); r.refresh() } | ||||
| func (r *rangeIterator) done() bool                 { return r.it.Done() } | ||||
| 
 | ||||
| // seekTo positions the iterator at the first cell that overlaps or follows | ||||
| // the current range minimum of the target iterator, i.e. such that its | ||||
| // rangeMax >= target.rangeMin. | ||||
| func (r *rangeIterator) seekTo(target *rangeIterator) { | ||||
| 	r.it.seek(target.rangeMin) | ||||
| 	// If the current cell does not overlap target, it is possible that the | ||||
| 	// previous cell is the one we are looking for. This can only happen when | ||||
| 	// the previous cell contains target but has a smaller CellID. | ||||
| 	if r.it.Done() || r.it.CellID().RangeMin() > target.rangeMax { | ||||
| 		if r.it.Prev() && r.it.CellID().RangeMax() < target.cellID() { | ||||
| 			r.it.Next() | ||||
| 		} | ||||
| 	} | ||||
| 	r.refresh() | ||||
| } | ||||
| 
 | ||||
| // seekBeyond positions the iterator at the first cell that follows the current | ||||
| // range minimum of the target iterator. i.e. the first cell such that its | ||||
| // rangeMin > target.rangeMax. | ||||
| func (r *rangeIterator) seekBeyond(target *rangeIterator) { | ||||
| 	r.it.seek(target.rangeMax.Next()) | ||||
| 	if !r.it.Done() && r.it.CellID().RangeMin() <= target.rangeMax { | ||||
| 		r.it.Next() | ||||
| 	} | ||||
| 	r.refresh() | ||||
| } | ||||
| 
 | ||||
| // refresh updates the iterators min and max values. | ||||
| func (r *rangeIterator) refresh() { | ||||
| 	r.rangeMin = r.cellID().RangeMin() | ||||
| 	r.rangeMax = r.cellID().RangeMax() | ||||
| } | ||||
| 
 | ||||
| // referencePointForShape is a helper function for implementing various Shapes | ||||
| // ReferencePoint functions. | ||||
| // | ||||
| // Given a shape consisting of closed polygonal loops, the interior of the | ||||
| // shape is defined as the region to the left of all edges (which must be | ||||
| // oriented consistently). This function then chooses an arbitrary point and | ||||
| // returns true if that point is contained by the shape. | ||||
| // | ||||
| // Unlike Loop and Polygon, this method allows duplicate vertices and | ||||
| // edges, which requires some extra care with definitions. The rule that we | ||||
| // apply is that an edge and its reverse edge cancel each other: the result | ||||
| // is the same as if that edge pair were not present. Therefore shapes that | ||||
| // consist only of degenerate loop(s) are either empty or full; by convention, | ||||
| // the shape is considered full if and only if it contains an empty loop (see | ||||
| // laxPolygon for details). | ||||
| // | ||||
| // Determining whether a loop on the sphere contains a point is harder than | ||||
| // the corresponding problem in 2D plane geometry. It cannot be implemented | ||||
| // just by counting edge crossings because there is no such thing as a point | ||||
| // at infinity that is guaranteed to be outside the loop. | ||||
| // | ||||
| // This function requires that the given Shape have an interior. | ||||
| func referencePointForShape(shape Shape) ReferencePoint { | ||||
| 	if shape.NumEdges() == 0 { | ||||
| 		// A shape with no edges is defined to be full if and only if it | ||||
| 		// contains at least one chain. | ||||
| 		return OriginReferencePoint(shape.NumChains() > 0) | ||||
| 	} | ||||
| 	// Define a "matched" edge as one that can be paired with a corresponding | ||||
| 	// reversed edge. Define a vertex as "balanced" if all of its edges are | ||||
| 	// matched. In order to determine containment, we must find an unbalanced | ||||
| 	// vertex. Often every vertex is unbalanced, so we start by trying an | ||||
| 	// arbitrary vertex. | ||||
| 	edge := shape.Edge(0) | ||||
| 
 | ||||
| 	if ref, ok := referencePointAtVertex(shape, edge.V0); ok { | ||||
| 		return ref | ||||
| 	} | ||||
| 
 | ||||
| 	// That didn't work, so now we do some extra work to find an unbalanced | ||||
| 	// vertex (if any). Essentially we gather a list of edges and a list of | ||||
| 	// reversed edges, and then sort them. The first edge that appears in one | ||||
| 	// list but not the other is guaranteed to be unmatched. | ||||
| 	n := shape.NumEdges() | ||||
| 	var edges = make([]Edge, n) | ||||
| 	var revEdges = make([]Edge, n) | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		edge := shape.Edge(i) | ||||
| 		edges[i] = edge | ||||
| 		revEdges[i] = Edge{V0: edge.V1, V1: edge.V0} | ||||
| 	} | ||||
| 
 | ||||
| 	sortEdges(edges) | ||||
| 	sortEdges(revEdges) | ||||
| 
 | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		if edges[i].Cmp(revEdges[i]) == -1 { // edges[i] is unmatched | ||||
| 			if ref, ok := referencePointAtVertex(shape, edges[i].V0); ok { | ||||
| 				return ref | ||||
| 			} | ||||
| 		} | ||||
| 		if revEdges[i].Cmp(edges[i]) == -1 { // revEdges[i] is unmatched | ||||
| 			if ref, ok := referencePointAtVertex(shape, revEdges[i].V0); ok { | ||||
| 				return ref | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// All vertices are balanced, so this polygon is either empty or full except | ||||
| 	// for degeneracies. By convention it is defined to be full if it contains | ||||
| 	// any chain with no edges. | ||||
| 	for i := 0; i < shape.NumChains(); i++ { | ||||
| 		if shape.Chain(i).Length == 0 { | ||||
| 			return OriginReferencePoint(true) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return OriginReferencePoint(false) | ||||
| } | ||||
| 
 | ||||
| // referencePointAtVertex reports whether the given vertex is unbalanced, and | ||||
| // returns a ReferencePoint indicating if the point is contained. | ||||
| // Otherwise returns false. | ||||
| func referencePointAtVertex(shape Shape, vTest Point) (ReferencePoint, bool) { | ||||
| 	var ref ReferencePoint | ||||
| 
 | ||||
| 	// Let P be an unbalanced vertex. Vertex P is defined to be inside the | ||||
| 	// region if the region contains a particular direction vector starting from | ||||
| 	// P, namely the direction p.Ortho(). This can be calculated using | ||||
| 	// ContainsVertexQuery. | ||||
| 
 | ||||
| 	containsQuery := NewContainsVertexQuery(vTest) | ||||
| 	n := shape.NumEdges() | ||||
| 	for e := 0; e < n; e++ { | ||||
| 		edge := shape.Edge(e) | ||||
| 		if edge.V0 == vTest { | ||||
| 			containsQuery.AddEdge(edge.V1, 1) | ||||
| 		} | ||||
| 		if edge.V1 == vTest { | ||||
| 			containsQuery.AddEdge(edge.V0, -1) | ||||
| 		} | ||||
| 	} | ||||
| 	containsSign := containsQuery.ContainsVertex() | ||||
| 	if containsSign == 0 { | ||||
| 		return ref, false // There are no unmatched edges incident to this vertex. | ||||
| 	} | ||||
| 	ref.Point = vTest | ||||
| 	ref.Contained = containsSign > 0 | ||||
| 
 | ||||
| 	return ref, true | ||||
| } | ||||
| 
 | ||||
| // containsBruteForce reports whether the given shape contains the given point. | ||||
| // Most clients should not use this method, since its running time is linear in | ||||
| // the number of shape edges. Instead clients should create a ShapeIndex and use | ||||
| // ContainsPointQuery, since this strategy is much more efficient when many | ||||
| // points need to be tested. | ||||
| // | ||||
| // Polygon boundaries are treated as being semi-open (see ContainsPointQuery | ||||
| // and VertexModel for other options). | ||||
| func containsBruteForce(shape Shape, point Point) bool { | ||||
| 	if shape.Dimension() != 2 { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	refPoint := shape.ReferencePoint() | ||||
| 	if refPoint.Point == point { | ||||
| 		return refPoint.Contained | ||||
| 	} | ||||
| 
 | ||||
| 	crosser := NewEdgeCrosser(refPoint.Point, point) | ||||
| 	inside := refPoint.Contained | ||||
| 	for e := 0; e < shape.NumEdges(); e++ { | ||||
| 		edge := shape.Edge(e) | ||||
| 		inside = inside != crosser.EdgeOrVertexCrossing(edge.V0, edge.V1) | ||||
| 	} | ||||
| 	return inside | ||||
| } | ||||
							
								
								
									
										72
									
								
								vendor/github.com/golang/geo/s2/shapeutil_edge_iterator.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/golang/geo/s2/shapeutil_edge_iterator.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,72 +0,0 @@ | |||
| // Copyright 2020 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // EdgeIterator is an iterator that advances through all edges in an ShapeIndex. | ||||
| // This is different to the ShapeIndexIterator, which advances through the cells in the | ||||
| // ShapeIndex. | ||||
| type EdgeIterator struct { | ||||
| 	index    *ShapeIndex | ||||
| 	shapeID  int32 | ||||
| 	numEdges int32 | ||||
| 	edgeID   int32 | ||||
| } | ||||
| 
 | ||||
| // NewEdgeIterator creates a new edge iterator for the given index. | ||||
| func NewEdgeIterator(index *ShapeIndex) *EdgeIterator { | ||||
| 	e := &EdgeIterator{ | ||||
| 		index:   index, | ||||
| 		shapeID: -1, | ||||
| 		edgeID:  -1, | ||||
| 	} | ||||
| 
 | ||||
| 	e.Next() | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // ShapeID returns the current shape ID. | ||||
| func (e *EdgeIterator) ShapeID() int32 { return e.shapeID } | ||||
| 
 | ||||
| // EdgeID returns the current edge ID. | ||||
| func (e *EdgeIterator) EdgeID() int32 { return e.edgeID } | ||||
| 
 | ||||
| // ShapeEdgeID returns the current (shapeID, edgeID). | ||||
| func (e *EdgeIterator) ShapeEdgeID() ShapeEdgeID { return ShapeEdgeID{e.shapeID, e.edgeID} } | ||||
| 
 | ||||
| // Edge returns the current edge. | ||||
| func (e *EdgeIterator) Edge() Edge { | ||||
| 	return e.index.Shape(e.shapeID).Edge(int(e.edgeID)) | ||||
| } | ||||
| 
 | ||||
| // Done reports if the iterator is positioned at or after the last index edge. | ||||
| func (e *EdgeIterator) Done() bool { return e.shapeID >= int32(len(e.index.shapes)) } | ||||
| 
 | ||||
| // Next positions the iterator at the next index edge. | ||||
| func (e *EdgeIterator) Next() { | ||||
| 	e.edgeID++ | ||||
| 	for ; e.edgeID >= e.numEdges; e.edgeID++ { | ||||
| 		e.shapeID++ | ||||
| 		if e.shapeID >= int32(len(e.index.shapes)) { | ||||
| 			break | ||||
| 		} | ||||
| 		shape := e.index.Shape(e.shapeID) | ||||
| 		if shape == nil { | ||||
| 			e.numEdges = 0 | ||||
| 		} else { | ||||
| 			e.numEdges = int32(shape.NumEdges()) | ||||
| 		} | ||||
| 		e.edgeID = -1 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										427
									
								
								vendor/github.com/golang/geo/s2/stuv.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										427
									
								
								vendor/github.com/golang/geo/s2/stuv.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,427 +0,0 @@ | |||
| // Copyright 2014 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 
 | ||||
| 	"github.com/golang/geo/r3" | ||||
| ) | ||||
| 
 | ||||
| // | ||||
| // This file contains documentation of the various coordinate systems used | ||||
| // throughout the library. Most importantly, S2 defines a framework for | ||||
| // decomposing the unit sphere into a hierarchy of "cells". Each cell is a | ||||
| // quadrilateral bounded by four geodesics. The top level of the hierarchy is | ||||
| // obtained by projecting the six faces of a cube onto the unit sphere, and | ||||
| // lower levels are obtained by subdividing each cell into four children | ||||
| // recursively. Cells are numbered such that sequentially increasing cells | ||||
| // follow a continuous space-filling curve over the entire sphere. The | ||||
| // transformation is designed to make the cells at each level fairly uniform | ||||
| // in size. | ||||
| // | ||||
| ////////////////////////// S2 Cell Decomposition ///////////////////////// | ||||
| // | ||||
| // The following methods define the cube-to-sphere projection used by | ||||
| // the Cell decomposition. | ||||
| // | ||||
| // In the process of converting a latitude-longitude pair to a 64-bit cell | ||||
| // id, the following coordinate systems are used: | ||||
| // | ||||
| //  (id) | ||||
| //    An CellID is a 64-bit encoding of a face and a Hilbert curve position | ||||
| //    on that face. The Hilbert curve position implicitly encodes both the | ||||
| //    position of a cell and its subdivision level (see s2cellid.go). | ||||
| // | ||||
| //  (face, i, j) | ||||
| //    Leaf-cell coordinates. "i" and "j" are integers in the range | ||||
| //    [0,(2**30)-1] that identify a particular leaf cell on the given face. | ||||
| //    The (i, j) coordinate system is right-handed on each face, and the | ||||
| //    faces are oriented such that Hilbert curves connect continuously from | ||||
| //    one face to the next. | ||||
| // | ||||
| //  (face, s, t) | ||||
| //    Cell-space coordinates. "s" and "t" are real numbers in the range | ||||
| //    [0,1] that identify a point on the given face. For example, the point | ||||
| //    (s, t) = (0.5, 0.5) corresponds to the center of the top-level face | ||||
| //    cell. This point is also a vertex of exactly four cells at each | ||||
| //    subdivision level greater than zero. | ||||
| // | ||||
| //  (face, si, ti) | ||||
| //    Discrete cell-space coordinates. These are obtained by multiplying | ||||
| //    "s" and "t" by 2**31 and rounding to the nearest unsigned integer. | ||||
| //    Discrete coordinates lie in the range [0,2**31]. This coordinate | ||||
| //    system can represent the edge and center positions of all cells with | ||||
| //    no loss of precision (including non-leaf cells). In binary, each | ||||
| //    coordinate of a level-k cell center ends with a 1 followed by | ||||
| //    (30 - k) 0s. The coordinates of its edges end with (at least) | ||||
| //    (31 - k) 0s. | ||||
| // | ||||
| //  (face, u, v) | ||||
| //    Cube-space coordinates in the range [-1,1]. To make the cells at each | ||||
| //    level more uniform in size after they are projected onto the sphere, | ||||
| //    we apply a nonlinear transformation of the form u=f(s), v=f(t). | ||||
| //    The (u, v) coordinates after this transformation give the actual | ||||
| //    coordinates on the cube face (modulo some 90 degree rotations) before | ||||
| //    it is projected onto the unit sphere. | ||||
| // | ||||
| //  (face, u, v, w) | ||||
| //    Per-face coordinate frame. This is an extension of the (face, u, v) | ||||
| //    cube-space coordinates that adds a third axis "w" in the direction of | ||||
| //    the face normal. It is always a right-handed 3D coordinate system. | ||||
| //    Cube-space coordinates can be converted to this frame by setting w=1, | ||||
| //    while (u,v,w) coordinates can be projected onto the cube face by | ||||
| //    dividing by w, i.e. (face, u/w, v/w). | ||||
| // | ||||
| //  (x, y, z) | ||||
| //    Direction vector (Point). Direction vectors are not necessarily unit | ||||
| //    length, and are often chosen to be points on the biunit cube | ||||
| //    [-1,+1]x[-1,+1]x[-1,+1]. They can be be normalized to obtain the | ||||
| //    corresponding point on the unit sphere. | ||||
| // | ||||
| //  (lat, lng) | ||||
| //    Latitude and longitude (LatLng). Latitudes must be between -90 and | ||||
| //    90 degrees inclusive, and longitudes must be between -180 and 180 | ||||
| //    degrees inclusive. | ||||
| // | ||||
| // Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are | ||||
| // right-handed on all six faces. | ||||
| // | ||||
| // | ||||
| // There are a number of different projections from cell-space (s,t) to | ||||
| // cube-space (u,v): linear, quadratic, and tangent. They have the following | ||||
| // tradeoffs: | ||||
| // | ||||
| //   Linear - This is the fastest transformation, but also produces the least | ||||
| //   uniform cell sizes. Cell areas vary by a factor of about 5.2, with the | ||||
| //   largest cells at the center of each face and the smallest cells in | ||||
| //   the corners. | ||||
| // | ||||
| //   Tangent - Transforming the coordinates via Atan makes the cell sizes | ||||
| //   more uniform. The areas vary by a maximum ratio of 1.4 as opposed to a | ||||
| //   maximum ratio of 5.2. However, each call to Atan is about as expensive | ||||
| //   as all of the other calculations combined when converting from points to | ||||
| //   cell ids, i.e. it reduces performance by a factor of 3. | ||||
| // | ||||
| //   Quadratic - This is an approximation of the tangent projection that | ||||
| //   is much faster and produces cells that are almost as uniform in size. | ||||
| //   It is about 3 times faster than the tangent projection for converting | ||||
| //   cell ids to points or vice versa. Cell areas vary by a maximum ratio of | ||||
| //   about 2.1. | ||||
| // | ||||
| // Here is a table comparing the cell uniformity using each projection. Area | ||||
| // Ratio is the maximum ratio over all subdivision levels of the largest cell | ||||
| // area to the smallest cell area at that level, Edge Ratio is the maximum | ||||
| // ratio of the longest edge of any cell to the shortest edge of any cell at | ||||
| // the same level, and Diag Ratio is the ratio of the longest diagonal of | ||||
| // any cell to the shortest diagonal of any cell at the same level. | ||||
| // | ||||
| //               Area    Edge    Diag | ||||
| //              Ratio   Ratio   Ratio | ||||
| // ----------------------------------- | ||||
| // Linear:      5.200   2.117   2.959 | ||||
| // Tangent:     1.414   1.414   1.704 | ||||
| // Quadratic:   2.082   1.802   1.932 | ||||
| // | ||||
| // The worst-case cell aspect ratios are about the same with all three | ||||
| // projections. The maximum ratio of the longest edge to the shortest edge | ||||
| // within the same cell is about 1.4 and the maximum ratio of the diagonals | ||||
| // within the same cell is about 1.7. | ||||
| // | ||||
| // For Go we have chosen to use only the Quadratic approach. Other language | ||||
| // implementations may offer other choices. | ||||
| 
 | ||||
| const ( | ||||
| 	// maxSiTi is the maximum value of an si- or ti-coordinate. | ||||
| 	// It is one shift more than maxSize. The range of valid (si,ti) | ||||
| 	// values is [0..maxSiTi]. | ||||
| 	maxSiTi = maxSize << 1 | ||||
| ) | ||||
| 
 | ||||
| // siTiToST converts an si- or ti-value to the corresponding s- or t-value. | ||||
| // Value is capped at 1.0 because there is no DCHECK in Go. | ||||
| func siTiToST(si uint32) float64 { | ||||
| 	if si > maxSiTi { | ||||
| 		return 1.0 | ||||
| 	} | ||||
| 	return float64(si) / float64(maxSiTi) | ||||
| } | ||||
| 
 | ||||
| // stToSiTi converts the s- or t-value to the nearest si- or ti-coordinate. | ||||
| // The result may be outside the range of valid (si,ti)-values. Value of | ||||
| // 0.49999999999999994 (math.NextAfter(0.5, -1)), will be incorrectly rounded up. | ||||
| func stToSiTi(s float64) uint32 { | ||||
| 	if s < 0 { | ||||
| 		return uint32(s*maxSiTi - 0.5) | ||||
| 	} | ||||
| 	return uint32(s*maxSiTi + 0.5) | ||||
| } | ||||
| 
 | ||||
| // stToUV converts an s or t value to the corresponding u or v value. | ||||
| // This is a non-linear transformation from [-1,1] to [-1,1] that | ||||
| // attempts to make the cell sizes more uniform. | ||||
| // This uses what the C++ version calls 'the quadratic transform'. | ||||
| func stToUV(s float64) float64 { | ||||
| 	if s >= 0.5 { | ||||
| 		return (1 / 3.) * (4*s*s - 1) | ||||
| 	} | ||||
| 	return (1 / 3.) * (1 - 4*(1-s)*(1-s)) | ||||
| } | ||||
| 
 | ||||
| // uvToST is the inverse of the stToUV transformation. Note that it | ||||
| // is not always true that uvToST(stToUV(x)) == x due to numerical | ||||
| // errors. | ||||
| func uvToST(u float64) float64 { | ||||
| 	if u >= 0 { | ||||
| 		return 0.5 * math.Sqrt(1+3*u) | ||||
| 	} | ||||
| 	return 1 - 0.5*math.Sqrt(1-3*u) | ||||
| } | ||||
| 
 | ||||
| // face returns face ID from 0 to 5 containing the r. For points on the | ||||
| // boundary between faces, the result is arbitrary but deterministic. | ||||
| func face(r r3.Vector) int { | ||||
| 	f := r.LargestComponent() | ||||
| 	switch { | ||||
| 	case f == r3.XAxis && r.X < 0: | ||||
| 		f += 3 | ||||
| 	case f == r3.YAxis && r.Y < 0: | ||||
| 		f += 3 | ||||
| 	case f == r3.ZAxis && r.Z < 0: | ||||
| 		f += 3 | ||||
| 	} | ||||
| 	return int(f) | ||||
| } | ||||
| 
 | ||||
| // validFaceXYZToUV given a valid face for the given point r (meaning that | ||||
| // dot product of r with the face normal is positive), returns | ||||
| // the corresponding u and v values, which may lie outside the range [-1,1]. | ||||
| func validFaceXYZToUV(face int, r r3.Vector) (float64, float64) { | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		return r.Y / r.X, r.Z / r.X | ||||
| 	case 1: | ||||
| 		return -r.X / r.Y, r.Z / r.Y | ||||
| 	case 2: | ||||
| 		return -r.X / r.Z, -r.Y / r.Z | ||||
| 	case 3: | ||||
| 		return r.Z / r.X, r.Y / r.X | ||||
| 	case 4: | ||||
| 		return r.Z / r.Y, -r.X / r.Y | ||||
| 	} | ||||
| 	return -r.Y / r.Z, -r.X / r.Z | ||||
| } | ||||
| 
 | ||||
| // xyzToFaceUV converts a direction vector (not necessarily unit length) to | ||||
| // (face, u, v) coordinates. | ||||
| func xyzToFaceUV(r r3.Vector) (f int, u, v float64) { | ||||
| 	f = face(r) | ||||
| 	u, v = validFaceXYZToUV(f, r) | ||||
| 	return f, u, v | ||||
| } | ||||
| 
 | ||||
| // faceUVToXYZ turns face and UV coordinates into an unnormalized 3 vector. | ||||
| func faceUVToXYZ(face int, u, v float64) r3.Vector { | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		return r3.Vector{1, u, v} | ||||
| 	case 1: | ||||
| 		return r3.Vector{-u, 1, v} | ||||
| 	case 2: | ||||
| 		return r3.Vector{-u, -v, 1} | ||||
| 	case 3: | ||||
| 		return r3.Vector{-1, -v, -u} | ||||
| 	case 4: | ||||
| 		return r3.Vector{v, -1, -u} | ||||
| 	default: | ||||
| 		return r3.Vector{v, u, -1} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // faceXYZToUV returns the u and v values (which may lie outside the range | ||||
| // [-1, 1]) if the dot product of the point p with the given face normal is positive. | ||||
| func faceXYZToUV(face int, p Point) (u, v float64, ok bool) { | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		if p.X <= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	case 1: | ||||
| 		if p.Y <= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	case 2: | ||||
| 		if p.Z <= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	case 3: | ||||
| 		if p.X >= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	case 4: | ||||
| 		if p.Y >= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	default: | ||||
| 		if p.Z >= 0 { | ||||
| 			return 0, 0, false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	u, v = validFaceXYZToUV(face, p.Vector) | ||||
| 	return u, v, true | ||||
| } | ||||
| 
 | ||||
| // faceXYZtoUVW transforms the given point P to the (u,v,w) coordinate frame of the given | ||||
| // face where the w-axis represents the face normal. | ||||
| func faceXYZtoUVW(face int, p Point) Point { | ||||
| 	// The result coordinates are simply the dot products of P with the (u,v,w) | ||||
| 	// axes for the given face (see faceUVWAxes). | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		return Point{r3.Vector{p.Y, p.Z, p.X}} | ||||
| 	case 1: | ||||
| 		return Point{r3.Vector{-p.X, p.Z, p.Y}} | ||||
| 	case 2: | ||||
| 		return Point{r3.Vector{-p.X, -p.Y, p.Z}} | ||||
| 	case 3: | ||||
| 		return Point{r3.Vector{-p.Z, -p.Y, -p.X}} | ||||
| 	case 4: | ||||
| 		return Point{r3.Vector{-p.Z, p.X, -p.Y}} | ||||
| 	default: | ||||
| 		return Point{r3.Vector{p.Y, p.X, -p.Z}} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // faceSiTiToXYZ transforms the (si, ti) coordinates to a (not necessarily | ||||
| // unit length) Point on the given face. | ||||
| func faceSiTiToXYZ(face int, si, ti uint32) Point { | ||||
| 	return Point{faceUVToXYZ(face, stToUV(siTiToST(si)), stToUV(siTiToST(ti)))} | ||||
| } | ||||
| 
 | ||||
| // xyzToFaceSiTi transforms the (not necessarily unit length) Point to | ||||
| // (face, si, ti) coordinates and the level the Point is at. | ||||
| func xyzToFaceSiTi(p Point) (face int, si, ti uint32, level int) { | ||||
| 	face, u, v := xyzToFaceUV(p.Vector) | ||||
| 	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 of 0 and maxSiTi 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 at the end. | ||||
| 	level = maxLevel - findLSBSetNonZero64(uint64(si|maxSiTi)) | ||||
| 	if level < 0 || level != maxLevel-findLSBSetNonZero64(uint64(ti|maxSiTi)) { | ||||
| 		return face, si, ti, -1 | ||||
| 	} | ||||
| 
 | ||||
| 	// 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, the center is computed exactly the same | ||||
| 	// way p was originally computed (if it is indeed the center of a Cell); | ||||
| 	// the comparison can be exact. | ||||
| 	if p.Vector == faceSiTiToXYZ(face, si, ti).Normalize() { | ||||
| 		return face, si, ti, level | ||||
| 	} | ||||
| 
 | ||||
| 	return face, si, ti, -1 | ||||
| } | ||||
| 
 | ||||
| // uNorm returns the right-handed normal (not necessarily unit length) for an | ||||
| // edge in the direction of the positive v-axis at the given u-value on | ||||
| // the given face.  (This vector is perpendicular to the plane through | ||||
| // the sphere origin that contains the given edge.) | ||||
| func uNorm(face int, u float64) r3.Vector { | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		return r3.Vector{u, -1, 0} | ||||
| 	case 1: | ||||
| 		return r3.Vector{1, u, 0} | ||||
| 	case 2: | ||||
| 		return r3.Vector{1, 0, u} | ||||
| 	case 3: | ||||
| 		return r3.Vector{-u, 0, 1} | ||||
| 	case 4: | ||||
| 		return r3.Vector{0, -u, 1} | ||||
| 	default: | ||||
| 		return r3.Vector{0, -1, -u} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // vNorm returns the right-handed normal (not necessarily unit length) for an | ||||
| // edge in the direction of the positive u-axis at the given v-value on | ||||
| // the given face. | ||||
| func vNorm(face int, v float64) r3.Vector { | ||||
| 	switch face { | ||||
| 	case 0: | ||||
| 		return r3.Vector{-v, 0, 1} | ||||
| 	case 1: | ||||
| 		return r3.Vector{0, -v, 1} | ||||
| 	case 2: | ||||
| 		return r3.Vector{0, -1, -v} | ||||
| 	case 3: | ||||
| 		return r3.Vector{v, -1, 0} | ||||
| 	case 4: | ||||
| 		return r3.Vector{1, v, 0} | ||||
| 	default: | ||||
| 		return r3.Vector{1, 0, v} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // faceUVWAxes are the U, V, and W axes for each face. | ||||
| var faceUVWAxes = [6][3]Point{ | ||||
| 	{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{1, 0, 0}}}, | ||||
| 	{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{0, 1, 0}}}, | ||||
| 	{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{0, 0, 1}}}, | ||||
| 	{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{-1, 0, 0}}}, | ||||
| 	{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, -1, 0}}}, | ||||
| 	{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 0, -1}}}, | ||||
| } | ||||
| 
 | ||||
| // faceUVWFaces are the precomputed neighbors of each face. | ||||
| var faceUVWFaces = [6][3][2]int{ | ||||
| 	{{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}}, | ||||
| } | ||||
| 
 | ||||
| // uvwAxis returns the given axis of the given face. | ||||
| func uvwAxis(face, axis int) Point { | ||||
| 	return faceUVWAxes[face][axis] | ||||
| } | ||||
| 
 | ||||
| // uvwFaces returns the face in the (u,v,w) coordinate system on the given axis | ||||
| // in the given direction. | ||||
| func uvwFace(face, axis, direction int) int { | ||||
| 	return faceUVWFaces[face][axis][direction] | ||||
| } | ||||
| 
 | ||||
| // uAxis returns the u-axis for the given face. | ||||
| func uAxis(face int) Point { | ||||
| 	return uvwAxis(face, 0) | ||||
| } | ||||
| 
 | ||||
| // vAxis returns the v-axis for the given face. | ||||
| func vAxis(face int) Point { | ||||
| 	return uvwAxis(face, 1) | ||||
| } | ||||
| 
 | ||||
| // Return the unit-length normal for the given face. | ||||
| func unitNorm(face int) Point { | ||||
| 	return uvwAxis(face, 2) | ||||
| } | ||||
							
								
								
									
										125
									
								
								vendor/github.com/golang/geo/s2/util.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/golang/geo/s2/util.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,125 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| import "github.com/golang/geo/s1" | ||||
| 
 | ||||
| // roundAngle returns the value rounded to nearest as an int32. | ||||
| // This does not match C++ exactly for the case of x.5. | ||||
| func roundAngle(val s1.Angle) int32 { | ||||
| 	if val < 0 { | ||||
| 		return int32(val - 0.5) | ||||
| 	} | ||||
| 	return int32(val + 0.5) | ||||
| } | ||||
| 
 | ||||
| // minAngle returns the smallest of the given values. | ||||
| func minAngle(x s1.Angle, others ...s1.Angle) s1.Angle { | ||||
| 	min := x | ||||
| 	for _, y := range others { | ||||
| 		if y < min { | ||||
| 			min = y | ||||
| 		} | ||||
| 	} | ||||
| 	return min | ||||
| } | ||||
| 
 | ||||
| // maxAngle returns the largest of the given values. | ||||
| func maxAngle(x s1.Angle, others ...s1.Angle) s1.Angle { | ||||
| 	max := x | ||||
| 	for _, y := range others { | ||||
| 		if y > max { | ||||
| 			max = y | ||||
| 		} | ||||
| 	} | ||||
| 	return max | ||||
| } | ||||
| 
 | ||||
| // minChordAngle returns the smallest of the given values. | ||||
| func minChordAngle(x s1.ChordAngle, others ...s1.ChordAngle) s1.ChordAngle { | ||||
| 	min := x | ||||
| 	for _, y := range others { | ||||
| 		if y < min { | ||||
| 			min = y | ||||
| 		} | ||||
| 	} | ||||
| 	return min | ||||
| } | ||||
| 
 | ||||
| // maxChordAngle returns the largest of the given values. | ||||
| func maxChordAngle(x s1.ChordAngle, others ...s1.ChordAngle) s1.ChordAngle { | ||||
| 	max := x | ||||
| 	for _, y := range others { | ||||
| 		if y > max { | ||||
| 			max = y | ||||
| 		} | ||||
| 	} | ||||
| 	return max | ||||
| } | ||||
| 
 | ||||
| // minFloat64 returns the smallest of the given values. | ||||
| func minFloat64(x float64, others ...float64) float64 { | ||||
| 	min := x | ||||
| 	for _, y := range others { | ||||
| 		if y < min { | ||||
| 			min = y | ||||
| 		} | ||||
| 	} | ||||
| 	return min | ||||
| } | ||||
| 
 | ||||
| // maxFloat64 returns the largest of the given values. | ||||
| func maxFloat64(x float64, others ...float64) float64 { | ||||
| 	max := x | ||||
| 	for _, y := range others { | ||||
| 		if y > max { | ||||
| 			max = y | ||||
| 		} | ||||
| 	} | ||||
| 	return max | ||||
| } | ||||
| 
 | ||||
| // minInt returns the smallest of the given values. | ||||
| func minInt(x int, others ...int) int { | ||||
| 	min := x | ||||
| 	for _, y := range others { | ||||
| 		if y < min { | ||||
| 			min = y | ||||
| 		} | ||||
| 	} | ||||
| 	return min | ||||
| } | ||||
| 
 | ||||
| // maxInt returns the largest of the given values. | ||||
| func maxInt(x int, others ...int) int { | ||||
| 	max := x | ||||
| 	for _, y := range others { | ||||
| 		if y > max { | ||||
| 			max = y | ||||
| 		} | ||||
| 	} | ||||
| 	return max | ||||
| } | ||||
| 
 | ||||
| // clampInt returns the number closest to x within the range min..max. | ||||
| func clampInt(x, min, max int) int { | ||||
| 	if x < min { | ||||
| 		return min | ||||
| 	} | ||||
| 	if x > max { | ||||
| 		return max | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
							
								
								
									
										97
									
								
								vendor/github.com/golang/geo/s2/wedge_relations.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/golang/geo/s2/wedge_relations.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,97 +0,0 @@ | |||
| // Copyright 2017 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. | ||||
| 
 | ||||
| package s2 | ||||
| 
 | ||||
| // WedgeRel enumerates the possible relation between two wedges A and B. | ||||
| type WedgeRel int | ||||
| 
 | ||||
| // Define the different possible relationships between two wedges. | ||||
| // | ||||
| // Given an edge chain (x0, x1, x2), the wedge at x1 is the region to the | ||||
| // left of the edges. More precisely, it is the set of all rays from x1x0 | ||||
| // (inclusive) to x1x2 (exclusive) in the *clockwise* direction. | ||||
| const ( | ||||
| 	WedgeEquals              WedgeRel = iota // A and B are equal. | ||||
| 	WedgeProperlyContains                    // A is a strict superset of B. | ||||
| 	WedgeIsProperlyContained                 // A is a strict subset of B. | ||||
| 	WedgeProperlyOverlaps                    // A-B, B-A, and A intersect B are non-empty. | ||||
| 	WedgeIsDisjoint                          // A and B are disjoint. | ||||
| ) | ||||
| 
 | ||||
| // WedgeRelation reports the relation between two non-empty wedges | ||||
| // A=(a0, ab1, a2) and B=(b0, ab1, b2). | ||||
| func WedgeRelation(a0, ab1, a2, b0, b2 Point) WedgeRel { | ||||
| 	// There are 6 possible edge orderings at a shared vertex (all | ||||
| 	// of these orderings are circular, i.e. abcd == bcda): | ||||
| 	// | ||||
| 	//  (1) a2 b2 b0 a0: A contains B | ||||
| 	//  (2) a2 a0 b0 b2: B contains A | ||||
| 	//  (3) a2 a0 b2 b0: A and B are disjoint | ||||
| 	//  (4) a2 b0 a0 b2: A and B intersect in one wedge | ||||
| 	//  (5) a2 b2 a0 b0: A and B intersect in one wedge | ||||
| 	//  (6) a2 b0 b2 a0: A and B intersect in two wedges | ||||
| 	// | ||||
| 	// We do not distinguish between 4, 5, and 6. | ||||
| 	// We pay extra attention when some of the edges overlap.  When edges | ||||
| 	// overlap, several of these orderings can be satisfied, and we take | ||||
| 	// the most specific. | ||||
| 	if a0 == b0 && a2 == b2 { | ||||
| 		return WedgeEquals | ||||
| 	} | ||||
| 
 | ||||
| 	// Cases 1, 2, 5, and 6 | ||||
| 	if OrderedCCW(a0, a2, b2, ab1) { | ||||
| 		// The cases with this vertex ordering are 1, 5, and 6, | ||||
| 		if OrderedCCW(b2, b0, a0, ab1) { | ||||
| 			return WedgeProperlyContains | ||||
| 		} | ||||
| 
 | ||||
| 		// We are in case 5 or 6, or case 2 if a2 == b2. | ||||
| 		if a2 == b2 { | ||||
| 			return WedgeIsProperlyContained | ||||
| 		} | ||||
| 		return WedgeProperlyOverlaps | ||||
| 
 | ||||
| 	} | ||||
| 	// We are in case 2, 3, or 4. | ||||
| 	if OrderedCCW(a0, b0, b2, ab1) { | ||||
| 		return WedgeIsProperlyContained | ||||
| 	} | ||||
| 
 | ||||
| 	if OrderedCCW(a0, b0, a2, ab1) { | ||||
| 		return WedgeIsDisjoint | ||||
| 	} | ||||
| 	return WedgeProperlyOverlaps | ||||
| } | ||||
| 
 | ||||
| // WedgeContains reports whether non-empty wedge A=(a0, ab1, a2) contains B=(b0, ab1, b2). | ||||
| // Equivalent to WedgeRelation == WedgeProperlyContains || WedgeEquals. | ||||
| func WedgeContains(a0, ab1, a2, b0, b2 Point) bool { | ||||
| 	// For A to contain B (where each loop interior is defined to be its left | ||||
| 	// side), the CCW edge order around ab1 must be a2 b2 b0 a0.  We split | ||||
| 	// this test into two parts that test three vertices each. | ||||
| 	return OrderedCCW(a2, b2, b0, ab1) && OrderedCCW(b0, a0, a2, ab1) | ||||
| } | ||||
| 
 | ||||
| // WedgeIntersects reports whether non-empty wedge A=(a0, ab1, a2) intersects B=(b0, ab1, b2). | ||||
| // Equivalent but faster than WedgeRelation != WedgeIsDisjoint | ||||
| func WedgeIntersects(a0, ab1, a2, b0, b2 Point) bool { | ||||
| 	// For A not to intersect B (where each loop interior is defined to be | ||||
| 	// its left side), the CCW edge order around ab1 must be a0 b2 b0 a2. | ||||
| 	// Note that it's important to write these conditions as negatives | ||||
| 	// (!OrderedCCW(a,b,c,o) rather than Ordered(c,b,a,o)) to get correct | ||||
| 	// results when two vertices are the same. | ||||
| 	return !(OrderedCCW(a0, b2, b0, ab1) && OrderedCCW(b0, a2, a0, ab1)) | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue