Friday, August 28, 2009

Build your own GPS/GIS system in less than 200 lines with OpenMap


Here is how to do your own (simplistic) GPS/GIS system using OpenMap in less than 200 lines of code. To get started you will need to download and install OpenMap.

The GPS Layer for OpenMap is as follows. Notice that the code is somewhat crude with regards to threading, drizzel some synchronized on to it as appropriate.


public class GPSLayer extends OMGraphicHandlerLayer {

private static String GPSDATA = "gpsData";

private static final double KT2MPS = 1852.0 / 3600.0;

private static final double speedVectorLengthInMinutes = 6;

private String gpsDataPath = "";

private float latitude, longitude, speed, course;

private OMGraphicList graphics = new OMGraphicList();;

private OMRect gpsPosition = new OMRect(0, 0, 0, 0, 10, 10);

private OMLine speedVector;

private OMText gpsText = new OMText(10, 20, "GPS Data",
OMText.JUSTIFY_LEFT);

private Timer timer;

public GPSLayer() {
gpsText.setFillPaint(Color.WHITE);
gpsText.setTextMatteColor(new Color(182, 235, 219));
gpsPosition.setFillPaint(Color.pink);
}

@Override
public void setProperties(String prefix, Properties props) {
super.setProperties(prefix, props);
gpsDataPath = props.getProperty(prefix + "." + GPSDATA);
// redraw every 5 secs
timer = new Timer(5000, this);
timer.start();

// emulate reading GPS data (threading issue here access to members not
// protected!)
new Thread(new Runnable() {
public void run() {
try {
BufferedReader in = new BufferedReader(new FileReader(
gpsDataPath));
String str;
while ((str = in.readLine()) != null) {
Thread.sleep(100);
if (str.startsWith("$GPRMC")) {
String[] fields = str.split(",");
// utc_date = fields[1];
double lat = Double.parseDouble(fields[3]);
double degrees = Math.floor((lat / 100.0));
double minute = (lat / 100.0) - degrees;
lat = (degrees) + ((minute * 100.0) / 60);
if (fields[4].equals("S"))
lat = -lat;
latitude = (float) lat;

double lon = Double.parseDouble(fields[5]);
degrees = Math.floor((lon / 100.0));
minute = (lon / 100.0) - degrees;
lon = (degrees) + ((minute * 100.0) / 60);
if (fields[6].equals("W"))
lon = -lon;
longitude = (float) lon;

speed = (float) (Double.parseDouble(fields[7]) * KT2MPS);

if (!fields[8].equals("")) {
course = (float) Double.parseDouble(fields[8]);
}
// could parse date but to lazy
// date = fields[9];
}
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}

@Override
public synchronized OMGraphicList prepare() {
gpsPosition.setLocation(latitude, longitude, -5, -5, 5, 5);

// calc. speed vector length using OM GIS functions
LatLonPoint startPos = new LatLonPoint(latitude, longitude);
float length = (float) Length.KM.toRadians(speedVectorLengthInMinutes
* ((speed * 3.6) / 60.0));
LatLonPoint endPos = startPos.getPoint(length, (float) ProjMath
.degToRad(course));
speedVector = new OMLine(startPos.getLatitude(), startPos
.getLongitude(), endPos.getLatitude(), endPos.getLongitude(),
OMLine.LINETYPE_STRAIGHT);
// vec.addArrowHead(OMArrowHead.ARROWHEAD_DIRECTION_FORWARD, 100, 3, 1);
speedVector.setLinePaint(Color.DARK_GRAY);

graphics.clear();
// order of add determines what is rendered on top
graphics.add(speedVector);
graphics.add(gpsPosition);
gpsText.setData(String.format("GPS Data\n%4.2f Km/h",
(speed * 3.60)));
graphics.add(gpsText);

graphics.project(getProjection());
return graphics;
}

@Override
public void actionPerformed(ActionEvent ae) {
doPrepare();
}
}

If you have a GPS antenna you can use one of the free GPS servers (gpsd on linux) to make its data available on a socket and then modify the in variable in reader thread to the following:

uc = new URL(gpsDataPath).openConnection(); // gps.gpsData=http://localhost:2244
InputStreamReader icr = new InputStreamReader(uc.getInputStream());
in = new BufferedReader(icr);


To run this put the above class into a jar file and copy it to the lib dir of the OpenMap installation. Then in the share dir create a openmap.properties file with the following content:

openmap.layers=gps graticule shapePolitical
openmap.startUpLayers=gps graticule shapePolitical

gps.class=GPSLayer
gps.prettyName=GPS Position
gps.gpsData=/tmp/gpslog.txt


Then go to the bin dir of the OpenMap installation and do ./openmap(.bat) and your GPS/GIS system will be running.

Then following can be used as test data

$GPRMC,143346,A,5616.9232,N,01008.2504,E,074.6,011.3,110105,000.9,E,A*13
$GPRMC,143347,A,5616.9435,N,01008.2571,E,074.5,010.4,110105,000.9,E,A*14
$GPRMC,143348,A,5616.9638,N,01008.2632,E,074.4,009.5,110105,000.9,E,A*18
$GPRMC,143349,A,5616.9842,N,01008.2686,E,074.3,008.4,110105,000.9,E,A*12

No comments:

Live Traffic Map