itowns 2.44.3-next.4 → 2.44.3-next.40
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.
- package/CODING.md +1 -1
- package/CONTRIBUTORS.md +1 -0
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/itowns.js +1 -1
- package/dist/itowns.js.LICENSE.txt +0 -2
- package/dist/itowns.js.map +1 -1
- package/dist/itowns_widgets.js +1 -1
- package/dist/itowns_widgets.js.map +1 -1
- package/examples/3dtiles_loader.html +123 -48
- package/examples/config.json +3 -10
- package/examples/copc_simple_loader.html +15 -5
- package/examples/effects_stereo.html +2 -2
- package/examples/entwine_3d_loader.html +3 -1
- package/examples/entwine_simple_loader.html +1 -1
- package/examples/images/itowns_logo.svg +123 -0
- package/examples/js/plugins/COGParser.js +1 -1
- package/examples/jsm/OGC3DTilesHelper.js +6 -1
- package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
- package/examples/misc_collada.html +2 -2
- package/examples/source_file_geojson_3d.html +0 -1
- package/examples/source_file_kml_raster_usgs.html +0 -1
- package/examples/source_stream_wfs_raster.html +0 -7
- package/examples/vector_tile_mapbox_raster.html +91 -0
- package/examples/view_3d_map_webxr.html +3 -1
- package/examples/view_multi_25d.html +2 -2
- package/lib/Controls/GlobeControls.js +45 -28
- package/lib/Controls/StateControl.js +5 -2
- package/lib/Converter/Feature2Mesh.js +10 -4
- package/lib/Converter/Feature2Texture.js +6 -1
- package/lib/Converter/convertToTile.js +3 -8
- package/lib/Converter/textureConverter.js +4 -5
- package/lib/Core/Deprecated/Undeprecator.js +0 -1
- package/lib/Core/Feature.js +3 -4
- package/lib/Core/Geographic/Coordinates.js +143 -132
- package/lib/Core/Geographic/Crs.js +140 -145
- package/lib/Core/Geographic/Extent.js +221 -397
- package/lib/Core/Geographic/GeoidGrid.js +1 -1
- package/lib/Core/MainLoop.js +1 -3
- package/lib/Core/Math/Ellipsoid.js +62 -21
- package/lib/Core/Prefab/Globe/Atmosphere.js +4 -8
- package/lib/Core/Prefab/Globe/GlobeLayer.js +22 -15
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
- package/lib/Core/Prefab/GlobeView.js +2 -7
- package/lib/Core/Prefab/Planar/PlanarLayer.js +17 -11
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
- package/lib/Core/Prefab/TileBuilder.js +42 -40
- package/lib/Core/Prefab/computeBufferTileGeometry.js +195 -130
- package/lib/Core/Scheduler/Cache.js +1 -240
- package/lib/Core/Style.js +34 -495
- package/lib/Core/StyleOptions.js +486 -0
- package/lib/Core/Tile/Tile.js +207 -0
- package/lib/Core/Tile/TileGrid.js +49 -0
- package/lib/Core/TileGeometry.js +112 -28
- package/lib/Core/TileMesh.js +3 -3
- package/lib/Core/View.js +15 -8
- package/lib/Layer/C3DTilesLayer.js +20 -16
- package/lib/Layer/ColorLayer.js +35 -9
- package/lib/Layer/CopcLayer.js +7 -2
- package/lib/Layer/ElevationLayer.js +39 -7
- package/lib/Layer/EntwinePointTileLayer.js +14 -7
- package/lib/Layer/FeatureGeometryLayer.js +20 -6
- package/lib/Layer/GeometryLayer.js +42 -11
- package/lib/Layer/LabelLayer.js +45 -27
- package/lib/Layer/Layer.js +92 -61
- package/lib/Layer/OGC3DTilesLayer.js +212 -56
- package/lib/Layer/OrientedImageLayer.js +11 -5
- package/lib/Layer/PointCloudLayer.js +76 -30
- package/lib/Layer/Potree2Layer.js +9 -2
- package/lib/Layer/PotreeLayer.js +10 -3
- package/lib/Layer/RasterLayer.js +12 -2
- package/lib/Layer/TiledGeometryLayer.js +69 -13
- package/lib/Main.js +2 -2
- package/lib/Parser/GeoJsonParser.js +1 -1
- package/lib/Parser/VectorTileParser.js +42 -29
- package/lib/Parser/XbilParser.js +14 -2
- package/lib/Provider/Fetcher.js +5 -1
- package/lib/Provider/URLBuilder.js +22 -11
- package/lib/Renderer/Camera.js +1 -1
- package/lib/Renderer/Label2DRenderer.js +9 -7
- package/lib/Renderer/OBB.js +11 -13
- package/lib/Renderer/PointsMaterial.js +5 -5
- package/lib/Renderer/RasterTile.js +1 -2
- package/lib/Renderer/SphereHelper.js +0 -6
- package/lib/Source/CopcSource.js +13 -2
- package/lib/Source/EntwinePointTileSource.js +14 -4
- package/lib/Source/FileSource.js +9 -10
- package/lib/Source/OrientedImageSource.js +2 -2
- package/lib/Source/Source.js +26 -46
- package/lib/Source/TMSSource.js +10 -9
- package/lib/Source/VectorTilesSource.js +38 -34
- package/lib/Source/WFSSource.js +18 -13
- package/lib/Source/WMSSource.js +56 -18
- package/lib/Source/WMTSSource.js +13 -7
- package/lib/ThreeExtended/libs/ktx-parse.module.js +310 -274
- package/lib/ThreeExtended/loaders/DRACOLoader.js +3 -2
- package/lib/ThreeExtended/loaders/GLTFLoader.js +6 -3
- package/lib/ThreeExtended/loaders/KTX2Loader.js +144 -60
- package/lib/ThreeExtended/math/ColorSpaces.js +59 -0
- package/lib/Utils/CameraUtils.js +1 -1
- package/lib/Utils/gui/C3DTilesStyle.js +2 -3
- package/lib/Utils/placeObjectOnGround.js +0 -1
- package/package.json +10 -8
- package/examples/3dtiles_25d.html +0 -120
- package/examples/3dtiles_basic.html +0 -94
- package/examples/3dtiles_batch_table.html +0 -86
- package/examples/3dtiles_ion.html +0 -126
- package/examples/3dtiles_pointcloud.html +0 -95
- package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { FEATURE_TYPES } from "./Feature.js";
|
|
2
|
+
import * as maplibre from '@maplibre/maplibre-gl-style-spec';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An object that can contain any properties (zoom, fill, stroke, point,
|
|
6
|
+
* text or/and icon) and sub properties of a Style.
|
|
7
|
+
* Used for the instanciation of a {@link Style}.
|
|
8
|
+
*
|
|
9
|
+
* @typedef {Object} StyleOptions
|
|
10
|
+
*
|
|
11
|
+
* @property {Object} [zoom] - Level on which to display the feature
|
|
12
|
+
* @property {Number} [zoom.max] - max level
|
|
13
|
+
* @property {Number} [zoom.min] - min level
|
|
14
|
+
*
|
|
15
|
+
* @property {Object} [fill] - Fill style for polygons.
|
|
16
|
+
* @property {String|Function|THREE.Color} [fill.color] - Defines the main fill color. Can be
|
|
17
|
+
* any [valid color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
18
|
+
* Default is no value, which means no fill.
|
|
19
|
+
* If the `Layer` is a `GeometryLayer` you can use `THREE.Color`.
|
|
20
|
+
* @property {Image|Canvas|String|Object|Function} [fill.pattern] - Defines a pattern to fill the
|
|
21
|
+
* surface with. It can be an `Image` to use directly, an url to fetch the pattern or an object containing
|
|
22
|
+
* the url of the image to fetch and the transformation to apply.
|
|
23
|
+
* from. See [this example](http://www.itowns-project.org/itowns/examples/#source_file_geojson_raster)
|
|
24
|
+
* for how to use.
|
|
25
|
+
* @property {Image|String} [fill.pattern.source] - The image or the url to fetch the pattern image
|
|
26
|
+
* @property {Object} [fill.pattern.cropValues] - The x, y, width and height (in pixel) of the sub image to use.
|
|
27
|
+
* @property {THREE.Color} [fill.pattern.color] - Can be any
|
|
28
|
+
* [valid color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
29
|
+
* It will change the color of the white pixels of the source image.
|
|
30
|
+
* @property {Number|Function} [fill.opacity] - The opacity of the color or of the
|
|
31
|
+
* pattern. Can be between `0.0` and `1.0`. Default is `1.0`.
|
|
32
|
+
* For a `GeometryLayer`, this opacity property isn't used.
|
|
33
|
+
* @property {Number|Function} [fill.base_altitude] - `GeometryLayer` style option, defines altitude
|
|
34
|
+
* for each coordinate.
|
|
35
|
+
* If `base_altitude` is `undefined`, the original altitude is kept, and if it doesn't exist
|
|
36
|
+
* then the altitude value is set to 0.
|
|
37
|
+
* @property {Number|Function} [fill.extrusion_height] - `GeometryLayer` style option, if defined,
|
|
38
|
+
* polygons will be extruded by the specified amount
|
|
39
|
+
*
|
|
40
|
+
* @property {Object} [stroke] - Lines and polygons edges.
|
|
41
|
+
* @property {String|Function|THREE.Color} [stroke.color] The color of the line. Can be any [valid
|
|
42
|
+
* color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
43
|
+
* Default is no value, which means no stroke.
|
|
44
|
+
* If the `Layer` is a `GeometryLayer` you can use `THREE.Color`.
|
|
45
|
+
* @property {Number|Function} [stroke.opacity] - The opacity of the line. Can be between
|
|
46
|
+
* `0.0` and `1.0`. Default is `1.0`.
|
|
47
|
+
* For a `GeometryLayer`, this opacity property isn't used.
|
|
48
|
+
* @property {Number|Function} [stroke.width] - The width of the line. Default is `1.0`.
|
|
49
|
+
* @property {Number|Function} [stroke.base_altitude] - `GeometryLayer` style option, defines altitude
|
|
50
|
+
* for each coordinate.
|
|
51
|
+
* If `base_altitude` is `undefined`, the original altitude is kept, and if it doesn't exist
|
|
52
|
+
* then the altitude value is set to 0.
|
|
53
|
+
*
|
|
54
|
+
* @property {Object} [point] - Point style.
|
|
55
|
+
* @property {String|Function} [point.color] - The color of the point. Can be any [valid
|
|
56
|
+
* color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
57
|
+
* Default is no value, which means points won't be displayed.
|
|
58
|
+
* @property {Number|Function} [point.radius] - The radius of the point, in pixel. Default
|
|
59
|
+
* is `2.0`.
|
|
60
|
+
* @property {String|Function} [point.line] - The color of the border of the point. Can be
|
|
61
|
+
* any [valid color
|
|
62
|
+
* string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
63
|
+
* Not supported for a `GeometryLayer`.
|
|
64
|
+
* @property {Number|Function} [point.width] - The width of the border, in pixel. Default
|
|
65
|
+
* is `0.0` (no border).
|
|
66
|
+
* @property {Number|Function} [point.opacity] - The opacity of the point. Can be between
|
|
67
|
+
* `0.0` and `1.0`. Default is `1.0`.
|
|
68
|
+
* Not supported for `GeometryLayer`.
|
|
69
|
+
* @property {Number|Function} [point.base_altitude] - `GeometryLayer` style option, defines altitude
|
|
70
|
+
* for each coordinate.
|
|
71
|
+
* If `base_altitude` is `undefined`, the original altitude is kept, and if it doesn't exist
|
|
72
|
+
* then the altitude value is set to 0.
|
|
73
|
+
* @property {Object} [point.model] - 3D model to instantiate at each point position.
|
|
74
|
+
*
|
|
75
|
+
* @property {Object} [text] - All things {@link Label} related. (Supported for Points features, not yet
|
|
76
|
+
* for Lines and Polygons features.)
|
|
77
|
+
* @property {String|Function} [text.field] - A string representing a property key of
|
|
78
|
+
* a `FeatureGeometry` enclosed in brackets, that will be replaced by the value of the
|
|
79
|
+
* property for each geometry. For example, if each geometry contains a `name` property,
|
|
80
|
+
* `text.field` can be set to `{name}`. Default is no value, indicating that no
|
|
81
|
+
* text will be displayed.
|
|
82
|
+
*
|
|
83
|
+
* It's also possible to create more complex expressions. For example, you can combine
|
|
84
|
+
* text that will always be displayed (e.g. `foo`) and variable properties (e.g. `{bar}`)
|
|
85
|
+
* like the following: `foo {bar}`. You can also use multiple variables in one field.
|
|
86
|
+
* Let's say for instance that you have two properties latin name and local name of a
|
|
87
|
+
* place, you can write something like `{name_latin} - {name_local}` which can result
|
|
88
|
+
* in `Marrakesh - مراكش` for example.
|
|
89
|
+
* @property {String|Function} [text.color] - The color of the text. Can be any [valid
|
|
90
|
+
* color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
91
|
+
* Default is `#000000`.
|
|
92
|
+
* @property {String|Number[]|Function} [text.anchor] - The anchor of the text compared to its
|
|
93
|
+
* position (see {@link Label} for the position). Can be one of the following values: `top`,
|
|
94
|
+
* `left`, `bottom`, `right`, `center`, `top-left`, `top-right`, `bottom-left`
|
|
95
|
+
* or `bottom-right`. Default is `center`.
|
|
96
|
+
*
|
|
97
|
+
* It can also be defined as an Array of two numbers. Each number defines an offset (in
|
|
98
|
+
* fraction of the label width and height) between the label position and the top-left
|
|
99
|
+
* corner of the text. The first value is the horizontal offset, and the second is the
|
|
100
|
+
* vertical offset. For example, `[-0.5, -0.5]` will be equivalent to `center`.
|
|
101
|
+
* @property {Array|Function} [text.offset] - The offset of the text, depending on its
|
|
102
|
+
* anchor, in pixels. First value is from `left`, second is from `top`. Default
|
|
103
|
+
* is `[0, 0]`.
|
|
104
|
+
* @property {Number|Function} [text.padding] - The padding outside the text, in pixels.
|
|
105
|
+
* Default is `2`.
|
|
106
|
+
* @property {Number|Function} [text.size] - The size of the font, in pixels. Default is
|
|
107
|
+
* `16`.
|
|
108
|
+
* @property {Number|Function} [text.wrap] - The maximum width, in pixels, before the text
|
|
109
|
+
* is wrapped, because the string is too long. Default is `10`.
|
|
110
|
+
* @property {Number|Function} [text.spacing] - The spacing between the letters, in `em`.
|
|
111
|
+
* Default is `0`.
|
|
112
|
+
* @property {String|Function} [text.transform] - A value corresponding to the [CSS
|
|
113
|
+
* property
|
|
114
|
+
* `text-transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform).
|
|
115
|
+
* Default is `none`.
|
|
116
|
+
* @property {String|Function} [text.justify] - A value corresponding to the [CSS property
|
|
117
|
+
* `text-align`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align).
|
|
118
|
+
* Default is `center`.
|
|
119
|
+
* @property {Number|Function} [text.opacity] - The opacity of the text. Can be between
|
|
120
|
+
* `0.0` and `1.0`. Default is `1.0`.
|
|
121
|
+
* @property {Array|Function} [text.font] - A list (as an array of string) of font family
|
|
122
|
+
* names, prioritized in the order it is set. Default is `Open Sans Regular,
|
|
123
|
+
* Arial Unicode MS Regular, sans-serif`.
|
|
124
|
+
* @property {String|Function} [text.haloColor] - The color of the halo. Can be any [valid
|
|
125
|
+
* color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
126
|
+
* Default is `#000000`.
|
|
127
|
+
* @property {Number|Function} [text.haloWidth] - The width of the halo, in pixels.
|
|
128
|
+
* Default is `0`.
|
|
129
|
+
* @property {Number|Function} [text.haloBlur] - The blur value of the halo, in pixels.
|
|
130
|
+
* Default is `0`.
|
|
131
|
+
*
|
|
132
|
+
* @property {Object} [icon] - Defines the appearance of icons attached to label.
|
|
133
|
+
* @property {String} [icon.source] - The url of the icons' image file.
|
|
134
|
+
* @property {String} [icon.id] - The id of the icons' sub-image in a vector tile data set.
|
|
135
|
+
* @property {String} [icon.cropValues] - the x, y, width and height (in pixel) of the sub image to use.
|
|
136
|
+
* @property {String} [icon.anchor] - The anchor of the icon compared to the label position.
|
|
137
|
+
* Can be `left`, `bottom`, `right`, `center`, `top-left`, `top-right`, `bottom-left`
|
|
138
|
+
* or `bottom-right`. Default is `center`.
|
|
139
|
+
* @property {Number} [icon.size] - If the icon's image is passed with `icon.source` and/or
|
|
140
|
+
* `icon.id`, its size when displayed on screen is multiplied by `icon.size`. Default is `1`.
|
|
141
|
+
* @property {String|Function} [icon.color] - The color of the icon. Can be any [valid
|
|
142
|
+
* color string](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
|
|
143
|
+
* It will change the color of the white pixels of the icon source image.
|
|
144
|
+
* @property {Number|Function} [icon.opacity] - The opacity of the icon. Can be between
|
|
145
|
+
* `0.0` and `1.0`. Default is `1.0`.
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* generate a StyleOptions from (geojson-like) properties.
|
|
150
|
+
* @param {Object} properties (geojson-like) properties.
|
|
151
|
+
* @param {FeatureContext} featCtx the context of the feature
|
|
152
|
+
*
|
|
153
|
+
* @returns {StyleOptions} containing all properties for itowns.Style
|
|
154
|
+
*/
|
|
155
|
+
function setFromProperties(properties, featCtx) {
|
|
156
|
+
const type = featCtx.type;
|
|
157
|
+
const style = {};
|
|
158
|
+
if (type === FEATURE_TYPES.POINT) {
|
|
159
|
+
const point = {
|
|
160
|
+
...(properties.fill !== undefined && {
|
|
161
|
+
color: properties.fill
|
|
162
|
+
}),
|
|
163
|
+
...(properties['fill-opacity'] !== undefined && {
|
|
164
|
+
opacity: properties['fill-opacity']
|
|
165
|
+
}),
|
|
166
|
+
...(properties.stroke !== undefined && {
|
|
167
|
+
line: properties.stroke
|
|
168
|
+
}),
|
|
169
|
+
...(properties.radius !== undefined && {
|
|
170
|
+
radius: properties.radius
|
|
171
|
+
})
|
|
172
|
+
};
|
|
173
|
+
if (Object.keys(point).length) {
|
|
174
|
+
style.point = point;
|
|
175
|
+
}
|
|
176
|
+
const text = {
|
|
177
|
+
...(properties['label-color'] !== undefined && {
|
|
178
|
+
color: properties['label-color']
|
|
179
|
+
}),
|
|
180
|
+
...(properties['label-opacity'] !== undefined && {
|
|
181
|
+
opacity: properties['label-opacity']
|
|
182
|
+
}),
|
|
183
|
+
...(properties['label-size'] !== undefined && {
|
|
184
|
+
size: properties['label-size']
|
|
185
|
+
})
|
|
186
|
+
};
|
|
187
|
+
if (Object.keys(point).length) {
|
|
188
|
+
style.text = text;
|
|
189
|
+
}
|
|
190
|
+
const icon = {
|
|
191
|
+
...(properties.icon !== undefined && {
|
|
192
|
+
source: properties.icon
|
|
193
|
+
}),
|
|
194
|
+
...(properties['icon-scale'] !== undefined && {
|
|
195
|
+
size: properties['icon-scale']
|
|
196
|
+
}),
|
|
197
|
+
...(properties['icon-opacity'] !== undefined && {
|
|
198
|
+
opacity: properties['icon-opacity']
|
|
199
|
+
}),
|
|
200
|
+
...(properties['icon-color'] !== undefined && {
|
|
201
|
+
color: properties['icon-color']
|
|
202
|
+
})
|
|
203
|
+
};
|
|
204
|
+
if (Object.keys(icon).length) {
|
|
205
|
+
style.icon = icon;
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
const stroke = {
|
|
209
|
+
...(properties.stroke !== undefined && {
|
|
210
|
+
color: properties.stroke
|
|
211
|
+
}),
|
|
212
|
+
...(properties['stroke-width'] !== undefined && {
|
|
213
|
+
width: properties['stroke-width']
|
|
214
|
+
}),
|
|
215
|
+
...(properties['stroke-opacity'] !== undefined && {
|
|
216
|
+
opacity: properties['stroke-opacity']
|
|
217
|
+
})
|
|
218
|
+
};
|
|
219
|
+
if (Object.keys(stroke).length) {
|
|
220
|
+
style.stroke = stroke;
|
|
221
|
+
}
|
|
222
|
+
if (type !== FEATURE_TYPES.LINE) {
|
|
223
|
+
const fill = {
|
|
224
|
+
...(properties.fill !== undefined && {
|
|
225
|
+
color: properties.fill
|
|
226
|
+
}),
|
|
227
|
+
...(properties['fill-opacity'] !== undefined && {
|
|
228
|
+
opacity: properties['fill-opacity']
|
|
229
|
+
})
|
|
230
|
+
};
|
|
231
|
+
if (Object.keys(fill).length) {
|
|
232
|
+
style.fill = fill;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return style;
|
|
237
|
+
}
|
|
238
|
+
function readVectorProperty(property, options) {
|
|
239
|
+
if (property != undefined) {
|
|
240
|
+
if (maplibre.expression.isExpression(property)) {
|
|
241
|
+
return maplibre.expression.createExpression(property, options).value;
|
|
242
|
+
} else {
|
|
243
|
+
return property;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const inv255 = 1 / 255;
|
|
248
|
+
function rgba2rgb(orig) {
|
|
249
|
+
if (!orig) {
|
|
250
|
+
return {};
|
|
251
|
+
} else if (orig.stops || orig.expression) {
|
|
252
|
+
return {
|
|
253
|
+
color: orig
|
|
254
|
+
};
|
|
255
|
+
} else if (typeof orig == 'string') {
|
|
256
|
+
const result = orig.match(/(?:((hsl|rgb)a? *\(([\d.%]+(?:deg|g?rad|turn)?)[ ,]*([\d.%]+)[ ,]*([\d.%]+)[ ,/]*([\d.%]*)\))|(#((?:[\d\w]{3}){1,2})([\d\w]{1,2})?))/i);
|
|
257
|
+
if (result === null) {
|
|
258
|
+
return {
|
|
259
|
+
color: orig,
|
|
260
|
+
opacity: 1.0
|
|
261
|
+
};
|
|
262
|
+
} else if (result[7]) {
|
|
263
|
+
let opacity = 1.0;
|
|
264
|
+
if (result[9]) {
|
|
265
|
+
opacity = parseInt(result[9].length == 1 ? `${result[9]}${result[9]}` : result[9], 16) * inv255;
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
color: `#${result[8]}`,
|
|
269
|
+
opacity
|
|
270
|
+
};
|
|
271
|
+
} else if (result[1]) {
|
|
272
|
+
return {
|
|
273
|
+
color: `${result[2]}(${result[3]},${result[4]},${result[5]})`,
|
|
274
|
+
opacity: result[6] ? Number(result[6]) : 1.0
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* generate a StyleOptions from vector tile layer properties.
|
|
282
|
+
* @param {Object} layer vector tile layer.
|
|
283
|
+
* @param {Object} sprites vector tile layer.
|
|
284
|
+
* @param {Boolean} [symbolToCircle=false]
|
|
285
|
+
*
|
|
286
|
+
* @returns {StyleOptions} containing all properties for itowns.Style
|
|
287
|
+
*/
|
|
288
|
+
function setFromVectorTileLayer(layer, sprites) {
|
|
289
|
+
let symbolToCircle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
290
|
+
const style = {
|
|
291
|
+
fill: {},
|
|
292
|
+
stroke: {},
|
|
293
|
+
point: {},
|
|
294
|
+
text: {},
|
|
295
|
+
icon: {}
|
|
296
|
+
};
|
|
297
|
+
layer.layout = layer.layout || {};
|
|
298
|
+
layer.paint = layer.paint || {};
|
|
299
|
+
if (layer.type === 'fill') {
|
|
300
|
+
const {
|
|
301
|
+
color,
|
|
302
|
+
opacity
|
|
303
|
+
} = rgba2rgb(readVectorProperty(layer.paint['fill-color'] || layer.paint['fill-pattern'], {
|
|
304
|
+
type: 'color'
|
|
305
|
+
}));
|
|
306
|
+
style.fill.color = color;
|
|
307
|
+
style.fill.opacity = readVectorProperty(layer.paint['fill-opacity']) || opacity;
|
|
308
|
+
if (layer.paint['fill-pattern']) {
|
|
309
|
+
try {
|
|
310
|
+
style.fill.pattern = {
|
|
311
|
+
id: layer.paint['fill-pattern'],
|
|
312
|
+
source: sprites.source,
|
|
313
|
+
cropValues: sprites[layer.paint['fill-pattern']]
|
|
314
|
+
};
|
|
315
|
+
} catch (err) {
|
|
316
|
+
err.message = `VTlayer '${layer.id}': argument sprites must not be null when using layer.paint['fill-pattern']`;
|
|
317
|
+
throw err;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (layer.paint['fill-outline-color']) {
|
|
321
|
+
const {
|
|
322
|
+
color,
|
|
323
|
+
opacity
|
|
324
|
+
} = rgba2rgb(readVectorProperty(layer.paint['fill-outline-color'], {
|
|
325
|
+
type: 'color'
|
|
326
|
+
}));
|
|
327
|
+
style.stroke.color = color;
|
|
328
|
+
style.stroke.opacity = opacity;
|
|
329
|
+
style.stroke.width = 1.0;
|
|
330
|
+
} else {
|
|
331
|
+
style.stroke.width = 0.0;
|
|
332
|
+
}
|
|
333
|
+
} else if (layer.type === 'line') {
|
|
334
|
+
const prepare = readVectorProperty(layer.paint['line-color'], {
|
|
335
|
+
type: 'color'
|
|
336
|
+
});
|
|
337
|
+
const {
|
|
338
|
+
color,
|
|
339
|
+
opacity
|
|
340
|
+
} = rgba2rgb(prepare);
|
|
341
|
+
style.stroke.dasharray = readVectorProperty(layer.paint['line-dasharray']);
|
|
342
|
+
style.stroke.color = color;
|
|
343
|
+
style.stroke.lineCap = layer.layout['line-cap'];
|
|
344
|
+
style.stroke.width = readVectorProperty(layer.paint['line-width']);
|
|
345
|
+
style.stroke.opacity = readVectorProperty(layer.paint['line-opacity']) || opacity;
|
|
346
|
+
} else if (layer.type === 'circle' || symbolToCircle) {
|
|
347
|
+
const {
|
|
348
|
+
color,
|
|
349
|
+
opacity
|
|
350
|
+
} = rgba2rgb(readVectorProperty(layer.paint['circle-color'], {
|
|
351
|
+
type: 'color'
|
|
352
|
+
}));
|
|
353
|
+
style.point.color = color;
|
|
354
|
+
style.point.opacity = opacity;
|
|
355
|
+
style.point.radius = readVectorProperty(layer.paint['circle-radius']);
|
|
356
|
+
} else if (layer.type === 'symbol') {
|
|
357
|
+
// if symbol we shouldn't draw stroke but defaut value is 1.
|
|
358
|
+
style.stroke.width = 0.0;
|
|
359
|
+
// overlapping order
|
|
360
|
+
style.text.zOrder = readVectorProperty(layer.layout['symbol-z-order']);
|
|
361
|
+
if (style.text.zOrder == 'auto') {
|
|
362
|
+
style.text.zOrder = readVectorProperty(layer.layout['symbol-sort-key']) || 'Y';
|
|
363
|
+
} else if (style.text.zOrder == 'viewport-y') {
|
|
364
|
+
style.text.zOrder = 'Y';
|
|
365
|
+
} else if (style.text.zOrder == 'source') {
|
|
366
|
+
style.text.zOrder = 0;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// position
|
|
370
|
+
style.text.anchor = readVectorProperty(layer.layout['text-anchor']);
|
|
371
|
+
style.text.offset = readVectorProperty(layer.layout['text-offset']);
|
|
372
|
+
style.text.padding = readVectorProperty(layer.layout['text-padding']);
|
|
373
|
+
style.text.size = readVectorProperty(layer.layout['text-size']);
|
|
374
|
+
style.text.placement = readVectorProperty(layer.layout['symbol-placement']);
|
|
375
|
+
style.text.rotation = readVectorProperty(layer.layout['text-rotation-alignment']);
|
|
376
|
+
|
|
377
|
+
// content
|
|
378
|
+
style.text.field = readVectorProperty(layer.layout['text-field']);
|
|
379
|
+
style.text.wrap = readVectorProperty(layer.layout['text-max-width']); // Units ems
|
|
380
|
+
style.text.spacing = readVectorProperty(layer.layout['text-letter-spacing']);
|
|
381
|
+
style.text.transform = readVectorProperty(layer.layout['text-transform']);
|
|
382
|
+
style.text.justify = readVectorProperty(layer.layout['text-justify']);
|
|
383
|
+
|
|
384
|
+
// appearance
|
|
385
|
+
const {
|
|
386
|
+
color,
|
|
387
|
+
opacity
|
|
388
|
+
} = rgba2rgb(readVectorProperty(layer.paint['text-color'], {
|
|
389
|
+
type: 'color'
|
|
390
|
+
}));
|
|
391
|
+
style.text.color = color;
|
|
392
|
+
style.text.opacity = readVectorProperty(layer.paint['text-opacity']) || opacity !== undefined && opacity;
|
|
393
|
+
style.text.font = readVectorProperty(layer.layout['text-font']);
|
|
394
|
+
const haloColor = readVectorProperty(layer.paint['text-halo-color'], {
|
|
395
|
+
type: 'color'
|
|
396
|
+
});
|
|
397
|
+
if (haloColor) {
|
|
398
|
+
style.text.haloColor = haloColor.color || haloColor;
|
|
399
|
+
style.text.haloWidth = readVectorProperty(layer.paint['text-halo-width']);
|
|
400
|
+
style.text.haloBlur = readVectorProperty(layer.paint['text-halo-blur']);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// additional icon
|
|
404
|
+
const iconImg = readVectorProperty(layer.layout['icon-image']);
|
|
405
|
+
if (iconImg) {
|
|
406
|
+
const cropValueDefault = {
|
|
407
|
+
x: 0,
|
|
408
|
+
y: 0,
|
|
409
|
+
width: 1,
|
|
410
|
+
height: 1
|
|
411
|
+
};
|
|
412
|
+
try {
|
|
413
|
+
style.icon.id = iconImg;
|
|
414
|
+
if (iconImg.stops) {
|
|
415
|
+
const iconCropValue = {
|
|
416
|
+
...(iconImg.base !== undefined && {
|
|
417
|
+
base: iconImg.base
|
|
418
|
+
}),
|
|
419
|
+
stops: iconImg.stops.map(stop => {
|
|
420
|
+
let cropValues = sprites[stop[1]];
|
|
421
|
+
if (stop[1].includes('{')) {
|
|
422
|
+
cropValues = function (p) {
|
|
423
|
+
const id = stop[1].replace(/\{(.+?)\}/g, (a, b) => p[b] || '').trim();
|
|
424
|
+
if (cropValues === undefined) {
|
|
425
|
+
// const warning = `WARNING: "${id}" not found in sprite file`;
|
|
426
|
+
sprites[id] = cropValueDefault; // or return cropValueDefault;
|
|
427
|
+
}
|
|
428
|
+
return sprites[id];
|
|
429
|
+
};
|
|
430
|
+
} else if (cropValues === undefined) {
|
|
431
|
+
// const warning = `WARNING: "${stop[1]}" not found in sprite file`;
|
|
432
|
+
cropValues = cropValueDefault;
|
|
433
|
+
}
|
|
434
|
+
return [stop[0], cropValues];
|
|
435
|
+
})
|
|
436
|
+
};
|
|
437
|
+
style.icon.cropValues = iconCropValue;
|
|
438
|
+
} else {
|
|
439
|
+
style.icon.cropValues = sprites[iconImg];
|
|
440
|
+
if (iconImg.includes('{')) {
|
|
441
|
+
style.icon.cropValues = function (p) {
|
|
442
|
+
const id = iconImg.replace(/\{(.+?)\}/g, (a, b) => p[b] || '').trim();
|
|
443
|
+
if (sprites[id] === undefined) {
|
|
444
|
+
// const warning = `WARNING: "${id}" not found in sprite file`;
|
|
445
|
+
sprites[id] = cropValueDefault; // or return cropValueDefault;
|
|
446
|
+
}
|
|
447
|
+
return sprites[id];
|
|
448
|
+
};
|
|
449
|
+
} else if (sprites[iconImg] === undefined) {
|
|
450
|
+
// const warning = `WARNING: "${iconImg}" not found in sprite file`;
|
|
451
|
+
style.icon.cropValues = cropValueDefault;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
style.icon.source = sprites.source;
|
|
455
|
+
style.icon.size = readVectorProperty(layer.layout['icon-size']) ?? 1;
|
|
456
|
+
const {
|
|
457
|
+
color,
|
|
458
|
+
opacity
|
|
459
|
+
} = rgba2rgb(readVectorProperty(layer.paint['icon-color'], {
|
|
460
|
+
type: 'color'
|
|
461
|
+
}));
|
|
462
|
+
// https://docs.mapbox.com/style-spec/reference/layers/#paint-symbol-icon-color
|
|
463
|
+
if (iconImg.sdf) {
|
|
464
|
+
style.icon.color = color;
|
|
465
|
+
}
|
|
466
|
+
style.icon.opacity = readVectorProperty(layer.paint['icon-opacity']) ?? (opacity !== undefined && opacity);
|
|
467
|
+
} catch (err) {
|
|
468
|
+
err.message = `VTlayer '${layer.id}': argument sprites must not be null when using layer.layout['icon-image']`;
|
|
469
|
+
throw err;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// VectorTileSet: by default minZoom = 0 and maxZoom = 24
|
|
474
|
+
// https://docs.mapbox.com/style-spec/reference/layers/#maxzoom and #minzoom
|
|
475
|
+
// Should be move to layer properties, when (if) one mapBox layer will be considered as several itowns layers.
|
|
476
|
+
// issue https://github.com/iTowns/itowns/issues/2153 (last point)
|
|
477
|
+
style.zoom = {
|
|
478
|
+
min: layer.minzoom || 0,
|
|
479
|
+
max: layer.maxzoom || 24
|
|
480
|
+
};
|
|
481
|
+
return style;
|
|
482
|
+
}
|
|
483
|
+
export default {
|
|
484
|
+
setFromProperties,
|
|
485
|
+
setFromVectorTileLayer
|
|
486
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import * as CRS from "../Geographic/Crs.js";
|
|
3
|
+
import Coordinates from "../Geographic/Coordinates.js";
|
|
4
|
+
import Extent from "../Geographic/Extent.js";
|
|
5
|
+
import { getInfoTms, getCountTiles } from "./TileGrid.js";
|
|
6
|
+
const _tmsCoord = new THREE.Vector2();
|
|
7
|
+
const _dimensionTile = new THREE.Vector2();
|
|
8
|
+
const r = {
|
|
9
|
+
row: 0,
|
|
10
|
+
col: 0,
|
|
11
|
+
invDiff: 0
|
|
12
|
+
};
|
|
13
|
+
function _rowColfromParent(tile, zoom) {
|
|
14
|
+
const diffLevel = tile.zoom - zoom;
|
|
15
|
+
const diff = 2 ** diffLevel;
|
|
16
|
+
r.invDiff = 1 / diff;
|
|
17
|
+
r.row = (tile.row - tile.row % diff) * r.invDiff;
|
|
18
|
+
r.col = (tile.col - tile.col % diff) * r.invDiff;
|
|
19
|
+
return r;
|
|
20
|
+
}
|
|
21
|
+
const _extent = new Extent('EPSG:4326');
|
|
22
|
+
const _extent2 = new Extent('EPSG:4326');
|
|
23
|
+
const _c = new Coordinates('EPSG:4326', 0, 0);
|
|
24
|
+
class Tile {
|
|
25
|
+
/**
|
|
26
|
+
* A tile is a geographical bounding rectangle uniquely defined by its zoom,
|
|
27
|
+
* row and column.
|
|
28
|
+
*
|
|
29
|
+
* @param crs - projection of limit values.
|
|
30
|
+
* @param zoom - `zoom` value. Default is 0.
|
|
31
|
+
* @param row - `row` value. Default is 0.
|
|
32
|
+
* @param col - `column` value. Default is 0.
|
|
33
|
+
*/
|
|
34
|
+
constructor(crs) {
|
|
35
|
+
let zoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
36
|
+
let row = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
37
|
+
let col = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
38
|
+
this.isTile = true;
|
|
39
|
+
this.crs = crs;
|
|
40
|
+
this.zoom = zoom;
|
|
41
|
+
this.row = row;
|
|
42
|
+
this.col = col;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns a new tile with the same bounds and crs as this one.
|
|
47
|
+
*/
|
|
48
|
+
clone() {
|
|
49
|
+
return new Tile(this.crs, this.zoom, this.row, this.col);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Converts this tile to the specified extent.
|
|
54
|
+
* @param crs - target's projection.
|
|
55
|
+
* @param target - The target to store the projected extent. If this not
|
|
56
|
+
* provided a new extent will be created.
|
|
57
|
+
*/
|
|
58
|
+
toExtent(crs) {
|
|
59
|
+
let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Extent('EPSG:4326');
|
|
60
|
+
CRS.isValid(crs);
|
|
61
|
+
const {
|
|
62
|
+
epsg,
|
|
63
|
+
globalExtent,
|
|
64
|
+
globalDimension
|
|
65
|
+
} = getInfoTms(this.crs);
|
|
66
|
+
const countTiles = getCountTiles(this.crs, this.zoom);
|
|
67
|
+
_dimensionTile.set(1, 1).divide(countTiles).multiply(globalDimension);
|
|
68
|
+
target.west = globalExtent.west + (globalDimension.x - _dimensionTile.x * (countTiles.x - this.col));
|
|
69
|
+
target.east = target.west + _dimensionTile.x;
|
|
70
|
+
target.south = globalExtent.south + _dimensionTile.y * (countTiles.y - this.row - 1);
|
|
71
|
+
target.north = target.south + _dimensionTile.y;
|
|
72
|
+
target.crs = epsg;
|
|
73
|
+
return crs == epsg ? target : target.as(crs, target);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Checks whether another tile is inside this tile.
|
|
78
|
+
*
|
|
79
|
+
* @param extent - the tile to check.
|
|
80
|
+
*/
|
|
81
|
+
isInside(tile) {
|
|
82
|
+
if (this.zoom == tile.zoom) {
|
|
83
|
+
return this.row == tile.row && this.col == tile.col;
|
|
84
|
+
} else if (this.zoom < tile.zoom) {
|
|
85
|
+
return false;
|
|
86
|
+
} else {
|
|
87
|
+
const r = _rowColfromParent(this, tile.zoom);
|
|
88
|
+
return r.row == tile.row && r.col == tile.col;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns the translation and scale to transform this tile to the input
|
|
94
|
+
* tile.
|
|
95
|
+
*
|
|
96
|
+
* @param tile - the input tile.
|
|
97
|
+
* @param target - copy the result to target.
|
|
98
|
+
*/
|
|
99
|
+
offsetToParent(tile) {
|
|
100
|
+
let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new THREE.Vector4();
|
|
101
|
+
if (this.crs != tile.crs) {
|
|
102
|
+
throw new Error('unsupported mix');
|
|
103
|
+
}
|
|
104
|
+
const r = _rowColfromParent(this, tile.zoom);
|
|
105
|
+
return target.set(this.col * r.invDiff - r.col, this.row * r.invDiff - r.row, r.invDiff, r.invDiff);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Returns the parent tile at the given level.
|
|
110
|
+
*
|
|
111
|
+
* @param levelParent - the level of the parent tile.
|
|
112
|
+
*/
|
|
113
|
+
tiledExtentParent(levelParent) {
|
|
114
|
+
if (levelParent && levelParent < this.zoom) {
|
|
115
|
+
const r = _rowColfromParent(this, levelParent);
|
|
116
|
+
return new Tile(this.crs, levelParent, r.row, r.col);
|
|
117
|
+
} else {
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sets zoom, row and column values.
|
|
124
|
+
*
|
|
125
|
+
* @param zoom - zoom value.
|
|
126
|
+
* @param row - row value.
|
|
127
|
+
* @param col - column value.
|
|
128
|
+
*/
|
|
129
|
+
set() {
|
|
130
|
+
let zoom = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
131
|
+
let row = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
132
|
+
let col = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
133
|
+
this.zoom = zoom;
|
|
134
|
+
this.row = row;
|
|
135
|
+
this.col = col;
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Copies the passed tile to this tile.
|
|
141
|
+
* @param tile - tile to copy.
|
|
142
|
+
*/
|
|
143
|
+
copy(tile) {
|
|
144
|
+
this.crs = tile.crs;
|
|
145
|
+
return this.set(tile.zoom, tile.row, tile.col);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Return values of tile in string, separated by the separator input.
|
|
150
|
+
* @param separator - string separator
|
|
151
|
+
*/
|
|
152
|
+
toString() {
|
|
153
|
+
let separator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
154
|
+
return `${this.zoom}${separator}${this.row}${separator}${this.col}`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export function tiledCovering(e, tms) {
|
|
158
|
+
if (e.crs == 'EPSG:4326' && tms == 'EPSG:3857') {
|
|
159
|
+
const WMTS_PM = [];
|
|
160
|
+
const extent = _extent.copy(e).as(tms, _extent2);
|
|
161
|
+
const {
|
|
162
|
+
globalExtent,
|
|
163
|
+
globalDimension,
|
|
164
|
+
sTs
|
|
165
|
+
} = getInfoTms(tms);
|
|
166
|
+
extent.clampByExtent(globalExtent);
|
|
167
|
+
extent.planarDimensions(_dimensionTile);
|
|
168
|
+
const zoom = Math.floor(Math.log2(Math.round(globalDimension.x / (_dimensionTile.x * sTs.x))));
|
|
169
|
+
const countTiles = getCountTiles(tms, zoom);
|
|
170
|
+
const center = extent.center(_c);
|
|
171
|
+
_tmsCoord.x = center.x - globalExtent.west;
|
|
172
|
+
_tmsCoord.y = globalExtent.north - extent.north;
|
|
173
|
+
_tmsCoord.divide(globalDimension).multiply(countTiles).floor();
|
|
174
|
+
|
|
175
|
+
// ]N; N+1] => N
|
|
176
|
+
const maxRow = Math.ceil((globalExtent.north - extent.south) / globalDimension.x * countTiles.y) - 1;
|
|
177
|
+
for (let r = maxRow; r >= _tmsCoord.y; r--) {
|
|
178
|
+
WMTS_PM.push(new Tile(tms, zoom, r, _tmsCoord.x));
|
|
179
|
+
}
|
|
180
|
+
return WMTS_PM;
|
|
181
|
+
} else {
|
|
182
|
+
const target = new Tile(tms, 0, 0, 0);
|
|
183
|
+
const {
|
|
184
|
+
globalExtent,
|
|
185
|
+
globalDimension,
|
|
186
|
+
sTs,
|
|
187
|
+
isInverted
|
|
188
|
+
} = getInfoTms(e.crs);
|
|
189
|
+
const center = e.center(_c);
|
|
190
|
+
e.planarDimensions(_dimensionTile);
|
|
191
|
+
// Each level has 2^n * 2^n tiles...
|
|
192
|
+
// ... so we count how many tiles of the same width as tile we can fit
|
|
193
|
+
// in the layer
|
|
194
|
+
// ... 2^zoom = tilecount => zoom = log2(tilecount)
|
|
195
|
+
const zoom = Math.floor(Math.log2(Math.round(globalDimension.x / (_dimensionTile.x * sTs.x))));
|
|
196
|
+
const countTiles = getCountTiles(tms, zoom);
|
|
197
|
+
|
|
198
|
+
// Now that we have computed zoom, we can deduce x and y (or row /
|
|
199
|
+
// column)
|
|
200
|
+
_tmsCoord.x = center.x - globalExtent.west;
|
|
201
|
+
_tmsCoord.y = isInverted ? globalExtent.north - center.y : center.y - globalExtent.south;
|
|
202
|
+
_tmsCoord.divide(globalDimension).multiply(countTiles).floor();
|
|
203
|
+
target.set(zoom, _tmsCoord.y, _tmsCoord.x);
|
|
204
|
+
return [target];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
export default Tile;
|