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

// $Id: PolylineRecognizer.java,v 1.2 2003/03/06 00:40:47 moltmans Exp $
// Time-stamp: <2002-04-23 13:33:14 moltmans>
package rec.core.recognizers;


import edu.mit.sketch.geom.Polygon;
import java.awt.*;
import java.util.*;
import rec.core.widgets.*;
import rec.geo.*;
import rec.sys.*;
import rec.util.*;


public class PolylineRecognizer extends PolygonStrokeRecognizer
{
  boolean second_order = false;

  public PolylineRecognizer()
  {
  }

  public boolean recognize( Surface s, Widget w )
  {
    Squiggle sq = (Squiggle)w;

    // hack to make sure little circles are not polygons, etc.
    if ( !generalCheck( sq ) )
      return false;

    int angleconst = 115;
    int bevconst = 125;  // bevel angle threshhold for round corners.

    if ( sq.getLength() < 160 )
    {
      bevconst = 360 / 3;
      angleconst = 360 / 5;
    }

    // do we look for heavily rounded corners?
    second_order = ( sq.getNumberOfPoints() > 15 );

    boolean did_it = runCalculation( sq, angleconst, bevconst );

    if ( !did_it )
    {
      Console.writeln( "Not single stroke bunch of lines." );
      return false;
    }
    else
    {
      //Console.writeln( "This line is made up of " + N + " lines" );
	
      // break up into lines
      HashSet st = new HashSet();
      Polygon polygon = new Polygon();
      for ( int i = 0; i < N; i++ ) {
	polygon.addPoint( points[i].getIntX(), points[i].getIntY() );
      }

      WPolyLine polyline = new WPolyLine( polygon );

      s.replaceWidget( sq, polyline, true );

      return true;
    }
  } // end recognize



  boolean defacit( int thresh_1, int bevel_threshold )
  {
    boolean[] hits = new boolean[ N ];
    int num_hits = 0;
    for ( int i = 0; i < N; i++ ) hits[i] = false;

    // the beginning is always a corner
    hits[0] = true;
    num_hits = 1;

    boolean bevel = false;

    for ( int i = 1; i < N - 1; i++ )
    {
      GPoint p1 = points[i-1];
      GPoint p2 = points[i];
      GPoint p3 = points[i+1];
	
      // if the three points form a corner, mark it.
      int a = Geometry.delta_angle( p1, p2, p3 );

      //	Console.writeln( "" + i + " - Angle = " + a );
      if ( a < thresh_1 )
      {
	//Console.writeln( "hit!" );
	hits[i] = true;
	num_hits++;
	bevel = false;
      }
      else if ( a < bevel_threshold ) // hack for rounded corners (bleh!)
      {
	if ( bevel )
	{
	  if ( Geometry.distance( p1, p2 ) < 15 )
	  {
	    //    Console.writeln( "bevel hit!" );
	    hits[i] = true;
	    num_hits++;
	    bevel = false;
	  }
	}
	else
	  bevel = true;
      }
      else
	bevel = false;
    }

    // dup code to skip points looking for rounded corners
    // bleh!

    if ( second_order )
    {
      for ( int i = 2; i < N - 2; i++ )
      {
	GPoint p1 = points[i-2];
	GPoint p2 = points[i];
	GPoint p3 = points[i+2];

	// if corner near here, forget it.
	if ( hits[i-2] || hits[i-1] || hits[i] || hits[i+1] || hits[i+2])
	  continue;

	// if the three points form a corner, mark it.
	int a = Geometry.delta_angle( p1, p2, p3 );

	//	Console.writeln( "" + i + " - Angle = " + a );
	if ( a < thresh_1 )
	{
	  //Console.writeln( "second order hit." );
	  hits[i] = true;
	  num_hits++;
	  bevel = false;
	}
      }
      // end second order hack
    }
    hits[N-1] = true;
    num_hits++;
    
    if ( num_hits >= 3 )
    {
      //Console.writeln( "Going to strip non-corner points." );
      int cur = 0;
      for ( int i = 0; i < N; i++ )
      {
	if ( hits[i] )
	  points[cur++] = points[i];
      }
      N = num_hits;

      //Console.writeln( "Poly now has " + N + " sides." );
      return true;
    }

    // no action taken
    return false;
  }


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

    v.addElement( "rec.core.widgets.WPolyLine" );

    return( v.iterator() );
  }


  

}
