Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 提高绘制热图时的渲染性能_C#_Wpf - Fatal编程技术网

C# 提高绘制热图时的渲染性能

C# 提高绘制热图时的渲染性能,c#,wpf,C#,Wpf,我试图用给定的输入点和每个点的振幅绘制一张热图。正常输入大小约为400000点,但代码每15点绘制一次。地图绘制在画布上 在XAML中: 渲染代码: public static void DrawPoints(Parser parser, Canvas canvas, double radiusX, double radiusY, double thickness, double minAmplitude, double maxAmplitude) { double cellWidt

我试图用给定的输入点和每个点的振幅绘制一张热图。正常输入大小约为400000点,但代码每15点绘制一次。地图绘制在
画布上

在XAML中:


渲染代码:

public static void DrawPoints(Parser parser, Canvas canvas, double radiusX, double radiusY, double thickness, double minAmplitude, double maxAmplitude)
{
    double cellWidth = canvas.ActualWidth;
    double cellHeight = canvas.ActualHeight;

    var list = parser.Data;

    // Draws every 15th point
    int res = 15;

    for (int i = 0; i < list.Count; i += res)
    {
        var location = list[i].Point;
        var amplitude = list[i].Amplitude;

        // Converts rgb to hsv values for representation
        var color= ColorConverter.hsv2rgb(
            COLOR_START_H * (1.0 - ((amplitude - minAmplitude) / (maxAmplitude - minAmplitude))),
            COLOR_START_S, COLOR_START_V);

        Point center = new Point(location.X, location.Y);
        DrawEllipse(canvas, center, radiusX, radiusY,
            new SolidColorBrush(color), new SolidColorBrush(color), thickness);
    }
    return;
}
在主代码中:

private void btnDraw_Click(object sender, RoutedEventArgs e)
{
    Painter.DrawPoints(parser, canvas, 3, 3, 1, 0, 100);
}

问题是,在将所有点渲染到
画布
上后,当我尝试在同一网格内的
文本框
中输入一些文本时,存在明显的延迟。我能做些什么来减少滞后

您可以做的是,将所有数据绘制到一个
可视化
中,并使用
渲染目标位图
进行渲染。这需要一段时间,但会解决您的性能问题

private List<Point> _points;
private Size _targetarea;

private void btnGenerate_Click(object sender, RoutedEventArgs e)
{
    _targetarea = new Size(500, 500);
    _points = GeneratePoints(10000, _targetarea);
    TheImage.Source = DrawPoints(_points, _targetarea, 5, 5, 1);
}

private List<Point> GeneratePoints(int count, Size size)
{
    Random r = new Random();

    return Enumerable.Range(0, count)
        .Select(j => new Point(r.NextDouble() * size.Width, r.NextDouble() * size.Height))
        .ToList();
}

private static ImageSource DrawPoints(IEnumerable<Point> points, Size size, double radiusX, double radiusY, double thickness)
{
    DrawingVisual visual = new DrawingVisual();

    using (DrawingContext context = visual.RenderOpen())
    {
        var fill = new SolidColorBrush(Colors.Yellow);
        var stroke = new SolidColorBrush(Colors.Red);

        foreach(var center in points)
        {
            context.DrawEllipse(fill, new Pen(stroke, thickness), center, radiusX, radiusY);
        }
    }

    RenderTargetBitmap bitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
    bitmap.Render(visual);
    bitmap.Freeze();
    return bitmap;
}


我无法访问你剩下的代码,因此,下面的代码使用了大量简化和随机数据,例如,我使用的是
图像
而不是
画布
和简单的
s,而不是解析器返回的任何内容。

您可能需要查看WriteableBitmapEx库。数据是否会更改,或者只需要生成一次?你需要互动(上下文菜单、工具提示、缩放)还是快照/图像(如克莱门斯建议的)就足够了?@ManfredRadlwimmer它只需要生成一次。唯一的交互性是
onMouseClick
,它将返回单击点的振幅值。这解决了GUI滞后的问题,但我意识到,使用这种渲染方法,它实际上比直接在画布上绘制要慢得多。有什么技巧可以帮助提高性能吗?@JohnTan您可以在多个线程中预渲染热图的部分(按z顺序排序),然后使用相同的方法将它们合并在一起。因为
bitmap.Freeze()
确保生成的图像是线程安全的(并且是锁定的),所以它不应该是一个问题。我该怎么做?这个想法是否类似于将
context
传递到不同的线程中,每个线程都运行
context.drawerlipse()
?如果是这样的话,我该怎么把它们重新合并在一起呢?哦,不,我不是这个意思。我的意思是将部分数据传递给几个线程,它们都创建一个单独的图像,然后将图像与
context.DrawImage
合并(覆盖)到一个新的DrawingVisual上。另一种选择是使用第三方库,它们在绘制图像时速度更快(我不知道任何库,但我确信它们确实存在)。@JohnTan
WriteableBitmapEx
(Clemes在评论中提到了这一点)工作非常出色-我已经更新了答案(在底部)。
private List<Point> _points;
private Size _targetarea;

private void btnGenerate_Click(object sender, RoutedEventArgs e)
{
    _targetarea = new Size(500, 500);
    _points = GeneratePoints(10000, _targetarea);
    TheImage.Source = DrawPoints(_points, _targetarea, 5, 5, 1);
}

private List<Point> GeneratePoints(int count, Size size)
{
    Random r = new Random();

    return Enumerable.Range(0, count)
        .Select(j => new Point(r.NextDouble() * size.Width, r.NextDouble() * size.Height))
        .ToList();
}

private static ImageSource DrawPoints(IEnumerable<Point> points, Size size, double radiusX, double radiusY, double thickness)
{
    DrawingVisual visual = new DrawingVisual();

    using (DrawingContext context = visual.RenderOpen())
    {
        var fill = new SolidColorBrush(Colors.Yellow);
        var stroke = new SolidColorBrush(Colors.Red);

        foreach(var center in points)
        {
            context.DrawEllipse(fill, new Pen(stroke, thickness), center, radiusX, radiusY);
        }
    }

    RenderTargetBitmap bitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
    bitmap.Render(visual);
    bitmap.Freeze();
    return bitmap;
}
private void TheImage_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Point clickPoint = GetCoordinates(e.GetPosition((IInputElement) sender));

    Point closestPoint = new Point();
    double minSquareDistance = double.MaxValue;

    foreach (Point point in _points)
    {
        double dX = point.X - clickPoint.X;
        double dY = point.Y - clickPoint.Y;
        double squareDistance = dX * dX * dY * dY;
        if (squareDistance < minSquareDistance)
        {
            minSquareDistance = squareDistance;
            closestPoint = point;
        }
    }

    MessageBox.Show($"Clicked near {closestPoint.X:f0}/{closestPoint.Y:f0}");
}

private Point GetCoordinates(Point position)
{
    // Here you need to translate Screen-Coordinates to your internal coordinate system
    return position;
}
private static ImageSource DrawPoints(IEnumerable<Point> points, Size size, double radiusX, double radiusY, double thickness)
{
    WriteableBitmap bitmap = new WriteableBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32, null);

    foreach(var center in points)
    {
        bitmap.FillEllipse((int)(center.X - radiusX), (int)(center.Y - radiusY), (int)(center.X + radiusX), (int)(center.Y + radiusY), Colors.Yellow);
        bitmap.DrawEllipse((int) (center.X - radiusX), (int) (center.Y - radiusY), (int) (center.X + radiusX), (int) (center.Y + radiusY), Colors.Red);
    }

    bitmap.Freeze();
    return bitmap;
}