aboutsummaryrefslogtreecommitdiff
path: root/js/lib/geom/brush-stroke.js
diff options
context:
space:
mode:
authorPushkar Joshi2012-03-26 16:22:21 -0700
committerPushkar Joshi2012-03-26 16:22:21 -0700
commit753244b4713243ab19ca246be674f0b45fb85b72 (patch)
treed24dd5265b81942b46bad2cc4ddd5a0e731f96f4 /js/lib/geom/brush-stroke.js
parent591812255e0e85e52825b1269f29f86fbd0f6182 (diff)
downloadninja-753244b4713243ab19ca246be674f0b45fb85b72.tar.gz
correctly update the brush stroke canvas size and position when the stroke path is smoothed (and also when the stroke width is changed) AND some code cleanup to remove unnecessary brush stroke properties
Diffstat (limited to 'js/lib/geom/brush-stroke.js')
-rwxr-xr-xjs/lib/geom/brush-stroke.js156
1 files changed, 38 insertions, 118 deletions
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js
index f0925ba5..70429ca9 100755
--- a/js/lib/geom/brush-stroke.js
+++ b/js/lib/geom/brush-stroke.js
@@ -28,20 +28,12 @@ var BrushStroke = function GLBrushStroke() {
28 this._BBoxMax = [0, 0, 0]; 28 this._BBoxMax = [0, 0, 0];
29 this._isDirty = true; 29 this._isDirty = true;
30 this._isInit = false; 30 this._isInit = false;
31 31
32
33 //whether or not to use the canvas drawing to stroke/fill
34 this._useCanvasDrawing = true;
35
36 //the HTML5 canvas that holds this brush stroke 32 //the HTML5 canvas that holds this brush stroke
37 this._canvas = null; 33 this._canvas = null;
38 34
39 //the X and Y location of this brush stroke canvas in stage world space of Ninja
40 this._canvasX = 0;
41 this._canvasY = 0;
42
43 //stroke information 35 //stroke information
44 this._strokeWidth = 0.0; 36 this._strokeWidth = 1.0;
45 this._strokeColor = [0.4, 0.4, 0.4, 1.0]; 37 this._strokeColor = [0.4, 0.4, 0.4, 1.0];
46 this._secondStrokeColor = [1, 0.4, 0.4, 1.0]; 38 this._secondStrokeColor = [1, 0.4, 0.4, 1.0];
47 this._strokeHardness = 100; 39 this._strokeHardness = 100;
@@ -114,22 +106,6 @@ var BrushStroke = function GLBrushStroke() {
114 this._dragPlane = p; 106 this._dragPlane = p;
115 }; 107 };
116 108
117 this.getCanvasX = function(){
118 return this._canvasX;
119 };
120
121 this.getCanvasY = function(){
122 return this._canvasY;
123 };
124
125 this.setCanvasX = function(cx){
126 this._canvasX=cx;
127 };
128
129 this.setCanvasY = function(cy){
130 this._canvasY=cy;
131 };
132
133 this.getNumPoints = function () { 109 this.getNumPoints = function () {
134 return this._Points.length; 110 return this._Points.length;
135 }; 111 };
@@ -190,6 +166,9 @@ var BrushStroke = function GLBrushStroke() {
190 166
191 this.setStrokeWidth = function (w) { 167 this.setStrokeWidth = function (w) {
192 this._strokeWidth = w; 168 this._strokeWidth = w;
169 if (this._strokeWidth<1) {
170 this._strokeWidth = 1;
171 }
193 this._isDirty=true; 172 this._isDirty=true;
194 }; 173 };
195 174
@@ -402,83 +381,37 @@ var BrushStroke = function GLBrushStroke() {
402 this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5); 381 this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5);
403 382
404 // ***** center the input stageworld data about the center of the bbox ***** 383 // ***** center the input stageworld data about the center of the bbox *****
405 this._LocalPoints = this._Points.slice(0); 384 this._LocalPoints = [];
406 for (i=0;i<numPoints;i++){ 385 for (i=0;i<numPoints;i++){
407 this._LocalPoints[i][0]-= this._stageWorldCenter[0]; 386 var localPoint = [this._Points[i][0],this._Points[i][1],this._Points[i][2]];
408 this._LocalPoints[i][1]-= this._stageWorldCenter[1]; 387 localPoint[0]-= this._stageWorldCenter[0];
409 } 388 localPoint[1]-= this._stageWorldCenter[1];
410 389
411 // ***** unproject all the centered points and convert them to 2D (plane space)***** 390 // ***** unproject all the centered points and convert them to 2D (plane space)*****
412 // (undo the projection step performed by the browser) 391 // (undo the projection step performed by the browser)
413 for (i=0;i<numPoints;i++) { 392 localPoint = this._unprojectPt(localPoint, 1400); //todo get the perspective distance from the canvas
414 this._LocalPoints[i] = this._unprojectPt(this._LocalPoints[i], 1400); //todo get the perspective distance from the canvas 393 localPoint = MathUtils.transformPoint(localPoint, this._planeMatInv);
415 this._LocalPoints[i] = MathUtils.transformPoint(this._LocalPoints[i], this._planeMatInv); 394
395 //add to the list of local points
396 this._LocalPoints.push(localPoint);
416 } 397 }
417 398
418 // ***** compute width, height, and midpoint position (in stage world position) of the canvas 399 // ***** compute width, height, and midpoint position (in stage world position) of the canvas
419 this._updateBoundingBox(); //compute the bbox to obtain the width and height used below 400 this._updateBoundingBox(); //compute the bbox to obtain the width and height used below
420 var halfwidth = 0.5*(this._BBoxMax[0]-this._BBoxMin[0]); 401 var halfwidth = 0.5*(this._BBoxMax[0]-this._BBoxMin[0]);
421 var halfheight = 0.5*(this._BBoxMax[1]-this._BBoxMin[1]); 402 var halfheight = 0.5*(this._BBoxMax[1]-this._BBoxMin[1]);
403 this._OrigPoints = [];
422 for (i=0;i<numPoints;i++) { 404 for (i=0;i<numPoints;i++) {
423 this._LocalPoints[i][0]+= halfwidth; 405 this._LocalPoints[i][0]+= halfwidth;
424 this._LocalPoints[i][1]+= halfheight; 406 this._LocalPoints[i][1]+= halfheight;
425 }
426 //store the original points
427 this._OrigPoints = this._LocalPoints.slice(0);
428
429 //var midPt = stageWorldBBoxCenter; //todo should I compute the instead as the midpoint of the plane-space bbox, transformed by this._planeMat
430 // The following offset seems to not match what was being done successfully for the brush tool, so I'm commenting this out
431 // the mid point is now relative to the center of the 3D space. To
432 // calculate the left and top offsets, this must be offset by the stage dimensions
433 //var wh = ViewUtils.getStageDimension();
434 //midPt[0] += wh[0]/ 2.0;
435 //midPt[1] += wh[1]/ 2.0;
436 };
437 /*this.translate = function (tx, ty, tz) {
438 for (var i=0;i<this._Points.length;i++){
439 this._Points[i][0]+=tx;
440 this._Points[i][1]+=ty;
441 this._Points[i][2]+=tz;
442 }
443 this._isDirty = true;
444 };*/
445
446 //build coordinates for the brush stroke in local space of the canvas...will assume that the canvas width, height, left and top will not be changed now
447 this.buildLocalCoord = function(){
448 /*
449 if (this._isLocalDirty) {
450 //DEBUGGING
451 //confirm that localToStageWorld produces the same coordinates as those I used for rendering currently
452 var numPoints = this._Points.length;
453 var objToStageWorldMat = ViewUtils.getObjToStageWorldMatrix(this._canvas, true);
454 var stageworldToObjMat = glmat4.inverse(objToStageWorldMat, []);
455 var wh = ViewUtils.getStageDimension();
456 for (var i=0;i<numPoints;i++) {
457 var origStageWorldPt = this._Points[i];
458 //var localPt = [origStageWorldPt[0]-bboxMin[0], origStageWorldPt[1]-bboxMin[1],0]; //this is how the brush tool currently renders points in stage world
459
460 //check using ObjToStageWorldMatrix --- works
461 //var tmp = MathUtils.transformHomogeneousPoint(localPt,objToStageWorldMat);
462 //var newStageWorldPt = MathUtils.applyHomogeneousCoordinate(tmp);
463 //newStageWorldPt = VecUtils.vecAdd(3, newStageWorldPt, [wh[0]/2, wh[1]/2, 0]);
464 //var diffPt = VecUtils.vecDist(3,origStageWorldPt,newStageWorldPt);
465
466 //now go the other way, to recover localPt
467 var offsetedStageWorldPt = VecUtils.vecSubtract(3, origStageWorldPt, [wh[0]/2, wh[1]/2, 0]);
468 var tmp = MathUtils.transformHomogeneousPoint(offsetedStageWorldPt,stageworldToObjMat);
469 var newLocalPt = MathUtils.applyHomogeneousCoordinate(tmp);
470 //var diffPt2 = VecUtils.vecDist(3,localPt,newLocalPt);
471 this._LocalPoints[i] = newLocalPt;
472 }
473 407
474 408 //store the original points
475 //end DEBUGGING 409 this._OrigPoints.push([this._LocalPoints[i][0],this._LocalPoints[i][1],this._LocalPoints[i][2]]);
476 this._isLocalDirty=false; 410 }
477 } //if this._isLocalDirty 411 //update the bbox with the same adjustment as was made for the local points above
478 */ 412 this._BBoxMax[0]+= halfwidth;this._BBoxMin[0]+= halfwidth;
413 this._BBoxMax[1]+= halfheight;this._BBoxMin[1]+= halfheight;
479 }; 414 };
480
481
482 415
483 this.update = function() { 416 this.update = function() {
484 if (this._isDirty){ 417 if (this._isDirty){
@@ -486,10 +419,10 @@ var BrushStroke = function GLBrushStroke() {
486 this._doSmoothing(); 419 this._doSmoothing();
487 420
488 // **** recompute the bounding box **** 421 // **** recompute the bounding box ****
489 var deltaWH = this._updateBoundingBox(); 422 this._updateBoundingBox();
490 423
491 // **** offset the local coords to account for the change in bbox **** 424 // **** offset the local coords to account for the change in bbox ****
492 this._offsetLocalCoord(deltaWH[0]*0.5, deltaWH[1]*0.5); 425 this._offsetLocalCoord(-this._BBoxMin[0], -this._BBoxMin[1]);
493 426
494 // **** turn off the dirty flag **** 427 // **** turn off the dirty flag ****
495 this._isDirty = false; 428 this._isDirty = false;
@@ -503,21 +436,30 @@ var BrushStroke = function GLBrushStroke() {
503 this._LocalPoints[i][1]+= deltaH; 436 this._LocalPoints[i][1]+= deltaH;
504 } 437 }
505 }; 438 };
439
440 //I had to write this function to do a deep copy because I think slice(0) creates a copy by reference
441 this._copyCoordinates3D = function(srcCoord, destCoord){
442 var i=0;
443 var numPoints = srcCoord.length;
444 for (i=0;i<numPoints;i++){
445 destCoord[i] = [srcCoord[i][0],srcCoord[i][1],srcCoord[i][2]];
446 }
447 };
506 this._doSmoothing = function() { 448 this._doSmoothing = function() {
507 var numPoints = this._LocalPoints.length; 449 var numPoints = this._LocalPoints.length;
508 if (this._strokeDoSmoothing && numPoints>1) { 450 if (this._strokeDoSmoothing && numPoints>1) {
509 this._LocalPoints = this._OrigPoints.slice(0); 451 this._copyCoordinates3D(this._OrigPoints, this._LocalPoints);
510 //iterations of Laplacian smoothing (setting the points to the average of their neighbors) 452 //iterations of Laplacian smoothing (setting the points to the average of their neighbors)
511 var numLaplacianIterations = this._strokeAmountSmoothing; 453 var numLaplacianIterations = this._strokeAmountSmoothing;
512 for (var n=0;n<numLaplacianIterations;n++){ 454 for (var n=0;n<numLaplacianIterations;n++){
513 var newPoints = this._LocalPoints;//.slice(0); 455 var newPoints = this._LocalPoints.slice(0); //I think this performs a copy by reference, which would make the following a SOR step
514 for (var i=1;i<numPoints-1;i++) { 456 for (var i=1;i<numPoints-1;i++) {
515 var avgPos = [ 0.5*(this._LocalPoints[i-1][0] + this._LocalPoints[i+1][0]), 457 var avgPos = [ 0.5*(this._LocalPoints[i-1][0] + this._LocalPoints[i+1][0]),
516 0.5*(this._LocalPoints[i-1][1] + this._LocalPoints[i+1][1]), 458 0.5*(this._LocalPoints[i-1][1] + this._LocalPoints[i+1][1]),
517 0.5*(this._LocalPoints[i-1][2] + this._LocalPoints[i+1][2])] ; 459 0.5*(this._LocalPoints[i-1][2] + this._LocalPoints[i+1][2])] ;
518 newPoints[i] = avgPos;