

/*----------------------------------------------------------------------
class cPolygoni (class polygon, integer).

*******************************************************************
Octavia. 
My modifications:

The class has a new method, called ResetArm, called when the "MoveArm" button
is pressed and the user clicks near the last vertex in the chain, dragging 
it to a new position. 
The method calls "TwoCircles", that deals with the intersection of the two 
circles that would give us the new coordinates of the elbow (the elbow is
the next-to-last vertex). 
The main problem seems to appear when I'm converting from double (the inter
section points) back to intiger, so that I can draw on the screen. For each 
new point I am dragging, there is a rounding error that adds up to full
units in the end. 
This could be avoinded storing the lenghths of the last two edges separately, 
but the problem is that in order to compute the intersection in an easy way, 
I am translating and rotating the points so that the center of the first circle
is of coordinates (0,0) and the center of the second one (the new target) is 
(a2,0). 
When I'm rotating back, it seems like I'm loosing precision. 


*********************************************************************

Joe's comments:

This corresponds to cPolygoni in the C code: type polygon, integer.
It is primarily a circular list of its vertices, an object of
type cVertexList called "list."  Other data members are used for
various polygon computations: diaglist for a (circular) list
of diagonals, CG for the coordinates of the center of gravity,
and various structures for point-in-polygon queries not yet
fully implemented.

There are many methods for this class.  We tried to include those
here that are specific to polygons, as opposed to list routines,
or basic geometric routines based on a constant number of points.
They can be classified into three groups:
  1. Those relating to input of the polygon, especially editing:
     ReadPoly() for reading from sysin.
     ClearPolygon() to clean out the structures when the user clicks on
        the "clear" button.
     SetVertex() to fix the coordinates of a vertex.
     AddVertex() to add a new vertex in response to a user mouseclick.
  2. Those that perform some high-level polygon computation:
     PolyArea2() to compute the area.
     FindCG() to compute the CG.
     Ccw() to determine if the polygon was entered ccw.
     Triangulate() to triangulate.
     InPoly1() to determine if a point is in the polygon (not yet finished).
  3. Subsidiary methods needed by those in the second group:
     Centroid3(), EarInit(), etc. [a long list].

----------------------------------------------------------------------*/

  import java.lang.Math;

public class cPolygoni 
{	 
  static final int SCREENWIDTH = 350;	//max number of intersections 
  cVertexList list, listcopy;		//vertices of polygon
  cDiagonalList diaglist;
  cPointd CG;      	       	        //center of gravity;
					// or pt of intersection
  private int inters[] = new int [SCREENWIDTH];
  private int intCount = 0;		//counts intersections 
                                        //when shooting the array in inPoly1
  private boolean diagdrawn = true;     //diag-s've been drawn after triang?

  private Math myMath;


  private cVertex newpoint, c, q;

  cVertex v1, v2;

//Ota
  int r1, r2;
  public int intersection = 0; 
//intersection is used for determining the number of intersections of the
//two circles: 0 for point out of reach, 1 for two tangent circles, 
//2 for 2 intersections, 3 for identical circles. 

//Ota
  public cPolygoni() 
  {
    list = new cVertexList();
    listcopy = new cVertexList();
    diaglist = new cDiagonalList();
    CG = new cPointd(0,0);
    intCount = 0;
    diagdrawn = true;
  }

//Ota

public double Length (cPointi point1, cPointi point2)
//Computes the length of the link between two points

{

System.out.println("In Length");

return(myMath.sqrt((double)myMath.abs(((point1.x-point2.x)*(point1.x-point2.x)
		+(point1.y-point2.y)*(point1.y-point2.y)))));

}


public boolean ResetArm(int x, int y)
//Is called when the user drags the last point of the link or releases it. 

{
int rad1, rad2;
//the radii of the two circles

cPointi newelbow;
cPointi newpoint;

System.out.println("In Reset Arm now");

rad1= (int)Length(list.head.prev.prev.prev.v, list.head.prev.prev.v);
rad2= (int)Length(list.head.prev.prev.v, list.head.prev.v);

newpoint=new cPointi(x, y);

System.out.println("Rad 1 is now new"+rad1);
System.out.println("Rad 2 is now new"+ rad2);
System.out.println("shoulder coord now new:"+ list.head.prev.prev.prev.v.x+" , "+list.head.prev.prev.prev.v.y);
System.out.println("elbow coord now new:"+ list.head.prev.prev.v.x+ " , " +list.head.prev.prev.v.y);
System.out.println("hand coord now new:"+ list.head.prev.v.x+ " , "+list.head.prev.v.y);


System.out.println("Send new point p"+x+" , "+y);


newelbow=TwoCircles(list.head.prev.prev.prev.v, rad1, newpoint, rad2);
//call the method that would return the new point for the elbow.

if ((intersection==1)||(intersection==2) || (intersection==3))
//interserction holds the number of intersections of the two
//circles

{

System.out.println("new elbow after calling two circles is" + newelbow.x +" , "+newelbow.y);
System.out.println("intersections:"+intersection);

list.ResetVertex(list.head.prev.prev, newelbow.x, newelbow.y);
list.ResetVertex(list.head.prev, x, y);
//modify the list so that it holds the new points

System.out.println("Int ok");
return true;

}
else 
return false;
}

//*************************************************************

public cPointi TwoCircles (cPointi shoulder, int r1, cPointi hand, int r2)
{

System.out.println("in two circles");

cPointi p;
cPointi newhand = new cPointi(hand.x-shoulder.x, hand.y-shoulder.y);
//translate the points so that the center of the first circle is (0,0).
cPointi newshoulder = new cPointi(0, 0);


double dc, dc2;     //Distance to center 2 /squared

double rplus2, rminus2;      //r1+or- r2 squared; used for reachability tests

double f;        //fraction along newhand for intersection=1-when the circles are
//tangent

p= new cPointi(0, 0);

//Handle special cases:
//No intersection, one intersection(tangent circles), 3 intersections 
//(identical circles)

dc = Length (shoulder, hand); //distance to center of circle 2
dc2 = dc*dc;
System.out.println("dc2:"+ dc2);

rplus2 = (r1+r2)*(r1+r2);
rminus2=(r1-r2)*(r1-r2);

System.out.println("Rplus2:"+rplus2);
System.out.println("Rminus2:"+rminus2);

//No solution if newhand is out of reach + or -.

if ((dc2>rplus2) || (dc2<rminus2))
//out of reach
{
intersection=0;
System.out.println("Hand out of reach!");
//p=new cPointi(elbow.x, elbow.y);

}//end out of reach

else//here we have intersection != 0

{
//One solution if newhand just reached
//sol is r1-of-the-way (f) to newhand.


if (dc2 == rplus2)
{
	f=r1/((double)(r1+r2));
	p.x=(int)(f*newhand.x);
	p.y=(int)(f*newhand.y); 
	intersection=1;
}//end dc2==rplus2

if (dc2 == rminus2 )
{
	if (rminus2== 0)//ident. circles
	{
		p.x=r1;
		p.y=0;
	intersection=3;
	}//end rminus2==0; identical circles 

	else {//circles are tangent
	f=r1/((double)(r1-r2));
	p.x=(int)(f*newhand.x);
	p.y=(int)(f*newhand.y);
	intersection=1;
	}//end c. are tangent
}//end dc2==rminus2

else
{
//two intersections

double a2;
double qx, qy;
double cost, sint;//used for rotating to the x axes so that the coordinates 
//of the second circle are (a2, 0)

cPointd pd;

pd = new cPointd(0, 0);

//Rotate newhand to a2 on x-axis

float lc2;

lc2=(float)Length(shoulder, hand);

//a2=myMath.sqrt(myMath.abs(lc2*lc2));

a2=lc2;

System.out.println("a2:"+a2);

cost=newhand.x/a2;
sint=newhand.y/a2;

double r1sq, r2sq; //r1, r2 squared

r1sq=r1*r1;
r2sq=r2*r2;

//Return only positive-y soln in p

pd.x=(a2 +(r1sq -r2sq)/a2)/2;
pd.y=myMath.sqrt(myMath.abs((double)(r1sq - p.x*p.x)));

qx = pd.x;
qy = pd.y;


//Rotate back

p.x=(int)(cost * qx - sint*qy);
p.y=(int)(sint * qx + cost*qy);
intersection=2;

}//end else 
}

//translate back:

p.x=p.x+shoulder.x;
p.y=p.y+shoulder.y;

System.out.println("New point: "+p.x+" , "+p.y);


return p;

}//end Two Circles

//end Ota
//***********************************************************

  public void ClearPolygon()
  {
    list.ClearVertexList();
    listcopy.ClearVertexList();
    diaglist.ClearDiagonalList();
    CG.x = CG.y = 0;
    intCount = 0;
    for (int i = 0; i < SCREENWIDTH; i++)
      inters[i] = 0;
    System.out.println("Polygon cleared");
    diagdrawn = true;
    PrintPoly();
  }

  public void ClearDiagList()
  {
      diaglist.ClearDiagonalList();
  }

  public void ClearListCopy()
  {
    listcopy.ClearVertexList();
  }



  public void SetVertex(int x, int y)
  { 
    cVertex v = new cVertex( x, y );
    list.InsertBeforeHead( v );
  }

  public void AddVertex(int x, int y)
  {
    cVertex v = new cVertex(x, y);
    //gets vertex of 1st vertex of the closest edge to the point	
    cVertex vNear = list.GetEdge( x, y);
    if (vNear != null)
      list.InsertBefore(v, vNear.next );
  }

  public int GetIntCount()
  {
    return intCount;
  }

  public boolean DiagDrawn()
  {
    return diagdrawn;
  }
	
  public void SetDiagDrawn(boolean bool)
  {
    diagdrawn = bool;
  }

  public int GetInters(int i)
  {
    return inters[i];
  }
  
  /*See Chapter 7 for an explanation of this code
   *The only modification we make is that the polygon is *not* translated 
   *to place q=(0,0)
   */
  public char InPoly1(cPointi q)
  {
    int i = 0, i1;
    int d; 
    double x;
    int Rcross=0;
    int Lcross=0;
    boolean Rstrad,Lstrad;
    cVertex vtemp = list.head; 
    cVertex vtemp1;
    vtemp1 = list.head;
    intCount=0;
    
    //For each edge e = (i-1,i), see if crosses rays*/
    //This code deviates from that in Chapter 7: 
    //the polygon is *not* translated to move q to the origin
    do {
      /*First check if q =(0,0) is a vertex.*/
      if (vtemp.v.x == q.x && vtemp.v.y == q.y)
	return 'v';

      vtemp1 = new cVertex();
      vtemp1 = vtemp.prev;
      
      /*Check if e straddles x-axis, with bias above/below.*/
      Rstrad = ((vtemp.v.y-q.y) > 0) != ((vtemp1.v.y-q.y) > 0);
      Lstrad = ((vtemp.v.y-q.y) < 0) != ((vtemp1.v.y-q.y) < 0);
      
      if(Rstrad || Lstrad)
      {
	/*Compute intersection of e with x-axis.*/
	x = ((vtemp.v.x-q.x) * (vtemp1.v.y-q.y) - 
	     (vtemp1.v.x-q.x) * (vtemp.v.y-q.y))
	      /(double)((vtemp1.v.y-q.y) - (vtemp.v.y-q.y));  
	/* saving the x-coordinates for the intersections;*/
	inters[intCount] = (int) x + q.x;
	intCount += 1;				
	
	if(Rstrad && x > 0) Rcross++;
	if(Lstrad && x < 0) Lcross++;				
      }
      vtemp = vtemp.next;
      i++;
    } while (vtemp != list.head);
			
    /*q on an edge if L/Rcross counts are not the same parity*/
    if((Rcross % 2) != (Lcross % 2)) return 'e';
    /*q inside iff an odd number of crossings*/
    if((Rcross % 2) == 1) return 'i';
    else 
      return 'o'; 
  }

