Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

toBeMultiPolygonWithHole #44

Closed
M-Scott-Lassiter opened this issue Jun 8, 2022 · 1 comment
Closed

toBeMultiPolygonWithHole #44

M-Scott-Lassiter opened this issue Jun 8, 2022 · 1 comment

Comments

@M-Scott-Lassiter
Copy link
Owner

M-Scott-Lassiter commented Jun 8, 2022

Description

GeoJSON MultiPolygon geometries support multiple linear rings in their coordinates array following the same rules as those in polygons. Each ring after the first represents a hole.

  • A linear ring is the boundary of a surface or the boundary of a hole in a surface.
  • A linear ring MUST follow the right-hand rule with respect to the area it bounds, i.e., exterior rings are counterclockwise, and holes are clockwise.

Note: the [GJ2008] specification did not discuss linear ring winding order. For backwards compatibility, parsers SHOULD NOT reject Polygons that do not follow the right-hand rule.

Though a linear ring is not explicitly represented as a GeoJSON geometry type, it leads to a canonical formulation of the Polygon geometry type definition as follows:

  • For type "Polygon", the "coordinates" member MUST be an array of linear ring coordinate arrays.

For Polygons with more than one of these rings, the first MUST be the exterior ring, and any others MUST be interior rings. The exterior ring bounds the surface, and the interior rings (if present) bound holes within the surface.

~ https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6

This matcher will make no assumptions about winding order. A planned future matcher will check that. Per the standard, as long as it meets the above criteria, it is a valid polygon object. It will validate the geometry using the toBeMultiPolygonGeometry functionality.

Example Matcher Usage

const multiPolygon1 = {
    type: 'MultiPolygon',
    coordinates: [
        [
            [
                [102.0, 2.0],
                [103.0, 2.0],
                [103.0, 3.0],
                [102.0, 3.0],
                [102.0, 2.0]
            ]
        ],
        [
            [
                [100.0, 0.0],
                [101.0, 0.0],
                [101.0, 1.0],
                [100.0, 1.0],
                [100.0, 0.0]
            ],
            [
                [100.2, 0.2],
                [100.2, 0.8],
                [100.8, 0.8],
                [100.8, 0.2],
                [100.2, 0.2]
            ]
        ]
    ]
}
const multiPolygon2 = {
    type: 'MultiPolygon',
    coordinates: [
        [
            [
                [102.0, 2.0],
                [103.0, 2.0],
                [103.0, 3.0],
                [102.0, 3.0],
                [102.0, 2.0]
            ]
        ]
    ]
}
const polygon = {
    type: 'Polygon',
    coordinates: [
        [
            [100.0, 0.0],
            [101.0, 0.0],
            [101.0, 1.0],
            [100.0, 1.0],
            [100.0, 0.0]
        ],
        [
            [100.2, 0.2],
            [100.2, 0.8],
            [100.8, 0.8],
            [100.8, 0.2],
            [100.2, 0.2]
        ]
    ]
}

expect(multiPolygon1).toBeMultiPolygonWithHole()

expect(multiPolygon2).not.toBeMultiPolygonWithHole()
expect(polygon).not.toBeMultiPolygonWithHole()

Passing Tests

Good MultiPolygons

Test each for clockwise and counterclockwise:

  • Known good MultiPolygon with a single hole
  • Known good MultiPolygon with 2 holes
  • Stress test: Known good MultiPolygon with 30 polygons each with 30 holes

Illogical Holes

  • Hole has 0 area
  • Hole is outside geometry
  • Hole is wound counterclockwise

Failing Tests

Invalid Inputs To Matcher

Rejects each of the following:

  • Each of the seven Geometry objects except MultiPolygon
  • An invalid MultiPolygon
  • Feature and FeatureCollection object
  • undefined, null, false, true, 0, NaN
  • { someProp: 'I am not GeoJSON', id: 4 }
  • {}
  • '',
  • 'Random Feature',
  •   JSON.stringify({
          type: 'Polygon',
          coordinates: [
              [
                  [
                      [102.0, 2.0],
                      [103.0, 2.0],
                      [103.0, 3.0],
                      [102.0, 3.0],
                      [102.0, 2.0]
                  ]
              ],
              [
                  [
                      [100.0, 0.0],
                      [101.0, 0.0],
                      [101.0, 1.0],
                      [100.0, 1.0],
                      [100.0, 0.0]
                  ],
                  [
                      [100.2, 0.2],
                      [100.2, 0.8],
                      [100.8, 0.8],
                      [100.8, 0.2],
                      [100.2, 0.2]
                  ]
              ]
          ]
      })

Non-Passing Polygons

  • MultiPolygon with bad geometry
  • MultiPolygon with no hole
@M-Scott-Lassiter M-Scott-Lassiter added the new matcher proposal Proposal for a new GeoJSON matcher label Jun 8, 2022
@M-Scott-Lassiter M-Scott-Lassiter self-assigned this Jun 8, 2022
@M-Scott-Lassiter M-Scott-Lassiter added matchers/geometries and removed new matcher proposal Proposal for a new GeoJSON matcher labels Jun 10, 2022
github-actions bot pushed a commit that referenced this issue Jun 10, 2022
## [1.4.0](v1.3.0...v1.4.0) (2022-06-10)

### 🎁 Feature Changes

* **toBeMultiPolygonWithHole:** add new matcher ([6668a1b](6668a1b)), closes [#44](#44)
* **toBePolygonWithHole:** add new matcher ([3eb435c](3eb435c)), closes [#43](#43)
* add Typescript support for the matchers ([602c33b](602c33b)), closes [#42](#42)
@M-Scott-Lassiter
Copy link
Owner Author

🎉 This issue has been resolved in version 1.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant