📄 vrmi.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 + -