  /*Determine if the polygon is oriented counterclockwise (ccw).
   *(A more efficient method is possible, but here we use the available
   *AreaPoly2())
   */
  public int Ccw ()
  {
    int sign = AreaPoly2();
    if (sign > 0 ) return 1;
    else return -1;
  }

  public void FindCG()
  {
      double A2, areaSum2 = 0;  	//partial area sum
      cPointi Cent3 = new cPointi();
      cVertex temp = list.head;
      cPointi fixed = list.head.v;
      this.CG.x = 0;
      this.CG.y = 0;
      
      do {
	Cent3 = fixed.Centroid3( fixed, temp.v, temp.next.v);
	A2 = fixed.Area2(fixed,temp.v, temp.next.v);
	this.CG.x = CG.x + (A2 * Cent3.x);
	this.CG.y = CG.y + (A2 * Cent3.y);
	areaSum2 = areaSum2 + A2;
	temp = temp.next;
      } while (temp != list.head.prev);
      //Division by 3 is delayed to the last moment.
      this.CG.x = this.CG.x / (3*areaSum2);
      this.CG.y = this.CG.y / (3*areaSum2);
  }
  
  /*---------------------------------------------------------------------
   *Returns true iff (a,b) is a proper internal *or* external	
   *diagonal of P, *ignoring edges incident to a and b*.
   */
  public boolean Diagonalie( cVertex a, cVertex b )
  {
    cVertex c, c1;
    
    /* For each edge (c,c1) of P */
    c = listcopy.head;
    do {
      c1 = c.next;
      /* Skip edges incident to a or b */
	      if (    ( c != a ) && ( c1 != a )
		      && ( c != b ) && ( c1 != b )
		      && a.v.Intersect( a.v, b.v, c.v, c1.v )
		      )
		return false;
	      c = c.next;
    } while ( c != listcopy.head );
    return true;
  }


  /*---------------------------------------------------------------------
   *This function initializes the data structures, and calls
   *Triangulate2 to clip off the ears one by one.
   *Note that it operates on listcopy rather than list,
   *to coordinate with Triangulate()
   */
  public void EarInit()
  {
      cVertex v0, v1, v2;   /* three consecutive vertices */

      /* Initialize v1->ear for all vertices. */
      v1 = listcopy.head;
      do {
	v2 = v1.next;
	v0 = v1.prev;
	v1.ear = Diagonal( v0, v2 );
	v1 = v1.next;
      } while ( v1 != listcopy.head );
  }


  /*---------------------------------------------------------------------
   *Prints out n-3 diagonals (as pairs of integer indices)
   *which form a triangulation of P.  This algorithm is O(n^2).
   *See Chapter 1 for a full explanation.
   *Triangulate operates on listcopy rather than list, so that
   *the original polygon is not destroyed.
   */
  public void Triangulate()
  {
    cVertex v0, v1, v2, v3, v4;   // five consecutive vertices 
    cDiagonal diag;
    int   n = listcopy.n;         //number of vertices; shrinks to 3
    boolean earfound = false;     //to prevent infinite loop on improper input

    System.out.println("Triangualtion started...");
    EarInit();

    /* Each step of outer loop removes one ear. */
    while ( n > 3 ) {
      /* Inner loop searches for an ear. */
      v2 = listcopy.head;
      do {
	if (v2.ear) {
	  /* Ear found. Fill variables. */
	  v3 = v2.next; v4 = v3.next;
	  v1 = v2.prev; v0 = v1.prev;
	  
	  /* (v1,v3) is a diagonal */
	  earfound = true;
	  diag = new cDiagonal (v1, v3);
	  diag.PrintDiagonal(listcopy.n - n);
	  diaglist.InsertBeforeHead( diag );
	  
	  /* Update earity of diagonal endpoints */
	  v1.ear = Diagonal( v0, v3 );
	  v3.ear = Diagonal( v1, v4 );
	  
	  /* Cut off the ear v2 */
	  v1.next = v3;
	  v3.prev = v1;
	  listcopy.head = v3;      /* In case the head was v2. */
	  n--;
	  break;   /* out of inner loop; resume outer loop */
	} /* end if ear found */
	v2 = v2.next;
      } while ( v2 != listcopy.head );
      if (!earfound) {
	System.out.println("Polygon is nonsimple: cannot triangulate");
	break;
      }
      else
	earfound = false;
      diagdrawn = false;
    } /* end outer while loop */
  }
  
