function polygonClip(subjectPolygon, clipPolygon) {
  let cp1,
    cp2,
    s,
    e,
    outputList = subjectPolygon
  cp1 = clipPolygon[clipPolygon.length - 2]
  for (let j = 0, jlen = clipPolygon.length - 1; j < jlen; j++) {
    cp2 = clipPolygon[j]
    const inputList = outputList
    outputList = []
    s = inputList[inputList.length - 1]
    for (let i = 0, len = inputList.length; i < len; i++) {
      e = inputList[i]
      if (clipInside(e, cp1, cp2)) {
        clipInside(s, cp1, cp2) || outputList.push(clipIntersection(cp1, cp2, s, e))
        outputList.push(e)
      } else clipInside(s, cp1, cp2) && outputList.push(clipIntersection(cp1, cp2, s, e))
      s = e
    }
    cp1 = cp2
  }
  if (outputList.length < 3) return []
  outputList.push(outputList[0])
  return outputList
}
function pointOnSegment(p, p1, p2) {
  const tx = ((p2[1] - p1[1]) / (p2[0] - p1[0])) * (p[0] - p1[0]) + p1[1]
  return Math.abs(tx - p[1]) < 1e-6 && p[0] >= p1[0] && p[0] <= p2[0]
}
function pointOnPolygon(point, vs) {
  for (let i = 0, len = vs.length; i < len - 1; i++) if (pointOnSegment(point, vs[i], vs[i + 1])) return !0
  return !1
}
function pointInPolygon(point, vs) {
  let inside = !1
  for (let x = point[0], y = point[1], i = 0, len = vs.length, j = len - 1; i < len; j = i++) {
    const xi = vs[i][0],
      yi = vs[i][1],
      xj = vs[j][0],
      yj = vs[j][1],
      intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
    intersect && (inside = !inside)
  }
  return inside
}
function getClosestPointOnSegment(p, p1, p2) {
  let t,
    x = p1[0],
    y = p1[1]
  const dx = p2[0] - x,
    dy = p2[1] - y,
    dot = dx * dx + dy * dy
  if (dot > 0) {
    t = ((p[0] - x) * dx + (p[1] - y) * dy) / dot
    if (t > 1) {
      x = p2[0]
      y = p2[1]
    } else if (t > 0) {
      x += dx * t
      y += dy * t
    }
  }
  return [x, y]
}
function sqClosestDistanceToSegment(p, p1, p2) {
  const p3 = getClosestPointOnSegment(p, p1, p2),
    dx = p[0] - p3[0],
    dy = p[1] - p3[1]
  return dx * dx + dy * dy
}
function sqClosestDistanceToPolygon(p, points) {
  let minSq = Number.MAX_VALUE
  for (let i = 0, len = points.length; i < len - 1; i++) {
    const sq = sqClosestDistanceToSegment(p, points[i], points[i + 1])
    sq < minSq && (minSq = sq)
  }
  return minSq
}
function clipInside(p, cp1, cp2) {
  return (cp2[0] - cp1[0]) * (p[1] - cp1[1]) > (cp2[1] - cp1[1]) * (p[0] - cp1[0])
}
function clipIntersection(cp1, cp2, s, e) {
  const dc = [cp1[0] - cp2[0], cp1[1] - cp2[1]],
    dp = [s[0] - e[0], s[1] - e[1]],
    n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
    n2 = s[0] * e[1] - s[1] * e[0],
    n3 = 1 / (dc[0] * dp[1] - dc[1] * dp[0])
  return [(n1 * dp[0] - n2 * dc[0]) * n3, (n1 * dp[1] - n2 * dc[1]) * n3]
}

export default {
  sqClosestDistanceToPolygon,
  pointOnPolygon,
  pointInPolygon,
  polygonClip
}
