Skip to content

Commit b8b2cde

Browse files
authored
Fix polygon layer (#105)
* Fix polygon layer * bump beta version
1 parent bfde800 commit b8b2cde

File tree

4 files changed

+99
-20
lines changed

4 files changed

+99
-20
lines changed

examples/polygon/app.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import DeckGL, { Layer, PickingInfo } from "deck.gl/typed";
55
import { GeoArrowPolygonLayer } from "@geoarrow/deck.gl-layers";
66
import * as arrow from "apache-arrow";
77

8-
const GEOARROW_POLYGON_DATA = "http://localhost:8080/small.feather";
8+
// const GEOARROW_POLYGON_DATA = "http://localhost:8080/small.feather";
9+
10+
const GEOARROW_POLYGON_DATA = "http://localhost:8080/nybb.feather";
911

1012
const INITIAL_VIEW_STATE = {
11-
latitude: 40.63403641639511,
12-
longitude: -111.91530172951025,
13+
latitude: 40.71,
14+
// longitude: -111.9,
15+
longitude: -74.0,
1316
zoom: 9,
1417
bearing: 0,
1518
pitch: 0,
@@ -59,7 +62,7 @@ function Root() {
5962
data: table,
6063
getFillColor: [0, 100, 60, 160],
6164
getLineColor: [255, 0, 0],
62-
lineWidthMinPixels: 0.1,
65+
lineWidthMinPixels: 1,
6366
extruded: false,
6467
wireframe: true,
6568
// getElevation: 0,

examples/polygon/generate_data.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import geopandas as gpd
22
import pyarrow.feather as feather
3-
from lonboard.geoarrow.geopandas_interop import geopandas_to_geoarrow
3+
from lonboard import SolidPolygonLayer
44

55

66
def main():
77
gdf = gpd.read_file("Utah.geojson.zip", engine="pyogrio")
8-
table = geopandas_to_geoarrow(gdf)
9-
feather.write_feather(table, "utah.feather", compression="uncompressed")
8+
layer = SolidPolygonLayer.from_geopandas(gdf)
9+
feather.write_feather(layer.table, "utah.feather", compression="uncompressed")
10+
11+
gdf = gpd.read_file(gpd.datasets.get_path("nybb"))
12+
layer = SolidPolygonLayer.from_geopandas(gdf)
13+
feather.write_feather(layer.table, "nybb.feather", compression="uncompressed")
1014

1115

1216
if __name__ == "__main__":

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"examples/*"
55
],
66
"name": "@geoarrow/deck.gl-layers",
7-
"version": "0.3.0-beta.11",
7+
"version": "0.3.0-beta.12",
88
"type": "module",
99
"description": "",
1010
"source": "src/index.ts",

src/polygon-layer.ts

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,82 @@ import { getGeometryVector } from "./utils.js";
1515
import { GeoArrowExtraPickingProps, getPickingInfo } from "./picking.js";
1616
import { ColorAccessor, FloatAccessor, GeoArrowPickingInfo } from "./types.js";
1717
import { EXTENSION_NAME } from "./constants.js";
18-
import { validateAccessors } from "./validate.js";
1918
import { GeoArrowSolidPolygonLayer } from "./solid-polygon-layer.js";
2019
import { GeoArrowPathLayer } from "./path-layer.js";
2120

21+
/**
22+
* Get the exterior of a PolygonVector or PolygonData as a MultiLineString
23+
*
24+
* Note that casting to a MultiLineString is a no-op of the underlying data
25+
* structure. For the purposes of the PolygonLayer we don't want to cast to a
26+
* LineString because that would change the number of rows in the table.
27+
*/
28+
export function getPolygonExterior(
29+
input: ga.vector.PolygonVector,
30+
): ga.vector.MultiLineStringVector;
31+
export function getPolygonExterior(
32+
input: ga.data.PolygonData,
33+
): ga.data.MultiLineStringData;
34+
35+
export function getPolygonExterior(
36+
input: ga.vector.PolygonVector | ga.data.PolygonData,
37+
): ga.vector.MultiLineStringVector | ga.data.MultiLineStringData {
38+
if ("data" in input) {
39+
return new arrow.Vector(input.data.map((data) => getPolygonExterior(data)));
40+
}
41+
42+
return input;
43+
}
44+
45+
/**
46+
* Get the exterior of a MultiPolygonVector or MultiPolygonData
47+
*
48+
* Note that for the purposes of the PolygonLayer, we don't want to change the
49+
* number of rows in the table. Instead, we convert each MultiPolygon to a
50+
* single MultiLineString, combining all exteriors of each contained Polygon
51+
* into a single united MultiLineString.
52+
*
53+
* This means that we need to condense both two offset buffers from the
54+
* MultiPolygonVector/Data (geomOffsets and polygonOffsets) into a single
55+
* `geomOffsets` for the new MultiLineStringVector/Data.
56+
*/
57+
export function getMultiPolygonExterior(
58+
input: ga.vector.MultiPolygonVector,
59+
): ga.vector.MultiLineStringVector;
60+
export function getMultiPolygonExterior(
61+
input: ga.data.MultiPolygonData,
62+
): ga.data.MultiLineStringData;
63+
64+
export function getMultiPolygonExterior(
65+
input: ga.vector.MultiPolygonVector | ga.data.MultiPolygonData,
66+
): ga.vector.MultiLineStringVector | ga.data.MultiLineStringData {
67+
if ("data" in input) {
68+
return new arrow.Vector(
69+
input.data.map((data) => getMultiPolygonExterior(data)),
70+
);
71+
}
72+
73+
const geomOffsets: Int32Array = input.valueOffsets;
74+
const polygonData = ga.child.getMultiPolygonChild(input);
75+
const polygonOffsets: Int32Array = polygonData.valueOffsets;
76+
const lineStringData = ga.child.getPolygonChild(polygonData);
77+
78+
const resolvedOffsets = new Int32Array(geomOffsets.length);
79+
for (let i = 0; i < resolvedOffsets.length; ++i) {
80+
// Perform the lookup
81+
resolvedOffsets[i] = polygonOffsets[geomOffsets[i]];
82+
}
83+
84+
return arrow.makeData({
85+
type: new arrow.List(polygonData.type.children[0]),
86+
length: input.length,
87+
nullCount: input.nullCount,
88+
nullBitmap: input.nullBitmap,
89+
child: lineStringData,
90+
valueOffsets: resolvedOffsets,
91+
});
92+
}
93+
2294
/** All properties supported by GeoArrowPolygonLayer */
2395
export type GeoArrowPolygonLayerProps = Omit<
2496
PolygonLayerProps,
@@ -97,6 +169,11 @@ const defaultProps: DefaultProps<GeoArrowPolygonLayerProps> = {
97169
const defaultLineColor: [number, number, number, number] = [0, 0, 0, 255];
98170
const defaultFillColor: [number, number, number, number] = [0, 0, 0, 255];
99171

172+
/** The `GeoArrowPolygonLayer` renders filled, stroked and/or extruded polygons.
173+
*
174+
* GeoArrowPolygonLayer is a CompositeLayer that wraps the
175+
* GeoArrowSolidPolygonLayer and the GeoArrowPathLayer.
176+
*/
100177
export class GeoArrowPolygonLayer<
101178
ExtraProps extends {} = {},
102179
> extends CompositeLayer<Required<GeoArrowPolygonLayerProps> & ExtraProps> {
@@ -119,12 +196,12 @@ export class GeoArrowPolygonLayer<
119196
return this._renderLayers(polygonVector);
120197
}
121198

122-
const MultiPolygonVector = getGeometryVector(
199+
const multiPolygonVector = getGeometryVector(
123200
table,
124201
EXTENSION_NAME.MULTIPOLYGON,
125202
);
126-
if (MultiPolygonVector !== null) {
127-
return this._renderLayers(MultiPolygonVector);
203+
if (multiPolygonVector !== null) {
204+
return this._renderLayers(multiPolygonVector);
128205
}
129206

130207
const geometryColumn = this.props.getPolygon;
@@ -147,16 +224,11 @@ export class GeoArrowPolygonLayer<
147224
): Layer<{}> | LayersList | null {
148225
const { data: table } = this.props;
149226

150-
if (this.props._validate) {
151-
assert(ga.vector.isPolygonVector(geometryColumn));
152-
validateAccessors(this.props, table);
153-
}
154-
155-
let getPath: ga.vector.LineStringVector | ga.vector.MultiLineStringVector;
227+
let getPath: ga.vector.MultiLineStringVector;
156228
if (ga.vector.isPolygonVector(geometryColumn)) {
157-
getPath = ga.algorithm.getPolygonExterior(geometryColumn);
229+
getPath = getPolygonExterior(geometryColumn);
158230
} else if (ga.vector.isMultiPolygonVector(geometryColumn)) {
159-
getPath = ga.algorithm.getMultiPolygonExterior(geometryColumn);
231+
getPath = getMultiPolygonExterior(geometryColumn);
160232
} else {
161233
assert(false);
162234
}

0 commit comments

Comments
 (0)