diff options
Diffstat (limited to 'js/helper-classes/3D/snap-manager.js')
-rw-r--r-- | js/helper-classes/3D/snap-manager.js | 2247 |
1 files changed, 2247 insertions, 0 deletions
diff --git a/js/helper-classes/3D/snap-manager.js b/js/helper-classes/3D/snap-manager.js new file mode 100644 index 00000000..3ed96082 --- /dev/null +++ b/js/helper-classes/3D/snap-manager.js | |||
@@ -0,0 +1,2247 @@ | |||
1 | /* <copyright> | ||
2 | This file contains proprietary software owned by Motorola Mobility, Inc.<br/> | ||
3 | No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> | ||
4 | (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. | ||
5 | </copyright> */ | ||
6 | |||
7 | /////////////////////////////////////////////////////////////////////// | ||
8 | // Class SnapManager | ||
9 | // Class to do hit testing of objects in the html page | ||
10 | /////////////////////////////////////////////////////////////////////// | ||
11 | var Montage = require("montage/core/core").Montage, | ||
12 | Component = require("montage/ui/component").Component; | ||
13 | |||
14 | var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; | ||
15 | var vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils; | ||
16 | var drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils; | ||
17 | var HitRecord = require("js/helper-classes/3D/hit-record").HitRecord; | ||
18 | var Snap2DRecord = require("js/helper-classes/3D/snap-2d-record").Snap2DRecord; | ||
19 | var NJUtils = require("js/lib/NJUtils").NJUtils; | ||
20 | |||
21 | var SnapManager = exports.SnapManager = Montage.create(Component, { | ||
22 | /////////////////////////////////////////////////////////////////////// | ||
23 | // Instance variables | ||
24 | /////////////////////////////////////////////////////////////////////// | ||
25 | currentStage: { value: null, writable: true }, | ||
26 | drawingCanvas: { value: null, writable: true}, | ||
27 | |||
28 | // we keep a stack of working planes to facilitate working on other planes temporarily | ||
29 | _workingPlaneStack : { value: [], writable: true }, | ||
30 | |||
31 | // snapping radii relative to a 25 pixel grid | ||
32 | GRID_VERTEX_HIT_RAD : { value: 10, writable: true }, | ||
33 | GRID_EDGE_HIT_RAD : { value: 6, writable: true}, | ||
34 | |||
35 | // these are the grid snapping tolerances scaled to the current grid spacing | ||
36 | _gridVertexHitRad : { value: this.GRID_VERTEX_HIT_RAD, writable: true }, | ||
37 | _gridEdgeHitRad : { value: this.GRID_EDGE_HIT_RAD, writable: true }, | ||
38 | |||
39 | ELEMENT_VERTEX_HIT_RAD : { value: 18, writable: true }, | ||
40 | ELEMENT_EDGE_HIT_RAD : { value: 14, writable: true }, | ||
41 | |||
42 | // keep a reference to the most recent hitRecord. Used for drawing feedback on the stage | ||
43 | _lastHit : { value: null, writable: true }, | ||
44 | |||
45 | // keep a list of objects to avoid snapping to | ||
46 | _avoidList : { value: [], writable: true }, | ||
47 | |||
48 | // keep a cache of 2D elements to snap to | ||
49 | _elementCache : { value: null, writable: true }, | ||
50 | _isCacheInvalid : { value: false, writable: true }, | ||
51 | |||
52 | // the snap manager can handle a 2D plane for dragging. | ||
53 | // A call to initDragPlane sets these variables. | ||
54 | // a call to clearDragPlane MUST be called on the completion of a drag | ||
55 | _hasDragPlane : {value: false, writable: true }, | ||
56 | _dragPlane : { value: null, writable: true }, | ||
57 | _dragPlaneToWorld : { value: Matrix.I(4), writable: true }, | ||
58 | _worldToDragPlane : { value: Matrix.I(4), writable: true }, | ||
59 | _dragPlaneActive : {value: false, writable: true }, | ||
60 | |||
61 | // cache the matrix linking stage world and global spaces | ||
62 | _stageWorldToGlobalMat : { value: Matrix.I(4), writable: true }, | ||
63 | _globalToStageWorldMat : { value: Matrix.I(4), writable: true }, | ||
64 | |||
65 | // various flags to enable snapping | ||
66 | _snapAlignEnabled : {value: true, writable: true }, | ||
67 | _elementSnapEnabled : {value: true, writable: true }, | ||
68 | _gridSnapEnabled : {value: true, writable: true }, | ||
69 | |||
70 | // these represent the app level snap settings as set by the end user through | ||
71 | // the menus. These should be stored somewhere else and serialized. Putting them here for now... | ||
72 | _snapAlignEnabledAppLevel : {value: true, writable: true }, | ||
73 | _elementSnapEnabledAppLevel : {value: true, writable: true }, | ||
74 | _gridSnapEnabledAppLevel : {value: true, writable: true }, | ||
75 | |||
76 | // App Model pointer | ||
77 | appModel: { value: null }, | ||
78 | |||
79 | |||
80 | /////////////////////////////////////////////////////////////////////// | ||
81 | // Property accessors | ||
82 | /////////////////////////////////////////////////////////////////////// | ||
83 | pushWorkingPlane : { value: function (p) { this._workingPlaneStack.push(workingPlane.slice(0)); workingPlane = p.slice(0); }}, | ||
84 | popWorkingPlane : { value: function () { workingPlane = this._workingPlaneStack.pop(); return workingPlane; }}, | ||
85 | |||
86 | getStageWidth : { value: function () { | ||
87 | return parseInt(this.currentStage.offsetWidth); | ||
88 | }}, | ||
89 | |||
90 | getStageHeight : { value: function () { | ||
91 | return parseInt(this.currentStage.offsetHeight); | ||
92 | }}, | ||
93 | |||
94 | getStage : { value: function() { return this.currentStage; }}, | ||
95 | |||
96 | getGridVertexHitRad : { value: function() { return this._gridVertexHitRad; }}, | ||
97 | getGridEdgeHitRad : { value: function() { return this._gridEdgeHitRad; }}, | ||
98 | |||
99 | getLastHit : { value: function() { return this._lastHit; }}, | ||
100 | setLastHit : { value: function(h) { this._lastHit = h; }}, | ||
101 | |||
102 | hasDragPlane : { value: function() { return this._hasDragPlane; }}, | ||
103 | getDragPlane : { value: function() { return this._dragPlane.slice(0); }}, | ||
104 | |||
105 | has2DCache : { value: function() { return (this._elementCache && !this._isCacheInvalid); }}, | ||
106 | |||
107 | enableSnapAlign : { value: function(e) { this._snapAlignEnabled = e; }}, | ||
108 | snapAlignEnabled : { value: function() { return this._snapAlignEnabled; }}, | ||
109 | enableElementSnap : { value: function(e) { this._elementSnapEnabled = e; }}, | ||
110 | elementSnapEnabled : { value: function() { return this._elementSnapEnabled; }}, | ||
111 | enableGridSnap : { value: function(e) { this._gridSnapEnabled = e; }}, | ||
112 | gridSnapEnabled : { value: function() { return this._gridSnapEnabled; }}, | ||
113 | |||
114 | enableSnapAlignAppLevel : { value: function(e) { this._snapAlignEnabledAppLevel = e; }}, | ||
115 | snapAlignEnabledAppLevel : { value: function() { return this._snapAlignEnabledAppLevel; }}, | ||
116 | enableElementSnapAppLevel : { value: function(e) { this._elementSnapEnabledAppLevel = e; }}, | ||
117 | elementSnapEnabledAppLevel : { value: function() { return this._elementSnapEnabledAppLevel; }}, | ||
118 | enableGridSnapAppLevel : { value: function(e) { this._gridSnapEnabledAppLevel = e; }}, | ||
119 | gridSnapEnabledAppLevel : { value: function() { return this._gridSnapEnabledAppLevel; }}, | ||
120 | |||
121 | /////////////////////////////////////////////////////////////////////// | ||
122 | // Methods | ||
123 | /////////////////////////////////////////////////////////////////////// | ||
124 | initialize: { | ||
125 | value: function() { | ||
126 | this.eventManager.addEventListener("elementDeleted", this, false); | ||
127 | } | ||
128 | }, | ||
129 | |||
130 | bindSnap: { | ||
131 | value: function() { | ||
132 | this.addEventListener("change@appModel.snap", this.toggleSnap, false); | ||
133 | this.addEventListener("change@appModel.snapGrid", this.toggleSnapGrid, false); | ||
134 | this.addEventListener("change@appModel.snapObjects", this.toggleSnapObjects, false); | ||
135 | this.addEventListener("change@appModel.snapAlign", this.toggleSnapAlign, false); | ||
136 | } | ||
137 | }, | ||
138 | |||
139 | toggleSnap: { | ||
140 | value: function() { | ||
141 | this.enableSnapAlignAppLevel(this.appModel.snap); | ||
142 | this.enableElementSnapAppLevel(this.appModel.snap); | ||
143 | this.enableGridSnapAppLevel(this.appModel.snap); | ||
144 | } | ||
145 | }, | ||
146 | |||
147 | toggleSnapGrid: { | ||
148 | value: function() { | ||
149 | this.enableGridSnapAppLevel(this.appModel.snapGrid); | ||
150 | } | ||
151 | }, | ||
152 | |||
153 | toggleSnapObjects: { | ||
154 | value: function() { | ||
155 | this.enableElementSnapAppLevel(this.appModel.snapObjects); | ||
156 | } | ||
157 | }, | ||
158 | |||
159 | toggleSnapAlign: { | ||
160 | value: function() { | ||
161 | this.enableSnapAlignAppLevel(this.appModel.snapAlign); | ||
162 | } | ||
163 | }, | ||
164 | |||
165 | |||
166 | handleElementDeleted: { | ||
167 | value: function(event) { | ||
168 | this.removeElementFrom2DCache(event.detail); | ||
169 | } | ||
170 | }, | ||
171 | |||
172 | |||
173 | setCurrentStage: { | ||
174 | value: function(stage) { | ||
175 | this.currentStage = stage; | ||
176 | } | ||
177 | }, | ||
178 | |||
179 | snap : { | ||
180 | value: function (xScreen, yScreen, snap3D, quadPt) | ||
181 | { | ||
182 | // force a 3D snap if a 2D snap is requested but the 2D cache has not been initialized | ||
183 | if (!snap3D && !this._elementCache) snap3D = true; | ||
184 | |||
185 | // clear out the last hit record | ||
186 | this.setLastHit( null ); | ||
187 | |||
188 | // snap to elements first, then the working plane | ||
189 | var screenPt = [xScreen, yScreen]; | ||
190 | var hitRecArray = new Array(); | ||
191 | if (this.elementSnapEnabled()) | ||
192 | { | ||
193 | if (snap3D) | ||
194 | this.snapToElements( screenPt, hitRecArray ); | ||
195 | |||
196 | // now always doing a 2D snap | ||
197 | this.snapToCached2DElements( screenPt, hitRecArray ); | ||
198 | } | ||
199 | |||
200 | // if we did not hit anything, and we are in 2D mode, try a snap align | ||
201 | if (this.snapAlignEnabled()) | ||
202 | { | ||
203 | //if (hitRecArray.length == 0) | ||
204 | this.snapAlign( screenPt, hitRecArray ); | ||
205 | } | ||
206 | |||
207 | |||
208 | // if we did not find any objects to snap to, snap to the working plane and/or grid | ||
209 | //if (hitRecArray.length == 0) | ||
210 | { | ||
211 | var stage = this.getStage(); | ||
212 | var parentPt; | ||
213 | if (quadPt) | ||
214 | parentPt = Vector.create([quadPt[0], quadPt[1], 0.0]); | ||
215 | else | ||
216 | parentPt = Vector.create([xScreen, yScreen, 0.0]); | ||
217 | var vec = viewUtils.parentToChildVec(parentPt, stage); | ||
218 | if (vec) | ||
219 | { | ||