Skip to content

Commit 7d33049

Browse files
authored
Merge pull request #12344 from CesiumGS/itwin-more-reality-data-types
iTwin Reality Data - add GeoJSON/KML support
2 parents 382c517 + 16496df commit 7d33049

File tree

7 files changed

+385
-39
lines changed

7 files changed

+385
-39
lines changed

.vscode/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"iife",
6363
"lerp",
6464
"Lilli",
65+
"maki",
6566
"MAXAR",
6667
"minifiers",
6768
"mipmapped",
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
9+
/>
10+
<meta
11+
name="description"
12+
content="Use Viewer to start building new applications or easily embed Cesium into existing applications."
13+
/>
14+
<meta name="cesium-sandcastle-labels" content="Beginner, Showcases" />
15+
<title>iTwin Feature Service</title>
16+
<script type="text/javascript" src="../Sandcastle-header.js"></script>
17+
<script type="module" src="../load-cesium-es6.js"></script>
18+
</head>
19+
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
20+
<style>
21+
@import url(../templates/bucket.css);
22+
</style>
23+
<div id="cesiumContainer" class="fullSize"></div>
24+
<div id="loadingOverlay"><h1>Loading...</h1></div>
25+
<div id="toolbar">
26+
<div id="layers"></div>
27+
</div>
28+
<script id="cesium_sandcastle_script">
29+
window.startup = async function (Cesium) {
30+
"use strict";
31+
//Sandcastle_Begin
32+
const serviceResponse = await fetch("https://api.cesium.com/itwin/token");
33+
const { access_token: token } = await serviceResponse.json();
34+
35+
Cesium.ITwinPlatform.defaultAccessToken = token;
36+
37+
const iTwinId = "04ba725f-f3c0-4f30-8014-a4488cbd612d";
38+
39+
const viewer = new Cesium.Viewer("cesiumContainer", {
40+
geocoder: false,
41+
sceneModePicker: false,
42+
homeButton: false,
43+
timeline: false,
44+
animation: false,
45+
});
46+
viewer.baseLayerPicker.viewModel.selectedImagery =
47+
viewer.baseLayerPicker.viewModel.imageryProviderViewModels[2];
48+
49+
const birdsEyeView = {
50+
destination: new Cesium.Cartesian3(
51+
-1525359.4318772827,
52+
6191643.528984093,
53+
148851.5321709012,
54+
),
55+
orientation: new Cesium.HeadingPitchRoll(
56+
0.16657338935967037,
57+
-0.7943050121851765,
58+
6.283180723449992,
59+
),
60+
duration: 0,
61+
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
62+
};
63+
viewer.scene.camera.flyTo(birdsEyeView);
64+
65+
// Load feature service geojson files
66+
const points = await Cesium.ITwinData.createDataSourceForRealityDataId(
67+
iTwinId,
68+
"57b975f6-fd92-42ba-8014-79911ed606d1",
69+
);
70+
const lines = await Cesium.ITwinData.createDataSourceForRealityDataId(
71+
iTwinId,
72+
"1099c53f-c568-48a3-a57c-0230a6f37229",
73+
);
74+
const areas = await Cesium.ITwinData.createDataSourceForRealityDataId(
75+
iTwinId,
76+
"21eaf0d0-ab90-400f-97cf-adc455b29a78",
77+
);
78+
79+
// Add some styling to the lines and points to differentiate types
80+
const pinBuilder = new Cesium.PinBuilder();
81+
points.entities.values.forEach(async (entity) => {
82+
const styleByType = {
83+
Tree: { color: Cesium.Color.GREEN, icon: "park2" },
84+
Lamp_post: { color: Cesium.Color.WHITE, icon: "lighthouse" },
85+
Traffic_light: { color: Cesium.Color.CRIMSON, icon: "circle-stroked" },
86+
Arrow_Marking: { color: Cesium.Color.YELLOW, icon: "car" },
87+
Road_Sign: { color: Cesium.Color.ORANGE, icon: "triangle" },
88+
};
89+
const type = entity.properties.Type?.getValue();
90+
if (Cesium.defined(type) && Cesium.defined(styleByType[type])) {
91+
const { color, icon } = styleByType[type];
92+
const canvas = await pinBuilder.fromMakiIconId(icon, color, 48);
93+
entity.billboard.image = canvas.toDataURL();
94+
entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
95+
}
96+
});
97+
lines.entities.values.forEach((entity) => {
98+
const lineColorsByType = {
99+
Contours: Cesium.Color.CRIMSON,
100+
Lane_Marking: Cesium.Color.CYAN,
101+
Kerb: Cesium.Color.BLUEVIOLET,
102+
Chevron_marking: Cesium.Color.DARKORANGE,
103+
Turning_pocket: Cesium.Color.DEEPPINK,
104+
Yellow_Box: Cesium.Color.GOLD,
105+
};
106+
const type = entity.properties.Type?.getValue();
107+
if (Cesium.defined(type) && Cesium.defined(lineColorsByType[type])) {
108+
entity.polyline.material = lineColorsByType[type];
109+
}
110+
});
111+
112+
// add the geojsons to the viewer
113+
viewer.dataSources.add(points);
114+
viewer.dataSources.add(lines);
115+
viewer.dataSources.add(areas);
116+
117+
// Create tileset of the reality data mesh and pointcloud
118+
const realityMeshId = "62e4432d-621d-489a-87ff-1fc56a2b5369";
119+
const realityMesh = await Cesium.ITwinData.createTilesetForRealityDataId(
120+
iTwinId,
121+
realityMeshId,
122+
);
123+
viewer.scene.primitives.add(realityMesh);
124+
const pointcloudId = "ebf2ee74-f0de-4cd6-a311-19a169c55fdc";
125+
const pointcloud = await Cesium.ITwinData.createTilesetForRealityDataId(
126+
iTwinId,
127+
pointcloudId,
128+
);
129+
// increase the size of the pointcloud points and turn on attenuation to
130+
// make them more visible in the viewer
131+
pointcloud.maximumScreenSpaceError = 1;
132+
pointcloud.pointCloudShading.attenuation = true;
133+
pointcloud.style = new Cesium.Cesium3DTileStyle({
134+
pointSize: 5.0,
135+
});
136+
pointcloud.show = false;
137+
viewer.scene.primitives.add(pointcloud);
138+
139+
Sandcastle.addToolbarButton(
140+
"Toggle Points",
141+
() => (points.show = !points.show),
142+
"layers",
143+
);
144+
Sandcastle.addToolbarButton(
145+
"Toggle Lines",
146+
() => (lines.show = !lines.show),
147+
"layers",
148+
);
149+
Sandcastle.addToolbarButton(
150+
"Toggle Areas",
151+
() => (areas.show = !areas.show),
152+
"layers",
153+
);
154+
Sandcastle.addToolbarButton(
155+
"Toggle Reality Mesh",
156+
() => (realityMesh.show = !realityMesh.show),
157+
"layers",
158+
);
159+
Sandcastle.addToolbarButton(
160+
"Toggle Pointcloud",
161+
() => (pointcloud.show = !pointcloud.show),
162+
"layers",
163+
);
164+
165+
Sandcastle.addToolbarButton("Birdseye View", () => {
166+
viewer.scene.camera.flyTo(birdsEyeView);
167+
});
168+
Sandcastle.addToolbarButton("Zoom to Pointcloud", () => {
169+
pointcloud.show = true;
170+
viewer.zoomTo(pointcloud);
171+
});
172+
//Sandcastle_End
173+
Sandcastle.finishedLoading();
174+
};
175+
if (typeof Cesium !== "undefined") {
176+
window.startupCalled = true;
177+
window.startup(Cesium).catch((error) => {
178+
"use strict";
179+
console.error(error);
180+
});
181+
}
182+
</script>
183+
</body>
184+
</html>
Loading

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
##### Additions :tada:
88

