// (c) MIT 2003.  All rights reserved.

// -*-Mode: Java-*- 
// $Id: WSquiggleArrow.java,v 1.8 2003/03/06 00:40:47 moltmans Exp $
// WSquiggleArrow.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Tue Oct 26 19:48:04 1999> 
// Time-stamp: <2000-07-18 13:55:44 moltmans> 
package rec.core.widgets;

import java.awt.*;
import java.util.*;
import rec.util.*;
import rec.sys.*;
import rec.geo.*;

/**
 * An arrow made from an arbitrary squiggle with an arrowhead.  The
 * "head" of the squiggle always refers to the head of the arrow.
 **/
public class WSquiggleArrow extends VisibleWidget
{
  protected GPolySegment m_PolySeg;
  protected GSegment m_Seg1;
  protected GSegment m_Seg2;


  public WSquiggleArrow( WSquiggleArrow arrow )
  {
    this( arrow.m_PolySeg, arrow.m_Seg1, arrow.m_Seg2 );
  }
  
  
  public WSquiggleArrow( GPolySegment polySeg, GSegment seg1, GSegment seg2 )
  {

    setEnglishName( "Arrow" );
    m_PolySeg = new GPolySegment( polySeg );
    m_Seg1 = new GSegment( seg1 );
    m_Seg2 = new GSegment( seg2 );
  }
  
  public WSquiggleArrow( Squiggle squiggle, GPoint head, double size )
  {
    setEnglishName( "Arrow" );
    m_PolySeg = new GPolySegment( squiggle.getPolygon() );

    // make sure the head of the squiggle is the head of the arrow
    if ( m_PolySeg.getTailPoint().includes( head, 2 ) ) {
      m_PolySeg.reverse();
    }
    else {
      Assert.check( m_PolySeg.getHeadPoint().includes( head, 2 ),
		    "Bad head point for arrow: " + head );
    }
    
    GPoint p = m_PolySeg.getPointFromHead( 1 );
    double angle = Geometry.angle( head, p );

    GPoint head1 = Geometry.locatePoint( head, size,
					 angle + (Math.PI / 4.0) );
    GPoint head2 = Geometry.locatePoint( head, size,
					 angle - (Math.PI / 4.0) );
    
    m_Seg1 = new GSegment( head, head1 );
    m_Seg2 = new GSegment( head, head2 );
  }

  ////////////////////////////////////////////////////////////////////
  public GPoint getHeadPoint()
  {
    return m_PolySeg.getHeadPoint();
  }

  public GPoint getTailPoint()
  {
    return m_PolySeg.getTailPoint();
  }

  public GPolySegment getPolySegment()
  {
    return new GPolySegment( m_PolySeg );
  }

  public Collection getParts() 
  {
    LinkedList list = new LinkedList();
    list.add( m_PolySeg );
    list.add( m_Seg1 );
    list.add( m_Seg2 );
    return list;
  }
  
  public double size()
  {
    return( m_PolySeg.size() );
  }

  public void resize( double scaleFactor )
  {
    m_PolySeg.resize( scaleFactor );
    m_Seg1.resize( scaleFactor );
    m_Seg2.resize( scaleFactor );
  }
  
  /** get the angle (radians) that the arrow starts out going in **/
  public double getTailAngle() 
  {
    return Geometry.angle( m_PolySeg.getPointFromTail(0),
			   m_PolySeg.getPointFromTail(1) );
  }


  /** get the angle (radians) that the arrow head is pointing in **/
  public double getHeadAngle()
  {
    return Geometry.angle( m_PolySeg.getPointFromHead(1),
			   m_PolySeg.getPointFromHead(0) );
  }
  
    
    

  ////////////////////////////////////////////////////////////////////

  public void draw( Graphics g )
  {
    m_PolySeg.display( g );

    m_Seg1.display( g );
    m_Seg2.display( g );
    // make this a Rudolf arrow :-)
    //    g.setColor( Color.red);
    //    g.fillOval( getHeadPoint().getIntX() - 3, getHeadPoint().getIntY() - 3, 6,6);
  }

  ////////////////////////////////////////////////////////////////////

  /**
   * @return Check if gp is on the arrow within offset
   **/
  public boolean includes( GPoint gp, double offset )
  {
    return( m_PolySeg.includes( gp, offset ) ||
	    m_Seg1.includes( gp, offset ) ||
	    m_Seg2.includes( gp, offset ) );
  }

  public boolean contains( GPoint gp )
  {
    return includes( gp, 2 );
  }

  /** Check if the arrow goes through w's bounding box. **/
  public boolean intersects( SpatialWidget w ) 
  {
    return m_PolySeg.intersects( w.getBounds() );
  }

  public boolean passesBy( GShape shape, double tolerance )
  {
    return m_PolySeg.isNear( shape, tolerance );
  }
  
  ////////////////////////////////////////////////////////////////////

  public void move( GPoint p )
  {
    GPoint c = getCenter();
    
    m_PolySeg.translate( c, p );
    m_Seg1.translate( c, p );
    m_Seg2.translate( c, p );
  }

  public GPoint getCenter() 
  {
    Rectangle r = getBounds();
    return new GPoint( (double)r.x + ((double)r.width / 2.0),
		       (double)r.y + ((double)r.height / 2.0) );
  }
  
  public void rotate( GPoint gp, double angle )
  {
    m_PolySeg.rotate( gp, angle );
    m_Seg1.rotate( gp, angle );
    m_Seg2.rotate( gp, angle );
  }

  ////////////////////////////////////////////////////////////////////

  public Location getLocation()
  {
    return( new Location( getBounds() ) );
  }

  public Rectangle getBounds()
  {
    return( m_PolySeg.getBounds() );
  }


  ////////////////////////////////////////////////////////////////////

  public Object clone()
  {
    return( new WSquiggleArrow( m_PolySeg, m_Seg1, m_Seg2 ) );
  }

  ////////////////////////////////////////////////////////////////////

}


