How to rotate figure from points(Hilbert curve)? - c#

I am working on Hilbert curve, and I cant rotate the whole figure, just lower rectangle(look at the screenshots, on third and next steps I have a problem)
first 3 steps
I have a Figure class. I use it to store every figure and build next firuge from previous one. Here is my code
public class Fragment
{
public static int PADDING = 50;
public static float sideLength;
private readonly Pen crimsonPen = new Pen(Color.Crimson);
public List<PointF> pointsF = new List<PointF>();
public PointF[] points;
public Fragment(int step, Graphics graphics)
{
sideLength = Form1.sideLenght;
points = new PointF[(int)Math.Pow(4, step + 1)];
if (step.Equals(0))
{
points[0] = new PointF(PADDING, PADDING + sideLength);
points[1] = new PointF(PADDING, PADDING);
points[2] = new PointF(PADDING + sideLength, PADDING);
points[3] = new PointF(PADDING + sideLength, PADDING + sideLength);
graphics.DrawLines(crimsonPen, new[] { points[0], points[1], points[2], points[3] });
}
else
{
var frag = Form1.fragments[step - 1];
for (var i = 0; i < step; i++)
{
PointF tmpPoint;
// left lower #1
for (int j = frag.points.Length - 1; j >= 0; j--)
{
points[frag.points.Length - 1 - j] = frag.points[j];
points[frag.points.Length - 1 - j].Y += sideLength * 2 * (i + 1);
}
//rotate left lower #1
for (int b = 0; b < Math.Pow(4, step) - 1; b++)
{
tmpPoint = points[0];
for (int j = 0; j < frag.points.Length; j++)
{
if (j.Equals(frag.points.Length - 1))
{
points[j] = tmpPoint;
}
else
{
points[j] = points[j + 1];
}
}
}
// left upper #2
for (int j = 0; j < frag.points.Length; j++)
{
points[j + frag.points.Length] = frag.points[j];
}
// right upper #3
for (int j = 0; j < frag.points.Length; j++)
{
points[j + 2 * frag.points.Length] = points[j + frag.points.Length];
points[j + 2 * frag.points.Length].X += sideLength * 2 * (i + 1);
}
//right lower #4
for (int j = frag.points.Length - 1; j >= 0; j--)
{
points[3 * frag.points.Length + j] = points[2 * frag.points.Length + frag.points.Length - j - 1];
points[3 * frag.points.Length + j].Y += sideLength * 2 * (i + 1);
}
tmpPoint = points[3 * frag.points.Length];
//rotate right lower #4
for (int j = 0; j < frag.points.Length; j++)
{
if (j.Equals(frag.points.Length - 1))
{
points[4 * (frag.points.Length) - 1] = tmpPoint;
}
else
{
points[3 * frag.points.Length + j] = points[3 * frag.points.Length + j + 1];
}
}
}
graphics.DrawLines(crimsonPen, points);
}
}
}
Here I use my recursive method to draw figures
private void drawButton_Click(object sender, EventArgs e)
{
canvas.Refresh();
count = 0;
if (Int32.TryParse(stepsTextBox.Text, out steps))
{
sideLenght = (float)((canvas.Width - 100) / (Math.Pow(2, steps) - 1));
fragments = new Fragment[steps];
drawCurve();
}
else
{
MessageBox.Show("Wow, incorrect input", "Try again");
}
}
private void drawCurve()
{
if (count < steps)
{
fragments[count] = new Fragment(count, graphics);
++count;
drawCurve();
}
}
I've tried to rotate points around figure center and use next code but the rotation is incorrect
public PointF rotatePoint(PointF pointToRotate)
{
pointToRotate.X = (float)(Math.Cos(180 * Math.PI / 180) * (pointToRotate.X - centerPoint.X) -
Math.Sin(180 * Math.PI / 180) * (pointToRotate.Y - centerPoint.Y) +
centerPoint.X);
pointToRotate.Y = (float)(Math.Sin(0 * Math.PI / 180) * (pointToRotate.X - centerPoint.X) +
Math.Cos(0 * Math.PI / 180) * (pointToRotate.Y - centerPoint.Y) +
centerPoint.Y);
return pointToRotate;
}

