-
even authored728a7172
antipodal.cpp 7.37 KiB
#include "antipodal.h"
Antipodal::Antipodal ()
{
ix = 0;
iy = 1;
vpt = NULL;
ept1 = NULL;
ept2 = NULL;
}
void Antipodal::init (CHVertex *v1, CHVertex *v2, CHVertex *v3)
{
if (v1->get (iy) < v2->get (iy))
{
if (v2->get (iy) < v3->get (iy))
{
vpt = v2;
ept1 = v1;
ept2 = v3;
}
else
{
if (v1->get (iy) < v3->get (iy))
{
vpt = v3;
ept1 = v1;
ept2 = v2;
}
else
{
vpt = v1;
ept1 = v2;
ept2 = v3;
}
}
}
else
{
if (v1->get (iy) < v3->get (iy))
{
vpt = v1;
ept1 = v2;
ept2 = v3;
}
else
{
if (v2->get (iy) <= v3->get (iy)) // EQUIV : au lieu de "<" !!!
{
vpt = v3;
ept1 = v1;
ept2 = v2;
}
else
{
vpt = v2;
ept1 = v1;
ept2 = v3;
}
}
}
}
AbsRat Antipodal::rationalWidth () const
{
int den = ept2->get (iy) - ept1->get (iy);
return (AbsRat (((vpt->get (ix) - ept1->get (ix)) * den
- (vpt->get (iy) - ept1->get (iy))
* (ept2->get (ix) - ept1->get (ix))), den));
}
void Antipodal::width (int &num, int &den) const
{
den = ept2->get (iy) - ept1->get (iy);
if (den < 0) den = -den;
num = (vpt->get (ix) - ept1->get (ix)) * den
- (vpt->get (iy) - ept1->get (iy)) * (ept2->get (ix) - ept1->get (ix));
if (num < 0) num = -num;
}
int Antipodal::remainder (CHVertex *v) const
{
int a = ept2->y () - ept1->y ();
int b = ept2->x () - ept1->x ();
if (a == 0) return ((b > 0 ? -b : b) * v->y ());
if (a < 0)
{
a = -a;
b = -b;
}
return (a * v->x () - b * v->y ());
}
bool Antipodal::edgeInFirstQuadrant () const
{
if (iy) return true;
int a = ept2->y () - ept1->y ();
if (a == 0) return true;
return (a > 0 ? (ept1->x () < ept2->x ()) : (ept2->x () < ept1->x ()));
}
int Antipodal::getA () const
{
int a = ept2->y () - ept1->y ();
return (a < 0 ? -a : a);
}
int Antipodal::getB () const
{
int a = ept2->y () - ept1->y ();
int b = ept2->x () - ept1->x ();
if (a < 0) b = -b;
else if (a == 0 && b < 0) b = -b;
return (b);
}
ostream& operator<< (ostream &os, const Antipodal &ap)
{
os << (ap.ix ? "AV [" : "AH [") << *(ap.vpt) << " + ("
<< *(ap.ept1) << " - " << *(ap.ept2) << ")]";
if (ap.remainder (ap.vpt) == ap.remainder (ap.ept1)) os << "--HS--";
return os;
}
void Antipodal::update (CHVertex *pt)
{
CHVertex *rpt = pt->right ();
CHVertex *lpt = pt->left ();
int rmp = remainder (pt);
int rmv = remainder (vpt);
int rme = remainder (ept1);
int zpt = pt->get (iy); // vertical AP : Z -> X -- horizontal AP : Z -> Y
int zav = vpt->get (iy); // coord of antipodal vertex
int zas = ept1->get (iy); // coord of antipodal edge start
int zae = ept2->get (iy); // coord of antipodal edge end
CHVertex *pvertex;
if (remainder (rpt) == rmv) pvertex = rpt;
else if (remainder (lpt) == rmv) pvertex = lpt;
else pvertex = vpt;
CHVertex *pedge;
if (remainder (rpt) == rme) pedge = rpt;
else if (remainder (lpt) == rme) pedge = lpt;
else pedge = ept1;
// P on the line supported by the Edge
if (rmp == rme)
{
// P between start end end of antipodal Edge : no change (IMPOSSIBLE)
if ((zpt == zas) || (zpt == zae) || ((zpt < zas) != (zpt < zae))) return;
// -> prolongation of antipodal Edge up to P
setEdge (pt, pedge);
return;
}
// P on the line (parallel to Edge) supported by the Vertex
if (rmp == rmv)
{
// P at the height of Edge -> P is the new Vertex
if ((zpt == zas) || (zpt == zae) || ((zpt < zas) != (zpt < zae)))
setVertex (pt);
else
{
// P beyond Edge Start : -> the Edge Start is the new Vertex
if ((zas == zae) || ((zas < zpt) != (zas < zae))) setVertex (ept1);
// P beyond Edge End : -> the Edge End is the new Vertex
if ((zae < zpt) != (zae < zas)) setVertex (ept2);
// -> the new Edge joins P to the former Vertex
setEdge (pt, pvertex);
}
return;
}
// P strictly between antipodal Edge and Vertex -> no change
if ((rmp < rmv) != (rmp < rme)) return;
// P at the height of the antipodal Vertex
if (zpt == zav)
{
// P beyond the antipodal Vertex
if ((rmv < rmp) != (rmv < rme))
{
// -> P is the new Vertex
setVertex (pt);
return;
}
CHVertex *oldvpt = vpt;
if (zav != lpt->get (iy))
{
if (oldvpt->vprod (oldvpt->left (), lpt, pt) > 0)
{
setVertex (oldvpt);
setEdge (lpt, pt);
}
else
{
setVertex (pt);
setEdge (oldvpt, oldvpt->left ());
}
}
else
{
if (oldvpt->vprod (oldvpt->right (), rpt, pt) < 0)
{
setVertex (oldvpt);
setEdge (rpt, pt);
}
else
{
setVertex (pt);
setEdge (oldvpt, oldvpt->right ());
}
}
return;
}
// Main case
//==============================================================
CHVertex *cvx = NULL; // candidate rotation vertex
CHVertex *lvx, *rvx; // left and right vertices of candidate
int zvx; // coord of candidate
bool firstQuad = true;
if (edgeInFirstQuadrant ())
{
if (((rmp > rme) && (rmp > rmv) && (zpt > zav))
|| ((rmp < rme) && (rmp < rmv) && (zpt < zav))) firstQuad = false;
}
else
if (((rmp > rme) && (rmp > rmv) && (zpt < zav))
|| ((rmp < rme) && (rmp < rmv) && (zpt > zav))) firstQuad = false;
if (firstQuad)
{
if ((rme < rmp) != (rme < rmv)) cvx = pvertex;
if ((rmv < rme) != (rmv < rmp))
cvx = (ept1->right () == ept2 ? ept1 : ept2);
zvx = cvx->get (iy);
lvx = cvx->left ();
rvx = cvx->right ();
while (cvx->vprod (rvx, rpt, pt) > 0)
{
cvx = rvx;
lvx = cvx->left ();
rvx = cvx->right ();
zvx = cvx->get (iy);
int zpn = lvx->get (iy);
if ((zpt == zvx) || (zpt == zpn) || ((zpt < zvx) != (zpt < zpn))) break;
}
if (zvx == zpt)
{
if (cvx->vprod (rvx, rpt, pt) <= 0) // Au lieu de < chez Phuong
{
setVertex (cvx);
setEdge (rpt, pt);
}
else
{
setVertex (pt);
setEdge (cvx, rvx);
}
}
else
{
int zpn = rpt->get (iy);
if ((zvx == zpn) || ((zvx < zpt) != (zvx < zpn)))
{
setVertex (cvx);
setEdge (rpt, pt);
}
else
{
setVertex (pt);
setEdge (lvx, cvx);
}
}
}
else // second quadrant
{
if ((rme < rmp) != (rme < rmv)) cvx = pvertex;
if ((rmv < rme) != (rmv < rmp))
cvx = (ept1->left () == ept2 ? ept1 : ept2);
zvx = cvx->get (iy);
rvx = cvx->right ();
lvx = cvx->left ();
while (cvx->vprod (lvx, lpt, pt) < 0)
{
cvx = lvx;
rvx = cvx->right ();
lvx = cvx->left ();
zvx = cvx->get (iy);
int zvn = rvx->get (iy);
if ((zpt == zvx) || (zpt == zvn) || ((zpt < zvx) != (zpt < zvn))) break;
}
if (zvx == zpt)
{
if (cvx->vprod (lvx, lpt, pt) >= 0)
{
setVertex (cvx);
setEdge (lpt, pt);
}
else
{
setVertex (pt);
setEdge (cvx, lvx);
}
}
else
{
int zvn = lpt->get (iy);
if ((zvx == zvn) || ((zvx < zvn) != (zvx < zpt)))
{
setVertex (cvx);
setEdge (lpt, pt);
}
else
{
setVertex (pt);
setEdge (rvx, cvx);
}
}
}
}