From 2dca8a0aa69981bc2a81c4a68f9061aef861f0ea Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Wed, 6 Jun 2012 15:01:10 -0700 Subject: enable gradients for brush stroke (in authoring as well as runtime) --- js/lib/geom/brush-stroke.js | 1406 ++++++++++++++++++++++--------------------- 1 file changed, 732 insertions(+), 674 deletions(-) (limited to 'js/lib/geom') diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 09a7023c..b2e56149 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js @@ -65,777 +65,835 @@ var BrushStroke = function GLBrushStroke() { this._planeMatInv = null; this._planeCenter = null; this._dragPlane = null; +}; //BrushStroke class defition - ///////////////////////////////////////////////////////// - // Property Accessors/Setters - ///////////////////////////////////////////////////////// - this.setCanvas = function(c) { - this._canvas = c; +BrushStroke.prototype = Object.create(GeomObj, {}); + +///////////////////////////////////////////////////////// +// Property Accessors/Setters +///////////////////////////////////////////////////////// +BrushStroke.prototype.setCanvas = function(c) { + this._canvas = c; +}; + +BrushStroke.prototype.setWorld = function (world) { + this._world = world; +}; + +BrushStroke.prototype.getWorld = function () { + return this._world; +}; + +BrushStroke.prototype.geomType = function () { + return this.GEOM_TYPE_BRUSH_STROKE; +}; + +BrushStroke.prototype.setDrawingTool = function (tool) { + this._drawingTool = tool; +}; + +BrushStroke.prototype.getDrawingTool = function () { + return this._drawingTool; +}; + +BrushStroke.prototype.setPlaneMatrix = function(planeMat){ + this._planeMat = planeMat; +}; + +BrushStroke.prototype.setPlaneMatrixInverse = function(planeMatInv){ + this._planeMatInv = planeMatInv; +}; + +BrushStroke.prototype.setPlaneCenter = function(pc){ + this._planeCenter = pc; +}; + +BrushStroke.prototype.setDragPlane = function(p){ + this._dragPlane = p; +}; + +BrushStroke.prototype.getNumPoints = function () { + if (this._LocalPoints.length) + return this._LocalPoints.length; + else + return this._Points.length; +}; + +BrushStroke.prototype.getPoint = function (index) { + return this._Points[index].slice(0); +}; + +BrushStroke.prototype.addPoint = function (pt) { + //add the point only if it is some epsilon away from the previous point + var numPoints = this._Points.length; + if (numPoints>0) { + var threshold = this._MIN_SAMPLE_DISTANCE_THRESHOLD; + var prevPt = this._Points[numPoints-1]; + var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; + var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); + if (diffPtMag>threshold){ + this._Points.push(pt); + this._isDirty=true; + this._isInit = false; + } + } else { + this._Points.push(pt); + this._isDirty=true; + this._isInit = false; } +}; - this.setWorld = function (world) { - this._world = world; - }; +BrushStroke.prototype.insertPoint = function(pt, index){ + this._Points.splice(index, 0, pt); + this._isDirty=true; + this._isInit = false; +}; - this.getWorld = function () { - return this._world; - }; +BrushStroke.prototype.isDirty = function(){ + return this._isDirty; +}; - this.geomType = function () { - return this.GEOM_TYPE_BRUSH_STROKE; - }; +BrushStroke.prototype.makeDirty = function(){ + this._isDirty=true; +}; - this.setDrawingTool = function (tool) { - this._drawingTool = tool; - }; +BrushStroke.prototype.getStageWorldCenter = function() { + return this._stageWorldCenter; +}; - this.getDrawingTool = function () { - return this._drawingTool; - }; +BrushStroke.prototype.getBBoxMin = function () { + return this._BBoxMin; +}; - this.setPlaneMatrix = function(planeMat){ - this._planeMat = planeMat; - }; +BrushStroke.prototype.getBBoxMax = function () { + return this._BBoxMax; +}; - this.setPlaneMatrixInverse = function(planeMatInv){ - this._planeMatInv = planeMatInv; - }; +BrushStroke.prototype.getStrokeWidth = function () { + return this._strokeWidth; +}; - this.setPlaneCenter = function(pc){ - this._planeCenter = pc; - }; +BrushStroke.prototype.setStrokeWidth = function (w) { + this._strokeWidth = w; + if (this._strokeWidth<1) { + this._strokeWidth = 1; + } + this._isDirty=true; +}; - this.setDragPlane = function(p){ - this._dragPlane = p; - }; +BrushStroke.prototype.getStrokeMaterial = function () { + return this._strokeMaterial; +}; - this.getNumPoints = function () { - if (this._LocalPoints.length) - return this._LocalPoints.length; - else - return this._Points.length; - }; +BrushStroke.prototype.setStrokeMaterial = function (m) { + this._strokeMaterial = m; this._isDirty = true; +}; - this.getPoint = function (index) { - return this._Points[index].slice(0); - }; +BrushStroke.prototype.getStrokeColor = function () { + return this._strokeColor; +}; - this.addPoint = function (pt) { - //add the point only if it is some epsilon away from the previous point - var numPoints = this._Points.length; - if (numPoints>0) { - var threshold = this._MIN_SAMPLE_DISTANCE_THRESHOLD; - var prevPt = this._Points[numPoints-1]; - var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; - var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); - if (diffPtMag>threshold){ - this._Points.push(pt); - this._isDirty=true; - this._isInit = false; - } - } else { - this._Points.push(pt); - this._isDirty=true; - this._isInit = false; - } - }; - - this.insertPoint = function(pt, index){ - this._Points.splice(index, 0, pt); - this._isDirty=true; - this._isInit = false; - }; +BrushStroke.prototype.setStrokeColor = function (c) { + this._strokeColor = c; this._isDirty = true; +}; - this.isDirty = function(){ - return this._isDirty; - }; +BrushStroke.prototype.setFillColor = function(c){ + return; +}; //NO-OP for now as we have no fill region - this.makeDirty = function(){ - this._isDirty=true; - }; +BrushStroke.prototype.setSecondStrokeColor = function(c){ + this._secondStrokeColor=c; this._isDirty = true; +}; - this.getStageWorldCenter = function() { - return this._stageWorldCenter; - }; +BrushStroke.prototype.setStrokeHardness = function(h){ + if (this._strokeHardness!==h){ + this._strokeHardness=h; + this._isDirty = true; + } +}; +BrushStroke.prototype.getStrokeHardness = function(){ + return this._strokeHardness; +}; + +BrushStroke.prototype.setDoSmoothing = function(s){ + if (this._strokeDoSmoothing!==s) { + this._strokeDoSmoothing = s; + this._isDirty = true; + } +}; - this.getBBoxMin = function () { - return this._BBoxMin; - }; +BrushStroke.prototype.getDoSmoothing = function(){ + return this._strokeDoSmoothing; +}; - this.getBBoxMax = function () { - return this._BBoxMax; - }; +BrushStroke.prototype.setSmoothingAmount = function(a){ + if (this._strokeAmountSmoothing!==a) { + this._strokeAmountSmoothing = a; + this._isDirty = true; + } +}; - this.getStrokeWidth = function () { - return this._strokeWidth; - }; +BrushStroke.prototype.getSmoothingAmount = function(){ + return this._strokeAmountSmoothing; +}; - this.setStrokeWidth = function (w) { - this._strokeWidth = w; - if (this._strokeWidth<1) { - this._strokeWidth = 1; - } - this._isDirty=true; - }; +BrushStroke.prototype.setStrokeUseCalligraphic = function(c){ + if (this._strokeUseCalligraphic!==c){ + this._strokeUseCalligraphic = c; + this._isDirty = true; + } +}; - this.getStrokeMaterial = function () { - return this._strokeMaterial; +BrushStroke.prototype.setStrokeAngle = function(a){ + if (this._strokeAngle!==a){ + this._strokeAngle = a; + this._isDirty = true; }; +}; - this.setStrokeMaterial = function (m) { - this._strokeMaterial = m; this._isDirty = true; - }; +BrushStroke.prototype.getStrokeUseCalligraphic = function(){ + return this._strokeUseCalligraphic; +}; - this.getStrokeColor = function () { - return this._strokeColor; - }; +BrushStroke.prototype.getStrokeAngle = function(){ + return this._strokeAngle; +}; - this.setStrokeColor = function (c) { - this._strokeColor = c; this._isDirty = true; - }; +BrushStroke.prototype.getStrokeStyle = function () { + return this._strokeStyle; +}; - this.setFillColor = function(c){ - return; - }; //NO-OP for now as we have no fill region +BrushStroke.prototype.setStrokeStyle = function (s) { + this._strokeStyle = s; +}; - this.setSecondStrokeColor = function(c){ - this._secondStrokeColor=c; this._isDirty = true; +BrushStroke.prototype.setWidth = function (newW) { + if (newW<1) { + newW=1; //clamp minimum width to 1 } - this.setStrokeHardness = function(h){ - if (this._strokeHardness!==h){ - this._strokeHardness=h; - this._isDirty = true; - } - } - this.getStrokeHardness = function(){ - return this._strokeHardness; + //scale the contents of this subpath to lie within this width + //determine the scale factor by comparing with the old width + var oldWidth = this._BBoxMax[0]-this._BBoxMin[0]; + if (oldWidth<1) { + oldWidth=1; } - this.setDoSmoothing = function(s){ - if (this._strokeDoSmoothing!==s) { - this._strokeDoSmoothing = s; - this._isDirty = true; - } + var scaleX = newW/oldWidth; + if (scaleX===1) { + return; //no need to do anything } - this.getDoSmoothing = function(){ - return this._strokeDoSmoothing; - } + //scale the local point positions such that the width of the bbox is the newW + var origX = this._BBoxMin[0]; + var numPoints = this._LocalPoints.length; + for (var i=0;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._isDirty = true; - }; + } + this._Points = newSampledPoints.slice(0); + newSampledPoints = []; +}; - this.getWidth = function() { - if (this._isDirty){ - this.update(); - } - return this._BBoxMax[0]-this._BBoxMin[0]; - }; +BrushStroke.prototype.init = function(){ + if (!this._isInit){ + // **** add samples to the _Points in stageworld space **** + this._addSamples(); - this.getHeight = function() { - if (this._isDirty){ - this.update(); - } - return this._BBoxMax[1]-this._BBoxMin[1]; - }; + // **** compute the 2D (canvas space) coord. of the _Points **** + this._buildLocalCoordFromStageWorldCoord(); - //remove all the points - this.clear = function () { - this._Points = []; - this._OrigLocalPoints = []; - this._isDirty=true; - this._isInit = false; - }; + // **** turn off the init. flag **** + this._isInit = true; + this._isDirty= true; + } - this._addSamples = function() { - //**** 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 numPoints = this._Points.length; - var numInsertedPoints = 0; - var newSampledPoints = []; - var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample too long - 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 pt[d]) { + bboxMin[d] = pt[d]; } - newSampledPoints.push(pt); - prevPt=pt; - - //end this function if the numPoints has gone above the max. size specified - if (numPoints> this._MAX_ALLOWED_SAMPLES){ - console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); - break; + if (bboxMax[d] < pt[d]) { + bboxMax[d] = pt[d]; } } - this._Points = newSampledPoints.slice(0); - newSampledPoints = []; - }; + } + //save the center of the bbox for later use (while constructing the canvas) + this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5); + + // ***** center the input stageworld data about the center of the bbox ***** + this._LocalPoints = []; + for (i=0;i1) { + this._copyCoordinates3D(this._OrigLocalPoints , this._LocalPoints); + //iterations of Laplacian smoothing (setting the points to the average of their neighbors) + var numLaplacianIterations = this._strokeAmountSmoothing; + for (var n=0;n pt[d]) { - bboxMin[d] = pt[d]; + if (this._BBoxMin[d] > pt[d]) { + this._BBoxMin[d] = pt[d]; } - if (bboxMax[d] < pt[d]) { - bboxMax[d] = pt[d]; + if (this._BBoxMax[d] < pt[d]) { + this._BBoxMax[d] = pt[d]; } - } - } - //save the center of the bbox for later use (while constructing the canvas) - this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5); - - // ***** center the input stageworld data about the center of the bbox ***** - this._LocalPoints = []; - for (i=0;i1) { - this._copyCoordinates3D(this._OrigLocalPoints , this._LocalPoints); - //iterations of Laplacian smoothing (setting the points to the average of their neighbors) - var numLaplacianIterations = this._strokeAmountSmoothing; - for (var n=0;n pt[d]) { - this._BBoxMin[d] = pt[d]; - } - if (this._BBoxMax[d] < pt[d]) { - this._BBoxMax[d] = pt[d]; - } - }//for every dimension d from 0 to 2 - } - } +//buildColor returns the fillStyle or strokeStyle for the Canvas 2D context +BrushStroke.prototype.buildColor = function(ctx, //the 2D rendering context (for creating gradients if necessary) + ipColor, //color string, also encodes whether there's a gradient and of what type + w, //width of the region of color + h, //height of the region of color + lw, //linewidth (i.e. stroke width/size) + alphaVal) //alpha value for this color (usually computed by the rendering code separately) +{ + if (ipColor.gradientMode){ + var position, gradient, cs, inset; //vars used in gradient calculations + inset = Math.ceil( lw ) - 0.5; - //increase the bbox given the stroke width and the angle (in case of calligraphic brush) - var bboxPadding = this._strokeWidth/2; - //todo TEMP! - //bboxPadding = 0; //for now, ignore the effect of stroke width on bounding box - //end todo TEMP - //if (this._strokeUseCalligraphic) { - //todo re-enable this if check once we are able to change the left and top of the brush canvas - if (false){ - this._BBoxMin[0]-= bboxPadding*Math.cos(this._strokeAngle); - this._BBoxMin[1]-= bboxPadding*Math.sin(this._strokeAngle); - this._BBoxMax[0]+= bboxPadding*Math.cos(this._strokeAngle); - this._BBoxMax[1]+= bboxPadding*Math.sin(this._strokeAngle); + if(ipColor.gradientMode === "radial") { + var ww = w - 2*lw, hh = h - 2*lw; + gradient = ctx.createRadialGradient(w*0.5, h*0.5, 0, w*0.5, h*0.5, Math.max(ww, hh)*0.5); } else { - for (var d = 0; d < 3; d++) { - this._BBoxMin[d]-= bboxPadding; - this._BBoxMax[d]+= bboxPadding; - }//for every dimension d from 0 to 2 + gradient = ctx.createLinearGradient(inset, h*0.5, w-inset, h*0.5); } - }; + var colors = ipColor.color; - this.buildBuffers = function () { - //return; //no need to do anything for now - };//buildBuffers() - - //render - // specify how to render the subpath in Canvas2D - this.render = function () { - // get the world - var world = this.getWorld(); - if (!world){ - throw( "null world in brushstroke render" ); - } - - var numPoints = this.getNumPoints(); - if (numPoints === 0) { - return; //nothing to do for empty paths - } - - if (this._isDirty){ - this.update(); - } - var bboxMin = this.getBBoxMin(); - var bboxMax = this.getBBoxMax(); - var bboxWidth = bboxMax[0] - bboxMin[0]; - var bboxHeight = bboxMax[1] - bboxMin[1]; - - if (!this._canvas){ - //set the canvas by querying the world - this._canvas = this.getWorld().getCanvas(); - } - if (this._canvas) { - var newLeft = Math.round(this._stageWorldCenter[0] - 0.5 * bboxWidth); - var newTop = Math.round(this._stageWorldCenter[1] - 0.5 * bboxHeight); - //assign the new position, width, and height as the canvas dimensions through the canvas controller - //CanvasController.setProperty(this._canvas, "left", newLeft+"px"); - //CanvasController.setProperty(this._canvas, "top", newTop+"px"); - - CanvasController.setProperty(this._canvas, "width", bboxWidth+"px"); - CanvasController.setProperty(this._canvas, "height", bboxHeight+"px"); - //this._canvas.elementModel.shapeModel.GLWorld.setViewportFromCanvas(this._canvas); + var len = colors.length; + for(n=0; n0) { + var transparencyFactor = distFromOpaqueRegion/maxTransparentRegionHalfWidth; + alphaVal = 1.0 - transparencyFactor;//(transparencyFactor*transparencyFactor);//the square term produces nonlinearly varying alpha values + alphaVal *= 0.5; //factor that accounts for lineWidth == 2 + } + ctx.save(); + if (t === (numTraces-1) || t === 0){ + ctx.lineWidth = 1; + } else { + //todo figure out the correct formula for the line width + ctx.lineWidth=2; } - ctx.lineJoin="bevel"; - ctx.lineCap="butt"; - ctx.globalCompositeOperation = 'source-over'; - ctx.globalAlpha = this._strokeColor[3]; - - for (t=0;t0) { - var transparencyFactor = distFromOpaqueRegion/maxTransparentRegionHalfWidth; - alphaVal = 1.0 - transparencyFactor;//(transparencyFactor*transparencyFactor);//the square term produces nonlinearly varying alpha values - alphaVal *= 0.5; //factor that accounts for lineWidth == 2 - } - ctx.save(); - if (t === (numTraces-1) || t === 0){ - ctx.lineWidth = 1; - } else { - //todo figure out the correct formula for the line width - ctx.lineWidth=2; - } + if (!useBuildColor){ ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; - //linearly interpolate between the two stroke colors - var currStrokeColor = VecUtils.vecInterpolate(4, this._strokeColor, this._secondStrokeColor, t/numTraces); - //ctx.strokeStyle="rgba("+parseInt(255*currStrokeColor[0])+","+parseInt(255*currStrokeColor[1])+","+parseInt(255*currStrokeColor[2])+","+alphaVal+")"; - ctx.translate(disp[0],disp[1]); - ctx.beginPath(); + } else { + ctx.strokeStyle = this.buildColor(ctx, this._strokeColor, w, h, this._strokeWidth, alphaVal); + } + //linearly interpolate between the two stroke colors + var currStrokeColor = VecUtils.vecInterpolate(4, this._strokeColor, this._secondStrokeColor, t/numTraces); + //ctx.strokeStyle="rgba("+parseInt(255*currStrokeColor[0])+","+parseInt(255*currStrokeColor[1])+","+parseInt(255*currStrokeColor[2])+","+alphaVal+")"; + ctx.translate(disp[0],disp[1]); + ctx.beginPath(); + if (drawStageWorldPts) { + tempP = points[0].slice(0); + tempP[0]+=stageWorldDeltaX; tempP[1]+=stageWorldDeltaY; + p = MathUtils.transformAndDivideHomogeneousPoint(tempP, stageWorldToScreenMat); + } else { + p = points[0]; + } + ctx.moveTo(p[0],p[1]); + for (var i=0;i - - retObject.stageWorldCenter = [this._stageWorldCenter[0],this._stageWorldCenter[1],this._stageWorldCenter[2]]; - retObject.planeMat = this._planeMat; - retObject.planeMatInv = this._planeMatInv; - retObject.dragPlane = [this._dragPlane[0],this._dragPlane[1],this._dragPlane[2],this._dragPlane[3]]; - - //stroke appearance properties - retObject.strokeWidth = this._strokeWidth; - retObject.strokeColor = this._strokeColor; - retObject.strokeHardness = this._strokeHardness; - retObject.strokeUseCalligraphic = this._strokeUseCalligraphic; - retObject.strokeAngle = this._strokeAngle; - - //stroke smoothing properties - retObject.strokeDoSmoothing = this._strokeDoSmoothing; - retObject.strokeAmountSmoothing = this._strokeAmountSmoothing; - - return retObject; - }; - - this.importJSON = function(jo){ - if (this.geomType()!== jo.geomType){ - return; - } - //the geometry for this object - this._LocalPoints = jo.localPoints.slice(0); - this._copyCoordinates3D(jo.localPoints, this._LocalPoints); //todo is this necessary in addition to the slice(0) above? - this._OrigLocalPoints = jo.origLocalPoints.slice(0); - this._copyCoordinates3D(jo.origLocalPoints, this._OrigLocalPoints); //todo - - this._stageWorldCenter = [jo.stageWorldCenter[0],jo.stageWorldCenter[1],jo.stageWorldCenter[2]]; - this._planeMat = jo.planeMat; - this._planeMatInv = jo.planeMatInv; - this._dragPlane = [jo.dragPlane[0],jo.dragPlane[1],jo.dragPlane[2],jo.dragPlane[3]]; - - //stroke appearance properties - this._strokeWidth = jo.strokeWidth; - this._strokeColor = jo.strokeColor; - this._strokeHardness = jo.strokeHardness; - this._strokeUseCalligraphic = jo.strokeUseCalligraphic; - this._strokeAngle = jo.strokeAngle; - - //stroke smoothing properties - this._strokeDoSmoothing = jo.strokeDoSmoothing; - this._strokeAmountSmoothing = jo.strokeAmountSmoothing; - - this._isInit = true; //do not re-initialize this brush stroke - this._isDirty = true; //force a re-computation of meta-geometry before rendering - this.update(); //after this, the stroke is ready to be rendered - }; - - this.collidesWithPoint = function (x, y, z) { - if (x < this._BBoxMin[0]) return false; - if (x > this._BBoxMax[0]) return false; - if (y < this._BBoxMin[1]) return false; - if (y > this._BBoxMax[1]) return false; - if (z < this._BBoxMin[2]) return false; - if (z > this._BBoxMax[2]) return false; - - return true; - }; - - this.collidesWithPoint = function (x, y) { - if (x < this._BBoxMin[0]) return false; - if (x > this._BBoxMax[0]) return false; - if (y < this._BBoxMin[1]) return false; - if (y > this._BBoxMax[1]) return false; - - return true; - }; - -}; //function BrushStroke ...class definition - -BrushStroke.prototype = Object.create(GeomObj, {}); + ctx.lineTo(p[0],p[1]); + } + ctx.lineWidth=2*l+minStrokeWidth; + + + //experiments with shadows + /* + ctx.shadowOffsetX = 10; + ctx.shadowOffsetY = 10; + ctx.shadowBlur = 10; + ctx.shadowColor = //"rgb("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+")"; + "#FF6666"; //or use rgb(red, green, blue) + */ + ctx.stroke(); + }//for every layer l + } //if there is no calligraphic stroke +}; //this.drawToCanvas() + + +BrushStroke.prototype.exportJSON = function(){ + var retObject= new Object(); + //the type of this object + retObject.type = this.geomType(); + retObject.geomType = retObject.type; + + //the geometry for this object + retObject.localPoints = this._LocalPoints.slice(0); + this._copyCoordinates3D(this._LocalPoints, retObject.localPoints); //todo is this necessary in addition to the slice(0) above? + retObject.origLocalPoints = this._OrigLocalPoints.slice(0); + this._copyCoordinates3D(this._OrigLocalPoints, retObject.origLocalPoints); //todo + + retObject.stageWorldCenter = [this._stageWorldCenter[0],this._stageWorldCenter[1],this._stageWorldCenter[2]]; + retObject.planeMat = this._planeMat; + retObject.planeMatInv = this._planeMatInv; + retObject.dragPlane = [this._dragPlane[0],this._dragPlane[1],this._dragPlane[2],this._dragPlane[3]]; + + //stroke appearance properties + retObject.strokeWidth = this._strokeWidth; + retObject.strokeColor = this._strokeColor; + retObject.strokeHardness = this._strokeHardness; + retObject.strokeUseCalligraphic = this._strokeUseCalligraphic; + retObject.strokeAngle = this._strokeAngle; + + //stroke smoothing properties + retObject.strokeDoSmoothing = this._strokeDoSmoothing; + retObject.strokeAmountSmoothing = this._strokeAmountSmoothing; + + return retObject; +}; + +BrushStroke.prototype.importJSON = function(jo){ + if (this.geomType()!== jo.geomType){ + return; + } + //the geometry for this object + this._LocalPoints = jo.localPoints.slice(0); + this._copyCoordinates3D(jo.localPoints, this._LocalPoints); //todo is this necessary in addition to the slice(0) above? + this._OrigLocalPoints = jo.origLocalPoints.slice(0); + this._copyCoordinates3D(jo.origLocalPoints, this._OrigLocalPoints); //todo + + this._stageWorldCenter = [jo.stageWorldCenter[0],jo.stageWorldCenter[1],jo.stageWorldCenter[2]]; + this._planeMat = jo.planeMat; + this._planeMatInv = jo.planeMatInv; + this._dragPlane = [jo.dragPlane[0],jo.dragPlane[1],jo.dragPlane[2],jo.dragPlane[3]]; + + //stroke appearance properties + this._strokeWidth = jo.strokeWidth; + this._strokeColor = jo.strokeColor; + this._strokeHardness = jo.strokeHardness; + this._strokeUseCalligraphic = jo.strokeUseCalligraphic; + this._strokeAngle = jo.strokeAngle; + + //stroke smoothing properties + this._strokeDoSmoothing = jo.strokeDoSmoothing; + this._strokeAmountSmoothing = jo.strokeAmountSmoothing; + + this._isInit = true; //do not re-initialize this brush stroke + this._isDirty = true; //force a re-computation of meta-geometry before rendering + this.update(); //after this, the stroke is ready to be rendered +}; + +BrushStroke.prototype.collidesWithPoint = function (x, y, z) { + if (x < this._BBoxMin[0]) return false; + if (x > this._BBoxMax[0]) return false; + if (y < this._BBoxMin[1]) return false; + if (y > this._BBoxMax[1]) return false; + if (z < this._BBoxMin[2]) return false; + if (z > this._BBoxMax[2]) return false; + + return true; +}; + +BrushStroke.prototype.collidesWithPoint = function (x, y) { + if (x < this._BBoxMin[0]) return false; + if (x > this._BBoxMax[0]) return false; + if (y < this._BBoxMin[1]) return false; + if (y > this._BBoxMax[1]) return false; + + return true; +}; BrushStroke.prototype._CatmullRomSplineInterpolate = function(ctrlPts, t) { -- cgit v1.2.3