Package net.sourceforge.gpstools.kml

Source Code of net.sourceforge.gpstools.kml.GpxKMLWriter$KmlCommandLine

package net.sourceforge.gpstools.kml;

/* gpxconv
* Copyright (C) 2006 Moritz Ringler
* $Id: GpxKMLWriter.java 441 2010-12-13 20:04:20Z ringler $
*
*  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/>.
*/

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import net.sourceforge.gpstools.AbstractCommandLine;
import net.sourceforge.gpstools.GPSDings;
import net.sourceforge.gpstools.gpx.GpxType;
import net.sourceforge.gpstools.gpx.Trk;
import net.sourceforge.gpstools.gpx.Trkpt;
import net.sourceforge.gpstools.gpx.Trkseg;
import net.sourceforge.gpstools.gpx.Wpt;
import net.sourceforge.gpstools.utils.ColorProvider;
import net.sourceforge.gpstools.utils.ColorListColorProvider;
import net.sourceforge.gpstools.utils.GpsFormat;
import de.mospace.xml.SaxXMLWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.xml.sax.SAXException;

public class GpxKMLWriter extends GPSDings {
    SaxXMLWriter xw;
    private final static String LOCAL_URN_PREFIX = "gpsdings:";
    private final static String GEARTH_URN_PREFIX = "google:";

    private final Properties kmlIcons = new Properties();
    private final List<String> myStyles = new Vector<String>();
    private final ColorProvider colorGen = new ColorListColorProvider("SBGR");
    private final GpsFormat format = GpsFormat.getInstance();
    private Set<String> customIcons;
    private boolean allowCustomIcons;

    public GpxKMLWriter(OutputStream out, String name, boolean enableCustomIcons) throws SAXException, IOException{
        allowCustomIcons = enableCustomIcons;
        kmlIcons.load(this.getClass().getResourceAsStream("kml.icons.properties"));
        try{
            xw = new SaxXMLWriter(out, "UTF-8", "http://earth.google.com/kml/2.1");
        } catch (UnsupportedEncodingException wonthappen){
            throw new Error(wonthappen);
        }
        xw.startElement("Document");

        xw.textElement("name", name);
        xw.textElement("visibility", "1");

        xw.attribute("id", "waypoint");
        xw.startElement("Style");
        writeIcon("root://icons/palette-4.png", "32", "128", "32", "32", null);
        xw.endElement("Style");
    }

    private void writeIcon(String href, String x, String y, String w, String h, String scale) throws SAXException, IOException{
        xw.startElement("IconStyle");
        if(scale != null){
            xw.textElement("scale", scale);
        }
        xw.startElement("Icon");
        xw.textElement("href", href);
        if(x != null && y!= null){
            xw.textElement("x", x);
            xw.textElement("y", y);
        }
        if(w != null && h != null){
            xw.textElement("w", w);
            xw.textElement("h", h);
        }
        xw.endElement("Icon");
        xw.endElement("IconStyle");
    }

    public void writeGpx(GpxType gpx) throws SAXException, IOException{
        if(gpx.getWptCount() > 0){
            /* waypoint styles */
            Set<String> syms = new HashSet<String>();
            for(Wpt wpt : gpx.getWpt()){
                if(wpt.getSym() != null){
                    syms.add(wpt.getSym().toLowerCase().replaceAll("[^a-z0-9]",""));
                }
            }
            for(String sym : syms){
                addSymbolStyle(sym);
            }

            /* waypoints */
            xw.startElement("Folder");
            xw.textElement("name", "Waypoints");
            xw.textElement("visibility", "1");
            for(Wpt pt : gpx.getWpt()){
                writeWaypoint(pt);
            }
            xw.endElement("Folder");
        }

        if(gpx.getTrkCount() > 0){
            /* tracklogs */
            xw.startElement("Folder");
            xw.textElement("name", "Tracklogs");
            xw.textElement("visibility", "1");
            for(Trk trk : gpx.getTrk()){
                Trkseg[] segs = trk.getTrkseg();
                final int numseg = segs.length;
                for(int i=0; i<numseg; i++){
                    writeTrackSegment(trk, segs[i], numseg, i+1);
                }
            }
            xw.endElement("Folder");
        }
    }

