Getting random Vector2 positions within a crescent area - c#

I am struggling to find a way to get Random positions within a Crescent area.
Calculating the crescent is well documented using the difference of two overlapping circles.
But that calculates the surface area, which is not enough if I want to generate random positions in that area.
In this illustration we know both the center origin points and radii:
CenterPoint of CircleA ca=0,0 Radius of ca caRad = 100
CenterPoint of CircleB cb=9,0 Radius of cb cbRad = 85
knowing these values we could fill in all the variables on the illustration; A, B, D, E and F.
Calculating the Crescent Area would be
π*(caRad²) - π*(cbRad²) = 2775π
And this is where I am stuck, I have all the information yet, don't know on how to proceed getting random positions 'Within' that crescent area.
Any help in this matter is very appreciated, Nick.

Repeat generating random points in the outer circle (in the full area of it) by generating points in the bounding square until a point is in the outer circle but not within the inner circle.
float caRad = 100;
float cbRad = 85;
var ca = new PointF(0, 0);
var cb = new PointF(caRad - cbRad, 0); // = (15, 0), because with (9, 0) the inner
// circle would not touch the outer circle.
var random = new Random();
PointF p;
do {
p = new PointF(
ca.X + 2 * caRad * random.NextSingle() - caRad,
ca.Y + 2 * caRad * random.NextSingle() - caRad
);
PointF da = p - ca;
PointF db = p - cb;
} while (da.X * da.X + da.Y * da.Y > caRad * caRad || // while p not in ca OR
db.X * db.X + db.Y * db.Y <= cbRad * cbRad); // p in cb
// Here the random point p is in ca but not in cb.
The while-condition calculates the square of the Euclidean distance of the point to the center of the circles and compares it to the square of the radii of the circles to determine whether a point is within a circle or not. The calculation of the Euclidean distance is based on the Pythagorean theorem.
We could use the square root function to get the real distance, but is cheaper to calculate the square of the radii instead.

If circle radii are not too close, then you can generate random point inside larger circle, then check if point is outside of the smaller circle. If not, repeat generation.
a = random()*2*Pi
r = R1*sqrt(random())
x = cx + r*cos(a)
y = cy + r*sin(a)
if (x-c2x)^2+(y-c2y)^2 >= R2^2:
point in crescent
For almost equal circles (very small crescent area) this method is not effective. In this case one could generate random angle in 0..2Pi range with cosine (non-uniform) distribution, then get radius in range corresponding to this angle.

