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?
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
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
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.