Vector Math. Clamp point to within x,y of spline? - vector

could you please help me with this vector math problem?
I have a game actor Camera_Rail that has one spline. Every point on the spline has an Up vector and Right vector, creating a perpendicular plane. Together, the spline and X,Y bounds describe a boxy noodle in space.
I would like a function: ClampPointWithinBounds(Spline, X, Y, ProposedPoint) returns ClampedPoint
This is my plan, but there are some ??? :
Finds the closest SplinePoint to ProposedPoint (done)
Converts ProposedPoint to ProposedPoint2D with SplinePoint at 0,0 (???)
Clamps ProposedPoint2d to X,Y bounds (done)
Convert ClampedPoint2d to ClampedPoint in 3d and return. (???)
Alternatively, I could compute a ClampingVector directly in 3d space, but I don't have a plan for that.
How can I convert from 3d<->2d and back, and is there a better way? I'm using UE4.
Thank you!

"Finds the closest SplinePoint to ProposedPoint (done)."
We will call these Vector3's SP and PP respectively.
A circular/spherical bounds of radius R is easiest:
P = (SP - PP).Normalize() * R; or expanded:
L = Sqrt((SP.X - PP.X) * (SP.X - PP.X) + (SP.Y - PP.Y) * (SP.Y - PP.Y) + (SP.Z - PP.Z) * (SP.Z - PP.Z));
P = ((SP.X - PP.X)/L,(SP.Y - PP.Y)/L,(SP.Z - PP.Z)/L) * R;
For clamped bounds having extents, 1/2 of box size, of (X1,Y1,Z1), use R = X1 * X1 + Y1 * Y1 + Z1 * Z1, the furthest distance possible.
The final clamped result = (Min(Abs(P.X),X1) * Sign(P.X), Min(Abs(P.Y),Y1) * Sign(P.Y), A.Z = Min(Abs(P.Z),Z1) * Sign(P.Z))
For 2D, I would consider using Trig functions:
P = (SP - PP);// ignoring Z
Ang = ATan2(P.Y, P.X);
X = X1 * Cos(Ang);
Y = Y1 * Sin(Ang);
The overhead of the trig functions is not worth extending into 3D. As a single Sqrt() call is usually quicker than the multiple trig calls required in 3D.

Related

How do I generate a random point on a circles circumference in 3D space? [migrated]

This question was migrated from Stack Overflow because it can be answered on Mathematics Stack Exchange.
Migrated 24 days ago.
I have a position vector and a normal vector that describes a plane. The plane is always orthogonal to the position vector. On this plane is a circle with its center at the position vector. How do I generate a random point on that circle with a given radius r? I know that in 2d space, I can do
x = cos(2 * PI * random) * radius
y = sin(2 * PI * random) * radius
but... I don't know how to translate that to a circle on a plane.
I tried to find a way to use the position vector and normal vector to generate points, but I just can't think of a correct way to do so. I might not be familiar enough with planes.
At first we need two base vectors in the circle plane.
The first one is arbitrary vector orthogonal to normal n:
Choose component of normal with the largest magnitude, then component with the second magnitude.
Exchange their values, negate the largest, and make the third component zero (note that dot product of result with normal is zero, so they are othogonal)
For example, if n.y is the largest and n.z is the second, make
v = (0, n.z, -n.y)
Then calculate the second base vector using vector product
u = n x v
Normalize vectors v and u (make unit magnitude).
Now we can generate a random point on circumference using center point c (your position, I think):
rho = 2 * PI * random
f.x = c.x + radius * v.x * cos(rho) + radius * u.x * sin(rho)
f.y = c.y + radius * v.y * cos(rho) + radius * u.y * sin(rho)
f.z = c.z + radius * v.z * cos(rho) + radius * u.z * sin(rho)

How to determine if a 3D line segment intersects a side of a 3D rectangular prism?

I am trying to find a way to determine if a line segment drawn between two points in 3D space will intersect another 3D body (rectangular prism) that is defined by regions using (x, y, z) vertices.
Is there a way to do this in Matlab?
Make equations for box faces. In the case of axis-aligned box they are simple like
for facet1 perpendicular to OX axis:
x - x1 = 0
y1 <= y <= y2
z1 >= z <= z2
At first check that segment ends don't lie at the same side of all facets, substituting their coordinates in plane equations. If signs of result for both segment ends are similar, segment does not intersect this plane. If all 6 planes are excluded, there in no intersection, but check if both ends lie inside the box (if this case is considered as intersection)
Now work with faces that provide distinct signs.
Make parametric representation of line segment
x(t) = p0.x + (p1.x - p0.x) * t
y(t) = p0.y + (p1.y - p0.y) * t
z(t) = p0.z + (p1.z - p0.z) * t
and substitute coordinates in plane equations like this:
(p0.x + (p1.x - p0.x) * t) - x1 = 0
Get t parameter. If it's in range 0..1, continue: put t value in
y = p0.y + (p1.y - p0.y) * t
and check that result is in range y1..y2, similar for z. If yes - segment does intersect facet1, otherwise continue with other facets.
Perhaps there are geometric libraries in Matlab providing some 3D line-clipping algorithm, in this case just use them.

