【问题标题】:How to detect a click on an edge of a multigraph?如何检测多图边缘上的点击?
【发布时间】:2019-01-28 00:29:02
【问题描述】:

我编写了一个基于 win32 api 的 GUI 应用程序,它使用了诸如 DrawCurve() 和 DrawLine() 等 GDI+ 功能。

此应用绘制代表多重图的直线和曲线。

边缘的数据结构只是一个由五个 int 组成的结构。 (x1, y1, x2, y2, 和 id)

如果两个顶点之间只有一条边,则使用 DrawLine() 绘制一条直线段。 如果有多个边,则使用 DrawCurve() 绘制曲线——在这里,我直线边沿两个顶点的中点展开,使它们成为曲线。使用法线方程计算距离它一些单位像素的点。如果添加更多边缘,则选择距离中点两个单位像素的像素,然后选择下一次 3 个单位像素,以此类推。

现在我有两个关于检测边缘点击的问题。

  1. 在寻找直线边缘时,为了尽量减少搜索时间,我应该怎么做?
    检查单击的像素是否在线段上非常简单,但是如果边数很大,比较所有边的效率会很低。似乎可以在 O(log n) 中完成,其中 n 是边数。
    编辑:此时边缘(边缘类)存储在映射边缘id(int)的std :: map中 到边缘对象,我正在考虑声明另一个将像素映射到边缘 id 的容器。
    我正在考虑使用二叉搜索树,但关键是什么?还是应该只使用二维像素阵列?

  2. 我可以得到 DrawCurve() 使用的点数组吗?如果这是不可能的,那么我应该重新计算基数样条,获取点数组,并检查用户点击的点是否与该数组中的任何点匹配。

【问题讨论】:

  • 目的是仅仅检测边缘是否被点击,还是需要根据点击边缘的位置来检索一个值?
  • 只检测点击了哪条边就可以了。然后将检索边缘的 id 并查找 std::map

标签: winapi graph gdi+ edge-detection


【解决方案1】:

如果你有复杂形状的线条,你可以这样做:

  • 创建一个与图表大小相同的内部位图并用黑色填充。
  • 当您渲染图形时,也将您希望可点击的边缘渲染到该位图,但是用不同的颜色渲染它们。将这些颜色值与相应的 ID 一起存储在一个表中。这里重要的是颜色不同(独特)。
  • 单击图形时,将 X 和 Y 坐标传输到您的内部位图并读取像素。如果不是黑色,请在表格中查找颜色值并获取相关 ID。

这种方式根本不需要担心形状,也不需要使用自己的曲线算法等等。成本是额外的内存,这是一个考虑因素,但除非它是一个巨大的图形(在这种情况下你可以缓冲绘图),否则在大多数情况下这不是问题。您可以在第二遍中渲染内部位图,以使主图形显示得更快(像往常一样)。

希望这会有所帮助!

(提示:您可以使用更宽的 Pen 渲染“内部”线条,使其更加敏感)。

【讨论】:

  • 在 1920 x 1080 分辨率和 32 bpp(因此一次可以绘制的最大边数为 2^32),大约需要 8 MB 的空间来检测每个边缘点击图形视图(在这里,我假设画布大小是固定的,因为位图缓冲区的频繁重新分配会大大降低性能)。我认为这是最简单和最快的 (O(1)) 实现方式,但起初它似乎浪费了太多空间 (O(xy)~=O(n^2))。但是,我可以降低 bpp 并减小位图缓冲区的大小,因为实际上,当绘制在一起时,甚至超过几千条曲线都不可见。
  • 当然,如果不可见 = 不可点击,因此您可以消除重叠实例。正如你所说,还可以通过将位图和 x/y 坐标减半来量化点击点,或者甚至将位图减少到 1/4,每个可点击点位于 4x4 像素区域,但如果您同时存在很多边缘,可能不太方便。我将只使用 24 bpp(2^24 或 16.8 百万。不同的颜色 - 甚至 16 位位图),因为在 1920x1080 空间中,您将永远无法使用所有颜色,因为只有大约 2 百万。屏幕上可用的像素。
猜你喜欢
  • 2016-12-14
  • 1970-01-01
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
相关资源
最近更新 更多