rearrange

This commit is contained in:
KatKatKateryna
2025-04-21 16:05:03 +01:00
parent 3c9ffaadf6
commit 8aa41509f9
19 changed files with 1804 additions and 1264 deletions
+1
View File
@@ -0,0 +1 @@
# speckleCon2024_GIS_workshop
@@ -1,58 +1,58 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
<body>
<div id="mapContainer" style="min-height: 80vh;"></div>
<script>
// Add a map object
var map = L.map('mapContainer').setView([ 45 , -75 ], 5);
// Add basemap layer
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
(async () => {
var speckleUrl = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments'
const speckle_data = await fetch(speckleUrl, {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
console.log(speckle_data)
speckle_layer = L.geoJSON(speckle_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "comment"
},
pointToLayer: (feature, latlng) => {
return new L.marker(latlng)
},
onEachFeature: function (feature, layer) {
var html = '<span><td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html);
}
});
speckle_layer.addTo(map);
map.fitBounds(speckle_layer.getBounds())
})();
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
<body>
<div id="mapContainer" style="min-height: 80vh;"></div>
<script>
// Add a map object
var map = L.map('mapContainer').setView([ 45 , -75 ], 5);
// Add basemap layer
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
(async () => {
var speckleUrl = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments'
const speckle_data = await fetch(speckleUrl, {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
console.log(speckle_data)
speckle_layer = L.geoJSON(speckle_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "comment"
},
pointToLayer: (feature, latlng) => {
return new L.marker(latlng)
},
onEachFeature: function (feature, layer) {
var html = '<span><td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html);
}
});
speckle_layer.addTo(map);
map.fitBounds(speckle_layer.getBounds())
})();
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -1,25 +1,25 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<script>
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/12e10a7220&datatype=lines&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
})();
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<script>
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/12e10a7220&datatype=lines&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
})();
</script>
</body>
</html>
@@ -1,32 +1,32 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
<body>
<div id="mapContainer" style="min-height: 80vh;"></div>
<script>
// Add a map object
var map = L.map('mapContainer').setView([ 45 , -75 ], 5);
// Add basemap layer
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
<body>
<div id="mapContainer" style="min-height: 80vh;"></div>
<script>
// Add a map object
var map = L.map('mapContainer').setView([ 45 , -75 ], 5);
// Add basemap layer
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
</script>
</body>
</html>
@@ -1,33 +1,33 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<script>
(async () => {
// provide your API key to HERE API
const TRAFFIC_API_KEY = "41_ea6vX0sH8ec-wbRIEzUKt9tCUbW4rXDUeObNKoUc" // disposable key, replace with yours
// specify the traffic query extent
center_x = 26.716031460406192
center_y = 58.37359442585144
buffer = 0.002 // degrees, approx 200 meters
range_x = range_y = 2 * buffer
var bbox = `${center_x-range_x/2},${center_y-range_y/2},${center_x+range_x/2},${center_y+range_y/2}`
var traffic_url = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:${bbox}&apiKey=${TRAFFIC_API_KEY}`
var traffic_data = await fetch(traffic_url).then(response => response.json());
results = traffic_data.results
console.log(results)
})();
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<script>
(async () => {
// provide your API key to HERE API
const TRAFFIC_API_KEY = "41_ea6vX0sH8ec-wbRIEzUKt9tCUbW4rXDUeObNKoUc" // disposable key, replace with yours
// specify the traffic query extent
center_x = 26.716031460406192
center_y = 58.37359442585144
buffer = 0.002 // degrees, approx 200 meters
range_x = range_y = 2 * buffer
var bbox = `${center_x-range_x/2},${center_y-range_y/2},${center_x+range_x/2},${center_y+range_y/2}`
var traffic_url = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:${bbox}&apiKey=${TRAFFIC_API_KEY}`
var traffic_data = await fetch(traffic_url).then(response => response.json());
results = traffic_data.results
console.log(results)
})();
</script>
</body>
</html>
@@ -1,66 +1,66 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeck(){
var state = {
longitude: 26.716031460406192,
latitude: 58.37359442585144,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
const deckgl = createDeck()
var tile_layer = createTileLayer()
deckgl.setProps({layers: [tile_layer]})
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeck(){
var state = {
longitude: 26.716031460406192,
latitude: 58.37359442585144,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
const deckgl = createDeck()
var tile_layer = createTileLayer()
deckgl.setProps({layers: [tile_layer]})
</script>
</body>
</html>
@@ -1,221 +1,221 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
deckgl.setProps({layers: [tile_layer, speckle_layer]})
})();
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
deckgl.setProps({layers: [tile_layer, speckle_layer]})
})();
</script>
</body>
</html>
@@ -1,321 +1,321 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 18,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
all_layers = [tile_layer, speckle_layer]
deckgl.setProps({layers: all_layers})
////////// add and animate traffic
// provide your API key to HERE API
const TRAFFIC_API_KEY = "41_ea6vX0sH8ec-wbRIEzUKt9tCUbW4rXDUeObNKoUc" // disposable key, replace with yours
autoUpdateTrafficLayer(extent, all_layers)
async function getFeaturesFromTraffic(traffic_url)
{
traffic_features = []
try{
const data = await fetch(traffic_url).then(response => response.json());
results = data.results
for (segm in results){
var speed_factor = results[segm].currentFlow.speed / results[segm].currentFlow.freeFlow
links = results[segm].location.shape.links
pts_coords = []
for (link_ind in links){
pts = links[link_ind].points
for (pt_ind in pts){
pt = pts[pt_ind]
pts_coords.push([pt.lng, pt.lat, 0])
}
}
lineColor = getTrafficColor(speed_factor);
new_line = {"type":"Feature",
"geometry": {"type": "LineString", "coordinates": pts_coords},
"displayProperties": {"color": lineColor } };
traffic_features.push(new_line);
}
}
catch {}
return traffic_features
}
function getTrafficColor(speed_factor){
if (speed_factor>1){
speed_factor=1
}
speed_factor = (speed_factor - 0.5)*2 // remap for bigger visual difference
if (speed_factor<0){
speed_factor=0.1
}
color = 'rgba(100,100,100,255)'
green = Math.pow( (speed_factor ),0.5) *240
blue = 0
red = Math.pow( ((1 - speed_factor) ),0.5) *240
color = `rgba(${Math.round(red)},${Math.round(green)},${Math.round(blue)},255)`
return color
}
async function addTrafficLayer(extent, all_layers){
console.log("__update traffic")
// specify the traffic query extend a bit larger than the model extent
buffer = 0.004 // degrees, approx 400 meters
range_x = extent[2] - extent[0] + 2* buffer
range_y = extent[3] - extent[1] + 2* buffer
center_x = extent[0] + (extent[2] - extent[0])/2
center_y = extent[1] + (extent[3] - extent[1])/2
var bbox = `${center_x-range_x/2},${center_y-range_y/2},${center_x+range_x/2},${center_y+range_y/2}`
var traffic_url = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:${bbox}&apiKey=${TRAFFIC_API_KEY}`
var traffic_features = await getFeaturesFromTraffic(traffic_url);
traffic_layer = new deck.GeoJsonLayer({
id: 'traffic_layer',
data: traffic_features,
getLineWidth: f => 6,
getLineColor: f => rgbaToArgbList(f.displayProperties.color),
})
all_layers.splice(2, 1); // remove old traffic layer
all_layers.push(traffic_layer);
}
async function delay( ms, state = null ) {
return new Promise( ( resolve, reject ) => {
window.setTimeout( () => resolve( state ), ms );
} );
}
async function autoUpdateTrafficLayer(extent, all_layers) {
try {
while( true ) {
await addTrafficLayer(extent, all_layers);
deckgl.setProps({layers: all_layers});
await delay( 60000 );
}
}
catch( err ) {
console.error( err );
}
}
})();
</script>
</body>
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 18,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
all_layers = [tile_layer, speckle_layer]
deckgl.setProps({layers: all_layers})
////////// add and animate traffic
// provide your API key to HERE API
const TRAFFIC_API_KEY = "41_ea6vX0sH8ec-wbRIEzUKt9tCUbW4rXDUeObNKoUc" // disposable key, replace with yours
autoUpdateTrafficLayer(extent, all_layers)
async function getFeaturesFromTraffic(traffic_url)
{
traffic_features = []
try{
const data = await fetch(traffic_url).then(response => response.json());
results = data.results
for (segm in results){
var speed_factor = results[segm].currentFlow.speed / results[segm].currentFlow.freeFlow
links = results[segm].location.shape.links
pts_coords = []
for (link_ind in links){
pts = links[link_ind].points
for (pt_ind in pts){
pt = pts[pt_ind]
pts_coords.push([pt.lng, pt.lat, 0])
}
}
lineColor = getTrafficColor(speed_factor);
new_line = {"type":"Feature",
"geometry": {"type": "LineString", "coordinates": pts_coords},
"displayProperties": {"color": lineColor } };
traffic_features.push(new_line);
}
}
catch {}
return traffic_features
}
function getTrafficColor(speed_factor){
if (speed_factor>1){
speed_factor=1
}
speed_factor = (speed_factor - 0.5)*2 // remap for bigger visual difference
if (speed_factor<0){
speed_factor=0.1
}
color = 'rgba(100,100,100,255)'
green = Math.pow( (speed_factor ),0.5) *240
blue = 0
red = Math.pow( ((1 - speed_factor) ),0.5) *240
color = `rgba(${Math.round(red)},${Math.round(green)},${Math.round(blue)},255)`
return color
}
async function addTrafficLayer(extent, all_layers){
console.log("__update traffic")
// specify the traffic query extend a bit larger than the model extent
buffer = 0.004 // degrees, approx 400 meters
range_x = extent[2] - extent[0] + 2* buffer
range_y = extent[3] - extent[1] + 2* buffer
center_x = extent[0] + (extent[2] - extent[0])/2
center_y = extent[1] + (extent[3] - extent[1])/2
var bbox = `${center_x-range_x/2},${center_y-range_y/2},${center_x+range_x/2},${center_y+range_y/2}`
var traffic_url = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:${bbox}&apiKey=${TRAFFIC_API_KEY}`
var traffic_features = await getFeaturesFromTraffic(traffic_url);
traffic_layer = new deck.GeoJsonLayer({
id: 'traffic_layer',
data: traffic_features,
getLineWidth: f => 6,
getLineColor: f => rgbaToArgbList(f.displayProperties.color),
})
all_layers.splice(2, 1); // remove old traffic layer
all_layers.push(traffic_layer);
}
async function delay( ms, state = null ) {
return new Promise( ( resolve, reject ) => {
window.setTimeout( () => resolve( state ), ms );
} );
}
async function autoUpdateTrafficLayer(extent, all_layers) {
try {
while( true ) {
await addTrafficLayer(extent, all_layers);
deckgl.setProps({layers: all_layers});
await delay( 60000 );
}
}
catch( err ) {
console.error( err );
}
}
})();
</script>
</body>
</html>
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
Slides are here: https://drive.google.com/drive/folders/163zk4vPxXp6ZYaWszvPvEdFv61VxCbFW?usp=drive_link
+221
View File
@@ -0,0 +1,221 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
deckgl.setProps({layers: [tile_layer, speckle_layer]})
})();
</script>
</body>
</html>
+301
View File
@@ -0,0 +1,301 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SpeckleCon2024 GIS demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
function rgbaToArgbList(color) {
col = color.replace('rgba(','').replace(')','').split(',',4);
return [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
}
function createTileLayer()
{
var tileLayer = new deck.TileLayer({
id: 'TileLayer',
data: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
minZoom: 0,
renderSubLayers: props => {
const {boundingBox} = props.tile;
return new deck.BitmapLayer(props, {
data: null,
image: props.data,
bounds: [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0], boundingBox[1][1]]
});
}
})
return tileLayer;
}
function createDeckWithExtent(extent){
var state= {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 20,
maxZoom: 22,
minZoom: 12,
pitch: 60,
bearing: 1.469387755102039
}
var newDeckgl = new deck.DeckGL({
container: 'map',
initialViewState: state,
controller: true,
layers: []
});
return newDeckgl;
}
function fixVerticalPolygons(speckle_data){
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (!(feature.geometry.type.includes("Polygon"))){
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": feature.geometry.type, "coordinates":feature.geometry.coordinates},
"properties": feature.properties,
"displayProperties": feature.displayProperties });
}
else {
polygon_all_parts = []
// iterate through Polygon Parts
for (let p = 0; p < coords.length; p++) {
// check orientation of each PolygonPart, if vertical - shift points slightly
polygon_part = [];
inner = false;
for (let c = 0; c < coords[p].length; c++) {
polygon_part_loop = [];
if (c>0){
inner = true;
}
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.000000001 < sum_orientation && sum_orientation <0.000000001){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
coords[p][c][2][0] += 0.0000001;
coords[p][c][2][1] += 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = coords[p][c].slice(0,3);
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
/////////
multipolygon_coords = [coords[p][c][2], coords[p][c][3], coords[p][c][0]];
polygon_part_loop = multipolygon_coords;
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
};
};
if (createdPolygon == false){ // if non-vertical, or vertical with more than 4 vertices
multipolygon_coords = coords[p][c];
polygon_part_loop = multipolygon_coords;
if (inner == false){
polygon_part = [polygon_part_loop];
polygon_all_parts.push(polygon_part);
}
else{
polygon_all_parts[polygon_all_parts.length-1].push(polygon_part_loop);
}
}
};
};
new_polygon = {"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":polygon_all_parts},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties };
new_polygon.displayProperties.lineWidth = 0.05
speckle_features.push(new_polygon);
}
}
speckle_data.features = speckle_features
}
function createSpeckleLayer(speckle_data) {
// Create layer
speckle_layer = new deck.GeoJsonLayer({
id: `speckle_data`,
data: speckle_data,
// Styles
filled: true,
opacity: 0.8,
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getPointRadius: f => f.displayProperties.radius / 2,
})
return speckle_layer;
}
async function getFeaturesFromTraffic(traffic_url)
{
traffic_features = []
try{
const data = await fetch(traffic_url).then(response => response.json());
results = data.results
console.log(results);
var max_jam_factor = Math.max(...results.map(o => o.currentFlow.jamFactor))
for (segm in results){
var jam_factor = results[segm].currentFlow.jamFactor / max_jam_factor;
links = results[segm].location.shape.links
pts_coords = []
for (link_ind in links){
pts = links[link_ind].points
for (pt_ind in pts){
pt = pts[pt_ind]
pts_coords.push([pt.lng, pt.lat, 0])
}
}
lineColor = getTrafficColor(jam_factor);
new_line = {"type":"Feature",
"geometry": {"type": "LineString", "coordinates": pts_coords},
"displayProperties": {"color": lineColor, "width": results[segm].currentFlow.freeFlow} };
traffic_features.push(new_line);
}
}
catch {}
return traffic_features
}
function getTrafficColor(jam_factor){
// higher jam factor, higher red color
color = 'rgba(100,100,100,255)'
red = Math.pow( (jam_factor ),0.5) *240
blue = 0
green = Math.pow( ((1 - jam_factor) ),0.5) *240
color = `rgba(${Math.round(red)},${Math.round(green)},${Math.round(blue)},255)`
return color
}
async function addTrafficLayer(extent, all_layers){
console.log("__update traffic")
const TRAFFIC_API_KEY = "41_ea6vX0sH8ec-wbRIEzUKt9tCUbW4rXDUeObNKoUc" // disposable key, replace with yours
// specify the traffic query extend a bit larger than the model extent
buffer = 0.004 // degrees, approx 400 meters
range_x = extent[2] - extent[0] + 2* buffer
range_y = extent[3] - extent[1] + 2* buffer
center_x = extent[0] + (extent[2] - extent[0])/2
center_y = extent[1] + (extent[3] - extent[1])/2
var bbox = `${center_x-range_x/2},${center_y-range_y/2},${center_x+range_x/2},${center_y+range_y/2}`
var traffic_url = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:${bbox}&apiKey=${TRAFFIC_API_KEY}`
var traffic_features = await getFeaturesFromTraffic(traffic_url);
traffic_layer = new deck.GeoJsonLayer({
id: 'traffic_layer',
data: traffic_features,
getLineWidth: f => Math.ceil(f.displayProperties.width),
getLineColor: f => rgbaToArgbList(f.displayProperties.color),
})
all_layers.splice(2, 1); // remove old traffic layer
all_layers.push(traffic_layer);
}
(async () => {
// define Speckle Models' URLs
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/b973c777fe/models/49aff22443&limit=1000000&datatype=polygons&lon=26.7155164&lat=58.3739412&preserveattributes=true';
// fetch Speckle data
const speckle_data = await fetch(speckle_url, { headers: {'Accept': 'application/geo+json'}}).then(response => response.json());
// print received data to console
console.log(speckle_data);
// fix rendering of vertical polygons
fixVerticalPolygons(speckle_data)
// get spatial extent of Speckle data
var extent = speckle_data["extent"]
// Create deck.gl map
const deckgl = createDeckWithExtent(extent)
var tile_layer = createTileLayer()
var speckle_layer = createSpeckleLayer(speckle_data)
// add traffic layer
all_layers = [tile_layer, speckle_layer]
await addTrafficLayer(extent, all_layers);
deckgl.setProps({layers: all_layers})
})();
</script>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"name": "square_json",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::27700" } },
"features": [
{ "type": "Feature", "properties": { "label": "EPSG:4326, [-10, -10, 10, 10]" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -10.0, -10.0 ], [ 10.0, -10.0 ], [ 10.0, 10.0 ], [ -10.0, 10.0 ], [ -10.0, -10.0 ] ] ] } }
]
}
+8
View File
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"name": "square_json - Copy",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::27700" } },
"features": [
{ "type": "Feature", "properties": { "label": "EPSG:27700, [-1000000, -1000000, 1000000, 1000000]" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -1000000.0, -1000000.0 ], [ 1000000.0, -1000000.0 ], [ 1000000.0, 1000000.0 ], [ -1000000.0, 1000000.0 ], [ -1000000.0, -1000000.0 ] ] ] } }
]
}
+1 -1
View File
@@ -1 +1 @@
# speckleCon2024_GIS_workshop
# Speckle GIS workshops