|
22 | 22 | #include <geos/operation/grid/Cell.h> |
23 | 23 | #include <geos/operation/grid/FloodFill.h> |
24 | 24 | #include <geos/operation/grid/GridIntersection.h> |
| 25 | +#include <geos/operation/grid/PerimeterDistance.h> |
25 | 26 | #include <geos/operation/overlayng/CoverageUnion.h> |
26 | 27 | #include <geos/util.h> |
27 | 28 |
|
@@ -504,6 +505,58 @@ traverse_polygons(Matrix<std::unique_ptr<Cell>>& cells, const Grid<infinite_exte |
504 | 505 | } |
505 | 506 | } |
506 | 507 |
|
| 508 | +// Create a rectangular polygon from a set of points lying on the boundary |
| 509 | +// of a specified envelope. The provided points do not need to include the |
| 510 | +// corners of the envelope itself. |
| 511 | +static std::unique_ptr<Geometry> |
| 512 | +createRectangle(const geom::GeometryFactory& gfact, const Envelope& env, std::vector<CoordinateXY>& points) |
| 513 | +{ |
| 514 | + if (points.empty()) { |
| 515 | + return gfact.toGeometry(&env); |
| 516 | + } else { |
| 517 | + auto perimeterDistanceCmp = [&env](const CoordinateXY& a, const CoordinateXY& b) { |
| 518 | + return PerimeterDistance::getPerimeterDistance(env, a) < |
| 519 | + PerimeterDistance::getPerimeterDistance(env, b); |
| 520 | + }; |
| 521 | + |
| 522 | + points.emplace_back(env.getMinX(), env.getMinY()); |
| 523 | + points.emplace_back(env.getMinX(), env.getMaxY()); |
| 524 | + points.emplace_back(env.getMaxX(), env.getMinY()); |
| 525 | + points.emplace_back(env.getMaxX(), env.getMaxY()); |
| 526 | + |
| 527 | + std::sort(points.begin(), points.end(), perimeterDistanceCmp); |
| 528 | + points.push_back(points.front()); |
| 529 | + auto seq = std::make_unique<geom::CoordinateSequence>(0, false, false); |
| 530 | + seq->reserve(points.size()); |
| 531 | + for (const auto& c : points) { |
| 532 | + seq->add(c, false); |
| 533 | + } |
| 534 | + |
| 535 | + auto ring = gfact.createLinearRing(std::move(seq)); |
| 536 | + return gfact.createPolygon(std::move(ring)); |
| 537 | + } |
| 538 | +} |
| 539 | + |
| 540 | +// Get any points from adjacent cells that are also on the boundary of this cell. |
| 541 | +static std::vector<CoordinateXY> |
| 542 | +getExtraNodes(const Matrix<std::unique_ptr<Cell> > &cells, size_t i, size_t j) { |
| 543 | + std::vector<CoordinateXY> points; |
| 544 | + |
| 545 | + if (const Cell *above = cells(i - 1, j).get()) { |
| 546 | + above->getEdgePoints(Side::BOTTOM, points); |
| 547 | + } |
| 548 | + if (const Cell *below = cells(i + 1, j).get()) { |
| 549 | + below->getEdgePoints(Side::TOP, points); |
| 550 | + } |
| 551 | + if (const Cell *left = cells(i, j - 1).get()) { |
| 552 | + left->getEdgePoints(Side::RIGHT, points); |
| 553 | + } |
| 554 | + if (const Cell *right = cells(i, j + 1).get()) { |
| 555 | + right->getEdgePoints(Side::LEFT, points); |
| 556 | + } |
| 557 | + |
| 558 | + return points; |
| 559 | +} |
507 | 560 |
|
508 | 561 | std::unique_ptr<Geometry> |
509 | 562 | GridIntersection::subdividePolygon(const Grid<bounded_extent>& p_grid, const Geometry& g, bool includeExterior) |
@@ -547,9 +600,11 @@ GridIntersection::subdividePolygon(const Grid<bounded_extent>& p_grid, const Geo |
547 | 600 | } |
548 | 601 | } else if (!edge && areas(i - 1, j - 1) == fill_values<float>::INTERIOR) { |
549 | 602 | // Cell is entirely covered by polygon |
550 | | - // TODO: Add nodes from adjacent polygons? |
| 603 | + // In order to have the outputs forms a properly noded coverage, |
| 604 | + // we need to add nodes from adjacent polygons. |
551 | 605 | Envelope env = cell_grid.getCellEnvelope(i, j); |
552 | | - geoms.push_back(gfact.toGeometry(&env)); |
| 606 | + std::vector<CoordinateXY> points = getExtraNodes(cells, i, j); |
| 607 | + geoms.push_back(createRectangle(gfact, env, points)); |
553 | 608 | } |
554 | 609 | } |
555 | 610 | } |
|
0 commit comments