Subtract distance from set of coordinates (x1, y1, x2, y2) - math

I need to "subtract" from the distance a line has and doing so maintaining the same direction it initially had.
Note: If we try to simply subtract a given value (example 10) the direction will change.
I guess it's a mathematical problem?
I need to be able to change coordinates to cause the distance to shorten by percentage. Be it from the initial position (x1, y1) or from the end position (x2, y2) all the while keeping the line in the same direction.
Note: See attached image for illustration.
// Gray line (100% distance)
<line x1="x1" y1="y1" x2="x2" y2="y2" />
// Purple line (90% distance)
<line
x1="x1"
y1="y1"
x2="subtractByPercentage(x2, '10%')"
y2="subtractByPercentage(y2, '10%')"
/>
Full distance vs percentage
I tried subtracting a given value e.g. 10, or a percentage of x and y value, but that would always change the direction of line.

Any point along the line has coordinates given by the parametric equations
X = X0 + t.(X1 - X0)
Y = Y0 + t.(X1 - X0)
where t varies from 0 to 1 along the segment. The distance travelled from P0 is just t.|P0P1| = t.√((X1 - X0)² + (Y1 - Y0)²). So if you want to adjust the length, set the value of t to the desired percentage.

The math that you are looking for is:
<line
x1="x1"
y1="y1"
x2="x1 + (x2 - x1) * .9"
y2="y1 + (y2 - y1) * .9">

Related

How to check if an infinite line intersects a rectangular prism in 3d space?

If I have a line segment defined by two points p1, p2, and then a rectangular prism defined by (x,y,z) (lowest corner point) with length/width/height (l, w, h), how can I check if the line will intersect the prism? And also get the point of intersection if there is one?
Does anyone know?
Thanks
Seems that your prism is axis-aligned box (rectangular parallelepiped).
So use any algorithm intended for line clipping - for example, 3D-version of Liang-Barsky algorithm
In short - make parametric equation for line segment
X = X1 + t * (X2 - X1)
Y = Y1 + t * (Y2 - Y1)
Z = Z1 + t * (Z2 - Z1)
find parameters t for intersection with faces: substitute X = x or X = x + l in equation, find t, check if point with this t lies inside face rectangle

Testing Axis Aligned Boxes (AAB) in frustum intersection

I read this tutorial for aabb-plane test, and I'm having trouble understanding the "optimized" aabb-plane test described.
Under "Geometric Approach - Testing Boxes II", I understand everything until this line:
Assume a AAB that has its components x,y,and z varying between xmin
and xmax; ymin and ymax; and zmin and zmax. The components of the
positive vertex p are selected as follows: ...
I also don't get the code that comes afterwards.
My AABB objects are defined by their minVertex, maxVertex parameters.
Can you explain me what did the author mean?
Consider the following picture where the diagonal PS is (supposedly) parallel to the normal vector (BTW, this is what the tutorial calls the AAB case). This picture represents the 2D version of the problem where the idea is easier to explain and understand.
The p-vertex is, by definition, the one that is further aligned with the direction of the normal. This means that you have to decide which one of the following four vectors is further aligned with the normal:
R - Q, Q - R, P - S or S - P (1)
In this case the answer is S - P, which means that S is the p-vertex and P the n-vertex. But the problem is how to detect this programmatically.
Well, the dot product between two vectors measures the projection of one of them onto the other, so the problem can be restated as: which of the vectors in (1) has the maximum dot product with the normal (xn, yn)?
Here are the four dot products:
(xn, yn).(R - Q) = xn(x1 - x2) + yn(y1 - y2)
(xn, yn).(Q - R) = xn(x2 - x1) + yn(y2 - y1)
(xn, yn).(P - S) = xn(x1 - x2) + yn(y2 - y1)
(xn, yn).(S - P) = xn(x2 - x1) + yn(y1 - y2)
So, the one we are looking for is the one that makes both terms of the sum positive, this is
if xn > 0 select x2 - x1 (>0) otherwise x1 - x2 (<0)
if yn > 0 select y2 - y1 (>0) otherwise y1 - y2 (<0)
The reason being the rule of signs (+ times + = + and - times - = +.)
All of this translates into
start with p-vertex = (x1, y1)
if xn > 0, change x1 with x2 (effectively leaving p-vertex = (x2, y1))
if yn > 0, change y1 with y2 (effectively leaving p-vertex = (x*, y2))
(In step 3, x* is x1 or x2 depending on the result of setp 2)
These arguments remain valid if you are in 3 dimensions. The only difference is that you have to add z coordinates everywhere.

