在边缘上添加点并拖动这些点后重新绘制多边形会绘制怪异的线

问题描述

通过绘制多边形,我获得了点的坐标。我可以在多边形的边缘上添加点,当我拖动任何点时,它应该只拖动连接的线。由于可以稍后在边缘上添加点,因此需要对点坐标进行排序,并且应该通过获取有序点来重绘多边形,以便在拖动任何点时仅拖动与拖动点连接的线。因此,要对点进行排序,我将使用Graham Scan /按极角排序顺时针对坐标(2D点)进行排序。

我的排序代码是 我发现多边形的中心像

function findCenter(points) {
  let x = 0,y = 0,i,len = points.length;

  for (i = 0; i < len; i++) {
    x += Number(points[i][0]);
    y += Number(points[i][1]);
  }

  return { x: x / len,y: y / len }; // return average position
}

然后我通过从中心找到每个点的角度来对点进行排序

function findAngle(points) {
  const center = findCenter(points);

  // find angle
  points.forEach((point) => {
    point.angle = Math.atan2(point[1] - center.y,point[0] - center.x);
  });
}

//arrVertexes is the array of points
arrVertexes.sort(function (a,b) {
    return a.angle >= b.angle ? 1 : -1;
  });

但是我面临的问题是,如果我再向相反的一侧拖动任何点,然后在边缘上添加一个新点,然后拖动新添加的点,则坐标的排序就不会精确排序,因为这会导致拖动时闪烁。

这里是我面临的问题的图示,以便快速理解。

最初我的svg看起来像

enter image description here

在此之后,我添加一个点并像

一样拖动

enter image description here

然后我又添加了一点,例如

enter image description here

一旦我拖动添加的点,它就会像这样重绘我的多边形

enter image description here

实际上应该是

enter image description here

这是我的游戏区域的链接

`https://codepen.io/jinata92/pen/MWyoepo?editors=0010`

所以我正在寻找不会给我重新绘制线条的解决方案。只能拖动到拖动点的连接线。

解决方法

我在折线算法上应用了最接近的点,并从点阵列中找到了添加点的索引,其中每个点都涉及制作一条折线。

/* desc Static function. Find point on lines nearest test point
   test point pXy with properties .x and .y
   lines defined by array aXys with nodes having properties .x and .y 
   return is object with .x and .y properties and property i indicating nearest segment in aXys 
   and property fFrom the fractional distance of the returned point from aXy[i-1]
   and property fTo the fractional distance of the returned point from aXy[i]   */
function getClosestPointOnLines(pXy,aXys) {
  var minDist;
  var fTo;
  var fFrom;
  var x;
  var y;
  var i;
  var dist;

  if (aXys.length > 1) {
    const getI = (n1,n2) => {
      let i;
      const a1 = aXys[n1];
      const a2 = aXys[n2];
      if (a1[0] != a2[0]) {
        let a = (a1[1] - a2[1]) / (a1[0] - a2[0]);
        let b = a1[1] - a * a1[0];
        dist = Math.abs(a * pXy[0] + b - pXy[1]) / Math.sqrt(a * a + 1);
      } else dist = Math.abs(pXy[0] - a1[0]);

      // length^2 of line segment
      let rl2 = Math.pow(a1[1] - a2[1],2) + Math.pow(a1[0] - a2[0],2);

      // distance^2 of pt to end line segment
      let ln2 = Math.pow(a1[1] - pXy[1],2) + Math.pow(a1[0] - pXy[0],2);

      // distance^2 of pt to begin line segment
      let lnm12 = Math.pow(a2[1] - pXy[1],2) + Math.pow(a2[0] - pXy[0],2);

      // minimum distance^2 of pt to infinite line
      let dist2 = Math.pow(dist,2);

      // calculated length^2 of line segment
      let calcrl2 = ln2 - dist2 + lnm12 - dist2;

      // redefine minimum distance to line segment (not infinite line) if necessary
      if (calcrl2 > rl2) dist = Math.sqrt(Math.min(ln2,lnm12));

      if (minDist == null || minDist > dist) {
        if (calcrl2 > rl2) {
          if (lnm12 < ln2) {
            fTo = 0; //nearer to previous point
            fFrom = 1;
          } else {
            fFrom = 0; //nearer to current point
            fTo = 1;
          }
        } else {
          // perpendicular from point intersects line segment
          fTo = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
          fFrom = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
        }
        minDist = dist;
        i = n1;
      }
      return i;
    };

    const updateI = (n1,n2) => {
      const newI = getI(n1,n2);
      if (newI !== undefined) {
        i = newI;
        return true;
      }
    };

    for (let n = 1; n < aXys.length; n++) {
      updateI(n,n - 1);
    }
    if (updateI(aXys.length - 1,0)) i = aXys.length;

    if (i < aXys.length) {
      let dx = aXys[i - 1][0] - aXys[i][0];
      let dy = aXys[i - 1][1] - aXys[i][1];

      x = aXys[i - 1][0] - dx * fTo;
      y = aXys[i - 1][1] - dy * fTo;
    }
  }

  return { x: x,y: y,i: i,fTo: fTo,fFrom: fFrom };
}