Home > WorldWind > Java API for KML – the 24 hour project

Java API for KML – the 24 hour project

September 22, 2009

I haven’t done any fun projects for almost 2 years (WorldWind .net and WiiMote) at home.  There are several TODOs on my list ranging from building a FITR based multitouch surface to writing an iPhone game to fixing bugs in WW.NET and revamping how icons work there.

Instead I’ve been doing a lot of coding with WorldWind Java (WWJ) at work and coming home a bit late in the evenings.  It’s nice coding again for work and I find I need to do that every couple years and take a break from technical management.  The side effect is I don’t have to code on the side to keep my hand in.

But Java API for KML came out recently and while it isn’t necessary for our work project I would like to play with it a bit and see if it can replace some of our custom KML code.  I’ve also had a long running itch to scratch in terms of getting the Worldwide SAM Site Overview data into WorldWind.

So a 24 hour project to do that.  That’s a little TOO simple so here are the overall requirements:

  • Import the SSO kmz file into java using JAK
  • Display the SSO data on WWJ
  • Automatically generate range circles based on the SAM type
  • Export the range circle and extra data back into KML

Extra credit:

  • Import CIA World Factbook data and display that as well
  • Use raycasting to limit the range cicles based on terrain
  • Provide ranges limits based on target altitude as a function of terrain and curvature of the earth

I started this weekend (12 hours worth) and things went quickly until they bogged down from gold plating:

  • I got JAK to import the SSO data (easy).
  • I got WWJ to show an icon (not the one that is used in the SSO kml but a generic one)
  • I parsed the site name to get the SAM type (S300-P, Patriot, Hawk, etc)

That took maybe 4 hours.  Then I went into la-la land.  I started looking at HSQL and H2 for an embedded DB.  I started wandering down the H2 spatial path.  I stated defining fairly complex data tables that this program would never need.  Then I ran out of weekend without being in a demoable state. 🙂

The project, alas, will have to go through my work to release but I can talk about JAK here.  Other than an a lack of documentation (common for open source) it was easy to figure out.  But since I couldn’t find an unmarshall example anywhere on the net here’s a simple example based on the SSO kml (I extracted it from the KMZ file first):


package edu.jhuapl.ssov.core;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import de.micromata.opengis.kml.v_2_2_0.Placemark;