The problem is that you are using the X co-ordinate that you have already rotated when you calculate the rotated Y co-ordinate. Use a temp variable to avoid this:
public PointF rotatePoint(PointF pointToRotate)
{
float rotatedX = (float)(Math.Cos(180 * Math.PI / 180) * (pointToRotate.X - centerPoint.X) -
Math.Sin(180 * Math.PI / 180) * (pointToRotate.Y - centerPoint.Y) +
centerPoint.X);
pointToRotate.Y = (float)(Math.Sin(0 * Math.PI / 180) * (pointToRotate.X - centerPoint.X) +
Math.Cos(0 * Math.PI / 180) * (pointToRotate.Y - centerPoint.Y) +
centerPoint.Y);
pointToRotate.X = rotatedX;
return pointToRotate;
}

Related

Why Bresenham Algorithm is not fast than DDA Algorithm in C#

I read in stackoverflow before about Bresenham algorithm use for a particular environment like low-language, but I have to compare it in my report so any ideal for my report. How can I prove Bresenham is faster than DDA. Now I created a simple paint on winform C# and the time when I draw with 2 different method is likely equal, sometime DDA is faster. Here is my code in both method
Bresenham Algorithm
List<Point> vertices = new List<Point>();
int deltaX = xN - x0; int signX = deltaX >= 0 ? 1 : -1;
int deltaY = yN - y0; int signY = deltaY >= 0 ? 1 : -1;
if (deltaX == deltaY && deltaX * deltaY == 0) return vertices;
// |dy|/|dx| < 1 => |dy| < |dx| => m < 1
if (Math.Abs(deltaX) > Math.Abs(deltaY))
{
int _2deltaX = deltaX * 2 * signX;
int _2deltaY = deltaY * 2 * signY;
int p0 = _2deltaY - deltaX * signX;
// create array to contain vertices
vertices.Add(new Point(x0, y0));
int xCurrent = x0;
int yCurrent = y0;
while (true)
{
if (count >= (Math.Abs(deltaX) + 1)) return vertices;
if (p0 < 0)
{
xCurrent += signX;
// pk + 1 = pk + 2.∆y.signX
p0 = p0 + _2deltaY;
}
else
{
xCurrent += signX;
yCurrent += signY;
// pk+1= pk + 2.∆y.signX - 2.∆x.signY
p0 = p0 + _2deltaY - _2deltaX;
}
vertices.Add(new Point(xCurrent, yCurrent));
}
}
// |dy|/|dx| > 1 => |dy| > |dx| => m > 1
else if (Math.Abs(deltaX) <= Math.Abs(deltaY))
{
int _2deltaX = deltaX * 2 * signX;
int _2deltaY = deltaY * 2 * signY;
int p0 = _2deltaX - deltaY * signY;
// create array to contain vertices
vertices.Add(new Point(x0, y0));
int xCurrent = x0;
int yCurrent = y0;
while (true)
{
if (count >= (Math.Abs(deltaY) + 1)) return vertices;
if (p0 < 0)
{
yCurrent += signY;
// pk + 1 = pk + 2.∆x.signY
p0 = p0 + _2deltaX;
}
else
{
xCurrent += signX;
yCurrent += signY;
// pk+1= pk + 2.∆x.signY - 2.∆y.signX
p0 = p0 + _2deltaX - _2deltaY;
}
vertices.Add(new Point(xCurrent, yCurrent));
}
}
return vertices;
DDA Algorithm
List<Point> vertices = new List<Point>();
int deltaX = xN - x0; int signX = deltaX >= 0 ? 1 : -1;
int deltaY = yN - y0; int signY = deltaY >= 0 ? 1 : -1;
if (deltaX == deltaY && deltaX * deltaY == 0) return vertices;
int step = Math.Abs(deltaX) > Math.Abs(deltaY) ? Math.Abs(deltaX) : Math.Abs(deltaY);
// x(k + 1) = xk + x'
double stepX = deltaX * 1.0 / step;
double stepY = deltaY * 1.0 / step;
vertices.Add(new Point(x0, y0));
double xCurrent = x0;
double yCurrent = y0;
for (int i = 0; i < step; i++)
{
xCurrent += stepX;
yCurrent += stepY;
vertices.Add(new Point((int)Math.Round(xCurrent), (int)Math.Round(yCurrent)));
}
return vertices;

