4

我有数十万个时间序列数据点要向用户表示。我目前的解决方案是使用 3rd 方库将所述数据呈现为 PNG,然后将该 PNG 加载到 aNSImage中并在滚动视图中显示。这很好用,除了:

  1. 超过 32k 像素宽的 NSImage 无法正确显示
  2. 我希望能够快速轻松地放大数据
  3. 从磁盘读取和写入是愚蠢的

我目前的尝试是直接将NSBezierPaths 绘制到 a NSView。即使我一次只绘制有限的点子集,该视图也呈现精美,但非常非常缓慢。每次滚动时,我都必须重新绘制,这也很慢。

我敢肯定,作为一个相对的 Co​​coa 新手,我错过了一些更好的方法来做到这一点。什么是“正确”的做法?

4

6 回答 6

6

我目前的尝试是直接将 NSBezierPaths 绘制到 NSView。即使我一次只绘制有限的点子集,该视图也呈现精美,但非常非常缓慢。每次滚动时,我都必须重新绘制,这也很慢。

在您采取任何激进的解决方案之前,请尝试以下更简单的步骤:

  1. 夹子。使用NSRectClip,将您作为参数的矩形传递给drawRect:. 这是一个单行。
  2. 在填充路径之前进行简单的矩形测试。对于每条路径,获取它的边界并使用NSIntersectsRect它来测试它是否在矩形内。
  3. 在描边路径之前进行稍微不那么简单的矩形测试。与上一步类似,除了您需要将矩形(作为参数接收的那个)扩大线宽,因为一半的笔划将落在路径之外。对于每条路径,获取线宽并将其取反(delta = -[path lineWidth]- 是的,您必须包含该减号),然后将结果作为两个参数传递给NSInsetRect. 确保保留原始矩形,因为不同的路径可能有不同的线宽。

这个想法很简单,就是少画。设置剪切路径(使用NSRectClip)将减少绘图操作导致的位块传输量。排除完全落在绘制矩形之外的路径将为您节省可能更昂贵的路径剪裁。

而且,当然,您应该在每个步骤中进行分析,以确保您没有让事情变慢。您可能想要设置某种帧速率计数器。

还有一件事:获取每条路径的界限可能很昂贵。(再次,配置文件。)如果是这样,您可能希望缓存每个路径的边界,可能使用 s 的并行NSArrayNSValue通过将路径和边界包装在一起在您自己设计的对象中。然后,您只需计算一次边界,然后在以后的绘图运行中检索它。

于 2009-01-30T03:39:31.137 回答
2

文档有一个关于NSBezierPath 性能的部分。

于 2009-01-29T21:45:15.207 回答
2

如果您要绘制那么多贝塞尔路径,OpenGL 可能是要走的路。Apple 的文档将是一个很好的起点。他们有在可可窗口中实现基本 OpenGL 渲染上下文的示例代码。

这会将困难的绘图任务的负担转移到图形处理器上,让您的应用程序可以随意滚动。

这个页面有用于绘制贝塞尔曲线的示例 OpenGL 代码。

于 2009-01-29T22:26:01.677 回答
2

为此,我会查看 CATiledLayer(仅限 Leopard)。您可以在平铺图层中绘制大量内容并根据需要显示区域。对于您的情况,您可以将 CATiledLayer 设置为 NSView 的支持,将所有贝塞尔路径绘制到该层,然后滚动甚至放大和缩小它。核心动画层像 OpenGL 纹理一样处理,因此您应该从中获得非常好的性能。矢量绘图缓存在图层中,并且在您滚动时不会重绘,就像您在标准 NSView 上找到的那样。

例如,Bill Dudney发布了一些关于如何使用 CATiledLayer 显示大量 PDF 文件的示例代码。

于 2009-01-30T21:25:08.257 回答
2

数据集的动态性如何?

如果它是相当静态的,并且您想要“缩放”,那么您应该考虑将数据合并到一个缩放的子集中。

人为的例子:如果你有 100,000 点(比如在 X 轴上前进),那么,很明显,在 1000 像素的图像中,你只会不可避免地绘制这 100,000 点中的 1000 点。

因此,您可以提前执行此操作(1000 分、10000 分、100000 分的原始数据),并根据您正在显示的“缩放”级别从适当的集合中进行选择。

至于点重叠时选择什么值,可以做min、max、median、average等。

于 2009-01-30T21:35:35.023 回答
0

考虑使用一个可以有效处理这类事情的框架,比如CorePlot

于 2012-10-01T09:02:11.560 回答