diff options
Diffstat (limited to 'js/lib')
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 205 |
1 files changed, 94 insertions, 111 deletions
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 4c42539a..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; |
@@ -39,10 +42,7 @@ var BrushStroke = function GLBrushStroke() { | |||
39 | this._strokeDoSmoothing = false; | 42 | this._strokeDoSmoothing = false; |
40 | this._strokeUseCalligraphic = false; | 43 | this._strokeUseCalligraphic = false; |
41 | this._strokeAngle = 0; | 44 | this._strokeAngle = 0; |
42 | 45 | this._strokeAmountSmoothing = 0; | |
43 | //the wetness of the brush (currently this is multiplied to the square of the stroke width, but todo should be changed to not depend on stroke width entirely | ||
44 | //smaller value means more samples for the path | ||
45 | this._WETNESS_FACTOR = 0.25; | ||
46 | 46 | ||
47 | //threshold that tells us whether two samples are too far apart | 47 | //threshold that tells us whether two samples are too far apart |
48 | this._MAX_SAMPLE_DISTANCE_THRESHOLD = 5; | 48 | this._MAX_SAMPLE_DISTANCE_THRESHOLD = 5; |
@@ -125,7 +125,7 @@ var BrushStroke = function GLBrushStroke() { | |||
125 | //add the point only if it is some epsilon away from the previous point | 125 | //add the point only if it is some epsilon away from the previous point |
126 | var numPoints = this._Points.length; | 126 | var numPoints = this._Points.length; |
127 | if (numPoints>0) { | 127 | if (numPoints>0) { |
128 | var threshold = this._MIN_SAMPLE_DISTANCE_THRESHOLD;//this._WETNESS_FACTOR*this._strokeWidth; | 128 | var threshold = this._MIN_SAMPLE_DISTANCE_THRESHOLD; |
129 | var prevPt = this._Points[numPoints-1]; | 129 | var prevPt = this._Points[numPoints-1]; |
130 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; | 130 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; |
131 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); | 131 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); |
@@ -140,7 +140,8 @@ var BrushStroke = function GLBrushStroke() { | |||
140 | }; | 140 | }; |
141 | 141 | ||
142 | this.insertPoint = function(pt, index){ | 142 | this.insertPoint = function(pt, index){ |
143 | this._Points.splice(index, 0, pt); this._dirty=true; | 143 | this._Points.splice(index, 0, pt); |
144 | this._dirty=true; | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | this.isDirty = function(){ | 147 | this.isDirty = function(){ |
@@ -173,7 +174,7 @@ var BrushStroke = function GLBrushStroke() { | |||
173 | }; | 174 | }; |
174 | 175 | ||
175 | this.setStrokeMaterial = function (m) { | 176 | this.setStrokeMaterial = function (m) { |
176 | this._strokeMaterial = m; | 177 | this._strokeMaterial = m; this._dirty = true; |
177 | }; | 178 | }; |
178 | 179 | ||
179 | this.getStrokeColor = function () { | 180 | this.getStrokeColor = function () { |
@@ -181,27 +182,47 @@ var BrushStroke = function GLBrushStroke() { | |||
181 | }; | 182 | }; |
182 | 183 | ||
183 | this.setStrokeColor = function (c) { | 184 | this.setStrokeColor = function (c) { |
184 | this._strokeColor = c; | 185 | this._strokeColor = c; this._dirty = true; |
185 | }; | 186 | }; |
186 | 187 | ||
187 | this.setSecondStrokeColor = function(c){ | 188 | this.setSecondStrokeColor = function(c){ |
188 | this._secondStrokeColor=c; | 189 | this._secondStrokeColor=c; this._dirty = true; |
189 | } | 190 | } |
190 | 191 | ||
191 | this.setStrokeHardness = function(h){ | 192 | this.setStrokeHardness = function(h){ |
192 | this._strokeHardness=h; | 193 | if (this._strokeHardness!==h){ |
194 | this._strokeHardness=h; | ||
195 | this._dirty = true; | ||
196 | } | ||
193 | } | 197 | } |
194 | 198 | ||
195 | this.setDoSmoothing = function(s){ | 199 | this.setDoSmoothing = function(s){ |
196 | this._strokeDoSmoothing = s; | 200 | if (this._strokeDoSmoothing!==s) { |
201 | this._strokeDoSmoothing = s; | ||
202 | this._dirty = true; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | this.setSmoothingAmount = function(a){ | ||
207 | if (this._strokeAmountSmoothing!==a) { | ||
208 | this._strokeAmountSmoothing = a; | ||
209 | this._dirty = true; | ||
210 | } | ||
211 | |||
197 | } | 212 | } |
198 | 213 | ||
199 | this.setStrokeUseCalligraphic = function(c){ | 214 | this.setStrokeUseCalligraphic = function(c){ |
200 | this._strokeUseCalligraphic = c; | 215 | if (this._strokeUseCalligraphic!==c){ |
216 | this._strokeUseCalligraphic = c; | ||
217 | this._dirty = true; | ||
218 | } | ||
201 | } | 219 | } |
202 | 220 | ||
203 | this.setStrokeAngle = function(a){ | 221 | this.setStrokeAngle = function(a){ |
204 | this._strokeAngle = a; | 222 | if (this._strokeAngle!==a){ |
223 | this._strokeAngle = a; | ||
224 | this._dirty = true; | ||
225 | }; | ||
205 | } | 226 | } |
206 | 227 | ||
207 | this.getStrokeStyle = function () { | 228 | this.getStrokeStyle = function () { |
@@ -220,133 +241,95 @@ var BrushStroke = function GLBrushStroke() { | |||
220 | 241 | ||
221 | };//NO-OP for now | 242 | };//NO-OP for now |
222 | 243 | ||
223 | |||
224 | //remove and return anchor at specified index, return null on error | ||
225 | this.removePoint = function (index) { | ||
226 | var retAnchor = null; | ||
227 | if (index < this._Points.length) { | ||
228 | retPt = this._Points.splice(index, 1); | ||
229 | this._dirty=true; | ||
230 | } | ||
231 | return retPoint; | ||
232 | }; | ||
233 | |||
234 | //remove all the points | 244 | //remove all the points |
235 | this.clear = function () { | 245 | this.clear = function () { |
236 | this._Points = []; | 246 | this._Points = []; |
247 | this._OrigPoints = []; | ||
237 | this._dirty=true; | 248 | this._dirty=true; |
238 | } | 249 | } |
239 | 250 | ||
240 | this.translate = function (tx, ty, tz) { | 251 | /*this.translate = function (tx, ty, tz) { |
241 | for (var i=0;i<this._Points.length;i++){ | 252 | for (var i=0;i<this._Points.length;i++){ |
242 | this._Points[i][0]+=tx; | 253 | this._Points[i][0]+=tx; |
243 | this._Points[i][1]+=ty; | 254 | this._Points[i][1]+=ty; |
244 | this._Points[i][2]+=tz; | 255 | this._Points[i][2]+=tz; |
245 | } | 256 | } |
246 | }; | 257 | this._dirty = true; |
258 | };*/ | ||
247 | 259 | ||
248 | this.computeMetaGeometry = function() { | 260 | this.computeMetaGeometry = function() { |
249 | if (this._dirty) { | 261 | var numPoints = this._Points.length; |
250 | var numPoints = this._Points.length; | 262 | if (this._addedSamples === false){ |
251 | 263 | //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation ***** | |
252 | //**** 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 |
253 | //if (numPoints>1) { | 265 | // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula |
254 | if (0){ | 266 | |
255 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; | 267 | var numInsertedPoints = 0; |
256 | var prevPt = this._Points[0]; | 268 | var newSampledPoints = []; |
257 | 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 |
258 | for (var i=1;i<numPoints;i++){ | 270 | var prevPt = this._Points[0]; |
259 | var pt = this._Points[i]; | 271 | newSampledPoints.push(this._Points[0]); |
260 | var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]]; | 272 | for (var i=1;i<numPoints;i++) { |
261 | var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]); | 273 | var pt = this._Points[i]; |
262 | if (distance>threshold){ | 274 | var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]]; |
263 | //insert points along the prev. to current point | 275 | var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]); |
264 | var numNewPoints = Math.floor(distance/threshold); | 276 | if (distance>threshold){ |
265 | for (var j=0;j<numNewPoints;j++){ | 277 | //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points) |
266 | var param = (j+1)/(numNewPoints+1); | 278 | var prev = (i===1) ? i-1 : i-2; |
267 | var newpt = [prevPt[0]+ diff[0]*param, prevPt[1]+ diff[1]*param]; | 279 | var next = (i===numPoints-1) ? i : i+1; |
268 | //insert new point before point i | 280 | var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]]; |
269 | this._Points.splice(i, 0, [newpt[0], newpt[1], 0]); | 281 | //insert points along the prev. to current point |
270 | i++; | 282 | var numNewPoints = Math.floor(distance/threshold); |
271 | } | 283 | for (var j=0;j<numNewPoints;j++){ |
272 | this._dirty=true; | 284 | var param = (j+1)/(numNewPoints+1); |
273 | } | 285 | var newpt = this._CatmullRomSplineInterpolate(ctrlPts, param); |
274 | prevPt=pt; | 286 | newSampledPoints.push(newpt); |
275 | //update numPoints to match the new length | 287 | numInsertedPoints++; |
276 | numPoints = this._Points.length; | ||
277 | |||
278 | //end this function if the numPoints has gone above the max. size specified | ||
279 | if (numPoints> this._MAX_ALLOWED_SAMPLES){ | ||
280 | console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); | ||
281 | break; | ||
282 | } | 288 | } |
283 | } | 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 | //} | ||
284 | } | 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); | ||