2017-09-11 7 views
0

Viewer APIでは、選択したオブジェクトをドラッグできますか? Ctrlキーを押しながらクリックするのではなく、ドラッグすることで複数のオブジェクトを選択できるようになります。ビューアApiでオブジェクトを選択してドラッグしますか?

+0

ないデフォルトでなんとか残念ながら、あなたは機能のようなものを自分で実装する必要があるだろう... –

+0

あなたは私のいずれかを与えることができますこの行動を開発するヒント? –

+0

簡単な答えはありません。3D世界で2Dマウスの位置を変換し、長方形のボリュームを計算し、モデルメッシュと交差検出を実行して、ボリューム内/外/交差を確認します。 .. –

答えて

0

私はコードサンプルとして、ウィンドウ選択機能を実装する過程にあります。詳細については、このarticleを見て、次のようなもののためにご期待...

import Toolkit from 'Viewer.Toolkit' 

export default class SelectSet { 

    ///////////////////////////////////////////////////////// 
    // 
    // 
    ///////////////////////////////////////////////////////// 
    constructor (viewer) { 

    this.viewer = viewer 

    this.viewer.impl.createOverlayScene (
     'debug', this.lineMat) 
    } 

    ///////////////////////////////////////////////////////// 
    // Set model: required to compute the bounding boxes 
    // 
    ///////////////////////////////////////////////////////// 
    async setModel (model) { 

    this.model = model 

    const instanceTree = model.getData().instanceTree 

    const rootId = instanceTree.getRootId() 

    const bbox = 
     await this.getComponentBoundingBox(
     model, rootId) 

    this.boundingSphere = bbox.getBoundingSphere() 

    const leafIds = await Toolkit.getLeafNodes (model) 

    this.boundingBoxInfo = leafIds.map((dbId) => { 

     const bbox = this.getLeafComponentBoundingBox(
     model, dbId) 

     return { 
     bbox, 
     dbId 
     } 
    }) 

    console.log(this.boundingBoxInfo) 
    console.log(model) 
    } 

    ///////////////////////////////////////////////////////// 
    // Returns bounding box as it appears in the viewer 
    // (transformations could be applied) 
    // 
    ///////////////////////////////////////////////////////// 
    getModifiedWorldBoundingBox (fragIds, fragList) { 

    const fragbBox = new THREE.Box3() 
    const nodebBox = new THREE.Box3() 

    fragIds.forEach(function(fragId) { 

     fragList.getWorldBounds(fragId, fragbBox) 

     nodebBox.union(fragbBox) 
    }) 

    return nodebBox 
    } 

    ///////////////////////////////////////////////////////// 
    // Returns bounding box for aggregated fragments 
    // 
    ///////////////////////////////////////////////////////// 
    async getComponentBoundingBox (model, dbId) { 

    const fragIds = await Toolkit.getFragIds(
     model, dbId) 

    const fragList = model.getFragmentList() 

    return this.getModifiedWorldBoundingBox(
     fragIds, fragList) 
    } 

    getLeafComponentBoundingBox (model, dbId) { 

    const fragIds = Toolkit.getLeafFragIds(
     model, dbId) 

    const fragList = model.getFragmentList() 

    return this.getModifiedWorldBoundingBox(
     fragIds, fragList) 
    } 

    ///////////////////////////////////////////////////////// 
    // Creates Raycaster object from the mouse pointer 
    // 
    ///////////////////////////////////////////////////////// 
    pointerToRay (pointer) { 

    const camera = this.viewer.navigation.getCamera() 
    const pointerVector = new THREE.Vector3() 
    const rayCaster = new THREE.Raycaster() 
    const pointerDir = new THREE.Vector3() 
    const domElement = this.viewer.canvas 

    const rect = domElement.getBoundingClientRect() 

    const x = ((pointer.clientX - rect.left)/rect.width) * 2 - 1 
    const y = -((pointer.clientY - rect.top)/rect.height) * 2 + 1 

    if (camera.isPerspective) { 

     pointerVector.set(x, y, 0.5) 

     pointerVector.unproject(camera) 

     rayCaster.set(camera.position, 
     pointerVector.sub(
      camera.position).normalize()) 

    } else { 

     pointerVector.set(x, y, -15) 

     pointerVector.unproject(camera) 

     pointerDir.set(0, 0, -1) 

     rayCaster.set(pointerVector, 
     pointerDir.transformDirection(
      camera.matrixWorld)) 
    } 

    return rayCaster.ray 
    } 

    ///////////////////////////////////////////////////////// 
    // 
    // 
    ///////////////////////////////////////////////////////// 
    containsBox (planes, box) { 

    const {min, max} = box 

    const vertices = [ 
     new THREE.Vector3(min.x, min.y, min.z), 
     new THREE.Vector3(min.x, min.y, max.z), 
     new THREE.Vector3(min.x, max.y, max.z), 
     new THREE.Vector3(max.x, max.y, max.z), 
     new THREE.Vector3(max.x, max.y, min.z), 
     new THREE.Vector3(max.x, min.y, min.z), 
     new THREE.Vector3(min.x, max.y, min.z), 
     new THREE.Vector3(max.x, min.y, max.z) 
    ] 

    for (let vertex of vertices) { 

     for (let plane of planes) { 

     if (plane.distanceToPoint(vertex) < 0) { 

      return false 
     } 
     } 
    } 

    return true 
    } 

