| 
                        123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 | 
                        - /**
 -  * @Author: Caven
 -  * @Date: 2020-08-21 18:05:39
 -  */
 - 
 - const TWO_PI = Math.PI * 2
 - const FITTING_COUNT = 100
 - const ZERO_TOLERANCE = 0.0001
 - 
 - class PlotUtil {
 -   /**
 -    * @param pnt1
 -    * @param pnt2
 -    * @returns {number}
 -    */
 -   static distance(pnt1, pnt2) {
 -     return Math.sqrt(
 -       Math.pow(pnt1[0] - pnt2[0], 2) + Math.pow(pnt1[1] - pnt2[1], 2)
 -     )
 -   }
 - 
 -   /**
 -    * @param points
 -    * @returns {number}
 -    */
 -   static wholeDistance(points) {
 -     let distance = 0
 -     for (let i = 0; i < points.length - 1; i++)
 -       distance += this.distance(points[i], points[i + 1])
 -     return distance
 -   }
 - 
 -   /**
 -    * @param points
 -    * @returns {number}
 -    */
 -   static getBaseLength(points) {
 -     return Math.pow(this.wholeDistance(points), 0.99)
 -   }
 - 
 -   /**
 -    * @param pnt1
 -    * @param pnt2
 -    * @returns {number[]}
 -    */
 -   static mid(pnt1, pnt2) {
 -     return [(pnt1[0] + pnt2[0]) / 2, (pnt1[1] + pnt2[1]) / 2]
 -   }
 - 
 -   /**
 -    * @param pnt1
 -    * @param pnt2
 -    * @param pnt3
 -    * @returns {[*, *]|[*, *]|[*, number]}
 -    */
 -   static getCircleCenterOfThreePoints(pnt1, pnt2, pnt3) {
 -     let pntA = [(pnt1[0] + pnt2[0]) / 2, (pnt1[1] + pnt2[1]) / 2]
 -     let pntB = [pntA[0] - pnt1[1] + pnt2[1], pntA[1] + pnt1[0] - pnt2[0]]
 -     let pntC = [(pnt1[0] + pnt3[0]) / 2, (pnt1[1] + pnt3[1]) / 2]
 -     let pntD = [pntC[0] - pnt1[1] + pnt3[1], pntC[1] + pnt1[0] - pnt3[0]]
 -     return this.getIntersectPoint(pntA, pntB, pntC, pntD)
 -   }
 - 
 -   /**
 -    * @param pntA
 -    * @param pntB
 -    * @param pntC
 -    * @param pntD
 -    * @returns {(*|number)[]|*[]}
 -    */
 -   static getIntersectPoint(pntA, pntB, pntC, pntD) {
 -     let x, y, f, e
 -     if (pntA[1] === pntB[1]) {
 -       f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
 -       x = f * (pntA[1] - pntC[1]) + pntC[0]
 -       y = pntA[1]
 -       return [x, y]
 -     }
 -     if (pntC[1] === pntD[1]) {
 -       e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
 -       x = e * (pntC[1] - pntA[1]) + pntA[0]
 -       y = pntC[1]
 -       return [x, y]
 -     }
 -     e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
 -     f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
 -     y = (e * pntA[1] - pntA[0] - f * pntC[1] + pntC[0]) / (e - f)
 -     x = e * y - e * pntA[1] + pntA[0]
 -     return [x, y]
 -   }
 - 
 -   /**
 -    * @param startPnt
 -    * @param endPnt
 -    * @returns {number}
 -    */
 -   static getAzimuth(startPnt, endPnt) {
 -     let azimuth
 -     let angle = Math.asin(
 -       Math.abs(endPnt[1] - startPnt[1]) / this.distance(startPnt, endPnt)
 -     )
 -     if (endPnt[1] >= startPnt[1] && endPnt[0] >= startPnt[0])
 -       azimuth = angle + Math.PI
 -     else if (endPnt[1] >= startPnt[1] && endPnt[0] < startPnt[0])
 -       azimuth = TWO_PI - angle
 -     else if (endPnt[1] < startPnt[1] && endPnt[0] < startPnt[0]) azimuth = angle
 -     else if (endPnt[1] < startPnt[1] && endPnt[0] >= startPnt[0])
 -       azimuth = Math.PI - angle
 -     return azimuth
 -   }
 - 
 -   /**
 -    * @param pntA
 -    * @param pntB
 -    * @param pntC
 -    * @returns {number}
 -    */
 -   static getAngleOfThreePoints(pntA, pntB, pntC) {
 -     let angle = this.getAzimuth(pntB, pntA) - this.getAzimuth(pntB, pntC)
 -     return angle < 0 ? angle + TWO_PI : angle
 -   }
 - 
 -   /**
 -    * @param pnt1
 -    * @param pnt2
 -    * @param pnt3
 -    * @returns {boolean}
 -    */
 -   static isClockWise(pnt1, pnt2, pnt3) {
 -     return (
 -       (pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) >
 -       (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0])
 -     )
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param startPnt
 -    * @param endPnt
 -    * @returns {*[]}
 -    */
 -   static getPointOnLine(t, startPnt, endPnt) {
 -     let x = startPnt[0] + t * (endPnt[0] - startPnt[0])
 -     let y = startPnt[1] + t * (endPnt[1] - startPnt[1])
 -     return [x, y]
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param startPnt
 -    * @param cPnt1
 -    * @param cPnt2
 -    * @param endPnt
 -    * @returns {number[]}
 -    */
 -   static getCubicValue(t, startPnt, cPnt1, cPnt2, endPnt) {
 -     t = Math.max(Math.min(t, 1), 0)
 -     let tp = 1 - t
 -     let t2 = t * t
 -     let t3 = t2 * t
 -     let tp2 = tp * tp
 -     let tp3 = tp2 * tp
 -     let x =
 -       tp3 * startPnt[0] +
 -       3 * tp2 * t * cPnt1[0] +
 -       3 * tp * t2 * cPnt2[0] +
 -       t3 * endPnt[0]
 -     let y =
 -       tp3 * startPnt[1] +
 -       3 * tp2 * t * cPnt1[1] +
 -       3 * tp * t2 * cPnt2[1] +
 -       t3 * endPnt[1]
 -     return [x, y]
 -   }
 - 
 -   /**
 -    * @param startPnt
 -    * @param endPnt
 -    * @param angle
 -    * @param distance
 -    * @param clockWise
 -    * @returns {*[]}
 -    */
 -   static getThirdPoint(startPnt, endPnt, angle, distance, clockWise) {
 -     let azimuth = this.getAzimuth(startPnt, endPnt)
 -     let alpha = clockWise ? azimuth + angle : azimuth - angle
 -     let dx = distance * Math.cos(alpha)
 -     let dy = distance * Math.sin(alpha)
 -     return [endPnt[0] + dx, endPnt[1] + dy]
 -   }
 - 
 -   /**
 -    * @param center
 -    * @param radius
 -    * @param startAngle
 -    * @param endAngle
 -    * @returns {[]}
 -    */
 -   static getArcPoints(center, radius, startAngle, endAngle) {
 -     let x,
 -       y,
 -       pnts = []
 -     let angleDiff = endAngle - startAngle
 -     angleDiff = angleDiff < 0 ? angleDiff + TWO_PI : angleDiff
 -     for (let i = 0; i <= FITTING_COUNT; i++) {
 -       let angle = startAngle + (angleDiff * i) / FITTING_COUNT
 -       x = center[0] + radius * Math.cos(angle)
 -       y = center[1] + radius * Math.sin(angle)
 -       pnts.push([x, y])
 -     }
 -     return pnts
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param pnt1
 -    * @param pnt2
 -    * @param pnt3
 -    * @returns {*[][]}
 -    */
 -   static getBisectorNormals(t, pnt1, pnt2, pnt3) {
 -     let normal = this.getNormal(pnt1, pnt2, pnt3)
 -     let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
 -     let uX = normal[0] / dist
 -     let uY = normal[1] / dist
 -     let d1 = this.distance(pnt1, pnt2)
 -     let d2 = this.distance(pnt2, pnt3)
 -     let dt, x, y, bisectorNormalLeft, bisectorNormalRight
 -     if (dist > ZERO_TOLERANCE) {
 -       if (this.isClockWise(pnt1, pnt2, pnt3)) {
 -         dt = t * d1
 -         x = pnt2[0] - dt * uY
 -         y = pnt2[1] + dt * uX
 -         bisectorNormalRight = [x, y]
 -         dt = t * d2
 -         x = pnt2[0] + dt * uY
 -         y = pnt2[1] - dt * uX
 -         bisectorNormalLeft = [x, y]
 -       } else {
 -         dt = t * d1
 -         x = pnt2[0] + dt * uY
 -         y = pnt2[1] - dt * uX
 -         bisectorNormalRight = [x, y]
 -         dt = t * d2
 -         x = pnt2[0] - dt * uY
 -         y = pnt2[1] + dt * uX
 -         bisectorNormalLeft = [x, y]
 -       }
 -     } else {
 -       x = pnt2[0] + t * (pnt1[0] - pnt2[0])
 -       y = pnt2[1] + t * (pnt1[1] - pnt2[1])
 -       bisectorNormalRight = [x, y]
 -       x = pnt2[0] + t * (pnt3[0] - pnt2[0])
 -       y = pnt2[1] + t * (pnt3[1] - pnt2[1])
 -       bisectorNormalLeft = [x, y]
 -     }
 -     return [bisectorNormalRight, bisectorNormalLeft]
 -   }
 - 
 -   /**
 -    * @param pnt1
 -    * @param pnt2
 -    * @param pnt3
 -    * @returns {number[]}
 -    */
 -   static getNormal(pnt1, pnt2, pnt3) {
 -     let dX1 = pnt1[0] - pnt2[0]
 -     let dY1 = pnt1[1] - pnt2[1]
 -     let d1 = Math.sqrt(dX1 * dX1 + dY1 * dY1)
 -     dX1 /= d1
 -     dY1 /= d1
 - 
 -     let dX2 = pnt3[0] - pnt2[0]
 -     let dY2 = pnt3[1] - pnt2[1]
 -     let d2 = Math.sqrt(dX2 * dX2 + dY2 * dY2)
 -     dX2 /= d2
 -     dY2 /= d2
 - 
 -     let uX = dX1 + dX2
 -     let uY = dY1 + dY2
 -     return [uX, uY]
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param controlPoints
 -    * @returns {[]}
 -    */
 -   static getCurvePoints(t, controlPoints) {
 -     let leftControl = this.getLeftMostControlPoint(t, controlPoints)
 -     let normals = [leftControl]
 -     let pnt1, pnt2, pnt3, normalPoints
 -     for (let i = 0; i < controlPoints.length - 2; i++) {
 -       pnt1 = controlPoints[i]
 -       pnt2 = controlPoints[i + 1]
 -       pnt3 = controlPoints[i + 2]
 -       normalPoints = this.getBisectorNormals(t, pnt1, pnt2, pnt3)
 -       normals = normals.concat(normalPoints)
 -     }
 -     let rightControl = this.getRightMostControlPoint(t, controlPoints)
 -     normals.push(rightControl)
 -     let points = []
 -     for (let i = 0; i < controlPoints.length - 1; i++) {
 -       pnt1 = controlPoints[i]
 -       pnt2 = controlPoints[i + 1]
 -       points.push(pnt1)
 -       for (let t = 0; t < FITTING_COUNT; t++) {
 -         let pnt = this.getCubicValue(
 -           t / FITTING_COUNT,
 -           pnt1,
 -           normals[i * 2],
 -           normals[i * 2 + 1],
 -           pnt2
 -         )
 -         points.push(pnt)
 -       }
 -       points.push(pnt2)
 -     }
 -     return points
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param controlPoints
 -    * @returns {number[]}
 -    */
 -   static getLeftMostControlPoint(t, controlPoints) {
 -     let pnt1 = controlPoints[0]
 -     let pnt2 = controlPoints[1]
 -     let pnt3 = controlPoints[2]
 -     let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
 -     let normalRight = pnts[0]
 -     let normal = this.getNormal(pnt1, pnt2, pnt3)
 -     let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
 -     let controlX, controlY
 -     if (dist > ZERO_TOLERANCE) {
 -       let mid = this.mid(pnt1, pnt2)
 -       let pX = pnt1[0] - mid[0]
 -       let pY = pnt1[1] - mid[1]
 -       let d1 = this.distance(pnt1, pnt2)
 -       // normal at midpoint
 -       let n = 2.0 / d1
 -       let nX = -n * pY
 -       let nY = n * pX
 -       // upper triangle of symmetric transform matrix
 -       let a11 = nX * nX - nY * nY
 -       let a12 = 2 * nX * nY
 -       let a22 = nY * nY - nX * nX
 -       let dX = normalRight[0] - mid[0]
 -       let dY = normalRight[1] - mid[1]
 -       // coordinates of reflected vector
 -       controlX = mid[0] + a11 * dX + a12 * dY
 -       controlY = mid[1] + a12 * dX + a22 * dY
 -     } else {
 -       controlX = pnt1[0] + t * (pnt2[0] - pnt1[0])
 -       controlY = pnt1[1] + t * (pnt2[1] - pnt1[1])
 -     }
 -     return [controlX, controlY]
 -   }
 - 
 -   /**
 -    * @param t
 -    * @param controlPoints
 -    * @returns {number[]}
 -    */
 -   static getRightMostControlPoint(t, controlPoints) {
 -     let count = controlPoints.length
 -     let pnt1 = controlPoints[count - 3]
 -     let pnt2 = controlPoints[count - 2]
 -     let pnt3 = controlPoints[count - 1]
 -     let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
 -     let normalLeft = pnts[1]
 -     let normal = this.getNormal(pnt1, pnt2, pnt3)
 -     let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
 -     let controlX, controlY
 -     if (dist > ZERO_TOLERANCE) {
 -       let mid = this.mid(pnt2, pnt3)
 -       let pX = pnt3[0] - mid[0]
 -       let pY = pnt3[1] - mid[1]
 - 
 -       let d1 = this.distance(pnt2, pnt3)
 -       // normal at midpoint
 -       let n = 2.0 / d1
 -       let nX = -n * pY
 -       let nY = n * pX
 - 
 -       // upper triangle of symmetric transform matrix
 -       let a11 = nX * nX - nY * nY
 -       let a12 = 2 * nX * nY
 -       let a22 = nY * nY - nX * nX
 - 
 -       let dX = normalLeft[0] - mid[0]
 -       let dY = normalLeft[1] - mid[1]
 - 
 -       // coordinates of reflected vector
 -       controlX = mid[0] + a11 * dX + a12 * dY
 -       controlY = mid[1] + a12 * dX + a22 * dY
 -     } else {
 -       controlX = pnt3[0] + t * (pnt2[0] - pnt3[0])
 -       controlY = pnt3[1] + t * (pnt2[1] - pnt3[1])
 -     }
 -     return [controlX, controlY]
 -   }
 - 
 -   /**
 -    * @param points
 -    * @returns {[]|*}
 -    */
 -   static getBezierPoints(points) {
 -     if (points.length <= 2) return points
 -     let bezierPoints = []
 -     let n = points.length - 1
 -     for (let t = 0; t <= 1; t += 0.01) {
 -       let x = 0
 -       let y = 0
 -       for (let index = 0; index <= n; index++) {
 -         let factor = this.getBinomialFactor(n, index)
 -         let a = Math.pow(t, index)
 -         let b = Math.pow(1 - t, n - index)
 -         x += factor * a * b * points[index][0]
 -         y += factor * a * b * points[index][1]
 -       }
 -       bezierPoints.push([x, y])
 -     }
 -     bezierPoints.push(points[n])
 -     return bezierPoints
 -   }
 - 
 -   /**
 -    *
 -    * @param n
 -    * @param index
 -    * @returns {number}
 -    */
 -   static getBinomialFactor(n, index) {
 -     return (
 -       this.getFactorial(n) /
 -       (this.getFactorial(index) * this.getFactorial(n - index))
 -     )
 -   }
 - 
 -   /**
 -    * @param n
 -    * @returns {number}
 -    */
 -   static getFactorial(n) {
 -     if (n <= 1) return 1
 -     if (n === 2) return 2
 -     if (n === 3) return 6
 -     if (n === 4) return 24
 -     if (n === 5) return 120
 -     let result = 1
 -     for (let i = 1; i <= n; i++) result *= i
 -     return result
 -   }
 - 
 -   /**
 -    * @param points
 -    * @returns {[]|*}
 -    */
 -   static getQBSplinePoints(points) {
 -     if (points.length <= 2) return points
 -     let n = 2
 -     let bSplinePoints = []
 -     let m = points.length - n - 1
 -     bSplinePoints.push(points[0])
 -     for (let i = 0; i <= m; i++) {
 -       for (let t = 0; t <= 1; t += 0.05) {
 -         let x = 0
 -         let y = 0
 -         for (let k = 0; k <= n; k++) {
 -           let factor = this.getQuadricBSplineFactor(k, t)
 -           x += factor * points[i + k][0]
 -           y += factor * points[i + k][1]
 -         }
 -         bSplinePoints.push([x, y])
 -       }
 -     }
 -     bSplinePoints.push(points[points.length - 1])
 -     return bSplinePoints
 -   }
 - 
 -   /**
 -    * @param k
 -    * @param t
 -    * @returns {number}
 -    */
 -   static getQuadricBSplineFactor(k, t) {
 -     if (k === 0) return Math.pow(t - 1, 2) / 2
 -     if (k === 1) return (-2 * Math.pow(t, 2) + 2 * t + 1) / 2
 -     if (k === 2) return Math.pow(t, 2) / 2
 -     return 0
 -   }
 - }
 - 
 - export default PlotUtil
 
 
  |