Processing, ellipse not following alpha values? - processing

class Particle{
PVector velocity, location; //PVector variables for each particle.
Particle(){ //Constructor - random location and speed for each particle.
velocity = new PVector(random(-0.5,0.5), random(-0.5,0.5));
location = new PVector(random(0,width),random(0,width));
}
void update() { location.add(velocity); } //Motion method.
void edge() { //Wraparound case for particles.
if (location.x > width) {location.x = 0;}
else if (location.x < 0) {location.x = width;}
if (location.y > height) {location.y = 0;}
else if (location.y < 0) {location.y = height;}
}
void display(ArrayList<Particle> p){ //Display method to show lines and ellipses between particles.
for(Particle other: p){ //For every particle in the ArrayList.
float d = PVector.dist(location,other.location); //Get distance between any two particle.
float a = 255 - d*2.5; //Map variable 'a' as alpha based on distance. E.g. if distance is high, d = 100, alpha is low, a = 255 - 225 = 30.
println("Lowest distance of any two particle =" + d); //Debug output.
if(d<112){ //If the distance of any two particle falls bellow 112.
noStroke(); //No outline.
fill(0,a); //Particle are coloured black, 'a' to vary alpha.
ellipse(location.x, location.y, 8, 8); //Draw ellipse based on location of particle.
stroke(0,a); //Lines are coloured black, 'a' to vary alpha.
strokeWeight(0.7);
line(location.x,location.y,other.location.x,other.location.y); //Draw line between four coordinates, between two particle.
}
}
}
}
ArrayList<Particle> particles = new ArrayList<Particle>(); //Create a new arraylist of type Particle.
void setup(){
size(640,640,P2D); //Setup frame of sketch.
particles.add(new Particle()); //Add five Particle elements into arraylist.
particles.add(new Particle());
particles.add(new Particle());
particles.add(new Particle());
particles.add(new Particle());
}
void draw(){
background(255); //Set white background.
for(Particle p: particles){ //For every 'p' of type Particle in arraylist particles.
p.update(); //Update location based on velocity.
p.display(particles); //Display each particle in relation to other particles.
p.edge(); //Wraparound if particle reaches edge of screen.
}
}
In the above code, there are to shape objects, lines and ellipses. The transparency of which are affected by variable a.
Variable 'a', or alpha, is extrapolated from 'd' which is distance. Hence, when the objects are further, the alpha value of the objects falls.
In this scenario, the alpha values of the line do not change over time e.g. fade with distance. However the ellipses seem to be stuck on alpha '255' despite having very similar code.
If the value of 'a' is hardcoded, e.g.
if(d<112){ //If the distance of any two particle falls bellow 112.
noStroke(); //No outline.
fill(0,100); //Particle are coloured black, set alpha 'a' to be 100, grey tint.
ellipse(location.x, location.y, 8, 8); //Draw ellipse based on location of particle.
the ellipses changes colour as expected to a grey tint.
Edit: I believe I have found the root of the issue. The variable 'a' does not discriminate between the particles that are being iterated. As such, the alpha might be stuck/adding up to 255.

You're going to have to post an MCVE. Note that this should not be your entire sketch, just a few hard-coded lines so we're all working from the same code. We should be able to copy and paste your code into our own machines to see the problem. Also, please try to properly format your code. Your lack of indentation makes your code hard to read.
That being said, I can try to help in a general sense. First of all, you're printing out the value of a, but you haven't told us what its value is. Is its value what you expect? If so, are you clearing out previous frames before drawing the ellipses, or are you drawing them on top of previously drawn ellipses? Are you drawing ellipses elsewhere in your code?
Start over with a blank sketch, and add just enough lines to show the problem. Here's an example MCVE that you can work from:
stroke(0);
fill(0);
ellipse(25, 25, 25, 25);
line(0, 25, width, 25);
stroke(0, 128);
fill(0, 128);
ellipse(75, 75, 25, 25);
line(0, 75, width, 75);
This code draws a black line and ellipse, then draws a transparent line and ellipse. Please hardcode the a value from your code, or add just enough code so we can see exactly what's going on.
Edit: Thanks for the MCVE. Your updated code still has problems. I don't understand this loop:
for(Particle other: p){ //For every particle in the ArrayList.
float d = PVector.dist(location,other.location); //Get distance between any two particle.
float a = 255 - d*2.5; //Map variable 'a' as alpha based on distance. E.g. if distance is high, d = 100, alpha is low, a = 255 - 225 = 30.
println("Lowest distance of any two particle =" + d); //Debug output.
if(d<112){ //If the distance of any two particle falls bellow 112.
noStroke(); //No outline.
fill(0,a); //Particle are coloured black, 'a' to vary alpha.
ellipse(location.x, location.y, 8, 8); //Draw ellipse based on location of particle.
stroke(0,a); //Lines are coloured black, 'a' to vary alpha.
strokeWeight(0.7);
line(location.x,location.y,other.location.x,other.location.y); //Draw line between four coordinates, between two particle.
}
}
}
You're saying for each Particle, you loop through every Particle and then draw an ellipse at the current Particle's location? That doesn't make any sense. If you have 100 Particles, that means each Particle will be drawn 100 times!
If you want each Particle's color to be based off its distance to the closest other Particle, then you need to modify this loop to simply find the closest Particle, and then base your calculations off of that. It might look something like this:
Particle closestNeighbor = null;
float closestDistance = 100000;
for (Particle other : p) { //For every particle in the ArrayList.
if (other == this) {
continue;
}
float d = PVector.dist(location, other.location);
if (d < closestDistance) {
closestDistance = d;
closestNeighbor = other;
}
}
Notice the if (other == this) { section. This is important, because otherwise you'll be comparing each Particle to itself, and the distance will be zero!
Once you have the closestNeighbor and the closestDistance, you can do your calculations.
Note that you're only drawing particles when they have a neighbor that's closer than 112 pixels away. Is that what you want to be doing?
If you have a follow-up question, please post an updated MCVE in a new question. Constantly editing the question and answer gets confusing, so just ask a new question if you get stuck again.

Related

Jumping realistic in Processing with PVectors

I tried to make a jump look realistic, while I watched through the Videos:
The Natur of Code - The Coding Train
I got into PVectors. I strongly recomend watching him. But to get to my question, everything seems to work, exept that it draws the rectangle (my PVector) the way I want.
void keyPressed() {
if (keyCode == UP) {
for (int i = 0; i < 16; i++) {
location.sub(velocity);
velocity.sub(acceleration);
h.display();
background(0);
}
velocity.set(0, 15);
}
}
That's the Code, I expect it to "jump", but nothing realy happens. You can see that the rectangle get's drawn again (on the same spot), but there's no movement. It's definitly an issue with the drawing of the background or something, I don't know what exaclty though.
The nature of your question is unclear. You mentioned issues regarding the background interfering with your rectangle after the UP arrow key is pressed. This is likely because background(0) is called immediately after h.display(). I would remove background(0) from your loop if it's a display issue.
Other than that, there seem to be other issues with the loop itself. When the UP key is pressed, h is affected by acceleration only for 16 frames. To make your object more realistic, gravity (or whatever acceleration you choose) should constantly be acting upon the object.
With that in mind, here's a solution for you.
void keyPressed() {
if (keyCode == UP) {
// Make the character 'jump' upwards when the UP arrow is pressed.
// Setting the velocity should be the only thing happening when the key is pressed.
velocity.set(0, -2);
}
}
void draw() {
// Reset the background each frame so rectangles don't overlap.
background(255);
// Always draw the rectangle AFTER resetting the canvas.
h.display();
// Change the object's location by it's velocity.
location.add(velocity);
// And chance the object's velocity by it's acceleration.
// Since acceleration is the acting force of gravity in this situation, acceleration need not be changed.
velocity.add(acceleration);
// Prevent the rectangle from falling through the bottom of the canvas.
if(location.y > height - 5) location.y = height - 5;
}
// You negleteced to define your variables in your code snippet. Here they are.
PVector location = new PVector(0, 0);
PVector velocity = new PVector(0, 0);
PVector acceleration = new PVector(0, 0.1); // Notice that acceleration's y-value is 0.01. This is so you can see the effect of gravity.
// Define your rectangle object.
Object h = new Object();
class Object {
Object() {} // Constructor.
void display() {
// Draw the rectangle at the x- and y-positions of the location vector.
// The '+ width/2' places it at the center of the screen.
rectMode(CENTER);
rect(location.x + width/2, location.y, 10, 10);
}
}

How can I optimize an animation in Processing, and keep it from leaving a trail of images?

I am creating a model of a solar system in processing, and after removing the background I noticed the planets were leaving a trail of their image behind them. The program runs fine when the background is back in, but I want to add a lot more and I am sure this is inefficient and will bog things down.
I am very new to processing, and I am really not sure how to solve this. Maybe delete previous images after a delay to create a shortened trail?
These are just the parts I think are important cherry picked from the code, this is just the example of one planet. Sorry if the code is clunky, any suggestions are happily accepted.
Planet p1;
void setup() {
mercury = loadImage("mercury.png")
p1 = new Planet(40, random(TWO_PI), 0.05);
}
void draw() {
//background(0)
translate(width / 2, height / 2);
p1.display1();
p1.orbit();
}
class Planet {
float radius;
float angle;
float distance;
float orbitSpeed;
Planet(float r, float d, float o) {
radius = r;
distance = d;
orbitSpeed = o;
angle = random(TWO_PI);
}
void orbit() {
angle = angle + orbitSpeed;
}
void display1() {
pushMatrix();
rotate(angle);
translate(distance, 0);
imageMode(CENTER);
image(mercury, radius, radius, 10, 10);
popMatrix();
}
}
I realized that this would probably happen, and I am not sure how to stop it.
The behavior you describe is simply the nature of computer graphics; it's how games, operating systems, and hardware displays all work – they clear and redraw everything every frame.
In Processing, graphic objects that are pushed to a buffer remain there indefinitely until the buffer is cleared or something is pushed on top of them (this is why the planets are leaving a trail without calling background() – previous frames remain in the buffer).
You are worried about the background() being inefficient. Don't be, as it's one of the fastest operations (simply sets the value of each pixel, as given by the user).
Processing does provide a clear() function, but this is equivalent to background(0).
If you're are still concerned about efficiency and speed, one way to speed up Processing is to use the FX2D renderer rather than default AWT renderer. Another way is cache drawn objects into PGraphics objects to prevent successive rasterization (since your planets are image files and not drawn with processing, you needn't worry about this).
Your code is simple enough that it doesn't need optimisations at this stage.
As micycle mentions, you are are drawing an image at a translated position, pretty similar to blitting.
In terms of the trails, one common trick you could use is not clear the screen completely, but draw a transparent rectangle as the background. The more transparency, the longer the trails.
Here's a tweaked version of your code:
// planet object
Planet p1;
// planet texture
PImage mercury;
void setup() {
size(300, 300);
// draw image from center
imageMode(CENTER);
// clear to black one
background(0);
// remove strokes (we'll use rect() later)
noStroke();
// set the fill to black but with 9/255 transparency (~3.5% transparent)
fill(0,9);
// init texture
mercury = loadImage("mercury.png");
// init planet
p1 = new Planet(40, random(TWO_PI), 0.05);
}
void draw() {
// draw a transparent rectangle instead of completely clearing the screen
rect(0,0,width,height);
// render planet
translate(width / 2, height / 2);
p1.display1();
p1.orbit();
}
class Planet {
float radius;
float angle;
float distance;
float orbitSpeed;
Planet(float r, float d, float o) {
radius = r;
distance = d;
orbitSpeed = o;
angle = random(TWO_PI);
}
void orbit() {
angle = angle + orbitSpeed;
}
void display1() {
pushMatrix();
rotate(angle);
translate(distance, 0);
image(mercury, radius, radius, 10, 10);
popMatrix();
}
}
It's an efficient quick'n'dirty hack as you won't need to store previous position and redraw multiple times, however it has it limitations in terms of the flexibility of the trails. Hopefully tweaking the fill() alpha parameter will get you the desired effect.
Later on if you're drawing many many many planets it things start running slow have a peak at VisualVM. Profile the CPU and see the methods that take the longest to complete and focus on those. Don't need to optimise everything, just the slowest calls. Remember that Processing have multiple renderers: JAVA2D is the default one, but there's also FX2D and P2D/P3D and they will behave differently. I strongly recommend optimising at the last moment (otherwise code might be less flexible and readable and will slow down development/iteration).

Different Processing rendering between native and online sketch

I get different results when running this sample with Processing directly, and with Processing.js in a browser. Why?
I was happy about my result and wanted to share it on open Processing, but the rendering was totally different and I don't see why. Below is a minimal working example.
/* Program that rotates a triange and draws an ellipse when the third vertex is on top of the screen*/
float y = 3*height/2;
float x = 3*width/2;
float previous_1 = 0.0;
float previous_2 = 0.0;
float current;
float angle = 0.0;
void setup() {
size(1100, 500);
}
void draw() {
fill(0, 30);
// rotate triangle
angle = angle - 0.02;
translate(x, y);
rotate(angle);
// display triangle
triangle(-50, -50, -30, 30, -90, -60);
// detect whether third vertex is on top by comparing its 3 successive positions
current = screenY(-90, -60); // current position of the third vertex
if (previous_1 < previous_2 && previous_1 < current) {
// draw ellipse at the extrema position
fill(128, 9, 9);
ellipse(-90, -60, 7, 10);
}
// update the 2 previous positions of the third vertex
previous_2 = previous_1;
previous_1 = current;
}
In processing, the ellipse is drawn when a triangle vertex is on top, which is my goal.
In online sketching, the ellipse is drawn during the whole time :/
In order to get the same results online as you get by running Processing locally you will need to specify the rendering mode as 3d when calling size
For example:
void setup() {
size(1100, 500, P3D);
}
You will also need to specify the z coordinate in the call to screenY()
current = screenY(-90, -60, 0);
With these two changes you should get the same results online as you get running locally.
Online:
Triangle Ellipse Example
Local:
The problem lies in the screenY function. Print out the current variable in your processing sketch locally and online. In OpenProcessing, the variable current grows quickly above multiple thousands, while it stays between 0 and ~260 locally.
It seems like OpenProcessing has a bug inside this function.
To fix this however, I would recommend you to register differently when you drew a triangle at the top of the circle, for example by using your angle variable:
// Calculate angle and modulo it by 2 * PI
angle = (angle - 0.02) % (2 * PI);
// If the sketch has made a full revolution
if (previous_1 < previous_2 && previous_1 < angle) {
// draw ellipse at the extrema position
fill(128, 9, 9);
ellipse(-90, -60, 7, 10);
}
// update the 2 previous angles of the third vertex
previous_2 = previous_1;
previous_1 = angle;
However, because of how you draw the triangles, the ellipse is at an angle of about PI / 3. To fix this, one option would be to rotate the screen by angle + PI / 3 like so:
rotate(angle + PI / 3);
You might have to experiment with the angle offset a bit more to draw the ellipse perfectly at the top of the circle.

