|
10 | 10 | #include <Eigen/Core> |
11 | 11 | #include <iostream> |
12 | 12 | #include <mapbox/geojson.hpp> |
| 13 | +#include <type_traits> |
13 | 14 |
|
14 | 15 | static_assert(sizeof(mapbox::geojson::point) == sizeof(Eigen::Vector3d), |
15 | 16 | "mapbox::geojson::point should be double*3 (xyz instead of xy)"); |
@@ -438,6 +439,189 @@ inline int __len__(mapbox::geojson::geometry &self) |
438 | 439 | [](auto &) -> int { return 0; }); |
439 | 440 | } |
440 | 441 |
|
| 442 | +inline double round_coords(double value, double scale) |
| 443 | +{ |
| 444 | + // rounding is hard, we just use the most simple implementation |
| 445 | + // see |
| 446 | + // - https://github.com/Tencent/rapidjson/issues/362 |
| 447 | + // - https://en.cppreference.com/w/cpp/numeric/math/round |
| 448 | + // rounding halfway cases away from zero |
| 449 | + // - |
| 450 | + // https://stackoverflow.com/questions/485525/round-for-float-in-c/24348037#24348037 |
| 451 | + // also note that, javascript Math.round differs from C++ round |
| 452 | + // e.g. std::round(-0.5) => -1.0 |
| 453 | + // Math.round(-0.5) => -0.0 |
| 454 | + return std::round(value * scale) / scale; |
| 455 | + // TODO, all should use Math.round!!! |
| 456 | + // Math.round equivalent: |
| 457 | + // std::floor(value * scale + 0.5) / scale |
| 458 | +} |
| 459 | + |
| 460 | +inline void round_coords(mapbox::geojson::point &xyz, |
| 461 | + const Eigen::Vector3d &scale) |
| 462 | +{ |
| 463 | + xyz.x = round_coords(xyz.x, scale[0]); |
| 464 | + xyz.y = round_coords(xyz.y, scale[1]); |
| 465 | + xyz.z = round_coords(xyz.z, scale[2]); |
| 466 | +} |
| 467 | + |
| 468 | +inline void round_coords(std::vector<mapbox::geojson::point> &coords, |
| 469 | + const Eigen::Vector3d &scale) |
| 470 | +{ |
| 471 | + for (auto &pt : coords) { |
| 472 | + round_coords(pt, scale); |
| 473 | + } |
| 474 | +} |
| 475 | + |
| 476 | +inline void round_coords(mapbox::geojson::geometry &g, const Eigen::Vector3d &s) |
| 477 | +{ |
| 478 | + return g.match( |
| 479 | + [&](mapbox::geojson::point &g) { return round_coords(g, s); }, |
| 480 | + [&](mapbox::geojson::multi_point &g) { round_coords(g, s); }, |
| 481 | + [&](mapbox::geojson::line_string &g) { round_coords(g, s); }, |
| 482 | + [&](mapbox::geojson::linear_ring &g) { round_coords(g, s); }, |
| 483 | + [&](mapbox::geojson::multi_line_string &gg) { |
| 484 | + for (auto &g : gg) { |
| 485 | + round_coords(g, s); |
| 486 | + } |
| 487 | + }, |
| 488 | + [&](mapbox::geojson::polygon &gg) { |
| 489 | + for (auto &g : gg) { |
| 490 | + round_coords(g, s); |
| 491 | + } |
| 492 | + }, |
| 493 | + [&](mapbox::geojson::multi_polygon &ggg) { |
| 494 | + for (auto &gg : ggg) { |
| 495 | + for (auto &g : gg) { |
| 496 | + round_coords(g, s); |
| 497 | + } |
| 498 | + } |
| 499 | + }, |
| 500 | + [&](mapbox::geojson::geometry_collection &gc) { |
| 501 | + for (auto &g : gc) { |
| 502 | + round_coords(g, s); |
| 503 | + } |
| 504 | + }, |
| 505 | + [](auto &) {}); |
| 506 | +} |
| 507 | + |
| 508 | +template <typename T> |
| 509 | +inline void round_coords(T &xyz, int lon = 8, int lat = 8, int alt = 3) |
| 510 | +{ |
| 511 | + Eigen::Vector3d scale_up(std::pow(10, lon), // |
| 512 | + std::pow(10, lat), // |
| 513 | + std::pow(10, alt)); |
| 514 | + round_coords(xyz, scale_up); |
| 515 | +} |
| 516 | + |
| 517 | +inline bool deduplicate_xyz(std::vector<mapbox::geojson::point> &geom) |
| 518 | +{ |
| 519 | + auto itr = std::unique( |
| 520 | + geom.begin(), geom.end(), |
| 521 | + [](const auto &prev, const auto &curr) { return prev == curr; }); |
| 522 | + if (itr == geom.end()) { |
| 523 | + return false; |
| 524 | + } |
| 525 | + geom.erase(itr, geom.end()); |
| 526 | + return true; |
| 527 | +} |
| 528 | +inline bool deduplicate_xyz(mapbox::geojson::empty &geom) |
| 529 | +{ |
| 530 | + return false; // dummy |
| 531 | +} |
| 532 | +inline bool deduplicate_xyz(mapbox::geojson::point &geom) |
| 533 | +{ |
| 534 | + return false; // dummy |
| 535 | +} |
| 536 | +inline bool deduplicate_xyz(mapbox::geojson::multi_point &geom) |
| 537 | +{ |
| 538 | + return deduplicate_xyz((std::vector<mapbox::geojson::point> &)geom); |
| 539 | +} |
| 540 | +inline bool deduplicate_xyz(mapbox::geojson::line_string &geom) |
| 541 | +{ |
| 542 | + return deduplicate_xyz((std::vector<mapbox::geojson::point> &)geom); |
| 543 | +} |
| 544 | +inline bool deduplicate_xyz(mapbox::geojson::multi_line_string &geom) |
| 545 | +{ |
| 546 | + bool removed = false; |
| 547 | + for (auto &g : geom) { |
| 548 | + removed |= deduplicate_xyz(g); |
| 549 | + } |
| 550 | + return removed; |
| 551 | +} |
| 552 | +inline bool deduplicate_xyz(mapbox::geojson::linear_ring &geom) |
| 553 | +{ |
| 554 | + return deduplicate_xyz((std::vector<mapbox::geojson::point> &)geom); |
| 555 | +} |
| 556 | +inline bool deduplicate_xyz(mapbox::geojson::polygon &geom) |
| 557 | +{ |
| 558 | + bool removed = false; |
| 559 | + for (auto &g : geom) { |
| 560 | + removed |= deduplicate_xyz(g); |
| 561 | + } |
| 562 | + return removed; |
| 563 | +} |
| 564 | +inline bool deduplicate_xyz(mapbox::geojson::multi_polygon &geom) |
| 565 | +{ |
| 566 | + bool removed = false; |
| 567 | + for (auto &g : geom) { |
| 568 | + removed |= deduplicate_xyz(g); |
| 569 | + } |
| 570 | + return removed; |
| 571 | +} |
| 572 | + |
| 573 | +inline bool deduplicate_xyz(mapbox::geojson::geometry &geom) |
| 574 | +{ |
| 575 | + return geom.match( |
| 576 | + [&](mapbox::geojson::multi_point &g) { return deduplicate_xyz(g); }, |
| 577 | + [&](mapbox::geojson::line_string &g) { return deduplicate_xyz(g); }, |
| 578 | + [&](mapbox::geojson::linear_ring &g) { return deduplicate_xyz(g); }, |
| 579 | + [&](mapbox::geojson::multi_line_string &g) { |
| 580 | + return deduplicate_xyz(g); |
| 581 | + }, |
| 582 | + [&](mapbox::geojson::polygon &g) { return deduplicate_xyz(g); }, |
| 583 | + [&](mapbox::geojson::multi_polygon &g) { return deduplicate_xyz(g); }, |
| 584 | + [&](mapbox::geojson::geometry_collection &gc) { |
| 585 | + bool removed = false; |
| 586 | + for (auto &g : gc) { |
| 587 | + removed |= deduplicate_xyz(g); |
| 588 | + } |
| 589 | + return removed; |
| 590 | + }, |
| 591 | + [](auto &) -> bool { return false; }); |
| 592 | +} |
| 593 | +inline bool deduplicate_xyz(mapbox::geojson::geometry_collection &geom) |
| 594 | +{ |
| 595 | + bool removed = false; |
| 596 | + for (auto &g : geom) { |
| 597 | + removed |= deduplicate_xyz(g); |
| 598 | + } |
| 599 | + return removed; |
| 600 | +} |
| 601 | + |
| 602 | +inline bool deduplicate_xyz(mapbox::geojson::feature &f) |
| 603 | +{ |
| 604 | + return deduplicate_xyz(f.geometry); |
| 605 | +} |
| 606 | +inline bool deduplicate_xyz(mapbox::geojson::feature_collection &fc) |
| 607 | +{ |
| 608 | + bool removed = false; |
| 609 | + for (auto &f : fc) { |
| 610 | + removed |= deduplicate_xyz(f); |
| 611 | + } |
| 612 | + return removed; |
| 613 | +} |
| 614 | +inline bool deduplicate_xyz(mapbox::geojson::geojson &geojson) |
| 615 | +{ |
| 616 | + return geojson.match( |
| 617 | + [](mapbox::geojson::geometry &g) { return deduplicate_xyz(g); }, |
| 618 | + [](mapbox::geojson::feature &f) { return deduplicate_xyz(f); }, |
| 619 | + [](mapbox::geojson::feature_collection &fc) { |
| 620 | + return deduplicate_xyz(fc); |
| 621 | + }, |
| 622 | + [](auto &) { return false; }); |
| 623 | +} |
| 624 | + |
441 | 625 | } // namespace cubao |
442 | 626 |
|
443 | 627 | #endif |
0 commit comments