blob: d12f1109088b1818b560961185a0fc568fd20f0e [file] [log] [blame]
#include "delaunator.h"
#include <cstdio>
#include <limits>
#include <tuple>
#include <exception>
#include <cmath>
using namespace std;
namespace {
const double max_double = numeric_limits<double>::max();
double dist(
const double &ax,
const double &ay,
const double &bx,
const double &by
) {
const double dx = ax - bx;
const double dy = ay - by;
return dx * dx + dy * dy;
}
double circumradius(
const double &ax,
const double &ay,
const double &bx,
const double &by,
const double &cx,
const double &cy
) {
const double dx = bx - ax;
const double dy = by - ay;
const double ex = cx - ax;
const double ey = cy - ay;
const double bl = dx * dx + dy * dy;
const double cl = ex * ex + ey * ey;
const double d = dx * ey - dy * ex;
const double x = (ey * bl - dy * cl) * 0.5 / d;
const double y = (dx * cl - ex * bl) * 0.5 / d;
if (bl && cl && d) {
return x * x + y * y;
} else {
return max_double;
}
}
double area(
const double &px,
const double &py,
const double &qx,
const double &qy,
const double &rx,
const double &ry
) {
return (qy - py) * (rx - qx) - (qx - px) * (ry - qy);
}
tuple<double, double> circumcenter(
const double &ax,
const double &ay,
const double &bx,
const double &by,
const double &cx,
const double &cy
) {
const double dx = bx - ax;
const double dy = by - ay;
const double ex = cx - ax;
const double ey = cy - ay;
const double bl = dx * dx + dy * dy;
const double cl = ex * ex + ey * ey;
const double d = dx * ey - dy * ex;
const double x = ax + (ey * bl - dy * cl) * 0.5 / d;
const double y = ay + (dx * cl - ex * bl) * 0.5 / d;
return make_tuple(x, y);
}
double compare(
const vector<double> &coords,
unsigned long int i,
unsigned long int j,
double cx,
double cy
) {
const double d1 = dist(coords[2 * i], coords[2 * i + 1], cx, cy);
const double d2 = dist(coords[2 * j], coords[2 * j + 1], cx, cy);
const double diff1 = d1 - d2;
const double diff2 = coords[2 * i] - coords[2 * j];
const double diff3 = coords[2 * i + 1] - coords[2 * j + 1];
if (diff1) {
return diff1;
} else if(diff2) {
return diff2;
} else {
return diff3;
}
}
void quicksort(
unsigned long int ids[],
const vector<double> &coords,
unsigned int left,
unsigned int right,
double &cx,
double &cy
) {
long int i;
long int j;
unsigned long int temp;
if (right - left <= 20) {
for (i = left + 1; i <= right; i++) {
// printf("i=%lu\n", i);
temp = ids[i];
j = i - 1;
while (
j >= left &&
compare(coords, ids[j], temp, cx, cy) > 0
) {
// printf("j=%lu\n", j);
ids[j + 1] = ids[j];
j--;
}
ids[j + 1] = temp;
}
} else {
throw runtime_error("not implemented");
}// else {
// const median = (left + right) >> 1;
// i = left + 1;
// j = right;
// swap(ids, median, i);
// if (compare(coords, ids[left], ids[right], cx, cy) > 0) swap(ids, left, right);
// if (compare(coords, ids[i], ids[right], cx, cy) > 0) swap(ids, i, right);
// if (compare(coords, ids[left], ids[i], cx, cy) > 0) swap(ids, left, i);
// temp = ids[i];
// while (true) {
// do i++; while (compare(coords, ids[i], temp, cx, cy) < 0);
// do j--; while (compare(coords, ids[j], temp, cx, cy) > 0);
// if (j < i) break;
// swap(ids, i, j);
// }
// ids[left + 1] = ids[j];
// ids[j] = temp;
// if (right - i + 1 >= j - left) {
// quicksort(ids, coords, i, right, cx, cy);
// quicksort(ids, coords, left, j - 1, cx, cy);
// } else {
// quicksort(ids, coords, left, j - 1, cx, cy);
// quicksort(ids, coords, i, right, cx, cy);
// }
// }
}
void print_array(unsigned long int ids[], unsigned int size) {
printf("[");
for (unsigned int i = 0; i < size; i++) {
printf("%lu, ", ids[i]);
}
printf("]\n");
}
void print_array(const vector<int> &v) {
printf("[");
for (int i = 0; i < v.size(); i++) {
printf("%d, ", v[i]);
}
printf("]\n");
}
}
Delaunator::Delaunator(const vector<double> &coords) {
const long int n = coords.size() >> 1;
double max_x = -1 * max_double;
double max_y = -1 * max_double;
double min_x = max_double;
double min_y = max_double;
unsigned long int ids[n];
for (long int i = 0; i < n; i++) {
const double x = coords[2 * i];
const double y = coords[2 * i + 1];
// printf("%f %f", x, y);
if (x < min_x) min_x = x;
if (y < min_y) min_y = y;
if (x > max_x) max_x = x;
if (y > max_y) max_y = y;
ids[i] = i;
}
const double cx = (min_x + max_x) / 2;
const double cy = (min_y + max_y) / 2;
double min_dist = max_double;
unsigned long int i0;
unsigned long int i1;
unsigned long int i2;
// pick a seed point close to the centroid
for (unsigned long int i = 0; i < n; i++) {
const double d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
if (d < min_dist) {
i0 = i;
min_dist = d;
}
}
min_dist = max_double;
// find the point closest to the seed
for (unsigned long int i = 0; i < n; i++) {
if (i == i0) continue;
const double d = dist(coords[2 * i0], coords[2 * i0 + 1], coords[2 * i], coords[2 * i + 1]);
if (d < min_dist && d > 0)
{
i1 = i;
min_dist = d;
}
}
double min_radius = max_double;
// find the third point which forms the smallest circumcircle with the first two
for (unsigned long int i = 0; i < n; i++)
{
if (i == i0 || i == i1) continue;
const double r = circumradius(
coords[2 * i0], coords[2 * i0 + 1],
coords[2 * i1], coords[2 * i1 + 1],
coords[2 * i], coords[2 * i + 1]);
if (r < min_radius)
{
i2 = i;
min_radius = r;
}
}
if (min_radius == max_double) {
throw No_triangulation();
}
if (
area(
coords[2 * i0], coords[2 * i0 + 1],
coords[2 * i1], coords[2 * i1 + 1],
coords[2 * i2], coords[2 * i2 + 1]
) < 0
) {
const double tmp = i1;
i1 = i2;
i2 = tmp;
}
const double i0x = coords[2 * i0];
const double i0y = coords[2 * i0 + 1];
const double i1x = coords[2 * i1];
const double i1y = coords[2 * i1 + 1];
const double i2x = coords[2 * i2];
const double i2y = coords[2 * i2 + 1];
tie(m_center_x, m_center_y) = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);
// sort the points by distance from the seed triangle circumcenter
quicksort(ids, coords, 0, n - 1, m_center_x, m_center_y);
// print_array(ids, n);
m_hash_size = ceil(sqrt(n));
m_hash.reserve(m_hash_size);
for (int i = 0; i < m_hash_size; i++) m_hash.push_back(-1);
print_array(m_hash);
// printf("isnan(m_hash[0])=%d\n", isnan(m_hash[0]));
printf("m_hash[1]=%d\n", m_hash[1]);
// printf("i0x=%f i0y=%f", i0x, i0y);
};