Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iTwin Reality Data - add GeoJSON/KML support #12344

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions Apps/Sandcastle/gallery/iTwin Feature Service.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<meta
name="description"
content="Use Viewer to start building new applications or easily embed Cesium into existing applications."
/>
<meta name="cesium-sandcastle-labels" content="Beginner, Showcases" />
<title>iTwin Feature Service</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="module" src="../load-cesium-es6.js"></script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<div id="layers"></div>
</div>
<script id="cesium_sandcastle_script">
window.startup = async function (Cesium) {
"use strict";
//Sandcastle_Begin
const serviceResponse = await fetch("https://api.cesium.com/itwin/token");
const { access_token: token } = await serviceResponse.json();

Cesium.ITwinPlatform.defaultAccessToken = token;

const iTwinId = "535a24a3-9b29-4e23-bb5d-9cedb524c743";

const viewer = new Cesium.Viewer("cesiumContainer");

const featureServiceBaseUrl = "https://featureservice-eus.bentley.com";
const proxyUrl = "http://localhost:3000/proxy";

const points = await Cesium.ITwinData.createDataSourceForRealityDataId(
iTwinId,
"60976bd9-3176-4017-974a-4fcea76346db",
);
const lines = await Cesium.ITwinData.createDataSourceForRealityDataId(
iTwinId,
"5af22b93-cf7e-4879-9305-4c6bdda7987f",
);
const areas = await Cesium.ITwinData.createDataSourceForRealityDataId(
iTwinId,
"ebec69b5-0b5f-49d8-9081-e29bcd517f6b",
);
viewer.dataSources.add(points);
viewer.dataSources.add(lines);
viewer.dataSources.add(areas);

// Create tileset of the reality data mesh
// TODO: swap this out with a different mesh
const realityMeshId = "85897090-3bcc-470b-bec7-20bb639cc1b9";
const realityMesh = await Cesium.ITwinData.createTilesetForRealityDataId(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tileset is really blurry for me, unless I force the maximumScreenSpaceError smaller.

Current maximumScreenSpaceError: 4:
image

With maximumScreenSpaceError: 1:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a problem in the other sandcastle as well. 4 seemed to be a decent value overall but maybe not that far zoomed out. This is not the final mesh going to be used for this Sandcastle so I can re-evaluate that when I update to the other data.

iTwinId,
realityMeshId,
);
viewer.scene.primitives.add(realityMesh);

Sandcastle.addToolbarButton(
"Toggle Points",
() => (points.show = !points.show),
"layers",
);
Sandcastle.addToolbarButton(
"Toggle Lines",
() => (lines.show = !lines.show),
"layers",
);
Sandcastle.addToolbarButton(
"Toggle Areas",
() => (areas.show = !areas.show),
"layers",
);
Sandcastle.addToolbarButton(
"Toggle Reality Mesh",
() => (realityMesh.show = !realityMesh.show),
"layers",
);

Sandcastle.addToolbarButton("Zoom to Lines", () => {
lines.show = true;
viewer.zoomTo(lines);
});
Sandcastle.addToolbarButton("Zoom to Reality Mesh", () => {
realityMesh.show = true;
viewer.zoomTo(realityMesh);
});

const birdsEyeView = {
destination: new Cesium.Cartesian3(
-1525452.5685833949,
6191771.429542403,
148747.35086195532,
),
orientation: new Cesium.HeadingPitchRoll(
3.552713678800501e-15,
-0.7854791130671286,
6.283185307179583,
),
duration: 0,
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
};
viewer.scene.camera.flyTo(birdsEyeView);
//Sandcastle_End
Sandcastle.finishedLoading();
};
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
window.startup(Cesium).catch((error) => {
"use strict";
console.error(error);
});
}
</script>
</body>
</html>
41 changes: 3 additions & 38 deletions packages/engine/Source/Core/ITwinPlatform.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,54 +38,19 @@ ITwinPlatform.ExportType = Object.freeze({
});

/**
* Types of Reality data
* Types of Reality data. This is a partial list of types we know we can support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we dropping the unsupported types here?
In the loading functions, we already create a local supportedRealityDataTypes array, so it seems like this enum could still retain all valid types, including unsupported ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was requested by the iTwin team. The types are potentially changing and/or not a complete list so I trimmed this down to only those types we really care about. I still wanted to keep it in the enum instead of only in the array of supportedRealityTypes to make it centrally located and easy to change later.

*
* @see https://developer.bentley.com/apis/reality-management/rm-rd-details/#types
* @enum {string}
*/
ITwinPlatform.RealityDataType = Object.freeze({
Cesium3DTiles: "Cesium3DTiles",
PNTS: "PNTS",
OPC: "OPC",
RealityMesh3DTiles: "RealityMesh3DTiles",
Terrain3DTiles: "Terrain3DTiles",
"3MX": "3MX",
"3SM": "3SM",
CCCloudProject: "CCCloudProject",
CCImageCollection: "CCImageCollection",
CCOrientations: "CCOrientations",
ContextCaptureInputs: "ContextCaptureInputs",
ContextDetector: "ContextDetector",
ContextScene: "ContextScene",
DAE: "DAE",
DGN: "DGN",
DSM: "DSM",
FBX: "FBX",
GLB: "GLB",
GLTF: "GLTF",
KML: "KML",
LAS: "LAS",
LAZ: "LAZ",
LOD: "LOD",
LodTree: "LodTree",
OBJ: "OBJ",
OMI: "OMI",
OMR: "OMR",
Orthophoto: "Orthophoto",
OrthophotoDSM: "OrthophotoDSM",
OSGB: "OSGB",
OVF: "OVF",
OBT: "OBT",
PLY: "PLY",
PointCloud: "PointCloud",
S3C: "S3C",
ScanCollection: "ScanCollection",
SHP: "SHP",
SLPK: "SLPK",
SpaceEyes3D: "SpaceEyes3D",
STL: "STL",
TSM: "TSM",
GeoJSON: "GeoJSON",
Unstructured: "Unstructured",
Other: "Other",
});

/**
Expand Down
70 changes: 70 additions & 0 deletions packages/engine/Source/Scene/ITwinData.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Resource from "../Core/Resource.js";
import ITwinPlatform from "../Core/ITwinPlatform.js";
import RuntimeError from "../Core/RuntimeError.js";
import Check from "../Core/Check.js";
import KmlDataSource from "../DataSources/KmlDataSource.js";
import GeoJsonDataSource from "../DataSources/GeoJsonDataSource.js";

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

/**
* Create a data source of the correct type for the specified reality data id.
* This function only works for KML and GeoJSON type data.
*
* If the <code>type</code> or <code>rootDocument</code> are not provided this function
* will first request the full metadata for the specified reality data to fill these values.
*
* @param {string} iTwinId The id of the iTwin to load data from
* @param {string} realityDataId The id of the reality data to load
* @param {ITwinPlatform.RealityDataType} [type] The type of this reality data
* @param {string} [rootDocument] The path of the root document for this reality data
* @returns {Promise<GeoJsonDataSource | KmlDataSource>}
*
* @throws {RuntimeError} if the type of reality data is not supported by this function
*/
ITwinData.createDataSourceForRealityDataId = async function loadRealityData(
iTwinId,
realityDataId,
type,
rootDocument,
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("iTwinId", iTwinId);
Check.typeOf.string("realityDataId", realityDataId);
if (defined(type)) {
Check.typeOf.string("type", type);
}
if (defined(rootDocument)) {
Check.typeOf.string("rootDocument", rootDocument);
}
//>>includeEnd('debug')

if (!defined(type) || !defined(rootDocument)) {
const metadata = await ITwinPlatform.getRealityDataMetadata(
iTwinId,
realityDataId,
);
rootDocument = metadata.rootDocument;
type = metadata.type;
}

const supportedRealityDataTypes = [
ITwinPlatform.RealityDataType.KML,
ITwinPlatform.RealityDataType.GeoJSON,
];

if (!supportedRealityDataTypes.includes(type)) {
throw new RuntimeError(
`Reality data type is not a data source type: ${type}`,
);
}

const tilesetAccessUrl = await ITwinPlatform.getRealityDataURL(
iTwinId,
realityDataId,
rootDocument,
);

if (type === ITwinPlatform.RealityDataType.GeoJSON) {
return GeoJsonDataSource.load(tilesetAccessUrl);
}

// If we get here it's guaranteed to be a KML type
return KmlDataSource.load(tilesetAccessUrl);
};

export default ITwinData;
Loading