【问题标题】:Finding a point that is interior to a sector找到一个扇区内部的点
【发布时间】:2012-07-10 02:54:49
【问题描述】:

已解决:请参阅 my answer

我正在尝试找到一个位于圆弧内部的点,因此当发生填充时,它不会意外填充圆弧外的区域。只要两个角之间距离的绝对值: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);

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

方括号是我的符号。

我已经完成了从 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);
            }

        }

    }
}

【问题讨论】:

  • 如果你只有角度/起始角度你不能定义弧,你应该有 1) 一个有符号的扫掠角,或顺时针/逆时针方向,说明弧的哪个部分从开始到结束是要考虑的
  • @FelicePollano 顺时针/逆时针方向由图形库自动确定。如果起始角度大于结束角度,则为顺时针方向,反之亦然。
  • 您似乎使用术语“弧”来表示通常称为扇区的部分
  • @n.m.官方allegro 只绘制弧线(扇区的弯曲边界)。我正在扩展它,允许用户还绘制与其相邻的扇区的边。见arc
  • 文档明确指出方向是逆时针的。这与您关于我认为是(a)错误和(b)您遇到困难的原因的方向的说法完全矛盾。你应该谈论有符号的角距离(逆时针为正,顺时针为负)。永远不要取它们的绝对值,这是没有意义的。

标签: c++ geometry trigonometry sector


【解决方案1】:

首先,关于你的'sic' cmets。圆心通常也称为圆心,逆时针最常见的约定。就像 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等了。what is the difference between atan and atan2 in c++?

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++ 编写它,你可以随心所欲地使用它。

【讨论】:

    【解决方案2】:

    正转方向为逆时针方向。我给出的是伪代码,而不是真正的 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);
    }
    

    【讨论】:

      【解决方案3】:

      已解决:

      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-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多