joachimeichborn.geotag.io.writer.kml.AbstractKmlWriter.java Source code

Java tutorial

Introduction

Here is the source code for joachimeichborn.geotag.io.writer.kml.AbstractKmlWriter.java

Source

/*
GeoTag
    
Copyright (C) 2015  Joachim von Eichborn
    
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 3 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, see <http://www.gnu.org/licenses/>.
*/

package joachimeichborn.geotag.io.writer.kml;

import java.io.IOException;

import org.joda.time.format.ISODateTimeFormat;

import de.micromata.opengis.kml.v_2_2_0.BalloonStyle;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.ExtendedData;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
import de.micromata.opengis.kml.v_2_2_0.LineString;
import de.micromata.opengis.kml.v_2_2_0.LineStyle;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import joachimeichborn.geotag.io.writer.TrackWriter;
import joachimeichborn.geotag.io.writer.kml.CirclePolygon.Radian;
import joachimeichborn.geotag.model.PositionData;
import joachimeichborn.geotag.model.Track;

public abstract class AbstractKmlWriter implements TrackWriter {
    private static final String EXTENDED_DATA_DATE = "date";
    private static final String EXTENDED_DATA_ACCURACY = "accuracy";
    private static final String EXTENDED_DATA_TIME = "time";

    private static final String PIN_STYLE = "PinStyle";
    private static final String ACCURACY_STYLE = "AccuracyStyle";
    private static final String PATH_STYLE = "PathStyle";

    GeoTagKml createKml(final String aTitle, final Track aTrack) throws IOException {
        final Document document = new Document().withName(aTitle).withOpen(true);

        addStylesDefinitions(document);

        addPlacemarkFolder(document, aTrack);

        addPath(document, aTrack);

        addAccuracyCircles(document, aTrack);

        final GeoTagKml kml = new GeoTagKml();
        kml.setFeature(document);

        return kml;
    }

    /**
     * Add styles that define how the contents of the KML file should be
     * displayed
     * 
     * @param aDocument
     *            The KML document that is build
     */
    private void addStylesDefinitions(final Document aDocument) {
        aDocument.createAndAddStyle().withLineStyle(new LineStyle().withColor("ff0000ff").withWidth(2))
                .withId(PATH_STYLE);
        aDocument.createAndAddStyle().withLineStyle(new LineStyle().withColor("ff55ff7f").withWidth(2))
                .withId(ACCURACY_STYLE);
        aDocument.createAndAddStyle().withLabelStyle(new LabelStyle().withColor("00ffffff")).withBalloonStyle(
                new BalloonStyle().withText("<h3>$[name]</h3><br><table border='1' cellpadding='5'>" + //
                        "<tr><td>Date</td><td>$[" + EXTENDED_DATA_DATE + "]</td></tr>" + //
                        "<tr><td>Time</td><td>$[" + EXTENDED_DATA_TIME + "]</td></tr>" + //
                        "<tr><td>Accuracy (m)</td><td>$[" + EXTENDED_DATA_ACCURACY + "]</td></tr>" + //
                        "</table>"))
                .withId(PIN_STYLE);
    }

    /**
     * Add a placemark for each position
     * 
     * @param aDocument
     *            The KML document that is build
     * @param aTrack
     */
    private void addPlacemarkFolder(final Document aDocument, final Track aTrack) {
        final Folder pinFolder = new Folder().withName("Places").withOpen(false);
        for (final PositionData position : aTrack.getPositions()) {
            final Placemark place = new Placemark();
            place.setName(position.getName());
            place.createAndSetTimeStamp()
                    .withWhen(position.getTimeStamp().toString(ISODateTimeFormat.dateTimeNoMillis()));
            place.createAndSetPoint().addToCoordinates(position.getCoordinates().getLongitude(),
                    position.getCoordinates().getLatitude(), position.getCoordinates().getAltitude());
            place.setStyleUrl("#" + PIN_STYLE);
            place.setVisibility(false);
            final ExtendedData extendedData = place.createAndSetExtendedData();
            extendedData.createAndAddData(position.getTimeStamp().toString(ISODateTimeFormat.yearMonthDay()))
                    .withName(EXTENDED_DATA_DATE);
            extendedData.createAndAddData(position.getTimeStamp().toString(ISODateTimeFormat.hourMinuteSecond()))
                    .withName(EXTENDED_DATA_TIME);
            extendedData.createAndAddData(Float.toString(position.getAccuracy())).withName(EXTENDED_DATA_ACCURACY);
            pinFolder.getFeature().add(place);
        }
        aDocument.getFeature().add(pinFolder);
    }

    /**
     * Add a path that connects all positions in chronological order
     * 
     * @param aDocument
     *            The KML document that is build
     */
    private void addPath(final Document aDocument, final Track aTrack) {
        final LineString line = new LineString().withTessellate(true);

        PositionData lastPosition = null;
        for (final PositionData position : aTrack.getPositions()) {
            if (lastPosition != null && !(position.getCoordinates().equals(lastPosition.getCoordinates()))) {
                line.addToCoordinates(position.getCoordinates().getLongitude(),
                        position.getCoordinates().getLatitude(), position.getCoordinates().getAltitude());
            }
            lastPosition = position;
        }
        aDocument.createAndAddPlacemark().withName("Path").withStyleUrl("#" + PATH_STYLE).withGeometry(line);
    }

    /**
     * Add for each position a circle that displays it's accuracy
     * 
     * @param aDocument
     *            The KML document that is build
     */
    private void addAccuracyCircles(final Document aDocument, final Track aTrack) {
        final Folder accuraciesFolder = new Folder().withName("Accuracies").withOpen(false);
        for (final PositionData position : aTrack.getPositions()) {
            if (position.getAccuracy() > 0f) {
                final LineString circle = new LineString().withTessellate(true);

                for (final Radian point : CirclePolygon.calculateCirclePoints(
                        position.getCoordinates().getLatitude(), position.getCoordinates().getLongitude(),
                        position.getAccuracy())) {
                    circle.addToCoordinates(point.getLongitude(), point.getLatitude());
                }
                accuraciesFolder.createAndAddPlacemark().withName(String.valueOf(position.getAccuracy()))
                        .withStyleUrl("#" + ACCURACY_STYLE).withVisibility(false).withGeometry(circle)
                        .createAndSetTimeStamp()
                        .withWhen(position.getTimeStamp().toString(ISODateTimeFormat.dateTimeNoMillis()));
            }
        }
        aDocument.getFeature().add(accuraciesFolder);
    }

}