LAB to XYZ and XYZ to RGB color space conversion algorithm

I tried to convert CIE-LAB color space to RGB color space. But there is a mistake.
input LAB values = (46.41,-39.24,33.51)
received result XYZ values =(-2,641482,15,57358,-5,368798)
received result RGB vaues = (-791,4557,135,8615,-271,5485)
XYZ values should be (9.22,15.58,5.54)
RGB values should be (50,125,50)
I checked these values from http://colorizer.org/
Where did I make a mistake?
If you check the following code and answer me. I will be glad. Thanks.
I convert RGB to XYZ and XYZ to LAB color space conversion. You can check
using the following link.
RGB / XYZ and XYZ-LAB color space conversion algorithm
public static Vector4 LabToXYZ(Vector4 color)
{
float[] xyz = new float[3];
float[] col = new float[] { color[0], color[1], color[2], color[3]};
xyz[1] = (col[0] + 16.0f) / 116.0f;
xyz[0] = (col[1] / 500.0f) + xyz[0];
xyz[2] = xyz[0] - (col[2] / 200.0f);
for (int i = 0; i < 3; i++)
{
float pow = xyz[i] * xyz[i] * xyz[i];
if (pow > .008856f)
{
xyz[i] = pow;
}
else
{
xyz[i] = (xyz[i]- 16.0f / 116.0f) / 7.787f;
}
}
xyz[0] = xyz[0] * (95.047f);
xyz[1] = xyz[1] * (100.0f);
xyz[2] = xyz[2] * (108.883f);
return new Vector4(xyz[0], xyz[1], xyz[2], color[3]);
}
public static Vector4 XYZToRGB(Vector4 color)
{
float[] rgb = new float[3];
float[] xyz = new float[3];
float[] col = new float[] { color[0], color[1], color[2] };
for (int i = 0; i < 3; i++)
{
xyz[i] = col[i] / 100.0f;
}
rgb[0] = (xyz[0] * 3.240479f) + (xyz[1] * -1.537150f) + (xyz[2] * -.498535f);
rgb[1] = (xyz[0] * -.969256f) + (xyz[1] * 1.875992f) + (xyz[2] * .041556f);
rgb[2] = (xyz[0] * .055648f) + (xyz[1] * -.204043f) + (xyz[2] * 1.057311f);
for (int i = 0; i < 3; i++)
{
if (rgb[i] > .0031308f)
{
rgb[i] = (1.055f * (float)Math.Pow(rgb[i], (1.0f / 2.4f))) - .055f;
}
else
{
rgb[i] = rgb[i] * 12.92f;
}
}
rgb[0] = rgb[0] * 255.0f;
rgb[1] = rgb[1] * 255.0f;
rgb[2] = rgb[2] * 255.0f;
return new Vector4(rgb[0], rgb[1], rgb[2], color[3]);
}
public static Vector4 LabToRGB(Vector4 color)
{
Vector4 xyz = LabToXYZ(color);
Vector4 rgb = XYZToRGB(xyz);
Debug.Log("R: " + rgb[0]);
Debug.Log("G: " + rgb[1]);
Debug.Log("B: " + rgb[2]);
Debug.Log("A: " + color[3]);
return new Vector4 (rgb[0],rgb[1],rgb[2]);
}
I changed only XYZ computations in the LabToXYZ function and I received correct values.
There is a little mistake.
xyz[1] = (col[0] + 16.0f) / 116.0f;
xyz[0] = (col[1] / 500.0f) + xyz[0];
xyz[2] = xyz[0] - (col[2] / 200.0f);
Is not correct. This should be like below
xyz[1] = (col[0] + 16.0f) / 116.0f;
xyz[0] = (col[1] / 500.0f) + xyz[1];
xyz[2] = xyz[1] - (col[2] / 200.0f);
Also, you can change to LabToXYZ function like the following function.
public static Vector4 LabToXYZ(Vector4 color)
{
float[] xyz = new float[3];
float[] col = new float[] { color[0], color[1], color[2], color[3]};
xyz[1] = (col[0] + 16.0f) / 116.0f;
xyz[0] = (col[1] / 500.0f) + xyz[1];
xyz[2] = xyz[1] - (col[2] / 200.0f);
for (int i = 0; i < 3; i++)
{
float pow = xyz[i] * xyz[i] * xyz[i];
float ratio = (6.0f / 29.0f);
if (xyz[i] > ratio)
{
xyz[i] = pow;
}
else
{
xyz[i] = (3.0f * (6.0f / 29.0f) * (6.0f / 29.0f) * (xyz[i] - (4.0f / 29.0f)));
}
}
xyz[0] = xyz[0] * 95.047f;
xyz[1] = xyz[1] * 100.0f;
xyz[2] = xyz[2] * 108.883f;
return new Vector4(xyz[0], xyz[1], xyz[2], color[3]);
}
see: https://en.wikipedia.org/wiki/CIELAB_color_space#RGB_and_CMYK_conversions for other computations

Why am I getting the System.OverflowException?

This program is coded in c#. It is supposed to display a 3d Graph of the function Log(x,y). I don't know why but everytime I run it I get the System.OverflowException when it begins to draw the graph and the program stops.
How can I prevent it from happening and why does it happen?
private void Draw_Function_Click(object sender, EventArgs e)
{
int size = 100;
double accuracy = 0.09;
int zoom = 1;
ver = new double[size, size];
xtag = new double[size, size];
ytag = new double[size, size];
function = Insert_Function.Text;
for (int i = 0; i < 100; i++)
{
for (int p = 0; p < 100; p++)
{
ver[i, p] = Math.Log(i,p);
xtag[i, p] = p * accuracy - i * accuracy * Math.Cos(Math.PI / 5);
ytag[i, p] = ver[i, p] - i * accuracy * Math.Sin(Math.PI / 5);
}
}
Graphics g = panel1.CreateGraphics();
for (int i = 0; i < ver.GetLength(0) - 1; i++)
for (int p = 1; p < ver.GetLength(1) - 1; p++)
{
int y0 = (panel1.Height / 2) - (int)(ytag[i, p] * zoom);
int x0 = (int)(zoom * xtag[i, p]) + panel1.Width / 2;
int y1 = (panel1.Height / 2) - (int)(ytag[i + 1, p + 1] * zoom);
int x1 = (int)(zoom * xtag[i + 1, p + 1]) + panel1.Width / 2;
g.DrawLine(Pens.Black,
(float)x0,
(float)y0,
(float)x1,
(float)y1);
}
}
I found the following answer: https://social.msdn.microsoft.com/Forums/windows/en-US/9f2b5bba-f725-45c1-9ada-383151267c13/overflow-exception-on-drawline-method-?forum=winforms
Quote: "Hi, the minimum value allowed for screen coordinate is x = -1073741376 and y = -1073740288, this is the boundary where the desktop surface lies, if you go further, you enter the void, therfore cause an overflow..."
I ran your calculation and besides the fact that it produces NaN and -Infinity values, it also produced very small values like -2147483503. This is the reason why you get the overflow exception.

Strange Fluid Simulation oscillations in Unity

