Skip to content
Snippets Groups Projects
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);
      }
    }
  }
}