流氓线被绘制到 window

Rogue line being drawn to window

我正在使用 SFML 库在 C++ 中制作图形程序。到目前为止,我已经能够在屏幕上绘制一个函数。一路上我遇到了两个问题 运行。 第一条线似乎 return 到我的飞机的原点,从我的函数结束开始。

您可以在这张图片中看到它:

如您所见,这条 "rogue" 线似乎在接近原点时改变了颜色。我的第一个问题是这条线是什么以及如何从我的 window 中删除它?

第二个问题稍微不相关但更数学化,可以在这张图中看到:

如您所见,绘制的渐近线是图形未定义或不连续的点。这引出了我的第二个问题:有没有办法(在代码中)识别渐近线而不是将其绘制到 window.

我对 window 绘制的任何内容的代码是:

VertexArray axis(Lines, 4);
VertexArray curve(PrimitiveType::LinesStrip, 1000);

axis[0].position = Vector2f(100000, 0);
axis[1].position = Vector2f(-100000, 0);
axis[2].position = Vector2f(0, -100000);
axis[3].position = Vector2f(0, 100000);

float x;

for (x = -pi; x < pi; x += .0005f)
{
    curve.append(Vertex(Vector2f(x, -tan(x)), Color::Green));
}

如有任何意见,我将不胜感激:)

更新:

感谢许多人的输入,这段代码似乎可以很好地解决渐近线问题:

for (x = -30*pi; x < 30*pi; x += .0005f)
{
    x0 = x1; y0 = y1;
    x1 = x; y1 = -1/sin(x);
    a = 0; 
    a = fabs(atan2(y1 - y0, x1 - x0));
    if (a > .499f*pi)
    {
        curve.append(Vertex(Vector2f(x1, y1), Color::Transparent));
    }
    else
    {
        curve.append(Vertex(Vector2f(x1, y1), Color::Green));
    }
}

更新二:

下面的代码摆脱了流氓行:

VertexArray curve(Lines, 1000);
float x,y;
for (x = -30 * pi; x < 30 * pi; x += .0005f)
{
    y = -asin(x);
    curve.append(Vertex(Vector2f(x, y)));
}
for (x = -30 * pi + .0005f; x < 30 * pi; x += .0005f)
{
    y = -asin(x);
    curve.append(Vertex(Vector2f(x, y)));
}

第一个问题 看起来是一个错误的polyline/curve 处理。不知道你用什么 API 来渲染,但有些像 GDI 需要正确启动 pen 位置.例如,如果你这样画:

Canvas->LineTo(x[0],y[0]);
Canvas->LineTo(x[1],y[1]);
Canvas->LineTo(x[2],y[2]);
Canvas->LineTo(x[3],y[3]);
...

那么你应该这样做:

Canvas->MoveTo(x[0],y[0]);
Canvas->LineTo(x[1],y[1]);
Canvas->LineTo(x[2],y[2]);
Canvas->LineTo(x[3],y[3]);
...

如果您的 API 需要 MoveTo 命令,而您没有设置它,则使用最后一个位置(或默认 (0,0))这会将曲线的起点与上次绘制或默认笔位置的直线连接起来。

第二题

在连续数据中,您可以通过检查后续的 y 值来确定渐近线或不连续点的阈值。如果你的曲线渲染看起来像这样:

Canvas->MoveTo(x[0],y[0]);
for (i=1;i<n;i++) Canvas->LineTo(x[i],y[i]);

那你可以改成这样:

y0=y[0]+2*threshold;
for (i=0;i<n;i++)
 {
 if (y[1]-y0>=threshold) Canvas->MoveTo(x[i],y[i]);
  else                   Canvas->LineTo(x[i],y[i]);
 y0=y[i];
 }

问题在于阈值的选择,因为它取决于 x 采样点的密度以及 y 数据的 x(斜角)的一阶推导

如果您要叠加更多函数,曲线附加将创建您不需要的线...而不是将每个数据作为单独的绘图处理或在它们之间放置 MoveTo 命令

[编辑1]

我是这样看的(假分裂):

double x0,y0,x1,y1,a;
for (e=1,x = -pi; x < pi; x += .0005f)
    {
    // last point
    x0=x1; y0=y1;
    // your actual point
    x1=x; y1=-tan(x);
    // test discontinuity
    if (e) { a=0; e=0; } else a=fabs(atan2(y1-y0,x1-x0));
    if (a>0.499*M_PI) curve.append(Vertex(Vector2f(x1,y1), Color::Black));
     else             curve.append(Vertex(Vector2f(x1,y1), Color::Green));
    }

0.499*M_PI 是你的阈值,越接近 0.5*M_PI 它检测到的跳跃越大......我伪造了黑色(背景)分割的曲线它会在轴交叉点上产生间隙(除非使用透明度)...但不需要曲线列表...

这些伪像是由于 sf::PrimitiveType::LinesStrip 的工作方式(或一般更具体的线条条)造成的。

在你的第二个例子中,可视化 y = -tan(x),你从正无穷大跳到负无穷大,这就是你看到的线。你无法摆脱这一点,除非你使用不同的原始类型或将渲染拆分为多个绘制调用。

将线条想象成一根用图钉固定的长线(代表顶点)。没有这些伪像,就没有(安全的)方法可以从正无穷大到负无穷大。当然,您可以移到可见区域之外,但话又说回来,这确实是这个功能所特有的。