Last active
March 28, 2016 09:51
-
-
Save kakajika/bf4986e110f39310b257 to your computer and use it in GitHub Desktop.
Android tap hit tester for lines, quadratic bezier curves, cubic bezier curves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.PointF; | |
public class CurveHitTester { | |
private static final float FLT_EPSILON = 1.1920928955078125E-7f; | |
private static final float PI_2 = (float) Math.PI / 2.0f; | |
public static boolean hitTestLine(PointF point, PointF origin, PointF destination, float lineWidth) { | |
PointF[] vertices = new PointF[]{ origin, destination }; | |
return hitTestCurve(point, vertices, 1, lineWidth); | |
} | |
public static boolean hitTestQuad(PointF point, PointF origin, PointF control1, PointF destination, int segments, float lineWidth) { | |
if (segments <= 0) { | |
return false; | |
} | |
PointF[] vertices = new PointF[segments + 1]; | |
float t = 0; | |
for (int i = 0; i < segments; i++) { | |
float u = 1 - t; | |
float x = u * u * origin.x + 2.0f * u * t * control1.x + t * t * destination.x; | |
float y = u * u * origin.y + 2.0f * u * t * control1.y + t * t * destination.y; | |
vertices[i] = new PointF(x, y); | |
t += 1.0f / segments; | |
} | |
vertices[segments] = destination | |
return hitTestCurve(point, vertices, segments, lineWidth); | |
} | |
public static boolean hitTestCubic(PointF point, PointF origin, PointF control1, PointF control2, PointF destination, int segments, float lineWidth) { | |
if (segments <= 0) { | |
return false; | |
} | |
PointF[] vertices = new PointF[segments + 1]; | |
float t = 0; | |
for (int i = 0; i < segments; i++) { | |
float u = 1 - t; | |
float x = u * u * u * origin.x + 3.0f * u * u * t * control1.x + 3.0f * u * t * t * control2.x + t * t * t * destination.x; | |
float y = u * u * u * origin.y + 3.0f * u * u * t * control1.y + 3.0f * u * t * t * control2.y + t * t * t * destination.y; | |
vertices[i] = new PointF(x, y); | |
t += 1.0f / segments; | |
} | |
vertices[segments] = destination; | |
return hitTestCurve(point, vertices, segments, lineWidth); | |
} | |
private static boolean hitTestCurve(PointF point, PointF[] vertices, int segments, float lineWidth) { | |
for (int i = 0; i < segments; i++) { | |
PointF from = vertices[i]; | |
PointF to = vertices[i + 1]; | |
PointF center = new PointF((from.x + to.x) / 2, (from.y + to.y) / 2); | |
PointF pa = new PointF(point.x - center.x, point.y - center.y); | |
float l = (float) Math.sqrt(pa.x*pa.x + pa.y*pa.y); | |
float r = PI_2; | |
if (Math.abs(to.x - from.x) > FLT_EPSILON) { | |
r = (float) Math.tan((to.y - from.y) / (to.x - from.x)); | |
} | |
float r1 = PI_2; | |
if (Math.abs(pa.x) > FLT_EPSILON) { | |
r1 = (float) Math.tan(pa.y / pa.x); | |
} | |
float r2 = r1 - r; | |
PointF point_ = new PointF((float) (l * Math.cos(r2)), (float) (l * Math.sin(r2))); | |
float w = (float) Math.sqrt(Math.pow(center.x - from.x, 2) + Math.pow(center.y - from.y, 2)); | |
if (-w < point_.x && w > point_.x) { | |
if (-lineWidth / 2 < point_.y && lineWidth / 2 > point_.y) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment