| function bezFunction(){ |
| |
| var easingFunctions = []; |
| var math = Math; |
| |
| function pointOnLine2D(x1,y1, x2,y2, x3,y3){ |
| var det1 = (x1*y2) + (y1*x3) + (x2*y3) - (x3*y2) - (y3*x1) - (x2*y1); |
| return det1 > -0.001 && det1 < 0.001; |
| } |
| |
| function pointOnLine3D(x1,y1,z1, x2,y2,z2, x3,y3,z3){ |
| if(z1 === 0 && z2 === 0 && z3 === 0) { |
| return pointOnLine2D(x1,y1, x2,y2, x3,y3); |
| } |
| var dist1 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); |
| var dist2 = Math.sqrt(Math.pow(x3 - x1, 2) + Math.pow(y3 - y1, 2) + Math.pow(z3 - z1, 2)); |
| var dist3 = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2) + Math.pow(z3 - z2, 2)); |
| var diffDist; |
| if(dist1 > dist2){ |
| if(dist1 > dist3){ |
| diffDist = dist1 - dist2 - dist3; |
| } else { |
| diffDist = dist3 - dist2 - dist1; |
| } |
| } else if(dist3 > dist2){ |
| diffDist = dist3 - dist2 - dist1; |
| } else { |
| diffDist = dist2 - dist1 - dist3; |
| } |
| return diffDist > -0.0001 && diffDist < 0.0001; |
| } |
| |
| var getBezierLength = (function(){ |
| |
| return function(pt1,pt2,pt3,pt4){ |
| var curveSegments = defaultCurveSegments; |
| var k; |
| var i, len; |
| var ptCoord,perc,addedLength = 0; |
| var ptDistance; |
| var point = [],lastPoint = []; |
| var lengthData = bezier_length_pool.newElement(); |
| len = pt3.length; |
| for(k=0;k<curveSegments;k+=1){ |
| perc = k/(curveSegments-1); |
| ptDistance = 0; |
| for(i=0;i<len;i+=1){ |
| ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*pt3[i]+3*(1-perc)*bm_pow(perc,2)*pt4[i]+bm_pow(perc,3)*pt2[i]; |
| point[i] = ptCoord; |
| if(lastPoint[i] !== null){ |
| ptDistance += bm_pow(point[i] - lastPoint[i],2); |
| } |
| lastPoint[i] = point[i]; |
| } |
| if(ptDistance){ |
| ptDistance = bm_sqrt(ptDistance); |
| addedLength += ptDistance; |
| } |
| lengthData.percents[k] = perc; |
| lengthData.lengths[k] = addedLength; |
| } |
| lengthData.addedLength = addedLength; |
| return lengthData; |
| }; |
| }()); |
| |
| function getSegmentsLength(shapeData) { |
| var segmentsLength = segments_length_pool.newElement(); |
| var closed = shapeData.c; |
| var pathV = shapeData.v; |
| var pathO = shapeData.o; |
| var pathI = shapeData.i; |
| var i, len = shapeData._length; |
| var lengths = segmentsLength.lengths; |
| var totalLength = 0; |
| for(i=0;i<len-1;i+=1){ |
| lengths[i] = getBezierLength(pathV[i],pathV[i+1],pathO[i],pathI[i+1]); |
| totalLength += lengths[i].addedLength; |
| } |
| if(closed && len){ |
| lengths[i] = getBezierLength(pathV[i],pathV[0],pathO[i],pathI[0]); |
| totalLength += lengths[i].addedLength; |
| } |
| segmentsLength.totalLength = totalLength; |
| return segmentsLength; |
| } |
| |
| function BezierData(length){ |
| this.segmentLength = 0; |
| this.points = new Array(length); |
| } |
| |
| function PointData(partial,point){ |
| this.partialLength = partial; |
| this.point = point; |
| } |
| |
| var buildBezierData = (function(){ |
| |
| var storedData = {}; |
| |
| return function (keyData){ |
| var pt1 = keyData.s; |
| var pt2 = keyData.e; |
| var pt3 = keyData.to; |
| var pt4 = keyData.ti; |
| var bezierName = (pt1[0]+'_'+pt1[1]+'_'+pt2[0]+'_'+pt2[1]+'_'+pt3[0]+'_'+pt3[1]+'_'+pt4[0]+'_'+pt4[1]).replace(/\./g, 'p'); |
| if(storedData[bezierName]){ |
| keyData.bezierData = storedData[bezierName]; |
| return; |
| } |
| var curveSegments = defaultCurveSegments; |
| var k, i, len; |
| var ptCoord,perc,addedLength = 0; |
| var ptDistance; |
| var point,lastPoint = null; |
| if (pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt1[0]+pt3[0],pt1[1]+pt3[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt2[0]+pt4[0],pt2[1]+pt4[1])){ |
| curveSegments = 2; |
| } |
| var bezierData = new BezierData(curveSegments); |
| len = pt3.length; |
| for (k = 0; k < curveSegments; k += 1) { |
| point = createSizedArray(len); |
| perc = k / (curveSegments - 1); |
| ptDistance = 0; |
| for (i = 0; i < len; i += 1){ |
| ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*(pt1[i] + pt3[i])+3*(1-perc)*bm_pow(perc,2)*(pt2[i] + pt4[i])+bm_pow(perc,3)*pt2[i]; |
| point[i] = ptCoord; |
| if(lastPoint !== null){ |
| ptDistance += bm_pow(point[i] - lastPoint[i],2); |
| } |
| } |
| ptDistance = bm_sqrt(ptDistance); |
| addedLength += ptDistance; |
| bezierData.points[k] = new PointData(ptDistance, point); |
| lastPoint = point; |
| } |
| bezierData.segmentLength = addedLength; |
| keyData.bezierData = bezierData; |
| storedData[bezierName] = bezierData; |
| }; |
| }()); |
| |
| function getDistancePerc(perc,bezierData){ |
| var percents = bezierData.percents; |
| var lengths = bezierData.lengths; |
| var len = percents.length; |
| var initPos = bm_floor((len-1)*perc); |
| var lengthPos = perc*bezierData.addedLength; |
| var lPerc = 0; |
| if(initPos === len - 1 || initPos === 0 || lengthPos === lengths[initPos]){ |
| return percents[initPos]; |
| }else{ |
| var dir = lengths[initPos] > lengthPos ? -1 : 1; |
| var flag = true; |
| while(flag){ |
| if(lengths[initPos] <= lengthPos && lengths[initPos+1] > lengthPos){ |
| lPerc = (lengthPos - lengths[initPos]) / (lengths[initPos+1] - lengths[initPos]); |
| flag = false; |
| }else{ |
| initPos += dir; |
| } |
| if(initPos < 0 || initPos >= len - 1){ |
| //FIX for TypedArrays that don't store floating point values with enough accuracy |
| if(initPos === len - 1) { |
| return percents[initPos]; |
| } |
| flag = false; |
| } |
| } |
| return percents[initPos] + (percents[initPos+1] - percents[initPos])*lPerc; |
| } |
| } |
| |
| function getPointInSegment(pt1, pt2, pt3, pt4, percent, bezierData) { |
| var t1 = getDistancePerc(percent,bezierData); |
| var u0 = 1; |
| var u1 = 1 - t1; |
| var ptX = Math.round((u1*u1*u1* pt1[0] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[0] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[0] + t1*t1*t1* pt2[0])* 1000) / 1000; |
| var ptY = Math.round((u1*u1*u1* pt1[1] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[1] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[1] + t1*t1*t1* pt2[1])* 1000) / 1000; |
| return [ptX, ptY]; |
| } |
| |
| function getSegmentArray() { |
| |
| } |
| |
| var bezier_segment_points = createTypedArray('float32', 8); |
| |
| function getNewSegment(pt1,pt2,pt3,pt4,startPerc,endPerc, bezierData){ |
| |
| startPerc = startPerc < 0 ? 0 : startPerc > 1 ? 1 : startPerc; |
| var t0 = getDistancePerc(startPerc,bezierData); |
| endPerc = endPerc > 1 ? 1 : endPerc; |
| var t1 = getDistancePerc(endPerc,bezierData); |
| var i, len = pt1.length; |
| var u0 = 1 - t0; |
| var u1 = 1 - t1; |
| var u0u0u0 = u0*u0*u0; |
| var t0u0u0_3 = t0*u0*u0*3; |
| var t0t0u0_3 = t0*t0*u0*3; |
| var t0t0t0 = t0*t0*t0; |
| // |
| var u0u0u1 = u0*u0*u1; |
| var t0u0u1_3 = t0*u0*u1 + u0*t0*u1 + u0*u0*t1; |
| var t0t0u1_3 = t0*t0*u1 + u0*t0*t1 + t0*u0*t1; |
| var t0t0t1 = t0*t0*t1; |
| // |
| var u0u1u1 = u0*u1*u1; |
| var t0u1u1_3 = t0*u1*u1 + u0*t1*u1 + u0*u1*t1; |
| var t0t1u1_3 = t0*t1*u1 + u0*t1*t1 + t0*u1*t1; |
| var t0t1t1 = t0*t1*t1; |
| // |
| var u1u1u1 = u1*u1*u1; |
| var t1u1u1_3 = t1*u1*u1 + u1*t1*u1 + u1*u1*t1; |
| var t1t1u1_3 = t1*t1*u1 + u1*t1*t1 + t1*u1*t1; |
| var t1t1t1 = t1*t1*t1; |
| for(i=0;i<len;i+=1){ |
| bezier_segment_points[i * 4] = Math.round((u0u0u0 * pt1[i] + t0u0u0_3 * pt3[i] + t0t0u0_3 * pt4[i] + t0t0t0 * pt2[i]) * 1000) / 1000; |
| bezier_segment_points[i * 4 + 1] = Math.round((u0u0u1 * pt1[i] + t0u0u1_3 * pt3[i] + t0t0u1_3 * pt4[i] + t0t0t1 * pt2[i]) * 1000) / 1000; |
| bezier_segment_points[i * 4 + 2] = Math.round((u0u1u1 * pt1[i] + t0u1u1_3 * pt3[i] + t0t1u1_3 * pt4[i] + t0t1t1 * pt2[i]) * 1000) / 1000; |
| bezier_segment_points[i * 4 + 3] = Math.round((u1u1u1 * pt1[i] + t1u1u1_3 * pt3[i] + t1t1u1_3 * pt4[i] + t1t1t1 * pt2[i]) * 1000) / 1000; |
| } |
| |
| return bezier_segment_points; |
| } |
| |
| return { |
| getSegmentsLength : getSegmentsLength, |
| getNewSegment : getNewSegment, |
| getPointInSegment : getPointInSegment, |
| buildBezierData : buildBezierData, |
| pointOnLine2D : pointOnLine2D, |
| pointOnLine3D : pointOnLine3D |
| }; |
| } |
| |
| var bez = bezFunction(); |