  /*---------------------------------------------------------------------
   *Creates a copy of list, with each new cell (temp2) pointing to 
   *the same cPointi object as in the corresponding old cell (temp1).
   */
  public void ListCopy() {
    cVertex temp1 = list.head, temp2;
    do {
      temp2 = new cVertex(); // Create a new vertex cell
      temp2.v = temp1.v;     // Fill it with the same cPointi as in list
      listcopy.InsertBeforeHead( temp2 );
      temp1 = temp1.next;
    } while (temp1 != list.head);
    System.out.println("Copied list:");
    listcopy.PrintVertices();
  }


  /*---------------------------------------------------------------------
   *Returns TRUE iff the diagonal (a,b) is strictly internal to the 
   *polygon in the neighborhood of the a endpoint.  
   */
  public boolean InCone( cVertex a, cVertex b )
  {
      cVertex a0,a1;	/* a0,a,a1 are consecutive vertices. */
      
      a1 = a.next;
      a0 = a.prev;
      
      /* If a is a convex vertex ... */
      if( a.v.LeftOn( a.v, a1.v, a0.v ) )
	return a.v.Left( a.v, b.v, a0.v )
	  &&   b.v.Left( b.v, a.v, a1.v );

      /* Else a is reflex: */
      return !(    a.v.LeftOn( a.v, b.v, a1.v )
		&& b.v.LeftOn( b.v, a.v, a0.v ) );
  }


  /*---------------------------------------------------------------------
   *Returns TRUE iff (a,b) is a proper internal diagonal.
   */
  public boolean Diagonal( cVertex a, cVertex b )
  {
    return InCone( a, b ) && InCone( b, a ) && Diagonalie( a, b );
  }

  public int AreaPoly2( )
  {
    int sum = 0;
    cVertex  a, p;
	
    p = list.head; /* Fixed   */
    a = p.next;    /* Moving. */
    do {
      sum += p.v.Area2( p.v, a.v, a.next.v );
      a = a.next;
    } while ( a.next != list.head );
    return sum;
    
  }