How to rotate the ball in the direction its moving?I try to use the rotate function but that throws everything off?

//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//setup
void setup() {
size(810, 810);
} //draw
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//a nose
triangle(x, y, x+10, y+10, x-10, y+10);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
}
// it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
}
if (keyCode=='S') {
speedX=0;
speedY=4;
}
if (keyCode=='A') {
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
speedX=4;
speedY=0;
}
}
I made this ball with a nose, which moves around the screen with the keys W S D A. If it hits the edges it will bounce back.
I'm trying to change the direction the ball is facing to make it face the same way as it's moving. I wanted to use rotate for this, but once I use rotate it throws all the coordinates off. Rotating it back doesn't help either.
I have commented out the stuff I have tried to do. For example, I tried to translate it to 250,250 and then rotate it afterwards, but then the X and Y coordinates are switched. Also, the ball won't go all the way to the corners and it moves out (since it's translated down).
What kind of rotation/translation logic do I need to change?
It is likely that using the rotate function on your triangle is wreaking havoc as you are performing the rotate on several variables in your draw loop because you're not telling processing exactly which object you want to transform. One way to do this is to look up the pushMatrix and popMatrix functions (google "processing pushMatrix" to see helpful info for how to use the type and associated functions). It would be cumbersome to implement this into your code as the triangle is created in your draw loop every frame. An easy way to make transformations to a specific shape you have (in your instance, a triangle) is to store it as a PShape and then make transformations as you need to. Since PShape's can easily be transformed using PShape functions you don't need to worry about your transformations effecting other variables (so no need to use push/popmatrix. Here is a commented version of your code that implements your Triangle as a PShape.
//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//Initialize PShape which we can later store a triangle in
PShape tri;
void setup() {
size(810, 810);
//Initialize triangle - this triangle faces right
tri = createShape(TRIANGLE, 0, 10, 0, -10, 10, 0);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//Draw the stored PShape at x and y coordinate
shape(tri,x,y);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
//Flip PShape rotation
tri.rotate(PI);
} // it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
//Flip PShape rotation
tri.rotate(PI);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
//reset triangle orientation (transformation matrix) to original then rotate to face UP
tri.resetMatrix();
tri.rotate(-PI/2);
}
if (keyCode=='S') {
//reset triangle orientation (transformation matrix) to original then rotate to face DOWN
speedX=0;
speedY=4;
tri.resetMatrix();
tri.rotate(PI/2);
}
if (keyCode=='A') {
//reset triangle orientation (transformation matrix) to original then rotate to face LEFT
tri.resetMatrix();
tri.rotate(PI);
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
//reset triangle orientation (transformation matrix) to original - it is already pointing right
tri.resetMatrix();
speedX=4;
speedY=0;
}
}
I suspect your next step, or a more efficient way to write this piece of code might be to begin to implement PVectors (google processing PVectors to see helpful info for how to use the type and associated functions) for position and direction of your 'ball'. Here is some commented code that begins to show you how you might implement this in your current code. Although there are many improvements that can be made on this. For more information on how vectors work in processing follow this tutorial - http://natureofcode.com/book/chapter-1-vectors/
//declaringglobalvaribales
//diameteroftheface
float dia1=50;
//initialize position PVector and tell it where you want it to be - in this case 400,400
PVector position = new PVector(400, 400);
//how many steps you want your position to move per frame
float speed=4;
//initialize direction vector as 0,0 - the ellipse will not move until you give it a
//direction as it is initialized with no direction
PVector direction = new PVector(0, 0);
void setup() {
size(810, 810);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
//draw ellipse at your position PVector using the PVectors x and y values
ellipse(position.x, position.y, dia1, dia1);
fill(0, 225, 0);
//drawing a line to indicate what direction the ellipse is heading in using the position coordinates and the position plus direction
line(position.x, position.y, position.x+direction.x*4, position.y+direction.y*4);
// add the direction to the position to make it move
position =position.add(direction);
//if the position PVector is close to sketch edges invert its direction by multiplying direction PVector by -1
if (position.x>width-dia1/2 || position.x<2+dia1/2) {
direction.mult(-1);
}
if (position.y>height-dia1/2 || position.y<2+dia1/2) {
direction.mult(-1);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
//set the direction coordinates based on keypresses
//also multiply the direction by speed variable so it moves at a speed set at top of script
if (keyCode=='W') {
direction.y = -1*speed;
direction.x = 0;
}
if (keyCode=='S') {
direction.y = 1*speed;
direction.x = 0;
}
if (keyCode=='A') {
direction.x = -1*speed;
direction.y = 0;
}
if (keyCode=='D') {
direction.x = 1*speed;
direction.y = 0;
}
}
If you have a center point, an angle you want to face, and a distance from that center, you can use cos() and sin() to calculate the end point. Here's a simple example:
float angle = 0;
float distance = 25;
void draw(){
angle += .01;
float startX = width/2;
float startY = height/2;
float endX = startX + cos(angle)*distance;
float endY = startY + sin(angle)*distance;
background(255);
line(startX, startY, endX, endY);
}
In the future, please try to narrow your question down to an MCVE like this before posting.

Algorithm for shape calculation (Ellipse)

I have n circles that must be perfectly surrounding an ellipse as shown in the picture here :
In this picture I need to find out the position of each circle around the ellipse, and also be able to calculate the ellipse that will fit perfectly inside those surrounding circles.
The information i know is the radius of each circles (all same), and the number of circles.
Hopefully this time the post is clear.
Thanks for your help.
Please let me know if you need more explanation.
OK as i understand you know common radius of circles R0 and their number N and want to know inside ellipse parameters and positions of everything.
If we convert ellipse to circle then we get this:
const int N=12; // number of satelite circles
const double R=10.0; // radius of satelite circles
struct _circle { double x,y,r; } circle[N]; // satelite circles
int i;
double x,y,r,l,a,da;
x=0.0; // start pos of first satelite circle
y=0.0;
r=R;
l=r+r; // distance ang angle between satelite circle centers
a=0.0*deg;
da=divide(360.0*deg,N);
for (i=0;i<N;i++)
{
circle[i].x=x; x+=l*cos(a);
circle[i].y=y; y+=l*sin(a);
circle[i].r=r; a+=da;
}
// inside circle params
_circle c;
r=divide(0.5*l,sin(0.5*da))-R;
c.x=circle[i].x;
c.y=circle[i].y+R+r;
c.r=r;
[Edit 1]
For ellipse its a whole new challenge (took me two hours to find all quirks out)
const int N=20; // number of satelite circles
const double R=10.0; // satelite circles radius
const double E= 0.7; // ellipse distortion ry=rx*E
struct _circle { double x,y,r; _circle() { x=0; y=0; r=0.0; } } circle[N];
struct _ellipse { double x,y,rx,ry; _ellipse() { x=0; y=0; rx=0.0; ry=0.0; } } ellipse;
int i,j,k;
double l,a,da,m,dm,x,y,q,r0;
l=double(N)*R; // circle cener lines polygon length
ellipse.x =0.0; // set ellipse parameters
ellipse.y =0.0;
r0=divide(l,M_PI*sqrt(0.5*(1.0+(E*E))))-R;// aprox radius to match ellipse length for start
l=R+R; l*=l;
m=1.0; dm=1.0; x=0.0;
for (k=0;k<5;k++) // aproximate ellipse size to the right size
{
dm=fabs(0.1*dm); // each k-iteration layer is 10x times more accurate
if (x>l) dm=-dm;
for (;;)
{
ellipse.rx=r0 *m;
ellipse.ry=r0*E*m;
for (a=0.0,i=0;i<N;i++) // set circle parameters
{
q=(2.0*a)-atanxy(cos(a),sin(a)*E);
circle[i].x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q));
circle[i].y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q));
circle[i].r=R;
da=divide(360*deg,N); a+=da;
for (j=0;j<5;j++) // aproximate next position to match 2R distance from current position
{
da=fabs(0.1*da); // each j-iteration layer is 10x times more accurate
q=(2.0*a)-atanxy(cos(a),sin(a)*E);
x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
if (x>l) for (;;) // if too far dec angle
{
a-=da;
q=(2.0*a)-atanxy(cos(a),sin(a)*E);
x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
if (x<=l) break;
}
else if (x<l) for (;;) // if too short inc angle
{
a+=da;
q=(2.0*a)-atanxy(cos(a),sin(a)*E);
x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
if (x>=l) break;
}
else break;
}
}
// check if last circle is joined as it should be
x=circle[N-1].x-circle[0].x; x*=x;
y=circle[N-1].y-circle[0].y; y*=y; x+=y;
if (dm>0.0) { if (x>=l) break; }
else { if (x<=l) break; }
m+=dm;
}
}
Well I know its a little messy code so here is some info:
first it try to set as close ellipse rx,ry axises as possible
ellipse length should be about N*R*2 which is polygon length of lines between circle centers
try to compose circles so they are touching each other and the ellipse
I use iteration of ellipse angle for that. Problem is that circles do not touch the ellipse in their position angle thats why there is q variable ... to compensate around ellipse normal. Look for yellowish-golden lines in image
after placing circles check if the last one is touching the first
if not interpolate the size of ellipse actually it scales the rx,ry by m variable up or down
you can adjust accuracy
by change of the j,k fors and/or change of dm,da scaling factors
input parameter E should be at least 0.5 and max 1.0
if not then there is high probability of misplacing circles because on very eccentric ellipses is not possible to fit circles (if N is too low). Ideal setting is 0.7<=E<=1.0 closser to 1 the safer the algorithm is
atanxy(dx,dy) is the same as `atan(dy/dx)
but it handles all 4 quadrants like atan2(dy,dx) by sign analysis of dx,dy
Hope it helps

Resources