Java API for KML - Advanced Example4The conceptThis 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.
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.
Figure 1: The Mobile Phone Subscriptions 1990 - 2008 animation in Google Earth.The CodeRead 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.
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). |
Java API for KML | @Google |








is the OpenSource platform of 