It's not necessarily cheap, and I don't think it distributes uniformly if you really care about that, but you can:
Generate a random point on the boundary of the inner circle (i.e. generate a random angle from 0 to 360)
Draw a line from the center of the inner circle to the point on the boundary you rolled, then continue that line until it hits the boundary of the outer circle (don't actually draw it, just conceptualize it)
Generate a random point on the part of that line which is outside the inner circle and inside the outer circle

Related

Drawing a circle of unknown number of circles

I am currently working on a WinForms app, which at some point has to draw some stuff. Basically, it has to draw an unknown number of circles (f.e 3, 5, 10) in organized in a shape of a circle. Something like this:
I know it looks horrible. So I thought about defining a center of a circle and a radius. Then I just have to go f.e from the top of the big circle and draw a small circle every x-degrees (like for 3 circles it would be 120 degrees, for 4 circles 90 degrees etc.).
My question here is: Is there an algorithm, which would give me the center point of a circle to draw? Like I define my big circle with f.e center X = 50, Y = 50 and a radius R = 10. And then I draw a circle at the top, decide that I want to draw the next one 120 degrees far from the first one and I just need a point (X, Y) which is on the big circle?
Basically, you just need some math to figure out the coordinate of where the angle lands at the end of perimeter of the circle (a distance of the radius of the circle from the center of the circle). Here's psuedocode for this situation.
var center = new Point(0,0);
var radius = 5;
var degrees = 83;
var angle = Math.PI * degrees / 180;
var xPos = center.X + (radius * Math.cos(angle));
var yPos = center.Y + (radius * Math.sin(angle));
var newPosition = new Point(xPos,yPos);
Here, newPosition becomes the center point for the circled you'll be drawing along your imaginary circle. As for gathering the angles, simply use 360 / count * index.

Algorithm for rounding a corner between line and arc

I need an algorithm that can round a corner between a line and an arc. The start information that I have is P0-start point, P-corner point, P2-end point, R2-radius of the arc between P and P2 and R-radius of the rounded corner(on the second picture).
Output or wanted points are cross sections C0 and C2 and center point of the rounding circle-O
In my sketch BF is part of given segment (F is not known yet), C is center of given arc, B is point of rough conjugation. c is line, parallel to BF, |GF|=|GH| = r - radius of small arc.
To make smooth conjugation, tangent to small arc in point F should be collinear with BF direction, so GF is perpendicular to BF, and tangents to both arcs in point H should coincide - so radius-vectors CH and GH lie on the same line.
Let unit direction vector of BF segment is ud=(dx,dy), so unit normal is un=(-dy, dx). (Negate normal for arcs at another side of BF)
Center of small arc G has coordinates (where t is unknown parameter - length of BF)
G = B + ud * t + un * r
and distance GC is difference of arcs radii, so
|G - C| = |R - r|
or in coordinates:
(B.x + dx * t - dy * r - C.x)^2 + (B.y + dy * t + dx * r - C.y)^2 = (R - r)^2
Open parentheses, solve quadratic equation for unknown t. If solutions exist, choose right root, and you'll get coordinates of center of conjugation arc G and its ends
quick check1:
Line Y=5, big arc with R=5, we want small arc with r=2
B=(5,5)
ud=(-1,0)
un=(0,-1)
(5-t)^2 + (5-2-5)^2 = (5-2)^2
solution gives
t = 5 +/- Sqrt(5), the second root is valid
E = (5 - (5 - Sqrt(5)), 3) = (2.23, 3)
Resulting smooth arc is c-f
quick check2:
Line Y=5, big arc with R=5, we want small arc with r=2
B=(5,5)
big arc center (H here) = (1,2)
ud=(-1,0)
un=(0,-1)
(4-t)^2 + (5-2-2)^2 = (5-2)^2
solution gives
t = 4 +/- Sqrt(8), the second root is valid
E = (5 - (4 - Sqrt(8)), 3) = (3.83, 3)
Resulting smooth arc is F-G
(In both cases larger root corresponds to conjugation with complementary part of big arc)
There isn't enough specification to choose a unique arc. You need to figure out what endpoints you want. Then solve for the ellipse that is tangent to both of those points. See Wikipedia/ellipse for the equations. I recommend a math package (e.g. SciKit) to solve for you.

Get random vector3 on plane

There are the planet and a few satellites in 3d space. I need to calculate axis of rotation for every satellite. They should rotate around planet center.
I calculated the vector from satellite to the center of the planet.
vec1 = planetCenter - sputnikCenter;
With vec1 and planetCenter I can calculate the equation of plane, that perpendicular to vec1.
equation like that:
A.x + B.y + C.z + D = 0
Now, I should get random vector on this plane. This vector will be axis of rotation. But how can I get this random vector?
well if you got the plane A.x + B.y + C.z + D = 0 then n(A,B,C) is the normal vector. So I think the easiest approach to your task is to use basis vectors. So you need 2 perpendicular vectors on this plane. For that you can exploit cross product. first some definitions:
knowns:
p planet center position (or the center point of your rotations or any point on the plane so in worst case you can try p=0,0,-D/C or any other combinationn...)
n normal vector
q= (1,0,0) or (0,1,0) chose the one that has lesser |dot(n,q)|
operations:
vector = cross(a,b) = a x b - cross product returns perpendicular vector to a,b
scalar = dot(a,b) = (a.b) - dot product returns 0 if a,b are perpendicular
|a| = abs(a) - absolute value (both scalar and vector)
scalar = Rand() - float pseudo random value on interval <0.0,1.0>
unknowns:
u,v - basis vectors
r - your pseudo-random point
So first get u,v by exploiting cross product:
u=cross(n,q)
v=cross(n,u)
And now the point:
r = p + u*(2.0*Rand()-1.0) + v*(2.0*Rand()-1.0)
If you want just random vector then ignore the start position p
r' = u*(2.0*Rand()-1.0) + v*(2.0*Rand()-1.0)
That is all ... so you can compute u,v once (per normal vector change) and generate the r as often as you need. If u,v are unit vectors then this will generate points inside 2x2 square ... if you want more or less just add scales to them ...
see Is it possible to make realistic n-body solar system simulation? and generate random orbital parameters for Kepler's equation instead ...
It seems your rotation axis might be random vector that is independent from vec1.
You can generate random unit vector with uniform distribution using methods for Sphere Point Picking.
Marsaglia method (eq. 9-11) is convenient to generate this vector:
Generate x1 and x2 in range -1..1 such as p = x1^2 +x2^2 <= 1 (rejecting bad pairs).
Then
x = 2 * x1 * Sqrt(1 - p)
y = 2 * x2 * Sqrt(1 - p)
z = 1 - 2 * p
Now your question is clear. You want to rotate object around another, like Earth and Sun. May be some other solutions may available but I would do it through LookAt and parametric equation of circle.
x = r * cos(theta) + displacementX
z = r * sin(theta) + displacementZ
where r is radius, distance in your case
displacementX and displacementZ are the distance from origin. If both (displacementX and displacementZ) is 0 then it will rotate around origin (0,0)
In Object(Earth) script, do it as follow
public Transform _sun;
float _theta = 0;
void Start ()
{
StartCoroutine ("ChangeAngle");
}
void Update ()
{
transform.LookAt (_sun);
float newX = (5 * Mathf.Cos (_theta)) + _sun.position.x;
float newZ = (5 * Mathf.Sin (_theta)) + _sun.position.z;
transform.position = new Vector3 (newX, _sun.position.y, newZ);
}
IEnumerator ChangeAngle ()
{
while (true) {
yield return new WaitForSeconds (0.01f);
_theta += 0.1f;
if (_theta >= 360)
_theta = 0;
}
}
You can further play with it

Detecting collision between circles drawn in an array c#

I am drawing 10 circles in an array, these circles are moving around and bouncing across the screen. How would I take these drawn circles and detect when they collide with each other. When they collide I need them to bounce off of each other. These circles have random widths and heights. random speeds and all spawn at center screen.
How the circles are drawn:
private void pbGamescreen_Paint(object sender, PaintEventArgs e)
{
for (int mt = 0; mt < spawn; mt++)
{
e.Graphics.FillEllipse(ballBrush[mt], (int)xPos[mt], (int)yPos[mt], ballSizex[mt], ballSizey[mt]);
e.Graphics.DrawEllipse(Pens.Gray, (int)xPos[mt], (int)yPos[mt], ballSizex[mt], ballSizey[mt]);
}
}
Two circles intersect if the distance between their center points is smaller than the addition of their radiuses. You need to iterate each of your circle and check this against each other circle.
For instance, say you have these two circles on a horizontal axis:
(-----o-----) (---o---)
They do not intersect, as the distance between their center points is 12, and the sum of their radiuses is 8. However, these two do:
(-----o----(-)--o---)
The formula for the distance between two 2D points is:
var xdiff = x2 - x1;
var ydiff = y2 - y1;
return Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
if r1 and r2 are radiuses of the two circles, and d is the distance between the centers of teh two circles then
bounce off when d<=r1 + r2;
ideally you should do it when d == r1 + r2;
Just a suggestion:
also keep the mass of the circle proportional to their r(radius) and then using the law of conservation momentum m1v1 = m2v2; bounce them offf in a way that looks real

Get vertices of an Arc where I have its StartPoint, Center and EndPoint

I want to know the vertices of the arc where I have its StartPoint, Center and the EndPoint as well as the radius of the arc. I am aware that the arc which is drawn is by creating a small lines with the precision which is specified in the parameter. What I am trying to achieve is calculate the area of a polygon which may have an arc in it which can look like the image I have attached with this question.
SP = StartPoint of the Arc.
EP = EndPoint of the Arc.
CP = Center of the Arc.
Knowing StartPoint, Center and the EndPoint of arc is not enough to define it uniquely. You have to knew some another parameter(s).
When arc is well defined, it is possible to calculate an area of circular segment geometrically
Edit: Because you also know radius R, we can calculate an area:
Theta = 2 * ArcSin(Distance_SPtoEP/(2*R))
Area = 1/2 * R * R * (Theta - Sin(Theta))
Quick check:
R = 1, semicircle.
Theta = 2 * ArcSin(2/2) = 2 * Pi/2 = Pi
Area = 1/2 * (Pi - 0) = Pi/2 - true
Edit2: It is simpler to connect SP and EP to get remaining polygon, than build polyline approximation of arc and calc area of hundred-vertice polygon.
Polyline approximation:
We want that arc-line distance doesn't excess some limit d. So we will calculate small arc angle A
d = R * (1-Cos(A/2))
A = 2 * ArcCos(1-d/R)
Now divide large arc to small pieces with angle A, and generate new vertices
Your drawing seems to indicate a half ellipse.
The long axis (A) would be SP-EP and the short axis (B) should be given. The area is Pi.A.B/8.

Categories

Resources