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

How to calculate coordinate with 'transform' and 'boundingVolume'? #158

Open
sophia-xll opened this issue Nov 5, 2018 · 1 comment
Open

Comments

@sophia-xll
Copy link

sophia-xll commented Nov 5, 2018

According to 3dtiles-spec:
An additional tile transform may be applied to transform a tile's local coordinate system to the parent tile's coordinate system.

I know how to calculate transform:
screenshot at 2018-11-05 15 03 54

Howerer, how to calculate coordinate with 'transform' and 'boundingVolume:box'?

tileset.json:
{"asset": {"version": "1.0"},
"geometricError": 1319.96566351801,
"root": {
"boundingVolume": {
"box": [
1.04773789644241e-9, -0.504322739783674, -0.616247923113406,
5641.31597575976, 0, 0, 0,
6311.33777747117, 0, 0, 0, 25.8459681412205]
},
"children": [
{
"boundingVolume": {
"box": [
2797.89169446776, -3133.07355675142, 12.5403080463512,
2843.42428129305, 0, 0,
0, 3180.84259900837, 0,
0, 0, 15.1854221645246 ]},
"content": {"url": "tileset_1_1_0.json"},
"geometricError": 164.995707939751,
"refine": "REPLACE"
}]
"geometricError": 329.991415879503,
"refine": "REPLACE",
"transform": [
-0.895897517499185, -0.444260777177997, 0, 0,
0.283927872032897, -0.572569735547873, 0.769122136866122, 0,
-0.341690798268945, 0.689054613072027, 0.639101821764334, 0,
-2176357.29229105, 4388848.16197401, 4070680.03399528, 1
]
}
}

tileset_1_1_0.json
{"asset": {"version": "1.0"},
"root": {
"boundingVolume": {
"box": [
2.3283064365387e-10, -0.113443724578246, 3.57330994307995,
2843.42474428168, 0, 0,
0, 3179.80389127671, 0,
0, 0, 15.5025072079152]
},
"children": [],
"content": {"url": "1/1/0.b3dm"},
"geometricError": 164.995707939751,
"refine": "REPLACE",
"transform": [
0.999999837172188, 0.00036471139259886, -0.000438909100338114, 0,
-0.000364495423816037, 0.999999812521052, 0.000492037546955482, 0,
0.000439088469750899, -0.000491877486479553, 0.999999782628903, 0,
2796.72426339705, -3132.95792494155, 8.96653714217246, 1]
}
}

How to calculate children'box of tileset.json according to tileset_1_1_0.json?
By the way, I have tried children:box of tileset.json not equal to T0*T1*B1.

@javagl
Copy link
Contributor

javagl commented Nov 22, 2022

By the way, I have tried children:box of tileset.json not equal to T0T1B1.

It is not entirely clear what you compared here.

These are the input files:

tileset.json

{
  "asset": { "version": "1.0" },
  "geometricError": 1319.96566351801,
  "root": {
    "boundingVolume": {
      "box": [
        1.04773789644241e-9, -0.504322739783674, -0.616247923113406,
        5641.31597575976, 0, 0, 
        0, 6311.33777747117, 0, 
        0, 0, 25.8459681412205
      ]
    },
    "children": [
      {
        "boundingVolume": {
          "box": [
            2797.89169446776, -3133.07355675142, 12.5403080463512,
            2843.42428129305, 0, 0, 0, 3180.84259900837, 0, 0, 0,
            15.1854221645246
          ]
        },
        "content": { "url": "tileset_1_1_0.json" },
        "geometricError": 164.995707939751,
        "refine": "REPLACE"
      }
    ],
    "geometricError": 329.991415879503,
    "refine": "REPLACE",
    "transform": [
      -0.895897517499185, -0.444260777177997, 0, 0, 0.283927872032897,
      -0.572569735547873, 0.769122136866122, 0, -0.341690798268945,
      0.689054613072027, 0.639101821764334, 0, -2176357.29229105,
      4388848.16197401, 4070680.03399528, 1
    ]
  }
}

and tileset_1_1_0.json

{
  "asset": { "version": "1.0" },
  "root": {
    "boundingVolume": {
      "box": [
        2.3283064365387e-10, -0.113443724578246, 3.57330994307995, 
        2843.42474428168, 0, 0, 
        0, 3179.80389127671, 0, 
        0, 0, 15.5025072079152
      ]
    },
    "children": [],
    "content": { "url": "1/1/0.b3dm" },
    "geometricError": 164.995707939751,
    "refine": "REPLACE",
    "transform": [
      0.999999837172188, 0.00036471139259886, -0.000438909100338114, 0,
      -0.000364495423816037, 0.999999812521052, 0.000492037546955482, 0,
      0.000439088469750899, -0.000491877486479553, 0.999999782628903, 0,
      2796.72426339705, -3132.95792494155, 8.96653714217246, 1
    ]
  }
}

They can be loaded with the following sandcastle:

