Java API for KML - Advanced Example4

The concept

This series of more sophisticated JAK examples is trying to show the capabilities what is possible with KML in Java. They show the usage of JAK for generating some nice-looking KML files, which can be viewed with Google Earth.

Important!
JAK only works if all dependencies are resolved! That are mainly JAK and JAXB! For further instructions check out the FAQ.

Mobile Phone Subscriptions from 1990 till 2008 (animated!).

The fourth example is similar to the third. Instead of only showing the mobile subscription rate for the year 2008, it shows the data in the period between 1990 and 2008. In Google Earth the user can move a pointer on the timeline or play all periods automatically, which results into an animation.
The mobile subscription data can be found on this site: data.un.org and is saved as CSV file and the 3D polygons of the country borders are created the same way as described in Advanced Example2 and Advanced Example3.

Figure 1: The Mobile Phone Subscriptions 1990 - 2008 animation in Google Earth.

The Code

Read data of mobile phone subscriptions in from 1960 - 2008 from a CSV and set the height of the polygons to the value of the data for each country. For each year, there is a folder, with the attribute begin and end, which activates the timeline in Google Earth for an animation.

  1. load world borders from a KML (worldBorders.kml)
  2. load data into a nested HashMap
    • loop over HashMap keys (year values)
    • create folder for current year
    • traverse through the object structure of the placemark elements
      • check if data exist for current year and placemark
      • set the height and properly color
Listing 1: The Mobile Phone Subscriptions 1990 - 2008
HashMap<String, HashMap<String, Double>> result = Utils
    .readMultiDataFromCVS("src/main/resources/exampledata/mobile_phone.csv", 0, 3, 2);
double max = result.get("info").get("maximum");
result.remove("info");
int minPolyHeight = 308000;
int maxPolyHeight = 2692000; // real max = 3000000 - 308000 = 2692000

String path = "src/main/resources/data/worldBorders.kml";
Kml unmarshal = Kml.unmarshal(new File(path));

Document document = (Document) unmarshal.getFeature();
Folder oldFolder = (Folder) document.getFeature().get(0);
int folderSize = oldFolder.getFeature().size();
Folder folder = new Folder();
folder.setName("Mobile Phone Subscriptions 1960 - 2008");
// pick up a country (AFG) and geht the HashMap keys to sort the KML file by years
ArrayList<String> yearKeys = new ArrayList<String>();
yearKeys.addAll(result.get("AFG").keySet());
Collections.sort(yearKeys);
Iterator<String> iterator = yearKeys.iterator();

// loop over the year range
while (iterator.hasNext()) {
	String currentYear = iterator.next();
	if (Integer.valueOf(currentYear).intValue() <= 1989) {
		continue; // skip years before 1989 (less data)
	}
	// create a (root) folder and set the time range for the current year
	Folder yearFolder = new Folder();
	yearFolder.withName(currentYear).createAndSetTimeSpan().withBegin(currentYear + "-01-01").withEnd(currentYear + "-12-31");

	// loop over all countries / Placemarks
	for (int i = 0; i < folderSize; i++) {
		Placemark placemark = Utils.clonePlacemark((Placemark) oldFolder.getFeature().get(i));
		MultiGeometry multigeometry = (MultiGeometry) placemark.getGeometry();

		double height = -1;
		// only set height if data found in the HashMap (CSV) AND found the current year in the nested HashMap as key
		if (result.containsKey(placemark.getId()) && result.get(placemark.getId()).containsKey(currentYear)) {
			height = result.get(placemark.getId()).get(currentYear);
			placemark.withDescription("" + (int) height);
			// set a color gradient from yellow to red, calculating by the height, no transparency and no stroke/line
			Utils.setDataValueColor(placemark, max, height, "FF", 1, null, ColorMode.NORMAL);
			yearFolder.addToFeature(placemark);
			// normalize height and add minimal polygon height to prevent the "polygon hole problem"
			height = ((height / max) * maxPolyHeight) + minPolyHeight;
		} else {
			// if no data found for the current country / Placemark, use no 3D polygon and set color to gray
			Utils.setPolyStyleAndLineStyle(placemark, "FFCCCCCC", ColorMode.NORMAL, 1, null, ColorMode.NORMAL);
			yearFolder.addToFeature(placemark);
			placemark.withDescription("no data");
		}

		for (int j = 0; j < multigeometry.getGeometry().size(); j++) {
			Polygon polygon = (Polygon) multigeometry.getGeometry().get(j);
			if (height < 0) {
				// color overlay
				polygon.setAltitudeMode(AltitudeMode.CLAMP_TO_GROUND);
				polygon.setTessellate(Boolean.TRUE);
			} else {
				// 3D polygon
				polygon.setAltitudeMode(AltitudeMode.RELATIVE_TO_GROUND);
				polygon.setExtrude(Boolean.TRUE);
			}

			// only for 3D polygons
			if (height > 0) {
				Boundary outerBoundaryIs = polygon.getOuterBoundaryIs();
				LinearRing linearRing = outerBoundaryIs.getLinearRing();
				List<Coordinate> coordinates = linearRing.getCoordinates();
				// set the altitude of all vertices (height of the polygon)
				for (Coordinate c : coordinates) {
					c.setAltitude(height);
				}
				// check enclaves or polygons like it
				if (!polygon.getInnerBoundaryIs().isEmpty()) {
					for (int k = 0; k < polygon.getInnerBoundaryIs().size(); k++) {
						Boundary innerBoundaryIs = polygon.getInnerBoundaryIs().get(k);
						LinearRing linearRingInner = innerBoundaryIs.getLinearRing();
						List<Coordinate> coordinatesInner = linearRingInner.getCoordinates();
						// set the altitude of all vertices (height of the polygon)
						for (Coordinate c : coordinatesInner) {
							c.setAltitude(height);
						}
					}
				}
			}
		}
	}
	folder.addToFeature(yearFolder); // put folder with current year into the root folder
}

Document newDocument = new Document().withName("JAK Example4");
newDocument.getFeature().add(folder);
unmarshal.setFeature(newDocument);

unmarshal.marshalAsKmz("advanvedexample4.kmz");

The full example is contained in JAK's sources (/JavaAPIforKML/src/test/java/de/micromata/jak/examples/Example4.java).

Searching JAK

Java API for KML | @Google

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.




PageRank verified www.micromata.de/