how is the quadratic formula used in game coding? - c++

hello guys i am game programmer from korea.
and just today i found a some code that use the QUADRATIC formula for calculating something. here is code
hduVector3Dd p = startPoint;
hduVector3Dd v = endPoint - startPoint;
// Solve the intersection implicitly using the quadratic formula.
double a = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
double b = 2 * (p[0]*v[0] + p[1]*v[1] + p[2]*v[2]);
double c = p[0]*p[0] + p[1]*p[1] + p[2]*p[2] - m_radius * m_radius;
double disc = b*b - 4*a*c;
// The scale factor that must be applied to v so that p + nv is
// on the sphere.
double n;
if(disc == 0.0)
{
n = (-b)/(2*a);
}
else if(disc > 0.0)
{
double posN = (-b + sqrt(disc))/(2*a);
double negN = (-b - sqrt(disc))/(2*a);
n = posN < negN ? posN : negN;
}
else
{
return false;
}
// n greater than one means that the ray defined by the two points
// intersects the sphere, but beyond the end point of the segment.
// n less than zero means that the intersection is 'behind' the
// start point.
if(n > 1.0 || n < 0.0)
{
return false;
}
this is the part of function that checking SOMETHING for sphere shape.
and i couldn't figure out why use QUADRATIC FORMULA for calculating SOMETHING.
any idea, will be preciated
i just really wanna know, understand and reuse it for my code in the future^^

It looks like it is doing a line-sphere collision check.
I'm not exactly sure where one would use this though(I could be dumb xD)

Related

Intersection of ray and ellipsoid