In 3D space, how do I calculate a point at a certain height, that is linear with 2 other known points?

background
I am working on a 3d game, where I need to transfer my mouse-input to a certain height in the 3d world, so I can move a unit across a surface.
This is done from the perspective of a tilted camera (45 degress tilted). the playcanvas API supplies me with a function on my camera, which can translate my mouse input on the 2d screen, into the 3d world using a set depth.
when I set my depth to 0, I get the exact coordinates of my camera (which in this case is (0,80,80), and if I set the depth to 100, I get ~(0.09, 11.52, 7.06)...
I need a way to figure out either the coordinates where the line between the two points hits the height (y-axis of 2), OR I could find a way to calculate the depth I need to supply the camera in order to get back the coordinates I need
which leads me to:
I have 2 coordinates in 3d space: let's say p1(0, 80, 80) and p2(0.09, 11.52, 7.06).
I want to figure out how to calculate a 3rd point, where y = 2. This point should be aligned with the 2 other points.
Any suggestions to how I can achieve this? I am looking for a solution with as few calculations as possible.
One way to do it is to write a family of equations that describes all of the points in space that are collinear with p1 and p2.
x = x1*t + x2*(1-t)
y = y1*t + y2*(1-t)
z = z1*t + z2*(1-t)
... Where x1,y1,z1 are the coordinates of p1, ditto for p2, and t is any real number.
We can find the coordinates of our particular desired point by solving for t. We know that y = 2, so we'll rearrange that equation.
y = y1*t +y2 - y2*t
y - y2 = y1*t - y2*t
y - y2 = (y1 - y2)*t
(y - y2) / (y1 - y2) = t
t = (y - y2) / (y1 - y2)
Now that you know t, you can plug it into the two remaining equations to get your x and z values.

Knowing two points of a rectangle, how can I figure out the other two?

Hey there guys, I'm learning processing.js, and I've come across a mathematical problem, which I can't seem to solve with my limited geometry and trigonometry knowledge or by help of Wikipedia.
I need to draw a rectangle. To draw this rectangle, I need to know the coordinate points of each corner. All I know is x and y for the midpoints of the top and bottom of the box, and the length of all four sides.
There is no guarantee on the orientation of the box.
Any help? This seems like it should be easy, but it is really stumping me.
If this quadrilateral is a rectangle (all four angles are 90 degrees), then it can be solved. (if it could be any quadrilateral, then it is not solvable)
if the points are (x1,y1), and (x2, y2), and if the two points are not perfectly vertical (x1 = x2) or horizontal (y1 = y2), then the slope of one edge of the rectangle is
m1 = (y2-y1) / (x2-x1)
and the slope of the other edge is:
m2 = - 1 / m1
If you know the lengths of the sides, and the midpoints of two opposite sides, then the corrner points are easily determined by adding dx, dy to the midpoints: (if L is length of the sides that the midpoints are on)
dx = Sqrt( L^2 / (1 + m2^2) ) / 2
and
dy = m2 * dx
NOTE: if the points are vertically or horizontally aligned, this technique will not work, although the obvious solution for those degenerative cases is much simpler.
If you know your quadrilateral is a rectangle, then you can use some simple vector maths to find the coordinates of the corners. The knowns are:
(x1,y1) - the coordinate of the midpoint on the top line
(x2,y2) - the coordinate of the midpoint on the bottom line
l1 - the length of the top and bottom lines
l2 - the length of the other two lines
First, we find the vector between the two known points. This vector is parallel to the side lines:
(vx, vy) = (x2 - x1, y2 - y1)
We need to normalize this vector (i.e. make it length 1) so we can use it later as a basis to find our coordinates.
vlen = sqrt(vx*vx + vy*vy)
(v1x, v1y) = (vx / vlen, vy / vlen)
Next, we rotate this vector anticlockwise by 90 degrees. The rotated vector will be parallel to the top and bottom lines. 90 degree rotation turns out to just be swapping the coordinates and negating one of them. You can see this just by trying it out on paper. Or take at look at the equations for 2D rotations and substitute in 90 degrees.
(u1x, u1y) = (-v1y, v1x)
Now we have enough information to find the 'top-left' corner. We simply start at our point (x1, y1) and move back along that side by half the side length:
(p1x, p1y) = (x1 - u1x * l1 / 2, y1 - u1y * l1 / 2)
From here we can find the remaining points just by adding the appropriate multiples of our basis vectors. When implementing this you can obviously speed it up by only calculating each unique multiplication a single time:
(p2x, p2y) = (p1x + u1x * l1, p1y + u1y * l1)
(p3x, p3y) = (p1x + v1x * l2, p1y + v1y * l2)
(p4x, p4y) = (p3x + u1x * l1, p3y + u1y * l1)
function getFirstPoint(x1,y1,x2,y2,l1,l2)
distanceV = {x2 - x1, y2 - y1}
vlen = math.sqrt(distanceV[1]^2 + distanceV[2]^2)
normalized = {distanceV[1] / vlen, distanceV[2] / vlen}
rotated = {-normalized[2], normalized[1]}
p1 = {x1 - rotated[1] * l1 / 2, y1 - rotated[2] * l1 / 2}
p2 = {p1[1] + rotated[1] * l1, p1[2] + rotated[2] * l1}
p3 = {p1[1] + normalized[1] * l2, p1[2] + normalized[2] * l2}
p4 = {p3[1] + rotated[1] * l1, p3[2] + rotated[2] * l1}
points = { p1 , p2 , p3 , p4}
return p1
end
It's definitely a rectangle? Then you know the orientation of the short sides (they're parallel to the line between your points), and hence the orientation of the long sides.
You know the orientation and length of the long sides, and you know their midpoints, so it's straightforward to find the corners from there.
Implementation is left as an exercise to the reader.
This means that there will be two lines parallel to the line between the two points you have. Get the corners by translating the line you have 1/2 the length of the top side in each direction perpendicular to the line you have.
If you know the midpoint for the top, and the length of the top, then you know that the y will stay the same for both top corners, and the x will be the midpoint plus/minus the width of the rectangle. This will also be true for the bottom.
Once you have the four corners, there is no need to worry about the side lengths, as their points are the same as those used for the top and bottom.
midpoint
x,10 10,10 x,10
*--------------------------------------------*
width = 30
mx = midpoint x.
top left corner = (w/2) - mx or 15 - 10
top left corner coords = -5,10
mx = midpoint x.
top right corner = (w/2) + mx or 15 + 10
top left corner coords = 25,10
There's a difference between a "quadrilateral" and a "rectangle".
If you have the midpoint of the top and bottom, and the sides lengths, the rest is simple.
Given:
(x1, y1) -- (top_middle_x, top_middle_y) -- (x2, y1)
(x1, y2) -- (btm_middle_x, btm_middle_y) -- (x2, y2)
and top/bottom length along with right/left length.
x1 = top_middle_x - top/bottom_length / 2;
x2 = x1 + top/bottom_length;
y1 = top_middle_y
y2 = bottom_middle_y
Obviously, that's the simplest case and assuming that the line of (tmx, tmy) (bmx, bmy) is solely along the Y axis.
We'll call that line the "mid line".
The next trick is to take the mid line, and calculate it's rotational offset off the Y axis.
Now, my trig is super rusty.
dx = tmx - bmx, dy = tmy - bmy.
So, the tangent of the angle is dy / dx. The arctangent(dy / dx) is the angle of the line.
From that you can get your orientation.
(mind, there's some games with quadrants, and signs, and stuff to get this right -- but this is the gist of it.)
Once you have the orientation, you can "rotate" the line back to the Y axis. Look up 2D graphics for the math, it's straight forward.
That gets you your normal orientation. Then calculate the rectangles points, in this new normal form, and finally, rotate them back.
Viola. Rectangle.
Other things you can do is "rotate" a line that's half the length of the "top" line to where it's 90 deg of the mid line. So, say you have a mid line that's 45 degrees. You would start this line at tmx, tmy, and rotate this line 135 degrees (90 + 45). That point would be your "top left" corner. Rotate it -45 (45 - 90) to get the "top right" point. Then do something similar with the lower points.
Calculate the angle of the line joining the two midpoints using an arc-tangent function applied to the vector you get between them.
Subtract 90 degrees from that angle to get the direction of the top edge
Starting from the top-center point, move relative (1/2 top width x sin(angle), 1/2 top width x cos(angle)) - that gets the top right corner point.
Continue around the rectangle using the sin and cos of the angles and widths as appropriate
As a test: Check you made it back to the starting point
/* rcx = center x rectangle, rcy = center y rectangle, rw = width rectangle, rh = height rectangle, rr = rotation in radian from the rectangle (around it's center point) */
function toRectObjectFromCenter(rcx, rcy, rw, rh, rr){
var a = {
x: rcx+(Math.sin((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2)),
y: rcy-(Math.cos((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2))
};
var b = {
x: a.x+Math.cos(rr)*rw,
y: a.y+Math.sin(rr)*rw
};
var c = {
x: b.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: b.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
var d = {
x: a.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: a.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
return {a:a,b:b,c:c,d:d};
}

turn a line into a rectangle

I have a method that draws a line between two points. This works pretty well, but now I want to make this line into a rectangle.
How can I get the points on the left and right side of each of the line points to make it into a rectangle that I can draw?
It is almost as though I need to somehow figure out how to get perpendicular lines programatically....
I'm guessing you basically want fat lines? Lets assume the line is specified by two points (x0, y0) and (x1, y1) we then have:
float dx = x1 - x0; //delta x
float dy = y1 - y0; //delta y
float linelength = sqrtf(dx * dx + dy * dy);
dx /= linelength;
dy /= linelength;
//Ok, (dx, dy) is now a unit vector pointing in the direction of the line
//A perpendicular vector is given by (-dy, dx)
const float thickness = 5.0f; //Some number
const float px = 0.5f * thickness * (-dy); //perpendicular vector with lenght thickness * 0.5
const float py = 0.5f * thickness * dx;
glBegin(GL_QUADS);
glVertex2f(x0 + px, y0 + py);
glVertex2f(x1 + px, y1 + py);
glVertex2f(x1 - px, y1 - py);
glVertex2f(x0 - px, y0 - py);
glEnd();
Since you're using OpenGL ES I guess you'll have to convert the immediate mode rendering (glBegin, glEnd, etc) to glDrawElements. You'll also have to convert the quad into two triangles.
One final thing, I'm a little tired and uncertain if the resulting quad is counterclockwise or clockwise so turn of backface culling when you try this out (glDisable(GL_CULL)).
Since you've asked this question with OpenGL taged I'll assume that you wish for a solution that is close to OpenGL.
As you know you have two points that make up a line. Lets call them x1,y1 and x2, y2
Lets also assume that x1, y1 is the top left point and x2, y2 is the bottom right.
Your 4 points to plot will be [you need to perserve order to make a rectangle with GL_LINES)
Height:y1-y1
Width: x2-x1
(x1, y1)
(x1+width, y1)
(x2, y2)
(x2-width, y2)
drawRect(x,y,w,h)
tl = (x,y)
tr = (x+w, y)
br = (x+w, y+h)
bl = (x, y+h)

Resources