aboutsummaryrefslogtreecommitdiff
path: root/js/lib/geom/brush-stroke.js
diff options
context:
space:
mode:
authorPushkar Joshi2012-03-14 15:37:09 -0700
committerPushkar Joshi2012-03-14 15:37:09 -0700
commit23baa44e0bc7bfb24e42702c1ef58bf62da083d8 (patch)
tree6efae3071b1b09e859fdefdbdac848063a22c355 /js/lib/geom/brush-stroke.js
parent6023f7c8258e660388ee33730601f1161f9299e9 (diff)
downloadninja-23baa44e0bc7bfb24e42702c1ef58bf62da083d8.tar.gz
PI for pen and brush strokes
Diffstat (limited to 'js/lib/geom/brush-stroke.js')
-rwxr-xr-xjs/lib/geom/brush-stroke.js196
1 files changed, 89 insertions, 107 deletions
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() {
18 // Instance variables 18 // Instance variables
19 /////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////
20 this._Points = []; 20 this._Points = [];
21 this._OrigPoints = [];
21 this._BBoxMin = [0, 0, 0]; 22 this._BBoxMin = [0, 0, 0];
22 this._BBoxMax = [0, 0, 0]; 23 this._BBoxMax = [0, 0, 0];
23 this._dirty = true; 24 this._dirty = true;
25 this._addedSamples = false;
26 this._storedOrigPoints = false;
24 27
25 //whether or not to use the canvas drawing to stroke/fill 28 //whether or not to use the canvas drawing to stroke/fill
26 this._useCanvasDrawing = true; 29 this._useCanvasDrawing = true;
@@ -137,7 +140,8 @@ var BrushStroke = function GLBrushStroke() {
137 }; 140 };
138 141
139 this.insertPoint = function(pt, index){ 142 this.insertPoint = function(pt, index){
140 this._Points.splice(index, 0, pt); this._dirty=true; 143 this._Points.splice(index, 0, pt);
144 this._dirty=true;
141 }; 145 };
142 146
143 this.isDirty = function(){ 147 this.isDirty = function(){
@@ -170,7 +174,7 @@ var BrushStroke = function GLBrushStroke() {
170 }; 174 };
171 175
172 this.setStrokeMaterial = function (m) { 176 this.setStrokeMaterial = function (m) {
173 this._strokeMaterial = m; 177 this._strokeMaterial = m; this._dirty = true;
174 }; 178 };
175 179
176 this.getStrokeColor = function () { 180 this.getStrokeColor = function () {
@@ -178,31 +182,47 @@ var BrushStroke = function GLBrushStroke() {
178 }; 182 };
179 183
180 this.setStrokeColor = function (c) { 184 this.setStrokeColor = function (c) {
181 this._strokeColor = c; 185 this._strokeColor = c; this._dirty = true;
182 }; 186 };
183 187
184 this.setSecondStrokeColor = function(c){ 188 this.setSecondStrokeColor = function(c){
185 this._secondStrokeColor=c; 189 this._secondStrokeColor=c; this._dirty = true;
186 } 190 }
187 191
188 this.setStrokeHardness = function(h){ 192 this.setStrokeHardness = function(h){
189 this._strokeHardness=h; 193 if (this._strokeHardness!==h){
194 this._strokeHardness=h;
195 this._dirty = true;
196 }
190 } 197 }
191 198
192 this.setDoSmoothing = function(s){ 199 this.setDoSmoothing = function(s){
193 this._strokeDoSmoothing = s; 200 if (this._strokeDoSmoothing!==s) {
201 this._strokeDoSmoothing = s;
202 this._dirty = true;
203 }
194 } 204 }
195 205
196 this.setSmoothingAmount = function(a){ 206 this.setSmoothingAmount = function(a){
197 this._strokeAmountSmoothing = a; 207 if (this._strokeAmountSmoothing!==a) {
208 this._strokeAmountSmoothing = a;
209 this._dirty = true;
210 }
211
198 } 212 }
199 213
200 this.setStrokeUseCalligraphic = function(c){ 214 this.setStrokeUseCalligraphic = function(c){
201 this._strokeUseCalligraphic = c; 215 if (this._strokeUseCalligraphic!==c){
216 this._strokeUseCalligraphic = c;
217 this._dirty = true;
218 }
202 } 219 }
203 220
204 this.setStrokeAngle = function(a){ 221 this.setStrokeAngle = function(a){
205 this._strokeAngle = a; 222 if (this._strokeAngle!==a){
223 this._strokeAngle = a;
224 this._dirty = true;
225 };
206 } 226 }
207 227
208 this.getStrokeStyle = function () { 228 this.getStrokeStyle = function () {
@@ -221,133 +241,95 @@ var BrushStroke = function GLBrushStroke() {
221 241
222 };//NO-OP for now 242 };//NO-OP for now
223 243
224
225 //remove and return anchor at specified index, return null on error
226 this.removePoint = function (index) {
227 var retAnchor = null;
228 if (index < this._Points.length) {
229 retPt = this._Points.splice(index, 1);
230 this._dirty=true;
231 }
232 return retPoint;
233 };
234
235 //remove all the points 244 //remove all the points
236 this.clear = function () { 245 this.clear = function () {
237 this._Points = []; 246 this._Points = [];
247 this._OrigPoints = [];
238 this._dirty=true; 248 this._dirty=true;
239 } 249 }
240 250
241 this.translate = function (tx, ty, tz) { 251 /*this.translate = function (tx, ty, tz) {
242 for (var i=0;i<this._Points.length;i++){ 252 for (var i=0;i<this._Points.length;i++){
243 this._Points[i][0]+=tx; 253 this._Points[i][0]+=tx;
244 this._Points[i][1]+=ty; 254 this._Points[i][1]+=ty;
245 this._Points[i][2]+=tz; 255 this._Points[i][2]+=tz;
246 } 256 }
247 }; 257 this._dirty = true;
258 };*/
248 259
249 this.computeMetaGeometry = function() { 260 this.computeMetaGeometry = function() {
250 if (this._dirty) { 261 var numPoints = this._Points.length;
251 var numPoints = this._Points.length; 262 if (this._addedSamples === false){
252 263 //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation *****
253 //**** add samples to the path if needed...linear interpolation for now 264 // instead of the following, may use 4-point subdivision iterations over continuous regions of 'long' segments
254 //if (numPoints>1) { 265 // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula
255 if (0){ 266
256 var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD; 267 var numInsertedPoints = 0;
257 var prevPt = this._Points[0]; 268 var newSampledPoints = [];
258 var prevIndex = 0; 269 var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample is long enough to warrant checking for angle
259 for (var i=1;i<numPoints;i++){ 270 var prevPt = this._Points[0];
260 var pt = this._Points[i]; 271 newSampledPoints.push(this._Points[0]);
261 var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]]; 272 for (var i=1;i<numPoints;i++) {
262 var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]); 273 var pt = this._Points[i];
263 if (distance>threshold){ 274 var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]];
264 //insert points along the prev. to current point 275 var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]);
265 var numNewPoints = Math.floor(distance/threshold); 276 if (distance>threshold){
266 for (var j=0;j<numNewPoints;j++){ 277 //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points)
267 var param = (j+1)/(numNewPoints+1); 278 var prev = (i===1) ? i-1 : i-2;
268 var newpt = [prevPt[0]+ diff[0]*param, prevPt[1]+ diff[1]*param]; 279 var next = (i===numPoints-1) ? i : i+1;
269 //insert new point before point i 280 var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]];
270 this._Points.splice(i, 0, [newpt[0], newpt[1], 0]); 281 //insert points along the prev. to current point
271 i++; 282 var numNewPoints = Math.floor(distance/threshold);
272 } 283 for (var j=0;j<numNewPoints;j++){
273 this._dirty=true; 284 var param = (j+1)/(numNewPoints+1);
274 } 285 var newpt = this._CatmullRomSplineInterpolate(ctrlPts, param);
275 prevPt=pt; 286 newSampledPoints.push(newpt);
276 //update numPoints to match the new length 287 numInsertedPoints++;
277 numPoints = this._Points.length;
278
279 //end this function if the numPoints has gone above the max. size specified
280 if (numPoints> this._MAX_ALLOWED_SAMPLES){
281 console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES);
282 break;
283 } 288 }
284 } 289 }
290 newSampledPoints.push(pt);
291 prevPt=pt;
292
293 //end this function if the numPoints has gone above the max. size specified
294 //if (numPoints> this._MAX_ALLOWED_SAMPLES){
295 // console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES);
296 // break;
297 //}
285 } 298 }
299 this._Points = newSampledPoints.slice(0);
300 newSampledPoints = [];
301 console.log("Inserted "+numInsertedPoints+" additional CatmullRom points");
302 this._addedSamples = true;
303 this._dirty=true;
304 }
305 //build a copy of the original points...this should be done only once
306 if (this._storedOrigPoints === false) {
307 this._OrigPoints = this._Points.slice(0);
308 this._storedOrigPoints = true;
309 }
286 310
287 //instead of the following, may use 4-point subdivision iterations over continuous regions of 'long' segments 311 if (this._dirty) {
288 // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula 312 this._Points = this._OrigPoints.slice(0);
289 //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation 313 numPoints = this._Points.length;
290 if (this._strokeDoSmoothing && numPoints>1) { 314 if (this._strokeDoSmoothing && numPoints>1) {
291 var numInsertedPoints = 0; 315 //iterations of Laplacian smoothing (setting the points to the average of their neighbors)
292 var newPoints = []; 316 var numLaplacianIterations = this._strokeAmountSmoothing;
293 var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample is long enough to warrant checking for angle