-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the wkb library in order to encode geometries as Well-Known Binary (WKB). The library was originally a WKB writer only and created by Cloudant. It's licensed under the Apache License 2.0. I extended it with a WKB reader. This commit includes the full library, but without the build system, as it originally uses rebar, but Couchbase uses CMake. Change-Id: I04096132ed7d559bf7dd0ec6d5b137c804e249ca Reviewed-on: http://review.couchbase.org/45340 Tested-by: buildbot <build@couchbase.com> Reviewed-by: Harsha H S <hhs.couchbase@gmail.com> Reviewed-by: Volker Mische <volker.mische@gmail.com>
- Loading branch information
Showing
7 changed files
with
645 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
wkb | ||
=== | ||
|
||
OGC Well Known Binary (WKB) writer and reader in Erlang |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
% Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
% use this file except in compliance with the License. You may obtain a copy of | ||
% the License at | ||
% | ||
% http://www.apache.org/licenses/LICENSE-2.0 | ||
% | ||
% Unless required by applicable law or agreed to in writing, software | ||
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
% License for the specific language governing permissions and limitations under | ||
% the License. | ||
-define(POINT, <<"Point">>). | ||
-define(LINESTRING, <<"LineString">>). | ||
-define(POLYGON, <<"Polygon">>). | ||
-define(MULTIPOINT, <<"MultiPoint">>). | ||
-define(MULTILINESTRING, <<"MultiLineString">>). | ||
-define(MULTIPOLYGON, <<"MultiPolygon">>). | ||
-define(GEOMETRYCOLLECTION, <<"GeometryCollection">>). | ||
|
||
-define(wkbPoint, 1). | ||
-define(wkbLineString, 2). | ||
-define(wkbPolygon, 3). | ||
-define(wkbMultiPoint, 4). | ||
-define(wkbMultiLineString, 5). | ||
-define(wkbMultiPolygon, 6). | ||
-define(wkbGeometryCollection, 7). | ||
|
||
-define(wkbZ, 16#80000000). | ||
-define(wkbM, 16#40000000). | ||
|
||
-define(BIG_ENDIAN, 0). | ||
-define(LITTLE_ENDIAN, 1). | ||
|
||
|
||
% spec - http://edndoc.esri.com/arcsde/9.0/general_topics/wkb_representation.htm | ||
|
||
% // Basic Type definitions | ||
% // byte : 1 byte | ||
% // uint32 : 32 bit unsigned integer (4 bytes) | ||
% // double : double precision number (8 bytes) | ||
|
||
% // Building Blocks : Point, LinearRing | ||
|
||
% Point { | ||
% double x; | ||
% double y; | ||
% }; | ||
|
||
% LinearRing { | ||
% uint32 numPoints; | ||
% Point points[numPoints]; | ||
% } | ||
|
||
% enum wkbGeometryType { | ||
% wkbPoint = 1, | ||
% wkbLineString = 2, | ||
% wkbPolygon = 3, | ||
% wkbMultiPoint = 4, | ||
% wkbMultiLineString = 5, | ||
% wkbMultiPolygon = 6, | ||
% wkbGeometryCollection = 7 | ||
% }; | ||
|
||
% enum wkbByteOrder { | ||
|
||
% wkbXDR = 0, // Big Endian | ||
|
||
% wkbNDR = 1 // Little Endian | ||
|
||
% }; | ||
|
||
% WKBPoint { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 1 | ||
% Point point; | ||
% } | ||
|
||
% WKBLineString { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 2 | ||
% uint32 numPoints; | ||
% Point points[numPoints]; | ||
% } | ||
|
||
% WKBPolygon { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 3 | ||
% uint32 numRings; | ||
% LinearRing rings[numRings]; | ||
% } | ||
|
||
% WKBMultiPoint { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 4 | ||
% uint32 num_wkbPoints; | ||
% WKBPoint WKBPoints[num_wkbPoints]; | ||
% } | ||
|
||
% WKBMultiLineString { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 5 | ||
% uint32 num_wkbLineStrings; | ||
% WKBLineString WKBLineStrings[num_wkbLineStrings]; | ||
% } | ||
|
||
% wkbMultiPolygon { | ||
% byte byteOrder; | ||
% uint32 wkbType; // 6 | ||
% uint32 num_wkbPolygons; | ||
% WKBPolygon wkbPolygons[num_wkbPolygons]; | ||
% } | ||
|
||
% WKBGeometry { | ||
% union { | ||
% WKBPoint point; | ||
% WKBLineString linestring; | ||
% WKBPolygon polygon; | ||
% WKBGeometryCollection collection; | ||
% WKBMultiPoint mpoint; | ||
% WKBMultiLineString mlinestring; | ||
% WKBMultiPolygon mpolygon; | ||
% } | ||
% }; | ||
|
||
% WKBGeometryCollection { | ||
% byte byte_order; | ||
% uint32 wkbType; // 7 | ||
% uint32 num_wkbGeometries; | ||
% WKBGeometry wkbGeometries[num_wkbGeometries] | ||
% } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{application, 'wkb', [ | ||
{description, "wkb - OGC Well Known Binary (WKB) writer and reader in Erlang"}, | ||
{vsn, "1.2.0"}, | ||
{modules, []}]}. | ||
{registered, []}, | ||
{applications, [kernel, stdlib]}, | ||
{env, {}} | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
% Copyright 2015 Couchbase Inc. | ||
% | ||
% Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
% use this file except in compliance with the License. You may obtain a copy of | ||
% the License at | ||
% | ||
% http://www.apache.org/licenses/LICENSE-2.0 | ||
% | ||
% Unless required by applicable law or agreed to in writing, software | ||
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
% License for the specific language governing permissions and limitations under | ||
% the License. | ||
-module(wkb_reader). | ||
|
||
-include("wkb.hrl"). | ||
|
||
-export([wkb_to_geojson/1]). | ||
|
||
-type coords() :: [float()] | [[float()]] | [[[float()]]] | [[[[float()]]]]. | ||
-type geojson() :: {[{binary(), binary() | coords()}]}. | ||
|
||
|
||
-spec wkb_to_geojson(binary()) -> {ok, geojson()}. | ||
wkb_to_geojson(Data) -> | ||
{GeoJson, <<>>} = parse_wkb(Data), | ||
{ok, GeoJson}. | ||
|
||
|
||
|
||
-spec parse_wkb(binary()) -> {geojson(), binary()}. | ||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbPoint:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?POINT, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbLineString:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?LINESTRING, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbPolygon:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?POLYGON, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbMultiPoint:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?MULTIPOINT, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbMultiLineString:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?MULTILINESTRING, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbMultiPolygon:32, _/binary>> = Wkb) -> | ||
{Coords, Rest} = parse_coords(Wkb), | ||
{create_json(?MULTIPOLYGON, Coords), Rest}; | ||
|
||
parse_wkb(<<?BIG_ENDIAN:8, ?wkbGeometryCollection:32, NumWkbGeometries:32, | ||
Rest/binary>>) -> | ||
Geoms = parse_wkb_multi(Rest, NumWkbGeometries), | ||
{{[{<<"type">>, ?GEOMETRYCOLLECTION}, {<<"geometries">>, Geoms}]}, <<>>}. | ||
|
||
|
||
-spec parse_coords(binary()) -> {coords(), binary()}. | ||
parse_coords(<<?BIG_ENDIAN:8, ?wkbPoint:32, X:64/float, Y:64/float, | ||
Rest/binary>>) -> | ||
{[X, Y], Rest}; | ||
|
||
parse_coords(<<?BIG_ENDIAN:8, ?wkbLineString:32, NumPoints:32, | ||
Points:NumPoints/binary-unit:128, Rest/binary>>) -> | ||
{parse_points(Points), Rest}; | ||
|
||
parse_coords(<<?BIG_ENDIAN:8, ?wkbPolygon:32, NumRings:32, Rest/binary>>) -> | ||
parse_rings(Rest, NumRings); | ||
|
||
parse_coords(<<?BIG_ENDIAN:8, ?wkbMultiPoint:32, NumWkbPoints:32, | ||
Rest/binary>>) -> | ||
parse_coords_multi(Rest, NumWkbPoints); | ||
|
||
parse_coords(<<?BIG_ENDIAN:8, ?wkbMultiLineString:32, NumWkbLineStrings:32, | ||
Rest/binary>>) -> | ||
parse_coords_multi(Rest, NumWkbLineStrings); | ||
|
||
parse_coords(<<?BIG_ENDIAN:8, ?wkbMultiPolygon:32, NumWkbPolygons:32, | ||
Rest/binary>>) -> | ||
parse_coords_multi(Rest, NumWkbPolygons). | ||
|
||
|
||
-spec parse_points(binary()) -> [[float()]]. | ||
parse_points(Points) -> | ||
[[X, Y] || <<X:64/float, Y:64/float>> <= Points]. | ||
|
||
|
||
-spec parse_rings(binary(), non_neg_integer()) -> {[[[float()]]], binary()}. | ||
parse_rings(Rings, NumRings) -> | ||
parse_rings(Rings, NumRings, []). | ||
|
||
-spec parse_rings(binary(), non_neg_integer(), [[[float()]]]) -> | ||
{[[[float()]]], binary()}. | ||
parse_rings(Rest, NumRings, Acc) when length(Acc) =:= NumRings -> | ||
{lists:reverse(Acc), Rest}; | ||
|
||
parse_rings(<<NumPoints:32, Points:NumPoints/binary-unit:128, Rest/binary>>, | ||
NumRings, Acc) -> | ||
Parsed = parse_points(Points), | ||
parse_rings(Rest, NumRings, [Parsed | Acc]). | ||
|
||
|
||
-spec parse_coords_multi(binary(), non_neg_integer()) -> {coords(), binary()}. | ||
parse_coords_multi(WkbMulti, NumWkbMulti) -> | ||
parse_coords_multi(WkbMulti, NumWkbMulti, []). | ||
|
||
-spec parse_coords_multi(binary(), non_neg_integer(), coords()) -> | ||
{coords(), binary()}. | ||
parse_coords_multi(Rest, NumWkbMulti, Acc) when length(Acc) =:= NumWkbMulti -> | ||
{lists:reverse(Acc), Rest}; | ||
|
||
parse_coords_multi(<<WkbMulti/binary>>, NumWkbMulti, Acc) -> | ||
{Parsed, Rest} = parse_coords(WkbMulti), | ||
parse_coords_multi(Rest, NumWkbMulti, [Parsed | Acc]). | ||
|
||
|
||
-spec parse_wkb_multi(binary(), non_neg_integer()) -> [geojson()]. | ||
parse_wkb_multi(WkbMulti, NumWkbMulti) -> | ||
parse_wkb_multi(WkbMulti, NumWkbMulti, []). | ||
|
||
-spec parse_wkb_multi(binary(), non_neg_integer(), [geojson()]) -> [geojson()]. | ||
parse_wkb_multi(<<>>, NumWkbMulti, Acc) when length(Acc) =:= NumWkbMulti -> | ||
lists:reverse(Acc); | ||
|
||
parse_wkb_multi(<<WkbMulti/binary>>, NumWkbMulti, Acc) -> | ||
{Parsed, Rest} = parse_wkb(WkbMulti), | ||
parse_wkb_multi(Rest, NumWkbMulti, [Parsed | Acc]). | ||
|
||
|
||
-spec create_json(binary(), coords()) -> geojson(). | ||
create_json(Type, Coordinates) -> | ||
{[{<<"type">>, Type}, {<<"coordinates">>, Coordinates}]}. |
Oops, something went wrong.