Galaxy Generation Algorithm - c#

I'm trying to generate a set of points (represented by a Vector struct) that roughly models a spiral galaxy.
The C# code I've been playing with is below; but I can only seem to get it to generate a single 'arm' of the galaxy.
public Vector3[] GenerateArm(int numOfStars, int numOfArms, float rotation)
{
Vector3[] result = new Vector3[numOfStars];
Random r = new Random();
float fArmAngle = (float)((360 / numOfArms) % 360);
float fAngularSpread = 180 / (numOfArms * 2);
for (int i = 0; i < numOfStars; i++)
{
float fR = (float)r.NextDouble() * 64.0f;
float fQ = ((float)r.NextDouble() * fAngularSpread) * 1;
float fK = 1;
float fA = ((float)r.NextDouble() % numOfArms) * fArmAngle;
float fX = fR * (float)Math.Cos((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));
float fY = fR * (float)Math.Sin((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));
float resultX = (float)(fX * Math.Cos(rotation) - fY * Math.Sin(rotation));
float resultY = (float)(fY * Math.Cos(rotation) - fX * Math.Sin(rotation));
result[i] = new Vector3(resultX, resultY, 1.0f);
}
return result;
}

Check this. It's a simulation of galaxy using density wave theory. Code is available.
http://beltoforion.de/galaxy/galaxy_en.html

I liked this idea so much i had to play around with it on my own and here is my result.
Note that i used PointF instead of Vector3, but you should be able to search and replace and add , 0) in a few places.
PointF[] points;
private void Render(Graphics g, int width, int height)
{
using (Brush brush = new SolidBrush(Color.FromArgb(20, 150, 200, 255)))
{
g.Clear(Color.Black);
foreach (PointF point in points)
{
Point screenPoint = new Point((int)(point.X * (float)width), (int)(point.Y * (float)height));
screenPoint.Offset(new Point(-2, -2));
g.FillRectangle(brush, new Rectangle(screenPoint, new Size(4, 4)));
}
g.Flush();
}
}
public PointF[] GenerateGalaxy(int numOfStars, int numOfArms, float spin, double armSpread, double starsAtCenterRatio)
{
List<PointF> result = new List<PointF>(numOfStars);
for (int i = 0; i < numOfArms; i++)
{
result.AddRange(GenerateArm(numOfStars / numOfArms, (float)i / (float)numOfArms, spin, armSpread, starsAtCenterRatio));
}
return result.ToArray();
}
public PointF[] GenerateArm(int numOfStars, float rotation, float spin, double armSpread, double starsAtCenterRatio)
{
PointF[] result = new PointF[numOfStars];
Random r = new Random();
for (int i = 0; i < numOfStars; i++)
{
double part = (double)i / (double)numOfStars;
part = Math.Pow(part, starsAtCenterRatio);
float distanceFromCenter = (float)part;
double position = (part * spin + rotation) * Math.PI * 2;
double xFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;
double yFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;
float resultX = (float)Math.Cos(position) * distanceFromCenter / 2 + 0.5f + (float)xFluctuation;
float resultY = (float)Math.Sin(position) * distanceFromCenter / 2 + 0.5f + (float)yFluctuation;
result[i] = new PointF(resultX, resultY);
}
return result;
}
public static double Pow3Constrained(double x)
{
double value = Math.Pow(x - 0.5, 3) * 4 + 0.5d;
return Math.Max(Math.Min(1, value), 0);
}
Example:
points = GenerateGalaxy(80000, 2, 3f, 0.1d, 3);
Result:

