From 23baa44e0bc7bfb24e42702c1ef58bf62da083d8 Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Wed, 14 Mar 2012 15:37:09 -0700 Subject: PI for pen and brush strokes --- .../brush-properties.reel/brush-properties.html | 7 +- js/controllers/elements/shapes-controller.js | 25 +++ js/data/pi/pi-data.js | 139 ++++++++++++++- js/lib/geom/brush-stroke.js | 196 ++++++++++----------- js/tools/BrushTool.js | 31 +++- js/tools/PenTool.js | 26 +++ 6 files changed, 311 insertions(+), 113 deletions(-) diff --git a/js/components/tools-properties/brush-properties.reel/brush-properties.html b/js/components/tools-properties/brush-properties.reel/brush-properties.html index cbe4c242..98442164 100755 --- a/js/components/tools-properties/brush-properties.reel/brush-properties.html +++ b/js/components/tools-properties/brush-properties.reel/brush-properties.html @@ -53,15 +53,14 @@ }, "smoothingAmountHT": { - "module": "js/components/hottextunit.reel", - "name": "HotTextUnit", + "module": "js/components/hottext.reel", + "name": "HotText", "properties": { "element": {"#": "smoothingAmount"}, "minValue": 0, "maxValue": 100, "value": 0, - "decimalPlace": 10, - "acceptableUnits" : ["px", "pt"] + "decimalPlace": 10 } }, diff --git a/js/controllers/elements/shapes-controller.js b/js/controllers/elements/shapes-controller.js index d72d9c14..b273350a 100755 --- a/js/controllers/elements/shapes-controller.js +++ b/js/controllers/elements/shapes-controller.js @@ -100,6 +100,31 @@ exports.ShapesController = Montage.create(CanvasController, { el.elementModel.shapeModel.GLWorld.render(); } break; + case "strokeHardness": + this.setShapeProperty(el, "strokeHardness", value); + el.elementModel.shapeModel.GLGeomObj.setStrokeHardness(val); + el.elementModel.shapeModel.GLWorld.render(); + break; + case "strokeSmoothing": + this.setShapeProperty(el, "strokeSmoothing", value); + el.elementModel.shapeModel.GLGeomObj.setSmoothingAmount(val); + el.elementModel.shapeModel.GLWorld.render(); + break; + case "doSmoothing": + this.setShapeProperty(el, "doSmoothing", value); + el.elementModel.shapeModel.GLGeomObj.setDoSmoothing(value); + el.elementModel.shapeModel.GLWorld.render(); + break; + case "isCalligraphic": + this.setShapeProperty(el, "isCalligraphic", value); + el.elementModel.shapeModel.GLGeomObj.setStrokeUseCalligraphic(value); + el.elementModel.shapeModel.GLWorld.render(); + break; + case "strokeAngle": + this.setShapeProperty(el, "strokeAngle", value); + el.elementModel.shapeModel.GLGeomObj.setStrokeAngle(Math.PI * -val/180); + el.elementModel.shapeModel.GLWorld.render(); + break; default: CanvasController.setProperty(el, p, value); } diff --git a/js/data/pi/pi-data.js b/js/data/pi/pi-data.js index ba03c347..ebd15832 100755 --- a/js/data/pi/pi-data.js +++ b/js/data/pi/pi-data.js @@ -585,7 +585,144 @@ exports.PiData = Montage.create( Montage, { ] } ] - } + }, + SubpathPi: { + value: [ + { + label: "Stroke", + + Section: [ + [ + { + type : "color", + prop: "border", + id : "stroke" + }, + { + type : "color", + id : "fill", + prop: "background", + divider : true + } + ], + [ + { + type : "hottext", + id : "strokeSize", + prop : "strokeSize", + label : "Stroke", + valueMutator: parseFloat, + min : 1, + max : 100, + value : 1, + unit : "px", + acceptableUnits: ["pt", "px"] + } + ] + ] + } + ] + }, + BrushStrokePi: { + value: [ + { + label: "Stroke", + + Section: [ + [ + { + type : "color", + prop: "border", + id : "stroke" + }, + { + type : "color", + id : "fill", + prop: "background", + visible : false, + divider : true + } + ], + [ + { + type : "hottext", + id : "strokeSize", + prop : "strokeSize", + label : "Stroke", + valueMutator: parseFloat, + min : 1, + max : 100, + value : 1, + unit : "px", + acceptableUnits: ["pt", "px"] + }, + { + type : "hottext", + id : "strokeHardness", + prop : "strokeHardness", + label : "Hardness", + valueMutator: parseFloat, + min : 0, + max : 100, + value : 100, + unit : "%", + acceptableUnits: ["%"] + } + ] + ] + }, + { + label: "Smoothing", + Section: [ + [ + { + type: "checkbox", + id: "doSmoothing", + prop: "doSmoothing", + defaultValue: false, + value: "Smoothing", + checked: false + }, + { + type : "hottext", + id : "strokeSmoothing", + prop : "strokeSmoothing", + label : "", + valueMutator: parseFloat, + min : 0, + max : 100, + value : 0 + } + ] + ] + }, + { + label: "Calligraphic", + Section: [ + [ + { + type: "checkbox", + id: "isCalligraphic", + prop: "isCalligraphic", + defaultValue: false, + value: "Calligraphic", + checked: false + }, + { + type : "hottext", + id : "strokeAngle", + prop : "strokeAngle", + label : "", + valueMutator: parseFloat, + min : -90, + max : 90, + value : 0 + } + ] + ] + } + ] //value: [ + } //BrushStrokePi: { }); diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 52f81ffe..0278e49c 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js @@ -18,9 +18,12 @@ var BrushStroke = function GLBrushStroke() { // Instance variables /////////////////////////////////////////////////// this._Points = []; + this._OrigPoints = []; this._BBoxMin = [0, 0, 0]; this._BBoxMax = [0, 0, 0]; this._dirty = true; + this._addedSamples = false; + this._storedOrigPoints = false; //whether or not to use the canvas drawing to stroke/fill this._useCanvasDrawing = true; @@ -137,7 +140,8 @@ var BrushStroke = function GLBrushStroke() { }; this.insertPoint = function(pt, index){ - this._Points.splice(index, 0, pt); this._dirty=true; + this._Points.splice(index, 0, pt); + this._dirty=true; }; this.isDirty = function(){ @@ -170,7 +174,7 @@ var BrushStroke = function GLBrushStroke() { }; this.setStrokeMaterial = function (m) { - this._strokeMaterial = m; + this._strokeMaterial = m; this._dirty = true; }; this.getStrokeColor = function () { @@ -178,31 +182,47 @@ var BrushStroke = function GLBrushStroke() { }; this.setStrokeColor = function (c) { - this._strokeColor = c; + this._strokeColor = c; this._dirty = true; }; this.setSecondStrokeColor = function(c){ - this._secondStrokeColor=c; + this._secondStrokeColor=c; this._dirty = true; } this.setStrokeHardness = function(h){ - this._strokeHardness=h; + if (this._strokeHardness!==h){ + this._strokeHardness=h; + this._dirty = true; + } } this.setDoSmoothing = function(s){ - this._strokeDoSmoothing = s; + if (this._strokeDoSmoothing!==s) { + this._strokeDoSmoothing = s; + this._dirty = true; + } } this.setSmoothingAmount = function(a){ - this._strokeAmountSmoothing = a; + if (this._strokeAmountSmoothing!==a) { + this._strokeAmountSmoothing = a; + this._dirty = true; + } + } this.setStrokeUseCalligraphic = function(c){ - this._strokeUseCalligraphic = c; + if (this._strokeUseCalligraphic!==c){ + this._strokeUseCalligraphic = c; + this._dirty = true; + } } this.setStrokeAngle = function(a){ - this._strokeAngle = a; + if (this._strokeAngle!==a){ + this._strokeAngle = a; + this._dirty = true; + }; } this.getStrokeStyle = function () { @@ -221,133 +241,95 @@ var BrushStroke = function GLBrushStroke() { };//NO-OP for now - - //remove and return anchor at specified index, return null on error - this.removePoint = function (index) { - var retAnchor = null; - if (index < this._Points.length) { - retPt = this._Points.splice(index, 1); - this._dirty=true; - } - return retPoint; - }; - //remove all the points this.clear = function () { this._Points = []; + this._OrigPoints = []; this._dirty=true; } - this.translate = function (tx, ty, tz) { + /*this.translate = function (tx, ty, tz) { for (var i=0;i1) { - if (0){ - var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD; - var prevPt = this._Points[0]; - var prevIndex = 0; - for (var i=1;ithreshold){ - //insert points along the prev. to current point - var numNewPoints = Math.floor(distance/threshold); - for (var j=0;j this._MAX_ALLOWED_SAMPLES){ - console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); - break; + var numPoints = this._Points.length; + if (this._addedSamples === false){ + //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation ***** + // instead of the following, may use 4-point subdivision iterations over continuous regions of 'long' segments + // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula + + var numInsertedPoints = 0; + var newSampledPoints = []; + var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample is long enough to warrant checking for angle + var prevPt = this._Points[0]; + newSampledPoints.push(this._Points[0]); + for (var i=1;ithreshold){ + //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points) + var prev = (i===1) ? i-1 : i-2; + var next = (i===numPoints-1) ? i : i+1; + var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]]; + //insert points along the prev. to current point + var numNewPoints = Math.floor(distance/threshold); + for (var j=0;j this._MAX_ALLOWED_SAMPLES){ + // console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); + // break; + //} } + this._Points = newSampledPoints.slice(0); + newSampledPoints = []; + console.log("Inserted "+numInsertedPoints+" additional CatmullRom points"); + this._addedSamples = true; + this._dirty=true; + } + //build a copy of the original points...this should be done only once + if (this._storedOrigPoints === false) { + this._OrigPoints = this._Points.slice(0); + this._storedOrigPoints = true; + } - //instead of the following, may use 4-point subdivision iterations over continuous regions of 'long' segments - // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula - //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation + if (this._dirty) { + this._Points = this._OrigPoints.slice(0); + numPoints = this._Points.length; if (this._strokeDoSmoothing && numPoints>1) { - var numInsertedPoints = 0; - var newPoints = []; - var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample is long enough to warrant checking for angle - var prevPt = this._Points[0]; - newPoints.push(this._Points[0]); - for (var i=1;ithreshold){ - //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points) - var prev = (i===1) ? i-1 : i-2; - var next = (i===numPoints-1) ? i : i+1; - var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]]; - //insert points along the prev. to current point - var numNewPoints = Math.floor(distance/threshold); - for (var j=0;j this._MAX_ALLOWED_SAMPLES){ - console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); - break; - } - } - this._Points = newPoints; - numPoints = this._Points.length; - console.log("Inserted "+numInsertedPoints+" additional CatmullRom points"); - - //now do 3-4 iterations of Laplacian smoothing (setting the points to the average of their neighbors) - var numLaplacianIterations = this._strokeAmountSmoothing; + //iterations of Laplacian smoothing (setting the points to the average of their neighbors) + var numLaplacianIterations = this._strokeAmountSmoothing; for (var n=0;n