So I have the following code that works fine
I've taken it from https://codereview.stackexchange.com/questions/192477/circle-line-segment-collision
I am now trying to figure out where along this function I can determine the angle in which the circle is hitting the line. Instead of returning true I'd like it to return the angle, since I didn't write the function myself going through it to try and figure this out myself has been a bit of a struggle. Wondering if someone excellent at math can help me figure this out at first glance. Thank you!
// Function to check intercept of line seg and circle
// A,B end points of line segment
// C center of circle
// radius of circle
// returns true if touching or crossing else false
function doesLineInterceptCircle(A, B, C, radius) {
var dist;
const v1x = B.x - A.x;
const v1y = B.y - A.y;
const v2x = C.x - A.x;
const v2y = C.y - A.y;
// get the unit distance along the line of the closest point to
// circle center
const u = (v2x * v1x + v2y * v1y) / (v1y * v1y + v1x * v1x);
// if the point is on the line segment get the distance squared
// from that point to the circle center
if(u >= 0 && u <= 1){
dist = (A.x + v1x * u - C.x) ** 2 + (A.y + v1y * u - C.y) ** 2;
} else {
// if closest point not on the line segment
// use the unit distance to determine which end is closest
// and get dist square to circle
dist = u < 0 ?
(A.x - C.x) ** 2 + (A.y - C.y) ** 2 :
(B.x - C.x) ** 2 + (B.y - C.y) ** 2;
}
return dist < radius * radius;
}
I need to reverse calculation of standard 360 angle to atan2.
It's my standard angle calulation
Standard angle = (int) Math.toDegrees(Math.atan2(y,x));
if(angle < 0)
angle += 360;
I need Math.atan2 value from angle how to achieve that.
To translate degrees range 0..360 into radians range -Pi..Pi:
if(angle > 180)
angle -= 360;
angle_radians = Math.toRadians(angle);
If your angle may be beyond standard range (you did not mentioned this), use integer modulo instead of loops
angle = angle % 360
(check how modulo operator works with negative numbers in your language)
Though your question is not very clear, it seems that you want to retrieve the angle before the statement
if (angle < 0)
angle += 360;
As atan2 returns a value in the range [-π,π), i.e. [-180°,180°), the subrange [-180°,0°) is mapped to [180°,360°). Then you invert with
if (angle >= 180°)
angle-= 360;
You also need to convert back to radians.
A general solution with O(1) performance:
double generalModulus(double value, double modulus, double offset) {
return value - Math.floor((value-offset)/modulus) * modulus + offset;
}
double normalizeAngleDegrees(double angleInDegrees, double offset) {
return generalModulus(angleInDegrees, 360.0, offset);
}
double normalizeAngleRadians(double angleInRadians, double offset) {
return generalModulus(angleInRadians, 2.0*Math.PI, offset);
}
To use:
double normDeg = normalizeAngleDegrees(angle, -180); // produces angle in range [-180, 180)
double normRad = normalizeAngleRadians(angle, 0); // produces angle in range [0, 2*Pi)
My Own answer
int normalizeAngle(int angle)
{
int newAngle = angle;
while (newAngle <= -180) newAngle += 360;
while (newAngle > 180) newAngle -= 360;
return newAngle;
}
Let's say I have an axis-aligned box. I also have a location outside that box.
How do I get the point on the boundaries of the box that is along the line from the center of the box to that point? (And thus, know how far the box extends in that direction).
EDIT: preferably, if the point is inside the box, it should just return the point... but that's something I could easily calculate myself.
2D diagram (Though the answer will preferably work in 3D as well):
point3d getIntersection(point3d topfrontleft, point3d backbottomright, point3d externpt)
{
//find the middle
point3d middle(topfrontleft/2+backbottomright/2);
//slide box and source as if the "middle" was at the origin
topfrontleft -= middle;
backbottomright-= middle;
externpt-= middle;
//scale source as if the box is the unit square
externpt/= topfrontleft;
//find the largest magnitude of the source offset
point3d mag = abs(externpt);
auto max = std::max(mag.x,std::max(mag.y,mag.z));
//if it's inside the box, don't scale
if (max < 1)
max = 1;
//scale the source so that it touches the box
externpt/= max;
//then scale and slide that touching point back to original coordinates
externpt= externpt* topfrontleft + middle;
return externpt;
}
http://coliru.stacked-crooked.com/a/9d9504964bc650bb
I'm not experienced with 3d math, so there's probably faster and more effective ways. No idea.
As a bonus, this algorithm doesn't make any reference to the number of dimensions except for finding the largest magnitude, so should work in both 2d, 3d, and any other theoretical number of dimensions.
Here is some code that does what I said in comments modified for rectangular boxes.
#include <stdio.h>
#include <math.h>
// Find intersection p between line A->B and box.
// Point A must be the box center.
// The box is [x_left, y_bottom, x_right, y_top].
void find_box_intersect(double *box, double *a, double *b, double *p)
{
double dx = b[0] - a[0];
double dy = b[1] - a[1];
if (fabs(dx * (box[3] - box[1])) > fabs(dy * (box[2] - box[0]))) {
p[0] = dx > 0 ? box[2] : box[0];
p[1] = a[1] + dy * (p[0] - a[0]) / dx;
} else {
p[1] = dy > 0 ? box[3] : box[1];
p[0] = a[0] + dx * (p[1] - a[1]) / dy;
}
}
int main(void) {
double box[] = { 1, 2,
2, 4 };
double p[2], a[] = { 0.5 * (box[0] + box[2]),
0.5 * (box[1] + box[3]) };
int i, n = 16;
for (i = 0; i < n; i++) {
double theta = 2 * 3.14159 * i / n;
double b[] = { a[0] + cos(theta), a[1] + sin(theta) };
find_box_intersect(box, a, b, p);
printf("%.2f, %.2f\n", p[0], p[1]);
}
return 0;
}
The 3d generalization of this is straightforward. Rather than the if statement that determines only 2 cases, there will be a 3 case if-else chain that determines 3: left-right, top-bottom, front-back.
Output:
2.00, 3.00
2.00, 3.21
2.00, 3.50
1.91, 4.00
1.50, 4.00
1.09, 4.00
1.00, 3.50
1.00, 3.21
1.00, 3.00
1.00, 2.79
1.00, 2.50
1.09, 2.00
1.50, 2.00
1.91, 2.00
2.00, 2.50
2.00, 2.79
Short answer: Intersect the line with the (right) border of the box.
Longer answer:
x is easy: It's at the right border of the box.
for y, solve this: y/line_height = (line_width - box_width/2) / line_width
then add the y of the line lower point
This is assuming the line intersects the right border, as in your picture.
To figure which border the line intersects, compare the ratio of line_height/line_width, and the signs, to the ratio of box_height/box_width.
If the box is square and you're only interested in the radius, and not the intersection point, you can throw away the signs of line_width and line_height, sort them, and just solve one case.
If the box is not square, you can still throw away the signs, but need to compare the ratios to pick one of two remaining cases (in 2D).
Assuming that you know the length and width of the rect, if the angle is pointing left or right, then x is known, so you only need to solve for y (r * sin(angle)); if the angle is pointing up or down, then y is known so you solve for x (r * cos(angle)).
// where the center of the rect = 0, 0 and angles are in degrees 0..360
// determine the 45's first
if (angle in (45, 135, 225, 315)) {
return { x:cos(angle) * (width / 2), y:sin(angle) * (height / 2) };
}
if (angle < 45 || angle > 315) {
// pointing right
return { x:(width / 2), y:sin(angle) * (height / 2) };
}
if (angle > 45 && angle < 135) {
// pointing up
return { x:cos(angle) * (width / 2), y:(height / 2) };
}
if (angle > 135 && angle < 225) {
// pointing left
return { x:(width / -2), y:sin(angle) * (height / 2) };
}
if (angle > 225 && angle < 315) {
// pointing down
return { x:cos( angle ) * (width / 2), y:(height / -2) };
}
There are undoubtedly more elegant mathematical solutions to this problem, but this one works for me--understandable, testable, etc.
I have a vector _pts that contains values for (x,y,z), i.e. a point in 3D. Starting with _pts[0], I want to select those points whose distance between previously selected points is bigger than sampleRadius.
Here is my code but apparently something's wrong because is selecting a lot of points instead of just selecting a few.
Can anyone see what am I doing wrong? Probably you would need more code to see what can be missed, but I would also appreciate any idea on how can I implement this.
float distance;
bool distanceIsOk;
//PICK A POINT IN VECTOR _pts
for (int cPIdx = 0; cPIdx < _pts.size(); cPIdx++) {
distanceIsOk = true;
//CHECK DISTANCE AGAINST PREVIOUSLY PICKED POINTS
for (int dPIdx = 0; dPIdx < indeces.size(); dPIdx++) {
distance = sqrt(
(_pts[cPIdx].v[0] - _pts[dPIdx].v[0])*(_pts[cPIdx].v[0] - _pts[dPIdx].v[0]) +
(_pts[cPIdx].v[1] - _pts[dPIdx].v[1])*(_pts[cPIdx].v[1] - _pts[dPIdx].v[1]) +
(_pts[cPIdx].v[2] - _pts[dPIdx].v[2])*(_pts[cPIdx].v[2] - _pts[dPIdx].v[2])
);
//IF DISTANCE IS <= SUBSAMPLERADIUS FOR AT LEAST ONE PREVIOUSLY SELECTED POINT
if (distance <= subsampleRadius) {
//DISCARD THE POINT
distanceIsOk = false;
dPIdx += indeces.size();
}
}
//OTHERWISE INCLUDE THAT POINT
if (distanceIsOk == true) {
indeces.push_back(cPIdx);
}
}
Found the error. Instead of
distance = sqrt(
(_pts[cPIdx].v[0] - _pts[dPIdx].v[0])*(_pts[cPIdx].v[0] - _pts[dPIdx].v[0]) +
(_pts[cPIdx].v[1] - _pts[dPIdx].v[1])*(_pts[cPIdx].v[1] - _pts[dPIdx].v[1]) +
(_pts[cPIdx].v[2] - _pts[dPIdx].v[2])*(_pts[cPIdx].v[2] - _pts[dPIdx].v[2])
it should be
distance = sqrt(
(_pts[cPIdx].v[0] - _pts[indeces[dPIdx]].v[0])*(_pts[cPIdx].v[0] - _pts[indeces[dPIdx]].v[0]) +
(_pts[cPIdx].v[1] - _pts[indeces[dPIdx]].v[1])*(_pts[cPIdx].v[1] - _pts[indeces[dPIdx]].v[1]) +
(_pts[cPIdx].v[2] - _pts[indeces[dPIdx]].v[2])*(_pts[cPIdx].v[2] - _pts[indeces[dPIdx]].v[2])
I'm trying to find the yaw, pitch and roll angles of a camera, assuming that I have the position of the camera, it's look_at point (target point) and it's up vector. My best try was by using the following code
zaxis = lookat-position
xaxis = cross(up, xaxis)
yaxos = cross(zxis, xaxis)
Then I find the angles between each axis and the normal vectors (1,0,0) (0,1,0) and (0,0,1)
and assign them to roll, yaw and pitch, but it doesn't seem to work
Any ideas, what I'm doing wrong?
Thanks in advance :)
You won't be able to get the roll angle - as that could be anything, but you can get the elevation and azimuth (pitch and yaw). I've found some old C code which I'll translate to pseudo code, so assuming that your vector isn't zero length:
Vector3 v = lookat - position;
double length = v.Length();
double elevation = asin(v.y / length);
double azimuth;
if (abs(v.z) < 0.00001)
{
// Special case
if (v.x > 0)
{
azimuth = pi/2.0;
}
else if (v.x < 0)
{
azimuth = -pi/2.0;
}
else
{
azimuth = 0.0;
}
}
else
{
azimuth = atan2(v.x, v.z);
}