#include "cir2d.h"
#include "cir2d.hpp"
#include <core/heap.h>
#include <sewer/bmath.hpp>
#include <sewer/bmem.h>
#include <sewer/cassert.h>
struct Support
{
uint32_t n;
uint32_t index[3];
};
Cir2Df cir2df(const real32_t x, const real32_t y, const real32_t r)
{
Cir2Df c;
cassert(r >= 0);
c.c.x = x;
c.c.y = y;
c.r = r;
return c;
}
Cir2Dd cir2dd(const real64_t x, const real64_t y, const real64_t r)
{
Cir2Dd c;
cassert(r >= 0);
c.c.x = x;
c.c.y = y;
c.r = r;
return c;
}
template < typename real >
static Cir2D< real > i_from_box(const Box2D< real > *box)
{
Cir2D< real > cir;
V2D< real > d;
cir.c = Box2D< real >::center(box);
d.x = (box->max.x - box->min.x) / 2;
d.y = (box->max.y - box->min.y) / 2;
cir.r = V2D< real >::length(&d);
return cir;
}
Cir2Df cir2d_from_boxf(const Box2Df *box)
{
Cir2D< real32_t > c = i_from_box< real32_t >((const Box2D< real32_t > *)box);
Cir2Df *cc = (Cir2Df *)&c;
return *cc;
}
Cir2Dd cir2d_from_boxd(const Box2Dd *box)
{
Cir2D< real64_t > c = i_from_box< real64_t >((const Box2D< real64_t > *)box);
Cir2Dd *cc = (Cir2Dd *)&c;
return *cc;
}
template < typename real >
static Cir2D< real > i_from_points(const V2D< real > *p, const uint32_t n)
{
Cir2D< real > cir = Cir2D< real >(0, 0, 0);
uint32_t i;
cassert_no_null(p);
cassert(n > 0);
for (i = 0; i < n; ++i)
{
cir.c.x += p[i].x;
cir.c.y += p[i].y;
}
cir.c.x /= n;
cir.c.y /= n;
for (i = 0; i < n; ++i)
{
real sqdist = V2D< real >::sqdist(&p[i], &cir.c);
if (sqdist > cir.r)
cir.r = sqdist;
}
cir.r = BMath< real >::sqrt(cir.r);
return cir;
}
Cir2Df cir2d_from_pointsf(const V2Df *p, const uint32_t n)
{
Cir2D< real32_t > c = i_from_points((const V2D< real32_t > *)p, n);
Cir2Df *cc = (Cir2Df *)&c;
return *cc;
}
Cir2Dd cir2d_from_pointsd(const V2Dd *p, const uint32_t n)
{
Cir2D< real64_t > c = i_from_points((const V2D< real64_t > *)p, n);
Cir2Dd *cc = (Cir2Dd *)&c;
return *cc;
}
template < typename real >
static bool_t i_support(const Support *support, const uint32_t idx, const V2D< real > **p)
{
uint32_t i = 0;
cassert_no_null(support);
cassert(support->n <= 3);
for (i = 0; i < support->n; ++i)
{
if (V2D< real >::sqdist(p[idx], p[support->index[i]]) < (real).000001)
return TRUE;
}
return FALSE;
}
template < typename real >
static ___INLINE bool_t i_point_in_circle(const Cir2D< real > *cir, const V2D< real > *p)
{
real sqdist = V2D< real >::sqdist(p, &cir->c);
return sqdist <= cir->r ? TRUE : FALSE;
}
template < typename real >
static Cir2D< real > i_exact_circle1(const V2D< real > *p)
{
Cir2D< real > min;
cassert_no_null(p);
min.c = *p;
min.r = 0;
return min;
}
template < typename real >
static Cir2D< real > i_exact_circle2(const V2D< real > *p0, const V2D< real > *p1)
{
Cir2D< real > min;
cassert_no_null(p0);
cassert_no_null(p1);
min.c.x = (real).5 * (p0->x + p1->x);
min.c.y = (real).5 * (p0->y + p1->y);
min.r = (real).25 * V2D< real >::sqdist(p1, p0);
return min;
}
template < typename real >
static Cir2D< real > i_exact_circle3(const V2D< real > *p0, const V2D< real > *p1, const V2D< real > *p2)
{
V2D< real > e10 = V2D< real >::sub(p1, p0);
V2D< real > e20 = V2D< real >::sub(p2, p0);
real aafA[2][2];
real afB[2];
Cir2D< real > min;
real det;
aafA[0][0] = e10.x;
aafA[0][1] = e10.y;
aafA[1][0] = e20.x;
aafA[1][1] = e20.y;
afB[0] = (real)0.5 * V2D< real >::sqlength(&e10);
afB[1] = (real)0.5 * V2D< real >::sqlength(&e20);
det = aafA[0][0] * aafA[1][1] - aafA[0][1] * aafA[1][0];
if (BMath< real >::abs(det) > (real).000001)
{
real idet = 1 / det;
V2D< real > q;
q.x = (aafA[1][1] * afB[0] - aafA[0][1] * afB[1]) * idet;
q.y = (aafA[0][0] * afB[1] - aafA[1][0] * afB[0]) * idet;
min.c = V2D< real >::add(p0, &q);
min.r = V2D< real >::sqlength(&q);
}
else
{
min.c = *V2D< real >::kZERO;
min.r = BMath< real >::kINFINITY;
}
return min;
}
template < typename real >
static Cir2D< real > i_update_support1(uint32_t i, const V2D< real > **p, Support *support)
{
const V2D< real > *p0 = p[support->index[0]];
const V2D< real > *p1 = p[i];
Cir2D< real > min = i_exact_circle2< real >(p0, p1);
cassert_no_null(support);
support->n = 2;
support->index[i] = i;
return min;
}
template < typename real >
static Cir2D< real > i_update_support2(uint32_t i, const V2D< real > **p, Support *support)
{
const V2D< real > *p0 = p[support->index[0]];
const V2D< real > *p1 = p[support->index[1]];
const V2D< real > *p2 = p[i];
Cir2D< real > akC[2];
Cir2D< real > min;
real min_sqlen = BMath< real >::kINFINITY;
uint32_t idx = UINT32_MAX;
cassert_no_null(support);
akC[0] = i_exact_circle2< real >(p0, p2);
if (i_point_in_circle< real >(&akC[0], p1) == TRUE)
{
min_sqlen = akC[0].r;
idx = 0;
}
akC[1] = i_exact_circle2< real >(p1, p2);
if (i_point_in_circle< real >(&akC[1], p0) == TRUE)
{
if (akC[1].r < min_sqlen)
{
min_sqlen = akC[1].r;
idx = 1;
}
}
if (idx != UINT32_MAX)
{
cassert(idx <= 1);
min = akC[idx];
support->index[1 - idx] = i;
}
else
{
min = i_exact_circle3< real >(p0, p1, p2);
cassert(min.r <= min_sqlen);
support->n = 3;
support->index[2] = i;
}
return min;
}
template < typename real >
static Cir2D< real > i_update_support3(uint32_t i, const V2D< real > **p, Support *support)
{
const V2D< real > *p0 = p[support->index[0]];
const V2D< real > *p1 = p[support->index[1]];
const V2D< real > *p2 = p[support->index[2]];
const V2D< real > *p3 = p[i];
Cir2D< real > akC[6];
Cir2D< real > min;
real min_sqlen = BMath< real >::kINFINITY;
uint32_t idx = UINT32_MAX;
akC[0] = i_exact_circle2< real >(p0, p3);
if (i_point_in_circle< real >(&akC[0], p1) == TRUE && i_point_in_circle< real >(&akC[0], p2) == TRUE)
{
min_sqlen = akC[0].r;
idx = 0;
}
akC[1] = i_exact_circle2< real >(p1, p3);
if (i_point_in_circle< real >(&akC[1], p0) == TRUE && i_point_in_circle< real >(&akC[1], p2) == TRUE)
{
if (akC[1].r < min_sqlen)
{
min_sqlen = akC[1].r;
idx = 1;
}
}
akC[2] = i_exact_circle2< real >(p2, p3);
if (i_point_in_circle< real >(&akC[2], p0) == TRUE && i_point_in_circle< real >(&akC[2], p1) == TRUE)
{
if (akC[2].r < min_sqlen)
{
min_sqlen = akC[2].r;
idx = 2;
}
}
akC[3] = i_exact_circle3< real >(p0, p1, p3);
if (i_point_in_circle< real >(&akC[3], p2) == TRUE)
{
if (akC[3].r < min_sqlen)
{
min_sqlen = akC[3].r;
idx = 3;
}
}
akC[4] = i_exact_circle3< real >(p0, p2, p3);
if (i_point_in_circle< real >(&akC[4], p1) == TRUE)
{
if (akC[4].r < min_sqlen)
{
min_sqlen = akC[4].r;
idx = 4;
}
}
akC[5] = i_exact_circle3< real >(p1, p2, p3);
if (i_point_in_circle< real >(&akC[5], p0) == TRUE)
{
if (akC[5].r < min_sqlen)
{
min_sqlen = akC[5].r;
idx = 5;
}
}
cassert(idx != UINT32_MAX);
min = akC[idx];
switch (idx)
{
case 0:
support->n = 2;
support->index[1] = i;
break;
case 1:
support->n = 2;
support->index[0] = i;
break;
case 2:
support->n = 2;
support->index[0] = support->index[2];
support->index[1] = i;
break;
case 3:
cassert(support->n == 3);
support->index[2] = i;
break;
case 4:
cassert(support->n == 3);
support->index[1] = i;
break;
case 5:
cassert(support->n == 3);
support->index[0] = i;
break;
}
return min;
}
template < typename real >
static Cir2D< real > i_minimum(const V2D< real > *p, const uint32_t n)
{
Cir2D< real > min;
Support support;
const V2D< real > **perm = NULL;
uint32_t i = 0;
cassert(n > 0);
perm = heap_new_n(n, const V2D< real > *);
for (i = 0; i < n; i++)
perm[i] = &p[i];
bmem_shuffle_n(perm, n, const V2D< real > *);
min = i_exact_circle1< real >(perm[0]);
support.n = 1;
support.index[0] = 0;
i = 1;
while (i < n)
{
if (i_support< real >(&support, i, perm) == FALSE)
{
if (i_point_in_circle< real >(&min, perm[i]) == FALSE)
{
switch (support.n)
{
case 1:
min = i_update_support1< real >(i, perm, &support);
break;
case 2:
min = i_update_support2< real >(i, perm, &support);
break;
case 3:
min = i_update_support3< real >(i, perm, &support);
break;
cassert_default();
}
i = 0;
continue;
}
}
i++;
}
heap_delete_n(&perm, n, const V2D< real > *);
min.r = BMath< real >::sqrt(min.r);
return min;
}
Cir2Df cir2d_minimumf(const V2Df *p, const uint32_t n)
{
Cir2D< real32_t > c = i_minimum< real32_t >((const V2D< real32_t > *)p, n);
Cir2Df *cc = (Cir2Df *)&c;
return *cc;
}
Cir2Dd cir2d_minimumd(const V2Dd *p, const uint32_t n)
{
Cir2D< real64_t > c = i_minimum< real64_t >((const V2D< real64_t > *)p, n);
Cir2Dd *cc = (Cir2Dd *)&c;
return *cc;
}
template < typename real >
static real i_area(const Cir2D< real > *cir)
{
cassert_no_null(cir);
return BMath< real >::kPI * cir->r * cir->r;
}
real32_t cir2d_areaf(const Cir2Df *cir)
{
return i_area< real32_t >((const Cir2D< real32_t > *)cir);
}
real64_t cir2d_aread(const Cir2Dd *cir)
{
return i_area< real64_t >((const Cir2D< real64_t > *)cir);
}
template < typename real >
static bool_t i_is_null(const Cir2D< real > *cir)
{
cassert_no_null(cir);
return cir->r < 0 ? TRUE : FALSE;
}
bool_t cir2d_is_nullf(const Cir2Df *cir)
{
return i_is_null< real32_t >((const Cir2D< real32_t > *)cir);
}
bool_t cir2d_is_nulld(const Cir2Dd *cir)
{
return i_is_null< real64_t >((const Cir2D< real64_t > *)cir);
}
const Cir2Df kCIR2D_NULLf = {{0, 0}, -1};
const Cir2Dd kCIR2D_NULLd = {{0, 0}, -1};
template <>
const Cir2D< real32_t >(*Cir2D< real32_t >::kNULL) = ((Cir2D< real32_t > *)&kCIR2D_NULLf);
template <>
const Cir2D< real64_t >(*Cir2D< real64_t >::kNULL) = ((Cir2D< real64_t > *)&kCIR2D_NULLd);
template <>
Cir2D< real32_t > (*Cir2D< real32_t >::from_box)(const Box2D< real32_t > *) = i_from_box< real32_t >;
template <>
Cir2D< real64_t > (*Cir2D< real64_t >::from_box)(const Box2D< real64_t > *) = i_from_box< real64_t >;
template <>
Cir2D< real32_t > (*Cir2D< real32_t >::from_points)(const V2D< real32_t > *, const uint32_t) = i_from_points< real32_t >;
template <>
Cir2D< real64_t > (*Cir2D< real64_t >::from_points)(const V2D< real64_t > *, const uint32_t) = i_from_points< real64_t >;
template <>
Cir2D< real32_t > (*Cir2D< real32_t >::minimum)(const V2D< real32_t > *, const uint32_t) = i_minimum< real32_t >;
template <>
Cir2D< real64_t > (*Cir2D< real64_t >::minimum)(const V2D< real64_t > *, const uint32_t) = i_minimum< real64_t >;
template <>
real32_t (*Cir2D< real32_t >::area)(const Cir2D< real32_t > *) = i_area< real32_t >;
template <>
real64_t (*Cir2D< real64_t >::area)(const Cir2D< real64_t > *) = i_area< real64_t >;
template <>
bool_t (*Cir2D< real32_t >::is_null)(const Cir2D< real32_t > *) = i_is_null< real32_t >;
template <>
bool_t (*Cir2D< real64_t >::is_null)(const Cir2D< real64_t > *) = i_is_null< real64_t >;