I am trying to implement a fluid surface simulation using the paper Fast Hydraulic Erosion Simulation and Visualization on GPU as a template to simulate water. However, I get artifacts like this:
The code for my update function is below, I have followed another post on this subject, but the change did not help.
private void updateHeight (float dt, float dx){
float dhL, dhR, dhF, dhB, DV;
float totalFlux;
float updateConstant;
float fluxConstant = dt*GRAVITY/(2*VISCOUSCOEFFICEINT*dx);
//Update Flux
for (int y=1; y<=N-1; y++){
for(int x=1;x<=N-1;x++){
dhL = this.height[x][y] - this.height[x-1][y];
dhR = this.height[x][y] - this.height[x+1][y];
dhF = this.height[x][y] - this.height[x][y+1];
dhB = this.height[x][y] - this.height[x][y-1];
if (Mathf.Abs(dhL) < 0.0001f){
dhL=0.0f;
}
if (Mathf.Abs(dhR) < 0.0001f){
dhR=0;
}
if (Mathf.Abs(dhF) < 0.0001f){
dhF=0;
}
if (Mathf.Abs(dhB) < 0.0001f){
dhB=0;
}
this.tempFluxArray[x][y].fluxL = Mathf.Max(0.0f, this.fluxArray[x][y].fluxL + fluxConstant*dhL);
this.tempFluxArray[x][y].fluxR = Mathf.Max(0.0f, this.fluxArray[x][y].fluxR + fluxConstant*dhR);
this.tempFluxArray[x][y].fluxF = Mathf.Max(0.0f, this.fluxArray[x][y].fluxF + fluxConstant*dhF);
this.tempFluxArray[x][y].fluxB = Mathf.Max(0.0f, this.fluxArray[x][y].fluxB + fluxConstant*dhB);
totalFlux = this.tempFluxArray[x][y].fluxL + this.tempFluxArray[x][y].fluxR + this.tempFluxArray[x][y].fluxF + this.tempFluxArray[x][y].fluxB;
if(totalFlux > 0){
updateConstant = Mathf.Min(1.0f, this.height[x][y]* dx*dx/(totalFlux * dt));
this.tempFluxArray[x][y].fluxL = updateConstant * this.tempFluxArray[x][y].fluxL;
this.tempFluxArray[x][y].fluxR = updateConstant * this.tempFluxArray[x][y].fluxR;
this.tempFluxArray[x][y].fluxF = updateConstant * this.tempFluxArray[x][y].fluxF;
this.tempFluxArray[x][y].fluxB = updateConstant * this.tempFluxArray[x][y].fluxB;
}
}
}
swap();
//Height Calculation
for (int y=1; y<=N-1; y++){
for(int x=1;x<=N-1;x++){
DV = dt*(this.fluxArray[x-1][y].fluxR + this.fluxArray[x][y-1].fluxF + this.fluxArray[x+1][y].fluxL + this.fluxArray[x][y+1].fluxB - this.fluxArray[x][y].fluxL - this.fluxArray[x][y].fluxR - this.fluxArray[x][y].fluxF - this.fluxArray[x][y].fluxB);
this.height[x][y] = this.height[x][y] + DV/(dx*dx);
if(this.height[x][y] < 1){
// Debug.Log(x);
// Debug.Log(y);
}
}
}
}
Could it be due to using this rather than ref? The way I interact with the water surface written below.
private void waterdrop(int x, int y){
float sqrD = 0.8f*0.8f;
for (int j = 1; j < N; j++) {
for (int i = 1; i < N; i++) {
float sqrDToVert = (float)0.2f*(i - x)*(i-x) + 0.2f*(j - y)*(j-y);
if (sqrDToVert <= sqrD){
float distanceCompensator = 1 - (sqrDToVert/sqrD);
this.fluxArray[i][j].fluxL = this.fluxArray[i][j].fluxL + (0.02f * distanceCompensator);
this.fluxArray[i][j].fluxR = this.fluxArray[i][j].fluxR + (0.02f * distanceCompensator);
this.fluxArray[i][j].fluxF = this.fluxArray[i][j].fluxF + (0.02f * distanceCompensator);
this.fluxArray[i][j].fluxB = this.fluxArray[i][j].fluxB + (0.02f * distanceCompensator);
//this.height[i][j] = this.height[i][j] - 1.0f * distanceCompensator;
Debug.Log(this.height[i][j]);
}
//Debug.Log("x = "+i+"\n y = "+j+" height is "+this.height[i][j]);
}
}
}
Namely just changing the flux at some point at all direction.
Some solutions I have tried was to change the height but that didn't work or clamp on small changes only but it only built up. The boundary conditions are zero flux on all boarders and the height would be the same as the closest point.

N body simulation in C#

I'm trying to implement an N body simulation in C# using either Runge Kutta 4 or Velocity Verlet integration algorithms.
Before I move to a bigger number of particles, I wanted to test the simulation by modeling the earth's orbit around the sun, however, instead of the elliptical orbit, I get a weird spiral for some reason.
I can't figure out the problem since I made a simpler simulation of the solar system using the same algorithms where the sun was fixed in position and everything worked perfectly. The integrators work perfectly because it doesn't matter which one I use, I get the spiral with both.
Any help would be appreciated.
Here's the code:
class NBODY
{
public static double G = 4 * Math.PI * Math.PI;
class Particle
{
public double[] r; // position vector
public double[] v; // velocity vector
public double mass;
//constructor
public Particle() {}
public Particle(double x, double y, double z, double vx, double vy, double vz, double m)
{
this.r = new double[3];
this.v = new double[3];
this.r[0] = x;
this.r[1] = y;
this.r[2] = z;
this.v[0] = vx;
this.v[1] = vy;
this.v[2] = vz;
this.mass = m;
}
public void Update(Particle[] particles, double t, double h, int particleNumber)
{
RungeKutta4(particles, t, h, particleNumber);
}
private double acc(double r, Particle[] particles, int particleNumber, double[] r_temp, int l)
{
// dv/dt = f(x) = -G * m_i * (x - x_i) / [(x - x_i)^2 + (y - y_i)^2 + (z - z_i)^2]^(3/2)
double sum = 0;
switch (l)
{
case 0:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow( Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[1] - particles[i].r[1], 2) + Math.Pow(r_temp[2] - particles[i].r[2], 2), 1.5);
break;
case 1:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow(Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[0] - particles[i].r[0], 2) + Math.Pow(r_temp[2] - particles[i].r[2], 2), 1.5);
break;
case 2:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow(Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[0] - particles[i].r[0], 2) + Math.Pow(r_temp[1] - particles[i].r[1], 2), 1.5);
break;
}
return -G * sum;
}
private void RungeKutta4(Particle[] particles, double t, double h, int particleNumber)
{
//current position of the particle is saved in a vector
double[] r_temp = new double[3];
for (int j = 0; j < 3; j++)
r_temp[j] = this.r[j];
//loop going over all the coordinates and updating each using RK4 algorithm
for (int l = 0; l < 3; l++)
{
double[,] k = new double[4, 2];
k[0, 0] = this.v[l]; //k1_r
k[0, 1] = acc(this.r[l], particles, particleNumber, r_temp, l); //k1_v
k[1, 0] = this.v[l] + k[0, 1] * 0.5 * h; //k2_r
k[1, 1] = acc(this.r[l] + k[0, 0] * 0.5 * h, particles, particleNumber, r_temp, l); //k2_v
k[2, 0] = this.v[l] + k[1, 1] * 0.5 * h; //k3_r
k[2, 1] = acc(this.r[l] + k[1, 0] * 0.5 * h, particles, particleNumber, r_temp, l); //k3_v
k[3, 0] = this.v[l] + k[2, 1] * h; //k4_r
k[3, 1] = acc(this.r[l] + k[2, 0] * h, particles, particleNumber, r_temp, l); //k4_v
this.r[l] += (h / 6.0) * (k[0, 0] + 2 * k[1, 0] + 2 * k[2, 0] + k[3, 0]);
this.v[l] += (h / 6.0) * (k[0, 1] + 2 * k[1, 1] + 2 * k[2, 1] + k[3, 1]);
}
}
/*
Velocity Verlet algorithm:
1. Calculate y(t+h) = y(t) + v(t)h + 0.5a(t)h*h
2. Derive a(t+h) from dv/dt = -y using y(t+h)
3. Calculate v(t+h) = v(t) + 0.5*(a(t) + a(t+h))*h
*/
private void VelocityVerlet(Particle[] particles, double t, double h, int particleNumber)
{
double[] r_temp = new double[3];
for (int j = 0; j < 3; j++)
r_temp[j] = this.r[j];
//loop going over all the coordinates and updating each using RK4 algorithm
for (int l = 0; l < 3; l++)
{
//position
this.r[l] += h * this.v[l] + 0.5 * h * h * acc(this.r[l], particles, particleNumber, r_temp, l);
//velocity
this.v[l] += 0.5 * h * (acc(r_temp[l], particles, particleNumber, r_temp,l)
+ acc(this.r[l], particles, particleNumber, r_temp,l));
}
}
}
static void Main(string[] args)
{
//output file
TextWriter output = new StreamWriter("ispis.txt");
// declarations of variables
Particle[] particles = new Particle[2];
particles[0] = new Particle(0, 0, 0, 0, 0, 0, 1); //sun
particles[1] = new Particle(1, 0, 0, 0, 6.28, 0, 3.003467E-06); //earth
int N = 200;
double h, t, tmax;
double[,,] x = new double[particles.Length, N, 3]; //output
// setting initial values, step size and max time tmax
h = 0.01; // the step size in years
tmax = h * N;
// initial time
t = 0;
int i = 0;
while (t <= tmax) {
//updates position of all particles
for (int z = 1; z < particles.Length; z++)
particles[z].Update(particles, t, h, z);
//saves the position for output
for (int j = 1; j < particles.Length ; j++)
for (int z = 0; z < 3; z++ )
x[j,i,z] = particles[j].r[z];
t += h;
i++;
}
//output to file
for (int k = 0; k < particles.Length; k++ )
{
for (int f = 0; f < 3; f++)
{
for (int l = 0; l < N; l++)
output.Write(string.Format("{0,-15:0.########},", x[k,l,f]));
output.Write(string.Format("\n\n"));
}
output.Write(string.Format("\n\n\n\n"));
}
output.Close();
}
}
And here's the plot of the output data for earth's orbit:
Your model calculates the gravity force between two particles twice: for the first particle the force is based on their original coordinates, and for the second particle it is based on an updated position of the first one. This is a clear violation of the Newton's 3rd law. You must precompute all the forces before any update.
Your problem with the orbital of Earth is because the Center of Gravity of the System Earth-Sun, if you want to see the Orbital stay in loops you need to set center Of Gravity In (x,y,z)=(0,0,0) ;
I have a C# code based on your code Above so :
public partial class Form1 : Form
{
static
int
x1,y1,x2,y2, x3, y3;//for the 3th particule
private void timer1_Tick_1(object sender, EventArgs e)
{Moveu();
Invalidate();
}
private void button1_Click_1(object sender, EventArgs e)
{
timer1.Enabled = !timer1.Enabled;
}
public Form1()
{
InitializeComponent();
Paint += new PaintEventHandler(paint);
MouseDown += new MouseEventHandler(mouse_Click);
MouseUp += new MouseEventHandler(mouse_up);
MouseMove += new MouseEventHandler(mouse_move);
// x y z vx vy vz m
particles[0] = new Particle( 0, 0, 0, 0, 0, 0, 1 ) ; //sun
particles[1] = new Particle( 1, 0, 0, 0, 6, 0, 0.03 ); //earth
// particles[2] = new Particle( 0, 2, 0, 0, 0, 0, 1 ); //planet
x1 = (int)(100 * particles[0].r[0] + 300);
y1 = (int)(100 * particles[0].r[1] + 300);
x2 = (int)(100 * particles[1].r[0] + 300);
y2 = (int)(100 * particles[1].r[1] + 300);
}
Particle[] particles = new Particle[2];
void Moveu()
{
double h, t;
// setting initial values, step size and max time tmax
h = 0.005; // the step size in years
// initial time
t = 0;
//updates position of --all-- particles ( z=0 not z=1 )
for (int z = 0; z < particles.Length; z++)
particles[z].RungeKutta4(particles, t, h, z);
x1 = (int)(100 * particles[0].r[0] + 300); // +300 just for render it in centre
y1 = (int)(100 * particles[0].r[1] + 300);
x2 = (int)(100 * particles[1].r[0] + 300);
y2 = (int)(100 * particles[1].r[1] + 300);
// x3 = (int)(100 * particles[2].r[0] + 300);
// y3 = (int)(100 * particles[2].r[1] + 300);
}
void paint(object s, PaintEventArgs e)
{
Graphics graf;
graf = CreateGraphics();
graf.FillEllipse(new SolidBrush(Color.AntiqueWhite), x1 + move.X, y1 + move.Y, 50, 50);
graf.FillEllipse(new SolidBrush(Color.Blue), x2 + move.X, y2 + move.Y, 10, 10);
// graf.FillEllipse(new SolidBrush(Color.Yellow), x3, y3, 20, 20);
}
class Particle
{
public double[] r; // position vector
public double[] v; // velocity vector
public double mass;
//constructor
public Particle() { }
public Particle(double x, double y, double z, double vx, double vy, double vz, double m)
{
this.r = new double[3];
this.v = new double[3];
this.r[0] = x;
this.r[1] = y;
this.r[2] = z;
this.v[0] = vx;
this.v[1] = vy;
this.v[2] = vz;
this.mass = m;
}
private double acc(double r, Particle[] particles, int particleNumber, double[] r_temp, int l)
{
// dv/dt = f(x) = -G * m_i * (x - x_i) / [(x - x_i)^2 + (y - y_i)^2 + (z - z_i)^2]^(3/2)
double sum = 0;
switch (l)
{
case 0:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow(Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[1] - particles[i].r[1], 2) + Math.Pow(r_temp[2] - particles[i].r[2], 2), 1.5);
break;
case 1:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow(Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[0] - particles[i].r[0], 2) + Math.Pow(r_temp[2] - particles[i].r[2], 2), 1.5);
break;
case 2:
for (int i = 0; i < particles.Length; i++)
if (i != particleNumber)
sum += particles[i].mass * (r - particles[i].r[l]) / Math.Pow(Math.Pow(r - particles[i].r[l], 2)
+ Math.Pow(r_temp[0] - particles[i].r[0], 2) + Math.Pow(r_temp[1] - particles[i].r[1], 2), 1.5);
break;
}
return -G * sum;
}
public void RungeKutta4(Particle[] particles, double t, double h, int particleNumber)
{
//current position of the particle is saved in a vector
double[] r_temp = new double[3];
for (int j = 0; j < 3; j++)
r_temp[j] = this.r[j];
//loop going over all the coordinates and updating each using RK4 algorithm
for (int l = 0; l < 3; l++)
{
double[,] k = new double[4, 2];
k[0, 0] = this.v[l]; //k1_r
k[0, 1] = acc(this.r[l], particles, particleNumber, r_temp, l); //k1_v
k[1, 0] = this.v[l] + k[0, 1] * 0.5 * h; //k2_r
k[1, 1] = acc(this.r[l] + k[0, 0] * 0.5 * h, particles, particleNumber, r_temp, l); //k2_v
k[2, 0] = this.v[l] + k[1, 1] * 0.5 * h; //k3_r
k[2, 1] = acc(this.r[l] + k[1, 0] * 0.5 * h, particles, particleNumber, r_temp, l); //k3_v
k[3, 0] = this.v[l] + k[2, 1] * h; //k4_r
k[3, 1] = acc(this.r[l] + k[2, 0] * h, particles, particleNumber, r_temp, l); //k4_v
this.r[l] += (h / 6.0) * (k[0, 0] + 2 * k[1, 0] + 2 * k[2, 0] + k[3, 0]);
this.v[l] += (h / 6.0) * (k[0, 1] + 2 * k[1, 1] + 2 * k[2, 1] + k[3, 1]);
}
}
}
public static double G = 4 * Math.PI * Math.PI; //then time unite in years and length unite = distance between Earth and Sun and masse is the sun masse unite
void mouse_Click(object o, MouseEventArgs e)
{
dwn = new Point(e.X, e.Y);
if ("" + e.Button == "Left")
{
pos = move;
clicked = true;
}
}
void mouse_move(object o, MouseEventArgs e)
{
if (clicked)
{
move = new Point(e.X + pos.X - dwn.X, e.Y + pos.Y - dwn.Y);
Invalidate();
}
}
void mouse_up(object o, MouseEventArgs e)
{
clicked = false;
}
Point dwn, pos,move;
bool clicked;
}`you need to create a Timer and a button [![enter image description here][1]][1]

Categories