views:

62

answers:

2
+2  Q: 

aliasing problem

hello,

the code below draws two vertical lines on a canvas. these lines appear to be of different thickness on the screen although they are the same in code. i am tying to find a way to make them look as sharp as the border around the canvas. setting Path.SnapsToDevicePixels does not have any effect. The code is a contrived example, and in general the canvas that plots these lines can be nested deeper inside the visual tree.

thanks for any help konstantin


<Window x:Class="wpfapp.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>
    <Border BorderBrush="Black"
            BorderThickness="1"
            Margin="10">
      <Canvas x:Name="Canvas"
              SizeChanged="OnCanvasSizeChanged" />
    </Border>
  </Grid>
</Window>

using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace wpfapp
{
    public partial class MyWindow : Window
    {
        public MyWindow()
        {
            InitializeComponent();
        }

        private void OnCanvasSizeChanged(object sender, SizeChangedEventArgs e)
        {
            StreamGeometry g = new StreamGeometry();
            double h = this.Canvas.ActualHeight;

            using (StreamGeometryContext c = g.Open())
            {
                c.BeginFigure(new Point(7, 0), false, false);
                c.LineTo(new Point(7, h), true, false);

                c.BeginFigure(new Point(14, 0), false, false);
                c.LineTo(new Point(14, h), true, false);
            }
            g.Freeze();

            Path p = new Path();

            p.Data = g;
            p.SnapsToDevicePixels = true;
            p.Stroke = new SolidColorBrush(Colors.Black);
            p.StrokeThickness = 1;

            this.Canvas.Children.Clear();
            this.Canvas.Children.Add(p);
        }
    }
}
A: 

Try adding

RenderOptions.EdgeMode="Aliased"

or in code behind

RenderOptions.SetEdgeMode(p, EdgeMode.Aliased);

UPDATE

The problem is SnapsToDevicePixels in combination with EdgeMode.Aliased. Remove SnapsToDevicePixels=true and keep EdgeMode.Aliased and you will get crisp 1px vertical lines

Meleak
this helps somewhat, and the lines appear antialiased but the thickness is still different if Path.StrokeThickness=1, if i set it to 2 the lines seem to be the same. i think i could replace lines with say rectangles, but i am plotting charts and lines can be arbitrary...
akonsu
@Meleak: thanks for the update. on screens with the default DPI it works, but on custom settings with pen thickness 1, it still has these thickness artifacts. with other pen sizes it seems ok. i had to use GuidelineSet to alleviate this.
akonsu
Ok, good you worked it out :)
Meleak
+1  A: 

need to use GuidelineSet:


        protected override void OnRender(DrawingContext c)
        {
            base.OnRender(c);

            Pen pen = new Pen(Brushes.Black, 1);
            double h = this.ActualHeight;
            double d = pen.Thickness / 2;

            foreach (double x in new double[] { 7, 14 })
            {
                GuidelineSet g = new GuidelineSet(new double[] { x + d },
                                                  new double[] { 0 + d, h + d });

                c.PushGuidelineSet(g);
                c.DrawLine(pen, new Point(x, 0), new Point(x, h));
                c.Pop();
            }
        }
akonsu