以通用方式从ARC中提取顶点

时间:2015-04-25 10:55:37

标签: javascript algorithm geometry bresenham rasterize

我想从ARC获取所有顶点。我有用于绘制弧的所有数据(例如:起点,终点,起始角,终止角,半径),但我需要从弧数据生成所有顶点。

我已尝试使用一个或两个算法,但我无法从弧数据中获取精确的顶点。

我使用了Bresenham的算法,但我失败了。

现在我正在使用下面的代码,但它不起作用..

            double theta = 2 * 3.1415926 / 100; 
            double c = Math.cos(theta);
            double s = Math.sin(theta);
            double t;

            double x = ((ArcTo) element).getRadius();//we start at angle = 0 
            double y = 0; 

            for(int ii = 0; ii < 100; ii++) { 
              coordinates.add(new Coordinate(x + element.getCenterPoint().getX(), y + element.getCenterPoint().getY()));//output vertex 

              //apply the rotation matrix
              t = x;
              x = c * x - s * y;
              y = s * t + c * y;
            }

请帮帮我。谢谢。

1 个答案:

答案 0 :(得分:0)

  1. 首先澄清一些

    我假设顶点表示像素, ARC 是标准 2D 圆弧(不是椭圆弧!!! ),您的输入数据是:

    int (x0,y0),(x1,y1) // star/end points on curve !!!
    float a0,a1         // start end angles [rad]
    int (xc,yc)         // center of circle
    int r               // radius
    
  2. 请勿使用Bresenham

    因为您需要从零角度开始并计算所有像素,直到命中起点。然后翻转绘制标记,以便从该点开始填充像素并停止在终点点击。此外,您需要处理绕组以匹配 ARC 方向。

  3. 您可以使用圆参数方程

    // just some arc data to test with
    float r=25.0;
    float a0= 45.0*M_PI/180.0;
    float a1=270.0*M_PI/180.0;
    int xc=100,x0=xc+floor(r*cos(a0)),x1=xc+floor(r*cos(a1));
    int yc=100,y0=yc+floor(r*sin(a0)),y1=yc+floor(r*sin(a1));
    // arc rasterize code
    int x,y;
    float a,da;
    // here draw pixels x0,y0 and x1,y1 to avoid rounding holes ...
    if (r) da=0.75/float(r); else da=0.1; // step slightly less then pixel to avoid holes
    for (a=a0;;a+=da)
     {
     x=xc+int(floor(r*cos(a)));
     y=yc+int(floor(r*sin(a)));
     // here draw pixel x,y
     if ((x==x1)&&(y==y1)) // stop if endpoint reach
      if (fabs(a-a1)<da)   // but ignore stop if not at end angle (full or empty circle arc)
       break;
     }
    

    可能是round而不是floor会有更少的像素位置错误。如果您的端点不匹配,那么这将无限循环。如果你稍微调整一下结束条件,你甚至可以避免或者从我x1,y1重新计算a1 ......

  4. 您可以使用公式(x-xc)^2+(y-yc)^2=r^2

    您需要将 ARC 划分为象限,并将每个处理为单独的弧循环遍历xy并计算其他坐标。循环通过更改更多的坐标

    dx,dy quadrants

    所以在蓝色区域循环y和红色循环x。例如,红色区域代码可能如下所示:

    int x,y;
    for (x=_x0;;x++)
     {
     y=sqrt((r*r)-((x-xc)*(x-xc)));
     // here draw pixel x,y
     if (x==_x1) // stop if endpoint reach
      break;
     }
    

    您需要在象限内计算{strong> ARC 的切割部分的(_x0,_y0),(_x1,_y1)个起点,并制作_x0<=_x1


    _x循环起点/终点坐标的值为xc +/- sqrt(r)x0x1
    _y循环起点/终点坐标的值为yc +/- sqrt(r)y0y1

    蓝色部分以类似方式完成(只需交换/替换xy)。由于切割这种方法有点复杂,但可以仅对整数进行。 sqrt可以加速 LUT (限制最大半径),^2也可以进一步优化。

  5. <强> [注释]

    所以,如果我重述参数方程是最简单的实现,但最慢。那么sqrt方法可以像Bresenham一样快速完成( LUT 可能会更快)但是需要将 ARC 切割成象限的代码在渲染之前需要很少if秒。

    所有代码都在 C ++ 中,可以进一步改进,例如避免一些int/float转换,在循环之前预先计算一些值等等。

    最后一次是Bresenham,但你需要改变一些内部的东西,当你不知道自己在做什么时,你很容易迷失。它还需要削减到八分圆,所以变化的复杂性远远大于sqrt方法