积极答复者
还是关于画点的几个疑问?

问题
-
我现在需要在canvas上进行画点,用的办法也是版主建议的:
EllipseGeometry dot= new EllipseGeometry();
dot.RadiusX = dot.RadiusY = 0.3;// radius;
dot.Center = position;我有几个疑问:
第一:关于圆半径的设定。如果我只需要一个像素,是不是就设为0呢?
实际上,我尝试设为0之后,发现每个像素的亮度和表现的效果都不太好,给人一种不饱满的感觉。
第二:我尝试用画一个像素的线来替代这种方法:
LineGeometry line = new LineGeometry();
line.StartPoint = position;
line.EndPoint = position;在试验的过程中,我发现 像上面那么写是不会有任何图形的,于是我就把
line.EndPoint =new Point( position.X+1,position.Y);
这样的话,图形就出现了,但我不确定这是不是一个点像素?如果不是的话,改怎么设定结束点的位置呢?
第三:我感觉使用第二种方法比第一种方法,程序执行起来要快一些,不知道是不是我的错觉?
第四:就像第二个问题提到的那样,会经常性的看到很多点 有些模糊,“不饱和”的感觉,而且亮度也低了很多。是不是点的位置中横坐标或纵坐标 是不是整数的原因呢?
第五:关于画大量的点,程序速度的问题。我看到之前版主回复的帖子上,有一个这方面的例子,但是水平有限,看不大懂。不知道有没有什么机制,可以加快画大亮点运算的速度呢?
请教版主和诸位高手啊,多谢多谢!
Best Regards! C.Lu
答案
-
你好 C.Lu,
是的,根据我的经验,第二种会好点。
你画的是一个像素的点。
不饱和的感觉? 你改变一下UseLayoutRounding属性,参考这个链接:
http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.uselayoutrounding.aspx
我上传的那个例子我没看,不过我建议你看看WPF performance相关的文章,MSDN上面就有,我感觉你看这方面的文章比花费时间研究那个例子的机制会好些,收获的也更多。
http://msdn.microsoft.com/zh-cn/library/aa970683.aspx
http://msdn.microsoft.com/zh-cn/library/aa969767.aspx
(有些地方中文翻译的不是很nice,你也可以看英文的。)
Best regards,
Sheldon _Xiao[MSFT]
如果您对我们的论坛在线支持服务有任何的意见或建议,请通过邮件告诉我们。
立刻免费下载 MSDN 论坛好帮手
- 已标记为答案 C.Lu 2011年3月11日 6:46
- 已编辑 Sheldon _XiaoModerator 2011年3月16日 7:50
全部回复
-
你好 C.Lu,
是的,根据我的经验,第二种会好点。
你画的是一个像素的点。
不饱和的感觉? 你改变一下UseLayoutRounding属性,参考这个链接:
http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.uselayoutrounding.aspx
我上传的那个例子我没看,不过我建议你看看WPF performance相关的文章,MSDN上面就有,我感觉你看这方面的文章比花费时间研究那个例子的机制会好些,收获的也更多。
http://msdn.microsoft.com/zh-cn/library/aa970683.aspx
http://msdn.microsoft.com/zh-cn/library/aa969767.aspx
(有些地方中文翻译的不是很nice,你也可以看英文的。)
Best regards,
Sheldon _Xiao[MSFT]
如果您对我们的论坛在线支持服务有任何的意见或建议,请通过邮件告诉我们。
立刻免费下载 MSDN 论坛好帮手
- 已标记为答案 C.Lu 2011年3月11日 6:46
- 已编辑 Sheldon _XiaoModerator 2011年3月16日 7:50
-
绘制椭圆确实要慢很多,椭圆多复杂啊.想想就慢.
LineGeometry应该会快一些,要更快些换用StreamGeometry
想再快些,则不需要画1个像素的线,改为画连接每个点的线,只不过用DashStyle调整一下(1,1000),这样每画1个像素,就画一个巨大的空白,结果就是每个线段只画了最开始的1个点(注:没试过,理论上这应该比画1个像素的一把线要快)
使用的Pen有个属性叫DashCap,默认是flat,改为Round效果会好一点,thickness调粗,嘿嘿,猜你喜欢粗一点的,是吧
What?还不够快?你狠,WPF目前就这样了,再快得用direct3d了,可以通过互操作,把WPF绘图区交给direct3d设备来绘,用显卡硬件来画,现在500块的显卡每秒画几亿个点不成问题
-
好吧,我知道怎么用这玩意画线了,是像下面这样吗?
StreamGeometry dot = new StreamGeometry();
StreamGeometryContext context = dot.Open();context.BeginFigure(center, true, true);
context.LineTo(center, true, true);
context.Close();不过,速度真的会比画线的方法快吗?
又:
我设置了canvas的UseLayoutRounding ,还是会出现模糊,“不饱和”的现象.
请问,您有什么高见?
Best Regards! C.Lu -
<Window x:Class="T_Mar11.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="640" Height="480"> <Grid> <Image x:Name="image" Width="800" Height="600"/> </Grid> </Window>
private DrawingImage Build() { Random rand = new Random(); var pts = new Point[10000]; for (int i = 0; i < pts.Length; i++) { pts[i].X = rand.Next(0, 800); pts[i].Y = rand.Next(0, 600); } double thickness = 8.0; var ds = new double[(pts.Length - 1) * 2]; for (int i = 0; i < pts.Length - 1; i++) { ds[2 * i] = 0; ds[2 * i + 1] = Point.Subtract(pts[i], pts[i + 1]).Length / thickness; } var streamDrawing = new StreamGeometry(); using (var ctx = streamDrawing.Open()) { ctx.BeginFigure(pts[0], true, false); for (int i = 1; i < pts.Length; i++) ctx.LineTo(pts[i], true, true); } var pen = new Pen(Brushes.DarkBlue, thickness); pen.DashCap = PenLineCap.Round; pen.StartLineCap = PenLineCap.Round; pen.EndLineCap = PenLineCap.Round; pen.DashStyle = new DashStyle(ds, 0); pen.MiterLimit = 1.0; pen.LineJoin = PenLineJoin.Round; var drawing = new GeometryDrawing(null, pen, streamDrawing); var source = new DrawingImage(drawing); source.Freeze(); return source; }
// 最后设置一下Source属性
image.Source = Build();
-
这个称为 "光栅化" 问题
当在点阵式显示设备上呈现图形时,设备上的某些点并不如理论图形有那么高的精度,它必须和周围的点进行插值运算,这个过程叫"光栅化"
这里有个原因的简单解示http://www.ownself.org/oswpblog/?p=45
简单点,对于你的圆就是,理论上圆的边界通过了显示屏上的某个点的中央,即,这个点的一部分在圆内,一部分在圆外,而这个点是显示器所能呈现的最小范围,它不可能一半画你的圆,一半画背景色;"光栅化"过程将进行处理,通过插值,这个点既不是你圆的前景色,也不是背景色,而是这两种结果的混和插值结果.
UseLayoutRounding事实上就是对WPF的光栅化进行一些控制
特别的,如果你的点只有一个像素,光栅化程序理解你的圆点理论上应覆盖了那个显示器上的小点(矩形点)的内切圆,内切圆之外应该是背景色,于是按占据面积的百分比,这点的实际呈现色会混合大部分的圆的前景色,小部分的背景色,最后看起来,就是点变模糊了
估计你用"方形点"不用Round点,同时再设置UseLayoutRounding,不会出现模糊的点(没试过,理论上是这样),但圆形的外观就没了,熊与鱼掌不能兼得啊
对这部分的控制很麻烦,交给WPF自己处理算了.
可以考虑让点变大一点,确保点的正中能完全占据一整个像素,这样这个点的正中会很清晰,周围的点还是会模糊,但会保持较好的圆形感觉;事实上,这很并不所想象的那么简单,程序并不只在你的机器上运行,对方机器的物理特性会影响这个过程,比如,同样的程序,对方1024*768还是1280*768的分辨率,是32万色,还是16万色都会有不同的最终效果.
-
<Window x:Class="T_Mar11.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="640" Height="480"> <Grid> <Image x:Name="image" Width="800" Height="600"/> </Grid> </Window>
private DrawingImage Build() { Random rand = new Random(); var pts = new Point[10000]; for (int i = 0; i < pts.Length; i++) { pts[i].X = rand.Next(0, 800); pts[i].Y = rand.Next(0, 600); } double thickness = 8.0; var ds = new double[(pts.Length - 1) * 2]; for (int i = 0; i < pts.Length - 1; i++) { ds[2 * i] = 0; ds[2 * i + 1] = Point.Subtract(pts[i], pts[i + 1]).Length / thickness; } var streamDrawing = new StreamGeometry(); using (var ctx = streamDrawing.Open()) { ctx.BeginFigure(pts[0], true, false); for (int i = 1; i < pts.Length; i++) ctx.LineTo(pts[i], true, true); } var pen = new Pen(Brushes.DarkBlue, thickness); pen.DashCap = PenLineCap.Round; pen.StartLineCap = PenLineCap.Round; pen.EndLineCap = PenLineCap.Round; pen.DashStyle = new DashStyle(ds, 0); pen.MiterLimit = 1.0; pen.LineJoin = PenLineJoin.Round; var drawing = new GeometryDrawing(null, pen, streamDrawing); var source = new DrawingImage(drawing); source.Freeze(); return source; }
// 最后设置一下Source属性
image.Source = Build();
我的问题要复杂一点,每次都只画一条短短的线段,但是要画几万次。
上面的方法只能一次就把所有想画的都画出来,我需要每次来一个消息,就画一条线。