Skip to content

Commit adf2d0b

Browse files
authored
Merge pull request #29 from stijnherreman/wkb-3d
Add support for 3D geometries to the WKB library
2 parents cb07f67 + 2464c7d commit adf2d0b

File tree

4 files changed

+323
-61
lines changed

4 files changed

+323
-61
lines changed

src/GeoJSON.Net.Contrib.Wkb/WkbDecode.cs

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,93 +19,93 @@ public static IGeometryObject Decode(byte[] wkb)
1919
return ParseShape(wkb, ref v_pos);
2020
}
2121

22-
private static Point ParsePoint(byte[] wkb, ref int wkbPosition)
22+
private static Point ParsePoint(byte[] wkb, ref int wkbPosition, bool hasAltitude)
2323
{
2424
var wkbGeometryType = GetType(wkb, ref wkbPosition);
2525

26-
CheckType(WkbGeometryType.Point, wkbGeometryType);
26+
CheckBaseType(WkbGeometryType.Point, wkbGeometryType);
2727

28-
Position geographicalPosition = GetGeographicPosition(wkb, ref wkbPosition);
28+
Position geographicalPosition = GetGeographicPosition(wkb, ref wkbPosition, hasAltitude);
2929

3030
return new Point(geographicalPosition);
3131
}
3232

33-
private static LineString ParseLineString(byte[] wkb, ref int wkbPosition)
33+
private static LineString ParseLineString(byte[] wkb, ref int wkbPosition, bool hasAltitude)
3434
{
3535
var wkbGeometryType = GetType(wkb, ref wkbPosition);
3636

37-
CheckType(WkbGeometryType.LineString, wkbGeometryType);
37+
CheckBaseType(WkbGeometryType.LineString, wkbGeometryType);
3838

39-
Position[] positions = ParsePositions(wkb, ref wkbPosition);
39+
Position[] positions = ParsePositions(wkb, ref wkbPosition, hasAltitude);
4040

4141
return new LineString(positions);
4242
}
4343

44-
private static Polygon ParsePolygon(byte[] wkb, ref int wkbPosition)
44+
private static Polygon ParsePolygon(byte[] wkb, ref int wkbPosition, bool hasAltitude)
4545
{
4646
var wkbGeometryType = GetType(wkb, ref wkbPosition);
4747

48-
CheckType(WkbGeometryType.Polygon, wkbGeometryType);
48+
CheckBaseType(WkbGeometryType.Polygon, wkbGeometryType);
4949

5050
var numberOfLines = GetUInt32(wkb, ref wkbPosition);
5151
var lines = new List<LineString>();
5252

5353
for (var v_ls = 0; v_ls < numberOfLines; ++v_ls)
5454
{
55-
Position[] positions = ParsePositions(wkb, ref wkbPosition);
55+
Position[] positions = ParsePositions(wkb, ref wkbPosition, hasAltitude);
5656

5757
lines.Add(new LineString(positions));
5858
}
5959

6060
return new Polygon(lines);
6161
}
6262

63-
private static MultiPoint ParseMultiPoint(byte[] wkb, ref int wkbPosition)
63+
private static MultiPoint ParseMultiPoint(byte[] wkb, ref int wkbPosition, bool hasAltitude)
6464
{
6565
var wkbGeometryType = GetType(wkb, ref wkbPosition);
6666

67-
CheckType(WkbGeometryType.MultiPoint, wkbGeometryType);
67+
CheckBaseType(WkbGeometryType.MultiPoint, wkbGeometryType);
6868

6969
var numberOfPoints = GetUInt32(wkb, ref wkbPosition);
7070
var points = new List<Point>();
7171

7272
for (var i = 0; i < numberOfPoints; ++i)
7373
{
74-
points.Add(ParsePoint(wkb, ref wkbPosition));
74+
points.Add(ParsePoint(wkb, ref wkbPosition, hasAltitude));
7575
}
7676

7777
return new MultiPoint(points);
7878
}
7979

80-
private static MultiLineString ParseMultiLineString(byte[] wkb, ref int wkbPosition)
80+
private static MultiLineString ParseMultiLineString(byte[] wkb, ref int wkbPosition, bool hasAltitude)
8181
{
8282
var wkbGeometryType = GetType(wkb, ref wkbPosition);
8383

84-
CheckType(WkbGeometryType.MultiLineString, wkbGeometryType);
84+
CheckBaseType(WkbGeometryType.MultiLineString, wkbGeometryType);
8585

8686
var numberOfLines = GetUInt32(wkb, ref wkbPosition);
8787
var lines = new List<LineString>();
8888

8989
for (var i = 0; i < numberOfLines; ++i)
9090
{
91-
lines.Add(ParseLineString(wkb, ref wkbPosition));
91+
lines.Add(ParseLineString(wkb, ref wkbPosition, hasAltitude));
9292
}
9393

9494
return new MultiLineString(lines);
9595
}
9696

