From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/tools/Rotate3DToolBase.js | 637 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 js/tools/Rotate3DToolBase.js (limited to 'js/tools/Rotate3DToolBase.js') diff --git a/js/tools/Rotate3DToolBase.js b/js/tools/Rotate3DToolBase.js new file mode 100644 index 00000000..6e17864b --- /dev/null +++ b/js/tools/Rotate3DToolBase.js @@ -0,0 +1,637 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +/* Base class for the 3D rotation tools +Subclass RotateObject3DTool will rotate the object that was clicked. +Subclass RotateStage3DTool will rotate the stage. + */ +var Montage = require("montage/core/core").Montage, + ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase, + snapManager = require("js/helper-classes/3D/snap-manager").SnapManager, + viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils, + vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils, + drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils, + ElementsMediator = require("js/mediators/element-mediator").ElementMediator; + +exports.Rotate3DToolBase = Montage.create(ModifierToolBase, { + _canSnap: { value: false }, + + _inLocalMode: { value: true, enumerable: true }, + + drawWithoutSnapping: + { + value: function(event) + { + if(this._handleMode !== null) + { + this._matL = this._handles[this._handleMode]._matL.slice(0); + this._planeEq = this._handles[this._handleMode]._planeEq.slice(0); + this._dirVecL = this._handles[this._handleMode]._dirVecL.slice(0); + this._startPoint = MathUtils.getLocalPoint(this.downPoint.x, + this.downPoint.y, + this._planeEq, + this._matL); + if(!this._startPoint) + { + this._startPoint = [this.downPoint.x, this.downPoint.y]; + } + } + } + }, + + modifyElements: { + value: function(data, event) { + var mat, + angle, + pt0 = data.pt0, + pt1 = data.pt1; + + if(this._handleMode !== null) + { + if(this._activateOriginHandle) + { + // move the transform origin handle + var dx = pt1.x - pt0.x; + var dy = pt1.y - pt0.y; + this._origin[0] += dx; + this._origin[1] += dy; + + var len = this._targets.length; + if(len === 1) + { + this._startOriginArray[0][0] += dx; + this._startOriginArray[0][1] += dy; + } + this.downPoint.x = pt1.x; + this.downPoint.y = pt1.y; + this.DrawHandles(); + return; + } + + angle = this._getAngleToRotate(pt1.x, pt1.y); + if(event.shiftKey) + { + var f = Math.floor(angle/(Math.PI/4)); + angle = f*Math.PI/4; + } + this._delta = angle; + switch(this._handleMode) + { + case 0: + // Rotate X; + mat = Matrix.RotationX(angle); + break; + case 1: + // Rotate Y + mat = Matrix.RotationY(angle); + break; + case 2: + // Rotate Z + mat = Matrix.RotationZ(angle); + break; + default: + break; + } + } + else + { + if (event.ctrlKey || event.metaKey) + { + var zAngle = this._mouseSpeed * (pt1.y - this.downPoint.y) * Math.PI / 180.0; + if (zAngle === 0) + { + zAngle = 0.01 * Math.PI / 180.0; + } + if(event.shiftKey) + { + var f = Math.floor(zAngle/(Math.PI/4)); + zAngle = f*Math.PI/4; + } + mat = Matrix.RotationZ(zAngle); + } + else + { + var yAngle = this._mouseSpeed * (pt1.x - this.downPoint.x) * Math.PI / 180.0; + var xAngle = -this._mouseSpeed * (pt1.y - this.downPoint.y) * Math.PI / 180.0; + if(event.shiftKey) + { + var f = Math.floor(yAngle/(Math.PI/4)); + yAngle = f*Math.PI/4; + f = Math.floor(xAngle/(Math.PI/4)); + xAngle = f*Math.PI/4; + } + + // check the orientation of the X axis + //if (drawUtils.drawYZ) xAngle = -xAngle; + var yMat = Matrix.RotationY( yAngle ), + xMat = Matrix.RotationX( xAngle ); + + mat = glmat4.multiply(yMat, xMat, []); + } + } + + if(this._inLocalMode && (this._targets.length === 1) ) + { + this._rotateLocally(mat); + } + else + { + this._rotateGlobally(mat); + } + +// this.UpdateSelection(); + NJevent("elementChanging", {type : "Changing", redraw: false}); + } + }, + + _rotateLocally: { + value: function (rotMat) { + var len = this._targets.length; + for(var i = 0; i < len; i++) + { + var item = this._targets[i]; + var elt = item.elt; + var curMat = item.mat; + + // pre-translate by the transformation center + var tMat = Matrix.I(4); + + var transformCtr = this._startOriginArray[i]; + + tMat[12] = transformCtr[0]; + tMat[13] = transformCtr[1]; + tMat[14] = transformCtr[2]; + + var mat = glmat4.multiply(curMat, tMat, []); + + // translate back + tMat[12] = -transformCtr[0]; + tMat[13] = -transformCtr[1]; + tMat[14] = -transformCtr[2]; + + glmat4.multiply(mat, rotMat, mat); + + + glmat4.multiply(mat, tMat, mat); + + // while moving, set inline style to improve performance + viewUtils.setMatrixForElement( elt, mat, true ); + } + } + }, + + _rotateGlobally: { + value: function (rotMat) { + var len = this._targets.length; + for(var i = 0; i < len; i++) + { + var item = this._targets[i]; + var elt = item.elt; + var curMat = item.mat; + + // pre-translate by the transformation center + var tMat = Matrix.I(4); + + var transformCtr = this._startOriginArray[i].slice(0); + transformCtr = MathUtils.transformPoint(transformCtr, curMat); + + tMat[12] = transformCtr[0]; + tMat[13] = transformCtr[1]; + tMat[14] = transformCtr[2]; + + var mat = glmat4.multiply(tMat, rotMat, []); + + // translate back + tMat[12] = -transformCtr[0]; + tMat[13] = -transformCtr[1]; + tMat[14] = -transformCtr[2]; + + glmat4.multiply(mat, tMat, mat); + + glmat4.multiply(mat, curMat, mat); + + viewUtils.setMatrixForElement( elt, mat, true ); + } + } + }, + + _getAngleToRotate: { + value: function (x, y) { + var angle; + var pt = MathUtils.getLocalPoint(x, y, this._planeEq, this._matL); + if(!pt) + { + //TODO - should this be _startPoint.x/y instead of downPoint.x/y? + var st = [this.downPoint.x, this.downPoint.y]; + pt = [x, y]; + var sub = vecUtils.vecSubtract(2, pt, st); + var dot = vecUtils.vecDot(2, sub, this._dirVecL); + + angle = vecUtils.vecDist(2, pt, st) * 0.1; + + if (dot < 0) + { + angle = -angle; + } + } + else + { + angle = MathUtils.getAngleBetweenPoints(this._startPoint, pt); + } + return angle; + } + }, + + captureSelectionChange: { + value: function(event){ + this.eventManager.addEventListener("selectionDrawn", this, true); + } + }, + + captureSelectionDrawn: { + value: function(event){ + this._origin = null; + this._targets = null; + this._startOriginArray = null; + + var len = this.application.ninja.selectedElements.length; + if(len) + { + if(len === 1) + { + this.target = this.application.ninja.selectedElements[0]._element; + drawUtils.addElement(this.target); + + viewUtils.pushViewportObj( this.target ); + var eltCtr = viewUtils.getCenterOfProjection(); + viewUtils.popViewportObj(); + + var ctrOffset = this.target.elementModel.props3D.m_transformCtr; + if(ctrOffset) + { + eltCtr[2] = 0; + eltCtr = vecUtils.vecAdd(3, eltCtr, ctrOffset); + } + + this._origin = viewUtils.localToGlobal(eltCtr, this.target); + this._updateTargets(); + this._setTransformOrigin(false); + } + else + { + this.target = this.application.ninja.currentDocument.documentRoot; + this._origin = drawUtils._selectionCtr.slice(0); + this._origin[0] += this.application.ninja.stage.userContentLeft; + this._origin[1] += this.application.ninja.stage.userContentTop; + this._updateTargets(); + this._setTransformOrigin(true); + } + } + else + { + this.target = null; + } + this.DrawHandles(); + + if(event) + { + this.eventManager.removeEventListener("selectionDrawn", this, true); + } + } + }, + + _updateTargets: { + value: function(addToUndoStack) { + var newStyles = [], + previousStyles = [], + len = this.application.ninja.selectedElements.length; + this._targets = []; + for(var i = 0; i < len; i++) + { + var elt = this.application.ninja.selectedElements[i]._element; +// this._initProps3D(elt); + + + var curMat = viewUtils.getMatrixFromElement(elt); + var curMatInv = glmat4.inverse(curMat, []); + + viewUtils.pushViewportObj( elt ); + var eltCtr = viewUtils.getCenterOfProjection(); + viewUtils.popViewportObj(); + + eltCtr = viewUtils.localToGlobal(eltCtr, elt); + + this._targets.push({elt:elt, mat:curMat, matInv:curMatInv, ctr:eltCtr}); + if(addToUndoStack) + { + var previousStyleStr = {dist:this._undoArray[i].dist, mat:MathUtils.scientificToDecimal(this._undoArray[i].mat.slice(0), 5)}; + + var newStyleStr = {dist:viewUtils.getPerspectiveDistFromElement(elt), mat:MathUtils.scientificToDecimal(curMat, 5)}; + + previousStyles.push(previousStyleStr); + newStyles.push(newStyleStr); + } + } + if(addToUndoStack) + { + ElementsMediator.set3DProperties(this.application.ninja.selectedElements, + newStyles, + "Change", + "rotateTool", + previousStyles + ); + } + // Save previous value for undo/redo + this._undoArray = []; + for(i = 0, len = this._targets.length; i < len; i++) + { + var elt = this._targets[i].elt; + var _mat = viewUtils.getMatrixFromElement(elt); + var _dist = viewUtils.getPerspectiveDistFromElement(elt); + this._undoArray.push({mat:_mat, dist:_dist}); + } + } + }, + + _setTransformOrigin: { + value: function(shouldUpdateCenter) { + if(!this._origin) + { + return; + } + var len = this._targets.length; + var elt, + eltCtr, + ctrOffset, + matInv; + if( len === 1) + { + elt = this._target; + + if(shouldUpdateCenter) + { + eltCtr = this._targets[0].ctr; + ctrOffset = vecUtils.vecSubtract(3, this._origin, eltCtr); + + matInv = this._targets[0].matInv; + ctrOffset = MathUtils.transformVector(ctrOffset, matInv); + + elt.elementModel.props3D.m_transformCtr = ctrOffset; + } + else + { + this._startOriginArray = []; + var ctrOffset = this._target.elementModel.props3D.m_transformCtr; + if(!ctrOffset) + { + ctrOffset = [0,0,0]; + } + } + this._startOriginArray[0] = ctrOffset; + } + else + { + // Update transform ctr for all elements if transform origin was modified + this._startOriginArray = []; + for (var i = 0; i < len; i++) { + elt = this._targets[i].elt; + eltCtr = this._targets[i].ctr; + ctrOffset = vecUtils.vecSubtract(3, this._origin, eltCtr); + matInv = this._targets[i].matInv; + ctrOffset = MathUtils.transformVector(ctrOffset, matInv); + + this._startOriginArray[i] = ctrOffset; + } + } + } + }, + + HandleDoubleClick: { + value: function () { + + if(!this._target) + { + return; + } + + if(this._activateOriginHandle) + { + var len = this.application.ninja.selectedElements.length; + if( (len === 1) || (this._toolID === "rotateStage3DTool") ) + { + this._target.elementModel.props3D.m_transformCtr = null; + } + + this._handleMode = null; + this._activateOriginHandle = false; + this.application.ninja.stage.drawingCanvas.style.cursor = this._cursor; + + this.captureSelectionDrawn(null); + } + } + }, + + Reset : { + value : function() + { + var item, + elt, + mat, + dist, + newStyles = [], + previousStyles = [], + len = this._targets.length, + iMat; + for(var i = 0; i < len; i++) + { + // Reset to the identity matrix but retain the rotation values + item = this._targets[i]; + elt = item.elt; + + // Reset to the identity matrix but retain the translation values + iMat = Matrix.I(4); + mat = item.mat; + iMat[12] = mat[12]; + iMat[13] = mat[13]; + iMat[14] = mat[14]; + + dist = this._undoArray[i].dist; + + var previousStyleStr = {dist:dist, mat:mat}; + + var newStyleStr = {dist:dist, mat:iMat}; + + previousStyles.push(previousStyleStr); + newStyles.push(newStyleStr); + + } + + ElementsMediator.set3DProperties(this.application.ninja.selectedElements, + newStyles, + "Change", + "rotateTool", + previousStyles + ); + + this.isDrawing = false; + this.endDraw(event); + +// this.UpdateSelection(true); + this.Configure(true); + } + }, + + /** + * SHIFT/ALT/SPACE Key Handlers + */ + HandleShiftKeyDown: { + value: function (event) { + } + }, + + HandleShiftKeyUp: { + value: function () { + } + }, + + HandleSpaceKeyDown: { + value: function () { + } + }, + + HandleSpaceUp: { + value: function () { + } + }, + + HandleAltKeyDown: { + value: function(event) { + this._inLocalMode = !this._inLocalMode; + this.DrawHandles(); + } + }, + + HandleAltKeyUp: { + value: function(event) { + this._inLocalMode = !this._inLocalMode; + this.DrawHandles(); + } + }, + + handleScroll: { + value: function(event) { + this.captureSelectionDrawn(null); + } + }, + + /** + * This function is for specifying custom feedback routine + * upon mouse over. + * For example, the drawing tools will add a glow when mousing + * over existing canvas elements to signal to the user that + * the drawing operation will act on the targeted canvas. + */ + _showFeedbackOnMouseMove : { + value: function (event) { + if(this._target && this._handles) + { + var len = this._handles.length; + var i = 0, + toolHandle, + c, + point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, + new WebKitPoint(event.pageX, event.pageY)); + for (i=0; i