@loaders.gl/wkt 4.0.0-alpha.24 → 4.0.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/README.md +4 -1
  2. package/dist/dist.min.js +1449 -404
  3. package/dist/es5/hex-wkb-loader.js +64 -0
  4. package/dist/es5/hex-wkb-loader.js.map +1 -0
  5. package/dist/es5/index.js +76 -1
  6. package/dist/es5/index.js.map +1 -1
  7. package/dist/es5/lib/encode-twkb.js +269 -0
  8. package/dist/es5/lib/encode-twkb.js.map +1 -0
  9. package/dist/es5/lib/encode-wkb.js +12 -10
  10. package/dist/es5/lib/encode-wkb.js.map +1 -1
  11. package/dist/es5/lib/encode-wkt-crs.js +32 -0
  12. package/dist/es5/lib/encode-wkt-crs.js.map +1 -0
  13. package/dist/es5/lib/encode-wkt.js +1 -1
  14. package/dist/es5/lib/encode-wkt.js.map +1 -1
  15. package/dist/es5/lib/parse-hex-wkb.js +2 -0
  16. package/dist/es5/lib/parse-hex-wkb.js.map +1 -0
  17. package/dist/es5/lib/parse-twkb.js +263 -0
  18. package/dist/es5/lib/parse-twkb.js.map +1 -0
  19. package/dist/es5/lib/parse-wkb-header.js +114 -0
  20. package/dist/es5/lib/parse-wkb-header.js.map +1 -0
  21. package/dist/es5/lib/parse-wkb.js +59 -52
  22. package/dist/es5/lib/parse-wkb.js.map +1 -1
  23. package/dist/es5/lib/parse-wkt-crs.js +106 -0
  24. package/dist/es5/lib/parse-wkt-crs.js.map +1 -0
  25. package/dist/es5/lib/parse-wkt.js +210 -153
  26. package/dist/es5/lib/parse-wkt.js.map +1 -1
  27. package/dist/es5/lib/utils/base64-encoder.js +26 -0
  28. package/dist/es5/lib/utils/base64-encoder.js.map +1 -0
  29. package/dist/es5/lib/utils/binary-reader.js +98 -0
  30. package/dist/es5/lib/utils/binary-reader.js.map +1 -0
  31. package/dist/es5/lib/utils/binary-writer.js +2 -2
  32. package/dist/es5/lib/utils/binary-writer.js.map +1 -1
  33. package/dist/es5/lib/utils/hex-encoder.js +63 -0
  34. package/dist/es5/lib/utils/hex-encoder.js.map +1 -0
  35. package/dist/es5/lib/utils/hex-transcoder.js +41 -0
  36. package/dist/es5/lib/utils/hex-transcoder.js.map +1 -0
  37. package/dist/es5/lib/utils/version.js +1 -1
  38. package/dist/es5/twkb-loader.js +53 -0
  39. package/dist/es5/twkb-loader.js.map +1 -0
  40. package/dist/es5/twkb-writer.js +40 -0
  41. package/dist/es5/twkb-writer.js.map +1 -0
  42. package/dist/es5/wkb-loader.js +8 -4
  43. package/dist/es5/wkb-loader.js.map +1 -1
  44. package/dist/es5/wkb-writer.js +2 -3
  45. package/dist/es5/wkb-writer.js.map +1 -1
  46. package/dist/es5/wkt-crs-loader.js +47 -0
  47. package/dist/es5/wkt-crs-loader.js.map +1 -0
  48. package/dist/es5/wkt-crs-writer.js +49 -0
  49. package/dist/es5/wkt-crs-writer.js.map +1 -0
  50. package/dist/es5/wkt-loader.js +10 -6
  51. package/dist/es5/wkt-loader.js.map +1 -1
  52. package/dist/es5/wkt-writer.js +2 -3
  53. package/dist/es5/wkt-writer.js.map +1 -1
  54. package/dist/es5/workers/wkb-worker.js.map +1 -1
  55. package/dist/es5/workers/wkt-worker.js.map +1 -1
  56. package/dist/esm/hex-wkb-loader.js +37 -0
  57. package/dist/esm/hex-wkb-loader.js.map +1 -0
  58. package/dist/esm/index.js +10 -1
  59. package/dist/esm/index.js.map +1 -1
  60. package/dist/esm/lib/encode-twkb.js +180 -0
  61. package/dist/esm/lib/encode-twkb.js.map +1 -0
  62. package/dist/esm/lib/encode-wkb.js +4 -4
  63. package/dist/esm/lib/encode-wkb.js.map +1 -1
  64. package/dist/esm/lib/encode-wkt-crs.js +21 -0
  65. package/dist/esm/lib/encode-wkt-crs.js.map +1 -0
  66. package/dist/esm/lib/encode-wkt.js +1 -1
  67. package/dist/esm/lib/encode-wkt.js.map +1 -1
  68. package/dist/esm/lib/parse-hex-wkb.js +2 -0
  69. package/dist/esm/lib/parse-hex-wkb.js.map +1 -0
  70. package/dist/esm/lib/parse-twkb.js +256 -0
  71. package/dist/esm/lib/parse-twkb.js.map +1 -0
  72. package/dist/esm/lib/parse-wkb-header.js +105 -0
  73. package/dist/esm/lib/parse-wkb-header.js.map +1 -0
  74. package/dist/esm/lib/parse-wkb.js +59 -51
  75. package/dist/esm/lib/parse-wkb.js.map +1 -1
  76. package/dist/esm/lib/parse-wkt-crs.js +96 -0
  77. package/dist/esm/lib/parse-wkt-crs.js.map +1 -0
  78. package/dist/esm/lib/parse-wkt.js +204 -152
  79. package/dist/esm/lib/parse-wkt.js.map +1 -1
  80. package/dist/esm/lib/utils/base64-encoder.js +7 -0
  81. package/dist/esm/lib/utils/base64-encoder.js.map +1 -0
  82. package/dist/esm/lib/utils/binary-reader.js +67 -0
  83. package/dist/esm/lib/utils/binary-reader.js.map +1 -0
  84. package/dist/esm/lib/utils/binary-writer.js +1 -1
  85. package/dist/esm/lib/utils/binary-writer.js.map +1 -1
  86. package/dist/esm/lib/utils/hex-encoder.js +40 -0
  87. package/dist/esm/lib/utils/hex-encoder.js.map +1 -0
  88. package/dist/esm/lib/utils/hex-transcoder.js +34 -0
  89. package/dist/esm/lib/utils/hex-transcoder.js.map +1 -0
  90. package/dist/esm/lib/utils/version.js +1 -1
  91. package/dist/esm/twkb-loader.js +24 -0
  92. package/dist/esm/twkb-loader.js.map +1 -0
  93. package/dist/esm/twkb-writer.js +14 -0
  94. package/dist/esm/twkb-writer.js.map +1 -0
  95. package/dist/esm/wkb-loader.js +6 -2
  96. package/dist/esm/wkb-loader.js.map +1 -1
  97. package/dist/esm/wkb-writer.js +1 -1
  98. package/dist/esm/wkb-writer.js.map +1 -1
  99. package/dist/esm/wkt-crs-loader.js +19 -0
  100. package/dist/esm/wkt-crs-loader.js.map +1 -0
  101. package/dist/esm/wkt-crs-writer.js +19 -0
  102. package/dist/esm/wkt-crs-writer.js.map +1 -0
  103. package/dist/esm/wkt-loader.js +8 -3
  104. package/dist/esm/wkt-loader.js.map +1 -1
  105. package/dist/esm/wkt-writer.js +2 -2
  106. package/dist/esm/wkt-writer.js.map +1 -1
  107. package/dist/esm/workers/wkb-worker.js.map +1 -1
  108. package/dist/esm/workers/wkt-worker.js.map +1 -1
  109. package/dist/src/bundle.d.ts.map +1 -0
  110. package/dist/src/hex-wkb-loader.d.ts +17 -0
  111. package/dist/src/hex-wkb-loader.d.ts.map +1 -0
  112. package/dist/src/index.d.ts +15 -0
  113. package/dist/src/index.d.ts.map +1 -0
  114. package/dist/src/lib/encode-twkb.d.ts +6 -0
  115. package/dist/src/lib/encode-twkb.d.ts.map +1 -0
  116. package/dist/{lib → src/lib}/encode-wkb.d.ts +16 -3
  117. package/dist/src/lib/encode-wkb.d.ts.map +1 -0
  118. package/dist/src/lib/encode-wkt-crs.d.ts +10 -0
  119. package/dist/src/lib/encode-wkt-crs.d.ts.map +1 -0
  120. package/dist/{lib → src/lib}/encode-wkt.d.ts +1 -1
  121. package/dist/src/lib/encode-wkt.d.ts.map +1 -0
  122. package/dist/src/lib/parse-hex-wkb.d.ts +1 -0
  123. package/dist/src/lib/parse-hex-wkb.d.ts.map +1 -0
  124. package/dist/src/lib/parse-twkb.d.ts +9 -0
  125. package/dist/src/lib/parse-twkb.d.ts.map +1 -0
  126. package/dist/src/lib/parse-wkb-header.d.ts +39 -0
  127. package/dist/src/lib/parse-wkb-header.d.ts.map +1 -0
  128. package/dist/src/lib/parse-wkb.d.ts +5 -0
  129. package/dist/src/lib/parse-wkb.d.ts.map +1 -0
  130. package/dist/src/lib/parse-wkt-crs.d.ts +15 -0
  131. package/dist/src/lib/parse-wkt-crs.d.ts.map +1 -0
  132. package/dist/src/lib/parse-wkt.d.ts +30 -0
  133. package/dist/src/lib/parse-wkt.d.ts.map +1 -0
  134. package/dist/src/lib/utils/base64-encoder.d.ts +5 -0
  135. package/dist/src/lib/utils/base64-encoder.d.ts.map +1 -0
  136. package/dist/src/lib/utils/binary-reader.d.ts +18 -0
  137. package/dist/src/lib/utils/binary-reader.d.ts.map +1 -0
  138. package/dist/{lib → src/lib}/utils/binary-writer.d.ts +1 -1
  139. package/dist/src/lib/utils/binary-writer.d.ts.map +1 -0
  140. package/dist/src/lib/utils/hex-encoder.d.ts +15 -0
  141. package/dist/src/lib/utils/hex-encoder.d.ts.map +1 -0
  142. package/dist/src/lib/utils/hex-transcoder.d.ts +15 -0
  143. package/dist/src/lib/utils/hex-transcoder.d.ts.map +1 -0
  144. package/dist/src/lib/utils/version.d.ts.map +1 -0
  145. package/dist/src/twkb-loader.d.ts +16 -0
  146. package/dist/src/twkb-loader.d.ts.map +1 -0
  147. package/dist/src/twkb-writer.d.ts +7 -0
  148. package/dist/src/twkb-writer.d.ts.map +1 -0
  149. package/dist/src/wkb-loader.d.ts +16 -0
  150. package/dist/src/wkb-loader.d.ts.map +1 -0
  151. package/dist/src/wkb-writer.d.ts +7 -0
  152. package/dist/src/wkb-writer.d.ts.map +1 -0
  153. package/dist/src/wkt-crs-loader.d.ts +12 -0
  154. package/dist/src/wkt-crs-loader.d.ts.map +1 -0
  155. package/dist/src/wkt-crs-writer.d.ts +13 -0
  156. package/dist/src/wkt-crs-writer.d.ts.map +1 -0
  157. package/dist/src/wkt-loader.d.ts +18 -0
  158. package/dist/src/wkt-loader.d.ts.map +1 -0
  159. package/dist/src/wkt-writer.d.ts +10 -0
  160. package/dist/src/wkt-writer.d.ts.map +1 -0
  161. package/dist/{workers → src/workers}/wkb-worker.d.ts.map +1 -1
  162. package/dist/{workers → src/workers}/wkt-worker.d.ts.map +1 -1
  163. package/dist/tsconfig.tsbuildinfo +1 -0
  164. package/dist/wkt-worker.js +222 -183
  165. package/package.json +4 -4
  166. package/src/hex-wkb-loader.ts +61 -0
  167. package/src/index.ts +22 -1
  168. package/src/lib/encode-twkb.ts +304 -0
  169. package/src/lib/encode-wkb.ts +5 -5
  170. package/src/lib/encode-wkt-crs.ts +39 -0
  171. package/src/lib/encode-wkt.ts +3 -2
  172. package/src/lib/parse-hex-wkb.ts +0 -0
  173. package/src/lib/parse-twkb.ts +356 -0
  174. package/src/lib/parse-wkb-header.ts +172 -0
  175. package/src/lib/parse-wkb.ts +69 -58
  176. package/src/lib/parse-wkt-crs.ts +147 -0
  177. package/src/lib/parse-wkt.ts +275 -174
  178. package/src/lib/utils/base64-encoder.ts +153 -0
  179. package/src/lib/utils/binary-reader.ts +72 -0
  180. package/src/lib/utils/binary-writer.ts +1 -1
  181. package/src/lib/utils/hex-encoder.ts +58 -0
  182. package/src/lib/utils/hex-transcoder.ts +50 -0
  183. package/src/twkb-loader.ts +42 -0
  184. package/src/twkb-writer.ts +25 -0
  185. package/src/wkb-loader.ts +17 -5
  186. package/src/wkb-writer.ts +6 -4
  187. package/src/wkt-crs-loader.ts +33 -0
  188. package/src/wkt-crs-writer.ts +37 -0
  189. package/src/wkt-loader.ts +20 -6
  190. package/src/wkt-writer.ts +12 -5
  191. package/src/workers/wkb-worker.ts +2 -0
  192. package/src/workers/wkt-worker.ts +2 -0
  193. package/dist/bundle.d.ts.map +0 -1
  194. package/dist/index.d.ts +0 -5
  195. package/dist/index.d.ts.map +0 -1
  196. package/dist/lib/encode-wkb.d.ts.map +0 -1
  197. package/dist/lib/encode-wkt.d.ts.map +0 -1
  198. package/dist/lib/parse-wkb.d.ts +0 -3
  199. package/dist/lib/parse-wkb.d.ts.map +0 -1
  200. package/dist/lib/parse-wkt.d.ts +0 -8
  201. package/dist/lib/parse-wkt.d.ts.map +0 -1
  202. package/dist/lib/utils/binary-writer.d.ts.map +0 -1
  203. package/dist/lib/utils/version.d.ts.map +0 -1
  204. package/dist/wkb-loader.d.ts +0 -11
  205. package/dist/wkb-loader.d.ts.map +0 -1
  206. package/dist/wkb-writer.d.ts +0 -6
  207. package/dist/wkb-writer.d.ts.map +0 -1
  208. package/dist/wkt-loader.d.ts +0 -11
  209. package/dist/wkt-loader.d.ts.map +0 -1
  210. package/dist/wkt-writer.d.ts +0 -6
  211. package/dist/wkt-writer.d.ts.map +0 -1
  212. /package/dist/{bundle.d.ts → src/bundle.d.ts} +0 -0
  213. /package/dist/{lib → src/lib}/utils/version.d.ts +0 -0
  214. /package/dist/{workers → src/workers}/wkb-worker.d.ts +0 -0
  215. /package/dist/{workers → src/workers}/wkt-worker.d.ts +0 -0
