diff options
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 177 |
1 files changed, 172 insertions, 5 deletions
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 9a934928..39af5c5c 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js | |||
@@ -32,6 +32,8 @@ var BrushStroke = function GLBrushStroke() { | |||
32 | //stroke information | 32 | //stroke information |
33 | this._strokeWidth = 0.0; | 33 | this._strokeWidth = 0.0; |
34 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; | 34 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; |
35 | this._secondStrokeColor = this._strokeColor; | ||
36 | this._strokeHardness = 100; | ||
35 | this._strokeMaterial = null; | 37 | this._strokeMaterial = null; |
36 | this._strokeStyle = "Solid"; | 38 | this._strokeStyle = "Solid"; |
37 | 39 | ||
@@ -114,7 +116,7 @@ var BrushStroke = function GLBrushStroke() { | |||
114 | //add the point only if it is some epsilon away from the previous point | 116 | //add the point only if it is some epsilon away from the previous point |
115 | var numPoints = this._Points.length; | 117 | var numPoints = this._Points.length; |
116 | if (numPoints>0) { | 118 | if (numPoints>0) { |
117 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; | 119 | var threshold = 1;//this._WETNESS_FACTOR*this._strokeWidth; |
118 | var prevPt = this._Points[numPoints-1]; | 120 | var prevPt = this._Points[numPoints-1]; |
119 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; | 121 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; |
120 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); | 122 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); |
@@ -173,6 +175,14 @@ var BrushStroke = function GLBrushStroke() { | |||
173 | this._strokeColor = c; | 175 | this._strokeColor = c; |
174 | }; | 176 | }; |
175 | 177 | ||
178 | this.setSecondStrokeColor = function(c){ | ||
179 | this._secondStrokeColor=c; | ||
180 | } | ||
181 | |||
182 | this.setStrokeHardness = function(h){ | ||
183 | this._strokeHardness=h; | ||
184 | } | ||
185 | |||
176 | this.getStrokeStyle = function () { | 186 | this.getStrokeStyle = function () { |
177 | return this._strokeStyle; | 187 | return this._strokeStyle; |
178 | }; | 188 | }; |
@@ -219,7 +229,8 @@ var BrushStroke = function GLBrushStroke() { | |||
219 | var numPoints = this._Points.length; | 229 | var numPoints = this._Points.length; |
220 | 230 | ||
221 | //**** add samples to the path if needed...linear interpolation for now | 231 | //**** add samples to the path if needed...linear interpolation for now |
222 | if (numPoints>1) { | 232 | //if (numPoints>1) { |
233 | if (0){ | ||
223 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; | 234 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; |
224 | var prevPt = this._Points[0]; | 235 | var prevPt = this._Points[0]; |
225 | var prevIndex = 0; | 236 | var prevIndex = 0; |
@@ -250,6 +261,44 @@ var BrushStroke = function GLBrushStroke() { | |||
250 | } | 261 | } |
251 | } | 262 | } |
252 | } | 263 | } |
264 | //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation | ||
265 | if (numPoints>1) { | ||
266 | var numInsertedPoints = 0; | ||
267 | var threshold = 5;//0.25*this._strokeWidth; //this determines whether a segment between two sample is too long | ||
268 | var prevPt = this._Points[0]; | ||
269 | for (var i=1;i<numPoints;i++){ | ||
270 | var pt = this._Points[i]; | ||
271 | var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]]; | ||
272 | var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]); | ||
273 | if (distance>threshold){ | ||
274 | //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points) | ||
275 | var prev = (i===1) ? i-1 : i-2; | ||
276 | var next = (i===numPoints-1) ? i : i+1; | ||
277 | var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]]; | ||
278 | //insert points along the prev. to current point | ||
279 | var numNewPoints = Math.floor(distance/threshold); | ||
280 | for (var j=0;j<numNewPoints;j++){ | ||
281 | var param = (j+1)/(numNewPoints+1); | ||
282 | var newpt = this._CatmullRomSplineInterpolate(ctrlPts, param); | ||
283 | //insert new point before point i | ||
284 | this._Points.splice(i, 0, newpt); | ||
285 | i++; | ||
286 | numInsertedPoints++; | ||
287 | } | ||
288 | this._dirty=true; | ||
289 | } | ||
290 | prevPt=pt; | ||
291 | //update numPoints to match the new length | ||
292 | numPoints = this._Points.length; | ||
293 | |||
294 | //end this function if the numPoints has gone above the max. size specified | ||
295 | if (numPoints> this._MAX_ALLOWED_SAMPLES){ | ||
296 | console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | console.log("Inserted "+numInsertedPoints+" additional CatmullRom points"); | ||
301 | } | ||
253 | 302 | ||
254 | // *** compute the bounding box ********* | 303 | // *** compute the bounding box ********* |
255 | this._BBoxMin = [Infinity, Infinity, Infinity]; | 304 | this._BBoxMin = [Infinity, Infinity, Infinity]; |
@@ -412,7 +461,7 @@ var BrushStroke = function GLBrushStroke() { | |||
412 | } | 461 | } |
413 | */ | 462 | */ |
414 | 463 | ||
415 | 464 | /* | |
416 | var R2 = this._strokeWidth; | 465 | var R2 = this._strokeWidth; |
417 | var R = R2*0.5; | 466 | var R = R2*0.5; |
418 | var hardness = 0; //for a pencil, this is always 1 //TODO get hardness parameter from user interface | 467 | var hardness = 0; //for a pencil, this is always 1 //TODO get hardness parameter from user interface |
@@ -440,6 +489,109 @@ var BrushStroke = function GLBrushStroke() { | |||
440 | //ctx.globalCompositeOperation = 'source-in'; | 489 | //ctx.globalCompositeOperation = 'source-in'; |
441 | //ctx.rect(x-R, y-R, R2, R2); | 490 | //ctx.rect(x-R, y-R, R2, R2); |
442 | } | 491 | } |
492 | */ | ||
493 | |||
494 | /* | ||
495 | //build the stamp for the brush stroke | ||
496 | //todo get this directly from the UI | ||
497 | var t=0; | ||
498 | var numTraces = this._strokeWidth; | ||
499 | var halfNumTraces = numTraces/2; | ||
500 | var startPos = [-this._strokeWidth/2,0]; | ||
501 | var brushStamp = []; | ||
502 | |||
503 | //build an angled (calligraphic) brush stamp | ||
504 | var deltaDisplacement = [1,1];//[this._strokeWidth/numTraces, 0]; //a horizontal line brush | ||
505 | for (t=0;t<numTraces;t++){ | ||
506 | var brushPt = [startPos[0]+t*deltaDisplacement[0], startPos[1]+t*deltaDisplacement[1]]; | ||
507 | brushStamp.push(brushPt); | ||
508 | } | ||
509 | |||
510 | |||
511 | //make a circular brush stamp | ||
512 | brushStamp=[]; | ||
513 | numTraces = this._strokeWidth*Math.PI; //figure out how to | ||
514 | var radius = this._strokeWidth/2; | ||
515 | for (t=0;t<numTraces;t++) | ||
516 | { | ||
517 | var angle = Math.PI*(360*t/numTraces)/180; | ||
518 | var brushPt = [radius*Math.cos(angle), radius*Math.sin(angle)]; | ||
519 | brushStamp.push(brushPt); | ||
520 | } | ||
521 | |||
522 | // //make a square brush stamp | ||
523 | // STOPPED HERE | ||
524 | // brushStamp = []; | ||
525 | // numTraces = 4*strokeWidth; | ||
526 | // for (t=0;t<numTraces;t++){ | ||
527 | // if (t<numTraces*0.25){ | ||
528 | // var brushPt = [startPos[0]+t*deltaDisplacement[0], startPos[1]+t*deltaDisplacement[1]]; | ||
529 | // } else if (t<numTraces*0.5){ | ||
530 | // | ||
531 | // } else if (t<numTraces*0.75){ | ||
532 | // | ||
533 | // } else { | ||
534 | // | ||
535 | // } | ||
536 | // brushStamp.push(brushPt); | ||
537 | // } | ||
538 | |||
539 | for (t=0;t<numTraces;t++){ | ||
540 | var disp = [brushStamp[t][0], brushStamp[t][1]]; | ||
541 | //ctx.globalCompositeOperation = 'source-over'; | ||
542 | var distFromMiddle = Math.abs(halfNumTraces-t); | ||
543 | var alphaVal = 1.0 - (100-this._strokeHardness)*(distFromMiddle/halfNumTraces)/100; | ||
544 | alphaVal = 0.2; | ||
545 | ctx.save(); | ||
546 | ctx.lineWidth=this._strokeWidth/10;//todo figure out the correct formula for the line width | ||
547 | if (ctx.lineWidth<2) | ||
548 | ctx.lineWidth=2; | ||
549 | if (t===numTraces-1){ | ||
550 | ctx.lineWidth = 1; | ||
551 | } | ||
552 | ctx.lineJoin="bevel"; | ||
553 | ctx.lineCap="butt"; | ||
554 | //if (t<numTraces/2) | ||
555 | ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; | ||
556 | //else | ||
557 | // ctx.strokeStyle="rgba("+parseInt(255*this._secondStrokeColor[0])+","+parseInt(255*this._secondStrokeColor[1])+","+parseInt(255*this._secondStrokeColor[2])+","+alphaVal+")"; | ||
558 | ctx.translate(disp[0],disp[1]); | ||
559 | ctx.beginPath(); | ||
560 | ctx.moveTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]); | ||
561 | for (var i=0;i<numPoints;i++){ | ||
562 | ctx.lineTo(this._Points[i][0]-bboxMin[0], this._Points[i][1]-bboxMin[1]); | ||
563 | } | ||
564 | ctx.stroke(); | ||
565 | ctx.restore(); | ||
566 | } | ||
567 | */ | ||
568 | |||
569 | /* | ||
570 | //debugging path | ||
571 | ctx.beginPath(); | ||
572 | ctx.moveTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]); | ||
573 | for (var i=1;i<numPoints;i++){ | ||
574 | ctx.lineTo(this._Points[i][0]-bboxMin[0], this._Points[i][1]-bboxMin[1]); | ||
575 | } | ||
576 | ctx.lineWidth=1.0; | ||
577 | ctx.strokeStyle = "black"; | ||
578 | ctx.stroke(); | ||
579 | */ | ||
580 | |||
581 | var numlayers = this._strokeWidth/2; | ||
582 | var alphaVal = 1.0/(numlayers-1); | ||
583 | for (var l=0;l<numlayers;l++){ | ||
584 | ctx.beginPath(); | ||
585 | ctx.moveTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]); | ||
586 | for (var i=1;i<numPoints;i++){ | ||
587 | ctx.lineTo(this._Points[i][0]-bboxMin[0], this._Points[i][1]-bboxMin[1]); | ||
588 | } | ||
589 | ctx.lineCap = "round"; | ||
590 | ctx.lineJoin="round"; | ||
591 | ctx.lineWidth=l+1; | ||
592 | ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; | ||
593 | ctx.stroke(); | ||
594 | } | ||
443 | 595 | ||
444 | ctx.restore(); | 596 | ctx.restore(); |
445 | }; //render() | 597 | }; //render() |
@@ -473,10 +625,25 @@ var BrushStroke = function GLBrushStroke() { | |||
473 | return true; | 625 | return true; |
474 | }; | 626 | }; |
475 | 627 | ||
476 | }; //function GLSubpath ...class definition | 628 | }; //function BrushStroke ...class definition |
477 | 629 | ||
478 | BrushStroke.prototype = new GeomObj(); | 630 | BrushStroke.prototype = new GeomObj(); |
479 | 631 | ||
632 | BrushStroke.prototype._CatmullRomSplineInterpolate = function(ctrlPts, t) | ||
633 | { | ||
634 | //perform CatmullRom interpolation on the spline...assume t is in [0,1] | ||
635 | var t2 = t*t; | ||