How do I find the point on the straight line that is specific distance away from a given point. I am writing this code in C but I do not get the right answer..Could you anyone guide me on what I am doing wrong.
I get the x1,y1,x2,y2 values and the distance left fine. Using these I can find the slope m and the y-intercept also fine.
Now, I need to find the point on the straight line connecting these two points that is 10 units away from the point x1,y1. I seem to be going wrong here. here's the code that I wrote.
int x1 = node[n].currentCoordinates.xCoordinate;
int y1 = node[n].currentCoordinates.yCoordinate;
int x2 = node[n].destinationLocationCoordinates.xCoordinate;
int y2 = node[n].destinationLocationCoordinates.yCoordinate;
int distanceleft = (y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1);
distanceleft = sqrt(distanceleft);
printf("Distance left to cover is %d\n",distanceleft);
int m = (y2 - y1)/(x2 - x1); // slope.
int b = y1 - m * x1; //y-intercept
//find point on the line that is 10 units away from
//current coordinates on equation y = mx + b.
if(x2 > x1)
{
printf("x2 is greater than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx <= x2; tempx++)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
else
{
printf("x2 is lesser than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx >= x2; tempx--)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
printf("at time %f, (%d,%d) are the coordinates of node %d\n",clock,node[n].currentCoordinates.xCoordinate,node[n].currentCoordinates.yCoordinate,n);
Here is how it is in math, I don't have time to write something in C.
You have a point (x1,y1) and another one (x2,y2), when linked it gives you a segment.
Thus you have a directional vector v=(xv, yv) where xv=x2-x1 and yv=y2-y1.
Now, you need to divide this vector by its norm, you get a new vector: vector = v / sqrt(xv2 + yv2).
Now, you just have to add to your origin point the vector multiplied by the distance at which you want your point:
Position = (x origin, y origin) + distance × vector
I hope this helps!
Or simpler,
Find the angle from the slope
θ = arctan(y2-y1/x2-x1)
You might want to modify the quadrant of θ based on the numerator and denominator of the slope. Then you can find any point on the line at distance d from (x1, y1)
x_new = x1 + d×cos(θ)
y_new = y1 + d×sin(θ)
In this case, you have d=10
Related
I've found this Generalized Bresenham's Line Drawing Algorithm and I'm having a hard time understanding what the while is doing here.
Any help is greatly appreciated.
the code:
#define sign(x) ((x > 0)? 1 : ((x < 0)? -1: 0))
x = x1;
y = y1;
dx = abs(x2 - x1);
dy = abs(y2 - y1);
s1 = sign(x2 - x1);
s2 = sign(y2 - y1);
swap = 0;
if (dy > dx) {
temp = dx;
dx = dy;
dy = temp;
swap = 1;
}
D = 2*dy - dx;
for (i = 0; i < dx; i++) {
display_pixel (x, y);
while (D >= 0) {
D = D - 2*dx;
if (swap)
x += s1;
else
y += s2;
}
D = D + 2*dy;
if (swap)
y += s2;
else
x += s1;
}
D is the scaled distance from the line to the candidate x, y coordinate.
Better: D is scaled difference of the distance from the line to the candidates x+1, y+0 and x+1, y+1.
That is, as x increments, the sign of D indicates should the closer y increment by 0 or 1?
(The role of x, y interchanges depending on which octant the algorithm is applied.)
I expected while (D >= 0) { as if (D >= 0) {. Bresenham's line algorithm
Note that OP's code is subject to overflow in abs(x2 - x1) and 2*dy - dx. Alternates exist that do not rely on wider math.
I want to find the point at distance d on the right side of a line defined by P1(x1,y1) and P2(x2,y2) (the distance is calculated from the middle of the line). I came up with the following code, which works well, but I think I have made unnecessary calculations, and it can be done faster.
#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
double x2, x1, y1, y2, px, py, p1x, p1y, p2x, p2y, d, ax, ay, b, dx, dy;
d = 2.0; // given distance
ax = (x1 + x2) / 2; // middle point
ay = (y1 + y2) / 2; // middle point
b = tan(atan2(y2 - y1, x2 - x1) + PI / 2); // slope of the perpendicular line
dx = (d / sqrt(1 + (b * b)));
dy = b * dx;
p1x = ax + dx;
p1y = ay + dy;
p2x = ax - dx;
p2y = ay - dy;
// cross product
if (((x2 - x1) * (p1y - y1) - (y2 - y1) * (p1x - x1)) > 0)
{
px = p1x;
py = p1y;
}
else
{
px = p2x;
py = p2y;
}
You don't need atan, b value, cross product to check orientation (moreover, b might be zero and cause division error).
Instead calculate normalized (unit length) direction vector and get right normal to it:
d = 2.0; // given distance
ax = (x1 + x2) / 2; // middle point
ay = (y1 + y2) / 2; // middle point
dx = x2 - x1;
dy = y2 - y1;
scale = d / sqrt(dx*dx + dy*dy); //distance/vector length
px = ax + dy * scale; // add normal vector to the right side of p1-p2 direction
py = ay - dx * scale; //note minus sign
For generating a 2D vector perpendicular to another, one result that falls out from a special case of the dot product is that you can swap the two components of the vector and negate one of them.
For example, let's say you have the vector d which points from p1 to p2:
dx = p2x - p1x;
dy = p2y - p1y;
And now you want to generate right which is perpendicular, it is simply:
rightx = dy;
righty = -dx;
Now, let's do a quick visual check for our definition of "on the right", in case we actually want to negate those two values...
o p2 = [2, 3]
/
o p1 = [0, 0]
Above, d is simple: [2, 3]. Intuitively, we would think of (as viewed from above) walking from p1 to p2 and looking to the right, which would mean a vector in the positive X direction and the negative Y direction. So yes, that looks fine.
Note: If your co-ordinate system is screen-based (i.e. positive Y direction is down), then the inverse is true (and you would negate both the terms in the calculation of the right vector). This is due to the handedness of the co-ordinate system being left instead of right.
Now, you can calculate the midpoint mid as either (p1 + p2) / 2 or p1 + d / 2.
midx = (p1x + p2x) / 2;
midy = (p1y + p2y) / 2;
And finally to generate p3 you start from mid and extend down the vector right by an amount height, you need to normalize that vector by dividing by its length and scale by height. Formally, the final point will be mid + right * height / length(right).
This is the only particularly expensive part of the calculation, because it needs a square root.
rdist = height / sqrt(rightx * rightx + righty * righty);
p3x = midx + rightx * rdist;
p3y = midy + righty * rdist;
Congratulations! You now have an isosceles triangle!
How can i find the length of a line between two points with coordinates (x1, y1) and (x2, y2) in array ? For example i have 2 arrays : arrayX[10] and arrayY[10].
I have to find the results of the following operations in the loop and save them in the result array :
sqrt((arrayX[0]- arrayX[1])^2+(arrayY[0]-arrayY[1]^2))
sqrt((arrayX[1]- arrayX[2])^2+(arrayY[1]-arrayY[2]^2))
.
.
.
In C there is no exponentiation operator. To compute x^2 either use x * x or pow(x, 2) from math.h.
Possible solution
double dist[9];
for (int i = 0; i + 1 < 10; ++i) {
double dx = arrayX[i]- arrayX[i + 1];
double dy = arrayY[i]- arrayY[i + 1];
dist[i] = sqrt(dx *dx + dy * dy);
}
y coordinates from user as double variable and calculating them if points forms a triangle but i cant get correct result.
I think there is a problem about using double variables for example if i put integer variable to x1 , y1 it does not calculate mAB
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#include<conio.h>
int main()
{
double x1,y1,x2,y2,x3,y3;
printf("Enter x , y coordinates of first vertice!\n");
scanf("%lf",&x1);
scanf("%lf",&y1);
/*
if(isInteger(x1)==0)
{
printf("\ndouble");
}
else
{
printf("\nint");
}
*/
/*********************************************/
printf("Enter x , y coordinates of second vertice!\n");
scanf("%lf",&x2);
scanf("%lf",&y2);
/*********************************************/
printf("Enter x , y coordinates of third vertice!\n");
scanf("%lf",&x3);
scanf("%lf",&y3);
/*********************************************/
/*********************************************/
double mAB = (fabs(x1-x2) / fabs(y1-y2));
double mAC = (fabs(x1-x3) / fabs(y1-y3));
printf("\n mAB %lf", mAB);
printf("\n mAC %lf", mAC);
if(mAB == mAC)
{
printf("These points does not forms a triangle!!!!");
}
else
{
/*
* 1-2 AB
* 1-3 AC
* 2-3 BC
*/
double distancexAB = (x2 - x1) * (x2 - x1);
double distanceyAB = (y2 - y1) * (y2 - y1);
double distanceAB = csqrt(fabs(distancexAB - distanceyAB));
/*********************************************/
double distancexAC = (x3 - x1) * (x3 - x1);
double distanceyAC = (y3 - y1) * (y3 - y1);
double distanceAC = csqrt(fabs(distancexAC - distanceyAC));
/*********************************************/
double distancexBC = (x2 - x3) * (x2 - x3);
double distanceyBC = (y2 - y3) * (y2 - y3);
double distanceBC = csqrt(fabs(distancexBC - distanceyBC));
/*********************************************/
printf("\n AB %lf", distanceAB);
printf("\n AC %lf", distanceAC);
printf("\n BC %lf", distanceBC);
double perimeter = distanceAB+distanceAC+distanceBC;
printf("\n Perimeter: %lf", perimeter);
}
getch();
return 0;
}
Test results:
Enter x , y coordinates of first vertice!
1 1
Enter x , y coordinates of second vertice!
2 2
Enter x , y coordinates of third vertice!
3 3
mAB 1.000000
mAC 1.000000These points does not forms a triangle!!!!
Second test
Enter x , y coordinates of first vertice!
3.4 5.6
Enter x , y coordinates of second vertice!
1.2 3.4
Enter x , y coordinates of third vertice!
1.8 9.8
mAB 1.000000
mAC 0.380952
AB 0.000000
AC 3.883298
BC 6.371813
Perimeter: 10.255111
Calculate the distance between points by adding the sum of squares, not subtracting them. fabs() not needed. sqrt() is sufficient. #Alexander Daum.
Even better, use hypot().
The hypot functions compute the square root of the sum of the squares of x and y, without undue overflow or underflow. C11 §7.12.7.3 2
double distancexAB = (x2 - x1) * (x2 - x1);
double distanceyAB = (y2 - y1) * (y2 - y1);
// double distanceAB = csqrt(fabs(distancexAB - distanceyAB));
double distanceAB = sqrt(distancexAB + distanceyAB);
// or even more simple
double distanceAB = hypot(x2 - x1, y2 - y1);
OP uses weak code to detect if slopes are parallel. 2 problems:
fabs() loses the sign of the slope.
OP's method is subject to divide by 0.0.
// Alternative code:
double delta_x12 = x1 - x2;
double delta_y12 = y1 - y2;
double delta_x13 = x1 - x3;
double delta_y13 = y1 - y3;
if (delta_x12*delta_y13 == delta_y12*delta_x13) {
printf("These points do not form a triangle.");
}
If OP wants to calculate the area, code could use Heron's formula and use that to determine if "points do not form a triangle".
double a = hypot(x1 - x2, y1 - y2);
double b = hypot(x2 - x3, y2 - y3);
double c = hypot(x2 - x1, y3 - y1);
double perimeter = a + b + c;
double s /* semi-perimeter */ = perimeter/2;
double area2 = s*(s-a)*(s-b)*(s-c);
// due to small inaccuracies, area2 may be negative.
double area = area2 > 0.0 ? sqrt(area2) : 0.0;
if (area == 0) {
printf("These points do not form a triangle.");
}
Where calculating distances, you have to write:
double distanceAB = sqrt(distancexAB + distanceyAB);
instead of
double distanceAB = csqrt(fabs(distancexAB - distanceyAB));
Because the distance is the hypothenuse and use sqrt instead of csqrt, because csqrt is intended for complex variables.
You don't need fabs, because distancexAB and distanceyAB are squares and so they cannot be negative, and the sum of two positive numbers will be positive as long as no overflow occurs.
I am currently trying to recreate the classic game Asteroids.
As of this moment I have managed to create a vector triangle on my screen and I have been able to make this triangle rotate around an origin point. I am now currently trying to get the triangle to move in the same way that the ship in the original game moves, with that floaty/on ice kind of feel. My problem however is that the direction of the ship's travel when the up button is pressed is not in line with the triangle's direction. I.e. the triangle travels off at the wrong direction and looks daft.
I am pretty sure the physics for the motion of the triangle is fine, so I think the error might be with the definition of the triangle but I am not sure. My code is below:
//handles updating the game state, moving the objects, and handling collisions.
#include "gamestate.h"
struct gameState_t{
int lives;
} game;
struct ship_t{
int heading;
int x, y;
double vx, vy;
int speed;
bool isAcc; //isAccelerating
} ship;
void physics(void)
{
moveShip();
}
void initGameState(void){
ship.heading = 0;
ship.x = 240;
ship.y = 240;
ship.vx = 0;
ship.vy = 0;
ship.speed = 0;
ship.isAcc = false; //acceleration
}
//getters
int getShipX(void){
return ship.x;
}
int getShipY(void){
return ship.y;
}
int getShipHeading(void){
return ship.heading;
}
int getShipSpeed(void)
{
return ship.speed;
}
bool getShipAcc(void)
{
return ship.isAcc;
}
double getShipVx(void)
{
return ship.vx;
}
double getShipVy(void)
{
return ship.vy;
}
void moveShip(void)
{
ship.x += (ship.vx / 10);
ship.y += (ship.vy / 10);
}
void incHeading(void)
{
ship.heading++;
if(ship.heading < 0)
{
ship.heading = 360;
}
if(ship.heading > 360)
{
ship.heading = 0;
}
}
void decHeading(void)
{
//ship.heading = ship.heading - 6;
ship.heading--;
if(ship.heading < 0)
{
ship.heading = 360;
}
if(ship.heading > 360)
{
ship.heading = 0;
}
}
void accelerate(void)
{
float shipHeadingRads = (ship.heading * (PI / 180));
//float shipHeadingRads = ship.heading;
ship.vy += sin(shipHeadingRads) * acceleration;
ship.vx += cos(shipHeadingRads) * acceleration;
}
This next part is the code that is used to draw the triangle on the screen, however this is used in another module.
void drawShipActive(void)
{
int shipX = getShipX();
int shipY = getShipY();
int shipHeading = getShipHeading();
float shipHeadingRads = (shipHeading * (PI / 180));
int x1, y1, x2, y2, x3, y3;
int x1r, y1r, x2r, y2r, x3r, y3r;
/*
x1 = shipX;
y1 = shipY - 20;
x2 = shipX - 10;
y2 = shipY + 10;
x3 = shipX + 10;
y3 = shipY + 10;
*/
x1 = shipX;
y1 = shipY + 20;
x2 = shipX - 10;
y2 = shipY - 10;
x3 = shipX + 10;
y3 = shipY - 10;
x1r = ((x1 - shipX) * cos(shipHeadingRads)) - ((shipY - y1) * -(sin(shipHeadingRads))) + shipX;
y1r = ((shipY - y1) * cos(shipHeadingRads)) - ((x1 - shipX) * sin(shipHeadingRads)) + shipY;
x2r = ((x2 - shipX) * cos(shipHeadingRads)) - ((shipY - y2) * -(sin(shipHeadingRads))) + shipX;
y2r = ((shipY - y2) * cos(shipHeadingRads)) - ((x2 - shipX) * sin(shipHeadingRads)) + shipY;
x3r = ((x3 - shipX) * cos(shipHeadingRads)) - ((shipY - y3) * -(sin(shipHeadingRads))) + shipX;
y3r = ((shipY - y3) * cos(shipHeadingRads)) - ((x3 - shipX) * sin(shipHeadingRads)) + shipY;
screen->drawTriangle(x1r, y1r, x2r, y2r, x3r, y3r, GREEN);
}
I am assuming this is a relatively minor problem but I'm not sure where the problem lies exactly.
Thank you for your help.
When shipHeadingRads is 0, you will be accelerated in the positive X direction (because cos(0) is 1 and sin(0) is 0).
ship.vy += sin(shipHeadingRads) * acceleration;
ship.vx += cos(shipHeadingRads) * acceleration;
However, the triangle's "point" will be in the positive Y direction because that's the shape you're drawing:
x1 = shipX;
y1 = shipY + 20;
x2 = shipX - 10;
y2 = shipY - 10;
x3 = shipX + 10;
y3 = shipY - 10;
If you draw the points (0,20), (-10,-10) and (10,-10) on paper you'll see the pointy side is in the positive Y direction.
You need to change either one of these things.