How to select multiple entities with a rectangle?

231 views
Skip to first unread message

Hieu Nguyen

unread,
Jul 4, 2019, 2:57:07 AM7/4/19
to cesium-dev
Hi all,
I found this example on the internet, but I want to select multiple entities ( not tileset)  with a rectangle. How can i do ?

selection.gif


Omar Shehata

unread,
Jul 8, 2019, 8:40:16 AM7/8/19
to cesium-dev
Can you link to where you found this example? Did it have code to go with it? You could potentially do the same type of selection with entities as you can with tiles.

Hieu Nguyen

unread,
Jul 8, 2019, 10:27:49 PM7/8/19
to cesium-dev
this is source for selection tiles. I don't know of any way to do it works as tiles. Can you support me ?


// Click to start selection, move mouse, then click again to end selection
var viewer = new Cesium.Viewer('cesiumContainer');
var boxElement = document.getElementById('box'); 

var scene = viewer.scene;
var camera = scene.camera;
var url = '../../../Specs/Data/Cesium3DTiles/Tilesets/Tileset/';
var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
    url : url,
    debugShowContentBoundingVolume : true
}));

tileset.readyPromise.then(function() {
    var boundingSphere = tileset.boundingSphere;
    viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0.0, -1.0, boundingSphere.radius));
    viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
});

var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);

var start;
var end;
handler.setInputAction(function(movement) {
    if (!Cesium.defined(start)) {
        start = Cesium.Cartesian2.clone(movement.position, new Cesium.Cartesian2());
        return;
    }
    if (Cesium.defined(start)) {
        end = Cesium.Cartesian2.clone(movement.position, new Cesium.Cartesian2());
        selectTiles(start, end);
        start = undefined;
        end = undefined;
        boxElement.style.width = '0px';
        boxElement.style.height = '0px';
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);


handler.setInputAction(function(movement) {
    if (Cesium.defined(start)) {
        var end = movement.endPosition;
        var rectangle = getRectangle(start, end);
        boxElement.style.left = rectangle.x + 'px';
        boxElement.style.top = rectangle.y + 'px';
        boxElement.style.width = rectangle.width + 'px';
        boxElement.style.height = rectangle.height + 'px';
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

function getRectangle(start, end) {
    var xMin = Math.min(start.x, end.x);
    var xMax = Math.max(start.x, end.x);
    var yMin = Math.min(start.y, end.y);
    var yMax = Math.max(start.y, end.y);
    var width = xMax - xMin;
    var height = yMax - yMin;
    
    return new Cesium.BoundingRectangle(xMin, yMin, width, height);
}

function getCenter(rectangle) {
    return new Cesium.Cartesian2(rectangle.x + rectangle.width / 2.0, rectangle.y + rectangle.height / 2.0);
}

function selectTiles(start, end) {
    start = Cesium.SceneTransforms.transformWindowToDrawingBuffer(scene, start, start);
    end = Cesium.SceneTransforms.transformWindowToDrawingBuffer(scene, end, end);
    
    var rectangle = getRectangle(start, end);
    var center = getCenter(rectangle);
    var cullingVolume = getCullingVolume(center, rectangle.width, rectangle.height);
    var selected = [];
    traverseTileset(tileset._root, cullingVolume, selected);
    
    var color = Cesium.Color.fromRandom({alpha:1.0});
    var length = selected.length;
    for (var i = 0; i < length; ++i) {
        selected[i].color = color;
    }
}

function traverseTileset(tile, cullingVolume, selected) {
    var boundingVolume = tile._boundingVolume;
    var contentBoundingVolume = tile._contentBoundingVolume;
    
    if (!intersectsBoundingVolume(cullingVolume, boundingVolume)) {
        // Stop traversal early since children won't be visible either
        return;
    }
    
    if (!Cesium.defined(contentBoundingVolume) || intersectsBoundingVolume(cullingVolume, contentBoundingVolume)) {
        // Test intersection with the content bounding volume
        selected.push(tile);
    }

    var children = tile.children;
    var length = children.length;
    for (var i = 0; i < length; ++i) {
        traverseTileset(children[i], cullingVolume, selected);
    }
}

function intersectsBoundingVolume(cullingVolume, boundingVolume) {
    return cullingVolume.computeVisibility(boundingVolume) !== Cesium.Intersect.OUTSIDE;
}

function getCullingVolume(center, width, height) {
    // Adapted from getPickPerspectiveCullingVolume in Scene.js
    var screenWidth = scene.drawingBufferWidth;
    var screenHeight = scene.drawingBufferHeight;

    var frustum = camera.frustum;
    var near = frustum.near;
    var far = frustum.far;

    var tanPhi = Math.tan(frustum.fovy * 0.5);
    var tanTheta = frustum.aspectRatio * tanPhi;

    var x = 2.0 * center.x / screenWidth - 1.0;
    var y = 2.0 * (screenHeight - center.y) / screenHeight - 1.0;

    var xDir = x * near * tanTheta;
    var yDir = y * near * tanPhi;

    var pixelSize = frustum.getPixelDimensions(screenWidth, screenHeight, near, new Cesium.Cartesian2());
    var pickWidth = pixelSize.x * width * 0.5;
    var pickHeight = pixelSize.y * height * 0.5;

    var offCenter = new Cesium.PerspectiveOffCenterFrustum();
    offCenter.top = yDir + pickHeight;
    offCenter.bottom = yDir - pickHeight;
    offCenter.right = xDir + pickWidth;
    offCenter.left = xDir - pickWidth;
    offCenter.near = near;
    offCenter.far = far;
    
    return offCenter.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
}




Vào 19:40:16 UTC+7 Thứ Hai, ngày 08 tháng 7 năm 2019, Omar Shehata đã viết:
Can you link to where you found this example? Did it have code to go with ithit? You could potentially do the same type of selection with entities as you can with tiles.

Omar Shehata

unread,
Jul 9, 2019, 2:18:20 PM7/9/19
to cesium-dev
I think you may be using an older version of CesiumJS. I was unable to get this code to work in Sandcastle (https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html). Looks like the URL should end with tileset.json, and it's missing the HTML box element.

In any case, you should be able to apply the same logic for entities by computing the entity's bounding sphere. There's some discussion on doing that here: https://groups.google.com/d/msg/cesium-dev/BSXl9QhzlXs/KMQ_1rXzBwAJ

Hieu Nguyen

unread,
Jul 10, 2019, 5:21:12 AM7/10/19
to cesium-dev
Thanks ! I did it. i create a rectangle like example and use drillPick ( ex: let pickedObjects = viewer.scene.drillPick(centerRectangle, null, rectangle.width, rectangle.height);
) to get entity collection 

Vào 01:18:20 UTC+7 Thứ Tư, ngày 10 tháng 7 năm 2019, Omar Shehata đã viết:
Reply all
Reply to author
Forward
0 new messages