Last active
June 19, 2016 14:22
-
-
Save IlyaHalsky/74e65e8cda5b24190fc34838f6049e44 to your computer and use it in GitHub Desktop.
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 java.util.ArrayList; | |
public class Main { | |
public static void main(String[] args) { | |
System.out.println(distance(0, 0, 3, 0, 1, 3.5, 2, 3.5, 10, 0.5)); | |
} | |
public static double distance(double ax0, double ay0, double bx0, double by0, double r0, double ax1, double ay1, double bx1, double by1, double r1) { | |
if (intersects(ax0, ay0, bx0, by0, ax1, ay1, bx1, by1)) { | |
return 0.0; | |
} | |
Pill pill0 = new Pill(ax0, ay0, bx0, by0, r0); | |
Pill pill1 = new Pill(ax1, ay1, bx1, by1, r1); | |
return pill0.distance(pill1); | |
} | |
private static boolean intersects(double ax0, double ay0, double bx0, double by0, double ax1, double ay1, double bx1, double by1) { | |
Vector ac = new Vector(ax0, ay0, ax1, ay1); | |
Vector ab = new Vector(ax0, ay0, bx0, by0); | |
Vector ad = new Vector(ax0, ay0, bx1, by1); | |
if (!checkOrder(false, ac, ab, ad)) { | |
return false; | |
} | |
Vector bc = new Vector(bx0, by0, ax1, ay1); | |
Vector ba = new Vector(bx0, by0, ax0, ay0); | |
Vector bd = new Vector(bx0, by0, bx1, by1); | |
if (!checkOrder(false, bc, ba, bd)) { | |
return false; | |
} | |
return true; | |
} | |
private static class Dot { | |
private double x; | |
private double y; | |
public String toString() { | |
return "( " + x + " , " + y + " )"; | |
} | |
Dot(double x, double y) { | |
this.x = x; | |
this.y = y; | |
} | |
double x() { | |
return x; | |
} | |
double y() { | |
return y; | |
} | |
} | |
private static class Pill { | |
Circle circleA; | |
Rectangle body; | |
Circle circleB; | |
Pill(double ax, double ay, double bx, double by, double r) { | |
circleA = new Circle(ax, ay, r); | |
body = new Rectangle(ax, ay, bx, by, r); | |
circleB = new Circle(bx, by, r); | |
} | |
double distance(Pill to) { | |
ArrayList<Double> distancesC = new ArrayList<>(); | |
distancesC.add(this.circleA.distance(to.circleA)); | |
distancesC.add(this.circleA.distance(to.circleB)); | |
distancesC.add(this.circleB.distance(to.circleA)); | |
distancesC.add(this.circleB.distance(to.circleB)); | |
double answer = distancesC.get(0); | |
for (double i : distancesC) { | |
if (answer > i) { | |
answer = i; | |
continue; | |
} | |
if (i < 0) { | |
answer = 0; | |
} | |
} | |
ArrayList<Double> distances = new ArrayList<>(); | |
distances.add(to.body.distance(this.circleB));//0 | |
distances.add(to.body.distance(this.circleA));//1 | |
distances.add(this.body.distance(to.circleA));//2 | |
distances.add(this.body.distance(to.circleB));//3 | |
distances.add(this.body.distance(to.body));//4 | |
for (Double i : distances) { | |
if (i != null && answer > i) { | |
answer = i; | |
continue; | |
} | |
} | |
return answer < 0.0 ? 0.0 : answer; | |
} | |
} | |
private static class Circle { | |
Dot center; | |
double radius; | |
Circle(double x, double y, double r) { | |
this.center = new Dot(x, y); | |
this.radius = r; | |
} | |
double distance(Circle to) { | |
return new Vector(x(), y(), to.x(), to.y()).length() - this.radius - to.radius; | |
} | |
double x() { | |
return this.center.x(); | |
} | |
double y() { | |
return this.center.y(); | |
} | |
} | |
private static class Rectangle { | |
Dot a; | |
Dot b; | |
Dot c; | |
Dot d; | |
Vector os; | |
Dot os_start; | |
Dot os_end; | |
double radius; | |
Rectangle(double ax, double ay, double bx, double by, double r) { | |
Vector axis = new Vector(ax, ay, bx, by); | |
this.os = axis; | |
this.os_start = new Dot(ax, ay); | |
this.os_end = new Dot(bx, by); | |
this.radius = r; | |
axis.normalize(); | |
Vector normal = axis.normal(); | |
this.a = new Dot(ax + normal.x() * r, ay + normal.y() * r); | |
this.b = new Dot(ax - normal.x() * r, ay - normal.y() * r); | |
this.c = new Dot(bx - normal.x() * r, by - normal.y() * r); | |
this.d = new Dot(bx + normal.x() * r, by + normal.y() * r); | |
} | |
Double distance(Circle to) { | |
Vector toa = new Vector(to.center, this.a); | |
Vector tob = new Vector(to.center, this.b); | |
Vector toc = new Vector(to.center, this.c); | |
Vector tod = new Vector(to.center, this.d); | |
if (checkSharp(this.os_end, this.os_start, to.center)) { | |
return height2(this.os, new Vector(this.os_start, to.center)) - to.radius - this.radius; | |
} | |
if (checkOrder(true, toa, tob, toc, tod)) { | |
return 0.0; | |
} | |
return null; | |
} | |
Double distance(Rectangle to) { | |
if (this.os.collinear(to.os) && checkSharp(this.os_end, this.os_start, to.os_end, to.os_start)) { | |
return height2(this.os, new Vector(this.os_start, to.os_start)) - this.radius - to.radius; | |
} | |
return null; | |
} | |
} | |
private static double height(Dot a, Dot b, Dot c) { | |
double AB = new Vector(a, b).length(); | |
double BC = new Vector(b, c).length(); | |
double CA = new Vector(c, a).length(); | |
double p = (AB + BC + CA) / 2; | |
return 2 * Math.sqrt(p * (p - AB) * (p - BC) * (p - CA)) / CA; | |
} | |
private static double height2(Vector a, Vector b) { | |
return Math.abs(a.mul(b) / a.length()); | |
} | |
private static boolean checkSharp(Dot a, Dot b, Dot... dots) { | |
Vector ab = new Vector(a, b); | |
Vector ab_reversed = ab.reverse(); | |
for (Dot i : dots) { | |
Vector ato = new Vector(a, i); | |
Vector bto = new Vector(b, i); | |
if (ato.mulsc(ab) > 0 && bto.mulsc(ab_reversed) > 0) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private static boolean checkOrder(boolean option, Vector... vectors) { | |
int sign = 0; | |
for (int i = 1; i < vectors.length; i++) { | |
Vector a = vectors[i - 1]; | |
Vector b = vectors[i]; | |
switch ((int) Math.signum(a.mul(b))) { | |
case -1: | |
if (sign == 0) { | |
sign = -1; | |
} else { | |
if (sign == 1) { | |
return false; | |
} | |
} | |
break; | |
case 0: | |
return false; | |
case 1: | |
if (sign == 0) { | |
sign = 1; | |
} else { | |
if (sign == -1) { | |
return false; | |
} | |
} | |
break; | |
} | |
} | |
Vector a = vectors[0]; | |
Vector b = vectors[vectors.length - 1]; | |
if (!option) { | |
if (Math.signum(a.mul(b)) != sign) { | |
return false; | |
} | |
} else { | |
if (Math.signum(a.mul(b)) != sign) { | |
return true; | |
} | |
} | |
return true; | |
} | |
private static class Vector { | |
Dot vector; | |
@Override | |
public String toString() { | |
return vector.toString(); | |
} | |
Vector(double fromx, double fromy, double tox, double toy) { | |
this.vector = new Dot(tox - fromx, toy - fromy); | |
} | |
Vector(Dot from, Dot to) { | |
this.vector = new Dot(to.x() - from.x(), to.y() - from.y()); | |
} | |
Vector(double tox, double toy) { | |
this.vector = new Dot(tox, toy); | |
} | |
Vector(Dot to) { | |
this.vector = new Dot(to.x(), to.y()); | |
} | |
Vector reverse() { | |
return new Vector(-this.vector.x(), -this.vector.y()); | |
} | |
double length2() { | |
return Math.pow(this.vector.x, 2) + Math.pow(this.vector.y, 2); | |
} | |
double length() { | |
return Math.sqrt(length2()); | |
} | |
void normalize() { | |
double l = this.length(); | |
this.vector = new Dot(this.vector.x / l, this.vector.y / l); | |
} | |
Vector normal() { | |
return new Vector(this.vector.y, -this.vector.x); | |
} | |
double mul(Vector with) { | |
return x() * with.y() - y() * with.x(); | |
} | |
double mulsc(Vector with) { | |
return x() * with.x() + y() * with.y(); | |
} | |
boolean collinear(Vector to) { | |
if (x() * to.y() - y() * to.x() == 0) { | |
return true; | |
} | |
return false; | |
} | |
double x() { | |
return this.vector.x(); | |
} | |
double y() { | |
return this.vector.y(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment