| 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 (pt1, pt2, pt3, pt4) { |
| var bezierName = (pt1[0] + '_' + pt1[1] + '_' + pt2[0] + '_' + pt2[1] + '_' + pt3[0] + '_' + pt3[1] + '_' + pt4[0] + '_' + pt4[1]).replace(/\./g, 'p'); |
| if (!storedData[bezierName]) { |
| 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; |
| storedData[bezierName] = bezierData; |
| } |
| return storedData[bezierName]; |
| }; |
| }()); |
| |
| 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]; |
| } |
| 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(); |