// Create a viewer, add the tileset, and zoom to the tileset
const viewer = new Cesium.Viewer("cesiumContainer");
const tileset = viewer.scene.primitives.add(
  new Cesium.Cesium3DTileset({
    url: "http://localhost:8003/tileset.json",
    debugShowBoundingVolume: true,
    maximumScreenSpaceError: 1.0,
  })
);
const offset = new Cesium.HeadingPitchRange(
  0,
  Cesium.Math.toRadians(-67.5),
  40000.0
);
viewer.zoomTo(tileset, offset);

/**
 * Creates an OrientedBoundingBox from an array of numbers, as
 * it is given in the tileset JSON input
 *
 * @param {Number[]} box The array
 * @returns The OrientedBoundingBox
 */
function createOrientedBoundingBox(box) {
  const center = Cesium.Cartesian3.fromElements(
    box[0],
    box[1],
    box[2],
    new Cesium.Cartesian3()
  );
  const halfAxes = Cesium.Matrix3.fromArray(box, 3, new Cesium.Matrix3());
  return new Cesium.OrientedBoundingBox(center, halfAxes);
}

/**
 * Transforms the given oriented bounding box with the given
 * transform, and returns the result
 *
 * @param {OrientedBoundingBox} obb The oriented bounding box
 * @param {Matrix4} transform The transform
 * @returns The transformed oriented bounding box
 */
function transformOrientedBoundingBox(obb, transform) {
  const center = Cesium.Matrix4.multiplyByPoint(
    transform,
    obb.center,
    new Cesium.Cartesian3()
  );
  const rotationScale = Cesium.Matrix4.getMatrix3(
    transform,
    new Cesium.Matrix3()
  );
  const halfAxes = Cesium.Matrix3.multiply(
    rotationScale,
    obb.halfAxes,
    new Cesium.Matrix3()
  );
  return new Cesium.OrientedBoundingBox(center, halfAxes);
}

// After all tiles have been loaded, print some bounding volume information:
tileset.allTilesLoaded.addEventListener(function () {
  // NOTE: The following lines make MANY assumptions about the
  // structure of the tileset, and are tailored SPECIFICALLY
  // for this example:
  const transform0 = tileset.root.transform;
  const externalRoot = tileset.root.children[0].content.tile.children[0];
  const transform1 = externalRoot.transform;
  const externalRootBox = externalRoot.boundingVolume.boundingVolume;

  // Compute the product of the root transform, and of the
  // root transform of the external tileset
  const T0 = Cesium.Matrix4.fromArray(transform0, 0, new Cesium.Matrix4());
  const T1 = Cesium.Matrix4.fromArray(transform1, 0, new Cesium.Matrix4());
  const P = Cesium.Matrix4.multiply(T0, T1, new Cesium.Matrix4());

  // Create an oriented bounding box from the original input
  // in the (external) tileset JSON file
  const boxFromInputJson = [
    2.3283064365387e-10, -0.113443724578246, 3.57330994307995, 2843.42474428168,
    0, 0, 0, 3179.80389127671, 0, 0, 0, 15.5025072079152,
  ];
  const originalChildBox = createOrientedBoundingBox(boxFromInputJson);

  // Print a comparison of
  // - the original bounding box of the external tileset
  // - the result of transforming this bounding box with T0*t1
  // - the bounding box of the external tileset root,
  //   as it was loaded with CesiumJS
  console.log("originalChildBox:");
  console.log("    center " + originalChildBox.center);
  console.log("    halfAxes " + originalChildBox.halfAxes);

  const transformed = transformOrientedBoundingBox(originalChildBox, P);
  console.log("transformed:");
  console.log("    center " + transformed.center);
  console.log("    halfAxes " + transformed.halfAxes);

  console.log("externalRootBox:");
  console.log("    center " + externalRootBox.center);
  console.log("    halfAxes " + externalRootBox.halfAxes);

  //debugger;
});

The output will be

originalChildBox:
    center (2.3283064365387e-10, -0.113443724578246, 3.57330994307995)
    halfAxes (2843.42474428168, 0, 0)
(0, 3179.80389127671, 0)
(0, 0, 15.5025072079152)
transformed:
    center (-2179756.7235751543, 4389408.229815634, 4068278.332300388)
    halfAxes (-2546.6958814336103, 903.3385461820669, -5.305326306015831)
(-1264.6755963022426, -1819.0661398295, 10.683413748708821)
(5.919066787294536e-14, 2446.657032950468, 9.901813631454507)
externalRootBox:
    center (-2179756.7235751543, 4389408.229815634, 4068278.332300388)
    halfAxes (-2546.6958814336103, 903.3385461820669, -5.305326306015831)
(-1264.6755963022426, -1819.0661398295, 10.683413748708821)
(5.919066787294536e-14, 2446.657032950468, 9.901813631454507)

The originalChildBox is the bounding box that was given in the tileset_1_1_0.json file. This bounding box is transformed with T0 * T1 (which are the transforms from tileset.json and tileset_1_1_0.json, respectively). The result is equal to the bounding box that is obtained directly from the external tileset root, after it was loaded with CesiumJS.

So usually, the bounding box of a single child eventually should be T0*T1*B1.

(It becomes trickier whe this does not only involve a bounding box, but also regions or spheres (or just multiple bounding boxes). But the overall idea of spatial consistency can be maintained there as well)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants