Skip to content

Instantly share code, notes, and snippets.

@IlyaHalsky
Last active June 19, 2016 14:22
Show Gist options
  • Save IlyaHalsky/74e65e8cda5b24190fc34838f6049e44 to your computer and use it in GitHub Desktop.
Save IlyaHalsky/74e65e8cda5b24190fc34838f6049e44 to your computer and use it in GitHub Desktop.
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