1

I am trying to draw a lot of points to the screen quickly. I have created the following method.

void _paintPoints(Canvas canvas, List matrix, Size size) {
  final width = size.width / matrix.length;
  final height = size.height / matrix.first.length;
  Float32List points = Float32List(matrix.length * matrix.length * 2);
  final pointColors = <Color>[];

  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < matrix[i].length; j++) {
      final x = i * width;
      final y = j * height;
      final index = (i * matrix.length + j) * 2;

      points[index] = x;
      points[index + 1] = y;

      Color color = Color.fromARGB(
          matrix[i][j][3], matrix[i][j][0], matrix[i][j][1], matrix[i][j][2]);
      pointColors.add(color);
    }
  }

  canvas.drawRawPoints(
    PointMode.points,
    points,
    paint
      ..blendMode = BlendMode.srcOver
      ..strokeWidth = 2.0,
  );
}

This method is able to draw the points quickly but all of the points are the same color (The pointColors are not used). Is there away to use drawRawPoints() or some other Canvas method to draw a lot of points (tens of thousands) quickly with specific colors?

I have tried drawing each point separately, but it was too slow.

MaLa
  • 582
  • 2
  • 16
  • 1
    Have you tried grouping the points by same color and then running DrawRawPoints? Also, if there is gradient based color, you could use shader in paint. – Rahul Mar 25 '23 at 04:35
  • @Rahul This was an improvement (about 5x faster). The issue with this solution is that I do not know how many times each colour appears before I check them. Because of this I cannot create Float32List. I am currently creating Map> and converting the list to Float32List before drawing. According to the performance tools the hashmap checking and adding items to the List take more time than the painting. – MaLa Mar 25 '23 at 08:44

1 Answers1

1

Can you try this?

void _paintPoints(Canvas canvas, List matrix, Size size) {
  final width = size.width / matrix.length;
  final height = size.height / matrix.first.length;

  final Map<Color, Set<Offset>> map = HashMap();

  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < matrix[i].length; j++) {
      final offset = Offset(i * width, j * height);
      final color = Color.fromARGB(
          matrix[i][j][3], matrix[i][j][0], matrix[i][j][1], matrix[i][j][2]);
      map.putIfAbsent(color, () => HashSet()).add(offset);
    }
  }

  for (var e in map.entries) {
    canvas.drawRawPoints(
      PointMode.points,
      Float32List.fromList(e.value.expand((e) => [e.dx, e.dy]).toList()),
      paint
        ..color = e.key
        ..blendMode = BlendMode.srcOver
        ..strokeWidth = 2.0,
    );
  }
}

I am sorry I had to post it as answer. It is a try out code. I would suggest to cache the map result and use diff of upcoming matrix and size to calculate new map values.

Edit: I did some editing and it should run fast. The idea here is to minimize memaddr calculation.

Updated code

void _paintPoints(Canvas canvas, List matrix, Size size) {
  final r = matrix.length;
  final c = matrix.first.length;
  final width = size.width / r;
  final height = size.height / c;

  final Map<Color, Set<Offset>> map = HashMap();

  for (var i = 0; i < r; i++) {
    final row = matrix[i];
    for (var j = 0; j < c; j++) {
      final cell = row[j];
      final offset = Offset(i * width, j * height);
      final color = Color.fromARGB(cell[3], cell[0], cell[1], cell[2]);
      map.putIfAbsent(color, () => HashSet()).add(offset);
    }
  }

  for (var e in map.entries) {
    canvas.drawPoints(
      PointMode.points,
      e.value.toList(),
      paint
        ..color = e.key
        ..blendMode = BlendMode.srcOver
        ..strokeWidth = 2.0,
    );
  }
}

Now the creation of map should be much faster. I did some benchmarking on my own and found out accessing 3d list with i and j takes more time than having a reference to it. Also, changed rowpoints to points. You could change it back.

Rahul
  • 3,529
  • 1
  • 5
  • 19
  • This is a good improvement. With 40000 points the painting part takes 1-2 ms but the creation of the points takes 10-20 ms. Yeah I have to structure the code in away that I can save the map values so that I do not have to recreate them always – MaLa Mar 25 '23 at 13:37
  • @MaLa please try updated answer. Alternatively, you can use iterator. – Rahul Mar 26 '23 at 04:04