Why project 3d to 2d out of image plane while the point lies on the image - perspectivecamera

I am trying to get the 2D coordinate on image plane given the 3D world coordinate in Unreal engine 4.
The world coordinate system is x(increase from right to left), y(increase from outside to inside screen), z(increase from bottom to top)
The image coordinate system I want is origin on bottom left and x(increase from left to right), y(increase from bottom to top)
I set up my camera intrinsic and extrinsic as below while the camera is located on
(-474.9739990234375, -67.140998840332031, 128.10400390625)
and its rotation is
(0, 0.80071002244949341, 99.797645568847656)
related to the origin of world coordinate.
import numpy as np
fov = 69.4
width = 1920.0
height = 1080.0
aspect_ratio = width / height
fx = width / (2 * np.tan(fov * np.pi / 2 / 180))
fy = height / (2 * np.tan(fov / aspect_ratio / 2 / 180 * np.pi))
intrinsic = [[-fx, 0, width / 2], [0, fy, height / 2], [0 , 0, 1]]
pitch = 0.80071002244949341 * np.pi / 180
yaw = 99.797645568847656 * np.pi / 180
roll = 0 * np.pi / 180
ry = [[np.cos(pitch), 0, np.sin(pitch)], [0, 1, 0], [-np.sin(pitch), 0, np.cos(pitch)]]
rx = [[1, 0, 0], [0, np.cos(roll), -np.sin(roll)], [0, np.sin(roll), np.cos(roll)]]
rz = [[np.cos(yaw), -np.sin(yaw), 0], [np.sin(yaw), np.cos(yaw), 0], [0, 0, 1]]
rotation_matrix = np.matmul(np.matmul(rx, ry), rz)
translation_matrix = np.array([[-474.9739990234375, -67.140998840332031, 128.10400390625]])
extrinsic = np.concatenate([rotation_matrix, translation_matrix.T], axis=1)
extrinsic = np.concatenate([extrinsic, np.array([[0, 0, 0, 1]])], axis=0)
extrinsic = np.linalg.inv(extrinsic)
extrinsic = extrinsic[:3]
print(extrinsic)
Let's say I have an object in the scene which are also in the camera view.
Its coordinate is
[-582.88897705078125, 143.63600158691406, 88.338996887207031]
Using the code below I should get the projection of the 3D point on image plane.
world_coordinate = np.array([[-582.88897705078125, 143.63600158691406, 88.338996887207031, 1]])
camera_coordinate = np.dot(extrinsic, world_coordinate.T)
print(camera_coordinate)
camera_coordinate[0] *= 1
tmp = camera_coordinate[1].copy()
camera_coordinate[1] = camera_coordinate[2]
camera_coordinate[2] = tmp
print(camera_coordinate)
image_coordinate = np.dot(intrinsic, camera_coordinate)
image_coordinate /= image_coordinate[2]
print(image_coordinate)
But I got
[[-3.52097326e+03]
[-3.59180874e+02]
[ 1.00000000e+00]]
Which does not lie on image plane. How do I solve this?

Turns out it was a mistake. The actual world coordinate system is x(increase from outside to inside screen), y(increase from left to right), z(increase from bottom to top).
Just map the project the yz plane to image space then it'll be done.

Related

draw arc using start, end and initial direction

I am trying to draw a railway in the way it is implemented in railroad tycoon 3. I have understood some of the patterns by which this is done, but I cannot find a formula for their application. I am trying to build an arc using only two points and some initial direction. For simplicity, let's assume that I can only plot a path in the range from 0 to 90 degrees. The arc should always start in the direction of "Initial direction". I need a method that would implement this. I tried to depict the idea in the drawings. Any pseudocode would do I guess.
general idea
borderline case at alpha = 0
borderline case at alpha = 90 degrees
Center C lies at middle perpendicular to SE segment, so we should find vectors
se = (E.x - S.x, E.y - S.y)
perp = (-se.y, se.x) = (S.y - E.y, E.x - S.x) //MC direction
and middle point
M = ((E.x + S.x)/2, (E.y - S.y)/2)
and express C coordinates using parametric equation
C = M + perp*t
Note that initial arc direction d is perpendicular to radius CS, so their dot product is zero:
(C - S).dot.d = 0
(M.x + perp.x * t - S.x)*d.x + (M.y + perp.y * t - S.y)*d.y = 0
This is linear equation for unknown parameter t, after solving it we know center C and can build the arc.
Python code. Perhaps examples are too simple to reveal bugs, but the first with half-circle gives R=L/2, center at M, and the second one shows correct C position and R.
from math import hypot, atan2
def arcfromptsdir(sx, sy, ex, ey, dx, dy):
sex = ex - sx
sey = ey - sy
perpx = -sey
perpy = sex
mx = (ex + sx) / 2
my = (ey + sy) / 2
#equation
#(sex/2 + perpx * t )*dx + (sey/2 + perp.y * t )*dy = 0
p = perpx * dx + perpy * dy
if p:
t = -0.5*(sex*dx + sey*dx) / p
else:
return None
#centerx, centery, radius
cx = mx + perpx * t
cy = my + perpy * t
radius = hypot(cx-sx, cy-sy)
arcangle = atan2((sx-cx) * (ey-cy) - (sy-cy) * (ex-cx),
(sx-cx) * (ex-cx) + (sy-cy) * (ey-cy))
return (cx, cy, radius, arcangle)
print(arcfromptsdir(0, 0, 2, 0, 0, 1))
print(arcfromptsdir(0, 0, 2, 0, 0.7071, 0.7071))
(1.0, 0.0, 1.0, -3.141592653589793)
(1.0, -1.0, 1.4142135623730951, -1.5707963267948966)

