0

已解决:请参阅我的答案

我试图找到一个位于弧内部的点,因此当发生洪水填充时,它不会意外填充弧外的区域。只要两个角之间距离的绝对值:start和end;小于 PI 这有效(有几个极端的边缘情况,其中绘制的线非常接近,以至于选择的点是这些线的一部分,但那是不同的一天......)。

我遇到的问题是,当开始角和结束角之间的距离的绝对值大于 PI 时,洪水发生在弧的外部而不是内部。许多例子之一是:如果弧从 0 开始并以 3PI/2 结束,则距离的绝对值为 3PI/2,泛光发生在角度之间,就好像绝对值距离为 PI/2 并泛滥整个屏幕除了吃豆人形的弧线。

编辑:

为避免混淆,这里是根据 allegro(以及一般的三角学)定义的弧:

void arc(BITMAP *bmp, int x, y, fixed ang1, ang2, int r, int color);

以逆时针 [sic] 方向绘制圆弧 [减去初始/终止边或中心点],中心 [sic] x, y 和半径 r,从角度 a1 开始,在到达 a2 时结束......零位于中心 [sic] 点的右侧,较大的值从那里逆时针旋转 [sic]。

方括号是我的符号。

我已经处理了从 allegro 的(愚蠢的)使用fixed integers转换为正确的radian值。

结束编辑

void Arc::Draw(BITMAP* dest, int color, bool filled, bool showCenter, bool showSides) {

    if(showSides || filled) {
        Line initial(GetX(), GetY(), GetZ(), GetStartPoint().GetX(), GetStartPoint().GetY(), GetZ(), false);
        initial.SetColor(color);

        Line terminal(GetX(), GetY(), GetZ(), GetEndPoint().GetX(), GetEndPoint().GetY(), GetZ(), false);
        terminal.SetColor(color);

        initial.Draw(dest, initial.GetColor(), false);
        terminal.Draw(dest, terminal.GetColor(), false);

    } else if(showCenter) {
        putpixel(dest, GetX(), GetY(), color);
    }

    //Draw arc first to prevent flood overflow.
    arc(dest, GetX(), GetY(), AngleConverter::RadianToFixed(_startAngle), AngleConverter::RadianToFixed(_endAngle), _radius, color);

    if(filled) {

        double distance = std::fabs(this->_endAngle - this->_startAngle);
        if(distance < a2de::A2DE_PI) {

            Line displace(GetStartPoint(), GetEndPoint(), false);
            Point displacePoint(displace.GetCenter());
            floodfill(dest, displacePoint.GetX(), displacePoint.GetY(), color);

        } else if(distance > a2de::A2DE_PI) {

            Line displace(GetStartPoint(), GetEndPoint(), false);
            Vector2D center_of_displacement(displace.GetCenter());
            Vector2D center_point(this->_center);
            Vector2D direction_of_center(center_of_displacement - center_point);

            double angle = std::atan2(direction_of_center.GetY(), direction_of_center.GetX());
            Vector2D flood_point = center_point - direction_of_center;
            flood_point += angle;

            double x = flood_point.GetX() > 0.0 ? std::ceilf(flood_point.GetX()) : std::floorf(flood_point.GetX());
            double y = flood_point.GetY() > 0.0 ? std::ceilf(flood_point.GetY()) : std::floorf(flood_point.GetY());
            floodfill(dest, x, y, color);

        } else {

            if(_startAngle == 0.0 || _endAngle == a2de::A2DE_2PI) {
                floodfill(dest, GetX(), GetY() - 1, color);
            } else if(_endAngle == 0.0 || _startAngle == a2de::A2DE_PI) {
                floodfill(dest, GetX(), GetY() + 1, color);
            }

        }

    }
}
4

3 回答 3

1

首先,关于您的“原文”评论。圆心点通常也称为圆心,逆时针最常见的惯例。就像 x 轴指向右侧和 y 轴向上一样,角度从正 x 轴开始。

要确定点 x,y 是否在以极坐标 (r,eta) 定义的区域内,只需将点 x_point,y_point 转换为极坐标

r_point=sqrt((x_point-x_circle)^2 + (y_point-y_circle)^2 )
eta_point=atan2((y_point-y_circle) , (y_point-x_circle))

使用atan2,那么你就不需要考虑符号和pi-flips等。c++中的atan和atan2有什么区别?

Now, is the radious within the 'sector' ?
if (r_point<r_sector) ... 

如果是这种情况,值得看一下角度部分:从 eta_point 和扇区的角度大小中减去星角

eta_point_new = eta_point - ang1
ang2_new = ang2 - ang1

现在,ang2_new 是该扇区在旋转方向上的大小,而 eta_point_new 是该点的距离。如果 ang2_new 为负数,则表示该扇区越过了您的角坐标的边界,因此您需要向其添加 2pi。然后:

if (eta_point_new < ang2_new) 
   ... then the point is inside...

很抱歉,我没有时间对此进行测试或用适当的 C++ 编写它,随心所欲地使用它。

于 2012-07-10T18:36:56.867 回答
0

正转方向为逆时针方向。我给出的是伪代码,而不是真正的 C++ 代码。

要确定旋转角度,请从结束角度减去开始角度。不要取绝对值。归一化到区间 [0, 2π)。

rot_angle = end_angle - start_angle;

while (rot_angle < 0)   
  rot_angle += TWO_PI;

现在我们需要在圆弧的中心和起点之间取一个点,并围绕中心旋转我们刚刚找到的总旋转角度的一半:

start_point = rotate (point (center.x+r, center.y), center, start_angle);
interior_point = rotate (midpoint (center, start_point), center, rot_angle/2);

pt将一个点绕原点旋转一个o角度theta

point rotate (point pt, point o, double theta)
{
  return point(cos(theta) * (pt.x-o.x) - sin(theta) * (pt.y-o.y) + o.x,
               sin(theta) * (pt.x-o.x) + cos(theta) * (pt.y-o.y) + o.y);

}

为了完整性:

point midpoint (point p1, point p2)
{
   return point((p1.x+p2.x)/2, (p1.y+p2.y)/2);
}
于 2012-07-10T21:00:25.197 回答
0

解决了:

1)计算圆心:

double e = GetEndAngle();
double s = GetStartAngle();
double d = e - s;

double arc_center_x = 0.0;
double arc_center_y = 0.0;
double offset = 0.0;
if(d < 0.0) {
    offset = PI;
}
arc_center_x = (GetPosition().GetX() + std::cos(((s + e) / 2.0) + offset) * GetRadius());
arc_center_y = (GetPosition().GetY() + -std::sin(((s + e) / 2.0) + offset) * GetRadius());
_center = Vector2D(x, y);

2)计算从该中心到扇区位置的线:

Line l(arc_center_x, arc_center_y, p_x, p_y);

3)获取始终位于扇区角度内部的那条线的中点:

double x = l.GetCenter().GetX();
double y = l.GetCenter().GetY();
于 2012-07-29T20:29:08.543 回答