V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iSNN
V2EX  ›  程序员

求教 C# 绘图问题

  •  
  •   iSNN · 2020-11-06 14:28:16 +08:00 · 2072 次点击
    这是一个创建于 1467 天前的主题,其中的信息可能已经有所发展或是发生改变。

    老师给的一个课题:

    用 C# 实现一个路况图,不需要 GIS 那样的,会给出道路的信息(横竖或者 45°这种简单的直线)和红绿灯,还有车辆的实时位置,车最多给十辆吧。要有缩放和拖动功能,1 秒刷一次

    各位大佬有什么好的方案吗...

    我现在是用 Graphics 来做的,Bitmap 手动做的二级缓存,缩放试过了 graphics 的 ScaleTransform,试过了构造函数直接给个新 size 再 new 一个 bitmap 来,试过了 drawimage 来缩放,但是效率都太低了,太卡了。调了 BitBlt 也还是太慢。

    请问各位大佬有好的方案吗?

    29 条回复    2020-11-13 13:59:34 +08:00
    GM
        1
    GM  
       2020-11-06 14:36:56 +08:00
    这问题,看得头皮发麻。。。。。


    “GIS 那样的”是怎样?

    “不需要 GIS 那样的”是什么意思?

    “效率太低”指的是缩放的时候效率低,还是所有时候效率都低?


    最后:
    缩放为什么会需要 ScaleTransform 、new Bitmap 、drawimage ?计算好比例,直接用 g.drawXxx 画到 buffer 里,然后 BitBlt 出来不就好了吗?
    shaderlab
        2
    shaderlab  
       2020-11-06 14:42:04 +08:00
    用 Unity3D 呀,也算 C# 开发吧,实现你这个功能太容易了
    iSNN
        3
    iSNN  
    OP
       2020-11-06 14:50:07 +08:00
    @GM GIS 那样就是要和真实地理信息结合,有海拔那些什么乱七八糟的,曲折的。不要那么具体的,地图只是简单的横竖 45°组成。效率低缩放是最严重的,其余也不高,明显感觉卡顿。
    缩放直接用 DrawXxx 不是 drawimage 吗?
    across
        4
    across  
       2020-11-06 14:54:13 +08:00
    嵌入 OpenGL/DirectX
    xxiu
        5
    xxiu  
       2020-11-06 14:55:52 +08:00
    需要将变化的和不变的独立出来,每次只在不变的上面画变化的,双缓冲,也就是 bitmap 变化异步刷新到界面。
    kanezeng
        6
    kanezeng  
       2020-11-06 14:56:23 +08:00
    Unity 吧,2D/3D 都简单。
    MinQ
        7
    MinQ  
       2020-11-06 14:58:35 +08:00
    这是 AGV 的实时监控吧,网上有个开源的 DragCanvas
    MinQ
        8
    MinQ  
       2020-11-06 14:58:56 +08:00
    @kanezeng 用 Unity 就整复杂了
    iSNN
        10
    iSNN  
    OP
       2020-11-06 15:17:52 +08:00
    @MinQ 感谢,我去看看这个。你这么一说 AGV 实时监控我开始怀疑是一个商业课题,被迫免费劳动力 2333
    GM
        11
    GM  
       2020-11-06 15:24:15 +08:00
    你对二级缓存理解错误了,Bitmap 做二级缓存不是这样做的。

    感觉你是做成了先画一张大图到 Bitmap 里,然后想通过缩放图片的方式来做缩放,这样当然慢了,奇慢无比。

    Bitmap 做二级缓存,是在需要更新画面的时候,不直接往屏幕上 DrawXxx,而是先往缓存 Bitmap 里 DrawXxx,所有东西都 Draw 完后,一句 BitBlt 直接输出到显示屏上,避免了直接在屏幕上各种 Draw 导致的闪烁。
    xdtr
        12
    xdtr  
       2020-11-06 15:40:44 +08:00
    使用 BufferedGraphicsContext 和 BufferedGraphics
    MinQ
        13
    MinQ  
       2020-11-06 15:42:22 +08:00
    @GM 话说这个不需要二级缓冲吧,就建个 WPF 的工程,搞个 Canvas 把车辆和地图上的标识当成组件扔进去,然后建个定时器,更新一下车辆组建的位置就完事了。画界面的破事都让 WPF 后面的 DirectX 处理去,这种量级的界面重绘根本就不需要二级缓冲
    iSNN
        14
    iSNN  
    OP
       2020-11-06 15:53:03 +08:00
    @GM 那请问怎么缩放呢?都 BitBlt 我不会直接往屏幕上 Draw 的......
    rocbomb
        15
    rocbomb  
       2020-11-06 15:57:16 +08:00
    @MinQ 我觉得反倒简单了
    这种需求,用 Unity 的 2d 一下午就撸出来了,而且绝对不会有性能问题
    rocbomb
        16
    rocbomb  
       2020-11-06 16:00:08 +08:00
    或者 monogame
    这个需求用游戏引擎来解决,会非常舒服
    MinQ
        17
    MinQ  
       2020-11-06 16:11:21 +08:00
    @rocbomb 本来用控件就不会有性能问题,这种项目我是做过的,用 Unity 的话还要学一堆 Unity2D 的东西,我个人觉得是犯不着。
    GM
        18
    GM  
       2020-11-06 16:33:52 +08:00
    @iSNN
    大概是这样:
    假设你显示区域大小为 W 、H,缩放系数为 x
    需要 new 一个和你目标显示区域一样大小的 bitmap,
    然后根据当前缩放比例,往 bitmap 上 draw 各种元素,也就是你说的横竖、斜 45 度的线条。
    draw 完后,BitBlt 到显示区域对应的 Graphics 对象中。
    完事。
    iSNN
        19
    iSNN  
    OP
       2020-11-06 16:37:13 +08:00
    @GM 您的意思是,重新绘图,比缩放图片要快?我确实没有缩放后再画线,我是一个原图,然后路线啊,红绿灯位置这些固定的画好,然后缩放后再画动态的东西,再 BitBlt
    zhujinliang
        20
    zhujinliang  
       2020-11-06 16:43:40 +08:00 via iPhone
    肯定先画大图然后缩放效率不行,而且图像会模糊
    ,应建立跟显示界面大小一样的缓冲区,使用数学计算进行坐标的缩放,根据缩放后的坐标绘制到缓冲区,最后 bitblt 到前台
    再不行就看看 SVG 方面有没有现成的东西
    kokutou
        21
    kokutou  
       2020-11-06 16:51:24 +08:00 via Android
    套个 cef 用网页画。。。

    其他的手画遇到 hidpi 缩放就跪了啊。。。
    GM
        22
    GM  
       2020-11-06 17:09:07 +08:00
    @iSNN 那当然了,图片缩放很慢的,慢得惨无人寰。想要快,事先准备好各种比例的图片,直接 draw 上去,别缩放。
    binsys
        23
    binsys  
       2020-11-07 09:45:35 +08:00
    CefSharp(或 CefGlue) 壳,跑 HTML 版本的 Leaflet openlayers d3 等,在 Leaflet openlayers 上做。
    iSNN
        24
    iSNN  
    OP
       2020-11-13 09:48:34 +08:00
    @MinQ 谢谢大佬的指点...这几天学了 WPF 的东西,图基本上是画出来了。但是遇到了个问题,我是用 Shapes 里面的图形去画的,道路就是 Line,信号灯就是 Ellipse......不过这些东西都会有一些其他属性,但是这些类都是 sealed 密封类不能继承。我现在就是把这些无法用 Shapes 表示的属性写个类来存储放在一个数组里,然后把道路啊信号编上 Name,然后根据 Name 去数组匹配.......比如一个事件的监听,从 sender 得到 Name,然后 for 数组找匹配的对象,在根据对象里的属性显示不同的东西。请问大佬有好的解决方案吗
    MinQ
        25
    MinQ  
       2020-11-13 12:15:32 +08:00 via Android
    @iSNN 写个新类继承 shape 呗,把想要的属性加上
    MinQ
        26
    MinQ  
       2020-11-13 12:15:47 +08:00 via Android
    @iSNN 控件同理
    iSNN
        27
    iSNN  
    OP
       2020-11-13 13:36:29 +08:00
    @MinQ 我也这样想过...但是那些图形的实现我也是不明白,去 referencesource.microsoft.com 找的代码,发现掉了很多 internal 的东西。那就算了吧,找了下 Dictionary 的效率挺不错的,不用数组了,这样效率应该不慢
    MinQ
        28
    MinQ  
       2020-11-13 13:58:47 +08:00 via Android
    @iSNN extends 下来以后会直接把父类的方法都继承了啊,根本不需要再写一遍
    MinQ
        29
    MinQ  
       2020-11-13 13:59:34 +08:00 via Android
    @MinQ 我 github 上有个 AGVMonitor,你参考一下吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4055 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:58 · PVG 08:58 · LAX 16:58 · JFK 19:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.