////////////////////////////////////////////////////////////////////////////////
//																			  //
// AUTHOR:      Tevfik Metin Sezgin	                        				  //
//				Massachusetts Institute of Technology						  //
//				Department of Electrical Engineering and Computer Science	  //
//				Artificial Intelligence Laboratory							  //
//																			  //
// E-MAIL:		mtsezgin@ai.mit.edu, mtsezgin@mit.edu						  //
//																			  //
// COPYRIGHT:   Tevfik Metin Sezgin                    						  //
//              All rights reserved. This code can not be copied, modified,   //
//              or distributed in whole or partially without the written 	  //
//				permission of the author. Also see the COPYRIGHT file.		  //
//																			  //
////////////////////////////////////////////////////////////////////////////////

/** 
  * 
  * See the end of the file for the log of changes.
  * 
  * $Author: mtsezgin $
  * $Date: 2000/04/18 06:59:48 $   
  * $Revision: 1.2 $
  * $Headers$
  * $Id: Filter.java,v 1.2 2000/04/18 06:59:48 mtsezgin Exp $     
  * $Name:  $   
  * $Locker:  $
  * $Source: /mit/mtsezgin/CVS/Repository/util/Filter.java,v $
  *  
  **/


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer;


public class
OrthogonalDistanceRegression
{
    /**
    *
    * Do an ODR using the inputs x and y, and return a double 
	* array of length 2 containing a and b, st. the line fitted
	* is represented by ax+b.
    *
    **/
	public static double[]
	doODR( String parameters_file_name,
		   String results_file_name,
		   double x[],
		   double y[] ) 
	{
		
		double result[]      = new double[2];						

        try {
			(Runtime.getRuntime().exec( "rm.bat " + 
										parameters_file_name + " " +
										results_file_name )).waitFor();
			System.out.println( "deleted " + parameters_file_name + " " +
								results_file_name );
			
    	    FileOutputStream fos = new FileOutputStream( parameters_file_name );

			fos.write( (x.length + " 1 2 1 \n").getBytes() );
			fos.write( ("1.0 1.0 \n").getBytes() );

			for ( int i=0; i<x.length; i++ ) {
				fos.write( (x[i] + "\t" + y[i] + " \n").getBytes() );
			}
			fos.close();

			System.out.println( "closed " + parameters_file_name );
			System.out.println( "computing fit" );
						
			(Runtime.getRuntime().exec( "compute" )).waitFor();
			
	        FileInputStream  fis = new FileInputStream( results_file_name );
			String result_string = "";

			System.out.println( "reading " + results_file_name );

			int read_char; 						
            read_char = fis.read();
            while ( read_char != -1 ) {
				result_string += (char)read_char;
                read_char      = fis.read();
            }
			fis.close();
						
			System.out.println( "> Read result " + result_string + " <" );

			result[0] = Double.parseDouble( 
							result_string.substring( 
								0,
								result_string.indexOf( ',' ) - 1 ) );
			result[1] = Double.parseDouble( 
							result_string.substring( 
								result_string.indexOf( ',' ) + 1 ) );
			
			System.out.println( "result[0] = " + result[0] );
			System.out.println( "result[1] = " + result[1] );			
			
        } catch( Exception e ) {
            System.out.println( "Exception in ODR " + e );
        }
			return result;
	}


    /**
    *
    * Do an ODR. x contains the x positions, y contains the y 
	* positions, and window_span determines how many elements
	* are considered at a time. window_span should be an odd 
	* integer. The sliding window contains a total of window_span
	* points, n on the left of the current point, n on the right 
	* of the current point, and 1 the current point where 
	* n = (window_span-1)/2. The regression for the first and the
	* last n points are done using a simpler method. This method
	* returns a two dimensional array of doubles whose length is 
	* equal to the length of the input arrays. So the first index
	* indices the points. The second one indices a and b (ie. the 
	* slope and the y intercept of the fitted line). 
    *
    **/
	public static double[][]
	doSlidingWindowODR( String parameters_file_name,
		 				String results_file_name,
		   				double x[],
		   				double y[], 
						int    window_span )
	{
		int    window_size = (window_span-1)/2;
		double result[][] = new double[x.length][2];						

        try {
			(Runtime.getRuntime().exec( "rm.bat " + 
										parameters_file_name + " " +
										results_file_name )).waitFor();
			System.out.println( "deleted " + parameters_file_name + " " +
								results_file_name );
			
    	    FileOutputStream fos = new FileOutputStream( parameters_file_name );

			fos.write( (x.length + " " + window_size + "\n").getBytes() );

			for ( int i=0; i<x.length; i++ ) {
				fos.write( (x[i] + "\t" + y[i] + " \n").getBytes() );
			}
			fos.close();

			System.out.println( "closed " + parameters_file_name );
			System.out.println( "computing fit" );
						
			(Runtime.getRuntime().exec( "swodr.exe" )).waitFor();

			System.out.println( "excuted swodr" );

			FileInputStream fis = new FileInputStream( results_file_name );
			
			StreamTokenizer st = 
				new StreamTokenizer( 
					new BufferedReader( 
						new InputStreamReader( fis )));

			System.out.println( "reading " + results_file_name );
			
			st.parseNumbers();
			int i = 0;
			while ( st.nextToken() != st.TT_EOF ) {
				if ( st.ttype == st.TT_NUMBER ) {
					result[1+i/2][i%2] = st.nval;
					System.out.print( st.nval + (( i%2 == 1 ) ? "\n" : " ") );
					i++;
				}
			}
			
			result[0][0] = result[1][0];
			result[0][1] = result[1][1];
			result[result.length-1][0] = result[result.length-2][0];
			result[result.length-1][1] = result[result.length-2][1];
			
			fis.close();
			System.out.println( "Read result" );
        } catch( Exception e ) {
            System.out.println( "Exception in ODR " + e );
        }
			return result;
	}
    
    
    /**
     *
     * Derive direction, and fill in the d array.
     * This method is different than the previous one in that here
	 * we look at a collection of points rather than two points to
	 * come up with the direction. 
     *
     **/
    public static double[]
    deriveDirectionUsingRotationalSWODR( Point points[],
										 int window_span )
    {
		int    window_size = (window_span-1)/2;
        double a;
		double x[] = new double[window_span];
		double y[] = new double[window_span];
		
		double d[]  = new double[points.length];
		
        for ( int i=window_size; i+window_size<d.length; i++ ) {
			for ( int j=-window_size; j<window_size+1; j++ ) {
				x[j+window_size] = points[i+j].x;
				y[j+window_size] = points[i+j].y;
			}
			// Util.printArrays( x, "window"+i+"_x", y, "window"+i+"_y" );
			d[i] = LinearFit.findAngle( x, y );
			// System.out.println( i + ", " + GeometryUtil.radian2degree( d[i] ) );
        }
		
		int end;
		for ( int i=0; i<window_size; i++ ) {
			end 	 = points.length-window_size+i-1;
			d[i] 	 = Math.atan2( points[i+1].y - points[i].y,  
								   points[i+1].x - points[i].x );
			d[end+1] = Math.atan2( points[end+1].y - points[end].y,  
								   points[end+1].x - points[end].x );
		}


		return d;
    }
}

/** 
  * 
  * $Log: Filter.java,v $
  * Revision 1.2  2000/04/18 06:59:48  mtsezgin
  * *** empty log message ***
  *
  *
  **/