Yes, I know that it is a popular problem. But I found nowhere the full clear implementing code without using OpenGL classes or a lot of headers files.
Okay, the math solution is to transfer ellipsoid to sphere. Then find intersections dots (if they exist of course) and make inverse transformation. Because affine transformation respect intersection.
But I have difficulties when trying to implement this.
I tried something for sphere but it is completely incorrect.
double CountDelta(Point X, Point Y, Sphere S)
{
double a = 0.0;
for(int i = 0; i < 3; i++){
a += (Y._coordinates[i] - X._coordinates[i]) * (Y._coordinates[i] - X._coordinates[i]);
}
double b = 0.0;
for(int i = 0; i < 3; i++)
b += (Y._coordinates[i] - X._coordinates[i]) * (X._coordinates[i] - S._coordinates[i]);
b *= 2;
double c = - S.r * S.r;
for(int i = 0; i < 3; i++)
c += (X._coordinates[i] - S._coordinates[i]) * (X._coordinates[i] - S._coordinates[i]);
return b * b - 4 * a * c;
}
Let I have start point P = (Px, Py, Pz), direction V = (Vx, Vy, Vz), ellipsoid = (Ex, Ey, Ec) and (a, b, c). How to construct clear code?
Let a line from P to P + D intersecting a sphere of center C and radius R.
WLOG, C can be the origin and R unit (otherwise translate by -C and scale by 1/R). Now using the parametric equation of the line and the implicit equation of the sphere,
(Px + t Dx)² + (Py + t Dy)² + (Pz + t Dz)² = 1
or
(Dx² + Dy² + Dz²) t² + 2 (Dx Px + Dy Py + Dz Pz) t + Px² + Py² + Pz² - 1 = 0
(Vectorially, D² t² + 2 D P t + P² - 1 = 0 and t = (- D P ±√((D P)² - D²(P² - 1))) / D².)
Solve this quadratic equation for t and get the two intersections as P + t D. (Don't forget to invert the initial transformations.)
For the ellipsoid, you can either plug the parametric equation of the line directly into the implicit equation of the conic, or reduce the conic (and the points simultaneously) and plug in the reduced equation.

How can I calculate the curvature of an extracted contour by opencv?

I did use the findcontours() method to extract contour from the image, but I have no idea how to calculate the curvature from a set of contour points. Can somebody help me? Thank you very much!
While the theory behind Gombat's answer is correct, there are some errors in the code as well as in the formulae (the denominator t+n-x should be t+n-t). I have made several changes:
use symmetric derivatives to get more precise locations of curvature maxima
allow to use a step size for derivative calculation (can be used to reduce noise from noisy contours)
works with closed contours
Fixes:
* return infinity as curvature if denominator is 0 (not 0)
* added square calculation in denominator
* correct checking for 0 divisor
std::vector<double> getCurvature(std::vector<cv::Point> const& vecContourPoints, int step)
{
std::vector< double > vecCurvature( vecContourPoints.size() );
if (vecContourPoints.size() < step)
return vecCurvature;
auto frontToBack = vecContourPoints.front() - vecContourPoints.back();
std::cout << CONTENT_OF(frontToBack) << std::endl;
bool isClosed = ((int)std::max(std::abs(frontToBack.x), std::abs(frontToBack.y))) <= 1;
cv::Point2f pplus, pminus;
cv::Point2f f1stDerivative, f2ndDerivative;
for (int i = 0; i < vecContourPoints.size(); i++ )
{
const cv::Point2f& pos = vecContourPoints[i];
int maxStep = step;
if (!isClosed)
{
maxStep = std::min(std::min(step, i), (int)vecContourPoints.size()-1-i);
if (maxStep == 0)
{
vecCurvature[i] = std::numeric_limits<double>::infinity();
continue;
}
}
int iminus = i-maxStep;
int iplus = i+maxStep;
pminus = vecContourPoints[iminus < 0 ? iminus + vecContourPoints.size() : iminus];
pplus = vecContourPoints[iplus > vecContourPoints.size() ? iplus - vecContourPoints.size() : iplus];
f1stDerivative.x = (pplus.x - pminus.x) / (iplus-iminus);
f1stDerivative.y = (pplus.y - pminus.y) / (iplus-iminus);
f2ndDerivative.x = (pplus.x - 2*pos.x + pminus.x) / ((iplus-iminus)/2*(iplus-iminus)/2);
f2ndDerivative.y = (pplus.y - 2*pos.y + pminus.y) / ((iplus-iminus)/2*(iplus-iminus)/2);
double curvature2D;
double divisor = f1stDerivative.x*f1stDerivative.x + f1stDerivative.y*f1stDerivative.y;
if ( std::abs(divisor) > 10e-8 )
{
curvature2D = std::abs(f2ndDerivative.y*f1stDerivative.x - f2ndDerivative.x*f1stDerivative.y) /
pow(divisor, 3.0/2.0 ) ;
}
else
{
curvature2D = std::numeric_limits<double>::infinity();
}
vecCurvature[i] = curvature2D;
}
return vecCurvature;
}
For me curvature is:
where t is the position inside the contour and x(t) resp. y(t) return the related x resp. y value. See here.
So, according to my definition of curvature, one can implement it this way:
std::vector< float > vecCurvature( vecContourPoints.size() );
cv::Point2f posOld, posOlder;
cv::Point2f f1stDerivative, f2ndDerivative;
for (size_t i = 0; i < vecContourPoints.size(); i++ )
{
const cv::Point2f& pos = vecContourPoints[i];
if ( i == 0 ){ posOld = posOlder = pos; }
f1stDerivative.x = pos.x - posOld.x;
f1stDerivative.y = pos.y - posOld.y;
f2ndDerivative.x = - pos.x + 2.0f * posOld.x - posOlder.x;
f2ndDerivative.y = - pos.y + 2.0f * posOld.y - posOlder.y;
float curvature2D = 0.0f;
if ( std::abs(f2ndDerivative.x) > 10e-4 && std::abs(f2ndDerivative.y) > 10e-4 )
{
curvature2D = sqrt( std::abs(
pow( f2ndDerivative.y*f1stDerivative.x - f2ndDerivative.x*f1stDerivative.y, 2.0f ) /
pow( f2ndDerivative.x + f2ndDerivative.y, 3.0 ) ) );
}
vecCurvature[i] = curvature2D;
posOlder = posOld;
posOld = pos;
}
It works on non-closed pointlists as well. For closed contours, you may would like to change the boundary behavior (for the first iterations).
UPDATE:
Explanation for the derivatives:
A derivative for a continuous 1 dimensional function f(t) is:
But we are in a discrete space and have two discrete functions f_x(t) and f_y(t) where the smallest step for t is one.
The second derivative is the derivative of the first derivative:
Using the approximation of the first derivative, it yields to:
There are other approximations for the derivatives, if you google it, you will find a lot.
Here's a python implementation mainly based on Philipp's C++ code. For those interested, more details on the derivation can be found in Chapter 10.4.2 of:
Klette & Rosenfeld, 2004: Digital Geometry
def getCurvature(contour,stride=1):
curvature=[]
assert stride<len(contour),"stride must be shorther than length of contour"
for i in range(len(contour)):
before=i-stride+len(contour) if i-stride<0 else i-stride
after=i+stride-len(contour) if i+stride>=len(contour) else i+stride
f1x,f1y=(contour[after]-contour[before])/stride
f2x,f2y=(contour[after]-2*contour[i]+contour[before])/stride**2
denominator=(f1x**2+f1y**2)**3+1e-11
curvature_at_i=np.sqrt(4*(f2y*f1x-f2x*f1y)**2/denominator) if denominator > 1e-12 else -1
curvature.append(curvature_at_i)
return curvature
EDIT:
you can use convexityDefects from openCV, here's a link
a code example to find fingers based in their contour (variable res) source
def calculateFingers(res,drawing): # -> finished bool, cnt: finger count
# convexity defect
hull = cv2.convexHull(res, returnPoints=False)
if len(hull) > 3:
defects = cv2.convexityDefects(res, hull)
if type(defects) != type(None): # avoid crashing. (BUG not found)
cnt = 0
for i in range(defects.shape[0]): # calculate the angle
s, e, f, d = defects[i][0]
start = tuple(res[s][0])
end = tuple(res[e][0])
far = tuple(res[f][0])
a = math.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)
b = math.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)
c = math.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)
angle = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) # cosine theorem
if angle <= math.pi / 2: # angle less than 90 degree, treat as fingers
cnt += 1
cv2.circle(drawing, far, 8, [211, 84, 0], -1)
return True, cnt
return False, 0
in my case, i used about the same function to estimate the bending of board while extracting the contour
OLD COMMENT:
i am currently working in about the same, great information in this post, i'll come back with a solution when i'll have it ready
from Jonasson's answer, Shouldn't be here a tuple on the right side too?, i believe it won't unpack:
f1x,f1y=(contour[after]-contour[before])/stride
f2x,f2y=(contour[after]-2*contour[i]+contour[before])/stride**2

