diff options
-rwxr-xr-x | js/lib/geom/sub-path.js | 173 | ||||
-rwxr-xr-x | js/tools/PenTool.js | 19 |
2 files changed, 110 insertions, 82 deletions
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index 761391b7..31bf4632 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js | |||
@@ -43,10 +43,6 @@ var GLSubpath = function GLSubpath() { | |||
43 | //initially set the _dirty bit so we will re-construct _Anchors and _Samples | 43 | //initially set the _dirty bit so we will re-construct _Anchors and _Samples |
44 | this._dirty = true; | 44 | this._dirty = true; |
45 | 45 | ||
46 | //the top left location of this subpath's canvas in screen space (used to identify cases when location changes) | ||
47 | this._canvasLeft = 0; | ||
48 | this._canvasTop = 0; | ||
49 | |||
50 | //stroke information | 46 | //stroke information |
51 | this._strokeWidth = 1.0; | 47 | this._strokeWidth = 1.0; |
52 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; | 48 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; |
@@ -97,7 +93,7 @@ var GLSubpath = function GLSubpath() { | |||
97 | if (numAnchors === 0) { | 93 | if (numAnchors === 0) { |
98 | return; //nothing to do for empty paths | 94 | return; //nothing to do for empty paths |
99 | } | 95 | } |
100 | this.createSamples(); //dirty bit checked in this function...will generate a polyline representation | 96 | this.createSamples(false); //dirty bit checked in this function...will generate a polyline representation |
101 | 97 | ||
102 | //figure the size of the area we will draw into | 98 | //figure the size of the area we will draw into |
103 | var bboxWidth=0, bboxHeight=0; | 99 | var bboxWidth=0, bboxHeight=0; |
@@ -123,6 +119,8 @@ var GLSubpath = function GLSubpath() { | |||
123 | } | 119 | } |
124 | var lineCap = ['butt','round','square']; | 120 | var lineCap = ['butt','round','square']; |
125 | ctx.lineCap = lineCap[1]; | 121 | ctx.lineCap = lineCap[1]; |
122 | var lineJoin = ['round','bevel','miter']; | ||
123 | ctx.lineJoin = lineJoin[0]; | ||
126 | 124 | ||
127 | /* | 125 | /* |
128 | commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered | 126 | commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered |
@@ -649,73 +647,100 @@ GLSubpath.prototype.getStrokeWidth = function () { | |||
649 | return this._strokeWidth; | 647 | return this._strokeWidth; |
650 | }; | 648 | }; |
651 | 649 | ||
652 | GLSubpath.prototype.setCanvasLeft = function(cl){ | ||
653 | this._canvasLeft = cl; | ||
654 | }; | ||
655 | GLSubpath.prototype.setCanvasTop = function(ct){ | ||
656 | this._canvasTop = ct; | ||
657 | }; | ||
658 | GLSubpath.prototype.setCanvasLeftTopPerElementMediator = function(elemMediator){ | ||
659 | if (!this._canvas){ | ||
660 | if (!this.getWorld()) | ||
661 | return; //cannot do anything if there is no world | ||
662 | //set the canvas by querying the world | ||
663 | this._canvas = this.getWorld().getCanvas(); | ||
664 | } | ||
665 | //check if the canvas was translated | ||
666 | var penCanvasCurrentLeft = parseInt(elemMediator.getProperty(this._canvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left")); | ||
667 | var penCanvasCurrentTop = parseInt(elemMediator.getProperty(this._canvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top")); | ||
668 | 650 | ||
669 | var translateCanvasX = Math.round(penCanvasCurrentLeft - this._canvasLeft); | 651 | GLSubpath.prototype.setStrokeWidth = function (w) { |
670 | var translateCanvasY = Math.round(penCanvasCurrentTop - this._canvasTop); | 652 | var diffStrokeWidth = w-this._strokeWidth;//if positive, then stroke width grew, else shrunk |
653 | if (diffStrokeWidth === 0){ | ||
654 | return;//nothing to do | ||
655 | } | ||
671 | 656 | ||
672 | //update the left and top parameters for this subpath and also translate the subpath points (since they're stored in stage world space) | 657 | //only allow to increase the stroke width with even increments (this avoids floating point round-off problems) |
673 | if (Math.abs(translateCanvasX)>=1 || Math.abs(translateCanvasY)>=1){ | 658 | diffStrokeWidth = Math.round(diffStrokeWidth); |
674 | this.setCanvasLeft(penCanvasCurrentLeft); | 659 | if (diffStrokeWidth%2){ |
675 | this.setCanvasTop(penCanvasCurrentTop); | 660 | diffStrokeWidth+=1; |
676 | } | 661 | } |
677 | this._dirty=true; | ||
678 | }; | ||
679 | 662 | ||
680 | GLSubpath.prototype.computeLeftTopWidthHeight = function() { | 663 | //update the stroke width by the delta |
681 | //build the width and height of this canvas by looking at local coordinates | 664 | this._strokeWidth += diffStrokeWidth; |
682 | var bboxMin = this.getLocalBBoxMin(); | ||
683 | var bboxMax = this.getLocalBBoxMax(); | ||
684 | var bboxWidth = bboxMax[0] - bboxMin[0]; | ||
685 | var bboxHeight = bboxMax[1] - bboxMin[1]; | ||
686 | 665 | ||
687 | //build the 3D position of the plane center of this canvas by looking at midpoint of the bounding box in stage world coords | 666 | //if we have no path yet, return |
688 | bboxMin = this.getBBoxMin(); | 667 | if (this.getNumAnchors()<2 || this._canvas===null){ |
689 | bboxMax = this.getBBoxMax(); | 668 | return; |
690 | //var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; | 669 | } |
691 | //var left = Math.round(bboxMid[0] - 0.5 * bboxWidth); | ||
692 | //var top = Math.round(bboxMid[1] - 0.5 * bboxHeight); | ||
693 | var left = this._canvasLeft; | ||
694 | var top = this._canvasTop; | ||
695 | return [left, top, bboxWidth, bboxHeight]; | ||
696 | }; | ||
697 | 670 | ||
698 | GLSubpath.prototype.setStrokeWidth = function (w) { | 671 | if (this._dirty){ |
699 | var diffStrokeWidth = w-Math.floor(this._strokeWidth);//if positive, then stroke width grew, else shrunk | 672 | this.createSamples(false); //this will also update the bounding box |
700 | if (diffStrokeWidth === 0) | 673 | } else{ |
701 | return;//nothing to do | 674 | this.computeBoundingBox(false); |
675 | } | ||
676 | this.offsetPerBBoxMin(); //this will shift the local coordinates such that the bbox min point is at (0,0) | ||
702 | 677 | ||
703 | this._strokeWidth = w; | 678 | //figure out the adjustment to the canvas position and size |
704 | this._dirty=true; | 679 | var delta = Math.round(diffStrokeWidth*0.5); |
705 | 680 | ||
681 | //update the width, height, left and top | ||
706 | var ElementMediator = require("js/mediators/element-mediator").ElementMediator; | 682 | var ElementMediator = require("js/mediators/element-mediator").ElementMediator; |
683 | var penCanvasCurrentWidth = parseInt(ElementMediator.getProperty(this._canvas, "width")); | ||
684 | var penCanvasNewWidth = penCanvasCurrentWidth + diffStrokeWidth; | ||
685 | var penCanvasCurrentHeight = parseInt(ElementMediator.getProperty(this._canvas, "height")); | ||
686 | var penCanvasNewHeight = penCanvasCurrentHeight + diffStrokeWidth; | ||
687 | var penCanvasCurrentLeft = parseInt(ElementMediator.getProperty(this._canvas, "left")); | ||
688 | var penCanvasNewLeft = penCanvasCurrentLeft - delta; | ||
689 | var penCanvasCurrentTop = parseInt(ElementMediator.getProperty(this._canvas, "top")); | ||
690 | var penCanvasNewTop = penCanvasCurrentTop - delta; | ||
691 | var canvasArray=[this._canvas]; | ||
692 | ElementMediator.setProperty(canvasArray, "width", [penCanvasNewWidth+"px"], "Changing", "penTool"); | ||
693 | ElementMediator.setProperty(canvasArray, "height", [penCanvasNewHeight+"px"], "Changing", "penTool"); | ||
694 | ElementMediator.setProperty(canvasArray, "left", [penCanvasNewLeft+"px"],"Changing", "penTool"); | ||
695 | ElementMediator.setProperty(canvasArray, "top", [penCanvasNewTop+ "px"],"Changing", "penTool"); | ||
696 | |||
697 | /* | ||
698 | //compute the current location of the canvas for this subpath | ||
699 | this.createSamples(); //this will also update the bounding box | ||
700 | var bboxMin = this.getBBoxMin(); | ||
701 | var bboxMax = this.getBBoxMax(); | ||
702 | var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0]; //ignore the Z coord. for local coordinates | ||
703 | |||
704 | //go from local coordinates to stage world | ||
705 | var ViewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; | ||
706 | var SnapManager = require("js/helper-classes/3D/snap-manager").SnapManager; | ||
707 | var localToStageWorldMat = ViewUtils.getLocalToStageWorldMatrix(this._canvas, true, true); | ||
708 | var bboxMidSW = MathUtils.transformAndDivideHomogeneousPoint(bboxMid, localToStageWorldMat); | ||
709 | bboxMidSW[0]+=SnapManager.getStageWidth()*0.5; | ||
710 | bboxMidSW[1]+=SnapManager.getStageHeight()*0.5; | ||
711 | |||
712 | this._strokeWidth = Math.round(w); | ||
713 | this._dirty=true; | ||
714 | |||
715 | // **** adjust the local coordinates to account for the change in stroke width **** | ||
716 | this.computeBoundingBox(); //this will take the new strokewidth into account | ||
717 | this.offsetPerBBoxMin(); //this will shift the local coordinates such that the bbox min point is at (0,0) | ||
707 | 718 | ||
708 | //translate the subpath in case the actual canvas location does not match where subpath thinks the canvas should be | 719 | // **** adjust the canvas position to account for the change in stroke width |
709 | this.setCanvasLeftTopPerElementMediator(ElementMediator); | 720 | var ElementMediator = require("js/mediators/element-mediator").ElementMediator; |
721 | //build the width and height of this canvas by looking at local coordinates | ||
722 | bboxMin = this.getBBoxMin(); | ||
723 | bboxMax = this.getBBoxMax(); | ||
724 | var width = Math.round(bboxMax[0] - bboxMin[0]); | ||
725 | var height = Math.round(bboxMax[1] - bboxMin[1]); | ||
726 | var left = Math.round(bboxMidSW[0] - 0.5 * width); | ||
727 | var top = Math.round(bboxMidSW[1] - 0.5 * height); | ||
710 | 728 | ||
711 | // **** adjust the left, top, width, and height to adjust for the change in stroke width **** | ||
712 | this.createSamples(); //dirty bit is checked here | ||
713 | var ltwh = this.computeLeftTopWidthHeight(); | ||
714 | var canvasArray=[this._canvas]; | 729 | var canvasArray=[this._canvas]; |
715 | ElementMediator.setProperty(canvasArray, "width", [ltwh[2]+"px"], "Changing", "penTool");//canvas.width = w; | 730 | ElementMediator.setProperty(canvasArray, "width", [width+"px"], "Changing", "penTool"); |
716 | ElementMediator.setProperty(canvasArray, "height", [ltwh[3]+"px"], "Changing", "penTool");//canvas.height = h; | 731 | ElementMediator.setProperty(canvasArray, "height", [height+"px"], "Changing", "penTool"); |
717 | ElementMediator.setProperty(canvasArray, "left", [ltwh[0]+"px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "left", parseInt(left) + "px"); | 732 | |
718 | ElementMediator.setProperty(canvasArray, "top", [ltwh[1]+ "px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "top", parseInt(top) + "px"); | 733 | //check if the canvas was translated |
734 | var penCanvasCurrentLeft = parseInt(ElementMediator.getProperty(this._canvas, "left")); | ||
735 | var penCanvasCurrentTop = parseInt(ElementMediator.getProperty(this._canvas, "top")); | ||
736 | left = Math.round(penCanvasCurrentLeft - diffStrokeWidth*0.5); | ||
737 | top = Math.round(penCanvasCurrentTop - diffStrokeWidth*0.5); | ||
738 | |||
739 | //left = Math.round(bboxMidSW[0] - 0.5 * width); | ||
740 | //top = Math.round(bboxMidSW[1] - 0.5 * height); | ||
741 | ElementMediator.setProperty(canvasArray, "left", [left+"px"],"Changing", "penTool"); | ||
742 | ElementMediator.setProperty(canvasArray, "top", [top+ "px"],"Changing", "penTool"); | ||
743 | */ | ||
719 | }; | 744 | }; |
720 | 745 | ||
721 | GLSubpath.prototype.getStrokeColor = function () { | 746 | GLSubpath.prototype.getStrokeColor = function () { |
@@ -866,7 +891,7 @@ GLSubpath.prototype._unprojectPt = function(pt, pespectiveDist) { | |||
866 | 891 | ||
867 | // createSamples | 892 | // createSamples |
868 | // stores samples of the subpath in _samples | 893 | // stores samples of the subpath in _samples |
869 | GLSubpath.prototype.createSamples = function () { | 894 | GLSubpath.prototype.createSamples = function (isStageWorldCoord) { |
870 | if (this._dirty) { | 895 | if (this._dirty) { |
871 | //clear any previously computed samples | 896 | //clear any previously computed samples |
872 | this._Samples = []; | 897 | this._Samples = []; |
@@ -928,7 +953,7 @@ GLSubpath.prototype.createSamples = function () { | |||
928 | } //if (numAnchors >== 2) { | 953 | } //if (numAnchors >== 2) { |
929 | 954 | ||
930 | //re-compute the bounding box (this also accounts for stroke width, so assume the stroke width is set) | 955 | //re-compute the bounding box (this also accounts for stroke width, so assume the stroke width is set) |
931 | this.computeBoundingBox(true); | 956 | this.computeBoundingBox(true, isStageWorldCoord); |
932 | } //if (this._dirty) | 957 | } //if (this._dirty) |
933 | this._dirty = false; | 958 | this._dirty = false; |
934 | }; | 959 | }; |
@@ -938,13 +963,14 @@ GLSubpath.prototype.offsetPerBBoxMin = function() | |||
938 | //offset the anchor and sample coordinates such that the min point of the bbox is at [0,0,0] | 963 | //offset the anchor and sample coordinates such that the min point of the bbox is at [0,0,0] |
939 | this.translateAnchors(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); | 964 | this.translateAnchors(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); |
940 | this.translateSamples(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); | 965 | this.translateSamples(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); |
966 | |||
941 | this._BBoxMax[0]-= this._BBoxMin[0]; | 967 | this._BBoxMax[0]-= this._BBoxMin[0]; |
942 | this._BBoxMax[1]-= this._BBoxMin[1]; | 968 | this._BBoxMax[1]-= this._BBoxMin[1]; |
943 | this._BBoxMax[2]-= this._BBoxMin[2]; | 969 | this._BBoxMax[2]-= this._BBoxMin[2]; |
944 | this._BBoxMin[0] = this._BBoxMin[1] = this._BBoxMin[2] = 0; |