⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vrmi.java

📁 JavaGPS enables access to GPS devices from any Java application. Provides Java API, NMEA0183 parser,
💻 JAVA
字号:
/***********************************************************************
 *  J a v a G P S - GPS access library and Java API                    *
 *  Copyright (C) 2001 Ulrich Walther                                  *
 *                                                                     *
 *  This program is free software; you can redistribute it and/or      *
 *  modify it under the terms of the GNU General Public License as     *
 *  published by the Free Software Foundation; either version 2 of     *
 *  the License, or (at your option) any later version.                *
 *                                                                     *
 *  This program is distributed in the hope that it will be useful,    *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
 *  General Public License for more details.                           *
 *                                                                     *
 *  You should have received a copy of the GNU General Public          *
 *  License along with this program; if not, write to the Free         *
 *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,     *
 *  MA 02111-1307 USA                                                  *
 ***********************************************************************/
package org.iu.gps;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

//import org.eml.deepmap.objects.*;
//import com.objectspace.voyager.*;
//import com.objectspace.voyager.space.*;
//import org.eml.JAMFrame.*;

/**
 *  VRMI is the next higher layer above the GPSDriver and allows for different
 *  kinds of triggers: - periodic reporting - distance-based reporting -
 *  region-based reporting
 *
 *@author     U.Walther
 *@created    3. April 2002
 *@started    0.01 (Jun 3, 2000)
 *@version    0.91 (Feb 12, 2002)
 */

class VRMITriggerInfo {
	final static int PERIODIC = 1, DISTANCE = 2, REGION = 3;
	int type;
	int id;
	GPSInfo gpsInfo;
}

/**
 *  The VRMI class encapsulates all "higher" GPS funcionality. Mainly, VRMI
 *  deals with the various kinds of triggers: - time-based triggers (periodical
 *  reporting) - distance-based triggers - region-based triggers (if the user
 *  enters/exits a given polygonal area)
 *
 *@author     walther
 *@created    3. April 2002
 */
public class VRMI implements GPSListener, Runnable {
	protected static int triggerid = 1;
	protected GPSDriver gpsDriver = null;
	protected Vector triggers = null;
	protected boolean die = false;
	protected GPSInfo gpsInfo = null;
	protected Thread thread = null;
	protected boolean threadStop = false;

	/**
	 *  Main constructor
	 *
	 *@param  _gpsDriver     Parameter
	 *@exception  Exception  Exception
	 */
	public VRMI( GPSDriver _gpsDriver )
			 throws Exception
	{
		gpsDriver = _gpsDriver;

		// initialize triggers list
		triggers = new Vector();

		// attach ourselves to the GPS
		gpsDriver.addGPSListener( this );

		// wait for the first GPSInfo to arrive
/*		while ( gpsInfo == null )
		{
			try
			{
				Thread.sleep( 100 );
			}
			catch ( InterruptedException ie )
			{
			}
		}
*/

		// instead of waiting for the 1st update, we read out the
		// current GPSInfo from the driver
		gpsInfo = gpsDriver.getGPSInfo();

		// start timeout thread
		thread = new Thread( this );
		thread.start();
	}

	public void destroy()
	{
		gpsDriver.removeGPSListener( this );
		threadStop = true;
	}


	/**
	 *  Test if the given point is within a polygon. Beam intersection algorithm,
	 *  runtime is O(n) (n=edges). Works for simple polygons, even for polys with
	 *  holes IFF the hole is connected with a vertical edge (both y equal).
	 *
	 *@param  poly  The 2D-polygon to use.
	 *@param  p     The 2D-point to test for inclusion.
	 *@return       Returned Value
	 */
	public static boolean pointInPoly( double[][] poly, double[] p )
	{
		// 18 Dec 2000, U.Walther

		int n = poly.length;
		int i;
		int k;

		// bounding box check
		double max[] = new double[]{0.0, 0.0};

		// bounding box check
		double min[] = new double[]{1e99, 1e99};

		for ( i = 0; i < n; i++ )
		{
			for ( k = 0; k < 2; k++ )
			{
				if ( poly[i][k] > max[k] )
				{
					max[k] = poly[i][k];
				}
				else if ( poly[i][k] < min[k] )
				{
					min[k] = poly[i][k];
				}
			}
		}

		// point outside bounding box?
		if ( p[0] < min[0] || p[1] < min[1] || p[0] > max[0] || p[1] > max[1] )
		{
			return false;
		}

		// calculate # of intersections btw. poly edges & beam from p towards +x
		int count = 0;
		for ( i = 0; i < n; i++ )
		{
			k = ( i + 1 ) % n;
			double x1 = poly[i][0];
			double y1 = poly[i][1];
			double x2 = poly[k][0];
			double y2 = poly[k][1];
			if ( Math.min( y1, y2 ) > p[1] || Math.max( y1, y2 ) < p[1] )
			{
				continue;
			}

			double dx = x2 - x1;

			double dy = y2 - y1;

			// calculate x-coord of intersection
			// y1+t*dy == p[1]

			double t = ( p[1] - y1 ) / dy;
			double x = x1 + t * dx;

			// only count intersections on the right (> p[0])
			if ( x > p[0] )
			{
				count++;
			}
		}

		// p is inside poly if count is odd
		return ( count & 1 ) > 0;
	}


	/**
	 *  Return current GPS info as retrieved latest from GPS driver.
	 *
	 *@return    The currentGPSInfo value
	 */
	public GPSInfo getCurrentGPSInfo()
	{
		return gpsInfo;
	}


	/**
	 *  Adds a trigger that periodically reports the current location.
	 *
	 *@param  recv        The VRMICallback that receives the trigger.
	 *@param  persistant  Specifies if trigger is one-shot (false) or
	 *      persistant(true)
	 *@param  dt          Period of time in milliseconds.
	 *@return             Returns an integer that identifies the trigger.
	 */
	public int addPeriodicTrigger( VRMITriggerListener recv, boolean persistant,
			long dt )
	{
		TimeTriggerInfo tti = new TimeTriggerInfo();
		tti.persistant = persistant;
		tti.receiver = recv;
		tti.t = System.currentTimeMillis();
		tti.dt = dt;
		return addTrigger( tti );
	}


	/**
	 *  Adds a trigger that reports the new location if the current location
	 *  changes more than a given distance, or if the user did not move for longer
	 *  than a given period of time.
	 *
	 *@param  recv        The VRMICallback that receives the trigger.
	 *@param  persistant  Specifies if trigger is one-shot (false) or
	 *      persistant(true)
	 *@param  ds          Distance in meters.
	 *@param  dt          Period of time in milliseconds.
	 *@return             Returns an integer that identifies the trigger.
	 */
	public int addDistanceTrigger( VRMITriggerListener recv, boolean persistant,
			double ds, long dt )
	{
		TimeTriggerInfo tti = new TimeTriggerInfo();
		tti.persistant = persistant;
		tti.receiver = recv;
		tti.t = System.currentTimeMillis();
		tti.dt = dt;
		tti.distance = ds;
		tti.fromx = gpsInfo.X;
		tti.fromy = gpsInfo.Y;
		return addTrigger( tti );
	}


	/**
	 *  Adds a trigger that reports if the user enters or exits a given region.
	 *
	 *@param  recv        The VRMICallback that receives the trigger.
	 *@param  persistant  Specifies if trigger is one-shot (false) or
	 *      persistant(true)
	 *@param  region      2D-polygon that specifies the region.
	 *@param  enter       Specifies if entering the region should be reported.
	 *@param  exit        Specifies if exiting the region should be reported.
	 *@return             Returns an integer that identifies the trigger.
	 */
	public int addRegionTrigger( VRMITriggerListener recv, boolean persistant,
			double[][] region, boolean enter, boolean exit )
	{
		RegionTriggerInfo rti = new RegionTriggerInfo();
		rti.persistant = persistant;
		rti.receiver = recv;
		rti.region = region;
		rti.enter = enter;
		rti.exit = exit;
		rti.inside = pointInPoly( region, new double[]{gpsInfo.X, gpsInfo.Y} );
		return addTrigger( rti );
	}


	/**
	 *  Remove the trigger given in
	 *
	 *@param  id  Parameter
	 */
	public void removeTrigger( int id )
	{
		synchronized ( triggers )
		{
			for ( int i = 0; i < triggers.size(); i++ )
			{
				// look if we have a trigger with the given ID
				if ( ( ( TriggerInfo ) triggers.get( i ) ).id == id )
				{
					// yes, remove it.
					triggers.remove( i );
					return;
				}
			}
		}

		System.err.println( "Warn: trigger not in list" );
	}


	/**
	 *  GPS callback. Retrieves latest GPSInfo from GPS driver.
	 *
	 *@param  _gpsInfo  Parameter
	 */
	public void gpsEvent( GPSInfo _gpsInfo )
	{
		// update local copy of GPSInfo structure
		gpsInfo = _gpsInfo;
		// check pending triggers
		checkTriggers();
	}


	/**
	 *  In this thread, we call checkTriggers every second to be sure that time
	 *  triggers are send even if the GPS driver does not deliver events.
	 */
	public void run()
	{
		// In case the GPS drive does not deliver new GPS data (e.g.
		// if disconnected, or hardware failure), ensure that at least
		// every second the triggers are checked.
		for ( ; ;  )
		{
			if (threadStop==true)
				break;

			try
			{
				Thread.currentThread().sleep( 1000 );
			}
			catch ( InterruptedException iex )
			{
			}

			checkTriggers();
		}
	}


	/**
	 *  Method
	 */
	protected void finalize()
	{
		gpsDriver.removeGPSListener( this );
	}


	/**
	 *  Checks in list of triggers if a trigger has to be sent. Note: this method
	 *  uses the instance variable gpsInfo which has to be set to the current
	 *  gpsInfo from the GPS driver.
	 */
	protected void checkTriggers()
	{
		if ( triggers != null )
		{
			synchronized ( triggers )
			{
				long t = System.currentTimeMillis();

				for ( int i = 0; i < triggers.size(); i++ )
				{
					TriggerInfo _t = ( TriggerInfo ) triggers.get( i );
					if ( _t instanceof RegionTriggerInfo )
					{
						RegionTriggerInfo ti = ( RegionTriggerInfo ) _t;

						// check if we entered or left the region
						boolean insideNow = pointInPoly( ti.region,
								new double[]{gpsInfo.X, gpsInfo.Y} );
						if ( ti.inside != insideNow )
						{
							if ( ( insideNow && ti.enter ) || ( !insideNow && ti.exit ) )
							{
								ti.inside = insideNow;
								ti.trigger( gpsInfo );

								if ( !ti.persistant )
								{
									// one-shot trigger: remove from list
									removeTrigger( ti.id );
								}
							}
						}
					}
					else if ( _t instanceof TimeTriggerInfo )
					{
						TimeTriggerInfo ti = ( TimeTriggerInfo ) _t;

						double dx = ti.fromx - gpsInfo.X;

						double
								dy = ti.fromy - gpsInfo.Y;

						if ( ti.distance > 0.0 && dx * dx + dy * dy >= ti.distance * ti.distance )
						{
							ti.t = t;
							ti.fromx = gpsInfo.X;
							ti.fromy = gpsInfo.Y;
							ti.trigger( gpsInfo );

							if ( !ti.persistant )
							{
								// one-shot trigger: remove from list
								removeTrigger( ti.id );
							}
						}
						else
								if ( t - ti.t > ti.dt )
						{
							ti.t = t;
							ti.trigger( gpsInfo );

							if ( !ti.persistant )
							{
								// one-shot trigger: remove from list
								removeTrigger( ti.id );
							}
						}
					}
				}
			}
		}
	}


	/**
	 *  Private method to add a trigger to the triggers vector.
	 *
	 *@param  ti  The feature to be added to the Trigger attribute
	 *@return     Returned Value
	 */
	protected int addTrigger( TriggerInfo ti )
	{
		synchronized ( triggers )
		{
			ti.id = triggerid++;
			triggers.add( ti );
			return ti.id;
		}
	}


	void log( String msg )
	{
		System.out.println( msg );
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -