一个简单的小算法编程题 - 平分多边形边长

题目:

    在直角坐标系平面上,给定一些点(个数大于2),这些点组成一个多边形。

    给定一个数字k(k>=2),将多边形的边长平分成k份。

   输出:k个点,这些点全部都是多边形上的。

 

我的思路如下:

    先求出总长度,然后求出平均长度。

   第一个点取输入的第一个顶点。

   具体过程看我源代码(Java):

 

package com.learing.divingpolygon;

public class PolygonDivider {

 /**
  * Divide input polygon into parts evenly by side length.
  * @param pts    Input points.
  * @param numOfParts  How many parts to be divided to.
  * @return null if failed, otherwise the points on polygon.
  */
 public static Point [] divide(Point [] pts, int numOfParts) {
  if (numOfParts <= 1 || pts == null || pts.length < 2) {
   return null;
  }
 
  // the part length.
  final float partLen = getDividingLen(pts, numOfParts);
 
  Point [] result = new Point[numOfParts];
 
  // set the first result point as pts[0].
  result[0] = pts[0];
 
  // count of currently found results.
  int count = 1;
 
  // index for source points.
  int sourceIndex = 1;
 
  // the current point from where to calculate.
  Point cur = pts[0];
 
  // accumulated length for current point calculation.
  float accumulated = 0.0f;
 
  while (true) {
   if (sourceIndex >= pts.length) {
    System.err.print("program error.");
    return null;
   }
   Point dest = pts[sourceIndex];
   float distance = getDistance(cur, dest);
   if (distance < partLen - accumulated) {
    cur = dest;
    accumulated += distance;
    ++sourceIndex;
   
    // the last segment 's target is the original point.
    // here the original point is set to the first point.
    if (sourceIndex == pts.length) {
     sourceIndex = 0;
    }
   } else {
    cur = getPointByDistance(cur, dest, partLen - accumulated);
    accumulated = 0.0f;
    result[count++] = cur;
    if (count == numOfParts) {
     break;
    }
   }
  }
 
  return result;
 }
 
 static float getDividingLen(Point [] pts, int numOfParts) {
  float sum = 0.0f;
  final int n = pts.length;
  for (int i = 1; i < n; ++i) {
   sum += getDistance(pts[i - 1], pts[i]);
  }
 
  float lastLen = getDistance(pts[n - 1], pts[0]);
  sum += lastLen;
  return sum / numOfParts;
 }
 
 /**
  * Get a float point on segment(from start to end) which satisfies that
  * the length between start and the point is len.
  * @param start
  * @param end
  * @param len
  * @return the point which satisfies
  * that the length between start and the point is len.
  */
 static Point getPointByDistance(Point start, Point end, float len) {
  // special occasion : vertical line, the slant ratio doesn't exist.
  if (start.x == end.x) {
   return new Point(start.x, end.y > start.y ? start.y + len : start.y - len);
  }
 
  final float slant = (end.y - start.y) / (end.x - start.x);
 
  // result point x:
  float x = end.x > start.x ?
    len / (float) Math.sqrt(1 + slant * slant) + start.x
    : -len / (float) Math.sqrt(1 + slant * slant) + start.x;
 
  // result point y:
  float y = start.y + slant * (x - start.x);
 
  return new Point(x, y);
 }

 private static float getDistance(Point pt1, Point pt2) {
  return (float) Math.hypot(pt2.x - pt1.x, pt2.y - pt1.y);
 }
 
}

 

测试代码如下:

  @Test
 public void testDividing() {
  Point pts[] = new Point[] {
    new Point(0, 0),
    new Point(10, 0),
    new Point(10, 10),
    new Point(0, 10),
  };
 
  Point [] result = PolygonDivider.divide(pts, 5);
 
  Assert.assertEquals(result.length, 5);
  Assert.assertEquals("assert equals", result[0].x, 0, 0.01f);
  Assert.assertEquals("assert equals", result[0].y, 0, 0.01f);
 
  Assert.assertEquals("assert equals", result[1].x, 8, 0.01f);
  Assert.assertEquals("assert equals", result[1].y, 0, 0.01f);
 
  Assert.assertEquals("assert equals", result[2].x, 10, 0.01f);
  Assert.assertEquals("assert equals", result[2].y, 6, 0.01f);
 
  Assert.assertEquals("assert equals", result[3].x, 6, 0.01f);
  Assert.assertEquals("assert equals", result[3].y, 10, 0.01f);
 
  Assert.assertEquals("assert equals", result[4].x, 0, 0.01f);
  Assert.assertEquals("assert equals", result[4].y, 8, 0.01f);
 }


 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值