Search code examples
dartmathmatrixgeometry

Ellipsis plotting in Dart


I want to create an ellipsis plotter for Minecraft players that I know. I have a Dart class:

class Ellipse with EquatableMixin implements Comparable<Ellipse> {
  const Ellipse(this.width, this.depth) : assert((width > 0) && (depth > 0));

  final int width;
  final int depth;

  @override
  int compareTo(Ellipse other) {
    final widthResult = width.compareTo(other.width);
    if (widthResult != 0) return widthResult;
    return depth.compareTo(other.depth);
  }

  List<List<bool>> get blocks {
    final blocks = List.generate(depth, (_) => List.filled(width, false));

    final a = width / 2.0; // Semi-major axis
    final b = depth / 2.0; // Semi-minor axis
    final centerX = a;
    final centerY = b;

    for (int x = 0; x < width; x++) {
      for (int y = 0; y < depth; y++) {
        final normalizedX = (x - centerX) / a;
        final normalizedY = (y - centerY) / b;
        if ((normalizedX * normalizedX) + (normalizedY * normalizedY) <= 1) {
          blocks[y][x] = true;
          blocks[depth - y - 1][x] = true; // Ensure vertical symmetry
          blocks[y][width - x - 1] = true; // Ensure horizontal symmetry
          blocks[depth - y - 1][width - x - 1] =
              true; // Ensure both horizontal and vertical symmetry
        }
      }
    }

    return blocks;
  }

  @override
  List<Object?> get props => [width, depth];
}

I thought of plotting on the screen in a GridView.

My question is, this code is plotting: (8, 10, 10, 10, 10, 10, 10, 10, 10, 8) columns/rows (symmetric) but I wanted something way more "rounded" like (4, 6, 8, 10, 10, 10, 10, 8, 6, 4).

Can anyone help me with the math for this?


Solution

  • The idea

    What I would probably do, is use the forumula for the points on an ellipse:

    x^2/a^2 + y^2/b^2 = 1
    

    https://en.wikipedia.org/wiki/Ellipse

    Where width = 2a and height = 2b

    Then, for each of the cells in your grid, you can calculate x^2/a^2 + y^2/b^2 see how much it diverts from 1, and use this to determine whether there should be a block in this position.

    For example, say you have a 5x5 grid. The formula becomes

    x^2/6.25 + y^2/6.25 = 1
    

    An example

    For example, I quickly wrote up the following script (as inspiration, to play around with!)

    import 'dart:math';
    
    void main() {
      int width = 6;
      int height = 6;
      double treshold = 0.2;
    
      for (int x = (-width/2).round(); x <= (width/2).round(); x++) {
        String row = '';
        for (int y = (-height/2).round(); y <= (height/2).round(); y++) {
          double value = pow(x, 2)/pow(width/2, 2) + pow(y, 2)/pow(height/2, 2);
          row += '${(value - 1).abs() < treshold ? 'O' : ' '}';
        }
        print(row);
      }
    }
    

    Which, for the given parameters, outputs a pretty nice circle (if the characters where square):

      OOO  
     O   O 
    O     O
    O     O
    O     O
     O   O 
      OOO  
    

    Recommendation

    You can play around with the parameters, the treshold for the values should probably depend on the width and height parameters. The circle is now centered around 0,0 which is why the for loops have become a bit messy, so you can also see if you can move the formula over.