@@ -0,0 +1,356 @@
1
+ // loaders.gl, MIT license
2
+ // Forked from https://github.com/cschwarz/wkx under MIT license, Copyright (c) 2013 Christian Schwarz
3
+
4
+ import type {Geometry, GeometryCollection} from '@loaders.gl/schema';
5
+ import type {Point, LineString, Polygon} from '@loaders.gl/schema';
6
+ import type {MultiPoint, MultiLineString, MultiPolygon} from '@loaders.gl/schema';
7
+ import {BinaryReader} from './utils/binary-reader';
8
+ import {WKBGeometryType} from './parse-wkb-header';
9
+
10
+ /**
11
+ * Check if an array buffer might be a TWKB array buffer
12
+ * @param arrayBuffer The array buffer to check
13
+ * @returns false if this is definitely not a TWKB array buffer, true if it might be a TWKB array buffer
14
+ */
15
+ export function isTWKB(arrayBuffer: ArrayBuffer): boolean {
16
+ const binaryReader = new BinaryReader(arrayBuffer);
17
+
18
+ const type = binaryReader.readUInt8();
19
+ const geometryType = type & 0x0f;
20
+
21
+ // Only geometry types 1 to 7 (point to geometry collection are currently defined)
22
+ if (geometryType < 1 || geometryType > 7) {
23
+ return false;
24
+ }
25
+
26
+ return true;
27
+ }
28
+
29
+ /** Passed around between parsing functions, extracted from the header */
30
+ type TWKBHeader = {
31
+ geometryType: WKBGeometryType;
32
+
33
+ hasBoundingBox: boolean;
34
+ hasSizeAttribute: boolean;
35
+ hasIdList: boolean;
36
+ hasExtendedPrecision: boolean;
37
+ isEmpty: boolean;
38
+
39
+ precision: number;
40
+ precisionFactor: number;
41
+
42
+ hasZ: boolean;
43
+ zPrecision: number;
44
+ zPrecisionFactor: number;
45
+
46
+ hasM: boolean;
47
+ mPrecision: number;
48
+ mPrecisionFactor: number;
49
+ };
50
+
51
+ export function parseTWKBGeometry(arrayBuffer: ArrayBuffer): Geometry {
52
+ const binaryReader = new BinaryReader(arrayBuffer);
53
+
54
+ const context = parseTWKBHeader(binaryReader);
55
+
56
+ if (context.hasSizeAttribute) {
57
+ binaryReader.readVarInt();
58
+ }
59
+
60
+ if (context.hasBoundingBox) {
61
+ let dimensions = 2;
62
+
63
+ if (context.hasZ) {
64
+ dimensions++;
65
+ }
66
+ if (context.hasM) {
67
+ dimensions++;
68
+ }
69
+
70
+ // TODO why are we throwing away these datums?
71
+ for (let i = 0; i < dimensions; i++) {
72
+ binaryReader.readVarInt();
73
+ binaryReader.readVarInt();
74
+ }
75
+ }
76
+
77
+ return parseGeometry(binaryReader, context, context.geometryType);
78
+ }
79
+
80
+ function parseTWKBHeader(binaryReader: BinaryReader): TWKBHeader {
81
+ const type = binaryReader.readUInt8();
82
+ const metadataHeader = binaryReader.readUInt8();
83
+
84
+ const geometryType = type & 0x0f;
85
+
86
+ const precision = zigZagDecode(type >> 4);
87
+
88
+ const hasExtendedPrecision = Boolean((metadataHeader >> 3) & 1);
89
+ let hasZ = false;
90
+ let hasM = false;
91
+ let zPrecision = 0;
92
+ let zPrecisionFactor = 1;
93
+ let mPrecision = 0;
94
+ let mPrecisionFactor = 1;
95
+
96
+ if (hasExtendedPrecision) {
97
+ const extendedPrecision = binaryReader.readUInt8();
98
+ hasZ = (extendedPrecision & 0x01) === 0x01;
99
+ hasM = (extendedPrecision & 0x02) === 0x02;
100
+
101
+ zPrecision = zigZagDecode((extendedPrecision & 0x1c) >> 2);
102
+ zPrecisionFactor = Math.pow(10, zPrecision);
103
+
104
+ mPrecision = zigZagDecode((extendedPrecision & 0xe0) >> 5);
105
+ mPrecisionFactor = Math.pow(10, mPrecision);
106
+ }
107
+
108
+ return {
109
+ geometryType,
110
+
111
+ precision,
112
+ precisionFactor: Math.pow(10, precision),
113
+
114
+ hasBoundingBox: Boolean((metadataHeader >> 0) & 1),
115
+ hasSizeAttribute: Boolean((metadataHeader >> 1) & 1),
116
+ hasIdList: Boolean((metadataHeader >> 2) & 1),
117
+ hasExtendedPrecision,
118
+ isEmpty: Boolean((metadataHeader >> 4) & 1),
119
+
120
+ hasZ,
121
+ hasM,
122
+ zPrecision,
123
+ zPrecisionFactor,
124
+ mPrecision,
125
+ mPrecisionFactor
126
+ };
127
+ }
128
+
129
+ function parseGeometry(
130
+ binaryReader: BinaryReader,
131
+ context: TWKBHeader,
132
+ geometryType: WKBGeometryType
133
+ ): Geometry {
134
+ switch (geometryType) {
135
+ case WKBGeometryType.Point:
136
+ return parsePoint(binaryReader, context);
137
+ case WKBGeometryType.LineString:
138
+ return parseLineString(binaryReader, context);
139
+ case WKBGeometryType.Polygon:
140
+ return parsePolygon(binaryReader, context);
141
+ case WKBGeometryType.MultiPoint:
142
+ return parseMultiPoint(binaryReader, context);
143
+ case WKBGeometryType.MultiLineString:
144
+ return parseMultiLineString(binaryReader, context);
145
+ case WKBGeometryType.MultiPolygon:
146
+ return parseMultiPolygon(binaryReader, context);
147
+ case WKBGeometryType.GeometryCollection:
148
+ return parseGeometryCollection(binaryReader, context);
149
+ default:
150
+ throw new Error(`GeometryType ${geometryType} not supported`);
151
+ }
152
+ }
153
+
154
+ // GEOMETRIES
155
+
156
+ function parsePoint(reader: BinaryReader, context: TWKBHeader): Point {
157
+ if (context.isEmpty) {
158
+ return {type: 'Point', coordinates: []};
159
+ }
160
+
161
+ return {type: 'Point', coordinates: readFirstPoint(reader, context)};
162
+ }
163
+
164
+ function parseLineString(reader: BinaryReader, context: TWKBHeader): LineString {
165
+ if (context.isEmpty) {
166
+ return {type: 'LineString', coordinates: []};
167
+ }
168
+
169
+ const pointCount = reader.readVarInt();
170
+
171
+ const previousPoint = makePreviousPoint(context);
172
+
173
+ const points: number[][] = [];
174
+ for (let i = 0; i < pointCount; i++) {
175
+ points.push(parseNextPoint(reader, context, previousPoint));
176
+ }
177
+
178
+ return {type: 'LineString', coordinates: points};
179
+ }
180
+
181
+ function parsePolygon(reader: BinaryReader, context: TWKBHeader): Polygon {
182
+ if (context.isEmpty) {
183
+ return {type: 'Polygon', coordinates: []};
184
+ }
185
+
186
+ const ringCount = reader.readVarInt();
187
+
188
+ const previousPoint = makePreviousPoint(context);
189
+
190
+ const exteriorRingLength = reader.readVarInt();
191
+ const exteriorRing: number[][] = [];
192
+
193
+ for (let i = 0; i < exteriorRingLength; i++) {
194
+ exteriorRing.push(parseNextPoint(reader, context, previousPoint));
195
+ }
196
+
197
+ const polygon: number[][][] = [exteriorRing];
198
+ for (let i = 1; i < ringCount; i++) {
199
+ const interiorRingCount = reader.readVarInt();
200
+
201
+ const interiorRing: number[][] = [];
202
+ for (let j = 0; j < interiorRingCount; j++) {
203
+ interiorRing.push(parseNextPoint(reader, context, previousPoint));
204
+ }
205
+
206
+ polygon.push(interiorRing);
207
+ }
208
+
209
+ return {type: 'Polygon', coordinates: polygon};
210
+ }
211
+
212
+ function parseMultiPoint(reader: BinaryReader, context: TWKBHeader): MultiPoint {
213
+ if (context.isEmpty) {
214
+ return {type: 'MultiPoint', coordinates: []};
215
+ }
216
+
217
+ const previousPoint = makePreviousPoint(context);
218
+ const pointCount = reader.readVarInt();
219
+
220
+ const coordinates: number[][] = [];
221
+ for (let i = 0; i < pointCount; i++) {
222
+ coordinates.push(parseNextPoint(reader, context, previousPoint));
223
+ }
224
+
225
+ return {type: 'MultiPoint', coordinates};
226
+ }
227
+
228
+ function parseMultiLineString(reader: BinaryReader, context: TWKBHeader): MultiLineString {
229
+ if (context.isEmpty) {
230
+ return {type: 'MultiLineString', coordinates: []};
231
+ }
232
+
233
+ const previousPoint = makePreviousPoint(context);
234
+ const lineStringCount = reader.readVarInt();
235
+
236
+ const coordinates: number[][][] = [];
237
+ for (let i = 0; i < lineStringCount; i++) {
238
+ const pointCount = reader.readVarInt();
239
+
240
+ const lineString: number[][] = [];
241
+ for (let j = 0; j < pointCount; j++) {
242
+ lineString.push(parseNextPoint(reader, context, previousPoint));
243
+ }
244
+
245
+ coordinates.push(lineString);
246
+ }
247
+
248
+ return {type: 'MultiLineString', coordinates};
249
+ }
250
+
251
+ function parseMultiPolygon(reader: BinaryReader, context: TWKBHeader): MultiPolygon {
252
+ if (context.isEmpty) {
253
+ return {type: 'MultiPolygon', coordinates: []};
254
+ }
255
+
256
+ const previousPoint = makePreviousPoint(context);
257
+ const polygonCount = reader.readVarInt();
258
+
259
+ const polygons: number[][][][] = [];
260
+ for (let i = 0; i < polygonCount; i++) {
261
+ const ringCount = reader.readVarInt();
262
+
263
+ const exteriorPointCount = reader.readVarInt();
264
+
265
+ const exteriorRing: number[][] = [];
266
+ for (let j = 0; j < exteriorPointCount; j++) {
267
+ exteriorRing.push(parseNextPoint(reader, context, previousPoint));
268
+ }
269
+
270
+ const polygon: number[][][] = exteriorRing ? [exteriorRing] : [];
271
+
272
+ for (let j = 1; j < ringCount; j++) {
273
+ const interiorRing: number[][] = [];
274
+
275
+ const interiorRingLength = reader.readVarInt();
276
+
277
+ for (let k = 0; k < interiorRingLength; k++) {
278
+ interiorRing.push(parseNextPoint(reader, context, previousPoint));
279
+ }
280
+
281
+ polygon.push(interiorRing);
282
+ }
283
+
284
+ polygons.push(polygon);
285
+ }
286
+
287
+ return {type: 'MultiPolygon', coordinates: polygons};
288
+ }
289
+
290
+ /** Geometry collection not yet supported */
291
+ function parseGeometryCollection(reader: BinaryReader, context: TWKBHeader): GeometryCollection {
292
+ return {type: 'GeometryCollection', geometries: []};
293
+ /**
294
+ if (context.isEmpty) {
295
+ return {type: 'GeometryCollection', geometries: []};
296
+ }
297
+
298
+ const geometryCount = reader.readVarInt();
299
+
300
+ const geometries: Geometry[] = new Array(geometryCount);
301
+ for (let i = 0; i < geometryCount; i++) {
302
+ const geometry = parseGeometry(reader, context, geometryType);
303
+ geometries.push(geometry);
304
+ }
305
+
306
+ return {type: 'GeometryCollection', geometries: []};
307
+ */
308
+ }
309
+
310
+ // HELPERS
311
+
312
+ /**
313
+ * Maps negative values to positive values while going back and
314
+ forth (0 = 0, -1 = 1, 1 = 2, -2 = 3, 2 = 4, -3 = 5, 3 = 6 ...)
315
+ */
316
+ function zigZagDecode(value: number): number {
317
+ return (value >> 1) ^ -(value & 1);
318
+ }
319
+
320
+ function makePointCoordinates(x: number, y: number, z?: number, m?: number): number[] {
321
+ return (z !== undefined ? (m !== undefined ? [x, y, z, m] : [x, y, z]) : [x, y]) as number[];
322
+ }
323
+
324
+ function makePreviousPoint(context: TWKBHeader): number[] {
325
+ return makePointCoordinates(0, 0, context.hasZ ? 0 : undefined, context.hasM ? 0 : undefined);
326
+ }
327
+
328
+ function readFirstPoint(reader: BinaryReader, context: TWKBHeader): number[] {
329
+ const x = zigZagDecode(reader.readVarInt()) / context.precisionFactor;
330
+ const y = zigZagDecode(reader.readVarInt()) / context.precisionFactor;
331
+ const z = context.hasZ ? zigZagDecode(reader.readVarInt()) / context.zPrecisionFactor : undefined;
332
+ const m = context.hasM ? zigZagDecode(reader.readVarInt()) / context.mPrecisionFactor : undefined;
333
+ return makePointCoordinates(x, y, z, m);
334
+ }
335
+
336
+ /**
337
+ * Modifies previousPoint
338
+ */
339
+ function parseNextPoint(
340
+ reader: BinaryReader,
341
+ context: TWKBHeader,
342
+ previousPoint: number[]
343
+ ): number[] {
344
+ previousPoint[0] += zigZagDecode(reader.readVarInt()) / context.precisionFactor;
345
+ previousPoint[1] += zigZagDecode(reader.readVarInt()) / context.precisionFactor;
346
+
347
+ if (context.hasZ) {
348
+ previousPoint[2] += zigZagDecode(reader.readVarInt()) / context.zPrecisionFactor;
349
+ }
350
+ if (context.hasM) {
351
+ previousPoint[3] += zigZagDecode(reader.readVarInt()) / context.mPrecisionFactor;
352
+ }
353
+
354
+ // Copy the point
355
+ return previousPoint.slice();
356
+ }
@@ -0,0 +1,172 @@
1
+ // loaders.gl, MIT license
2
+
3
+ const EWKB_FLAG_Z = 0x80000000;
4
+ const EWKB_FLAG_M = 0x40000000;
5
+ const EWKB_FLAG_SRID = 0x20000000;
6
+
7
+ const MAX_SRID = 10000; // TBD: Assume no more than 10K SRIDs are defined
8
+
9
+ /**
10
+ * Integer code for geometry types in WKB and related formats
11
+ * Reference: https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary
12
+ */
13
+ export enum WKBGeometryType {
14
+ Point = 1,
15
+ LineString = 2,
16
+ Polygon = 3,
17
+ MultiPoint = 4,
18
+ MultiLineString = 5,
19
+ MultiPolygon = 6,
20
+ GeometryCollection = 7
21
+ }
22
+
23
+ /** Parsed WKB header */
24
+ export type WKBHeader = {
25
+ /** WKB variant */
26
+ type: 'wkb' | 'ewkb' | 'iso-wkb' | 'twkb';
27
+ /** geometry type encoded in this WKB: point, line, polygon etc */
28
+ geometryType: 1 | 2 | 3 | 4 | 5 | 6 | 7;
29
+ /** Number of dimensions for coordinate data */
30
+ dimensions: 2 | 3 | 4;
31
+ /** Coordinate names, Z and M are controlled by flags */
32
+ coordinates: 'xy' | 'xyz' | 'xym' | 'xyzm';
33
+ srid?: number;
34
+ /** true if binary data is stored as little endian */
35
+ littleEndian: boolean;
36
+ /** Offset to start of geometry */
37
+ byteOffset: number;
38
+ };
39
+
40
+ /** Sanity checks that first to 5-9 bytes could represent a supported WKB dialect header */
41
+ export function isWKB(arrayBuffer: ArrayBuffer): boolean {
42
+ const dataView = new DataView(arrayBuffer);
43
+ let byteOffset = 0;
44
+
45
+ const endianness = dataView.getUint8(byteOffset);
46
+ byteOffset += 1;
47
+
48
+ // Check valid endianness (only 0 or 1 are allowed)
49
+ if (endianness > 1) {
50
+ return false;
51
+ }
52
+
53
+ const littleEndian = endianness === 1;
54
+
55
+ const geometry = dataView.getUint32(byteOffset, littleEndian);
56
+ byteOffset += 4;
57
+
58
+ // check valid geometry type (we don't support extension geometries)
59
+ const geometryType = geometry & 0x07;
60
+ if (geometryType === 0 || geometryType > 7) {
61
+ return false;
62
+ }
63
+
64
+ const geometryFlags = geometry - geometryType;
65
+
66
+ // Accept iso-wkb flags
67
+ if (
68
+ geometryFlags === 0 ||
69
+ geometryFlags === 1000 ||
70
+ geometryFlags === 2000 ||
71
+ geometryFlags === 3000
72
+ ) {
73
+ return true;
74
+ }
75
+
76
+ // Accept ewkb flags but reject otherwise
77
+ if ((geometryFlags & ~(EWKB_FLAG_Z | EWKB_FLAG_M | EWKB_FLAG_SRID)) !== 0) {
78
+ return false;
79
+ }
80
+
81
+ if (geometryFlags & EWKB_FLAG_SRID) {
82
+ const srid = dataView.getUint32(byteOffset, littleEndian);
83
+ byteOffset += 4;
84
+
85
+ if (srid > MAX_SRID) {
86
+ return false;
87
+ }
88
+ }
89
+
90
+ return true;
91
+ }
92
+
93
+ /**
94
+ * Parses header and provides a byteOffset to start of geometry data
95
+ * @param dataView
96
+ * @param target optionally supply a WKBHeader object to avoid creating a new object for every call
97
+ * @returns a header object describing the WKB data
98
+ */
99
+ // eslint-disable-next-line max-statements
100
+ export function parseWKBHeader(dataView: DataView, target?: WKBHeader): WKBHeader {
101
+ const wkbHeader: WKBHeader = Object.assign(target || {}, {
102
+ type: 'wkb',
103
+ geometryType: 1,
104
+ dimensions: 2,
105
+ coordinates: 'xy',
106
+ littleEndian: true,
107
+ byteOffset: 0
108
+ } as WKBHeader);
109
+
110
+ // Check endianness of data
111
+ wkbHeader.littleEndian = dataView.getUint8(wkbHeader.byteOffset) === 1;
112
+ wkbHeader.byteOffset++;
113
+
114
+ // 4-digit code representing dimension and type of geometry
115
+ const geometryCode = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
116
+ wkbHeader.byteOffset += 4;
117
+
118
+ wkbHeader.geometryType = (geometryCode & 0x7) as 1 | 2 | 3 | 4 | 5 | 6 | 7;
119
+
120
+ // Check if iso-wkb variant: iso-wkb adds 1000, 2000 or 3000 to the geometry code
121
+ const isoType = (geometryCode - wkbHeader.geometryType) / 1000;
122
+ switch (isoType) {
123
+ case 0:
124
+ break;
125
+ case 1:
126
+ wkbHeader.type = 'iso-wkb';
127
+ wkbHeader.dimensions = 3;
128
+ wkbHeader.coordinates = 'xyz';
129
+ break;
130
+ case 2:
131
+ wkbHeader.type = 'iso-wkb';
132
+ wkbHeader.dimensions = 3;
133
+ wkbHeader.coordinates = 'xym';
134
+ break;
135
+ case 3:
136
+ wkbHeader.type = 'iso-wkb';
137
+ wkbHeader.dimensions = 4;
138
+ wkbHeader.coordinates = 'xyzm';
139
+ break;
140
+ default:
141
+ throw new Error(`WKB: Unsupported iso-wkb type: ${isoType}`);
142
+ }
143
+
144
+ // Check if EWKB variant. Uses bitmasks for Z&M dimensions as well as optional SRID field
145
+ const ewkbZ = geometryCode & EWKB_FLAG_Z;
146
+ const ewkbM = geometryCode & EWKB_FLAG_M;
147
+ const ewkbSRID = geometryCode & EWKB_FLAG_SRID;
148
+
149
+ if (ewkbZ && ewkbM) {
150
+ wkbHeader.type = 'ewkb';
151
+ wkbHeader.dimensions = 4;
152
+ wkbHeader.coordinates = 'xyzm';
153
+ } else if (ewkbZ) {
154
+ wkbHeader.type = 'ewkb';
155
+ wkbHeader.dimensions = 3;
156
+ wkbHeader.coordinates = 'xyz';
157
+ } else if (ewkbM) {
158
+ wkbHeader.type = 'ewkb';
159
+ wkbHeader.dimensions = 3;
160
+ wkbHeader.coordinates = 'xym';
161
+ }
162
+
163
+ // If SRID present read four more bytes
164
+ if (ewkbSRID) {
165
+ wkbHeader.type = 'ewkb';
166
+ // 4-digit code representing dimension and type of geometry
167
+ wkbHeader.srid = dataView.getUint32(wkbHeader.byteOffset, wkbHeader.littleEndian);
168
+ wkbHeader.byteOffset += 4;
169
+ }
170
+
171
+ return wkbHeader;
172
+ }