  public void PrintPoly()
  {
    cVertex v = list.head;
    int i=0;
    if (v == null)
      System.out.println("Polygon is empty");
    else 
      do {
	System.out.println("Vertex " + i + " (" + v.v.x + ", " + v.v.y + ")");
	i++;
	v = v.next;
      } while (v != list.head);
  }

/* --------------------------------------------------------------------- */
/*The following set of routines compute the (real) intersection point between
 *two segments.  The two segments are taken to be the first four edges of
 *the input "polygon" list.  A character "code" is returned and printed out.
 */
public char SegSegTopLevel( )
{
   // Set the segments ab and cd to be the first four points in the list.
   cVertex temp = list.head;
   cPointi a = temp.v;
   temp = temp.next;
   cPointi b = temp.v;
   temp = temp.next;
   cPointi c = temp.v;
   temp = temp.next;
   cPointi d = temp.v;

   // Store the results in class data field CG, and returns code.
   return SegSegInt( a, b, c, d, this.CG );

}
   
/*---------------------------------------------------------------------
SegSegInt: Finds the point of intersection p between two closed
segments ab and cd.  Returns p and a char with the following meaning:
   'e': The segments collinearly overlap, sharing a point.
   'v': An endpoint (vertex) of one segment is on the other segment,
        but 'e' doesn't hold.
   '1': The segments intersect properly (i.e., they share a point and
        neither 'v' nor 'e' holds).
   '0': The segments do not intersect (i.e., they share no points).
Note that two collinear segments that share just one point, an endpoint
of each, returns 'e' rather than 'v' as one might expect.
---------------------------------------------------------------------*/
public char SegSegInt( cPointi a, cPointi b, cPointi c, cPointi d, cPointd p )
{
   double  s, t;       /* The two parameters of the parametric eqns. */
   double num, denom;  /* Numerator and denoninator of equations. */
   char code = '?';    /* Return char characterizing intersection. */
   p.x = p.y = 100.0;  /* For testing purposes only... */

   denom = a.x * (double)( d.y - c.y ) +
           b.x * (double)( c.y - d.y ) +
           d.x * (double)( b.y - a.y ) +
           c.x * (double)( a.y - b.y );

   /* If denom is zero, then segments are parallel: handle separately. */
   if (denom == 0.0)
      return  ParallelInt(a, b, c, d, p);

   num =    a.x * (double)( d.y - c.y ) +
            c.x * (double)( a.y - d.y ) +
            d.x * (double)( c.y - a.y );
   if ( (num == 0.0) || (num == denom) ) code = 'v';
   s = num / denom;
   System.out.println("SegSegInt: num=" + num + ",denom=" + denom + ",s=" + s);

   num = -( a.x * (double)( c.y - b.y ) +
            b.x * (double)( a.y - c.y ) +
            c.x * (double)( b.y - a.y ) );
   if ( (num == 0.0) || (num == denom) ) code = 'v';
   t = num / denom;
   System.out.println("SegSegInt: num=" + num + ",denom=" + denom + ",t=" + t);

   if      ( (0.0 < s) && (s < 1.0) &&
             (0.0 < t) && (t < 1.0) )
     code = '1';
   else if ( (0.0 > s) || (s > 1.0) ||
             (0.0 > t) || (t > 1.0) )
     code = '0';

   p.x = a.x + s * ( b.x - a.x );
   p.y = a.y + s * ( b.y - a.y );

   return code;
}

public char ParallelInt( cPointi a, cPointi b, cPointi c, cPointi d, cPointd p )
{
   if ( !a.Collinear( a, b, c) )
      return '0';

   if ( Between1( a, b, c ) ) {
      Assigndi( p, c );
      return 'e';
   }
   if ( Between1( a, b, d ) ) {
      Assigndi( p, d );
      return 'e';
   }
   if ( Between1( c, d, a ) ) {
      Assigndi( p, a );
      return 'e';
   }
   if ( Between1( c, d, b ) ) {
      Assigndi( p, b );
      return 'e';
   }
   return '0';
}

public void Assigndi( cPointd p, cPointi a )
{
   p.x = a.x;
   p.y = a.y;
}
/*---------------------------------------------------------------------
Returns TRUE iff point c lies on the closed segement ab.
Assumes it is already known that abc are collinear.
(This is the only difference with Between().)
---------------------------------------------------------------------*/
public boolean Between1( cPointi a, cPointi b, cPointi c )
{
   cPointi      ba, ca;

   /* If ab not vertical, check betweenness on x; else on y. */
   if ( a.x != b.x )
      return ((a.x <= c.x) && (c.x <= b.x)) ||
             ((a.x >= c.x) && (c.x >= b.x));
   else
      return ((a.y <= c.y) && (c.y <= b.y)) ||
             ((a.y >= c.y) && (c.y >= b.y));
}


}//End class cPolygoni
