1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
|
// Copyright 2005 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: ericv@google.com (Eric Veach)
#include "s2/s2polyline.h"
#include <algorithm>
#include <cmath>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "absl/container/fixed_array.h"
#include "absl/flags/flag.h"
#include "absl/memory/memory.h"
#include "absl/utility/utility.h"
#include "s2/base/commandlineflags.h"
#include "s2/base/logging.h"
#include "s2/s1angle.h"
#include "s2/s1interval.h"
#include "s2/s2builderutil_s2polyline_layer.h"
#include "s2/s2builderutil_snap_functions.h"
#include "s2/s2cap.h"
#include "s2/s2cell.h"
#include "s2/s2debug.h"
#include "s2/s2edge_crosser.h"
#include "s2/s2edge_distances.h"
#include "s2/s2error.h"
#include "s2/s2latlng_rect_bounder.h"
#include "s2/s2point.h"
#include "s2/s2point_compression.h"
#include "s2/s2pointutil.h"
#include "s2/s2polyline_measures.h"
#include "s2/s2predicates.h"
#include "s2/util/coding/coder.h"
#include "s2/util/math/matrix3x3.h"
using absl::make_unique;
using absl::Span;
using s2builderutil::S2CellIdSnapFunction;
using s2builderutil::S2PolylineLayer;
using std::max;
using std::min;
using std::set;
using std::vector;
static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
static const unsigned char kCurrentCompressedEncodingVersionNumber = 2;
S2Polyline::S2Polyline()
: s2debug_override_(S2Debug::ALLOW) {}
S2Polyline::S2Polyline(S2Polyline&& other)
: s2debug_override_(other.s2debug_override_),
num_vertices_(absl::exchange(other.num_vertices_, 0)),
vertices_(std::move(other.vertices_)) {
}
S2Polyline& S2Polyline::operator=(S2Polyline&& other) {
s2debug_override_ = other.s2debug_override_;
num_vertices_ = absl::exchange(other.num_vertices_, 0);
vertices_ = std::move(other.vertices_);
return *this;
}
S2Polyline::S2Polyline(Span<const S2Point> vertices)
: S2Polyline(vertices, S2Debug::ALLOW) {}
S2Polyline::S2Polyline(Span<const S2LatLng> vertices)
: S2Polyline(vertices, S2Debug::ALLOW) {}
S2Polyline::S2Polyline(Span<const S2Point> vertices,
S2Debug override)
: s2debug_override_(override) {
Init(vertices);
}
S2Polyline::S2Polyline(Span<const S2LatLng> vertices, S2Debug override)
: s2debug_override_(override) {
Init(vertices);
}
S2Polyline::~S2Polyline() {
}
void S2Polyline::set_s2debug_override(S2Debug override) {
s2debug_override_ = override;
}
S2Debug S2Polyline::s2debug_override() const {
return s2debug_override_;
}
void S2Polyline::Init(Span<const S2Point> vertices) {
num_vertices_ = vertices.size();
vertices_ = make_unique<S2Point[]>(num_vertices_);
std::copy(vertices.begin(), vertices.end(), &vertices_[0]);
if (absl::GetFlag(FLAGS_s2debug) && s2debug_override_ == S2Debug::ALLOW) {
S2_CHECK(IsValid());
}
}
void S2Polyline::Init(Span<const S2LatLng> vertices) {
num_vertices_ = vertices.size();
vertices_ = make_unique<S2Point[]>(num_vertices_);
for (int i = 0; i < num_vertices_; ++i) {
vertices_[i] = vertices[i].ToPoint();
}
if (absl::GetFlag(FLAGS_s2debug) && s2debug_override_ == S2Debug::ALLOW) {
S2_CHECK(IsValid());
}
}
void S2Polyline::InitToSnapped(const S2Polyline& polyline, int snap_level) {
S2Builder builder{S2Builder::Options(S2CellIdSnapFunction(snap_level))};
InitFromBuilder(polyline, &builder);
}
void S2Polyline::InitToSimplified(
const S2Polyline& polyline, const S2Builder::SnapFunction& snap_function) {
S2Builder::Options options(snap_function);
options.set_simplify_edge_chains(true);
S2Builder builder(options);
InitFromBuilder(polyline, &builder);
}
void S2Polyline::InitFromBuilder(const S2Polyline& polyline,
S2Builder* builder) {
builder->StartLayer(absl::make_unique<S2PolylineLayer>(this));
builder->AddPolyline(polyline);
S2Error error;
S2_CHECK(builder->Build(&error)) << "Could not build polyline: " << error;
}
bool S2Polyline::IsValid() const {
S2Error error;
if (FindValidationError(&error)) {
S2_LOG_IF(ERROR, absl::GetFlag(FLAGS_s2debug)) << error;
return false;
}
return true;
}
bool S2Polyline::FindValidationError(S2Error* error) const {
// All vertices must be unit length.
for (int i = 0; i < num_vertices(); ++i) {
if (!S2::IsUnitLength(vertex(i))) {
error->Init(S2Error::NOT_UNIT_LENGTH, "Vertex %d is not unit length", i);
return true;
}
}
// Adjacent vertices must not be identical or antipodal.
for (int i = 1; i < num_vertices(); ++i) {
if (vertex(i - 1) == vertex(i)) {
error->Init(S2Error::DUPLICATE_VERTICES,
"Vertices %d and %d are identical", i - 1, i);
return true;
}
if (vertex(i - 1) == -vertex(i)) {
error->Init(S2Error::ANTIPODAL_VERTICES,
"Vertices %d and %d are antipodal", i - 1, i);
return true;
}
}
return false;
}
S2Polyline::S2Polyline(const S2Polyline& src)
: num_vertices_(src.num_vertices_),
vertices_(new S2Point[num_vertices_]) {
// TODO(user, ericv): Decide whether to use a canonical empty
// representation.
// If num_vertices_ == 0, then src.vertices_ will be null if src was default
// constructed.
if (num_vertices_ != 0) {
std::copy(&src.vertices_[0], &src.vertices_[num_vertices_], &vertices_[0]);
}
}
S2Polyline* S2Polyline::Clone() const {
return new S2Polyline(*this);
}
S1Angle S2Polyline::GetLength() const {
return S2::GetLength(vertices_span());
}
S2Point S2Polyline::GetCentroid() const {
return S2::GetCentroid(vertices_span());
}
int S2Polyline::GetSnapLevel() const {
int snap_level = -1;
for (int i = 0; i < num_vertices_; ++i) {
int face;
unsigned int si, ti;
const int level = S2::XYZtoFaceSiTi(vertices_[i], &face, &si, &ti);
if (level < 0) return level; // Vertex is not a cell center.
if (level != snap_level) {
if (snap_level < 0) {
snap_level = level; // First vertex.
} else {
return -1; // Vertices at more than one cell level.
}
}
}
return snap_level;
}
S2Point S2Polyline::GetSuffix(double fraction, int* next_vertex) const {
S2_DCHECK_GT(num_vertices(), 0);
// 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) {
*next_vertex = 1;
return vertex(0);
}
S1Angle length_sum;
for (int i = 1; i < num_vertices(); ++i) {
length_sum += S1Angle(vertex(i-1), vertex(i));
}
S1Angle target = fraction * length_sum;
for (int i = 1; i < num_vertices(); ++i) {
S1Angle length(vertex(i-1), vertex(i));
if (target < length) {
// This interpolates with respect to arc length rather than
// straight-line distance, and produces a unit-length result.
S2Point result = S2::GetPointOnLine(vertex(i - 1), vertex(i), target);
// It is possible that (result == vertex(i)) due to rounding errors.
*next_vertex = (result == vertex(i)) ? (i + 1) : i;
return result;
}
target -= length;
}
*next_vertex = num_vertices();
return vertex(num_vertices() - 1);
}
S2Point S2Polyline::Interpolate(double fraction) const {
int next_vertex;
return GetSuffix(fraction, &next_vertex);
}
double S2Polyline::UnInterpolate(const S2Point& point, int next_vertex) const {
S2_DCHECK_GT(num_vertices(), 0);
if (num_vertices() < 2) {
return 0;
}
S1Angle length_sum;
for (int i = 1; i < next_vertex; ++i) {
length_sum += S1Angle(vertex(i-1), vertex(i));
}
S1Angle length_to_point = length_sum + S1Angle(vertex(next_vertex-1), point);
for (int i = next_vertex; i < num_vertices(); ++i) {
length_sum += S1Angle(vertex(i-1), vertex(i));
}
// The ratio can be greater than 1.0 due to rounding errors or because the
// point is not exactly on the polyline.
return min(1.0, length_to_point / length_sum);
}
S2Point S2Polyline::Project(const S2Point& point, int* next_vertex) const {
S2_DCHECK_GT(num_vertices(), 0);
if (num_vertices() == 1) {
// If there is only one vertex, it is always closest to any given point.
*next_vertex = 1;
return vertex(0);
}
// Initial value larger than any possible distance on the unit sphere.
S1Angle min_distance = S1Angle::Radians(10);
int min_index = -1;
// Find the line segment in the polyline that is closest to the point given.
for (int i = 1; i < num_vertices(); ++i) {
S1Angle distance_to_segment = S2::GetDistance(point, vertex(i-1),
vertex(i));
if (distance_to_segment < min_distance) {
min_distance = distance_to_segment;
min_index = i;
}
}
S2_DCHECK_NE(min_index, -1);
// Compute the point on the segment found that is closest to the point given.
S2Point closest_point =
S2::Project(point, vertex(min_index - 1), vertex(min_index));
*next_vertex = min_index + (closest_point == vertex(min_index) ? 1 : 0);
return closest_point;
}
bool S2Polyline::IsOnRight(const S2Point& point) const {
S2_DCHECK_GE(num_vertices(), 2);
int next_vertex;
S2Point closest_point = Project(point, &next_vertex);
S2_DCHECK_GE(next_vertex, 1);
S2_DCHECK_LE(next_vertex, num_vertices());
// 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.
if (closest_point == vertex(next_vertex-1) && next_vertex > 1 &&
next_vertex < num_vertices()) {
if (point == vertex(next_vertex-1))
return false; // Polyline vertices are not on the RHS.
return s2pred::OrderedCCW(vertex(next_vertex-2), point, vertex(next_vertex),
vertex(next_vertex-1));
}
// Otherwise, the closest point C is incident to exactly one polyline edge.
// We test the point P against that edge.
if (next_vertex == num_vertices())
--next_vertex;
return s2pred::Sign(point, vertex(next_vertex), vertex(next_vertex - 1)) > 0;
}
bool S2Polyline::Intersects(const S2Polyline& line) const {
if (num_vertices() <= 0 || line.num_vertices() <= 0) {
return false;
}
if (!GetRectBound().Intersects(line.GetRectBound())) {
return false;
}
// TODO(ericv): Use S2ShapeIndex here.
for (int i = 1; i < num_vertices(); ++i) {
S2EdgeCrosser crosser(&vertex(i - 1), &vertex(i), &line.vertex(0));
for (int j = 1; j < line.num_vertices(); ++j) {
if (crosser.CrossingSign(&line.vertex(j)) >= 0) {
return true;
}
}
}
return false;
}
void S2Polyline::Reverse() {
if (num_vertices_ > 0) {
std::reverse(&vertices_[0], &vertices_[num_vertices_]);
}
}
S2LatLngRect S2Polyline::GetRectBound() const {
S2LatLngRectBounder bounder;
for (int i = 0; i < num_vertices(); ++i) {
bounder.AddPoint(vertex(i));
}
return bounder.GetBound();
}
S2Cap S2Polyline::GetCapBound() const {
return GetRectBound().GetCapBound();
}
bool S2Polyline::MayIntersect(const S2Cell& cell) const {
if (num_vertices() == 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 (int i = 0; i < num_vertices(); ++i) {
if (cell.Contains(vertex(i))) return true;
}
S2Point cell_vertices[4];
for (int i = 0; i < 4; ++i) {
cell_vertices[i] = cell.GetVertex(i);
}
for (int j = 0; j < 4; ++j) {
S2EdgeCrosser crosser(&cell_vertices[j], &cell_vertices[(j+1)&3],
&vertex(0));
for (int i = 1; i < num_vertices(); ++i) {
if (crosser.CrossingSign(&vertex(i)) >= 0) {
// There is a proper crossing, or two vertices were the same.
return true;
}
}
}
return false;
}
void S2Polyline::Encode(Encoder* const encoder) const {
EncodeUncompressed(encoder);
}
void S2Polyline::EncodeUncompressed(Encoder* const encoder) const {
encoder->Ensure(num_vertices_ * sizeof(vertices_[0]) + 10); // sufficient
encoder->put8(kCurrentLosslessEncodingVersionNumber);
encoder->put32(num_vertices_);
encoder->putn(vertices_.get(), sizeof(vertices_[0]) * num_vertices_);
S2_DCHECK_GE(encoder->avail(), 0);
}
bool S2Polyline::Decode(Decoder* const decoder) {
if (decoder->avail() < sizeof(unsigned char)) {
return false;
}
const unsigned char version = decoder->get8();
switch (version) {
case kCurrentLosslessEncodingVersionNumber:
return DecodeUncompressed(decoder);
case kCurrentCompressedEncodingVersionNumber:
return DecodeCompressed(decoder);
}
return false;
}
bool S2Polyline::DecodeUncompressed(Decoder* const decoder) {
if (decoder->avail() < sizeof(uint32)) {
return false;
}
num_vertices_ = decoder->get32();
// Check the bytes available before allocating memory in case of
// corrupt/malicious input.
if (decoder->avail() < num_vertices_ * sizeof(S2Point)) return false;
vertices_ = make_unique<S2Point[]>(num_vertices_);
decoder->getn(&vertices_[0], num_vertices_ * sizeof(vertices_[0]));
if (absl::GetFlag(FLAGS_s2debug) && s2debug_override_ == S2Debug::ALLOW) {
S2_CHECK(IsValid());
}
return true;
}
void S2Polyline::EncodeMostCompact(Encoder* encoder) const {
if (num_vertices_ == 0) {
EncodeCompressed(encoder, {}, S2::kMaxCellLevel);
return;
}
// Convert S2Points to (face, si, ti) representation.
absl::FixedArray<S2XYZFaceSiTi> all_vertices(num_vertices_);
for (int i = 0; i < num_vertices_; ++i) {
all_vertices[i].xyz = vertices_[i];
all_vertices[i].cell_level =
S2::XYZtoFaceSiTi(all_vertices[i].xyz, &all_vertices[i].face,
&all_vertices[i].si, &all_vertices[i].ti);
}
// Computes a histogram of the cell levels at which the vertices are snapped.
// cell_level is -1 for unsnapped, or 0 through kMaxCellLevel if snapped,
// so we add one to it to get a non-negative index. (histogram[0] is the
// number of unsnapped vertices, histogram[i] the number of vertices
// snapped at level i-1).
std::array<int, S2::kMaxCellLevel + 2> histogram;
histogram.fill(0);
for (int i = 0; i < num_vertices_; ++i) {
histogram[all_vertices[i].cell_level + 1] += 1;
}
// Compute the level at which most of the vertices are snapped.
// If multiple levels have the same maximum number of vertices
// snapped to it, the first one (lowest level number / largest
// area / smallest encoding length) will be chosen, so this
// is desired. Start with histogram[1] since histogram[0] is
// the number of unsnapped vertices, which we don't care about.
const auto max_iter =
std::max_element(histogram.begin() + 1, histogram.end());
// snap_level will be at position histogram[snap_level + 1], see above.
const int snap_level = max_iter - (histogram.begin() + 1);
const int num_snapped = *max_iter;
// The compressed encoding requires approximately 4 bytes per vertex plus
// "exact_point_size" for each unsnapped vertex (encoded as an S2Point plus
// the index at which it is located).
int exact_point_size = sizeof(S2Point) + 2;
int num_unsnapped = num_vertices_ - num_snapped;
int compressed_size = 4 * num_vertices_ + exact_point_size * num_unsnapped;
int lossless_size = sizeof(S2Point) * num_vertices_;
if (compressed_size < lossless_size) {
EncodeCompressed(encoder, all_vertices, snap_level);
} else {
EncodeUncompressed(encoder);
}
}
void S2Polyline::EncodeCompressed(Encoder* encoder,
absl::Span<const S2XYZFaceSiTi> all_vertices,
int snap_level) const {
// Set version number.
encoder->Ensure(2 + Encoder::kVarintMax32);
encoder->put8(kCurrentCompressedEncodingVersionNumber);
encoder->put8(snap_level);
encoder->put_varint32(num_vertices_);
S2EncodePointsCompressed(all_vertices, snap_level, encoder);
}
bool S2Polyline::DecodeCompressed(Decoder* decoder) {
if (decoder->avail() < sizeof(uint8)) return false;
const int snap_level = decoder->get8();
if (snap_level > S2::kMaxCellLevel) return false;
vector<S2Point> points;
uint32 num_vertices;
if (!decoder->get_varint32(&num_vertices)) return false;
if (num_vertices == 0) {
// Empty polylines are allowed.
Init(points);
return true;
}
// TODO(b/209937354): Prevent large allocations like in DecodeUncompressed.
// This is more complicated due to the compressed encoding, but perhaps the
// minimum required size can be bounded.
points.resize(num_vertices);
if (!S2DecodePointsCompressed(decoder, snap_level, absl::MakeSpan(points))) {
return false;
}
Init(points);
return true;
}
namespace {
// Given a polyline, a tolerance distance, and a start index, this function
// returns the maximal end index such that the line segment between these two
// vertices passes within "tolerance" of all interior vertices, in order.
int FindEndVertex(const S2Polyline& polyline,
S1Angle tolerance, int index) {
S2_DCHECK_GE(tolerance.radians(), 0);
S2_DCHECK_LT((index + 1), polyline.num_vertices());
// 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 (-Pi, Pi]. 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
// S1Interval, i.e. an interval on the unit circle.
Matrix3x3_d frame;
const S2Point& origin = polyline.vertex(index);
S2::GetFrame(origin, &frame);
// 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).
S1Interval current_wedge = S1Interval::Full();
double last_distance = 0;
for (++index; index < polyline.num_vertices(); ++index) {
const S2Point& candidate = polyline.vertex(index);
double distance = origin.Angle(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 > M_PI/2 && last_distance > 0) break;
// Vertices must be in increasing order along the ray, except for the
// initial disc around the origin.
if (distance < last_distance && last_distance > tolerance.radians()) break;
last_distance = 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.radians()) 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.
S2Point direction = S2::ToFrame(frame, candidate);
double center = atan2(direction.y(), direction.x());
if (!current_wedge.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.
double half_angle = asin(sin(tolerance.radians()) / sin(distance));
S1Interval target = S1Interval::FromPoint(center).Expanded(half_angle);
current_wedge = current_wedge.Intersection(target);
S2_DCHECK(!current_wedge.is_empty());
}
// 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;
}
} // namespace
void S2Polyline::SubsampleVertices(S1Angle tolerance,
vector<int>* indices) const {
indices->clear();
if (num_vertices() == 0) return;
indices->push_back(0);
S1Angle clamped_tolerance = max(tolerance, S1Angle::Radians(0));
for (int index = 0; index + 1 < num_vertices(); ) {
int next_index = FindEndVertex(*this, clamped_tolerance, index);
// Don't create duplicate adjacent vertices.
if (vertex(next_index) != vertex(index)) {
indices->push_back(next_index);
}
index = next_index;
}
}
bool S2Polyline::Equals(const S2Polyline& b) const {
if (num_vertices() != b.num_vertices()) return false;
for (int offset = 0; offset < num_vertices(); ++offset) {
if (vertex(offset) != b.vertex(offset)) return false;
}
return true;
}
bool S2Polyline::ApproxEquals(const S2Polyline& b, S1Angle max_error) const {
if (num_vertices() != b.num_vertices()) return false;
for (int offset = 0; offset < num_vertices(); ++offset) {
if (!S2::ApproxEquals(vertex(offset), b.vertex(offset), max_error)) {
return false;
}
}
return true;
}
size_t S2Polyline::SpaceUsed() const {
return sizeof(*this) + num_vertices() * sizeof(S2Point);
}
namespace {
// Return the first i > "index" such that the ith vertex of "pline" is not at
// the same point as the "index"th vertex. Returns pline.num_vertices() if
// there is no such value of i.
inline int NextDistinctVertex(const S2Polyline& pline, int index) {
const S2Point& initial = pline.vertex(index);
do {
++index;
} while (index < pline.num_vertices() && pline.vertex(index) == initial);
return index;
}
// This struct represents a search state in the NearlyCovers algorithm
// below. See the description of the algorithm for details.
struct SearchState {
inline SearchState(int i_val, int j_val, bool i_in_progress_val)
: i(i_val), j(j_val), i_in_progress(i_in_progress_val) {}
int i;
int j;
bool i_in_progress;
};
// This operator is needed for storing SearchStates in a set. The ordering
// chosen has no special meaning.
struct SearchStateKeyCompare {
bool operator() (const SearchState& a, const SearchState& b) const {
if (a.i != b.i) return a.i < b.i;
if (a.j != b.j) return a.j < b.j;
return a.i_in_progress < b.i_in_progress;
}
};
} // namespace
bool S2Polyline::NearlyCovers(const S2Polyline& covered,
S1Angle max_error) const {
// NOTE: This algorithm is described assuming that adjacent vertices in a
// polyline are never at the same point. That is, the ith and i+1th vertices
// of a polyline are never at the same point in space. The implementation
// does not make this assumption.
// DEFINITIONS:
// - edge "i" of a polyline is the edge from the ith to i+1th vertex.
// - covered_j is a polyline consisting of edges 0 through j of "covered."
// - this_i is a polyline consisting of edges 0 through i of this polyline.
//
// A search state is represented as an (int, int, bool) tuple, (i, j,
// i_in_progress). Using the "drive a car" analogy from the header comment, a
// search state signifies that you can drive one car along "covered" from its
// first vertex through a point on its jth edge, and another car along this
// polyline from some point on or before its ith edge to a to a point on its
// ith edge, such that no car ever goes backward, and the cars are always
// within "max_error" of each other. If i_in_progress is true, it means that
// you can definitely drive along "covered" through the jth vertex (beginning
// of the jth edge). Otherwise, you can definitely drive along "covered"
// through the point on the jth edge of "covered" closest to the ith vertex of
// this polyline.
//
// The algorithm begins by finding all edges of this polyline that are within
// "max_error" of the first vertex of "covered," and adding search states
// representing all of these possible starting states to the stack of
// "pending" states.
//
// The algorithm proceeds by popping the next pending state,
// (i,j,i_in_progress), off of the stack. First it checks to see if that
// state represents finding a valid covering of "covered" and returns true if
// so. Next, if the state represents reaching the end of this polyline
// without finding a successful covering, the algorithm moves on to the next
// state in the stack. Otherwise, if state (i+1,j,false) is valid, it is
// added to the stack of pending states. Same for state (i,j+1,true).
//
// We need the stack because when "i" and "j" can both be incremented,
// sometimes only one choice leads to a solution. We use a set to keep track
// of visited states to avoid duplicating work. With the set, the worst-case
// number of states examined is O(n+m) where n = this->num_vertices() and m =
// covered.num_vertices(). Without it, the amount of work could be as high as
// O((n*m)^2). Using set, the running time is O((n*m) log (n*m)).
//
// TODO(user): Benchmark this, and see if the set is worth it.
if (covered.num_vertices() == 0) return true;
if (this->num_vertices() == 0) return false;
vector<SearchState> pending;
set<SearchState, SearchStateKeyCompare> done;
// Find all possible starting states.
for (int i = 0, next_i = NextDistinctVertex(*this, 0), next_next_i;
next_i < this->num_vertices(); i = next_i, next_i = next_next_i) {
next_next_i = NextDistinctVertex(*this, next_i);
S2Point closest_point = S2::Project(
covered.vertex(0), this->vertex(i), this->vertex(next_i));
// In order to avoid duplicate starting states, we exclude the end vertex
// of each edge *except* for the last non-degenerate edge.
if ((next_next_i == this->num_vertices() ||
closest_point != this->vertex(next_i)) &&
S1Angle(closest_point, covered.vertex(0)) <= max_error) {
pending.push_back(SearchState(i, 0, true));
}
}
while (!pending.empty()) {
const SearchState state = pending.back();
pending.pop_back();
if (!done.insert(state).second) continue;
const int next_i = NextDistinctVertex(*this, state.i);
const int next_j = NextDistinctVertex(covered, state.j);
if (next_j == covered.num_vertices()) {
return true;
} else if (next_i == this->num_vertices()) {
continue;
}
S2Point i_begin, j_begin;
if (state.i_in_progress) {
j_begin = covered.vertex(state.j);
i_begin = S2::Project(
j_begin, this->vertex(state.i), this->vertex(next_i));
} else {
i_begin = this->vertex(state.i);
j_begin = S2::Project(
i_begin, covered.vertex(state.j), covered.vertex(next_j));
}
if (S2::IsEdgeBNearEdgeA(j_begin, covered.vertex(next_j),
i_begin, this->vertex(next_i), max_error)) {
pending.push_back(SearchState(next_i, state.j, false));
}
if (S2::IsEdgeBNearEdgeA(i_begin, this->vertex(next_i),
j_begin, covered.vertex(next_j), max_error)) {
pending.push_back(SearchState(state.i, next_j, true));
}
}
return false;
}
void S2Polyline::Shape::Init(const S2Polyline* polyline) {
S2_LOG_IF(WARNING, polyline->num_vertices() == 1)
<< "S2Polyline::Shape with one vertex has no edges";
polyline_ = polyline;
}
int S2Polyline::Shape::num_chains() const {
return min(1, Shape::num_edges()); // Avoid virtual call.
}
S2Shape::Chain S2Polyline::Shape::chain(int i) const {
S2_DCHECK_EQ(i, 0);
return Chain(0, Shape::num_edges()); // Avoid virtual call.
}
|