aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPushkar Joshi2012-04-11 10:07:42 -0700
committerPushkar Joshi2012-04-11 10:07:42 -0700
commit25e406c9924438697564bc2341bd5b045a1dd85c (patch)
treef4c904662708a6d5db8c463a23256ac661c972a1
parent7fed1940bb4f3a333cef92fd51787a29e6dd787b (diff)
downloadninja-25e406c9924438697564bc2341bd5b045a1dd85c.tar.gz
Use local coordinates to pick a point within the path (works correctly even with canvas and/or stage transformation). Dragging does not yet work in case of canvas transformation
-rwxr-xr-xjs/lib/geom/sub-path.js87
-rwxr-xr-xjs/tools/PenTool.js20
2 files changed, 75 insertions, 32 deletions
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js
index 64f27bd3..87840bdc 100755
--- a/js/lib/geom/sub-path.js
+++ b/js/lib/geom/sub-path.js
@@ -752,9 +752,9 @@ GLSubpath.prototype.pathSamplesLocalHitTest = function(pickX, pickY, pickZ, radi
752 currAnchor = nextAnchor; 752 currAnchor = nextAnchor;
753 }//for every anchor i 753 }//for every anchor i
754 return [selAnchorIndex,retParam]; 754 return [selAnchorIndex,retParam];
755
756}; 755};
757 756
757
758//pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance 758//pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance
759GLSubpath.prototype.pathHitTest = function (pickX, pickY, pickZ, radius) { 759GLSubpath.prototype.pathHitTest = function (pickX, pickY, pickZ, radius) {
760 var numAnchors = this._Anchors.length; 760 var numAnchors = this._Anchors.length;
@@ -828,16 +828,27 @@ GLSubpath.prototype.pathHitTest = function (pickX, pickY, pickZ, radius) {
828 return [selAnchorIndex,retParam]; 828 return [selAnchorIndex,retParam];
829} //GLSubpath.pathHitTest function 829} //GLSubpath.pathHitTest function
830 830
831
831//pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance 832//pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance
832GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) { 833GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius, useLocal) {
833 var numAnchors = this._Anchors.length; 834 var numAnchors = this._Anchors.length;
834 var selAnchorIndex = -1; 835 var selAnchorIndex = -1;
835 var retCode = this.SEL_NONE; 836 var retCode = this.SEL_NONE;
836 var radSq = radius * radius; 837 var radSq = radius * radius;
837 var minDistance = Infinity; 838 var minDistance = Infinity;
839
840 //ignore the useLocal flag if the anchor points are not in-sync. with the local coordinates
841 if (numAnchors != this._AnchorLocalCoords.length){
842 useLocal = false;
843 }
844
838 //check if the clicked location is close to the currently selected anchor position 845 //check if the clicked location is close to the currently selected anchor position
839 if (this._selectedAnchorIndex>=0 && this._selectedAnchorIndex<this._Anchors.length){ 846 if (this._selectedAnchorIndex>=0 && this._selectedAnchorIndex<this._Anchors.length){
840 var distSq = this._Anchors[this._selectedAnchorIndex].getDistanceSq(pickX, pickY, pickZ); 847 var distSq;
848 if (!useLocal)
849 distSq = this._Anchors[this._selectedAnchorIndex].getDistanceSq(pickX, pickY, pickZ);
850 else
851 distSq = VecUtils.vecDistSq(3, this._AnchorLocalCoords[this._selectedAnchorIndex][1], [pickX, pickY, pickZ]);
841 //check the anchor point 852 //check the anchor point
842 if (distSq < minDistance && distSq < radSq) { 853 if (distSq < minDistance && distSq < radSq) {
843 selAnchorIndex = this._selectedAnchorIndex; 854 selAnchorIndex = this._selectedAnchorIndex;
@@ -845,10 +856,16 @@ GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) {
845 retCode = retCode | this.SEL_ANCHOR; 856 retCode = retCode | this.SEL_ANCHOR;
846 } 857 }
847 } 858 }
859
848 //now check if the click location is close to any anchor position 860 //now check if the click location is close to any anchor position
849 if (selAnchorIndex===-1) { 861 if (selAnchorIndex===-1) {
850 for (var i = 0; i < numAnchors; i++) { 862 for (var i = 0; i < numAnchors; i++) {
851 var distSq = this._Anchors[i].getDistanceSq(pickX, pickY, pickZ); 863 var distSq;
864 if (!useLocal)
865 distSq = this._Anchors[i].getDistanceSq(pickX, pickY, pickZ);
866 else
867 distSq = VecUtils.vecDistSq(3, this._AnchorLocalCoords[i][1], [pickX, pickY, pickZ]);
868
852 //check the anchor point 869 //check the anchor point
853 if (distSq < minDistance && distSq < radSq) { 870 if (distSq < minDistance && distSq < radSq) {
854 selAnchorIndex = i; 871 selAnchorIndex = i;
@@ -860,14 +877,23 @@ GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) {
860 877
861 //check the prev and next of the selected anchor if the above did not register a hit 878 //check the prev and next of the selected anchor if the above did not register a hit
862 if (this._selectedAnchorIndex>=0 && selAnchorIndex === -1) { 879 if (this._selectedAnchorIndex>=0 && selAnchorIndex === -1) {
863 var distSq = this._Anchors[this._selectedAnchorIndex].getPrevDistanceSq(pickX, pickY, pickZ); 880 var distSq;
881 if (!useLocal)
882 distSq = this._Anchors[this._selectedAnchorIndex].getPrevDistanceSq(pickX, pickY, pickZ);
883 else
884 distSq = VecUtils.vecDistSq(3, this._AnchorLocalCoords[this._selectedAnchorIndex][0], [pickX, pickY, pickZ]);
885
864 if (distSq < minDistance && distSq < radSq){ 886 if (distSq < minDistance && distSq < radSq){
865 selAnchorIndex = this._selectedAnchorIndex; 887 selAnchorIndex = this._selectedAnchorIndex;
866 minDistance = distSq; 888 minDistance = distSq;
867 retCode = retCode | this.SEL_PREV; 889 retCode = retCode | this.SEL_PREV;
868 } else { 890 } else {
869 //check the next for this anchor point 891 //check the next for this anchor point
870 distSq = this._Anchors[this._selectedAnchorIndex].getNextDistanceSq(pickX, pickY, pickZ); 892 if (!useLocal)
893 distSq = this._Anchors[this._selectedAnchorIndex].getNextDistanceSq(pickX, pickY, pickZ);
894 else
895 distSq = VecUtils.vecDistSq(3, this._AnchorLocalCoords[this._selectedAnchorIndex][2], [pickX, pickY, pickZ]);
896
871 if (distSq<minDistance && distSq<radSq){ 897 if (distSq<minDistance && distSq<radSq){
872 selAnchorIndex = this._selectedAnchorIndex; 898 selAnchorIndex = this._selectedAnchorIndex;
873 minDistance = distSq; 899 minDistance = distSq;
@@ -881,27 +907,38 @@ GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) {
881 this._selectedAnchorIndex = selAnchorIndex; 907 this._selectedAnchorIndex = selAnchorIndex;
882 } else { 908 } else {
883 this._selectedAnchorIndex = -1; 909 this._selectedAnchorIndex = -1;
884 var numSegments = this._isClosed ? numAnchors : numAnchors-1; 910 if (!useLocal){
885 for (var i = 0; i < numSegments; i++) { 911 var numSegments = this._isClosed ? numAnchors : numAnchors-1;
886 var nextIndex = (i+1)%numAnchors; 912 var currAnchor = this._AnchorLocalCoords[0];
887 //check if the point is close to the bezier segment between anchor i and anchor nextIndex 913 var nextAnchor = null;
888 var controlPoints = [[this._Anchors[i].getPosX(),this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()], 914 for (var i = 0; i < numSegments; i++) {
889 [this._Anchors[i].getNextX(),this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()], 915 var nextIndex = (i+1)%numAnchors;
890 [this._Anchors[nextIndex].getPrevX(),this._Anchors[nextIndex].getPrevY(),this._Anchors[nextIndex].getPrevZ()], 916 //check if the point is close to the bezier segment between anchor i and anchor nextIndex
891 [this._Anchors[nextIndex].getPosX(),this._Anchors[nextIndex].getPosY(),this._Anchors[nextIndex].getPosZ()]]; 917 var controlPoints = [[this._Anchors[i].getPosX(),this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()],
892 var point = [pickX, pickY, pickZ]; 918 [this._Anchors[i].getNextX(),this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()],
893 if (this._isWithinBoundingBox(point, controlPoints, radius)) { 919 [this._Anchors[nextIndex].getPrevX(),this._Anchors[nextIndex].getPrevY(),this._Anchors[nextIndex].getPrevZ()],
894 //var intersectParam = this._checkIntersection(controlPoints, 0.0, 1.0, point, radius); 920 [this._Anchors[nextIndex].getPosX(),this._Anchors[nextIndex].getPosY(),this._Anchors[nextIndex].getPosZ()]];
895 var intersectParam = this._checkIntersectionWithSamples(this._anchorSampleIndex[i], this._anchorSampleIndex[nextIndex], point, radius); 921 var point = [pickX, pickY, pickZ];
896 console.log("intersectParam:"+intersectParam); 922 if (this._isWithinBoundingBox(point, controlPoints, radius)) {
897 if (intersectParam){ 923 //var intersectParam = this._checkIntersection(controlPoints, 0.0, 1.0, point, radius);
898 retCode = retCode | this.SEL_PATH; 924 var intersectParam = this._checkIntersectionWithSamples(this._anchorSampleIndex[i], this._anchorSampleIndex[nextIndex], point, radius);
899 retParam = intersectParam-i; //make the retParam go from 0 to 1 925 console.log("intersectParam:"+intersectParam);
900 this._selectedAnchorIndex = i; 926 if (intersectParam){
901 break; 927 retCode = retCode | this.SEL_PATH;
928 retParam = intersectParam-i; //make the retParam go from 0 to 1
929 this._selectedAnchorIndex = i;
930 break;
931 }
902 } 932 }
933 }//for every anchor i
934 } else {
935 var selAnchorParam = this.pathSamplesLocalHitTest(pickX, pickY, pickZ, radius);
936 if (selAnchorParam[0]!== -1){
937 this._selectedAnchorIndex = selAnchorParam[0];
938 retParam = selAnchorParam[1];
939 retCode = retCode | this.SEL_PATH;
903 } 940 }
904 }//for every anchor i 941 }
905 } 942 }
906 this._selectMode = retCode; 943 this._selectMode = retCode;
907 return retParam; 944 return retParam;
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js
index cd15b36b..8065e1a6 100755
--- a/js/tools/PenTool.js
+++ b/js/tools/PenTool.js
@@ -182,12 +182,23 @@ exports.PenTool = Montage.create(ShapeTool, {
182 console.log("Warning...PenTool handleMouseDown: changing from SELECT_PATH to SELECT_NONE"); 182 console.log("Warning...PenTool handleMouseDown: changing from SELECT_PATH to SELECT_NONE");
183 } 183 }
184 } 184 }
185 185
186 //build the mouse down position in local coordinates
187 var drawingCanvas = this._selectedSubpath.getCanvas();
188 if (!drawingCanvas){
189 drawingCanvas = ViewUtils.getStageElement();
190 }
191 var globalMousePos = this._getUnsnappedScreenPosition(event.pageX, event.pageY);
192 var localMousePos = ViewUtils.globalToLocal(globalMousePos, drawingCanvas);
193
194
186 var prevSelectedAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex(); 195 var prevSelectedAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex();
187 // ************* Add/Select Anchor Point ************* 196 // ************* Add/Select Anchor Point *************
188 //check if the clicked location is close to an anchor point...if so, make that anchor the selected point and do nothing else 197 //check if the clicked location is close to an anchor point...if so, make that anchor the selected point and do nothing else
189 // BUT if the anchor point selected is the first anchor point, check if the previous selected anchor was the last anchor point...in that case, close the path 198 // BUT if the anchor point selected is the first anchor point, check if the previous selected anchor was the last anchor point...in that case, close the path
190 var selParam = this._selectedSubpath.pickPath(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2], this._PICK_POINT_RADIUS); 199
200 //var selParam = this._selectedSubpath.pickPath(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2], this._PICK_POINT_RADIUS);
201 var selParam = this._selectedSubpath.pickPath(localMousePos[0], localMousePos[1], localMousePos[2], this._PICK_POINT_RADIUS, true);
191 var whichPoint = this._selectedSubpath.getSelectedMode(); 202 var whichPoint = this._selectedSubpath.getSelectedMode();
192 if (whichPoint & this._selectedSubpath.SEL_ANCHOR) { 203 if (whichPoint & this._selectedSubpath.SEL_ANCHOR) {
193 //if we're in ENTRY_SELECT_PATH mode AND we have not yet clicked on the endpoint AND if we have now clicked on the endpoint 204 //if we're in ENTRY_SELECT_PATH mode AND we have not yet clicked on the endpoint AND if we have now clicked on the endpoint
@@ -288,9 +299,6 @@ exports.PenTool = Montage.create(ShapeTool, {
288 }, //HandleLeftButtonDown 299 }, //HandleLeftButtonDown
289 300
290 301
291 //need to override this function because the ShapeTool's definition contains a clearDrawingCanvas call - Pushkar
292 // might not need to override once we draw using OpenGL instead of SVG
293 // Also took out all the snapping code for now...need to add that back
294 HandleMouseMove: 302 HandleMouseMove:
295 { 303 {
296 value: function (event) { 304 value: function (event) {
@@ -647,7 +655,6 @@ exports.PenTool = Montage.create(ShapeTool, {
647 } //if this is a new path being rendered 655 } //if this is a new path being rendered
648 656
649 this._selectedSubpath.makeDirty(); 657 this._selectedSubpath.makeDirty();
650
651 this._selectedSubpath.createSamples(); 658 this._selectedSubpath.createSamples();
652 //if we have some samples to render... 659 //if we have some samples to render...
653 if (this._selectedSubpath.getNumAnchors() > 1) { 660 if (this._selectedSubpath.getNumAnchors() > 1) {
@@ -1011,7 +1018,6 @@ exports.PenTool = Montage.create(ShapeTool, {
1011 ctx.stroke(); 1018 ctx.stroke();
1012 } 1019 }
1013 1020
1014
1015 //display selected anchor and its prev. and next points 1021 //display selected anchor and its prev. and next points
1016 if (this._selectedSubpath &&a