Find a point on perpendicular of a line

I have a side of a irregular polygon (x1,y1) (x2,y2) at a angle A and the midpoint of the side (mx, my).
I need to find two points (x3,y3) and (x4,y4) on a perpendicular from A passing through (mx, my), with some offset. So that I could check which point is the inside/outside of the polygon.
I'll use the outside one to show the measurement text of the side of the polygon, e.g 2cms
Click to see Visuals
You dont specify the language, but in almost all of them we have atan2 function for that.
canvas.width = window.innerWidth - 10;
canvas.height = window.innerHeight - 10;
const ctx = canvas.getContext('2d');
const line = [canvas.width/2, canvas.height/2, 10, 10];
const pLen = 100; // Length of perpendicular
function drawOrto(line) {
// line vector
const dx = line[2] - line[0];
const dy = line[3] - line[1];
// center point
const mx = line[0] + dx / 2;
const my = line[1] + dy / 2;
const atan = Math.atan2(dy, dx);
// perpendicular vector
const pdx = - pLen * Math.sin(atan);
const pdy = pLen * Math.cos(atan);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Line
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.moveTo(line[0], line[1]);
ctx.lineTo(line[2], line[3]);
ctx.stroke();
// Perpendicular (draw vector both sides from center)
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.moveTo(mx - pdx / 2, my - pdy / 2);
ctx.lineTo(mx + pdx / 2, my + pdy / 2);
ctx.stroke();
// Dots
ctx.fillStyle = 'red';
ctx.fillRect(line[0] - 1, line[1] - 1, 3, 3);
ctx.fillRect(line[2] - 1, line[3] - 1, 3, 3);
ctx.fillStyle = 'yellow';
ctx.fillRect(mx - 1, my - 1, 3, 3);
ctx.fillStyle = 'green';
ctx.fillRect(mx - pdx / 2 - 1, my - pdy / 2 - 1, 3, 3);
ctx.fillRect(mx + pdx / 2 - 1, my + pdy / 2 - 1, 3, 3);
}
drawOrto(line);
canvas.onmousemove = e => {
line[2] = e.offsetX;
line[3] = e.offsetY;
drawOrto(line);
}
<canvas id=canvas></canvas>
Rotation by a quarter-turn is easy: if you have a vector with coordinates (x, y) and rotate it by a quarter-turn anti-clockwise, the coordinates of the new vector are (-y, x).
To find a point (x5,y5) on the perpendicular, you can rotate point (x2,y2) by a quarter-turn anti-clockwise centered on (mx,my), so that:
x5 - mx = - (y2 - my)
y5 - my = x2 - mx
Then you can choose your two points (x3, y3) and (x4, y4) by renormalizing vector (x5-mx, y5-my) to have the length you want:
x4 - mx = (x5 - mx) * (2 cm) / ((x5-mx)**2 + (y5-my)**2)
y4 - my = (y5 - my) * (2 cm) / ((x5-mx)**2 + (y5-my)**2)
x3 - mx = (x5 - mx) * (-2 cm) / ((x5-mx)**2 + (y5-my)**2)
y3 - my = (y5 - my) * (-2 cm) / ((x5-mx)**2 + (y5-my)**2)
First you have to find the side equation:
y - y1 = (y2-y1)/(x2-x1)*(x-x1)
y = (y2-y1)/(x2-x1) * x1 - (y2-y1)/(x2-x1) * x + y1
Once you have an equation like this y=mx+q (y and x are costants, so you only care about finding m and q) you can find the middle point
M((x1+x2)/2), (y1+y2)/2)
When you have both the equation and the middle point you can choose your offset. Now just find the points that correspond to that offset on the segment
P1(mx + offset, my + (offset * m)) and P2(mx - offset, my - (offset * m))
where m is the one you found in the first equation
Now you have the 2 points
To find out which is inside and which is outside we would need to have more data. You could try for example to bisect the angles to find the middle point of the polygon M1 and check which between P1 and P2 has a distance to M1 so that:
if distance(P1, M1) < distance(M, M1) then P1 is inside
"if the distance between the point and the middle of the polygon is less than the distance between the middle of the polygon and the middle of the side then P1 is inside the polygon"
There are other solutions, but with the data available this is all i can do. Now you just have to turn this explanation into code
LEGEND:
y -> equation constant
x -> equation constant
m -> line inclination
q -> intersection with axis (you really don't need it for this)
M -> middle point of the side mx, my -> coordinates of middle point of the side
P1 -> point on the line with positive offset
P2 -> point on the line with negative offset
M1 -> middle point of the polygon

get coordinates of arrow of a line point

Consider I have 2 points.
QPoint(100,100)
QPoint(200,200)
Now, I need to draw a pointed arrow at the end of line QPoint(200,200).
How can I get the points of the arrow coordinates since the line is in inclined angle? The arrow should be like given below.
As this is more a general question, Im tagging on pyqt5 and css.
You need to calculate the slope of your line, which will let you find a point on the line a given distance from your endpoint. You can then build a a new line perpendicular to the original line that goes through the point. The ends of the arrows should lie on that line a given distance from the original. It's easier to show than explain:
function draw(point1, point2, distance, length) {
// slope is dx/dy
let dx = point2[0] - point1[0]
let dy = point2[1] - point1[1]
let v_norm = Math.sqrt(dx ** 2 + dy ** 2)
// point on line at distance
let point_on_line = [point2[0] - distance * dx / v_norm, point2[1] - distance * dy / v_norm]
// endpoints of arrows at length above point (the distance from the original line
let point_below = [point_on_line[0] - length * -dy / v_norm, point_on_line[1] - length * dx / v_norm, ]
let point_above = [point_on_line[0] + length * -dy / v_norm, point_on_line[1] + length * dx / v_norm, ]
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(...point1);
ctx.lineTo(...point2);
ctx.moveTo(...point_above)
ctx.lineTo(...point2)
ctx.lineTo(...point_below)
ctx.stroke();
}
draw([100, 100], [200, 150], 20, 10)
draw([100, 100], [300, 150], 20, 10)
draw([100, 100], [150, 10], 20, 10)
draw([100, 100], [90, 150], 20, 10)
draw([100, 100], [200, 100], 20, 10)
draw([100, 100], [5, 10], 20, 10)
<canvas id="canvas" width='500' height='500'></canvas>
You can alter the shape of the arrows using distance and length
If we have a look at the points we need (U and D needed, S and E given):
U
/|
/ |
S---------------------E
\ |
\|
D
We actually have to go back from S to E, then we turn by 90 degrees and walk up the same length. If we take the direction between S and E (represented as Vectors):
d = E - S
Then we can get the distance to walk back:
b = -d / 4
And then to walk up in a 90 degree angle, we just swap x and y, to go down we just take the negative one:
u = [b.y, b.x]
d = -u
So we can finally get our points as:
U = S + b + u
D = S + b + d
(The code above is pseudocode as you wanted a general solution)

Find corners of a rotated rectangle given its center point and rotation

Can someone give me an algorithm that finds the position of all four corners of a rectangle if I know its center point(in global coordinate space), width and height, and its rotation around that center point?
clarification edit:
The width and height I am referring to is the length of the sides of the rectangle.
Top right corner has coordinates w/2, h/2 relative to the center. After rotation its absolute coordinates are
x = cx + w/2 * Cos(Phi) - h/2 * Sin(Phi)
y = cy + w/2 * Sin(Phi) + h/2 * Cos(Phi)
The coordinates of each vertices:
Center point = (center.x, center.y)
Angle = angle
Height = height
Width = width
TOP RIGHT VERTEX:
Top_Right.x = center.x + ((width / 2) * cos(angle)) - ((height / 2) * sin(angle))
Top_Right.y = center.y + ((width / 2) * sin(angle)) + ((height / 2) * cos(angle))
TOP LEFT VERTEX:
Top_Left.x = center.x - ((width / 2) * cos(angle)) - ((height / 2) * sin(angle))
Top_Left.y = center.y - ((width / 2) * sin(angle)) + ((height / 2) * cos(angle))
BOTTOM LEFT VERTEX:
Bot_Left.x = center.x - ((width / 2) * cos(angle)) + ((height / 2) * sin(angle))
Bot_Left.y = center.y - ((width / 2) * sin(angle)) - ((height / 2) * cos(angle))
BOTTOM RIGHT VERTEX:
Bot_Right.x = center.x + ((width / 2) * cos(angle)) + ((height / 2) * sin(angle))
Bot_Right.y = center.y + ((width / 2) * sin(angle)) - ((height / 2) * cos(angle))
This algorithm is a compressed version of these 3 steps:
Step 1: Center your rectangle around the origin
Step 2: Apply the rotation matrix to each vertex
Step 3: Move the rotated rectangle to the correct position, by adding the center point to each coordinate
This is explained in more depth here https://math.stackexchange.com/questions/126967/rotating-a-rectangle-via-a-rotation-matrix
If you need all of the corners, it just might be faster to create two perpendicular vectors from the center of the rectangle to both of its sides, and then to add/subtract these vectors to/from the center of the rectangle to form the points.
This might be faster, since you don't need to repeatedly call sin() and cos() functions (you do so only once for each).
Assuming we have a Vector library (for cleaner code - only helps with vector arithmetic), here is the code in Python:
def get_corners_from_rectangle(center: Vector, angle: float, dimensions: Vector):
# create the (normalized) perpendicular vectors
v1 = Vector(cos(angle), sin(angle))
v2 = Vector(-v1[1], v1[0]) # rotate by 90
# scale them appropriately by the dimensions
v1 *= dimensions[0] / 2
v2 *= dimensions[1] / 2
# return the corners by moving the center of the rectangle by the vectors
return [
center + v1 + v2,
center - v1 + v2,
center - v1 - v2,
center + v1 - v2,
]
Code Python with matrices :
import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle
#center of rectangle
X = 2698.77
Y = 1283.01
center = np.array([[X],[Y]])
angle_deg = 83.5694 #angle rectangle
angle = math.radians(angle_deg)
# rectangle's dimension
width = 2022.23
height = 1978.78
R_lt = np.array([[np.cos(angle),-np.sin(angle)],[-np.sin(angle),-np.cos(angle)]])
A = np.dot(R_lt,np.array([[width/2], [height/2]])) + center
R_rt = np.array([[np.cos(angle),np.sin(angle)],[-np.sin(angle),np.cos(angle)]])
B = np.dot(R_rt,np.array([[width/2], [height/2]])) + center
R_rb = np.array([[-np.cos(angle),np.sin(angle)],[np.sin(angle),np.cos(angle)]])
C = np.dot(R_rb,np.array([[width/2], [height/2]])) + center
R_lb = np.array([[-np.cos(angle),-np.sin(angle)],[np.sin(angle),-np.cos(angle)]])
D = np.dot(R_lb,np.array([[width/2], [height/2]])) + center
corners = [A,B,C,D]

Given an angle in degrees, how can I find the logic for line of travel using x and y? (Math dilemma)

I am making a simple game in HTML5 canvas, it involves driving a little car.
The up arrow moves the car, the left and right arrow steers it.
I have rotation sorted, but now it needs to move its x and y position when holding the up key, based on what angle it is at.
Example:
Angle is 0, the up arrow will only affect the y coordinate.
Angle is 45, the up arrow will affect both x and y coordinates at an equal pace.
What logic can I use if the angle is say, 32?
You could try something like this
velY = Math.cos(angle * Math.PI / 180) * thrust;
velX = Math.sin(angle * Math.PI / 180) * thrust;
x += velX;
y -= velY;
Quick example, angle is just incremented every loop.
http://jsfiddle.net/j5U5h/5/
Angle 0 is up like you have in your initial question.
Here is the jsfiddle modified so the angle of 0 moves you to the right.
http://jsfiddle.net/j5U5h/7/
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x += velX;
y += velY;
To make 0 go to the right initially just change to this,
velX = -Math.cos(angle * Math.PI / 180) * thrust;
Did you really mean that 90 moves both axes equally? It seems to me that it should be 45 moves both axes equally.
if 45 moves both axes equally:
xfactor = angle * (1/90)
yfactor = (90 - angle) * (1/90)
xpos = xpos + (xincrement * xfactor)
ypos = ypos + (yincrement * yfactor)
if 90 moves both axes equally:
xfactor = (2 * angle) * (1/180)
yfactor = (180 - (2 * angle)) * (1/180)
xpos = xpos + (xincrement * xfactor)
ypos = ypos + (yincrement * yfactor)

Resources