99
- Added an integration with the [iTwin Platform](https://developer.bentley.com/) to load iModels as 3D Tiles. Use `ITwinPlatform.defaultAccessToken` to set the access token. Use `ITwinData.createTilesetFromIModelId(iModelId)` to load the iModel as a `Cesium3DTileset`. [#12289](https://github.com/CesiumGS/cesium/pull/12289)
10+
- Added an integration with the [iTwin Platform](https://developer.bentley.com/) to load Reality Data terrain meshes and GeoJSON. Use `ITwinPlatform.defaultAccessToken` to set the access token. Then use `ITwinData.createTilesetForRealityDataId(iTwinId, dataId)` to load terrain meshes as a `Cesium3DTileset` or `ITwinData.createDataSourceForRealityDataId(iTwinId, dataId)` to load GeoJSON or KML files as data sources. [#12344](https://github.com/CesiumGS/cesium/pull/12344)
1011
- Added `getSample` to `SampledProperty` to get the time of samples. [#12253](https://github.com/CesiumGS/cesium/pull/12253)
1112
- Added `Entity.trackingReferenceFrame` property to allow tracking entities in various reference frames. [#12194](https://github.com/CesiumGS/cesium/pull/12194), [#12314](https://github.com/CesiumGS/cesium/pull/12314)
1213
- `TrackingReferenceFrame.AUTODETECT` (default): uses either VVLH or ENU depending on entity's dynamic. Use `TrackingReferenceFrame.ENU` if your camera orientation flips abruptly from time to time.

packages/engine/Source/Core/ITwinPlatform.js

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -38,54 +38,19 @@ ITwinPlatform.ExportType = Object.freeze({
3838
});
3939

4040
/**
41-
* Types of Reality data
41+
* Types of Reality data. This is a partial list of types we know we can support
42+
*
4243
* @see https://developer.bentley.com/apis/reality-management/rm-rd-details/#types
4344
* @enum {string}
4445
*/
4546
ITwinPlatform.RealityDataType = Object.freeze({
4647
Cesium3DTiles: "Cesium3DTiles",
4748
PNTS: "PNTS",
48-
OPC: "OPC",
4949
RealityMesh3DTiles: "RealityMesh3DTiles",
5050
Terrain3DTiles: "Terrain3DTiles",
51-
"3MX": "3MX",
52-
"3SM": "3SM",
53-
CCCloudProject: "CCCloudProject",
54-
CCImageCollection: "CCImageCollection",
55-
CCOrientations: "CCOrientations",
56-
ContextCaptureInputs: "ContextCaptureInputs",
57-
ContextDetector: "ContextDetector",
58-
ContextScene: "ContextScene",
59-
DAE: "DAE",
60-
DGN: "DGN",
61-
DSM: "DSM",
62-
FBX: "FBX",
63-
GLB: "GLB",
64-
GLTF: "GLTF",
6551
KML: "KML",
66-
LAS: "LAS",
67-
LAZ: "LAZ",
68-
LOD: "LOD",
69-
LodTree: "LodTree",
70-
OBJ: "OBJ",
71-
OMI: "OMI",
72-
OMR: "OMR",
73-
Orthophoto: "Orthophoto",
74-
OrthophotoDSM: "OrthophotoDSM",
75-
OSGB: "OSGB",
76-
OVF: "OVF",
77-
OBT: "OBT",
78-
PLY: "PLY",
79-
PointCloud: "PointCloud",
80-
S3C: "S3C",
81-
ScanCollection: "ScanCollection",
82-
SHP: "SHP",
83-
SLPK: "SLPK",
84-
SpaceEyes3D: "SpaceEyes3D",
85-
STL: "STL",
86-
TSM: "TSM",
52+
GeoJSON: "GeoJSON",
8753
Unstructured: "Unstructured",
88-
Other: "Other",
8954
});
9055

9156
/**

packages/engine/Source/Scene/ITwinData.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Resource from "../Core/Resource.js";
44
import ITwinPlatform from "../Core/ITwinPlatform.js";
55
import RuntimeError from "../Core/RuntimeError.js";
66
import Check from "../Core/Check.js";
7+
import KmlDataSource from "../DataSources/KmlDataSource.js";
8+
import GeoJsonDataSource from "../DataSources/GeoJsonDataSource.js";
79

810
/**
911
* Methods for loading iTwin platform data into CesiumJS
@@ -86,6 +88,8 @@ ITwinData.createTilesetFromIModelId = async function (iModelId, options) {
8688
* @param {ITwinPlatform.RealityDataType} [type] The type of this reality data
8789
* @param {string} [rootDocument] The path of the root document for this reality data
8890
* @returns {Promise<Cesium3DTileset>}
91+
*
92+
* @throws {RuntimeError} if the type of reality data is not supported by this function
8993
*/
9094
ITwinData.createTilesetForRealityDataId = async function (
9195
iTwinId,
@@ -135,4 +139,70 @@ ITwinData.createTilesetForRealityDataId = async function (
135139
});
136140
};
137141

142+
/**
143+
* Create a data source of the correct type for the specified reality data id.
144+
* This function only works for KML and GeoJSON type data.
145+
*
146+
* If the <code>type</code> or <code>rootDocument</code> are not provided this function
147+
* will first request the full metadata for the specified reality data to fill these values.
148+
*
149+
* @param {string} iTwinId The id of the iTwin to load data from
150+
* @param {string} realityDataId The id of the reality data to load
151+
* @param {ITwinPlatform.RealityDataType} [type] The type of this reality data
152+
* @param {string} [rootDocument] The path of the root document for this reality data
153+
* @returns {Promise<GeoJsonDataSource | KmlDataSource>}
154+
*
155+
* @throws {RuntimeError} if the type of reality data is not supported by this function
156+
*/
157+
ITwinData.createDataSourceForRealityDataId = async function loadRealityData(
158+
iTwinId,
159+
realityDataId,
160+
type,
161+
rootDocument,
162+
) {
163+
//>>includeStart('debug', pragmas.debug);
164+
Check.typeOf.string("iTwinId", iTwinId);
165+
Check.typeOf.string("realityDataId", realityDataId);
166+
if (defined(type)) {
167+
Check.typeOf.string("type", type);
168+
}
169+
if (defined(rootDocument)) {
170+
Check.typeOf.string("rootDocument", rootDocument);
171+
}
172+
//>>includeEnd('debug')
173+
174+
if (!defined(type) || !defined(rootDocument)) {
175+
const metadata = await ITwinPlatform.getRealityDataMetadata(
176+
iTwinId,
177+
realityDataId,
178+
);
179+
rootDocument = metadata.rootDocument;
180+
type = metadata.type;
181+
}
182+
183+
const supportedRealityDataTypes = [
184+
ITwinPlatform.RealityDataType.KML,
185+
ITwinPlatform.RealityDataType.GeoJSON,
186+
];
187+
188+
if (!supportedRealityDataTypes.includes(type)) {
189+
throw new RuntimeError(
190+
`Reality data type is not a data source type: ${type}`,
191+
);
192+
}
193+
194+
const tilesetAccessUrl = await ITwinPlatform.getRealityDataURL(
195+
iTwinId,
196+
realityDataId,
197+
rootDocument,
198+
);
199+
200+
if (type === ITwinPlatform.RealityDataType.GeoJSON) {
201+
return GeoJsonDataSource.load(tilesetAccessUrl);
202+
}
203+
204+
// If we get here it's guaranteed to be a KML type
205+
return KmlDataSource.load(tilesetAccessUrl);
206+
};
207+
138208
export default ITwinData;

0 commit comments

Comments
 (0)