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

////////////////////////////////////////////////////////////////////////////////
//
// FILE:	PistonRecognizer.java
//
// AUTHOR:	Manoj D. Muzumdar
//		archon@ai.mit.edu
//
// DATE:	Mar 99
//
// COPYRIGHT:	Massachusetts Institute of Technology
//		All rights reserved.
//
// PURPOSE:	Mechanical engineering drawing recognition
//
// HISTORY:     Mar 99  archon  created
//
////////////////////////////////////////////////////////////////////////////////

package rec.meche;

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

public class PistonRecognizer extends Recognizer
{
  public static WMPiston isPiston( WRectangle r, WLine l1, WLine l2 )
  {
    // Make sure the rectangle is not a square.
    if( r instanceof WSquare )
      return( null );

    GSegment majAxis = r.getMajorAxis();
    GSegment minAxis = r.getMinorAxis();

    GSegment s1 = new GSegment( l1.getHead(), l1.getTail() );
    GSegment s2 = new GSegment( l2.getHead(), l2.getTail() );

    if( Estimator.rectOverlap( r, s2 ) != null
	&& Estimator.rectOverlap( r, s2 ).equals( majAxis.getHeadPoint() )
	&& Estimator.connects( Estimator.rectInside( r, s2 ),
			       s1.getMidpoint(), 20.0 )
	&& Estimator.arePerpendicular( majAxis, s1 )
	&& Estimator.arePerpendicular( minAxis, s2 )
	&& Estimator.isSameSize( minAxis.size(), s1.size() )
	&& s2.size() > s1.size()
	&& s2.size() < majAxis.size()
	&& Estimator.isSameAngle( majAxis.getHeadPoint(),
				  majAxis.getTailPoint(),
				  majAxis.getHeadPoint(),
				  s1.getMidpoint() ) ) {

      return( new WMPiston( r.getLocation().getCenter(),
			    Geometry.angle( majAxis.getTailPoint(),
					    s1.getMidpoint() )
                                              + Math.PI / 2.0,
			    r.size(),
			    null ) );
    }

    if( Estimator.rectOverlap( r, s2 ) != null
	&& Estimator.rectOverlap( r, s2 ).equals( majAxis.getTailPoint() )
	&& Estimator.connects( Estimator.rectInside( r, s2 ),
			       s1.getMidpoint(), 20.0 )
	&& Estimator.arePerpendicular( majAxis, s1 )
	&& Estimator.arePerpendicular( minAxis, s2 )
	&& Estimator.isSameSize( minAxis.size(), s1.size() )
	&& s2.size() > s1.size()
	&& s2.size() < majAxis.size()
	&& Estimator.isSameAngle( majAxis.getTailPoint(),
				  majAxis.getHeadPoint(),
				  majAxis.getTailPoint(),
				  s1.getMidpoint() ) ) {

      return( new WMPiston( r.getLocation().getCenter(),
			    Geometry.angle( majAxis.getHeadPoint(),
					    s1.getMidpoint() )
                                              + Math.PI / 2.0,
			    r.size(),
			    null ) );
    }

    if( Estimator.rectOverlap( r, s1 ) != null
	&& Estimator.rectOverlap( r, s1 ).equals( majAxis.getHeadPoint() )
	&& Estimator.connects( Estimator.rectInside( r, s1 ),
			       s2.getMidpoint(), 20.0 )
	&& Estimator.arePerpendicular( majAxis, s2 )
	&& Estimator.arePerpendicular( minAxis, s1 )
	&& Estimator.isSameSize( minAxis.size(), s2.size() )
	&& s1.size() > s2.size()
	&& s1.size() < majAxis.size()
	&& Estimator.isSameAngle( majAxis.getHeadPoint(),
				  majAxis.getTailPoint(),
				  majAxis.getHeadPoint(),
				  s2.getMidpoint() ) ) {

      return( new WMPiston( r.getLocation().getCenter(),
			    Geometry.angle( majAxis.getTailPoint(),
					    s2.getMidpoint() )
                                              + Math.PI / 2.0,
			    r.size(),
			    null ) );
    }

    if( Estimator.rectOverlap( r, s1 ) != null
	&& Estimator.rectOverlap( r, s1 ).equals( majAxis.getTailPoint() )
	&& Estimator.connects( Estimator.rectInside( r, s1 ),
			       s2.getMidpoint(), 20.0 )
	&& Estimator.arePerpendicular( majAxis, s2 )
	&& Estimator.arePerpendicular( minAxis, s1 )
	&& Estimator.isSameSize( minAxis.size(), s2.size() )
	&& s1.size() > s2.size()
	&& s1.size() < majAxis.size()
	&& Estimator.isSameAngle( majAxis.getTailPoint(),
				  majAxis.getHeadPoint(),
				  majAxis.getTailPoint(),
				  s2.getMidpoint() ) ) {

      return( new WMPiston( r.getLocation().getCenter(),
			    Geometry.angle( majAxis.getHeadPoint(),
					    s2.getMidpoint() )
                                              + Math.PI / 2.0,
			    r.size(),
			    null ) );
    }

    return( null );
  }

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

  public PistonRecognizer()
  {
  }

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

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

    if( vect.size() < 3 )
      return( false );

    // Try to match with two other lines.

    if( w instanceof WRectangle ) {

      WRectangle r = (WRectangle)w;

      for( int i = 0; i < vect.size(); ++i ) {

	Widget vw1 = (Widget)vect.elementAt( i );

	if( vw1 instanceof WLine ) {

	  for( int j = 0; j < vect.size(); ++j ) {

	    Widget vw2 = (Widget)vect.elementAt( j );
	      
	    if( vw2 instanceof WLine && !vw2.equals( vw1 ) ) {
	      
	      WMPiston wp = isPiston( r, (WLine)vw1, (WLine)vw2 );

	      if( wp != null ) {

		s.removeWidget( r );
		s.removeWidget( vw1 );
		s.removeWidget( vw2 );

		s.addWidget( wp );

		return( true );
	      }
	    }
	  }
	}
      }
    }

    // Try to match with another line and a rectangle.

    if( w instanceof WLine ) {

      WLine l = (WLine)w;

      for( int i = 0; i < vect.size(); ++i ) {

	Widget vw1 = (Widget)vect.elementAt( i );

	if( vw1 instanceof WRectangle ) {

	  for( int j = 0; j < vect.size(); ++j ) {

	    Widget vw2 = (Widget)vect.elementAt( j );

	    if( vw2 instanceof WLine && !vw2.equals( l ) ) {

	      WMPiston wp = isPiston( (WRectangle)vw1, l, (WLine)vw2 );

	      if( wp != null ) {

		s.removeWidget( vw1 );
		s.removeWidget( l );
		s.removeWidget( vw2 );

		s.addWidget( wp );

		return( true );
	      }
	    }
	  }
	}
      }
    }

    return( false );
  }

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

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

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

    return( v.iterator() );
  }

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

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

    return( v.iterator() );
  }
}

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