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

////////////////////////////////////////////////////////////////////////////////
//
// FILE:	BallRecognizer.java
//
// AUTHOR:	Manoj D. Muzumdar
//		archon@ai.mit.edu
//
// DATE:	April 99
//
// COPYRIGHT:	Massachusetts Institute of Technology
//		All rights reserved.
//
// PURPOSE:	Ball recognition
//
// HISTORY:     April 99  archon  created
//
////////////////////////////////////////////////////////////////////////////////

package rec.meche;

import java.util.*;
import rec.geo.*;
import rec.sys.*;
import rec.core.widgets.*;

public class BallRecognizer extends Recognizer
{
  public static WMBall isBall( WCircle c, WLine l )
  {
    // Check sizes first.

    if( l.size() > c.size() * 4.0 || l.size() < c.size() * 1.5 )
      return( null );

    GPoint cen = c.getCenter();
    double dist = c.getRadius();
    GPoint mid = l.getLine().getMidpoint();

    if( Math.abs( Geometry.distance( cen, l.getHead() ) - dist ) <= 5.0
	&& Estimator.isSameAngle( cen, mid, l.getHead(), l.getTail() ) ) {

      GPoint op = Geometry.midpoint(
		    cen.locatePoint( dist,
				     Geometry.angle( cen, l.getHead() ) ),
		    l.getHead() );

      return( new WMBall( op,
			  Geometry.angle( mid, cen ) + Math.PI / 2.0,
			  c.size(),
			  null ) );
    }

    if( Math.abs( Geometry.distance( cen, l.getTail() ) - dist ) <= 5.0
	&& Estimator.isSameAngle( cen, mid, l.getTail(), l.getHead() ) ) {

      GPoint op = Geometry.midpoint(
		    cen.locatePoint( dist,
				     Geometry.angle( cen, l.getTail() ) ),
		    l.getTail() );

      return( new WMBall( op,
			  Geometry.angle( mid, cen ) + Math.PI / 2.0,
			  c.size(),
			  null ) );
    }

    return( null );
  }

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

  public BallRecognizer()
  {
  }

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

  public boolean recognize( Surface s, Widget w )
  {
    GeometryCalculator gc = new GeometryCalculator( s );

    Iterator iter = gc.getVisibleWidgets().iterator();

    if( iter == null )
      return( false );

    // Look for the matching arc.

    if( w instanceof WLine ) {

      WLine l = (WLine)w;

      while( iter.hasNext() ) {

	Widget vw = (Widget)iter.next();

	if( !( vw instanceof WCircle ) )
	  continue;

	WCircle c = (WCircle)vw;

	WMBall part = null;

	if( (part = isBall( c, l )) != null ) {

	  s.removeWidget( c );
	  s.removeWidget( l );

	  s.addWidget( part );

	  return( true );
	}
      }

      return( false );
    }

    // Look for the matching line.

    WCircle c = (WCircle)w;

    while( iter.hasNext() ) {

      Widget vw = (Widget)iter.next();

      if( !( vw instanceof WLine ) )
	continue;

      WLine l = (WLine)vw;

      WMBall part = null;

      if( (part = isBall( c, l )) != null ) {

	s.removeWidget( c );
	s.removeWidget( l );

	s.addWidget( part );

	return( true );
      }
    }

    return( false );
  }

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

  public Iterator getInputTypes()
  {
    Vector v = new Vector();

    v.addElement( "rec.core.widgets.WLine" );
    v.addElement( "rec.core.widgets.WCircle" );

    return( v.iterator() );
  }

  public Iterator getOutputTypes()
  {
    Vector v = new Vector();

    v.addElement( "rec.meche.WMBall" );

    return( v.iterator() );
  }
}

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