Given 2 vector and 2 angle how to find the 3rd vector

It seems to be a very easy question but I just can't figure it out ...
as shown on the below graph:
Supposing we know :
Vector (X,Y)
Vector (X1,Y1)
Angle a
How can I get the vector (?,?) in Unity ?
Many Thanks in advance.
Subtract X1,Y1 from all coordinates.
XX = X - X1
YY = Y - Y1
Let (DX, DY) is vector between (XX, YY) and unknown point.
This vector is perpendicular to (XX, YY), so scalar product is zero.
And length of this vector is equal to length of (XX, YY) multiplied by tangent of angle.
So equation system is
DX * XX + DY * YY = 0
DX^2 + DY^2 = (XX^2 + YY^2) * Tan^2(Alpha)
Solve this system for unknowns (DX, DY) (there are two solutions in general case), then calculate unknown coordinates as (X + DX, Y + DY)
Not totally sure if there is a more efficient method to do this, but it will work.
First you need to find the magnitude of the distance vector between X,Y and X1,Y1. We will call this Dist1.
Dist1 = Vector2.Distance(new Vector2(X,Y), new Vector2(X1,Y1));
Using this distance, we can find the magnitude of the vector for the line going to X?,Y? which we will call DistQ.
DistQ = Dist1 / Mathf.Cos(a * Mathf.Deg2Rad);
You now need to find the angle of this line relative to the overall coordinate plane which will create a new triangle with X?Y? and the x-axis.
angle = Mathf.Atan2((Y - Y1), (X - X1)) * Mathf.Rad2Deg - a;
Now we can use more trig with the DistQ hypotenuse and this new angle to find the X?(XF) and Y?(YF) components relative to X1 and Y1, which we will add on to get the final vector components.
XF = DistQ * Mathf.Cos(angle * Mathf.Deg2Rad) + X1;
YF = DistQ * Mathf.Sin(angle * Mathf.Deg2Rad) + Y1;

Compute 3D vertex at end of vector of known length

I'm trying to project a vector from said vertex to unknown vertex at the end of
that vector.
The knowns: Length of vector, starting vertex coordinates, angles (yaw,roll,pitch).
Unknowns: Terminating vertex coordinates at end of vector.
In 2D I can accomplish it in this manner:
Target.X = Source.X + (sin(Facing*DEG2RAD)*Distance);
Target.Y = Source.Y - (cos(Facing*DEG2RAD)*Distance);
Matrices seem to be overkill. I have something working feebly for 3D, but it's inaccurate which makes me believe I do not have all of the appropriate elements of the overall formula.
Target.Z = Source.Z - (sin(Pitch*DEG2RAD)*Distance);
Ref: Facing/Pitch are in degrees (multiplied by DEG2RAD which is pi/180).
Any/all help is appreciated. Thanks.
You have to correct the x and y coordinates (project them back onto the x/y plane):
Target.X = Source.X + Distance * cos(Pitch * DEG2RAD) * sin(Facing * DEG2RAD);
Target.Y = Source.Y - Distance * cos(Pitch * DEG2RAD) * cos(Facing * DEG2RAD);
Target.Z = Source.Z - Distance * sin(Pitch * DEG2RAD);

Generating random point in a cylinder

What is best way or an algorithm for generating a random 3d point [x,y,z] inside the volume of the circular cylinder if radius r and height h of the cylinder are given?
How about -- in Python pseudocode, letting R be the radius and H be the height:
s = random.uniform(0, 1)
theta = random.uniform(0, 2*pi)
z = random.uniform(0, H)
r = sqrt(s)*R
x = r * cos(theta)
y = r * sin(theta)
z = z # .. for symmetry :-)
The problem with simply taking x = r * cos(angle) and y = r * sin(angle) is that then when r is small, i.e. at the centre of the circle, a tiny change in r doesn't change the x and y positions very much. IOW, it leads to a nonuniform distribution in Cartesian coordinates, and the points get concentrated toward the centre of the circle. Taking the square root corrects this, at least if I've done my arithmetic correctly.
[Ah, it looks like the sqrt was right.]
(Note that I assumed without thinking about it that the cylinder is aligned with the z-axis and the cylinder centre is located at (0,0,H/2). It'd be less arbitrary to set (0,0,0) at the cylinder centre, in which case z should be chosen to be between -H/2 and H/2, not 0,H.)
Generate a random point inside the rectangular solid circumscribing the cylinder; if it's inside the cylinder (probability pi/4), keep it, otherwise discard it and try again.
Generate a random angle (optionally less than 2π), a random r less than the radius, and a random z less than the height.
x = r * cos(angle)
y = r * sin(angle)
The z axis is easy: -0.5 * h <= z <= 0.5 * h
The x and y are equal to a circle will be:
x^2 + y^2 <= r^2
Buth math is long ago for me :-)

Resources