Skip to content

Commit

Permalink
feat: LineString and MultiLineString types (#17)
Browse files Browse the repository at this point in the history
This adds support for [LineString] and [MultiLineString] geometry
object types.

[LineString]: https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.4
[MultiLineString]: https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.5
  • Loading branch information
EvanHahn authored Dec 11, 2024
1 parent eda2f94 commit 0681efc
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The encoding format is inspired by [Geobuf](https://github.com/mapbox/geobuf), w

The subset of GeoJSON geometries supported are:

- Only `Point`, `Polygon`, `MultiPoint` and `MultiPolygon` are supported.
- Only `Point`, `LineString`, `MultiLineString`, `Polygon`, `MultiPoint` and `MultiPolygon` are supported.
- Only 2D positions (coordinates) are supported.
- No support for `bbox`.

Expand Down
41 changes: 41 additions & 0 deletions json/geometry.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,47 @@
},
"additionalProperties": false
},
{
"title": "LineString",
"type": "object",
"required": ["type", "coordinates"],
"properties": {
"type": {
"type": "string",
"const": "LineString"
},
"coordinates": {
"type": "array",
"items": {
"$ref": "#/definitions/position"
},
"minLength": 2
}
},
"additionalProperties": false
},
{
"title": "MultiLineString",
"type": "object",
"required": ["type", "coordinates"],
"properties": {
"type": {
"type": "string",
"const": "MultiLineString"
},
"coordinates": {
"type": "array",
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/position"
},
"minLength": 2
}
}
},
"additionalProperties": false
},
{
"title": "Polygon",
"type": "object",
Expand Down
67 changes: 67 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {
Position,
LinearRing,
Point,
LineString,
MultiLineString,
MultiPoint,
Polygon,
MultiPolygon,
Expand All @@ -23,6 +25,10 @@ export const Geometry = {
switch (message.type) {
case 'Point':
return GeometryProto.encode(encodePoint(message), writer)
case 'LineString':
return GeometryProto.encode(encodeLineString(message), writer)
case 'MultiLineString':
return GeometryProto.encode(encodeMultiLineString(message), writer)
case 'MultiPoint':
return GeometryProto.encode(encodeMultiPoint(message), writer)
case 'Polygon':
Expand All @@ -43,6 +49,10 @@ export const Geometry = {
switch (geometryProto.type) {
case GeometryType.POINT:
return decodePoint(geometryProto)
case GeometryType.LINE_STRING:
return decodeLineString(geometryProto)
case GeometryType.MULTI_LINE_STRING:
return decodeMultiLineString(geometryProto)
case GeometryType.MULTI_POINT:
return decodeMultiPoint(geometryProto)
case GeometryType.POLYGON:
Expand Down Expand Up @@ -70,6 +80,63 @@ function encodePoint({ coordinates }: Point): GeometryProto {
}
}

function decodeLineString({
coordinates: rawCoords,
}: GeometryProto): LineString {
return {
type: 'LineString',
coordinates: readPositionArray(rawCoords, {
start: 0,
length: rawCoords.length / 2,
}),
}
}

function encodeLineString({ coordinates }: LineString): GeometryProto {
return {
lengths: [],
type: GeometryType.LINE_STRING,
coordinates: coordinates.flat(),
}
}

function decodeMultiLineString({
coordinates: rawCoords,
lengths,
}: GeometryProto): MultiLineString {
let coordinates: Position[][]

if (lengths.length === 0) {
coordinates = [
readPositionArray(rawCoords, { start: 0, length: rawCoords.length / 2 }),
]
} else {
let start = 0
coordinates = lengths.map((length) => {
const line = readPositionArray(rawCoords, { start, length })
start += length * 2
return line
})
}

return {
type: 'MultiLineString',
coordinates,
}
}

function encodeMultiLineString({
coordinates,
}: MultiLineString): GeometryProto {
return {
lengths:
// For simple (most common?) case, omit lengths
coordinates.length === 1 ? [] : coordinates.map((line) => line.length),
type: GeometryType.MULTI_LINE_STRING,
coordinates: coordinates.flat(3),
}
}

function decodeMultiPoint({
coordinates: rawCoords,
}: GeometryProto): MultiPoint {
Expand Down
5 changes: 5 additions & 0 deletions test/fixture/bad-proto/too-big-length-multilinestring.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "MultiLineString",
"lengths": [2, 1],
"coordinates": [12, 34]
}
5 changes: 5 additions & 0 deletions test/fixture/bad-proto/too-short-line-multilinestring.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "MultiLineString",
"lengths": [2, 1],
"coordinates": [170.0, 45.0, 180.0, 45.0, -180.0, 45.0]
}
5 changes: 5 additions & 0 deletions test/fixture/bad-proto/too-short-linestring.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "LineString",
"lengths": [],
"coordinates": [-170, 10]
}
7 changes: 7 additions & 0 deletions test/fixture/good-geojson/linestring-2.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "LineString",
"coordinates": [
[-170, 10],
[170, 11]
]
}
8 changes: 8 additions & 0 deletions test/fixture/good-geojson/linestring-3.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "LineString",
"coordinates": [
[-170, 10],
[170, 11],
[123, 45]
]
}
9 changes: 9 additions & 0 deletions test/fixture/good-geojson/multilinestring-1-2.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "MultiLineString",
"coordinates": [
[
[170.0, 45.0],
[180.0, 45.0]
]
]
}
10 changes: 10 additions & 0 deletions test/fixture/good-geojson/multilinestring-1-3.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"type": "MultiLineString",
"coordinates": [
[
[170.0, 45.0],
[180.0, 45.0],
[-180.0, 45.0]
]
]
}
13 changes: 13 additions & 0 deletions test/fixture/good-geojson/multilinestring-2-2.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "MultiLineString",
"coordinates": [
[
[170.0, 45.0],
[180.0, 45.0]
],
[
[-180.0, 45.0],
[-170.0, 45.0]
]
]
}
20 changes: 20 additions & 0 deletions test/fixture/good-geojson/multilinestring-3-3.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"type": "MultiLineString",
"coordinates": [
[
[170.0, 45.0],
[180.0, 45.0],
[123, 45]
],
[
[-180.0, 45.0],
[-170.0, 45.0],
[123, 45]
],
[
[1, 2],
[3, 4],
[5, 6]
]
]
}

0 comments on commit 0681efc

Please sign in to comment.