public class SsoParser {
HashMap<String, List > samTable = new HashMap<String, List >();
ArrayList samType = new ArrayList();

public void parseKML(String filename)
{
Kml kml = Kml.unmarshal(new File(filename));

initSamType();

if (kml != null)
{

Feature feature = kml.getFeature();
processFeature(null, feature);
}

System.out.println(samTable.size() + " SAM types.");

List unknown = samTable.get("UNKNOWN");
if (unknown != null)
{
System.out.println(unknown.size() + " unknown installations.");

for (Placemark placemark : unknown)
{
System.out.println("UNKNOWN: " + placemark.getName());

}
}

List genericSAM = samTable.get("SAM");
if (genericSAM != null)
{
System.out.println(genericSAM.size() + " generic SAM installations.");

for (Placemark placemark : genericSAM)
{
System.out.println("SAM: " + placemark.getName());

}
}

List genericEW= samTable.get("EW");
if (genericSAM != null)
{
System.out.println(genericEW.size() + " generic EW installations.");

for (Placemark placemark : genericEW)
{
System.out.println("EW: " + placemark.getName());

}
}
}

public void processFeature(Feature parentFeature, Feature feature)
{
if (feature instanceof Document)
{
processDocument(parentFeature, (Document) feature);
}
else if (feature instanceof Folder)
{
processFolder(parentFeature, (Folder) feature);
}
else if (feature instanceof Placemark)
{
processPlacemark(parentFeature, (Placemark) feature);
}
else
{
System.out.println("Feature " + feature.getName() + " : " + feature);
}
}

public void processDocument(Feature parentFeature, Document doc)
{
List features = doc.getFeature();

// System.out.println("Document " + doc.getName());

for (Feature docFeature : features)
{
processFeature(doc, docFeature);
}
}

public void processFolder(Feature parentFeature, Folder folder)
{
List features = folder.getFeature();

// System.out.println("Folder " + folder.getName());

for (Feature folderFeature : features)
{
processFeature(folder, folderFeature);
}
}

public void processPlacemark(Feature parentFeature, Placemark placemark)
{
String samType = processPlacemarkName (placemark.getName());
List placemarks = samTable.get(samType);

if (placemarks == null)
{
// System.out.println("SAM Type " + samType +" found: " + placemark.getName());

placemarks = new ArrayList();
samTable.put(samType, placemarks);
}

placemarks.add(placemark);
}

public String processPlacemarkName(String name)
{
boolean emptyFlag = false;

for (String samName : samType)
{
emptyFlag = false;
if (name.toLowerCase().contains("Empty"))
{
emptyFlag = true;
}

if (name.toLowerCase().contains(samName.toLowerCase()))
{
if (emptyFlag)
return "Empty " + samName;
else
return samName;
}
}
return "UNKNOWN";
}

private void initSamType()
{
samType.add("SA-11");
samType.add("SA-15");
samType.add("SA-20");
samType.add("SA-1");
samType.add("SA-2");
samType.add("SA-3");
samType.add("SA-4");
samType.add("SA-5");
samType.add("SA-6");
samType.add("SA-8");
samType.add("Buk-M1-2");
samType.add("HAWK");
samType.add("FM-90");
samType.add("KS-1A");
samType.add("HQ-2");
samType.add("HQ-6");
samType.add("HQ-9");
samType.add("S-300PS/PMU");
samType.add("S-300PMU-1");
samType.add("S-300PMU");
samType.add("S-300PT");
samType.add("S-300P");
samType.add("S-300V");
samType.add("Chu-SAM");
samType.add("NIKE HERCULES");
samType.add("NIKE-HERCULES");
samType.add("PATRIOT");
samType.add("Arrow II");
samType.add("SL-AMRAAM");
samType.add("Rapier");
samType.add("Crotale");
samType.add("Skyguard");
samType.add("Shahine");
samType.add("TACSAM");
samType.add("Bloodhound");
samType.add("NASAMS");

samType.add("36D6");
samType.add("64N6");
samType.add("96L6");
samType.add("9S18M1");
samType.add("TK-II");
samType.add("HT-233");
samType.add("5V11 Dal");
samType.add("OTH-R");
samType.add("OTH-T");
samType.add("OTH");
samType.add("LPAR");
samType.add("7010 ABM RADAR");
samType.add("AN/FPS-108 COBRA DANE");
samType.add("AN/TPS-71 Receiver");
samType.add("AN/TPS-71 Transmitter");

samType.add("SAM Garrison");
samType.add("SAM Training Facility");
samType.add("SAM Training Range");
samType.add("SAM Test Range");
samType.add("SAM");

samType.add("BMEW");
samType.add("ABM");
samType.add("RADAR");
samType.add("EW");
samType.add("TEST");
}
}

Yes, my java conventions are kinda funny. I’m mostly a C/C++/C# developer. 🙂 Also, some things are stubbed in there (like SAM types) that will come from the embedded database (Yes, this is where I went off track).

So I went from 4 hours to 12 hours very quickly. On the other hand I have some hibernate hbm files and a semi-working database (HSQL because I have code samples for that and I only have 12 hours left).

Advertisements
Categories: WorldWind
  1. July 8, 2010 at 6:50 pm

    Just wanted to express thanks for providing this helpful example. I’m working on a project that would benefit from being able to parse google earth KMZ files containing a variety of different maritime data types. Specifically, I need to iterate through all of the placemarks and extract various data fields like the geometries and descriptions.

    I recently discovered the JavaAPIForKML project, and needed an example to kickstart my development effort. This did the job very nicely. I’ve already got a few working examples. Kudos for showing me how!

    Scott C. in Cary, NC USA

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: