Winapi 如何检测多重图边上的点击?

Winapi 如何检测多重图边上的点击?,winapi,graph,gdi+,edge-detection,Winapi,Graph,Gdi+,Edge Detection,我已经编写了一个基于win32 api的GUI应用程序,它使用GDI+功能,如DrawCurve()和DrawLine() 此应用程序绘制表示多重图形的直线和曲线 edge的数据结构只是一个由五个int组成的结构。(x1、y1、x2、y2和id) 如果两个顶点之间只有一条边,则使用DrawLine()绘制直线段。 如果有多条边,则使用DrawCurve()绘制曲线——在这里,我围绕两个顶点的中点展开直线边,使它们成为曲线。使用法线方程计算一个点,该点与它相隔若干单位像素。如果添加更多边,则选择距

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

此应用程序绘制表示多重图形的直线和曲线

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

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

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

  • 在查找直线边时,为了尽可能缩短搜索时间,我应该做什么?
    检查单击的像素是否在线段上非常简单,但如果边的数量很大,则比较所有边的效率会很低。似乎可以在O(logn)中执行此操作,其中n是边数。
    编辑:此时边(类边)存储在映射边id(int)的std::map中 到边缘对象,我正在考虑声明另一个将像素映射到边缘id的容器。
    我正在考虑使用二进制搜索树,但关键是什么?或者我应该只使用2D像素阵列

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


  • 如果有复杂的造型线,可以执行以下操作:

    • 创建一个图形大小的内部位图,并用黑色填充
    • 渲染图形时,也会将要单击的边渲染到此位图,但是,请使用其他颜色渲染它们。将这些颜色值与相应的ID一起存储在表中。这里重要的是颜色不同(唯一)
    • 单击图形时,将X和Y坐标传输到内部位图并读取像素。如果不是黑色,请在表中查找颜色值并获取关联的ID
    这种方法根本不需要担心形状,也不需要使用自己的曲线算法等等。成本是额外的内存,这将是一个考虑因素,但除非它是一个巨大的图形(在这种情况下,您可以缓冲图形),否则在大多数情况下这不是一个问题。您可以在第二遍中渲染内部位图,以使主图形显示得更快(与往常一样)

    希望这有帮助


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

    目的是检测是否单击了边,还是需要根据单击边的位置检索值?仅检测单击的边即可。然后将检索边的id并查找std::map。在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 mil.不同颜色,甚至16位位图)在1920x1080空间中,由于屏幕上只有大约200万像素可用,所以您永远无法使用所有颜色。