UNPKG

vicowa-web-components

Version:
590 lines (551 loc) 36.1 kB
import { CAP_TYPES } from './vicowa-webgl-definitions.js'; import { vectorLength, angleToPoint, pointToAngle, vectorSubtract, vectorAdd, toRadians } from '../utilities/mathHelpers.js'; const MANIPULATOR_GROUP_TYPES = Object.freeze({ MOVE: 'MOVE', SCALE: 'SCALE', ROTATE: 'ROTATE', }); export const MANIPULATOR_TYPES = Object.freeze({ MOVE_X: 'MOVE_X', MOVE_Y: 'MOVE_Y', MOVE_Z: 'MOVE_Z', MOVE_PLANE: 'MOVE_PLANE', SCALE: 'SCALE', SCALE_X: 'SCALE_X', SCALE_Y: 'SCALE_Y', SCALE_Z: 'SCALE_Z', ROTATE_X: 'ROTATE_X', ROTATE_Y: 'ROTATE_Y', ROTATE_Z: 'ROTATE_Z', }); const privateData = Symbol('privateData'); const manipulation = Symbol('manipulation'); const manipulatorRenderingGroup = 1; function createMoveObject(name, extensionData) { const moveObject = extensionData.webglIF.createGroup(name); moveObject.addChild(extensionData.webglIF.createSphere({ diameter: 0.2, rotation: { x: 90, y: 0, z: 0 }, material: 'move-manipulator-unselected', renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { y: -0.2 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: -0.3 }, rotation: { x: 0, y: 0, z: 180 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { y: 0.2 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: 0.3 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.visible = false; return moveObject; } function createPlaneMoveObject(name, extensionData) { const moveObject = extensionData.webglIF.createGroup(name); moveObject.addChild(extensionData.webglIF.createSphere({ diameter: 0.2, rotation: { x: 90, y: 0, z: 0 }, material: 'move-manipulator-unselected', renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { y: -0.2 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: -0.3 }, rotation: { z: 180 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { y: 0.2 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: 0.3 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { z: -0.2 }, rotation: { x: 90 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { z: -0.3 }, rotation: { x: 90, z: 180 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.15, position: { z: 0.2 }, rotation: { x: -90 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { z: 0.3 }, rotation: { x: -90, z: 180 }, renderingGroupId: manipulatorRenderingGroup })); moveObject.visible = false; return moveObject; } function createScaleObject(name, extensionData) { const scaleObject = extensionData.webglIF.createGroup(name); scaleObject.addChild(extensionData.webglIF.createSphere({ diameter: 0.15, diameterZ: 0.3, rotation: { x: 90, y: 0, z: 0 }, material: 'scale-manipulator-unselected', renderingGroupId: manipulatorRenderingGroup })); scaleObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: -0.3 }, rotation: { x: 0, y: 0, z: 180 }, renderingGroupId: manipulatorRenderingGroup })); scaleObject.addChild(extensionData.webglIF.createCylinder({ diameter: 0.05, height: 0.6, renderingGroupId: manipulatorRenderingGroup })); scaleObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { y: 0.3 }, renderingGroupId: manipulatorRenderingGroup })); scaleObject.visible = false; return scaleObject; } function createRotateObject(name, extensionData) { const rotateObject = extensionData.webglIF.createGroup(name); rotateObject.addChild(extensionData.webglIF.createSphere({ diameter: 0.2, rotation: { x: 90, y: 0, z: 0 }, material: 'rotate-manipulator-unselected', renderingGroupId: manipulatorRenderingGroup })); const path = []; const arc = toRadians(270); const startAngle = toRadians(0); const stepSize = arc / 16; const dist = 0.2; for (let rad = startAngle; rad < startAngle + arc; rad += stepSize) { path.push([Math.sin(rad) * dist, Math.cos(rad) * dist, 0]); } rotateObject.addChild(extensionData.webglIF.createTube({ radius: 0.025, cap: CAP_TYPES.CAP_ALL, path, renderingGroupId: manipulatorRenderingGroup })); rotateObject.addChild(extensionData.webglIF.createCylinder({ diameterTop: 0, diameterBottom: 0.1, height: 0.1, position: { x: -0.2 }, rotation: { x: 0, y: 0, z: 0 }, renderingGroupId: manipulatorRenderingGroup })); rotateObject.visible = false; return rotateObject; } function createManipulatorTemplates(extension) { const extensionData = extension[privateData]; extensionData.manipulators[MANIPULATOR_TYPES.MOVE_X] = extensionData.manipulators[MANIPULATOR_TYPES.MOVE_Y] = extensionData.manipulators[MANIPULATOR_TYPES.MOVE_Z] = createMoveObject('move-manipulator', extensionData); extensionData.manipulators[MANIPULATOR_TYPES.MOVE_PLANE] = createPlaneMoveObject('move-manipulator', extensionData); extensionData.manipulators[MANIPULATOR_TYPES.SCALE_X] = extensionData.manipulators[MANIPULATOR_TYPES.SCALE_Y] = extensionData.manipulators[MANIPULATOR_TYPES.SCALE_Z] = extensionData.manipulators[MANIPULATOR_TYPES.SCALE] = createScaleObject('scale-manipulator', extensionData); extensionData.manipulators[MANIPULATOR_TYPES.ROTATE_X] = extensionData.manipulators[MANIPULATOR_TYPES.ROTATE_Y] = extensionData.manipulators[MANIPULATOR_TYPES.ROTATE_Z] = createRotateObject('rotate-manipulator', extensionData); } function createAndAttachManipulatorInstance(manipulatorName, extension, obj, settings) { const extensionData = extension[privateData]; const name = `${manipulatorName}-${obj.name}`; obj.getChildren((childObject) => childObject.name === name).forEach((childObject) => obj.removeChild(childObject)); const clonedObject = extensionData.manipulators[manipulatorName].clone(name); extensionData.webglIF.applySettings(Object.assign({ collisions: true, visible: true }, settings), clonedObject); clonedObject.manipulatorType = manipulatorName; obj.addChild(clonedObject); } function attachMoveXManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.MOVE_X, extension, object, settings); } function attachMoveYManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.MOVE_Y, extension, object, settings); } function attachMoveZManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.MOVE_Z, extension, object, settings); } function attachMovePlaneManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.MOVE_PLANE, extension, object, settings); } function attachScaleXManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.SCALE_X, extension, object, settings); } function attachScaleYManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.SCALE_Y, extension, object, settings); } function attachScaleZManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.SCALE_Z, extension, object, settings); } function attachScaleManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.SCALE, extension, object, settings); } function attachRotateAroundXManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.ROTATE_X, extension, object, settings); } function attachRotateAroundYManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.ROTATE_Y, extension, object, settings); } function attachRotateAroundZManipulator(extension, object, settings) { createAndAttachManipulatorInstance(MANIPULATOR_TYPES.ROTATE_Z, extension, object, settings); } function attachManipulators(extension, object, clickPoint) { const extensionData = extension[privateData]; const allowed = object[manipulation].allowed; const activeGroup = object[manipulation].activeGroup; const manipulatorPlane = object[manipulation].manipulatorPlane; extension.removeManipulators(object.name); if (allowed && Object.keys(allowed).find((key) => MANIPULATOR_TYPES[key] && allowed[key])) { const center = object.center; const boundingVectors = object.boundingVectors; const manipulatorObject = extensionData.webglIF.createGroup(`manipulator-for-${object.name}`); extensionData.activeManipulationObjects[manipulatorObject.name] = manipulatorObject; manipulatorObject.manipulatedObject = object; manipulatorObject.manipulatedObject.onRemove = (removingObject) => { extension.removeManipulators(removingObject.name); }; const getPosition = (targetOffsetX, targetOffsetY) => { const screenPoint = extensionData.webglIF.pointToScreenPoint(clickPoint || center); const planePointPair = extensionData.webglIF.screenPointToBoundingProjection(screenPoint, object); const distance = vectorLength(vectorSubtract(planePointPair.intersection, planePointPair.start)); const factor = 1 / distance; const position = { x: planePointPair.intersection.x - ((planePointPair.intersection.x - planePointPair.start.x) * factor), y: planePointPair.intersection.y - ((planePointPair.intersection.y - planePointPair.start.y) * factor), z: planePointPair.intersection.z - ((planePointPair.intersection.z - planePointPair.start.z) * factor), }; const vector = vectorSubtract(planePointPair.intersection, planePointPair.start); const zAngle = 0; const yAngle = 90 - pointToAngle({ x: vector.x, y: vector.z }); const xAngle = (vector.z > 0) ? -pointToAngle({ x: vector.z, y: vector.y }) : pointToAngle({ x: vector.z, y: vector.y }); const tempPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position, rotation: { x: xAngle, y: yAngle, z: zAngle }, collisions: true, sideOrientation: 2, visible: true, }); tempPlane.updateCoordinates(); const planePos = extensionData.webglIF.screenToObjectPoint({ x: screenPoint.x + targetOffsetX, y: screenPoint.y + targetOffsetY }, tempPlane); tempPlane.remove(); return { position: planePos, scale: { x: distance / 5, y: distance / 5, z: distance / 5, }, }; }; if (activeGroup === MANIPULATOR_GROUP_TYPES.MOVE) { if (allowed[MANIPULATOR_TYPES.MOVE_PLANE]) { if (manipulatorPlane) { const pos = getPosition(0, 0); attachMovePlaneManipulator(extension, manipulatorObject, { position: pos.position, scale: pos.scale, rotation: { x: 0, y: manipulatorPlane.rotation.y + 90, z: manipulatorPlane.rotation.x } }); manipulatorObject.getChildren()[0].manipulatorPlane = manipulatorPlane; } } else { if (allowed[MANIPULATOR_TYPES.MOVE_X]) { const pos = getPosition(60, 60); attachMoveXManipulator(extension, manipulatorObject, { position: pos.position, scale: pos.scale, rotation: { x: 0, y: 0, z: 90 } }); } if (allowed[MANIPULATOR_TYPES.MOVE_Y]) { const pos = getPosition(-60, -60); attachMoveYManipulator(extension, manipulatorObject, { position: pos.position, scale: pos.scale, rotation: { x: 0, y: 0, z: 0 } }); } if (allowed[MANIPULATOR_TYPES.MOVE_Z]) { const pos = getPosition(-60, 60); attachMoveZManipulator(extension, manipulatorObject, { position: pos.position, scale: pos.scale, rotation: { x: 90, y: 0, z: 0 } }); } } } else if (activeGroup === MANIPULATOR_GROUP_TYPES.SCALE) { if (allowed[MANIPULATOR_TYPES.SCALE]) { const pos = getPosition(60, -60); attachScaleManipulator(extension, manipulatorObject, { position: pos.position, scale: pos.scale, rotation: { x: -45, y: -45, z: 0 } }); } else { if (allowed[MANIPULATOR_TYPES.SCALE_X]) { const pos = getPosition(60, 60); attachScaleXManipulator(extension, manipulatorObject, { position: boundingVectors[0], scale: pos.scale, rotation: { x: 0, y: 0, z: 90 } }); } if (allowed[MANIPULATOR_TYPES.SCALE_Y]) { const pos = getPosition(-60, -60); attachScaleYManipulator(extension, manipulatorObject, { position: boundingVectors[1], scale: pos.scale, rotation: { x: 0, y: 0, z: 0 } }); } if (allowed[MANIPULATOR_TYPES.SCALE_Z]) { const pos = getPosition(-60, 60); attachScaleZManipulator(extension, manipulatorObject, { position: boundingVectors[2], scale: pos.scale, rotation: { x: 90, y: 0, z: 0 } }); } } } else if (activeGroup === MANIPULATOR_GROUP_TYPES.ROTATE) { if (allowed[MANIPULATOR_TYPES.ROTATE_X]) { const pos = getPosition(60, 60); attachRotateAroundXManipulator(extension, manipulatorObject, { position: boundingVectors[0], scale: pos.scale, rotation: { x: 180, y: 270, z: -90 } }); } if (allowed[MANIPULATOR_TYPES.ROTATE_Y]) { const pos = getPosition(-60, -60); attachRotateAroundYManipulator(extension, manipulatorObject, { position: boundingVectors[1], scale: pos.scale, rotation: { x: 90, y: 270, z: 0 } }); } if (allowed[MANIPULATOR_TYPES.ROTATE_Z]) { const pos = getPosition(-60, 60); attachRotateAroundZManipulator(extension, manipulatorObject, { position: boundingVectors[2], scale: pos.scale, rotation: { x: 0, y: 0, z: 90 } }); } } } } function setNextGroup(extension, obj) { if (obj[manipulation].activeGroup) { if (obj[manipulation].activeGroup === MANIPULATOR_GROUP_TYPES.ROTATE) { if (obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_PLANE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.MOVE; } else if (obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.SCALE; } } else if (obj[manipulation].activeGroup === MANIPULATOR_GROUP_TYPES.MOVE) { if (obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.SCALE; } else if (obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Z]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.ROTATE; } } else if (obj[manipulation].activeGroup === MANIPULATOR_GROUP_TYPES.SCALE) { if (obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Z]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.ROTATE; } else if (obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_PLANE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.MOVE; } } } else { if (obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.MOVE_PLANE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.MOVE; } else if (obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE_Z] || obj[manipulation].allowed[MANIPULATOR_TYPES.SCALE]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.SCALE; } else if (obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_X] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Y] || obj[manipulation].allowed[MANIPULATOR_TYPES.ROTATE_Z]) { obj[manipulation].activeGroup = MANIPULATOR_GROUP_TYPES.ROTATE; } } } export default class VicowaWebGLManipulationExtension { static getAllManipulatorsAllowed() { return Object.keys(MANIPULATOR_TYPES).reduce((previous, option) => { previous[option] = true; return previous; }, {}); } constructor() { this[privateData] = { webgl: null, webglIF: null, manipulators: {}, activeManipulationObjects: {}, draggingManipulator: null, }; } attach(webGL, webglInterface) { const extensionData = this[privateData]; extensionData.webgl = webGL; extensionData.webglIF = webglInterface; extensionData.webgl.addMaterial('move-manipulator-unselected', { diffuse: { r: 0.6, g: 0.6, b: 1 } }); extensionData.webgl.addMaterial('move-manipulator-selected', { diffuse: { r: 0, g: 0, b: 1 } }); extensionData.webgl.addMaterial('scale-manipulator-unselected', { diffuse: { r: 0.6, g: 1, b: 1 } }); extensionData.webgl.addMaterial('scale-manipulator-selected', { diffuse: { r: 0, g: 1, b: 1 } }); extensionData.webgl.addMaterial('rotate-manipulator-unselected', { diffuse: { r: 1, g: 0.6, b: 1 } }); extensionData.webgl.addMaterial('rotate-manipulator-selected', { diffuse: { r: 1, g: 0, b: 1 } }); const getPlanePosition = () => ((extensionData.draggingManipulator && extensionData.draggingManipulator.manipulatorPlane) ? extensionData.webglIF.screenToObjectPoint(extensionData.webglIF.pointerPos, extensionData.draggingManipulator.manipulatorPlane) : null); extensionData.webglIF.addPointerClickListener((event) => { let hitObject = event.hitObject; while (hitObject && !MANIPULATOR_TYPES[hitObject.manipulatorType]) { hitObject = hitObject.parent; } if (hitObject && (!extensionData.draggingManipulator || !extensionData.draggingManipulator.hasMoved)) { let objectManipulator = hitObject; while (objectManipulator && !objectManipulator.manipulatedObject) { objectManipulator = objectManipulator.parent; } if (objectManipulator) { setNextGroup(this, objectManipulator.manipulatedObject); attachManipulators(this, objectManipulator.manipulatedObject); } } }); extensionData.webglIF.addPointerDownListener((event) => { let hitObject = event.hitObject; while (hitObject && !MANIPULATOR_TYPES[hitObject.manipulatorType]) { hitObject = hitObject.parent; } if (hitObject) { extensionData.draggingManipulator = { manipulatorType: hitObject.manipulatorType, activeManipulator: hitObject }; extensionData.draggingManipulator.hasMoved = false; let objectManipulator = hitObject; while (objectManipulator && !objectManipulator.manipulatedObject) { objectManipulator = objectManipulator.parent; } if (objectManipulator) { extensionData.draggingManipulator.activeManipulator.activeGroup = objectManipulator.manipulatedObject[manipulation].activeGroup; switch (hitObject.manipulatorType) { case MANIPULATOR_TYPES.MOVE_X: case MANIPULATOR_TYPES.SCALE_X: case MANIPULATOR_TYPES.ROTATE_Z: extensionData.draggingManipulator.manipulatorPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position: hitObject.center, collisions: true, visible: false, }); extensionData.draggingManipulator.manipulatorPlane.updateCoordinates(); extensionData.draggingManipulator.startPoint = getPlanePosition(); extensionData.draggingManipulator.startHandlerRotation = pointToAngle(vectorSubtract(extensionData.draggingManipulator.startPoint, objectManipulator.manipulatedObject.center)); break; case MANIPULATOR_TYPES.SCALE: extensionData.draggingManipulator.manipulatorPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position: hitObject.center, collisions: true, visible: false, }); extensionData.draggingManipulator.manipulatorPlane.applySettings({ rotation: { x: 0, y: 45, z: 0 } }); extensionData.draggingManipulator.manipulatorPlane.updateCoordinates(); extensionData.draggingManipulator.startPoint = getPlanePosition(); break; case MANIPULATOR_TYPES.MOVE_Y: case MANIPULATOR_TYPES.SCALE_Y: extensionData.draggingManipulator.manipulatorPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position: hitObject.center, collisions: true, visible: false, }); extensionData.draggingManipulator.manipulatorPlane.updateCoordinates(); extensionData.draggingManipulator.startPoint = getPlanePosition(); break; case MANIPULATOR_TYPES.ROTATE_X: extensionData.draggingManipulator.manipulatorPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position: hitObject.center, collisions: true, visible: false, rotation: { x: 0, y: 90, z: 0 }, }); extensionData.draggingManipulator.manipulatorPlane.updateCoordinates(); extensionData.draggingManipulator.startPoint = getPlanePosition(); extensionData.draggingManipulator.startHandlerRotation = pointToAngle(vectorSubtract({ x: extensionData.draggingManipulator.startPoint.z, y: extensionData.draggingManipulator.startPoint.y }, { x: objectManipulator.manipulatedObject.center.z, y: objectManipulator.manipulatedObject.center.y })); break; case MANIPULATOR_TYPES.MOVE_Z: case MANIPULATOR_TYPES.SCALE_Z: case MANIPULATOR_TYPES.ROTATE_Y: extensionData.draggingManipulator.manipulatorPlane = extensionData.webglIF.createPlane({ width: 10000 / extensionData.webgl.unitMultiplier, height: 10000 / extensionData.webgl.unitMultiplier, position: hitObject.center, collisions: true, visible: false, rotation: { x: 90, y: 0, z: 0 }, }); extensionData.draggingManipulator.manipulatorPlane.updateCoordinates(); extensionData.draggingManipulator.startPoint = getPlanePosition(); extensionData.draggingManipulator.startHandlerRotation = pointToAngle(vectorSubtract({ x: extensionData.draggingManipulator.startPoint.x, y: extensionData.draggingManipulator.startPoint.z }, { x: objectManipulator.manipulatedObject.center.x, y: objectManipulator.manipulatedObject.center.z })); break; case MANIPULATOR_TYPES.MOVE_PLANE: extensionData.draggingManipulator.manipulatorPlane = hitObject.manipulatorPlane; extensionData.draggingManipulator.startPoint = getPlanePosition(); break; } extensionData.draggingManipulator.startPosition = extensionData.draggingManipulator.activeManipulator.position; extensionData.draggingManipulator.startScale = objectManipulator.manipulatedObject.scale; extensionData.draggingManipulator.startRotation = objectManipulator.manipulatedObject.rotation; if (extensionData.draggingManipulator.startPoint) { extensionData.draggingManipulator.manipulatorsObject = objectManipulator; extensionData.draggingManipulator.activeManipulator.getChildren()[0].applySettings({ material: (extensionData.draggingManipulator.activeManipulator.activeGroup === MANIPULATOR_GROUP_TYPES.SCALE) ? 'scale-manipulator-selected' : (extensionData.draggingManipulator.activeManipulator.activeGroup === MANIPULATOR_GROUP_TYPES.ROTATE) ? 'rotate-manipulator-selected' : 'move-manipulator-selected' }); extensionData.webglIF.detachCameraControl(); } else { if (extensionData.draggingManipulator.manipulatorType !== MANIPULATOR_TYPES.MOVE_PLANE) { extensionData.draggingManipulator.manipulatorPlane.remove(); } extensionData.draggingManipulator = null; } } else { extensionData.draggingManipulator.manipulatorPlane.remove(); extensionData.draggingManipulator = null; } } }); extensionData.webglIF.addPointerUpListener(() => { if (extensionData.draggingManipulator) { if (extensionData.draggingManipulator.manipulatorType !== MANIPULATOR_TYPES.MOVE_PLANE) { extensionData.draggingManipulator.manipulatorPlane.remove(); } if (!extensionData.draggingManipulator.activeManipulator.isRemoved()) { extensionData.draggingManipulator.activeManipulator.getChildren()[0].applySettings({ material: (extensionData.draggingManipulator.activeManipulator.activeGroup === MANIPULATOR_GROUP_TYPES.SCALE) ? 'scale-manipulator-unselected' : (extensionData.draggingManipulator.activeManipulator.activeGroup === MANIPULATOR_GROUP_TYPES.ROTATE) ? 'rotate-manipulator-unselected' : 'move-manipulator-unselected' }); } } extensionData.draggingManipulator = null; extensionData.webglIF.attachCameraControl(); }); extensionData.webglIF.addPointerMoveListener(() => { if (extensionData.draggingManipulator && extensionData.draggingManipulator.startPoint) { const currentPoint = getPlanePosition(); if (currentPoint) { extensionData.draggingManipulator.hasMoved = true; const targetObjectCenter = extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center; const diff = { x: Math.round((currentPoint.x - extensionData.draggingManipulator.startPoint.x) * 1000) / 1000, y: Math.round((currentPoint.y - extensionData.draggingManipulator.startPoint.y) * 1000) / 1000, z: Math.round((currentPoint.z - extensionData.draggingManipulator.startPoint.z) * 1000) / 1000 }; switch (extensionData.draggingManipulator.manipulatorType) { case MANIPULATOR_TYPES.MOVE_X: diff.y = 0; diff.z = 0; extensionData.draggingManipulator.manipulatorsObject.offset(diff); extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.offset(diff); extensionData.draggingManipulator.startPoint = currentPoint; break; case MANIPULATOR_TYPES.MOVE_Y: diff.x = 0; diff.z = 0; extensionData.draggingManipulator.manipulatorsObject.offset(diff); extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.offset(diff); extensionData.draggingManipulator.startPoint = currentPoint; break; case MANIPULATOR_TYPES.MOVE_Z: diff.x = 0; diff.y = 0; extensionData.draggingManipulator.manipulatorsObject.offset(diff); extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.offset(diff); extensionData.draggingManipulator.startPoint = currentPoint; break; case MANIPULATOR_TYPES.MOVE_PLANE: extensionData.draggingManipulator.manipulatorsObject.offset(diff); extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.offset(diff); extensionData.draggingManipulator.startPoint = currentPoint; break; case MANIPULATOR_TYPES.SCALE: { const oldRelativePoint = { x: extensionData.draggingManipulator.startPoint.x - targetObjectCenter.x, y: extensionData.draggingManipulator.startPoint.y - targetObjectCenter.y, z: extensionData.draggingManipulator.startPoint.z - targetObjectCenter.z }; const oldDistance = Math.sqrt((oldRelativePoint.x * oldRelativePoint.x) + (oldRelativePoint.y * oldRelativePoint.y) + (oldRelativePoint.z * oldRelativePoint.z)); const newRelativePoint = { x: currentPoint.x - targetObjectCenter.x, y: currentPoint.y - targetObjectCenter.y, z: currentPoint.z - targetObjectCenter.z }; const newDistance = Math.sqrt((newRelativePoint.x * newRelativePoint.x) + (newRelativePoint.y * newRelativePoint.y) + (newRelativePoint.z * newRelativePoint.z)); extensionData.draggingManipulator.activeManipulator.position = { x: extensionData.draggingManipulator.startPosition.x + currentPoint.x - extensionData.draggingManipulator.startPoint.x, y: extensionData.draggingManipulator.startPosition.y + currentPoint.y - extensionData.draggingManipulator.startPoint.y, z: extensionData.draggingManipulator.startPosition.z + currentPoint.z - extensionData.draggingManipulator.startPoint.z }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.scale = { x: extensionData.draggingManipulator.startScale.x * newDistance / oldDistance, y: extensionData.draggingManipulator.startScale.y * newDistance / oldDistance, z: extensionData.draggingManipulator.startScale.z * newDistance / oldDistance, }; } break; case MANIPULATOR_TYPES.SCALE_X: { const oldDistance = extensionData.draggingManipulator.startPoint.x - targetObjectCenter.x; const newDistance = currentPoint.x - targetObjectCenter.x; extensionData.draggingManipulator.activeManipulator.position = { x: extensionData.draggingManipulator.startPosition.x + currentPoint.x - extensionData.draggingManipulator.startPoint.x }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.scale = { x: extensionData.draggingManipulator.startScale.x * newDistance / oldDistance }; } break; case MANIPULATOR_TYPES.SCALE_Y: { const oldDistance = extensionData.draggingManipulator.startPoint.y - targetObjectCenter.y; const newDistance = currentPoint.y - targetObjectCenter.y; extensionData.draggingManipulator.activeManipulator.position = { y: extensionData.draggingManipulator.startPosition.y + currentPoint.y - extensionData.draggingManipulator.startPoint.y }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.scale = { y: extensionData.draggingManipulator.startScale.y * newDistance / oldDistance }; } break; case MANIPULATOR_TYPES.SCALE_Z: { const oldDistance = extensionData.draggingManipulator.startPoint.z - targetObjectCenter.z; const newDistance = currentPoint.z - targetObjectCenter.z; extensionData.draggingManipulator.activeManipulator.position = { z: extensionData.draggingManipulator.startPosition.z + currentPoint.z - extensionData.draggingManipulator.startPoint.z }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.scale = { z: extensionData.draggingManipulator.startScale.z * newDistance / oldDistance }; } break; case MANIPULATOR_TYPES.ROTATE_X: { const relevantCenter = { x: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.z, y: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.y }; const relevantStart = { x: extensionData.draggingManipulator.startPoint.z, y: extensionData.draggingManipulator.startPoint.y }; const newHandlerRotation = pointToAngle(vectorSubtract({ x: currentPoint.z, y: currentPoint.y }, relevantCenter)); const newPos = angleToPoint(newHandlerRotation, vectorLength(vectorSubtract(relevantStart, relevantCenter))); const manipulatePos = vectorAdd({ x: newPos.x, y: newPos.y }, relevantCenter); extensionData.draggingManipulator.activeManipulator.position = { z: manipulatePos.x, y: manipulatePos.y }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.rotation = { x: extensionData.draggingManipulator.startRotation.x - (newHandlerRotation - extensionData.draggingManipulator.startHandlerRotation) }; } break; case MANIPULATOR_TYPES.ROTATE_Y: { const relevantCenter = { x: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.x, y: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.z }; const relevantStart = { x: extensionData.draggingManipulator.startPoint.x, y: extensionData.draggingManipulator.startPoint.z }; const newHandlerRotation = pointToAngle(vectorSubtract({ x: currentPoint.x, y: currentPoint.z }, relevantCenter)); const newPos = angleToPoint(newHandlerRotation, vectorLength(vectorSubtract(relevantStart, relevantCenter))); const manipulatePos = vectorAdd({ x: newPos.x, y: newPos.y }, relevantCenter); extensionData.draggingManipulator.activeManipulator.position = { x: manipulatePos.x, z: manipulatePos.y }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.rotation = { y: extensionData.draggingManipulator.startRotation.y - (newHandlerRotation - extensionData.draggingManipulator.startHandlerRotation) }; } break; case MANIPULATOR_TYPES.ROTATE_Z: { const relevantCenter = { x: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.x, y: extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.center.y }; const relevantStart = { x: extensionData.draggingManipulator.startPoint.x, y: extensionData.draggingManipulator.startPoint.y }; const newHandlerRotation = pointToAngle(vectorSubtract(currentPoint, relevantCenter)); const newPos = angleToPoint(newHandlerRotation, vectorLength(vectorSubtract(relevantStart, relevantCenter))); const manipulatePos = vectorAdd({ x: newPos.x, y: newPos.y }, relevantCenter); extensionData.draggingManipulator.activeManipulator.position = { x: manipulatePos.x, y: manipulatePos.y }; extensionData.draggingManipulator.manipulatorsObject.manipulatedObject.rotation = { z: extensionData.draggingManipulator.startRotation.z + (newHandlerRotation - extensionData.draggingManipulator.startHandlerRotation) }; } break; } } } }); createManipulatorTemplates(this); } setAllowedManipulators(obj, settings) { const extensionData = this[privateData]; const targetObject = extensionData.webglIF.getObject(obj); targetObject[manipulation] = targetObject[manipulation] || { allowed: {}, manipulatorPlane: null }; Object.keys(settings).forEach((key) => { if (MANIPULATOR_TYPES[key]) { targetObject[manipulation].allowed[key] = settings[key]; if (key === MANIPULATOR_TYPES.MOVE_PLANE) { targetObject[manipulation].manipulatorPlane = settings.movePlane; } } }); } removeManipulators(obj) { const extensionData = this[privateData]; const targetObject = extensionData.webglIF.getObject(obj); const manipulatorName = `manipulator-for-${targetObject.name}`; if (extensionData.activeManipulationObjects[manipulatorName]) { extensionData.activeManipulationObjects[manipulatorName].remove(); delete extensionData.activeManipulationObjects[manipulatorName]; } } attachManipulators(obj, clickPoint) { const extensionData = this[privateData]; const targetObject = extensionData.webglIF.getObject(obj); if (targetObject && targetObject[manipulation]) { if (!targetObject[manipulation].activeGroup) { setNextGroup(this, targetObject); } attachManipulators(this, targetObject, clickPoint); } } }