diff options
author | Pushkar Joshi | 2012-04-09 15:55:10 -0700 |
---|---|---|
committer | Pushkar Joshi | 2012-04-09 15:55:10 -0700 |
commit | dae3041e6b8269da3d593a44c09e2288bb434a02 (patch) | |
tree | 495fc661a2e90816706a09b8d7d702550bd7fd8c /js | |
parent | 6cce5e9367676f5b452c28dd7d960aa46f4e464c (diff) | |
download | ninja-dae3041e6b8269da3d593a44c09e2288bb434a02.tar.gz |
snapping feedback for pen tool, correct for subpaths that may lie on rotated canvas, and with a rotated view
Diffstat (limited to 'js')
-rwxr-xr-x | js/helper-classes/3D/vec-utils.js | 19 | ||||
-rwxr-xr-x | js/lib/geom/sub-path.js | 29 | ||||
-rwxr-xr-x | js/tools/PenTool.js | 63 |
3 files changed, 97 insertions, 14 deletions
diff --git a/js/helper-classes/3D/vec-utils.js b/js/helper-classes/3D/vec-utils.js index 4eacd856..0916c840 100755 --- a/js/helper-classes/3D/vec-utils.js +++ b/js/helper-classes/3D/vec-utils.js | |||
@@ -113,6 +113,25 @@ var VecUtils = exports.VecUtils = Object.create(Object.prototype, | |||
113 | } | 113 | } |
114 | }, | 114 | }, |
115 | 115 | ||
116 | vecDistSq : { | ||
117 | value: function( dimen, a, b ) { | ||
118 | var sum; | ||
119 | |||
120 | if ((a.length < dimen) || (b.length < dimen)) | ||
121 | { | ||
122 | throw new Error( "dimension error in VecUtils.vecDistSq" ); | ||
123 | } | ||
124 | |||
125 | var sum = 0.0; | ||
126 | for (var i=0; i<dimen; i++) | ||
127 | { | ||
128 | var d = a[i] - b[i]; | ||
129 | sum += d*d; | ||
130 | } | ||
131 | return sum; | ||
132 | } | ||
133 | }, | ||
134 | |||
116 | vecDot : { | 135 | vecDot : { |
117 | value: function( dimen, v0, v1 ) { | 136 | value: function( dimen, v0, v1 ) { |
118 | if ((v0.length < dimen) || (v1.length < dimen)) | 137 | if ((v0.length < dimen) || (v1.length < dimen)) |
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index d784fbc6..33bcfc9a 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js | |||
@@ -620,7 +620,28 @@ GLSubpath.prototype._isWithinBoundingBox = function(point, ctrlPts, radius) { | |||
620 | return true; | 620 | return true; |
621 | }; | 621 | }; |
622 | 622 | ||
623 | GLSubpath.prototype._checkAnchorIntersection = function(pickX, pickY, pickZ, radSq, anchorIndex, minDistance) { | 623 | GLSubpath.prototype._checkAnchorIntersection = function(pickX, pickY, pickZ, radSq, anchorIndex, minDistance, useLocal) { |
624 | //if we are asked to use the local coordinate and the local coordinate for this anchor exists | ||
625 | if (useLocal && this._anchorSampleIndex.length>anchorIndex && this._LocalPoints.length > this._anchorSampleIndex[anchorIndex]) { | ||
626 | var localCoord = this._LocalPoints[this._anchorSampleIndex[anchorIndex]] | ||
627 | var distSq = VecUtils.vecDistSq(3, [pickX, pickY, pickZ], localCoord); | ||
628 | //check the anchor point | ||
629 | if (distSq < radSq && distSq<minDistance) { | ||
630 | return this.SEL_ANCHOR; | ||
631 | } | ||
632 | /* | ||
633 | //check the prev. and next of the selected anchor point | ||
634 | distSq = this._Anchors[anchorIndex].getPrevDistanceSq(pickX, pickY, pickZ); | ||
635 | if (distSq<radSq && distSq<minDistance){ | ||
636 | return this.SEL_PREV; | ||
637 | } | ||
638 | distSq = this._Anchors[anchorIndex].getNextDistanceSq(pickX, pickY, pickZ); | ||
639 | if (distSq<radSq && distSq<minDistance){ | ||
640 | return this.SEL_NEXT; | ||
641 | }*/ | ||
642 | return this.SEL_NONE; | ||
643 | } | ||
644 | |||
624 | var distSq = this._Anchors[anchorIndex].getDistanceSq(pickX, pickY, pickZ); | 645 | var distSq = this._Anchors[anchorIndex].getDistanceSq(pickX, pickY, pickZ); |
625 | //check the anchor point | 646 | //check the anchor point |
626 | if (distSq < radSq && distSq<minDistance) { | 647 | if (distSq < radSq && distSq<minDistance) { |
@@ -638,7 +659,7 @@ GLSubpath.prototype._checkAnchorIntersection = function(pickX, pickY, pickZ, rad | |||
638 | return this.SEL_NONE; | 659 | return this.SEL_NONE; |
639 | }; | 660 | }; |
640 | 661 | ||
641 | GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | 662 | GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius, useLocal) { |
642 | var numAnchors = this._Anchors.length; | 663 | var numAnchors = this._Anchors.length; |
643 | var selAnchorIndex = -1; | 664 | var selAnchorIndex = -1; |
644 | var retCode = this.SEL_NONE; | 665 | var retCode = this.SEL_NONE; |
@@ -646,14 +667,14 @@ GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | |||
646 | var radSq = radius * radius; | 667 | var radSq = radius * radius; |
647 | //check if the clicked location is close to the currently selected anchor position | 668 | //check if the clicked location is close to the currently selected anchor position |
648 | if (this._selectedAnchorIndex>=0 && this._selectedAnchorIndex<this._Anchors.length){ | 669 | if (this._selectedAnchorIndex>=0 && this._selectedAnchorIndex<this._Anchors.length){ |
649 | retCode = this._checkAnchorIntersection(pickX, pickY, pickZ, radSq, this._selectedAnchorIndex, minDistance); | 670 | retCode = this._checkAnchorIntersection(pickX, pickY, pickZ, radSq, this._selectedAnchorIndex, minDistance, useLocal); |
650 | if (retCode!==this.SEL_NONE){ | 671 | if (retCode!==this.SEL_NONE){ |
651 | return [this._selectedAnchorIndex, retCode]; | 672 | return [this._selectedAnchorIndex, retCode]; |
652 | } | 673 | } |
653 | } | 674 | } |
654 | //now check if the click location is close to any anchor position | 675 | //now check if the click location is close to any anchor position |
655 | for (var i = 0; i < numAnchors; i++) { | 676 | for (var i = 0; i < numAnchors; i++) { |
656 | retCode = this._checkAnchorIntersection(pickX, pickY, pickZ, radSq, i, minDistance); | 677 | retCode = this._checkAnchorIntersection(pickX, pickY, pickZ, radSq, i, minDistance, useLocal); |
657 | if (retCode!==this.SEL_NONE){ | 678 | if (retCode!==this.SEL_NONE){ |
658 | selAnchorIndex=i; | 679 | selAnchorIndex=i; |
659 | break; | 680 | break; |
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js index 61a254ea..6c016cab 100755 --- a/js/tools/PenTool.js +++ b/js/tools/PenTool.js | |||
@@ -119,6 +119,27 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
119 | } | 119 | } |
120 | }, | 120 | }, |
121 | 121 | ||
122 | _getUnsnappedScreenPosition: { | ||
123 | value: function(x,y){ | ||
124 | var elemSnap = snapManager.elementSnapEnabled(); | ||
125 | var gridSnap = snapManager.gridSnapEnabled(); | ||
126 | var alignSnap = snapManager.snapAlignEnabled(); | ||
127 | |||
128 | snapManager.enableElementSnap(false); | ||
129 | snapManager.enableGridSnap(false); | ||
130 | snapManager.enableSnapAlign(false); | ||
131 | |||
132 | var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); | ||
133 | var unsnappedpos = (snapManager.snap(point.x, point.y, false)).getScreenPoint(); | ||
134 | this._dragPlane = snapManager.getDragPlane(); | ||
135 | |||
136 | snapManager.enableElementSnap(elemSnap); | ||
137 | snapManager.enableGridSnap(gridSnap); | ||
138 | snapManager.enableSnapAlign(alignSnap); | ||
139 | |||
140 | return unsnappedpos; | ||
141 | } | ||
142 | }, | ||
122 | ShowToolProperties: { | 143 | ShowToolProperties: { |
123 | value: function () { | 144 | value: function () { |
124 | this._penView = PenView.create(); | 145 | this._penView = PenView.create(); |
@@ -351,20 +372,31 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
351 | 372 | ||
352 | //make the subpath dirty so it will get re-drawn | 373 | //make the subpath dirty so it will get re-drawn |
353 | this._selectedSubpath.makeDirty(); | 374 | this._selectedSubpath.makeDirty(); |
354 | //this.DrawSubpathSVG(this._selectedSubpath); | ||
355 | } | ||
356 | //todo temp code only...remove this and uncomment the DrawSubpathSVG above | ||
357 | if (this._selectedSubpath){ | ||
358 | this.DrawSubpathSVG(this._selectedSubpath); | 375 | this.DrawSubpathSVG(this._selectedSubpath); |
359 | } | 376 | } |
360 | |||
361 | } else { //if mouse is not down: | 377 | } else { //if mouse is not down: |
362 | //this.doSnap(event); | 378 | //this.doSnap(event); |
363 | //this.DrawHandles(); | 379 | //this.DrawHandles(); |
364 | 380 | ||
365 | var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY); | 381 | var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY); |
366 | if (currMousePos && this._selectedSubpath ){ | 382 | if (currMousePos && this._selectedSubpath ){ |
367 | var selAnchorRetCode = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS); | 383 | /* |
384 | //convert the mouse pos. to local space of the canvas | ||
385 | var widthAdjustment = -snapManager.getStageWidth()*0.5; | ||
386 | var heightAdjustment = -snapManager.getStageHeight()*0.5; */ | ||
387 | |||
388 | |||
389 | var drawingCanvas = this._selectedSubpath.getCanvas(); | ||
390 | if (!drawingCanvas){ | ||
391 | drawingCanvas = ViewUtils.getStageElement(); | ||
392 | } | ||
393 | /*var stageWorldToGlobalMatrix = ViewUtils.getStageWorldToGlobalMatrix(); | ||
394 | var globalMousePos = MathUtils.transformAndDivideHomogeneousPoint([currMousePos[0]+widthAdjustment, currMousePos[1]+heightAdjustment, currMousePos[2]], stageWorldToGlobalMatrix);*/ | ||
395 | var globalMousePos = this._getUnsnappedScreenPosition(event.pageX, event.pageY); | ||
396 | var localMousePos = ViewUtils.globalToLocal(globalMousePos, drawingCanvas); | ||
397 | |||
398 | //var selAnchorRetCode = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS, false); | ||
399 | var selAnchorRetCode = this._selectedSubpath.pickAnchor(localMousePos[0], localMousePos[1], localMousePos[2], this._PICK_POINT_RADIUS, true); | ||
368 | if (selAnchorRetCode[0] >=0) { | 400 | if (selAnchorRetCode[0] >=0) { |
369 | this._hoveredAnchorIndex = selAnchorRetCode[0]; | 401 | this._hoveredAnchorIndex = selAnchorRetCode[0]; |
370 | var lastAnchorIndex = this._selectedSubpath.getNumAnchors()-1; | 402 | var lastAnchorIndex = this._selectedSubpath.getNumAnchors()-1; |
@@ -599,12 +631,23 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
599 | strokeSize = ShapesController.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units); | 631 | strokeSize = ShapesController.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units); |
600 | } | 632 | } |
601 | this._selectedSubpath.setStrokeWidth(strokeSize); | 633 | this._selectedSubpath.setStrokeWidth(strokeSize); |
602 | if (this.application.ninja.colorController.colorToolbar.stroke.webGlColor){ | 634 | |
603 | this._selectedSubpath.setStrokeColor(this.application.ninja.colorController.colorToolbar.stroke.webGlColor); | 635 | var colorArray=[]; |
636 | var color = this.application.ninja.colorController.colorToolbar.stroke.color; | ||
637 | if (color){ | ||
638 | colorArray = [color.r/255, color.g/255, color.b/255, color.a]; | ||
639 | }else { | ||
640 | colorArray = [1,1,1,0]; | ||
604 | } | 641 | } |
605 | if (this.application.ninja.colorController.colorToolbar.fill.webGlColor){ | 642 | this._selectedSubpath.setStrokeColor(colorArray); |
606 | this._selectedSubpath.setFillColor(this.application.ninja.colorController.colorToolbar.fill.webGlColor); | 643 | |
644 | color = this.application.ninja.colorController.colorToolbar.fill.color; | ||
645 | if (color){ | ||
646 | colorArray = [color.r/255, color.g/255, color.b/255, color.a]; | ||
647 | } else { | ||
648 | colorArray = [1,1,1,0]; | ||
607 | } | 649 | } |
650 | this._selectedSubpath.setFillColor(colorArray); | ||
608 | } //if this is a new path being rendered | 651 | } //if this is a new path being rendered |
609 | 652 | ||
610 | this._selectedSubpath.makeDirty(); | 653 | this._selectedSubpath.makeDirty(); |