Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
HARP-13120: Fix the winding of the inner rings of GeoJson polygon.
Browse files Browse the repository at this point in the history
This change ensure that the winding of the inner rings of GeoJson
Polygon features is opposite to the winding of the outer ring.

Signed-off-by: Roberto Raggi <[email protected]>
  • Loading branch information
robertoraggi committed Nov 24, 2020
1 parent 5c22a7c commit 6470275
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,25 @@ function convertLineGeometry(
);
}

function signedPolygonArea(contour: GeoPointLike[]): number {
const n = contour.length;
let area = 0.0;
for (let p = n - 1, q = 0; q < n; p = q++) {
area += contour[p][0] * contour[q][1] - contour[q][0] * contour[p][1];
}
return area * 0.5;
}

function convertRings(coordinates: GeoPointLike[][], decodeInfo: DecodeInfo): IPolygonGeometry {
const rings = coordinates.map(ring => {
let outerWinding: boolean | undefined;
const rings = coordinates.map((ring, i) => {
const { positions } = convertLineStringGeometry(ring, decodeInfo);
const winding = signedPolygonArea(ring) < 0;
if (i === 0) {
outerWinding = winding;
} else if (winding === outerWinding) {
positions.reverse();
}
return positions;
});
return { rings };
Expand Down
88 changes: 78 additions & 10 deletions test/rendering/GeoJsonDataRendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import {
Feature,
FeatureCollection,
FlatTheme,
GeoJson,
Light,
StyleSet,
Expand All @@ -21,14 +22,17 @@ import {
GeoBox,
GeoCoordinates,
GeoPointLike,
TileKey,
webMercatorProjection,
webMercatorTilingScheme
} from "@here/harp-geoutils";
import { LookAtParams, MapView, MapViewEventNames } from "@here/harp-mapview";
import { DataProvider } from "@here/harp-mapview-decoder";
import { GeoJsonTiler } from "@here/harp-mapview-decoder/index-worker";
import { RenderingTestHelper, waitForEvent } from "@here/harp-test-utils";
import { GeoJsonDataProvider, VectorTileDataSource } from "@here/harp-vectortile-datasource";
import { VectorTileDecoder } from "@here/harp-vectortile-datasource/lib/VectorTileDecoder";
import * as turf from "@turf/turf";
import * as sinon from "sinon";
import { Vector2, Vector3 } from "three";

Expand Down Expand Up @@ -65,11 +69,11 @@ describe("MapView + OmvDataSource + GeoJsonDataProvider rendering test", functio
interface GeoJsoTestOptions {
mochaTest: Mocha.Context;
testImageName: string;
theme: Theme;
geoJson: string | GeoJson;

theme: Theme | FlatTheme;
geoJson?: string | GeoJson;
lookAt?: Partial<LookAtParams>;
tileGeoJson?: boolean;
dataProvider?: DataProvider;
}

async function geoJsonTest(options: GeoJsoTestOptions) {
Expand Down Expand Up @@ -109,13 +113,15 @@ describe("MapView + OmvDataSource + GeoJsonDataProvider rendering test", functio

const geoJsonDataSource = new VectorTileDataSource({
decoder: new VectorTileDecoder(),
dataProvider: new GeoJsonDataProvider(
"geojson",
typeof options.geoJson === "string"
? new URL(options.geoJson, window.location.href)
: options.geoJson,
{ tiler }
),
dataProvider:
options.dataProvider ??
new GeoJsonDataProvider(
"geojson",
typeof options.geoJson === "string"
? new URL(options.geoJson, window.location.href)
: options.geoJson!,
{ tiler }
),
name: "geojson",
styleSetName: "geojson"
});
Expand Down Expand Up @@ -949,4 +955,66 @@ describe("MapView + OmvDataSource + GeoJsonDataProvider rendering test", functio
});
});
});

describe("Tiled GeoJson", async function() {
it("Circle with an hole with same winding as the outer ring", async function() {
const dataProvider = new (class extends DataProvider {
ready(): boolean {
return true;
}

async getTile(tileKey: TileKey) {
const geoBox = webMercatorTilingScheme.getGeoBox(tileKey);
const { longitudeSpan, center } = geoBox;
const [cx, cy] = center.toGeoPoint();

const circle = turf.circle([cx, cy], longitudeSpan * 0.1, {
units: "degrees"
});

const innerCircle = turf.circle([cx, cy], longitudeSpan * 0.04, {
units: "degrees"
});

const ring = turf.polygon([
...circle.geometry!.coordinates,
...innerCircle.geometry!.coordinates
]);

return turf.featureCollection([ring]);
}

protected async connect(): Promise<void> {}

protected dispose(): void {}
})();

await geoJsonTest({
dataProvider,
mochaTest: this,
testImageName: "geojson-polygon-holes-windings",
theme: {
styles: [
{
styleSet: "geojson",
when: ["==", ["geometry-type"], "Polygon"],
technique: "fill",
color: "red",
lineColor: "#000",
lineWidth: 1
}
]
},
lookAt: {
zoomLevel: 14.0,
target: webMercatorTilingScheme.getGeoBox(
webMercatorTilingScheme.getTileKey(
GeoCoordinates.fromGeoPoint([-90, -42.52556]),
13
)!
).center
}
});
});
});
});

0 comments on commit 6470275

Please sign in to comment.