Skip to content

Instantly share code, notes, and snippets.

@kakajika
Last active March 28, 2016 09:51
Show Gist options
  • Save kakajika/bf4986e110f39310b257 to your computer and use it in GitHub Desktop.
Save kakajika/bf4986e110f39310b257 to your computer and use it in GitHub Desktop.
Android tap hit tester for lines, quadratic bezier curves, cubic bezier curves
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