Alternative algorithm for integral calculation inaccurate - c++

I thought of an algorithm for integral calculation that should be more accurate that the regular rectangle approach. My algorithm can be best described with a graphic (I am using f(x) = sin(x) as example):
First the x and y positions of the points P1, P2, P3, P4 are
calculated (red dots).
The area of the green four sided figure is a part of the result.
This area is calculated by dividing it into two triangles (blue
line).
The area of each triangle is calculated using the Heron’s formula.
I think it is obvious that this should lead to much better results than the rectangle approach.
In code this looks like this:
double integral(double f(double x), double min, double max) {
Point p1, p2, p3, p4;
double area = 0.0;
double s1 = 0.0;
double s2 = 0.0;
for(double x = min; x < max; x += stepSize) {
p1.x = x;
p1.y = 0.0;
p2.x = x;
p2.y = f(x);
p3.x = x + stepSize;
p3.y = f(x + stepSize);
p4.x = x + stepSize;
p4.y = 0.0;
s1 = 0.5 * (distance(p1, p2) + distance(p2, p4) + distance(p1, p4));
s2 = 0.5 * (distance(p2, p3) + distance(p3, p4) + distance(p2, p4));
area += sqrt(s1 * (s1 - distance(p1, p2)) * (s1 - distance(p2, p4)) * (s1 - distance(p1, p4)));
area += sqrt(s2 * (s2 - distance(p2, p3)) * (s2 - distance(p3, p4)) * (s2 - distance(p2, p4)));
}
return area;
}
The distance function is just returning the distance between two points in 2D space. The Point struct is just holding a x and y coordinate. stepSize is a constant that I set to 0.001
My function is giving a result that is correct, but I wanted to know how much more precise it is compared to the rectangle approach.
On the internet I found this code that is calculating a integral using rectangles:
double integral2(double(*f)(double x), double a, double b, int n) {
double step = (b - a) / n; // width of each small rectangle
double area = 0.0; // signed area
for (int i = 0; i < n; i ++) {
area += f(a + (i + 0.5) * step) * step; // sum up each small rectangle
}
return area;
}
I both tested them using the standard math.h sin function from 0.0 to half π. This area should be 1.
My algorithm has given me the result 1.000204 for a step-size of 0.001.
The rectangle algorithm hast given me the result 1.000010 with a calculated step-size of 0.015708.
How can such a difference in accuracy and step-size be explained?
Did I implement my algorithm wrong?
Update
Using the calculated step-size of the second method, I get the result 0.999983 which is much closer to one than the result with a step-size of 0.001.
Now how can that work??

Your last trapezoid may be too wide: x+stepSize may be above max if max-min isn't a multiple of stepSize. That's why in the rectangular summation code you included, rather than stepSize, they use n (the number of rectangles).
You compute the trapezoid in a complicated way. Note that its area is stepSize * (P2.y + P3.y)/2. This adds computation cost, but I guess is not the cause of the numerical error in your test integral.
Except for these issues, your method is otherwise equivalent to the trapezoid rule. https://en.wikipedia.org/wiki/Trapezoidal_rule
Here is Python code that approximates the integral in three different ways, using 100 rectangles. The three ways are trap_heron (your method, using Heron's rule), trap (trapezoid method), and rect (rectangular summation). Your question is C++, but the results should be the same.
import math
N = 100
def dist(a, b):
dx = a[0] - b[0]
dy = a[1] - b[1]
return math.sqrt(dx*dx + dy*dy)
def trap_heron(f, min, max):
area = 0.0
for i in range(N):
x0 = min + (max-min) * i/N
x1 = min + (max-min) * (i+1)/N
y0 = f(x0)
y1 = f(x1)
p1 = (x0, 0.0)
p2 = (x0, y0)
p3 = (x1, y1)
p4 = (x1, 0.0)
s1 = 0.5 * (dist(p1, p2) + dist(p2, p4) + dist(p1, p4))
s2 = 0.5 * (dist(p2, p3) + dist(p3, p4) + dist(p2, p4))
area += math.sqrt(s1 * (s1 - dist(p1, p2)) * (s1 - dist(p2, p4)) * (s1 - dist(p1, p4)))
area += math.sqrt(s2 * (s2 - dist(p2, p3)) * (s2 - dist(p3, p4)) * (s2 - dist(p2, p4)))
return area
def trap(f, min, max):
area = 0.0
for i in range(N):
x0 = min + (max-min) * i/N
x1 = min + (max-min) * (i+1)/N
y0 = f(x0)
y1 = f(x1)
area += (x1-x0) * (y0+y1)/2
return area
def rect(f, min, max):
area = 0.0
for i in range(N):
y = f(min + (max-min)*(i+0.5)/N)
area += (max-min)/N * y
return area
print(trap(math.sin, 0, math.pi/2))
print(trap_heron(math.sin, 0, math.pi/2))
print(rect(math.sin, 0, math.pi/2))
The output is:
0.9999794382396076
0.9999794382396054
1.0000102809119051
Note that trap and trap_heron produce very nearly the same result.
In your comments, you have a result of 1.015686. The error is very close to stepSize * sin(pi/2), so I guess you've summed up one too many trapezoids.

You can try Kahan summation to reduce the error but the precision issue is real. You are approximating the integral using a numerical method after all.

Related

C++ Voronoi styled tile map

I am trying to display map with Voronoi styled map tiles.
It is on 2d array, I set some steps to achieve it:
Divide 2d array map into equal sized squares (tile).
int map_width = 100, map_height = 100,
tile_size = 10;
vector<vector<int>> tile_map; // size 10x10
Uniformly distribute site(or central) points in tiles
vector<pair<int,int>> sites
for (int y = 0; y < tile_map.size(); y++)
for (int x = 0; x < tile_map[y].size(); x++)
sites.push_back({x*tile_size+(rand()%tile_size(),y*tile_size+(rand()%tile_size()});
Link site points to other sites in adjacent tiles.
Draw perpendicular line of lines formed in step 3.
Intersecting point of perpendicular lines is the vertex of voronoi styled polygon.
Here I am stuck with step 4 and 5.
Is there a way to find perpendicular line with 2 given points?
Or is there a better way to design voronoi diagram in c++?enter image description here
Given 2 points (x1, y1) and (x2, y2) gives you a dx = x2 - x1 and dy = y2 - y1 and a parametric equation for the line line(t) = (x1 + t * dx, y1 + t * dy).
Constructing a perpendicular line from that is easy. Find the midpoint and rotate the slope by 90°:
cx = (x1 + x2) / 2;
cy = (y1 + y2) / 2;
p(t) = (cx + t * dy, cy + t * dx)
Finding the intersection of 2 such lines is easy too:
p1(t1) = (cx1 + t1 * dy1, cy1 + t1 * dx1)
p2(t2) = (cx2 + t2 * dy2, cy2 + t2 * dx2)
The 2 lines intersect when p1(t1) = p2(t2). That gives you 2 equations and 2 unknowns:
cx1 + t1 * dy1 == cx2 + t2 * dy2
cy1 + t1 * dx1 == cy2 + t2 * dx2
Solve for either t1 or t2 and calculate p1(t1) or p2(t2) at that point.

How do you determine if a point is in front or behind a line segment using the Half Space test?

How do you determine if a point is in front of a line with the half space test? I have tried the following. It works most of the time, but fails others. Are there circumstances where it will not work? For example, will it only work if all points are within certain quadrants? If not, what am I incorrectly doing?
I have tried:
bool PointInFrontOfLine(Point testPoint, Point v1, Point v2)
{
// Compute line normal
double dx = v2.x - v1.x;
double dy = v2.y - v1.y;
double nx = -dy;
double ny = dx;
double length = sqrt(dx * dx + dy * dy);
nx /= length;
ny /= length;
glm::vec3 normal(nx, 0, ny);
glm::vec3 vec(testPoint.x - v1.x, 0, testPoint.y - v1.y);
double distance = glm::dot(vecTemp, normal);
if (distance > 0)
return true;
else
return false;
}
What you actually do is to calculate the (left turned) normal vector to the line which is defined by the points v1 and v2:
double dx = v2.x - v1.x;
double dy = v2.y - v1.y;
double nx = -dy;
double ny = dx;
double length = sqrt(dx * dx + dy * dy);
nx /= length;
ny /= length;
glm::vec3 normal(nx, 0, ny);
This can be simplified:
glm::vec3 normal(v1.y - v2.y, 0, v2.x - v1.x);
normal = glm::normalize(normal);
Note, for the algorithm you can even skip the normalization, then you won't get the correct normal distance, but the sign of distance is still correct. This is sufficient in your case because you only check distance > 0:
glm::vec3 normal(v1.y - v2.y, 0, v2.x - v1.x);
Then you check if the angle between the normal vector and the vector from v1 to testPoint is greater -90 degrees and less than +90 degrees:
glm::vec3 vec(testPoint.x - v1.x, 0, testPoint.y - v1.y);
double distance = glm::dot(vecTemp, normal);
This works, because in general The dot product of 2 vectors is equal the cosine of the angle between the 2 vectors multiplied by the magnitude (lenght) of both vectors. If the cosine of an angle is >= 0, the the angle is in range [-90°, 90°].
dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B )
But the algorithm only works, if v2.x < v1.x (In the following pictures the x-axis points from left to right and the y-axis points from bottom to top):
If the 2 points are swapped (v2.x > v1.x), then you'll get the opposite result:
Finally the code can be expressed somehow like this:
glm::dot(glm::vec2(testPoint.x-v1.x, testPoint.y-v1.y),
glm::vec2(v1.y-v2.y, v2.x-v1.x)) * glm::sign(v1.x-v2.x) > 0
Of coures the result still depends on, what "in front of" means. In my assumptions it means, that the y coordinate of testPoint is less than the y coordinate of the intersection point of the line v1 to v2 with a parallel line to the y-axis through testPoint. This means it depends on your program logic and coordinate system if this algorithm always calculates "in front" or "in back".

distance from given point to given ellipse

I have an ellipse, defined by Center Point, radiusX and radiusY, and I have a Point. I want to find the point on the ellipse that is closest to the given point. In the illustration below, that would be S1.
Now I already have code, but there is a logical error somewhere in it, and I seem to be unable to find it. I broke the problem down to the following code example:
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>
using namespace std;
void dostuff();
int main()
{
dostuff();
return 0;
}
typedef std::vector<cv::Point> vectorOfCvPoints;
void dostuff()
{
const double ellipseCenterX = 250;
const double ellipseCenterY = 250;
const double ellipseRadiusX = 150;
const double ellipseRadiusY = 100;
vectorOfCvPoints datapoints;
for (int i = 0; i < 360; i+=5)
{
double angle = i / 180.0 * CV_PI;
double x = ellipseRadiusX * cos(angle);
double y = ellipseRadiusY * sin(angle);
x *= 1.4;
y *= 1.4;
x += ellipseCenterX;
y += ellipseCenterY;
datapoints.push_back(cv::Point(x,y));
}
cv::Mat drawing = cv::Mat::zeros( 500, 500, CV_8UC1 );
for (int i = 0; i < datapoints.size(); i++)
{
const cv::Point & curPoint = datapoints[i];
const double curPointX = curPoint.x;
const double curPointY = curPoint.y * -1; //transform from image coordinates to geometric coordinates
double angleToEllipseCenter = atan2(curPointY - ellipseCenterY * -1, curPointX - ellipseCenterX); //ellipseCenterY * -1 for transformation to geometric coords (from image coords)
double nearestEllipseX = ellipseCenterX + ellipseRadiusX * cos(angleToEllipseCenter);
double nearestEllipseY = ellipseCenterY * -1 + ellipseRadiusY * sin(angleToEllipseCenter); //ellipseCenterY * -1 for transformation to geometric coords (from image coords)
cv::Point center(ellipseCenterX, ellipseCenterY);
cv::Size axes(ellipseRadiusX, ellipseRadiusY);
cv::ellipse(drawing, center, axes, 0, 0, 360, cv::Scalar(255));
cv::line(drawing, curPoint, cv::Point(nearestEllipseX,nearestEllipseY*-1), cv::Scalar(180));
}
cv::namedWindow( "ellipse", CV_WINDOW_AUTOSIZE );
cv::imshow( "ellipse", drawing );
cv::waitKey(0);
}
It produces the following image:
You can see that it actually finds "near" points on the ellipse, but it are not the "nearest" points. What I intentionally want is this: (excuse my poor drawing)
would you extent the lines in the last image, they would cross the center of the ellipse, but this is not the case for the lines in the previous image.
I hope you get the picture. Can anyone tell me what I am doing wrong?
Consider a bounding circle around the given point (c, d), which passes through the nearest point on the ellipse. From the diagram it is clear that the closest point is such that a line drawn from it to the given point must be perpendicular to the shared tangent of the ellipse and circle. Any other points would be outside the circle and so must be further away from the given point.
So the point you are looking for is not the intersection between the line and the ellipse, but the point (x, y) in the diagram.
Gradient of tangent:
Gradient of line:
Condition for perpedicular lines - product of gradients = -1:
When rearranged and substituted into the equation of your ellipse...
...this will give two nasty quartic (4th-degree polynomial) equations in terms of either x or y. AFAIK there are no general analytical (exact algebraic) methods to solve them. You could try an iterative method - look up the Newton-Raphson iterative root-finding algorithm.
Take a look at this very good paper on the subject:
http://www.spaceroots.org/documents/distance/distance-to-ellipse.pdf
Sorry for the incomplete answer - I totally blame the laws of mathematics and nature...
EDIT: oops, i seem to have a and b the wrong way round in the diagram xD
There is a relatively simple numerical method with better convergence than Newtons Method. I have a blog post about why it works http://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/
This implementation works without any trig functions:
def solve(semi_major, semi_minor, p):
px = abs(p[0])
py = abs(p[1])
tx = 0.707
ty = 0.707
a = semi_major
b = semi_minor
for x in range(0, 3):
x = a * tx
y = b * ty
ex = (a*a - b*b) * tx**3 / a
ey = (b*b - a*a) * ty**3 / b
rx = x - ex
ry = y - ey
qx = px - ex
qy = py - ey
r = math.hypot(ry, rx)
q = math.hypot(qy, qx)
tx = min(1, max(0, (qx * r / q + ex) / a))
ty = min(1, max(0, (qy * r / q + ey) / b))
t = math.hypot(ty, tx)
tx /= t
ty /= t
return (math.copysign(a * tx, p[0]), math.copysign(b * ty, p[1]))
Credit to Adrian Stephens for the Trig-Free Optimization.
Here is the code translated to C# implemented from this paper to solve for the ellipse:
http://www.geometrictools.com/Documentation/DistancePointEllipseEllipsoid.pdf
Note that this code is untested - if you find any errors let me know.
//Pseudocode for robustly computing the closest ellipse point and distance to a query point. It
//is required that e0 >= e1 > 0, y0 >= 0, and y1 >= 0.
//e0,e1 = ellipse dimension 0 and 1, where 0 is greater and both are positive.
//y0,y1 = initial point on ellipse axis (center of ellipse is 0,0)
//x0,x1 = intersection point
double GetRoot ( double r0 , double z0 , double z1 , double g )
{
double n0 = r0*z0;
double s0 = z1 - 1;
double s1 = ( g < 0 ? 0 : Math.Sqrt(n0*n0+z1*z1) - 1 ) ;
double s = 0;
for ( int i = 0; i < maxIter; ++i ){
s = ( s0 + s1 ) / 2 ;
if ( s == s0 || s == s1 ) {break; }
double ratio0 = n0 /( s + r0 );
double ratio1 = z1 /( s + 1 );
g = ratio0*ratio0 + ratio1*ratio1 - 1 ;
if (g > 0) {s0 = s;} else if (g < 0) {s1 = s ;} else {break ;}
}
return s;
}
double DistancePointEllipse( double e0 , double e1 , double y0 , double y1 , out double x0 , out double x1)
{
double distance;
if ( y1 > 0){
if ( y0 > 0){
double z0 = y0 / e0;
double z1 = y1 / e1;
double g = z0*z0+z1*z1 - 1;
if ( g != 0){
double r0 = (e0/e1)*(e0/e1);
double sbar = GetRoot(r0 , z0 , z1 , g);
x0 = r0 * y0 /( sbar + r0 );
x1 = y1 /( sbar + 1 );
distance = Math.Sqrt( (x0-y0)*(x0-y0) + (x1-y1)*(x1-y1) );
}else{
x0 = y0;
x1 = y1;
distance = 0;
}
}
else // y0 == 0
x0 = 0 ; x1 = e1 ; distance = Math.Abs( y1 - e1 );
}else{ // y1 == 0
double numer0 = e0*y0 , denom0 = e0*e0 - e1*e1;
if ( numer0 < denom0 ){
double xde0 = numer0/denom0;
x0 = e0*xde0 ; x1 = e1*Math.Sqrt(1 - xde0*xde0 );
distance = Math.Sqrt( (x0-y0)*(x0-y0) + x1*x1 );
}else{
x0 = e0;
x1 = 0;
distance = Math.Abs( y0 - e0 );
}
}
return distance;
}
The following python code implements the equations described at "Distance from a Point to an Ellipse" and uses newton's method to find the roots and from that the closest point on the ellipse to the point.
Unfortunately, as can be seen from the example, it seems to only be accurate outside the ellipse. Within the ellipse weird things happen.
from math import sin, cos, atan2, pi, fabs
def ellipe_tan_dot(rx, ry, px, py, theta):
'''Dot product of the equation of the line formed by the point
with another point on the ellipse's boundary and the tangent of the ellipse
at that point on the boundary.
'''
return ((rx ** 2 - ry ** 2) * cos(theta) * sin(theta) -
px * rx * sin(theta) + py * ry * cos(theta))
def ellipe_tan_dot_derivative(rx, ry, px, py, theta):
'''The derivative of ellipe_tan_dot.
'''
return ((rx ** 2 - ry ** 2) * (cos(theta) ** 2 - sin(theta) ** 2) -
px * rx * cos(theta) - py * ry * sin(theta))
def estimate_distance(x, y, rx, ry, x0=0, y0=0, angle=0, error=1e-5):
'''Given a point (x, y), and an ellipse with major - minor axis (rx, ry),
its center at (x0, y0), and with a counter clockwise rotation of
`angle` degrees, will return the distance between the ellipse and the
closest point on the ellipses boundary.
'''
x -= x0
y -= y0
if angle:
# rotate the points onto an ellipse whose rx, and ry lay on the x, y
# axis
angle = -pi / 180. * angle
x, y = x * cos(angle) - y * sin(angle), x * sin(angle) + y * cos(angle)
theta = atan2(rx * y, ry * x)
while fabs(ellipe_tan_dot(rx, ry, x, y, theta)) > error:
theta -= ellipe_tan_dot(
rx, ry, x, y, theta) / \
ellipe_tan_dot_derivative(rx, ry, x, y, theta)
px, py = rx * cos(theta), ry * sin(theta)
return ((x - px) ** 2 + (y - py) ** 2) ** .5
Here's an example:
rx, ry = 12, 35 # major, minor ellipse axis
x0 = y0 = 50 # center point of the ellipse
angle = 45 # ellipse's rotation counter clockwise
sx, sy = s = 100, 100 # size of the canvas background
dist = np.zeros(s)
for x in range(sx):
for y in range(sy):
dist[x, y] = estimate_distance(x, y, rx, ry, x0, y0, angle)
plt.imshow(dist.T, extent=(0, sx, 0, sy), origin="lower")
plt.colorbar()
ax = plt.gca()
ellipse = Ellipse(xy=(x0, y0), width=2 * rx, height=2 * ry, angle=angle,
edgecolor='r', fc='None', linestyle='dashed')
ax.add_patch(ellipse)
plt.show()
Which generates an ellipse and the distance from the boundary of the ellipse as a heat map. As can be seen, at the boundary the distance is zero (deep blue).
Given an ellipse E in parametric form and a point P
the square of the distance between P and E(t) is
The minimum must satisfy
Using the trigonometric identities
and substituting
yields the following quartic equation:
Here's an example C function that solves the quartic directly and computes sin(t) and cos(t) for the nearest point on the ellipse:
void nearest(double a, double b, double x, double y, double *ecos_ret, double *esin_ret) {
double ax = fabs(a*x);
double by = fabs(b*y);
double r = b*b - a*a;
double c, d;
int switched = 0;
if (ax <= by) {
if (by == 0) {
if (r >= 0) { *ecos_ret = 1; *esin_ret = 0; }
else { *ecos_ret = 0; *esin_ret = 1; }
return;
}
c = (ax - r) / by;
d = (ax + r) / by;
} else {
c = (by + r) / ax;
d = (by - r) / ax;
switched = 1;
}
double cc = c*c;
double D0 = 12*(c*d + 1); // *-4
double D1 = 54*(d*d - cc); // *4
double D = D1*D1 + D0*D0*D0; // *16
double St;
if (D < 0) {
double t = sqrt(-D0); // *2
double phi = acos(D1 / (t*t*t));
St = 2*t*cos((1.0/3)*phi); // *2
} else {
double Q = cbrt(D1 + sqrt(D)); // *2
St = Q - D0 / Q; // *2
}
double p = 3*cc; // *-2
double SS = (1.0/3)*(p + St); // *4
double S = sqrt(SS); // *2
double q = 2*cc*c + 4*d; // *2
double l = sqrt(p - SS + q / S) - S - c; // *2
double ll = l*l; // *4
double ll4 = ll + 4; // *4
double esin = (4*l) / ll4;
double ecos = (4 - ll) / ll4;
if (switched) {
double t = esin;
esin = ecos;
ecos = t;
}
*ecos_ret = copysign(ecos, a*x);
*esin_ret = copysign(esin, b*y);
}
Try it online!
You just need to calculate the intersection of the line [P1,P0] to your elipse which is S1.
If the line equeation is:
and the elipse equesion is:
than the values of S1 will be:
Now you just need to calculate the distance between S1 to P1 , the formula (for A,B points) is:
I've solved the distance issue via focal points.
For every point on the ellipse
r1 + r2 = 2*a0
where
r1 - Euclidean distance from the given point to focal point 1
r2 - Euclidean distance from the given point to focal point 2
a0 - semimajor axis length
I can also calculate the r1 and r2 for any given point which gives me another ellipse that this point lies on that is concentric to the given ellipse. So the distance is
d = Abs((r1 + r2) / 2 - a0)
As propposed by user3235832
you shall solve quartic equation to find the normal to the ellipse (https://www.mathpages.com/home/kmath505/kmath505.htm). With good initial value only few iterations are needed (I use it myself). As an initial value I use S1 from your picture.
The fastest method I guess is
http://wwwf.imperial.ac.uk/~rn/distance2ellipse.pdf
Which has been mentioned also by Matt but as he found out the method doesn't work very well inside of ellipse.
The problem is the theta initialization.
I proposed an stable initialization:
Find the intersection of ellipse and horizontal line passing the point.
Find the other intersection using vertical line.
Choose the one that is closer the point.
Calculate the initial angle based on that point.
I got good results with no issue inside and outside:
As you can see in the following image it just iterated about 3 times to reach 1e-8. Close to axis it is 1 iteration.
The C++ code is here:
double initialAngle(double a, double b, double x, double y) {
auto abs_x = fabs(x);
auto abs_y = fabs(y);
bool isOutside = false;
if (abs_x > a || abs_y > b) isOutside = true;
double xd, yd;
if (!isOutside) {
xd = sqrt((1.0 - y * y / (b * b)) * (a * a));
if (abs_x > xd)
isOutside = true;
else {
yd = sqrt((1.0 - x * x / (a * a)) * (b * b));
if (abs_y > yd)
isOutside = true;
}
}
double t;
if (isOutside)
t = atan2(a * y, b * x); //The point is outside of ellipse
else {
//The point is inside
if (xd < yd) {
if (x < 0) xd = -xd;
t = atan2(y, xd);
}
else {
if (y < 0) yd = -yd;
t = atan2(yd, x);
}
}
return t;
}
double distanceToElipse(double a, double b, double x, double y, int maxIter = 10, double maxError = 1e-5) {
//std::cout <<"p="<< x << "," << y << std::endl;
auto a2mb2 = a * a - b * b;
double t = initialAngle(a, b, x, y);
auto ct = cos(t);
auto st = sin(t);
int i;
double err;
for (i = 0; i < maxIter; i++) {
auto f = a2mb2 * ct * st - x * a * st + y * b * ct;
auto fp = a2mb2 * (ct * ct - st * st) - x * a * ct - y * b * st;
auto t2 = t - f / fp;
err = fabs(t2 - t);
//std::cout << i + 1 << " " << err << std::endl;
t = t2;
ct = cos(t);
st = sin(t);
if (err < maxError) break;
}
auto dx = a * ct - x;
auto dy = b * st - y;
//std::cout << a * ct << "," << b * st << std::endl;
return sqrt(dx * dx + dy * dy);
}

two circles collision

I have been testing collision between two circles using the method:
Circle A = (x1,y1) Circle b = (x2,y2)
Radius A Radius b
x1 - x2 = x' * x'
y1 - y2 = y' * y'
x' + y' = distance
square root of distance - Radius A + Radius B
and if the resulting answer is a negative number it is intersecting.
I have used this method in a test but it doesn't seem to be very accurate at all.
bool circle::intersects(circle & test)
{
Vector temp;
temp.setX(centre.getX() - test.centre.getX());
temp.setY(centre.getY() - test.centre.getY());
float distance;
float temp2;
float xt;
xt = temp.getX();
temp2 = xt * xt;
temp.setX(temp2);
xt = temp.getY();
temp2 = xt * xt;
temp.setY(temp2);
xt = temp.getX() + temp.getY();
distance = sqrt(xt);
xt = radius + test.radius;
if( distance - xt < test.radius)
{
return true;
}
else return false;
}
This is the function using this method maybe I'm wrong here. I just wondered what other methods I could use. I know separating axis theorem is better , but I wouldn't know where to start.
if( distance - xt < test.radius)
{
return true;
}
distance - xt will evaluate to the blue line, the distance between the two disks. It also meets the condition of being less than the test radius, but there is no collision going on.
The solution:
if(distance <= (radius + test.radius) )
return true;
Where distance is the distance from the centres.
Given: xt = radius + test.radius;
The correct test is: if( distance < xt)
Here is an attempt to re-write the body for you: (no compiler, so may be errors)
bool circle::intersects(circle & test)
{
float x = this->centre.getX() - test.centre.getX()
float y = this->centre.getY() - test.centre.getY()
float distance = sqrt(x*x+y*y);
return distance < (this->radius + test.radius);
}
Based on Richard solution but comparing the squared distance. This reduce the computation errors and the computation time.
bool circle::intersects(circle & test)
{
float x = this->centre.getX() - test.centre.getX()
float y = this->centre.getY() - test.centre.getY()
float distance2 = x * x + y * y;
float intersect_distance2 = (this->radius + test.radius) * (this->radius + test.radius);
return distance <= intersect_distance2;
}
Use Pythagoras theorem to compute the distance between the centres
That is a straight line
If they have collided then that distance is shorter that the sum of the two radiuses

Given two points, find a third point on the line

I have two points A (x1,y1) and B (x2,y2) that are given as an input to the program. I have to find a third point C that lies on the line AB and is at a distance 10 away from the point A.
I can easily get the slope of the line but that doesn't give me the full equation for the line. Even if I get the full equation, I am not sure using this equation, how would I find out a point that is x distance away from A.
Any suggestions on how to approach this?
There are always two points on each line:
get the vector from A to B (subtract the coordinates)
normalize the vector (divide by its length; pythagorean theorem)
multiply the vector by 10 or -10
add the vector to A to get C
Note that if A==B, the line is not defined, and this algorithm causes a division by zero. You may want to add a test for equality at the beginning.
You can use the sine or the cosine (times 10) of the angle of the line to get the horizontal or vertical distance of the point that is a distance of 10 from a given point. A shortcut is to use the horizontal or vertical distance divided by the direct distance between the points to get the sine or cosine.
You can do it using vectors like this:
Let D = the difference between B and A (D = B - A)
Then any point on the line can be described by this formula:
point = A + Dt
where t is a real number.
So just plug in any value for t to get another point. For example if you let t == 1 then the equation above reduces to point = B. If you let t = 0 then it reduces to point = A. So you can see that you can use this to find a point between A and B simply by let t range from 0 to 1. Additionally if you let t > 1, you will find a point past B.
You can see from the image that your given points are x1,y1 and x2,y2. You need to find an intermediate point at a distance 'R' from point x1,y1.
All you need to do is to find θ using
Tan θ = (y2-y1)/(x2-x1)
Then you can get the intermediate point as (R * cos θ),(R * Sin θ)
I have drawn this assuming positive slope.
Going on similar lines you can seek a solution for other special cases lile:
i. Horizontal line
ii. Vertical line
iii. Negative slope
Hope it clarifies.
I have done the calculation in Andengine using a Sprite object. I have two Array List x coordinates and y coordinates. Here i am just calculating using the last two values from these two array list to calculate the third point 800 pixel distant from Your point B. you can modify it using different values other than 800. Hope it will work.The coordinate system here is a little different where (0,0) on the top left corner of the screen. Thanks
private void addExtraCoordinate(CarSprite s) {
int x0, y0, x1, y1;
float x = 0f, y = 0f;
x0 = Math.round(xCoordinates.get(xCoordinates.size() - 2));
x1 = Math.round(xCoordinates.get(xCoordinates.size() - 1));
y0 = Math.round(yCoordinates.get(yCoordinates.size() - 2)) * (-1);
y1 = Math.round(yCoordinates.get(yCoordinates.size() - 1)) * (-1);
if (x1 == x0 && y1 == y0) {
return;
} else if (y1 == y0 && x1 != x0) {
if (x1 > x0) {
x = (float) x1 + 800f;
} else
x = (float) x1 - 800f;
y = Math.round(yCoordinates.get(yCoordinates.size() - 1));
} else if (y1 != y0 && x1 == x0) {
if (y1 > y0) {
y = (float) Math.abs(y1) - 800f;
} else
y = (float) Math.abs(y1) + 800f;
x = Math.round(xCoordinates.get(xCoordinates.size() - 1));
} else {
float m = (float) (yCoordinates.get(yCoordinates.size() - 1) * (-1) - yCoordinates
.get(yCoordinates.size() - 2) * (-1))
/ (float) (xCoordinates.get(xCoordinates.size() - 1) - xCoordinates
.get(xCoordinates.size() - 2));
if (x1 > x0) {
x = (float) ((float) x1 + 800f / (float) Math
.sqrt((double) ((double) 1f + (double) (m * m))));
} else
x = (float) ((float) x1 - 800f / (float) Math
.sqrt((double) ((double) 1f + (double) (m * m))));
if (y0 > y1) {
y = (float) ((float) Math.abs(y1) + 800f / (float) Math
.sqrt((double) (((double) 1f / (double) (m * m)) + (double) 1f)));
} else
y = (float) ((float) Math.abs(y1) - 800f / (float) Math
.sqrt((double) (((double) 1f / (double) (m * m)) + (double) 1f)));
}
xCoordinates.add(x);
yCoordinates.add(y);
}