    private synchronized void addSymbolStyle(String sym) throws SAXException, IOException{
        final String pStyle = "sym." + sym + ".style";
        String style = kmlIcons.getProperty(pStyle);

        if(myStyles.contains(style)){
            return;
        }

        if(style == null){
            /* we have no style for this symbol, before we give up... */
            /* try if sym is a single letter or digit:
            * if so use gearth icons with 1-9 and a-z */
            if(sym.length() == 1){
                char c = Character.toLowerCase(sym.charAt(0));
                int offset = -1;
                style = "letter." + c;
                int pal = 5;
                if(c > '0' && c < '9'){
                    style = "digit." + c;
                    offset = 49;
                    pal = 3;
                } else  if(c >= 'a' && c < 'i'){
                    offset = 49;
                } else if (c >= 'i' && c < 'q'){
                    offset = 73;
                } else if (c >= 'q' && c < 'y'){
                    offset = 97;
                } else if (c == 'y' || c == 'z'){
                    offset = 121;
                } else {
                    style = null;
                }
                final String pIconSrc = "style." + style + ".icon.src";
                if(style != null && kmlIcons.getProperty(pIconSrc) == null){
                    kmlIcons.setProperty(pStyle, style);
                    kmlIcons.setProperty(pIconSrc,
                        GEARTH_URN_PREFIX +
                        "pal" + pal + "/pIcon" + (c - offset) + "l.png");
                }
            } else {
                /* try if we have a style with the same name */
                final String pIconSrc = "style." + sym + ".icon.src";
                if(kmlIcons.containsKey(pIconSrc)){
                    style = sym;
                    kmlIcons.setProperty(pStyle, style);
                }
            }
        } else {
            final String pIcon = "style." + style + ".icon";
            final String pIconSrc = pIcon + ".src";
            final String pHlIcon = "style." + style + ".highlight.icon";
            final String pHlIconSrc = pHlIcon + ".src";
            String href = resolveURI(kmlIcons.getProperty(pIconSrc));
            String hlHref = resolveURI(kmlIcons.getProperty(pHlIconSrc));

            if(href == null){
                kmlIcons.setProperty(pStyle, "waypoint");
            } else {
                String styleId = rewriteId(style);
                if(hlHref == null){
                    writeIconStyle(href, pIcon, styleId, null);
                } else {
                    writeIconStyle(href, pIcon, "sn_"+styleId, null);
                    writeIconStyle(hlHref, pHlIcon, "sh_"+styleId, "1.1");
                    writeStyleMap(styleId);
                }
                myStyles.add(style);
            }
        }
    }

    private String rewriteId(String id){
        char[] chars = id.toCharArray();
        int i = 0;
        boolean upper = false;
        for(int k=0; k < chars.length; k++){
            if(chars[k] == '.'){
                upper = true;
            } else {
            chars[i++] = (upper)? Character.toUpperCase(chars[k]) : chars[k];
                upper = false;
            }
        }
        return new String(chars, 0, i);
    }

    private void writeStyleMap(String style) throws SAXException, IOException{
        xw.attribute("id", style);
        xw.startElement("StyleMap");
        xw.startElement("Pair");
        xw.textElement("key","normal");
        xw.textElement("styleUrl", "#sn_"+style);
        xw.endElement("Pair");
        xw.startElement("Pair");
        xw.textElement("key","highlight");
        xw.textElement("styleUrl", "#sh_"+style);
        xw.endElement("Pair");
        xw.endElement("StyleMap");
    }

    private void writeIconStyle(String href, String iconProp, String style, String scale) throws SAXException, IOException{
        xw.attribute("id", style);
        xw.startElement("Style");
        writeIcon(href,
            kmlIcons.getProperty(iconProp + ".x"),
            kmlIcons.getProperty(iconProp + ".y"),
            kmlIcons.getProperty(iconProp + ".w"),
            kmlIcons.getProperty(iconProp + ".h"),
            scale);
        xw.endElement("Style");
    }

