我們正在建設一個圖形應用程序,我們要畫在畫布上的背景點,因爲我們有像捕捉到的特徵電網當然繪製大量點的最佳方式是什麼?
中,用戶可以設置捕捉點之間的距離,所以,如果我們有一個大小爲1024 x 1024的畫布,每個點之間有5個像素,我們將有大約41775個點!
在畫布上渲染大量點的建議方法是什麼?我們需要它儘可能快。
我們正在建設一個圖形應用程序,我們要畫在畫布上的背景點,因爲我們有像捕捉到的特徵電網當然繪製大量點的最佳方式是什麼?
中,用戶可以設置捕捉點之間的距離,所以,如果我們有一個大小爲1024 x 1024的畫布,每個點之間有5個像素,我們將有大約41775個點!
在畫布上渲染大量點的建議方法是什麼?我們需要它儘可能快。
WPF沒有直接的方法在畫布上繪製像素。實現它的最佳方法是使用Image和WriteableBitmap源代碼。看看下面的代碼。它有兩個函數:drawGrid1和drawGrid2。在我的機器上,第一個函數(繪製橢圓元素)需要6秒。後者的功能需要50毫秒。
下面的代碼僅用於說明。您可以緩存WritebaleBitmap,並且您應該敏感(如果您的場景需要)更改寬度或高度(或者,只需創建一個非常大的位圖)。如果你需要更多的性能,並且你可以使用不安全的代碼,你可以調用WritebaleBitmap.Lock,然後獲得WriteableBitmap.BackBuffer,並手動修改後臺緩衝區。最後,調用WriteableBitmap.AddDirtyBuffer來使整個矩形失效。如果你的Grid只有兩種顏色,你也可以通過使用調色板來獲得更高的性能。
更多WriteableBitmap的:http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap(VS.85).aspx
XAML:
<Window
x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="1000" Width="1000"
Title="SO Sample"
Loaded="Window_Loaded"
>
<Canvas x:Name="x_canvas">
<Border Canvas.Left="4" Canvas.Right="4" Width="120" Height="32" Background="White" >
<TextBlock x:Name="x_txt" VerticalAlignment="Center" />
</Border>
</Canvas>
</Window>
代碼背後:
private void Window_Loaded(object sender, RoutedEventArgs e) {
DateTime start = DateTime.Now;
//drawGrid1();
drawGrid2();
DateTime end = DateTime.Now;
TimeSpan span = end - start;
x_txt.Text = span.ToString();
}
private void drawGrid2() {
// Create a new image
Image img = new Image();
RenderOptions.SetBitmapScalingMode(img, BitmapScalingMode.NearestNeighbor);
RenderOptions.SetEdgeMode(img, EdgeMode.Aliased);
// Add this image to the canvas
x_canvas.Children.Add(img);
int width = (int)x_canvas.ActualWidth;
int height = (int)x_canvas.ActualHeight;
// Create the bitmap, and set
WriteableBitmap wb = new WriteableBitmap(
width,
height,
96, 96,
PixelFormats.Bgra32,
null
);
img.Source = wb;
img.Stretch = Stretch.None;
img.HorizontalAlignment = HorizontalAlignment.Left;
img.VerticalAlignment = VerticalAlignment.Top;
Canvas.SetZIndex(img, -100);
// Each "dot" is 2x2 rectangle
Int32Rect rect = new Int32Rect(0, 0, 2, 2);
int size = rect.Width * rect.Height * 4;
byte[] pixels = new byte[ size ];
// Setup the pixel array
for(int i=0; i<rect.Height*rect.Width; ++i) {
pixels[ i*4 + 0 ] = 255; // Blue
pixels[ i*4 + 1 ] = 0; // Green
pixels[ i*4 + 2 ] = 0; // Red
pixels[ i*4 + 3 ] = 255; // Alpha
}
wb.WritePixels(rect, pixels, rect.Width*4, 0);
int step = 5;
for(int r = 0; r<height; r+=step) {
for(int c = 0; c<width; c+=step) {
rect.X = c;
rect.Y = r;
wb.WritePixels(rect, pixels, rect.Width*4, 0);
}
}
}
private void drawGrid1() {
int step = 10;
for(int i=0; i<1024; i+=step) {
for(int j=0; j<1024; j+=step) {
Ellipse l = new Ellipse();
if(i%100==0 && j%100==0) {
l.Width = 4;
l.Height = 4;
}
else {
l.Width = 2;
l.Height = 2;
}
l.Fill = new SolidColorBrush(Colors.Black);
Canvas.SetTop(l, i);
Canvas.SetLeft(l, j);
Canvas.SetZIndex(l, -100);
this.x_canvas.Children.Add(l);
}
}
}