diff options
author | Pushkar Joshi | 2012-03-26 16:22:21 -0700 |
---|---|---|
committer | Pushkar Joshi | 2012-03-26 16:22:21 -0700 |
commit | 753244b4713243ab19ca246be674f0b45fb85b72 (patch) | |
tree | d24dd5265b81942b46bad2cc4ddd5a0e731f96f4 | |
parent | 591812255e0e85e52825b1269f29f86fbd0f6182 (diff) | |
download | ninja-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
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 156 |
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; | 460 | newPoints[i] = avgPos; |
519 | } | 461 | } |
520 | this._LocalPoints = newPoints;//.slice(0); | 462 | this._LocalPoints = newPoints.slice(0); |
521 | } | 463 | } |