    private String resolveURI(String href){
        String result = href;
        if(href == null){
            //return null;
        } else if(href.startsWith(GEARTH_URN_PREFIX)){
            result = "http://maps.google.com/mapfiles/kml/" + href.substring(GEARTH_URN_PREFIX.length());
        } else if(href.startsWith(LOCAL_URN_PREFIX)){
            if(allowCustomIcons){
                result = "icon/" + href.substring(LOCAL_URN_PREFIX.length());
                if(customIcons == null){
                    customIcons = new HashSet<String>();
                }
                customIcons.add(result);
            } else {
                result = null;
            }
        }
        return result;
    }

    private void writeTrackSegment(Trk trk, Trkseg seg, int numseg, int segidx) throws SAXException, IOException{
        String n = trk.getName();
        if(n == null){
            n = "UNNAMED TRACK";
        }
        StringBuilder name = new StringBuilder(n.trim());
        if(numseg > 1){
            name.append("- ").append(segidx);
        }
        xw.startElement("Placemark");
        xw.textElement("name", name.toString());
        /* Style */
        xw.startElement("Style");
        xw.startElement("LineStyle");
        xw.textElement("color", colorGen.getNextColorString());
        xw.textElement("width", "2");
        xw.endElement("LineStyle");
        xw.endElement("Style");
        /* Data */
        xw.startElement("LineString");
        xw.textElement("coordinates", formatCoordinates(seg));
        xw.endElement("LineString");
        xw.endElement("Placemark");
    }