Ray Tracing - Geometric Sphere Intersection - Intersection function returns true for all rays despite no intersection

I am writing a ray tracing project with C++ and OpenGL and am running into some obstacles with my sphere intersection function: I've checked multiple sources and the math looks right, but for some reason for every single ray, the intersection method is returning true. Here is the code to the sphere intersection function as well as some other code for clarification:
bool intersect(Vertex & origin, Vertex & rayDirection, float intersection)
{
bool insideSphere = false;
Vertex oc = position - origin;
float tca = 0.0;
float thcSquared = 0.0;
if (oc.length() < radius)
insideSphere = true;
tca = oc.dot(rayDirection);
if (tca < 0 && !insideSphere)
return false;
thcSquared = pow(radius, 2) - pow(oc.length(), 2) + pow(tca, 2);
if (thcSquared < 0)
return false;
insideSphere ? intersection = tca + sqrt(thcSquared) : intersection = tca - sqrt(thcSquared);
return true;
}
Here is some context from the ray tracing function that calls the intersection function. FYI my camera is at (0, 0, 0) and that is what is in my "origin" variable in the ray tracing function:
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define WINDOW_METERS_WIDTH 30
#define WINDOW_METERS_HEIGHT 20
#define FOCAL_LENGTH 25
rayDirection.z = FOCAL_LENGTH * -1;
for (int r = 0; r < WINDOW_HEIGHT; r++)
{
rayDirection.y = (WINDOW_METERS_HEIGHT / 2 * -1) + (r * ((float)WINDOW_METERS_HEIGHT / (float)WINDOW_HEIGHT));
for (int c = 0; c < WINDOW_WIDTH; c++)
{
intersection = false;
t = 0.0;
rayDirection.x = (WINDOW_METERS_WIDTH / 2 * -1) + (c * ((float)WINDOW_METERS_WIDTH / (float)WINDOW_WIDTH));
rayDirection = rayDirection - origin;
for (int i = 0; i < NUM_SPHERES; i++)
{
if (spheres[i].intersect(CAM_POS, rayDirection, t))
{
intersection = true;
}
}
Thanks for taking a look and let me know if there is any other code that may help!
It seems you got your math a bit mixed. The first part of the function, ie until the first return false, is ok and will return false if the ray start outside of the sphere and don't go toward it. However, I think you put the camera outside all your spheres in such a manner that all spheres are visible, that's why this part never return false.
thcSquared is really wrong and I don't know what it is supposed to represent.
Let's do the intersection mathematically. We have:
origin : the start of the ray, let's call this A
rayDirection : the direction of the infinite ray, let's call this d.
position : the center of the sphere, called P
radius : self-explanatory, called r
What you want is a point on both the sphere and the line, let's call it M:
M = A + t * d because it is on the line
|M - P| = r because it is on the sphere
The second equation can be changed to be |A + t * d - P|² = r², which gives (A - P)² + 2 * t * (A - P).dot(d) + t²d² = r². This is a simple quadratic equation. Once solved, you have 0, 1 or 2 solutions, select the closest to the ray origin (but which is positive).
edit: You are forced to use another approach that I will detail here:
Compute the distance between the center of the sphere and the line (calling it l). This is done by 'projecting' the center on the line. So:
tca = ( (P - A) dot d ) / |d|, or with your variable names, tca = (OC dot rd) / |rd|. The projection is H = A + tca * d, and l = |H - P|.
If l > R then return false, there is no intersection.
Let's call M one intersection point. The triangle MHP have a right angle, so MH² + HP² = MP², in other terms thc² + l² = r², so we now have thc, the distance from H to the sphere.
With all that, t = tca +- thc, simply take the lowest non-negative of the two.
The paper you linked explain this, but without saying that it assumes the norm of the ray direction to be 1. I don't see a normalization in your code, that may be why your code fails (not verified).
Side note: the name Vertex for a 3d vector is really badly chosen, something like Vector3 or vec3 would be way better.

How to do ray plane intersection?

How do I calculate the intersection between a ray and a plane?
Code
This produces the wrong results.
float denom = normal.dot(ray.direction);
if (denom > 0)
{
float t = -((center - ray.origin).dot(normal)) / denom;
if (t >= 0)
{
rec.tHit = t;
rec.anyHit = true;
computeSurfaceHitFields(ray, rec);
return true;
}
}
Parameters
ray represents the ray object.
ray.direction is the direction vector.
ray.origin is the origin vector.
rec represents the result object.
rec.tHit is the value of the hit.
rec.anyHit is a boolean.
My function has access to the plane:
center and normal defines the plane
As wonce commented, you want to also allow the denominator to be negative, otherwise you will miss intersections with the front face of your plane. However, you still want a test to avoid a division by zero, which would indicate the ray being parallel to the plane. You also have a superfluous negation in your computation of t. Overall, it should look like this:
float denom = normal.dot(ray.direction);
if (abs(denom) > 0.0001f) // your favorite epsilon
{
float t = (center - ray.origin).dot(normal) / denom;
if (t >= 0) return true; // you might want to allow an epsilon here too
}
return false;
First consider the math of the ray-plane intersection:
In general one intersects the parametric form of the ray, with the implicit form of the geometry.
So given a ray of the form x = a * t + a0, y = b * t + b0, z = c * t + c0;
and a plane of the form: A x * B y * C z + D = 0;
now substitute the x, y and z ray equations into the plane equation and you will get a polynomial in t. you then solve that polynomial for the real values of t. With those values of t you can back substitute into the ray equation to get the real values of x, y and z.
Here it is in Maxima:
Note that the answer looks like the quotient of two dot products!
The normal to a plane is the first three coefficients of the plane equation A, B, and C.
You still need D to uniquely determine the plane.
Then you code that up in the language of your choice like so:
Point3D intersectRayPlane(Ray ray, Plane plane)
{
Point3D point3D;
// Do the dot products and find t > epsilon that provides intersection.
return (point3D);
}
Math
Define:
Let the ray be given parametrically by q = p + t*v for initial point p and direction vector v for t >= 0.
Let the plane be the set of points r satisfying the equation dot(n, r) + d = 0 for normal vector n = (a, b, c) and constant d. Fully expanded, the plane equation may also be written in the familiar form ax + by + cz + d = 0.
The ray-plane intersection occurs when q satisfies the plane equation. Substituting, we have:
d = -dot(n, q)
= -dot(n, p + t * v)
= -dot(n, p) + t * dot(n, v)
Rearranging:
t = -(dot(n, p) + d) / dot(n, v)
This value of t can be used to determine the intersection by plugging it back into p + t*v.
Example implementation
std::optional<vec3> intersectRayWithPlane(
vec3 p, vec3 v, // ray
vec3 n, float d // plane
) {
float denom = dot(n, v);
// Prevent divide by zero:
if (abs(denom) <= 1e-4f)
return std::nullopt;
// If you want to ensure the ray reflects off only
// the "top" half of the plane, use this instead:
//
// if (-denom <= 1e-4f)
// return std::nullopt;
float t = -(dot(n, p) + d) / dot(n, v);
// Use pointy end of the ray.
// It is technically correct to compare t < 0,
// but that may be undesirable in a raytracer.
if (t <= 1e-4)
return std::nullopt;
return p + t * v;
}
implementation of vwvan's answer
Vector3 Intersect(Vector3 planeP, Vector3 planeN, Vector3 rayP, Vector3 rayD)
{
var d = Vector3.Dot(planeP, -planeN);
var t = -(d + Vector3.Dot(rayP, planeN)) / Vector3.Dot(rayD, planeN);
return rayP + t * rayD;
}

Box2D & Cocos2d-x finding future location of a body

I'm in the process of making a mobile game and am having trouble predicting the future location of a body/sprite pair. The method I am using to do this is below.
1 --futureX is passed in as the cocos2d sprite's location, found using CCSprite.getPosition().x
2 -- I am using b2Body values for acceleration and velocity, so I must correct the futureX coordinate by dividing it by PTM_RATIO (defined elsewhere)
3 -- the function solves for the time it will take for a the b2Body to reach the futureX position (based off of its x-direction acceleration and velocity) and then uses that time to determine where the futureY position for the body should be. I multiply by PTM_RATIO at the end because the coordinate is meant to be used for creating another sprite.
4 -- when solving for time I have two cases: one with x acceleration != 0 and one for x acceleration == 0.
5 -- I am using the quadratic formula and kinematic equations to solve my equations.
Unfortunately, the sprite I'm creating is not where I expect it to be. It ends up in the correct x location, however, the Y location is always too large. Any idea why this could be? Please let me know what other information is helpful here, or if there is an easier way to solve this!
float Sprite::getFutureY(float futureX)
{
b2Vec2 vel = this->p_body->GetLinearVelocity();
b2Vec2 accel = p_world->GetGravity();
//we need to solve a quadratic equation:
// --> 0 = 1/2(accel.x)*(time^2) + vel.x(time) - deltaX
float a = accel.x/2;
float b = vel.x;
float c = this->p_body->GetPosition().x - futureX/PTM_RATIO;
float t1;
float t2;
//if Acceleration.x is not 0, solve quadratically
if(a != 0 ){
t1 = (-b + sqrt( b * b - 4 * a * c )) / (2 * a);
t2 = (-b - sqrt( b * b - 4 * a * c )) / (2 * a);
//otherwise, solve linearly
}else{
t2 = -1;
t1 = (c/b)*(-1);
}
//now that we know how long it takes to get to posX, we can tell the y location on the sprites path
float time;
if(t1 >= 0){
time = t1;
}else{
time = t2;
}
float posY = this->p_body->GetPosition().y;
float futureY = (posY + (vel.y)*time + (1/2)*accel.y*(time*time))*PTM_RATIO;
return futureY;
}
SOLVED:
The issue was in this line:
float futureY = (posY + (vel.y)*time + (1/2)*accel.y*(time*time))*PTM_RATIO;
I needed to explicitley cast the (1/2) as a float. I fixed it with this:
float futureY = (posY + (vel.y)*time + (float).5*accel.y*(time*time))*PTM_RATIO;
Note, otherwise, the term with acceleration was evaluated to zero.