    ///////////////////////////////////////////////////////// 
    // 
    // 
    ///////////////////////////////////////////////////////// 
    getCameraPlane() { 

    const camera = this.viewer.navigation.getCamera() 

    const normal = camera.target.clone().sub(
     camera.position).normalize() 

    const pos = camera.position 

    const dist = 
     - normal.x * pos.x 
     - normal.y * pos.y 
     - normal.z * pos.z 

    return new THREE.Plane (normal, dist) 
    } 

    ///////////////////////////////////////////////////////// 
    // Runs the main logic of the select set: 
    // computes a pyramid shape from the selection window 
    // corners and determines enclosed meshes from the model 
    // 
    ///////////////////////////////////////////////////////// 
    compute (pointer1, pointer2) { 

    // build 4 rays to project the 4 corners 
    // of the selection window 

    const xMin = Math.min(pointer1.clientX, pointer2.clientX) 
    const xMax = Math.max(pointer1.clientX, pointer2.clientX) 

    const yMin = Math.min(pointer1.clientY, pointer2.clientY) 
    const yMax = Math.max(pointer1.clientY, pointer2.clientY) 

    const ray1 = this.pointerToRay({ 
     clientX: xMin, 
     clientY: yMin 
    }) 

    const ray2 = this.pointerToRay({ 
     clientX: xMax, 
     clientY: yMin 
    }) 

    const ray3 = this.pointerToRay({ 
     clientX: xMax, 
     clientY: yMax 
    }) 

    const ray4 = this.pointerToRay({ 
     clientX: xMin, 
     clientY: yMax 
    }) 

    // first we compute the top of the pyramid 
    const top = new THREE.Vector3(0,0,0) 

    top.add (ray1.origin) 
    top.add (ray2.origin) 
    top.add (ray3.origin) 
    top.add (ray4.origin) 

    top.multiplyScalar(0.25) 

    // we use the bounding sphere to determine 
    // the height of the pyramid 
    const {center, radius} = this.boundingSphere 

    // compute distance from pyramid top to center 
    // of bounding sphere 

    const dist = new THREE.Vector3(
     top.x - center.x, 
     top.y - center.y, 
     top.z - center.z) 

    // compute height of the pyramid: 
    // to make sure we go far enough, 
    // we add the radius of the bounding sphere 

    const height = radius + dist.length() 

    // compute the length of the side edges 

    const angle = ray1.direction.angleTo(
     ray2.direction) 

    const length = height/Math.cos(angle * 0.5) 

    // compute bottom vertices 

    const v1 = new THREE.Vector3(
     ray1.origin.x + ray1.direction.x * length, 
     ray1.origin.y + ray1.direction.y * length, 
     ray1.origin.z + ray1.direction.z * length) 

    const v2 = new THREE.Vector3(
     ray2.origin.x + ray2.direction.x * length, 
     ray2.origin.y + ray2.direction.y * length, 
     ray2.origin.z + ray2.direction.z * length) 

    const v3 = new THREE.Vector3(
     ray3.origin.x + ray3.direction.x * length, 
     ray3.origin.y + ray3.direction.y * length, 
     ray3.origin.z + ray3.direction.z * length) 

    const v4 = new THREE.Vector3(
     ray4.origin.x + ray4.direction.x * length, 
     ray4.origin.y + ray4.direction.y * length, 
     ray4.origin.z + ray4.direction.z * length) 

    // create planes 

    const plane1 = new THREE.Plane() 
    const plane2 = new THREE.Plane() 
    const plane3 = new THREE.Plane() 
    const plane4 = new THREE.Plane() 
    const plane5 = new THREE.Plane() 

    plane1.setFromCoplanarPoints(top, v1, v2) 
    plane2.setFromCoplanarPoints(top, v2, v3) 
    plane3.setFromCoplanarPoints(top, v3, v4) 
    plane4.setFromCoplanarPoints(top, v4, v1) 
    plane5.setFromCoplanarPoints(v3, v2, v1) 

    const planes = [ 
     plane1, plane2, 
     plane3, plane4, 
     plane5, this.getCameraPlane() 
    ] 

    // filter all bbox which are contained inside 
    // the pyramid defined by our planes 

    const selectedBBoxInfo = 
     this.boundingBoxInfo.filter((bboxInfo) => { 

     return this.containsBox(planes, bboxInfo.bbox) 
     }) 

    const dbIds = selectedBBoxInfo.map((bboxInfo) => { 

     return bboxInfo.dbId 
    }) 

    return dbIds 
    } 
} 
関連する問題