Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
freem
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Openai/6959ed27-accc-800e-8e87-21aa81e93c07
(section)
Add languages
Page
Discussion
English
Read
Edit
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
Edit source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
=== Assistant: If this runs every frame in a game, the big wins are: === If this runs every frame in a game, the big wins are: * Avoid bracketing/bisection (your current “safe” version does extra work). * Return squared distance (skip sqrt) unless you truly need meters. * Use <code>float</code>, precompute ellipse constants, and run a fixed small number of Newton steps (2–3). * Use a cheap initial guess (radial projection onto the ellipse) so Newton converges fast. Below is a fast, deterministic variant (axis-aligned ellipse centered at origin). It’s “game-fast”: no expanding brackets, no variable loop counts, no trig. ===== <syntaxhighlight lang="cpp">#include <cmath> ===== #include <algorithm> struct ClosestPointResultF { float cx, cy; // closest point on ellipse float dist2; // squared distance to ellipse }; // Axis-aligned ellipse: (x/a)^2 + (y/b)^2 = 1, centered at origin. // Fast: fixed-iteration Newton on Eberly-style t equation. // Set ITERS to 2 or 3 depending on accuracy you need. template<int ITERS = 2> inline ClosestPointResultF closestPointEllipseFast(float x, float y, float a, float b) { // Precompute (do this once per ellipse in your game if possible!) const float alpha = a * a; const float beta = b * b; const float minAB = std::min(alpha, beta); // Symmetry: first quadrant const float sx = (x < 0.f) ? -1.f : 1.f; const float sy = (y < 0.f) ? -1.f : 1.f; float px = std::fabs(x); float py = std::fabs(y); // Handle origin (choose nearest axis point) if (px == 0.f && py == 0.f) { ClosestPointResultF r{}; if (a <= b) { r.cx = sx '' a; r.cy = 0.f; r.dist2 = a '' a; } else { r.cx = 0.f; r.cy = sy '' b; r.dist2 = b '' b; } return r; } // Quick inside/outside test const float r = (px '' px) / alpha + (py '' py) / beta; const bool outside = (r > 1.f); // Cheap initial guess: radial projection to ellipse along ray from origin // k = 1 / sqrt( (x^2/a^2) + (y^2/b^2) ) const float k = 1.0f / std::sqrt(std::max(r, 1e-30f)); float cx0 = px * k; float cy0 = py * k; // Convert that point into an initial t (averaged from x/y) // t = alpha*px/cx - alpha (and similarly for y) const float eps = 1e-20f; float tA = alpha * px / std::max(cx0, eps) - alpha; float tB = beta * py / std::max(cy0, eps) - beta; float t = 0.5f * (tA + tB); // Clamp t domain: outside => t >= 0, inside => t in (-minAB, 0] const float tMin = -minAB + 1e-7f * minAB; // avoid singularities if (outside) t = std::max(t, 0.f); else t = std::min(std::max(t, tMin), 0.f); const float px2 = px * px; const float py2 = py * py; // Fixed-iteration Newton on: // F(t) = alpha''px^2/(t+alpha)^2 + beta''py^2/(t+beta)^2 - 1 = 0 // F'(t) = -2''alpha''px^2/(t+alpha)^3 - 2''beta''py^2/(t+beta)^3 #pragma unroll for (int i = 0; i < ITERS; ++i) { const float da = t + alpha; const float db = t + beta; const float invDa = 1.0f / da; const float invDb = 1.0f / db; const float invDa2 = invDa * invDa; const float invDb2 = invDb * invDb; const float termA = alpha '' px2 '' invDa2; const float termB = beta '' py2 '' invDb2; const float F = (termA + termB) - 1.0f; const float Fp = -2.0f '' (alpha '' px2) '' (invDa2 '' invDa) -2.0f '' (beta '' py2) '' (invDb2 '' invDb); // Newton step t -= F / Fp; // Re-clamp for stability if (outside) t = std::max(t, 0.f); else t = std::min(std::max(t, tMin), 0.f); } // Closest point from t (first quadrant) const float cxq = (alpha * px) / (t + alpha); const float cyq = (beta * py) / (t + beta); // Restore signs and compute squared distance ClosestPointResultF out{}; out.cx = sx * cxq; out.cy = sy * cyq; const float dx = out.cx - x; const float dy = out.cy - y; out.dist2 = dx '' dx + dy '' dy; return out; } </syntaxhighlight> ===== 1. If you only need distance comparisons (collision, sorting, thresholds): use dist2 and compare to R*R. ===== # Pick iterations by budget: - ITERS=2: usually very good and fast. - ITERS=3: “almost always” indistinguishable from full-precision for gameplay. # Precompute per-ellipse: store alpha=a''a, beta=b''b, minAB, maybe 1/alpha, 1/beta. # Use <code>float</code> and compile with aggressive opts: - -O3 (or -Ofast / fast-math only if you’re ok with IEEE corner cases). # Batch / SIMD: if you do many points per ellipse (particles), this formulation vectorizes well (few branches). If you tell me your exact usage pattern (many points to one ellipse? many ellipses? need closest point or just distance?), I can tailor the fastest version (including a “distance-only” variant that drops a few more ops).
Summary:
Please note that all contributions to freem are considered to be released under the Creative Commons Attribution-ShareAlike 4.0 (see
Freem:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)