Calculate a curve that goes through all the points - c#

I having trouble building a curve that goes through all the points but not outside of those points as the bezier curve does in SVG.
I have tried
Bezier Curve,
Quadratic Curve,
Smooth Curve,
and Casteljau
Here is a link to my example https://dotnetfiddle.net/KEqts0
Unfortunately, I can use a 3rd party to do the mapping.
I do not want to place the output in because that will just be noise, I have included a picture for reference.

Observation: The initial question was tagged javascript. After posting my answer the javascript tag was deleted (not by the OP).
Given a points array pointsRy you will need to calculate the position of the control points for the Bézier curves. The first & the last curve are quadratic Bezier. All the other curves are cubic Bézier.
This is an image where I'm marking the points and the tangent to the curve through each point. The control points are the starting and ending points of the tangent.
The size of the tangent is calculated relative to the distance between the points: let t = 1 / 5; Change this to change the curvature.
let svg = document.querySelector("svg")
let t = 1 / 5;// change this to change the curvature
let pointsRy = [[100,100],[250,150],[300,300],[450,250], [510,140],[590,250],[670,140]];
thePath.setAttribute("d", drawCurve(pointsRy));
function drawCurve(p) {
var pc = controlPoints(pointsRy); // the control points array
let d="";
d += `M${p[0][0]}, ${p[0][1]}`
// the first & the last curve are quadratic Bezier
// because I'm using push(), pc[i][1] comes before pc[i][0]
d += `Q${pc[1][1].x}, ${pc[1][1].y}, ${p[1][0]}, ${p[1][1]}`;
if (p.length > 2) {
// central curves are cubic Bezier
for (var i = 1; i < p.length - 2; i++) {
d+= `C${pc[i][0].x}, ${pc[i][0].y} ${pc[i + 1][1].x},${pc[i + 1][1].y} ${p[i + 1][0]},${p[i + 1][1]}`;
}//end for
// the first & the last curve are quadratic Bezier
let n = p.length - 1;
d+=`Q${pc[n - 1][0].x}, ${pc[n - 1][0].y} ${p[n][0]},${p[n][1]}`;
}
return d;
}
function controlPoints(p) {
// given the points array p calculate the control points
let pc = [];
for (var i = 1; i < p.length - 1; i++) {
let dx = p[i - 1][0] - p[i + 1][0]; // difference x
let dy = p[i - 1][1] - p[i + 1][1]; // difference y
// the first control point
let x1 = p[i][0] - dx * t;
let y1 = p[i][1] - dy * t;
let o1 = {
x: x1,
y: y1
};
// the second control point
var x2 = p[i][0] + dx * t;
var y2 = p[i][1] + dy * t;
var o2 = {
x: x2,
y: y2
};
// building the control points array
pc[i] = [];
pc[i].push(o1);
pc[i].push(o2);
}
return pc;
}
body{background:black; margin:1em;}
svg{border: 1px solid #999;}
path{fill:none; stroke:white;}
<svg viewBox="0 0 800 400">
<path id="thePath" stroke="white"/>
</svg>

Related

Why do these random events follow a specific pattern?

I have created a grid layout. It displays 100 balls. Initially, all the balls will be in a random position. Every 25 ms a ball will move some unit (this is common for all the balls) in a random direction. You can see this in action in the below image:
Even though the direction of the balls is random, after some time all the balls move towards the bottom right corner. This behavior repeats every time. You can see this in the below image:
Why do these random events follow a specific pattern?
Are random numbers truly random?
Is there is a problem with the C# random number generator?
Is there is any mathematical explanation for this?
C# Code
Random random = new Random();
var direction = random.NextDouble() * 360;
var ballTranslate = child.RenderTransform.TransformPoint(new Point(0, 0));
var x = ballTranslate.X;
var y = ballTranslate.Y;
var x1 = x + (parm.Speed * Math.Cos(direction));
while (x1 < 0 || x1 > (parm.CellSize * parm.NoOfSplit))
{
direction = random.NextDouble() * 360;
x1 = x + (parm.Speed * Math.Cos(direction));
}
var y1 = y + (parm.Speed * Math.Sin(direction));
while (y1 < 0 || y1 > (parm.CellSize * parm.NoOfSplit))
{
direction = random.NextDouble() * 360;
y1 = y + (parm.Speed * Math.Sin(direction));
}
TranslateTransform myTranslate = new TranslateTransform();
myTranslate.X = x1;
myTranslate.Y = y1;
child.RenderTransform = myTranslate;
Full Code
https://github.com/Vijay-Nirmal/ProjectChaos
You appear to be generating a direction in degrees and passing it to Math.Sin, which takes an angle in radians. 360/2PI = 57.3 (approximately), so you're slightly more likely to pick an angle between 0 and 0.3 radians than other, larger angles.
When you have so many iterations, it's also possible that there's a tiny rounding error somewhere

Bezier Curve Arc-Length Parameterization

I'm learning about Bezier curves and would like to parameterize the equations for distance using an estimation method. So far, my code seems to work for single points (EG Bezier(start=0, mid=1, end=5, nPoints=6) yields [0 1 2 3 4 5]). However, when I attempt to apply this to multi-dimensional curves, my results are not as expected.
C# code (executed in Unity for visualization). The function (should) get a point on the curve (defined by the points pts) at a length l% of the length.
Vector3 BezierL(Vector3[] pts, float l)
{
int i;
float[] tVals = new float[n];
Vector3[] points = new Vector3[n];
float[] cumDist = new float[n];
for (i = 1; i < n; i++)
{
tVals[i] = i / (float)(n - 1);
points[i] = Bezier(pts, tVals[i]);
cumDist[i] = cumDist[i - 1] +
(points[i] - points[i - 1]).magnitude;
}
// Interpolate to estimate t
float targetLen = l * cumDist[n - 1];
int ind = Array.BinarySearch(cumDist, targetLen);
if (ind < 0)
ind = ~ind;
float t = Mathf.Lerp(tVals[ind - 1], tVals[ind],
(targetLen - cumDist[ind - 1]) / (cumDist[ind] - cumDist[ind - 1]));
return Bezier(pts, t);
}
where Bezier(Vector3[] pts, t) gets a point on the curve defined by pts at time t. For whatever reason, this partially works in that all points are equally spaced, but some points are stacked at the initial point rather than being distributed along the curve.
This was my reference for developing this algorithm, so I'm unsure if my implementation is incorrect, or if it only applies to lower-dimensional curves.
Thanks in advance!
Oof how embarrassing, I just forgot to compute the 0th point!

C# intersect a line bettween 2 Vector3 point on a plane

I have a line going bettween two Vector3 points and I want to find when the line is intersected at a height along the Z axis.
I am trying to write a function to calculate the intersection point.
void Main()
{
Vector3 A = new Vector3(2.0f, 2.0f, 2.0f);
Vector3 B = new Vector3(7.0f, 10.0f, 6.0f);
float Z = 3.0f;
Vector3 C = getIntersectingPoint(A, B, Z);
//C should be X=3.25, Y=4.0, Z=3.0
}
But trying to figure out how to do the math to handle possible negative numbers correctly is really starting to confuse me.
This is what I have and the moment, but this isn't correct.
public static Vector3 getIntersectingPoint(Vector3 A, Vector3 B, float Z)
{
// Assume z is bettween A and B and we don't need to validate
// Get ratio of triangle hight, height Z divided by (Za to Zb)
("absolute value: " + Math.Abs(A.Z-B.Z)).Dump();
("z offset: " + (Math.Abs(Z-B.Z)<Math.Abs(A.Z-Z)?Math.Abs(Z-B.Z):Math.Abs(A.Z-Z))).Dump();
float ratio = (Math.Abs(Z-B.Z)<Math.Abs(A.Z-Z)?Math.Abs(Z-B.Z):Math.Abs(A.Z-Z))/Math.Abs(A.Z-B.Z);
("ratio: " + ratio.ToString()).Dump();
float difX = ratio*Math.Abs(A.X-B.X);//this still needs to be added to or taken from the zero point offset
("difX: " + difX.ToString()).Dump();
float difY = ratio*Math.Abs(A.Y-B.Y);//this still needs to be added to or taken from the zero point offset
("difY: " + difY.ToString()).Dump();
float X = difX + (A.X<B.X?A.X:B.X);
("X: " + X).Dump();
float Y = difY + (A.Y<B.Y?A.Y:B.Y);
("Y: " + Y).Dump();
return new Vector3(X,Y,Z);
}
Does anyone know if there are any Math libraries that will already do this or examples that show how to do this that I can follow?
You have the starting (2.0f) and ending (6.0f) Z coordinates. The Z distance between the two points is 4.0f. You want to know the X and Y coordinates at the point where Z is 3.0f.
Remember that Z changes linearly along the segment. The segment is 4 units long, The point you're interested in is 1 unit from the start, or 1/4 of the length of the segment.
The X distance of the entire segment is 7.0 - 2.0, or 5 units. 1/4 of 5 is 1.25, so the X coordinate at the intersection is 3.25.
The Y distance of the entire segment is 8. 1/4 of 8 is 2. So the Y coordinate of the intersection point is 6.0.
The intersection point is (3.25f, 6.0f, 3.0f).
How to compute:
// start is the starting point
// end is the ending point
// target is the point you're looking for.
// It's pre-filled with the Z coordinate.
zDist = Math.Abs(end.z - start.z);
zDiff = Math.Abs(target.z - start.z);
ratio = zDiff / zDist;
xDist = Math.Abs(end.x - start.x);
xDiff = xDist * ratio;
xSign = (start.x < end.x) ? 1 : -1;
target.x = start.x + (xDiff * xSign);
yDist = Math.Abs(end.y - start.y);
yDiff = yDist * ratio;
ySign = (start.y < end.y) ? 1 : -1;
target.y = start.y + (yDiff * ySign);
Come to think of it, the whole sign thing shouldn't be necessary. Consider this, when end.x = 10 and start.x = 18:
xDist = end.x - start.x; // xDist = -8
xDiff = xDist * ratio; // xDiff = -2
target.x = start.x + xDiff; // target.x = 18 + (-2) = 16
Yeah, no need for sign silliness.
Also no need for the calls to Math.Abs when computing the ratio. We know that zDist and zDiff will both have the same sign, so ratio will always be positive.

Finding the intersect location of two Rays

I have two rays. Each ray has a start location vector (Vector3D) and a direction vector (Vector3D), but continue on to infinity. They are both on the same plane, but in a 3D environment. The Rays are interdependent, which means that they might not mirror each other perfectly. From this i need to calculate the location at which these rays intersect in the 3D environment and output it as a vector. In essence: a rangefinder.
How should i go about doing this? Is there a better way of doing it than using the C# Ray structure, is it even possible?
I am a pretty new coder (read: bad) but any answer is appreciated, I would enjoy it if an explanation was included.
Crude image of the rays
Two lines in 3D space only intersect if they are on the same plane. The probability that two random lines in space intersect is really small.
When you want to find out if two rays intersect, if you are looking for an exact intersection point, the chance is that you are not going to be able to calculate it due to floating point errors.
The next best thing is to find the shortest distance between two rays. Then if that distance is smaller than a certain threshold (defined by you) we could say the rays are intersecting.
Finding shortest distance
Here are two rays in 3D space, with the blue vector representing the shortest distance.
Let's take a frame from that gif:
Legend:
p1 is ray1.Position
p2 is ray2.Position
d1 is ray1.Direction
d2 is ray2.Direction
d3 is the cross product d1 x d2
The cross product of the rays directions will be perpendicular to both rays, so it's the shortest direction from ray to ray. If lines are parallel, the cross product will be zero, but for now lets only deal with non-parallel lines.
From the photo, we get the equation:
p1 + a*d1 + c*d3 = p2 + b*d2
Rearranged so the variables are on the left:
a*d1 - b*d2 + c*d3 = p2 - p1
Since each of the know values (d1, d2, d3, p1 and p2) has three components (x,y,z), this is a system of three linear equations with 3 variables.
a*d1.X - b*d2.X + c*d3.X = p2.X - p1.X
a*d1.Y - b*d2.Y + c*d3.Y = p2.Y - p1.Y
a*d1.Z - b*d2.Z + c*d3.Z = p2.Z - p1.Z
Using Gaussian elimination, we get the values of a, b and c.
If both a and b are positive, the position of the intersection will be
Vector3 position = ray1.Position + a*ray1.Direction;
Vector3 direction = c * d3; //direction.Length() is the distance
You could return these values as a Ray for convenience.
If either a or b are negative, this means that the calculated shortest distance would be behind one (or both) of the rays, so a different method should be used to find the shortest distance. This method is the same for lines that are parallel (cross product d1 x d2 is zero).
Now the calculation becomes finding which ray (positive direction) is closest to the position (p1 or p2) of the other ray. For this we use dot product (projection of a vector onto another vector)
Legend:
dP = p2 - p1
Before calculating dot product of d1 dot dP, make sure that d1 (or d2) are normalized (Vector3.Normalize()) - dot product is meant to work on unit vectors.
Now it's a matter of finding which is the shortest distance, based on the projection factor (result of dot) on ray1 (lets call it a2) and projection factor on ray2 (lets call it b2).
If both a2 and b2 are negative (negative side of the ray), then the shortest distance is from position to position. If one is in the negative direction then the other one is the shortest. Else it's the shorter of the two.
Working code:
public Ray FindShortestDistance(Ray ray1, Ray ray2)
{
if (ray1.Position == ray2.Position) // same position - that is the point of intersection
return new Ray(ray1.Position, Vector3.Zero);
var d3 = Vector3.Cross(ray1.Direction, ray2.Direction);
if (d3 != Vector3.Zero) // lines askew (non - parallel)
{
//d3 is a cross product of ray1.Direction (d1) and ray2.Direction(d2)
// that means d3 is perpendicular to both d1 and d2 (since it's not zero - we checked that)
//
//If we would look at our lines from the direction where they seem parallel
// (such projection must always exist for lines that are askew)
// we would see something like this
//
// p1 a*d1
// +----------->x------
// |
// | c*d3
// p2 b*d2 v
// +------->x----
//
//p1 and p2 are positions ray1.Position and ray2.Position - x marks the points of intersection.
// a, b and c are factors we multiply the direction vectors with (d1, d2, d3)
//
//From the illustration we can the shortest distance equation
// p1 + a*d1 + c*d3 = p2 + b*d2
//
//If we rearrange it so we have a b and c on the left:
// a*d1 - b*d2 + c*d3 = p2 - p1
//
//And since all of the know variables (d1, d2, d3, p2 and p1) have 3 coordinates (x,y,z)
// now we have a set of 3 linear equations with 3 variables.
//
// a * d1.X - b * d2.X + c * d3.X = p2.X - p1.X
// a * d1.Y - b * d2.Y + c * d3.Y = p2.Y - p1.Y
// a * d1.Z - b * d2.Z + c * d3.Z = p2.Z - p1.Z
//
//If we use matrices, it would be
// [d1.X -d2.X d3.X ] [ a ] [p2.X - p1.X]
// [d1.Y -d2.Y d3.Y ] * [ a ] = [p2.Y - p1.Y]
// [d1.Z -d2.Z d3.Z ] [ a ] [p2.Z - p1.Z]
//
//Or in short notation
//
// [d1.X -d2.X d3.X | p2.X - p1.X]
// [d1.Y -d2.Y d3.Y | p2.Y - p1.Y]
// [d1.Z -d2.Z d3.Z | p2.Z - p1.Z]
//
//After Gaussian elimination, the last column will contain values a b and c
float[] matrix = new float[12];
matrix[0] = ray1.Direction.X;
matrix[1] = -ray2.Direction.X;
matrix[2] = d3.X;
matrix[3] = ray2.Position.X - ray1.Position.X;
matrix[4] = ray1.Direction.Y;
matrix[5] = -ray2.Direction.Y;
matrix[6] = d3.Y;
matrix[7] = ray2.Position.Y - ray1.Position.Y;
matrix[8] = ray1.Direction.Z;
matrix[9] = -ray2.Direction.Z;
matrix[10] = d3.Z;
matrix[11] = ray2.Position.Z - ray1.Position.Z;
var result = Solve(matrix, 3, 4);
float a = result[3];
float b = result[7];
float c = result[11];
if (a >= 0 && b >= 0) // normal shortest distance (between positive parts of the ray)
{
Vector3 position = ray1.Position + a * ray1.Direction;
Vector3 direction = d3 * c;
return new Ray(position, direction);
}
//else will fall through below:
// the shortest distance was between a negative part of a ray (or both rays)
// this means the shortest distance is between one of the ray positions and another ray
// (or between the two positions)
}
//We're looking for the distance between a point and a ray, so we use dot products now
//Projecting the difference between positions (dP) onto the direction vectors will
// give us the position of the shortest distance ray.
//The magnitude of the shortest distance ray is the the difference between its
// position and the other rays position
ray1.Direction.Normalize(); //needed for dot product - it works with unit vectors
ray2.Direction.Normalize();
Vector3 dP = ray2.Position - ray1.Position;
//shortest distance ray position would be ray1.Position + a2 * ray1.Direction
// or ray2.Position + b2 * ray2.Direction (if b2 < a2)
// or just distance between points if both (a and b) < 0
//if either a or b (but not both) are negative, then the shortest is with the other one
float a2 = Vector3.Dot(ray1.Direction, dP);
float b2 = Vector3.Dot(ray2.Direction, -dP);
if (a2 < 0 && b2 < 0)
return new Ray(ray1.Position, dP);
Vector3 p3a = ray1.Position + a2 * ray1.Direction;
Vector3 d3a = ray2.Position - p3a;
Vector3 p3b = ray1.Position;
Vector3 d3b = ray2.Position + b2 * ray2.Direction - p3b;
if (b2 < 0)
return new Ray(p3a, d3a);
if (a2 < 0)
return new Ray(p3b, d3b);
if (d3a.Length() <= d3b.Length())
return new Ray(p3a, d3a);
return new Ray(p3b, d3b);
}
//Solves a set of linear equations using Gaussian elimination
float[] Solve(float[] matrix, int rows, int cols)
{
for (int i = 0; i < cols - 1; i++)
for (int j = i; j < rows; j++)
if (matrix[i + j * cols] != 0)
{
if (i != j)
for (int k = i; k < cols; k++)
{
float temp = matrix[k + j * cols];
matrix[k + j * cols] = matrix[k + i * cols];
matrix[k + i * cols] = temp;
}
j = i;
for (int v = 0; v < rows; v++)
if (v == j)
continue;
else
{
float factor = matrix[i + v * cols] / matrix[i + j * cols];
matrix[i + v * cols] = 0;
for (int u = i + 1; u < cols; u++)
{
matrix[u + v * cols] -= factor * matrix[u + j * cols];
matrix[u + j * cols] /= matrix[i + j * cols];
}
matrix[i + j * cols] = 1;
}
break;
}
return matrix;
}
It is so simple. you need to apply AAS Triangle formula.
Consider the above figure as triangle,
Ray1 location as A and Ray2 Location as B and you need to find point c. Using dot product find angle between Ray AB and AC (alpha), BA and BC (theta).
Find the distance between location A and B (D). So finally you have alpha, beta and D, i.e (2 angles and 1 side of the triangle.) Apply AAS method and find C location.
https://www.mathsisfun.com/algebra/trig-solving-aas-triangles.html.

Shorten a line by a number of pixels

I'm drawing a custom diagram of business objects using .NET GDI+. Among other things, the diagram consists of several lines that are connecting the objects.
In a particular scenario, I need to shorten a line by a specific number of pixels, let's say 10 pixels, i.e. find the point on the line that lies 10 pixels before the end point of the line.
Imagine a circle with radius r = 10 pixels, and a line with start point (x1, y1) and end point (x2, y2). The circle is centered at the end point of the line, as in the following illustration.
How do I calculate the point marked with a red circle, i.e. the intersection between circle and line? This would give me the new end point of the line, shortening it by 10 pixels.
Solution
Thank you for your answers from which I was able to put together the following procedure. I named it LengthenLine, since I find it more natural to pass a negative number of pixels if I want the line shortened.
Specifically, I was trying to put together a function that could draw a line with rounded corners, which can be found here.
public void LengthenLine(PointF startPoint, ref PointF endPoint, float pixelCount)
{
if (startPoint.Equals(endPoint))
return; // not a line
double dx = endPoint.X - startPoint.X;
double dy = endPoint.Y - startPoint.Y;
if (dx == 0)
{
// vertical line:
if (endPoint.Y < startPoint.Y)
endPoint.Y -= pixelCount;
else
endPoint.Y += pixelCount;
}
else if (dy == 0)
{
// horizontal line:
if (endPoint.X < startPoint.X)
endPoint.X -= pixelCount;
else
endPoint.X += pixelCount;
}
else
{
// non-horizontal, non-vertical line:
double length = Math.Sqrt(dx * dx + dy * dy);
double scale = (length + pixelCount) / length;
dx *= scale;
dy *= scale;
endPoint.X = startPoint.X + Convert.ToSingle(dx);
endPoint.Y = startPoint.Y + Convert.ToSingle(dy);
}
}
Find the direction vector, i.e. let the position vectors be (using floats) B = (x2, y2) and A = (x1, y1), then AB = B - A. Normalize that vector by dividing by its length ( Math.Sqrt(xx + yy) ). Then multiply the direction vector AB by the original length minus the circle's radius, and add back to the lines starting position:
double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.Sqrt(dx * dx + dy * dy);
if (length > 0)
{
dx /= length;
dy /= length;
}
dx *= length - radius;
dy *= length - radius;
int x3 = (int)(x1 + dx);
int y3 = (int)(y1 + dy);
Edit: Fixed the code, aaand fixed the initial explanation (thought you wanted the line to go out from the circle's center to its perimeter :P)
I'm not sure why you even had to introduce the circle. For a line stretching from (x2,y2) to (x1,y1), you can calculate any point on that line as:
(x2+p*(x1-x2),y2+p*(y1-y2))
where p is the percentage along the line you wish to go.
To calculate the percentage, you just need:
p = r/L
So in your case, (x3,y3) can be calculated as:
(x2+(10/L)*(x1-x2),y2+(10/L)*(y1-y2))
For example, if you have the two points (x2=1,y2=5) and (x1=-6,y1=22), they have a length of sqrt(72 + 172 or 18.38477631 and 10 divided by that is 0.543928293. Putting all those figures into the equation above:
(x2 + (10/l) * (x1-x2) , y2 + (10/l) * (y1-y2))
= (1 + 0.543928293 * (-6- 1) , 5 + 0.543928293 * (22- 5))
= (1 + 0.543928293 * -7 , 5 + 0.543928293 * 17 )
= (x3=-2.807498053,y3=14.24678098)
The distance between (x3,y3) and (x1,y1) is sqrt(3.1925019472 + 7.7532190152) or 8.384776311, a difference of 10 to within one part in a thousand million, and that's only because of rounding errors on my calculator.
You can use similar triangles. For the main triangle, d is the hypotenuses and the extension of r is the vertical line that meets the right angle. Inside the circle you will have a smaller triangle with a hypotenuses of length r.
r/d = (x2-a0)/(x2-x1) = (y2-b0)/(y2-y1)
a0 = x2 + (x2-x1)r/d
b0 = y2 + (y2-y1)r/d

Categories

Resources