97-
private static MultiPolygon ParseMultiPolygon(byte[] wkb, ref int wkbPosition)
97+
private static MultiPolygon ParseMultiPolygon(byte[] wkb, ref int wkbPosition, bool hasAltitude)
9898
{
9999
var wkbGeometryType = GetType(wkb, ref wkbPosition);
100100

101-
CheckType(WkbGeometryType.MultiPolygon, wkbGeometryType);
101+
CheckBaseType(WkbGeometryType.MultiPolygon, wkbGeometryType);
102102

103103
var numberOfPolygons = GetUInt32(wkb, ref wkbPosition);
104104
var polygons = new List<Polygon>();
105105

106106
for (var i = 0; i < numberOfPolygons; ++i)
107107
{
108-
polygons.Add(ParsePolygon(wkb, ref wkbPosition));
108+
polygons.Add(ParsePolygon(wkb, ref wkbPosition, hasAltitude));
109109
}
110110

111111
return new MultiPolygon(polygons);
@@ -115,7 +115,7 @@ private static GeometryCollection ParseGeometryCollection(byte[] wkb, ref int wk
115115
{
116116
var wkbGeometryType = GetType(wkb, ref wkbPosition);
117117

118-
CheckType(WkbGeometryType.GeometryCollection, wkbGeometryType);
118+
CheckBaseType(WkbGeometryType.GeometryCollection, wkbGeometryType);
119119

120120
var numberOfShapes = GetUInt32(wkb, ref wkbPosition);
121121
var geometries = new List<IGeometryObject>();
@@ -131,26 +131,34 @@ private static GeometryCollection ParseGeometryCollection(byte[] wkb, ref int wk
131131
private static IGeometryObject ParseShape(byte[] wkb, ref int wkbPosition)
132132
{
133133
var v_type = BitConverter.ToUInt32(wkb, wkbPosition + 1);
134+
var baseType = v_type % 1000;
135+
bool hasAltitude = v_type / 1000 == 1 || v_type / 1000 == 3;
136+
bool hasMeasure = v_type / 1000 == 2 || v_type / 1000 == 3;
134137

135-
switch (v_type)
138+
if (hasMeasure)
139+
{
140+
throw new ArgumentOutOfRangeException("WKB data with an M value is currently not supported.");
141+
}
142+
143+
switch (baseType)
136144
{
137145
case (uint)WkbGeometryType.Point:
138-
return ParsePoint(wkb, ref wkbPosition);
146+
return ParsePoint(wkb, ref wkbPosition, hasAltitude);
139147

140148
case (uint)WkbGeometryType.LineString:
141-
return ParseLineString(wkb, ref wkbPosition);
149+
return ParseLineString(wkb, ref wkbPosition, hasAltitude);
142150

143151
case (uint)WkbGeometryType.Polygon:
144-
return ParsePolygon(wkb, ref wkbPosition);
152+
return ParsePolygon(wkb, ref wkbPosition, hasAltitude);
145153

146154
case (uint)WkbGeometryType.MultiPoint:
147-
return ParseMultiPoint(wkb, ref wkbPosition);
155+
return ParseMultiPoint(wkb, ref wkbPosition, hasAltitude);
148156

149157
case (uint)WkbGeometryType.MultiLineString:
150-
return ParseMultiLineString(wkb, ref wkbPosition);
158+
return ParseMultiLineString(wkb, ref wkbPosition, hasAltitude);
151159

152160
case (uint)WkbGeometryType.MultiPolygon:
153-
return ParseMultiPolygon(wkb, ref wkbPosition);
161+
return ParseMultiPolygon(wkb, ref wkbPosition, hasAltitude);
154162

155163
case (uint)WkbGeometryType.GeometryCollection:
156164
return ParseGeometryCollection(wkb, ref wkbPosition);
@@ -174,24 +182,25 @@ private static double GetDouble(byte[] wkb, ref int wkbPosition)
174182
return doubleConversion;
175183
}
176184

177-
private static Position[] ParsePositions(byte[] wkb, ref int wkbPosition)
185+
private static Position[] ParsePositions(byte[] wkb, ref int wkbPosition, bool hasAltitude)
178186
{
179187
var numberOfPoints = GetUInt32(wkb, ref wkbPosition);
180188
Position[] positions = new Position[numberOfPoints];
181189

182190
for (var i = 0; i < numberOfPoints; ++i)
183191
{
184-
positions[i] = GetGeographicPosition(wkb, ref wkbPosition);
192+
positions[i] = GetGeographicPosition(wkb, ref wkbPosition, hasAltitude);
185193
}
186194

187195
return positions;
188196
}
189197

190-
private static Position GetGeographicPosition(byte[] wkb, ref int wkbPosition)
198+
private static Position GetGeographicPosition(byte[] wkb, ref int wkbPosition, bool hasAltitude)
191199
{
192-
var longitud = GetDouble(wkb, ref wkbPosition);
193-
var latitud = GetDouble(wkb, ref wkbPosition);
194-
return new Position(latitud, longitud);
200+
var longitude = GetDouble(wkb, ref wkbPosition);
201+
var latitude = GetDouble(wkb, ref wkbPosition);
202+
var altitude = hasAltitude ? GetDouble(wkb, ref wkbPosition) : (double?)null;
203+
return new Position(latitude, longitude, altitude);
195204
}
196205

197206
private static uint GetType(byte[] wkb, ref int wkbPosition)
@@ -206,9 +215,9 @@ private static uint GetType(byte[] wkb, ref int wkbPosition)
206215
return GetUInt32(wkb, ref wkbPosition);
207216
}
208217

209-
private static void CheckType(WkbGeometryType expected, uint actual)
218+
private static void CheckBaseType(WkbGeometryType expected, uint actual)
210219
{
211-
if (actual != (uint)expected)
220+
if (actual % 1000 != (uint)expected)
212221
{
213222
throw new ArgumentException($"Invalid wkb geometry type, expected {expected}, actual {actual}");
214223
}

0 commit comments

Comments
 (0)