MaLiang icon indicating copy to clipboard operation
MaLiang copied to clipboard

渐进恢复数据

Open Harley-xk opened this issue 5 years ago • 58 comments

新开 issue,渐进恢复数据问题集中在这里讨论

Harley-xk avatar May 11 '19 08:05 Harley-xk

哈哈哈,这个响应速度可以呀。 https://github.com/Harley-xk/MaLiang/issues/34

liufsd avatar May 11 '19 08:05 liufsd

自己给自己加班中。。。

Harley-xk avatar May 11 '19 08:05 Harley-xk

哈哈哈。。。 +1 。。。 有什么好的思路么?

liufsd avatar May 11 '19 08:05 liufsd

@liufsd 这几个属性的访问权限忘了调整了,我来改一下。要对单个线条进行渐进恢复的话,需要深入到LineStriplines 属性了,思路是一样的。 不过现在 redraw() 函数确实存在性能问题,画布内容数量多的时候重绘的效率比较低(可以在缩放画布上测试,现在缩放的时候是每一帧调用 redraw 的),要避免高频调用。暂时还没有好的优化的办法,需要深入研究一下 Metal 的高阶用法。

Harley-xk avatar May 11 '19 08:05 Harley-xk

是的。之前openGL的方案,当时体验这个效果的思路大概也是这样的,内容不多的话,好像也还可以的吧。

liufsd avatar May 11 '19 08:05 liufsd

还有就是,如果操作数据是在子线程,redraw() 又在主线程,这样切换线程性能开销也是个问题。

liufsd avatar May 11 '19 08:05 liufsd

嗯, 内容不多的话, 适当控制一下频率(比如每秒十次), 问题应该不大

Harley-xk avatar May 11 '19 08:05 Harley-xk

redraw 要把内容提交到缓冲区,只能在主线程操作。数据量不大的话,可以考虑把数据操作也放在主线程,或许可以稍微提升一些速度。 不过从目前调试的结果来看,性能瓶颈主要在 buffer 的创建和释放上。

Harley-xk avatar May 11 '19 08:05 Harley-xk

嗯 好像这样的话,每次 canvas.data.elements拿到的数据都是上一次的数据加上接下来要话的元素集合。然后再调用redraw() , 不知道会不会有问题,毕竟相当于同一个坐标掉被绘制了很多次。

内容放在缓冲区?是指?

liufsd avatar May 11 '19 08:05 liufsd

Metal 层要把需要显示的像素数据提交到缓冲区才能在屏幕上显示,redraw 会触发这一步操作,所以也要在主线程调用。

Harley-xk avatar May 11 '19 08:05 Harley-xk

嗯 听下来:大概思路是:每隔一段时间取一下数据到 canvas.data.elements 上,然后再调用 canvas.redraw()

liufsd avatar May 11 '19 08:05 liufsd

差不多是这样,其实恢复数据和绘制过程是很类似的,一个是通过用户手势触发相关操作,向 canvas.data 中添加数据,一个是由我们的程序主动向其中添加数据,最终结果是一样的。 用这种思路,甚至可以添加一些原本不是用户绘制的内容,这个就可以看上层 App 的发挥了。

Harley-xk avatar May 11 '19 08:05 Harley-xk

嗯,是的,只是程序每隔一段时间绘制一个线条。 拉取了你刚才提交的代码’ $0.brush‘ 编译不过。 image

liufsd avatar May 11 '19 08:05 liufsd

改过来了

在 2019年5月11日,16:48,liupeng [email protected] 写道:

嗯,是的,只是程序每隔一段时间绘制一个线条。 拉取了你刚才提交的代码’ $0.brush‘ 编译不过。 https://user-images.githubusercontent.com/1910405/57567482-9cc38680-740c-11e9-9806-5167026ffdd8.png — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Harley-xk/MaLiang/issues/43#issuecomment-491492838, or mute the thread https://github.com/notifications/unsubscribe-auth/ADBLWHOU46SOYDK4ZB3HOTLPU2B6NANCNFSM4HMHS6KA.

Harley-xk avatar May 11 '19 08:05 Harley-xk

嗯 看到了的,写了个简单的实现,效果不是很理想:

 let elements: [CanvasElement] = (content.lineStrips + content.chartlets).sorted(by: { $0.index < $1.index})
        let list = elements.chunks(3)
        for frames in list {
            sleep(1)
            canvas.data.elements += frames
            DispatchQueue.main.async {
                /// redraw must be call on main thread
                canvas.redraw()
            }
        }

extension Array {
    func chunks(_ chunkSize: Int) -> [[Element]] {
        return stride(from: 0, to: self.count, by: chunkSize).map {
            Array(self[$0..<Swift.min($0 + chunkSize, self.count)])
        }
    }
}

有其他什么好的思路么?

liufsd avatar May 11 '19 09:05 liufsd

感觉都是一个一个线条直接“蹦”出来的,不是很理想~

liufsd avatar May 11 '19 09:05 liufsd

粒度再细一些,对每一个linestrip的数据也进行渐进恢复,另外时间间隔可以再短一些

在 2019年5月11日,17:14,liupeng [email protected] 写道:

感觉都是一个一个线条直接“蹦”出来的,不是很理想~

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

Harley-xk avatar May 11 '19 10:05 Harley-xk

啊? 我看你做的数据源不是: content.lineStrips + content.chartlets 还加了排序的么? 能在例子中添加一个简单实现不? 我看一下你那边的思路。

liufsd avatar May 11 '19 10:05 liufsd

linestrip 的 lines 数组中的 MLLine 也用定时器一个一个添进去

发自我的 iPhone

在 2019年5月11日,18:42,liupeng [email protected] 写道:

啊? 我看你做的数据源不是: content.lineStrips + content.chartlets 还加了排序的么? 能在例子中添加一个简单实现不? 我看一下你那边的思路。

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

Harley-xk avatar May 11 '19 10:05 Harley-xk

定时器?

liufsd avatar May 11 '19 10:05 liufsd

不一定用定时器,像你之前用 sleep 也没什么问题。 主要是要对每一条 LineStrip 本身进行渐进恢复,原来直接操作 canvas.data.elements 是没有这么细的,elements 里面每一个元素都是一条完整的线,不能直接添加进去。一个 LineStrip 由 n 多个 MLLine 组成,应该把每一个 LineStriplines 属性里面的 MLLine 元素拿出来,也用逐渐添加的方式添加回去,同时进行重绘。一条线恢复完了之后下一条线继续这么做,这样一条线才是逐渐画出来的。你可以看一下 Canvas 里面 pushPointrender(lines:) 两个方法的实现。

Harley-xk avatar May 11 '19 12:05 Harley-xk

我后面写一个专门给渐进恢复数据用的重绘方法。现在的重绘是针对清空、缩放还有平移这种会导致整个画布的内容发生变化的场景用的,所以每次都会清空画布之后对所有数据进行重绘,所以效率比较低。渐进恢复数据的时候其实不需要清空画布全部重新绘制,可以只绘制新增的内容,这样就不会有性能问题了。

Harley-xk avatar May 11 '19 12:05 Harley-xk

嗯,好,什么时候更新呢?很期待您的更新哦,感觉是一个比较炫酷的功能。 我刚才也只是先尝试体验一下~发现那样做确实效果不好。

liufsd avatar May 11 '19 13:05 liufsd

要晚一些,最近事情比较多

Harley-xk avatar May 11 '19 13:05 Harley-xk

哈哈哈哈 好的 看来大家最近 都一样…

liufsd avatar May 11 '19 15:05 liufsd

有进展了么? 哈哈哈😝~

liufsd avatar May 20 '19 06:05 liufsd

😅还没有空出来

Harley-xk avatar May 21 '19 02:05 Harley-xk

还记得之前跟你讨论过的么? 如果是把大画板上画的数据恢复到一个小的画板上么? 似乎不行,因为对应的坐标点在小的画板上已经超出view的范围了的。所以需要对每条mlline进行缩放。???

1559372163555.maliang.zip

liufsd avatar Jun 01 '19 07:06 liufsd

你可以下载我之前写的App: Soul Sketch 体验一下这个场景,当时基于的OpenGL的方案。

liufsd avatar Jun 01 '19 07:06 liufsd

应该是在恢复之前检查保存文件中的画布大小属性,然后重设当前画板的大小之后再执行数据恢复的操作。 画布尺寸保存在 content 文件里面的 size 字段。 不过恢复数据的时候也要看情况,针对固定大小的画板,应该是是重设尺寸,如果是可滚动的画板,应该是重设 content size。 重设尺寸这一步目前可以在自定义的数据恢复逻辑里面做。在 MaLiang 内置的 DataImporter 里面暂时还没有实现,需要考虑一个完善的策略。

Harley-xk avatar Jun 01 '19 07:06 Harley-xk