字节跳动 有一个n边形(P0, P1, ..., Pn),等分点

201 阅读1分钟
public static class Coordinates {
   public Coordinates() {

   }

   public Coordinates(double x, double y) {
      this.x = x;
      this.y = y;
   }

   protected double x, y;

   public double getX() {
      return x;
   }

   public void setX(double x) {
      this.x = x;
   }

   public double getY() {
      return y;
   }

   public void setY(double y) {
      this.y = y;
   }
}

/**
 * 有一个n边形(P0, P1, ..., Pn), 每一条边皆为垂直或水平线段。现给定数值k,以P0为起点将n边形的周长分为k段,每段的长度相等,请打印出k等分点的坐标(T0, T1, ..., Tk)的坐标。
 */
@Test
public void test1() {
   List<Coordinates> list = new ArrayList<>();
   list.add(new Coordinates(0, 0));
   list.add(new Coordinates(0, 3));
   list.add(new Coordinates(3, 3));
   list.add(new Coordinates(3, 4));
   list.add(new Coordinates(4, 4));
   list.add(new Coordinates(4, 2));
   list.add(new Coordinates(6, 2));
   list.add(new Coordinates(6, 0));
   //周长
   int perimeter = 0;
   int num = 10;
   List<Coordinates> result = new ArrayList<>(num - 1);
   for (int i = 0; i < list.size(); i++) {
      Coordinates last = i == 0 ? list.get(list.size() - 1) : list.get(i - 1);
      if (list.get(i).getX() == last.getX()) {
         perimeter += Math.abs(list.get(i).getY() - last.getY());
      } else {
         perimeter += Math.abs(list.get(i).getX() - last.getX());
      }
   }
   double diff = perimeter * 1.0 / num;
   double l = 0;
   //上个点位
   Coordinates last = list.get(0);
   //当前点位
   Coordinates now;
   //多边形顶点序号
   int i = 1;
   //多出长度,需算入下次计算
   double t = 0;
   while (i <= list.size()) {
      now = i == list.size() ? list.get(0) : list.get(i);
      //两点 垂直水平
      if (now.getX() == last.getX()) {
         l = Math.abs(now.getY() - last.getY());
         //上次计算多出长度+边长 > 平均值时,期间有均分点
         if (t + l >= diff) {
            //向上延伸  则 上一点y+均值-上次多出长度 = 均分点y  否则 上一点y—(均值-上次多出长度) = 均分点y
            double y = now.getY() - last.getY() > 0 ? (last.getY() + diff - t) : (last.getY() + t - diff);
            last = new Coordinates(now.getX(), y);
            result.add(last);
            t = 0;
         } else {
            last = now;
            i++;
            t = t + l;
         }
      } else {//两点水平
         l = Math.abs(now.getX() - last.getX());
         //上次计算多出长度+边长 > 平均值时,期间有均分点
         if (t + l >= diff) {
            //向右延伸  则 上一点x+均值-上次多出长度 = 均分点x  否则 上一点x—(均值-上次多出长度) = 均分点x
            double x = now.getX() - last.getX() > 0 ? (last.getX() + diff - t) : (last.getX() + t - diff);
            //以均分点为起点,进行下次计算
            last = new Coordinates(x, now.getY());
            result.add(last);
            t = 0;
         } else {//期间没有均分点,寻找下个顶点
            last = now;
            i++;
            t = t + l;
         }
      }
   }
   JLogger.debug(JSONObject.toJSONString(result));
}