/* <copyright> This file contains proprietary software owned by Motorola Mobility, Inc.<br/> No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. </copyright> */ /* Base class for the 3D translate tools Subclass TranslateObject3DTool will translate the object that was clicked. */ var Montage = require("montage/core/core").Montage, ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase, toolHandleModule = require("js/stage/tool-handle"), 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.Translate3DToolBase = Montage.create(ModifierToolBase, { _inLocalMode: { value: true, enumerable: true }, _clickedOnStage: { value: false }, HandleDoubleClick : { value : function() { } }, modifyElements : { value : function(data, event) { //console.log( "modifyElements, data: " + data.pt0 + " => " + data.pt1 ); // form the translation vector and post translate the matrix by it. var delta = vecUtils.vecSubtract( 3, data.pt1, data.pt0 ); if(this._handleMode !== null) { switch(this._handleMode) { case 0: delta[1] = 0; delta[2] = 0; break; case 1: delta[0] = 0; delta[2] = 0; break; case 2: delta[0] = 0; delta[1] = 0; break; } if( (this.application.ninja.selectedElements.length > 1) && this._clickedOnStage ) { this._delta = ~~(delta[this._handleMode]); } else { this._delta += ~~(delta[this._handleMode]); } } else { if(this._mode === 1) { delta[2] = delta[1]; delta[0] = 0; delta[1] = 0; } this._delta = delta.slice(0); } //console.log( "modifyElements delta: " + delta ); var transMat = Matrix.Translation( delta ); //console.log( "Translate: " + delta ); if(this._inLocalMode && (this.application.ninja.selectedElements.length === 1) ) { this._translateLocally(transMat); } else { this._translateGlobally(transMat); } } }, Reset: { value: function() { var mat, iMat, dist, mod3dObject = [], self = this; this.application.ninja.selectedElements.forEach(function(element) { // Reset to the identity matrix //item = this.application.ninja.selectedElements[i]; iMat = Matrix.I(4); mat = ElementsMediator.getMatrix(element); mat[12] = 0; mat[13] = 0; mat[14] = 0; dist = ElementsMediator.getPerspectiveDist(element); var previousStyleStr = {dist:dist, mat:element.elementModel.getProperty("mat")}; var newStyleStr = {dist:dist, mat:iMat}; mod3dObject.push({element:element, properties:newStyleStr, previousProperties: previousStyleStr}); }); ElementsMediator.set3DProperties(mod3dObject, "Change", "rotateTool"); this.isDrawing = false; this.endDraw(event); // Need to force stage to draw immediately so the new selection center is calculated this.application.ninja.stage.draw(); // And captureSelectionDrawn to draw the transform handles this.captureSelectionDrawn(null); } }, // We will only translate single elements locally _translateLocally: { value: function (transMat) { //console.log( "_translateLocally, startMat: " + this._startMat ); //console.log( "_translateLocally, transMat: " + transMat ); //console.log( "_translateLocally, startMat: " + this._startMat + ", transMat: " + transMat ); var mat = glmat4.multiply(this._startMat, transMat, []); viewUtils.setMatrixForElement( this._target, mat, true ); if(this._mode !== 1) { this._startMat = mat; } } }, _translateGlobally: { value: function (transMat) { //console.log( "_translateGlobally, transMat: " + transMat ); var selectedElements = this.application.ninja.selectedElements; var len = selectedElements.length, self = this, target = selectedElements[0], curMat = viewUtils.getMatrixFromElement( target ), matInv = glmat4.inverse(this._startMat, []), nMat = glmat4.multiply(transMat, this._startMat, [] ); // qMat = glmat4.multiply(matInv, nMat, []); if(this._mode === 1) { if (len > 1) curMat = target.elementModel.getProperty("mat").slice(); var curInv = glmat4.inverse( curMat, [] ); transMat = glmat4.multiply( nMat, curInv, [] ); } var shouldUpdateStartMat = true; if(this._clickedOnStage || ((this._handleMode === 2) && (len > 1))) { shouldUpdateStartMat = false; } else if(this._mode !== 1) { this._startMat = nMat; } selectedElements.forEach(function(element) { curMat = element.elementModel.getProperty("mat").slice(0); // glmat4.multiply(curMat, qMat, curMat); // viewUtils.setMatrixForElement( elt, curMat, true); curMat[12] += transMat[12]; curMat[13] += transMat[13]; curMat[14] += transMat[14]; viewUtils.setMatrixForElement(element, curMat, true); if(shouldUpdateStartMat) { //console.log( "\t\tshouldUpdateStartMat" ); element.elementModel.setProperty("mat", curMat); } }); } }, _updateTargets: { value: function(addToUndo) { var mod3dObject = [], self = this; this.application.ninja.selectedElements.forEach(function(element) { if(addToUndo) { var previousMat = element.elementModel.getProperty("mat").slice(0); var previousStyleStr = {dist:element.elementModel.getProperty("dist"), mat:MathUtils.scientificToDecimal(previousMat, 5)}; var newStyleStr = {dist:viewUtils.getPerspectiveDistFromElement(element), mat:MathUtils.scientificToDecimal(viewUtils.getMatrixFromElement(element), 5)}; mod3dObject.push({element:element, properties:newStyleStr, previousProperties: previousStyleStr}); } }); if(addToUndo) { ElementsMediator.set3DProperties(mod3dObject, "Change", "translateTool"); if(this._origin && this._delta) { if(this._handleMode !== null) { this._origin[this._handleMode] += this._delta; } else { this._origin[0] += this._delta[0]; this._origin[1] += this._delta[1]; } } this._delta = null; } this.application.ninja.selectedElements.forEach(function(element) { element.elementModel.setProperty("mat", viewUtils.getMatrixFromElement(element)); element.elementModel.setProperty("dist", viewUtils.getPerspectiveDistFromElement(element)); }); } }, 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); } }, _updateHandlesOrigin: { value: function () { var ctr; var len = this.application.ninja.selectedElements.length; if(len > 0) { if(len === 1) { var item = this._target; viewUtils.pushViewportObj( item ); ctr = viewUtils.getCenterOfProjection(); viewUtils.popViewportObj(); ctr[2] = 0; this._origin = viewUtils.localToGlobal(ctr, item); } else { this._origin = undefined; this._origin = this.calculateMultiSelOrigin(); } } } }, captureSelectionDrawn: { value: function(event){ this._origin = null; this._startOriginArray = null; var len = this.application.ninja.selectedElements.length; if(len) { if(len === 1) { this.target = this.application.ninja.selectedElements[0]; drawUtils.addElement(this.target); viewUtils.pushViewportObj( this.target ); var eltCtr = viewUtils.getCenterOfProjection(); eltCtr[2] = 0; 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); // console.log( "Rotate3DToolBase.captureSelectionDrawn _origin: " + this._origin ); 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._origin = this.calculateMultiSelOrigin(); //this._setTransformOrigin(true); } } else { this.target = null; } this.DrawHandles(); if(event) { this.eventManager.removeEventListener("selectionDrawn", this, true); } } }, calculateMultiSelOrigin: { value: function() { var minPt, maxPt, i,j; this._startOriginArray = []; var len = this.application.ninja.selectedElements.length; for (i = 0; i < len; i++) { // get the next element and localToGlobal matrix var elt = this.application.ninja.selectedElements[i]; var l2g = elt.elementModel.getProperty("l2g"); // get the element bounds in 'plane' space var bounds = viewUtils.getElementViewBounds3D( elt ); for (j=0; j<4; j++) { var localPt = bounds[j]; //var pt = MathUtils.transformAndDivideHomogeneousPoint( localPt, l2g ); var pt = viewUtils.localToStageWorld( localPt, elt ); if (!minPt) { minPt = pt.slice(); maxPt = pt.slice(); } else { minPt[0] = Math.min(minPt[0],pt[0]); minPt[1] = Math.min(minPt[1],pt[1]); minPt[2] = Math.min(minPt[2],pt[2]); maxPt[0] = Math.max(maxPt[0],pt[0]); maxPt[1] = Math.max(maxPt[1],pt[1]); maxPt[2] = Math.max(maxPt[2],pt[2]); } } } var stageWorldCtr = [ 0.5*(minPt[0] + maxPt[0]), 0.5*(minPt[1] + maxPt[1]), 0.5*(minPt[2] + maxPt[2]) ]; var globalCtr = MathUtils.transformAndDivideHomogeneousPoint( stageWorldCtr, viewUtils.getStageWorldToGlobalMatrix() ); // console.log( "resetting _origin to: " + this._origin ); return globalCtr; } }, DrawHandles: { value: function (delta) { this.application.ninja.stage.clearDrawingCanvas(); if(!this._handles) { this._handles = []; // TODO - Using dummy cursors for now // translateX var rX = toolHandleModule.TranslateHandle.create(); rX.init("url('images/cursors/Translate_X.png') 0 0, default", 'rgba(255,0,0,1)', "x"); this._handles.push(rX); // translateY var rY = toolHandleModule.TranslateHandle.create(); rY.init("url('images/cursors/Translate_Y.png') 0 0, default", 'rgba(0,255,0,1)', "y"); this._handles.push(rY); // translateZ var rZ = toolHandleModule.TranslateHandle.create(); rZ.init("url('images/cursors/Translate_Z.png') 0 0, default", 'rgba(0,0,255,1)', "z"); this._handles.push(rZ); } var item = this._target; if(!item) { return; } // Draw tool handles this._updateHandlesOrigin(); var base = this._origin.slice(0); // if (this.isDrawing) // console.log( "handle origin: " + base ); var len = this.application.ninja.selectedElements.length; var lMode = this._inLocalMode; if(len === 1) { viewUtils.pushViewportObj( item ); } else { lMode = false; viewUtils.pushViewportObj( this.application.ninja.currentDocument.documentRoot ); } if(this._handleMode !== null) { switch(this._handleMode) { case 0: this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 0.2)'; this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 0.2)'; break; case 1: this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 0.2)'; this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 0.2)'; break; case 2: this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 0.2)'; this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 0.2)'; break; } if( delta && (len > 1) ) { base[this._handleMode] += ~~delta; } } this._handles[0].draw(base, item, lMode); this._handles[1].draw(base, item, lMode); this._handles[2].draw(base, item, lMode); if(delta && (this._handleMode !== null)) { this._handles[this._handleMode].drawDelta(~~delta); } this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 1)'; this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 1)'; this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 1)'; viewUtils.popViewportObj(); } } });