【问题标题】:Rogue line being drawn to window流氓线被绘制到窗口
【发布时间】:2017-06-13 04:44:36
【问题描述】:

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

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

正如您所见,这条“流氓”线似乎在接近原点时改变了颜色。我的第一个问题是这条线是什么,我怎样才能从我的窗户上根除它?

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

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

我绘制到窗口的代码是:

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));
    }
}

更新 2:

以下代码摆脱了流氓行:

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)));
}

【问题讨论】:

  • @user3853544 你指的白线我认为是轴。该代码包含在我帖子的最后一部分中。 “axis[n].pos...”部分。
  • @billy606 Spekre 在他的回答中对此有一些代码,我只想添加一个条件,即连续的 y 值具有相反的符号,只是为了更加确定它是不连续的,而不仅仅是连续大跳跃
  • @billy606 顺便说一句,你好像在做这样的事情:plotting real time Data on (qwt )Oscillocope 这对你来说可能会很有趣
  • @Spektre 哦,当然。好吧,确实确定这是一个不连续的部分,并且确定不虐待连续的部分,我认为这很有趣,但并不那么容易。取决于他需要什么。如果只是一些化妆品,任何有效的都可以。另一方面,如果它应该适用于任何类型的功能,我实际上建议将其作为一个单独的问题
  • @Spektre 在考虑了两次之后......如果有像y=|tan(x)| 这样的不连续性,那么无论如何连接线都是不可见的:P

标签: c++ math graphics 2d sfml


【解决方案1】:

第一个问题看起来像是错误的折线/曲线处理。不知道您使用什么 API 进行渲染,但像 GDI 之类的 API 需要正确启动 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它检测到的跳跃越大...我伪造了由黑色(背景)分割的曲线,它会在轴交叉点上产生间隙(除非使用透明度) ...但不需要曲线列表...

【讨论】:

  • 他使用 SFML 作为标签指示,并使用 SFML 的 sf::VertexArray 作为线条,没有通用的方法来模拟“移动到”命令,除非你开始第二次抽奖打电话。
  • @Mario 我不使用 SFML,但大多数顶点数组实现都知道边缘标志数组(如 OpenGL)......您可以在其中编码 MoveTo
  • 感谢您的代码。它完美地解决了渐近线问题。
【解决方案2】:

这些伪影是由于 sf::PrimitiveType::LinesStrip 的工作方式造成的(或者更具体的线条通常是条带)。

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

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

【讨论】:

  • 有没有像 LinesStrip 这样的原始类型(我认为是这样的哈哈)会让我没有流氓线?
  • @billy606 sf::PrimitiveType::Lines 但这需要您为每个线段提交起点和终点,即将顶点数加倍。
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 2022-01-02
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多