    private String formatCoordinates(Trkseg seg){
        StringBuilder sb = new StringBuilder();
        GpsFormat gpsFormat = GpsFormat.getInstance();
        for(Trkpt pt : seg.getTrkpt()){
            sb.append(gpsFormat.asLatLon(pt.getLon(), pt.getLat()));
            Number ele = pt.getEle();
            if(ele != null && ele.doubleValue() >= 0.01){
                sb.append(',');
                sb.append(gpsFormat.asAltitude(ele));
            }
            sb.append(' ');
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    private void writeWaypoint(Wpt ptthrows SAXException, IOException{
        String lon = format.asLatLon(pt.getLon());
        String lat = format.asLatLon(pt.getLat());
        BigDecimal ele = pt.getEle();
        String alt = (ele == null)? null : format.asAltitude(ele);
        String sym = pt.getSym();
        if(sym != null){
            sym = sym.toLowerCase().replaceAll("[^a-z0-9]","");
        }
        String style = "#" + (
            (sym == null)
            ? "waypoint"
            : rewriteId(kmlIcons.getProperty("sym." + sym + ".style", "waypoint"))
            );

        xw.startElement("Placemark");

        String name = pt.getName();
        if(name == null){
            name = "Waypoint";
        }
        xw.textElement("name", name);

        String desc = pt.getDesc();
        if(desc != null){
            xw.textElement("description", pt.getDesc());
        }

        xw.textElement("styleUrl", style);

        xw.startElement("LookAt");
        xw.textElement("longitude", lon);
        xw.textElement("latitude", lat);
        xw.textElement("altitude", "0");
        xw.textElement("range", "800");
        xw.textElement("tilt", "45");
        xw.textElement("heading", "0");
        xw.endElement("LookAt");

        xw.startElement("Point");
        StringBuilder coords = new StringBuilder();
        coords.append(lon).append(',');
        coords.append(lat);

        if(alt != null){
            coords.append(',').append(alt);
        }
        xw.textElement("coordinates", coords.toString());
        xw.endElement("Point");

        xw.endElement("Placemark");
    }

    public void endDocument() throws SAXException, IOException{
        xw.endElement("Document");
        xw.endDocument();
    }

    public static void addIcon(String icon, ZipOutputStream zippo) throws IOException{
        final int BUFFSIZE = 2048;
        byte[] buffer = new byte[BUFFSIZE];
        String res = "/net/sourceforge/gpstools/res/" + icon;
        InputStream in = GpxKMLWriter.class.getResourceAsStream(res);
        if(in == null){
            throw new IOException("Cannot find resource: " + res);
        }
        try{
            zippo.putNextEntry(new ZipEntry(icon));
            int count = 0;
            while ((count = in.read(buffer, 0, BUFFSIZE)) != -1) {
                zippo.write(buffer, 0, count);
            }
        } finally {
            try{
                zippo.closeEntry();
            } finally {
                in.close();
            }
        }
    }

    public static void convertFiles(File[] inpt, File outdir, String title, boolean kmz)
    throws IOException, SAXException{
        GpxType xgpx;
        GpxKMLWriter kw;
        final String ext =  (kmz)? ".kmz" : ".kml";

        /* loop over input files */
        for(File gpx : inpt){

            /* read input */
            final FileInputStream in = new FileInputStream(gpx);
            try{
                xgpx = GPSDings.readGPX(in);
            } finally {
                in.close();
            }

            /* create target file and outputstream*/
            File todir = (outdir == null)? gpx.getAbsoluteFile().getParentFile() : outdir;
            String name = gpx.getName().replaceFirst("\\.gpx$","");
            File kml = new File(todir, name + ext);
            OutputStream os = new FileOutputStream(kml);
            try{
                ZipOutputStream zippo = null;
                if(kmz){
                    zippo = new ZipOutputStream(os);
                    zippo.putNextEntry(new ZipEntry(name + ".kml"));
                    os = zippo;
                }
                os = new BufferedOutputStream(os);

                /* create the GPXKMLWriter instance and convert gpx to kml */
                kw = new GpxKMLWriter(os, (title == null)? name : title, kmz);
                kw.writeGpx(xgpx);
                kw.endDocument();
                if(kmz && zippo != null){
                    zippo.closeEntry();

                    /* if we have customIcons, add them to the kmz */
                    if(kw.customIcons != null){
                        for (String icon : kw.customIcons){
                            addIcon(icon, zippo);
                        }
                    }
                }
            } finally{
                os.close();
            }
        }
    }


    public static void main(String[] argv){
        (new KmlCommandLine(argv)).execute();
    }

    private static class KmlCommandLine extends AbstractCommandLine<GpxKMLWriter>{
        private File outdir;
        private String title;
        private boolean asKMZ = false;

        public static final String OPT_NAME = "name";
        public static final String OPT_TO_DIR = "todir";
        public static final String OPT_KMZ = "kmz";

        public KmlCommandLine(String[] argv){
            super(null, argv);
        }

        @Override
        public void execute(){
            try{
                //java.util.Locale.setDefault(java.util.Locale.US);
                processArguments();
                File[] input = getInputFiles();
                if(input == null){
                    System.exit(1);
                }
                GpxKMLWriter.convertFiles(input, outdir, title, asKMZ);
            } catch (RuntimeException ex){
                ex.printStackTrace();
                System.err.println(ex);
                System.exit(1);
            } catch (Exception ex){
                System.err.println(ex);
                System.exit(1);
            }
        }

        @Override
        public void printHelp(PrintStream out){
            try{
                super.printHelp(out);
                cat("gpxkml.txt");
            } catch (Exception ex){
                throw new Error(ex);
            }
        }

        @Override
        protected Options createOptions(){
            Options options = super.createOptions();
            options.addOption(makeOption(OPT_NAME, File.class, 1, "name"));
            options.addOption(makeOption(OPT_TO_DIR, File.class, 1, "directory"));
            options.addOption(makeOption('z', OPT_KMZ,  Boolean.class, 0, null));
            return options;
        }

        @Override
        protected CommandLine processOptions(Options options)
            throws org.apache.commons.cli.ParseException,
           IOException,
           java.text.ParseException
        {
            CommandLine cl = super.processOptions(options);
            char c;

            /* name option */
            opt = OPT_NAME;
            c = opt.charAt(0);
            if(cl.hasOption(c)){
                title = cl.getOptionValue(c);
            }

            /* kmz option */
            opt = OPT_KMZ;
            c = 'z';
            if(cl.hasOption(c)){
                asKMZ = true;
            }

            /* todir option */
            opt = OPT_TO_DIR;
            c = opt.charAt(0);
            if(cl.hasOption(c)){
                File outputdir = new File(cl.getOptionValue(c));
                if(!outputdir.isDirectory() || outputdir.mkdirs()){
                    throw new java.io.FileNotFoundException("Cannot neither access nor create directory " + outputdir.getAbsolutePath());
                }
                outdir = outputdir;
            }

            return cl;
        }

    }
}
TOP

Related Classes of net.sourceforge.gpstools.kml.GpxKMLWriter$KmlCommandLine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.