I’m trying to relocate a iTwin BIM model (iModel) from its source location (0,0,0) to a new location on the other side of the globe, which means it also needs to be rotated. The relocation bit of the code works as designed, but the model tileset is sitting at an angle against the surface of the globe. I understand “quaternion” is part of the answer, but not able to figure it out. Any help very much appreciated. Here is an extract of my code:
if (auth.isAuthenticated) {
let viewer: Cesium.Viewer | undefined = undefined;
let selectedFeature: any | undefined;
let iModelTiles: Cesium.Cesium3DTileset | undefined = undefined;
useEffect(() => {
const initializeCesium = async () => {
Cesium.ITwinPlatform.defaultAccessToken = auth.user?.access_token!;
// Set up viewer
viewer = new Cesium.Viewer('cesiumContainer', {
animation: false,
sceneModePicker: false,
geocoder: Cesium.IonGeocodeProviderType.GOOGLE,
homeButton: true,
infoBox: false,
timeline: false,
globe: false,
});
const scene = viewer.scene;
// Configure the mouse over event for Cesium Feature and Element Id
const handler = new Cesium.ScreenSpaceEventHandler(scene?.canvas);
handler.setInputAction((movement: any) => {
if (selectedFeature) {
selectedFeature = unselectFeature(selectedFeature);
}
const feature = scene?.pick(movement.endPosition);
if (feature instanceof Cesium3DTileFeature) {
selectedFeature = selectFeature(feature);
}
}, ScreenSpaceEventType.MOUSE_MOVE);
Cesium.Fullscreen.requestFullscreen(scene.canvas);
// Use Google Photo realistic tiles
const tileset = await Cesium.createGooglePhotorealistic3DTileset();
scene.primitives.add(tileset);
// Overlay the iTwin / iModel BIM Models
iModelTiles = await Cesium.ITwinData.createTilesetFromIModelId('d60aef62-0d6b-41f0-8f95-5551591c02c3');
scene.primitives.add(iModelTiles);
//Find the position of the Model in the Cesium world
const cartographic = Cesium.Cartographic.fromCartesian(iModelTiles!.boundingSphere.center);
console.log('cartographic', cartographic);
const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
console.log('surface', surface);
//Determine the new position of the model in the Cesium world
const offset = Cesium.Cartesian3.fromDegrees(-117.412848, 33.273222, 0);
console.log('offset', offset);
const updatedPosition = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
console.log('updatedPosition', updatedPosition);
//const newModelMatrix = Cesium.Matrix4.fromTranslation(updatedPosition);
//iModelTiles!.modelMatrix = newModelMatrix;
//Up to here it works - repositioning the model in the Cesium world
const heading = Cesium.Math.toRadians(135);
const pitch = 0;
const roll = 0;
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
console.log('hpr', hpr);
const quaternion = Cesium.Transforms.headingPitchRollQuaternion(updatedPosition, hpr);
console.log('quaternion', quaternion);
const rotationMatrix = Cesium.Matrix3.fromQuaternion(quaternion);
console.log('rotationMatrix', rotationMatrix);
const newModelMatrix = Cesium.Matrix4.fromRotationTranslation(rotationMatrix, updatedPosition);
console.log('newModelMatrix', newModelMatrix);
iModelTiles!.modelMatrix = newModelMatrix;
// this will reposition and rotate the model, but up in the sky somewhere, and when the mouse moves the model disappears
//Prep the bounding sphere for the iModel tileset so we can zoom to it
const bs: Cesium.BoundingSphere = iModelTiles!.boundingSphere;
viewer!.camera.flyToBoundingSphere(bs, { duration: 2 });
};
initializeCesium();
}, [viewer]);