I would abstract that function out into a createArm function.
Then you can store each arm as its own galaxy (temporarily).
So if you want 2 arms, do 2 galaxies of 5000. Then, rotate one of them 0 degrees around the origin (so doesn't move) and the other 180 degrees around the origin.
With this you can do an arbitrary number of arms by using different rotation amounts. You could even add some "naturalization" to it by making the rotation distance more random, like with a range instead of straight (360 / n). For example, 5 arms would be 0, 72, 144, 216, 288. But with some randomization you could make it 0, 70, 146, 225, 301.
Edit:
Some quick google-fu tells me (source)
q = initial angle, f = angle of rotation.
x = r cos q
y = r sin q
x' = r cos ( q + f ) = r cos q cos f - r sin q sin f
y' = r sin ( q + w ) = r sin q cos f + r cos q sin f
hence:
x' = x cos f - y sin f
y' = y cos f + x sin f

Related

Rotate point test is failing. Why?

This is my Point.cs file that is failing.
// Rotates the point counter-clockwise by deg degrees. For example, applying
// a 90 degree rotation to (1, 0) should give (0, 1).
public void rotate(double deg)
{
double rotCos = Math.Cos(deg * Math.PI / 180);
double rotSin = Math.Sin(deg * Math.PI / 180);
double oldX = x;
double oldY = y;
x = oldX * rotCos - oldY * rotSin;
y = oldX * rotSin + oldY * rotCos;
Point point = new Point(x, y);
}
I run this test and get the result:
"Message: Assert.AreEqual failed. Expected:<2>. Actual:<2>."
[TestMethod]
public void Rotate_Test()
{
double rotate = -90;
double i = 4;
double o = 2;
Point point = new Point(i, o);
double expectedX = 2;
double expectedY = 4;
point.rotate(rotate);
Assert.AreEqual(expectedX, point.getX());
Assert.AreEqual(expectedY, point.getY());
}
Doubles are not exact numbers. They should not be compared for equality without specifying an acceptable difference between them.
https://msdn.microsoft.com/en-us/library/ms243458.aspx
https://msdn.microsoft.com/en-us/library/ya2zha7s(v=vs.110).aspx
Try
Assert.AreEqual(expectedX, point.getX(), 0.001);

Rotating multiple objects to face from one vector to another

Currently, I have the player select 2 positions in the map, it's a 3d world but my problem is only relevant in the first 2 dimensions. I want to create a floor between the 2 selected points, and rotate them to the angle between those 2 points. http://i.imgur.com/hCjtEzB.png (excuse my paint skills)
My code works properly in some cases, but in other cases the crates are spawned at the wrong angle. I think it has something to do with vec1.x > vec2.x, or something similar. But I can't figure it out.
What am I missing?
const int modelLength = 55;
const int modelWidth = 30;
void createFloor(Vector vec1, Vector vec2)
{
float height = vec1.Z;
float length = Math.Abs(vec1.X - vec2.X);
float width = Math.Abs(vec1.Y - vec2.Y);
int crateWidth = (int)Math.Ceiling(width / modelWidth);
int crateLength = (int)Math.Ceiling(length / modelLength);
int adjustedWidth = crateWidth * modelWidth;
int adjustedLength = crateLength * modelLength;
double angleRad = Math.Atan2(adjustedWidth, adjustedLength);
double angleDeg = Util.RadianToDegree(angleRad);
Vector angles = new Vector(0, (float)angleDeg, 0);
float mX = (vec1.X < vec2.X) ? adjustedLength / 2 + vec1.X : vec1.X - (adjustedLength / 2);
float mY = (vec1.Y < vec2.Y) ? adjustedWidth / 2 + vec1.Y : vec1.Y - (adjustedWidth / 2);
Vector middle = new Vector(mX, mY, vec1.Z);
for (int i = 0; i < crateLength; i++)
{
for (int j = 0; j < crateWidth; j++)
{
float x = (vec1.X < vec2.X) ? vec1.X + i * modelLength : vec1.X - i * modelLength;
float y = (vec1.Y < vec2.Y) ? vec1.Y + j * modelWidth : vec1.Y - j * modelWidth;
Vector v = new Vector(x, y, height);
v = Util.RotateAround(v, middle, angleDeg);
spawnCrate(v, angles);
}
}
}
public static Vector RotateAround(Vector vectorToRotate, Vector center, double angleDeg)
{
double angleRad = DegreeToRadian(angleDeg);
double cosTheta = Math.Cos(angleRad);
double sinTheta = Math.Sin(angleRad);
return new Vector
{
X = (int)(cosTheta * (vectorToRotate.X - center.X) - sinTheta * (vectorToRotate.Y - center.Y) + center.X),
Y = (int)(sinTheta * (vectorToRotate.X - center.X) + cosTheta * (vectorToRotate.Y - center.Y) + center.Y),
Z = vectorToRotate.Z
};
}
Thanks.

how to Color map to dense optical flow

I'm trying to give certain colors to image based on their movement (like vector direction) in Emgu Cv. I have managed to calculate the dense optical flow to my video stream. I have used this
OpticalFlow.Farneback(prev,NextFrame,velx,vely,0.5,1,1,2,5,1.1,Emgu.CV.CvEnum.OPTICALFLOW_FARNEBACK_FLAG.FARNEBACK_GAUSSIAN);
The variable vely and velx contains the velocity of vertical and horizontal directions.Does anyone know how to map colors to these. There are many algorithms that calculates the dense flow. HS also can be used, but I'm not sure what to use.
Any solution would be really appreciated.
EDIT:
Optical Flow Color Map in OpenCV
This is the same thing that i wanted, since I'm using Emgu cv I tried to convert this code to c# but I cannot understand how to pass the dense flow to function "colorflow".
public void colorflow(MCvMat imgColor)
{
MCvMat imgHsv = new MCvMat();
double max_s = 0;
double[] hsv_ptr = new double[3000];
IntPtr[] color_ptr = new IntPtr[3000];
int r = 0, g = 0, b = 0;
double angle = 0;
double h = 0, s = 0, v = 0;
double deltaX = 0, deltaY = 0;
int x = 0, y = 0;
for (y = 0; y < imgColor.rows; y++)
{
for (x = 0; x < imgColor.cols; x++)
{
PointF fxy = new PointF(y, x);
deltaX = fxy.X;
deltaY = fxy.Y;
angle = Math.Atan2(deltaX, deltaY);
if (angle < 0)
angle += 2 * Math.PI;
hsv_ptr[3 * x] = angle * 180 / Math.PI;
hsv_ptr[3 * x + 1] = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
hsv_ptr[3 * x + 2] = 0.9;
if (hsv_ptr[3 * x + 1] > max_s)
max_s = hsv_ptr[3 * x + 1];
}
}
for (y = 0; y < imgColor.rows; y++)
{
//hsv_ptr=imgHsv.ptr<float>(y);
//color_ptr=imgColor.ptr<unsigned char>(y);
for (x = 0; x < imgColor.cols; x++)
{
h = hsv_ptr[3 * x];
s = hsv_ptr[3 * x + 1] / max_s;
v = hsv_ptr[3 * x + 2];
//hsv2rgb(h,s,v,r,g,b);
Color c = ColorFromHSV(h, s, v);
color_ptr[3 * x] = (IntPtr)c.B;
color_ptr[3 * x + 1] = (IntPtr)c.G;
color_ptr[3 * x + 2] = (IntPtr)c.R;
}
}
drawLegendHSV(imgColor, 15, 25, 15);
}
I having trouble how to covert the two commented lines in the code. Can anyone Help me with this.?
Another thing that the Farneback algorithm gives two images velx and vely. It does not gives the flow( MCvMat). The colorFlow algorithms it takes the MCvMat type parameters.Did i done any wrong with the code. thanks

Rotate bunch of points thourgh an origin [duplicate]

This question already has answers here:
Rotating a point about another point (2D)
(6 answers)
Closed 9 years ago.
I have list of points containing x and y locations of a page. I want to apply rotation on all these points relative to any pivot point of page (currently lets assume its center).
var points = new List<Point>();
points.Add(1,1);
points.Add(15,18);
points.Add(25,2);
points.Add(160,175);
points.Add(150,97);
const int pageHeight = 300;
const int pageWidth = 400;
var pivotPoint = new Point(200, 150); //Center
var angle = 45; // its in degree.
// Apply rotation.
Do I need some formula here?
public static Point Rotate(Point point, Point pivot, double angleDegree)
{
double angle = angleDegree * Math.PI / 180;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
int dx = point.X - pivot.X;
int dy = point.Y - pivot.Y;
double x = cos * dx - sin * dy + pivot.X;
double y = sin * dx + cos * dy + pivot.X;
Point rotated = new Point((int)Math.Round(x), (int)Math.Round(y));
return rotated;
}
static void Main(string[] args)
{
Console.WriteLine(Rotate(new Point(1, 1), new Point(0, 0), 45));
}
If you have a large number of points to rotate, you might want to precompute the rotation matrix…
[C -S U]
[S C V]
[0 0 1]
…where…
C = cos(θ)
S = sin(θ)
U = (1 - C) * pivot.x + S * pivot.y
V = (1 - C) * pivot.y - S * pivot.x
You then rotate each point as follows:
rotated.x = C * original.x - S * original.y + U;
rotated.x = S * original.x + C * original.y + V;
The above formula is the result of combining three transforms…
rotated = translate(pivot) * rotate(θ) * translate(-pivot) * original
…where…
translate([x y]) = [1 0 x]
[0 1 y]
[0 0 1]
rotate(θ) = [cos(θ) -sin(θ) 0]
[sin(θ) cos(θ) 0]
[ 0 0 1]
if u rotate a point(x,y) around point (x1,y1) by an angle some a then you need a formula...
x2 = cos(a) * (x-x1) - sin(a) * (y-y1) + x1
y2 = sin(a) * (x-x1) + cos(a) * (y-y1) + y1
Point newRotatedPoint = new Point(x2,y2)

Creating a spiral galaxy need math guidance

I am creating a spinning galaxy made of blocks for the stars/systems.
I have been fiddling with this for a few days and have this so far:
public int numberArms = 6;
public int numberStars = 1000;
public float galaxyRadius = 500f;
public int spread = 100;
float fHatRandom (float fRange)
{
float fArea = 4 * Mathf.Atan (6.0f);
float fP = fArea * Random.value;
return Mathf.Tan (fP / 4) * fRange / 6.0f;
}
float fLineRandom (float fRange)
{
float fArea = fRange * fRange / 2;
float fP = fArea * Random.value;
return fRange - Mathf.Sqrt (fRange * fRange - 2 * fP);
}
// Use this for initialization
void Start ()
{
Random.seed = 100;
int starsPerArm = numberStars / numberArms;
float fAngularSpread = spread / numberArms;
float fArmAngle = (360 / numberArms);
for (int arm = 0; arm < numberArms; arm++)
{
for (int i = 0; i < starsPerArm; i++)
{
float fR = fHatRandom (galaxyRadius);
float fQ = fLineRandom (fAngularSpread);
float fK = 1;
float fA = numberArms * (fArmAngle);
float fX = fR * Mathf.Cos (Mathf.Deg2Rad * (fA + fR * fK + fQ));
float fY = fR * Mathf.Sin (Mathf.Deg2Rad * (fA + fR * fK + fQ));
Vector3 starPos = new Vector3 (fX, fY, arm*4);
Collider[] colliders = Physics.OverlapSphere (starPos, 1);
if (colliders.Length == 0)
{
GameObject star = GameObject.CreatePrimitive (PrimitiveType.Cube);
star.transform.position = starPos;
star.transform.parent = transform;
} else
{
i--;//because they overlapped, we try again.
}
}
}
}
}
As it works right now, it creates the spiral arm of the galaxy just fine. But as you can see, I just set the position of the arm to be stacked on the other arms because I cannot for the life of me figure out how to get them to rotate around the center, for that matter my center seems to be off.
I admittedly have the math skills of a gnat and have been fumbling my way through this, can someone help correct the math and get the arms/center where they belong?
Shouldn't that:
float fA = numberArms * (fArmAngle);
be
float fA = arm * (fArmAngle);
Just saying...

Categories

Resources