From b63d426e0f02bdc702d06945183b11450724866f Mon Sep 17 00:00:00 2001 From: Bryan Kowal Date: Wed, 5 Sep 2012 18:39:08 -0500 Subject: [PATCH] Issue #1141 - Merging KML into the Common Baseline Former-commit-id: 3180ae0c5767b50c12919daa5e58a0fa44745b99 [formerly c3f584fdc5f53ecd62afe41c481aaa96cf532009] Former-commit-id: 7b45633097e84a373a3347d0241e264b48d5dbe9 --- cave/build/cave/customTargets.xml | 4 + cave/build/p2-build.xml | 12 +- .../.project | 11 + .../build.properties | 1 + .../feature.xml | 32 + .../com.raytheon.uf.viz.kml.export/.classpath | 7 + cave/com.raytheon.uf.viz.kml.export/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../META-INF/MANIFEST.MF | 27 + .../build.properties | 5 + .../com.raytheon.uf.viz.kml.export/plugin.xml | 62 ++ .../raytheon/uf/viz/kml/export/Activator.java | 50 ++ .../uf/viz/kml/export/KmlExportDialog.java | 606 ++++++++++++++++ .../uf/viz/kml/export/KmlExportHandler.java | 103 +++ .../uf/viz/kml/export/KmlExportJob.java | 676 ++++++++++++++++++ .../uf/viz/kml/export/KmlExportOptions.java | 172 +++++ .../viz/kml/export/KmlFeatureGenerator.java | 111 +++ .../raytheon/uf/viz/kml/export/KmlPane.java | 123 ++++ .../uf/viz/kml/export/graphics/KmlFont.java | 185 +++++ .../graphics/KmlGraphicsFactoryAdapter.java | 101 +++ .../export/graphics/KmlGraphicsTarget.java | 333 +++++++++ .../kml/export/graphics/KmlShadedShape.java | 208 ++++++ .../uf/viz/kml/export/graphics/KmlView.java | 108 +++ .../export/graphics/KmlWireframeShape.java | 284 ++++++++ .../basicgen/KmlCirclesGenerator.java | 119 +++ .../graphics/basicgen/KmlLinesGenerator.java | 92 +++ .../graphics/basicgen/KmlPointsGenerator.java | 162 +++++ .../graphics/basicgen/KmlRectGenerator.java | 113 +++ .../basicgen/KmlStringsGenerator.java | 189 +++++ .../ext/KmlCanvasRenderingExtension.java | 412 +++++++++++ .../graphics/ext/KmlColormappedImage.java | 125 ++++ .../ext/KmlColormappedImageExtension.java | 337 +++++++++ .../ext/KmlGroundOverlayGenerator.java | 143 ++++ .../viz/kml/export/graphics/ext/KmlImage.java | 96 +++ .../graphics/ext/KmlMapMeshExtension.java | 77 ++ .../viz/kml/export/graphics/ext/KmlMesh.java | 101 +++ .../export/graphics/ext/KmlMosaicImage.java | 149 ++++ .../graphics/ext/KmlMosaicImageExtension.java | 255 +++++++ .../ext/KmlMosaicMaxValImageExtension.java | 62 ++ .../ext/KmlMosaicOrderedImageExtension.java | 59 ++ .../export/graphics/ext/KmlRasterImage.java | 130 ++++ .../graphics/ext/KmlRasterImageExtension.java | 122 ++++ .../graphics/ext/KmlSingleColorImage.java | 90 +++ .../ext/KmlSingleColorImageExtension.java | 53 ++ .../ext/point/KmlPointImageExtension.java | 153 ++++ .../ext/radar/KmlRadialMeshExtension.java | 78 ++ .../kml/export/io/KmlFolderOutputManager.java | 96 +++ .../viz/kml/export/io/KmlOutputManager.java | 63 ++ .../kml/export/io/KmlRootOutputManager.java | 164 +++++ cots/de.micromata.opengis.kml/.classpath | 7 + cots/de.micromata.opengis.kml/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../JavaAPIforKml-sources.jar | Bin 0 -> 492760 bytes .../JavaAPIforKml.jar | Bin 0 -> 619517 bytes .../META-INF/MANIFEST.MF | 13 + .../de.micromata.opengis.kml/build.properties | 3 + 56 files changed, 6755 insertions(+), 1 deletion(-) create mode 100644 cave/com.raytheon.uf.viz.kml.export.feature/.project create mode 100755 cave/com.raytheon.uf.viz.kml.export.feature/build.properties create mode 100755 cave/com.raytheon.uf.viz.kml.export.feature/feature.xml create mode 100644 cave/com.raytheon.uf.viz.kml.export/.classpath create mode 100644 cave/com.raytheon.uf.viz.kml.export/.project create mode 100644 cave/com.raytheon.uf.viz.kml.export/.settings/org.eclipse.jdt.core.prefs create mode 100644 cave/com.raytheon.uf.viz.kml.export/META-INF/MANIFEST.MF create mode 100644 cave/com.raytheon.uf.viz.kml.export/build.properties create mode 100644 cave/com.raytheon.uf.viz.kml.export/plugin.xml create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/Activator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportDialog.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportHandler.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportJob.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportOptions.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlFeatureGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlPane.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlFont.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlGraphicsFactoryAdapter.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlGraphicsTarget.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlShadedShape.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlView.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlWireframeShape.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/basicgen/KmlCirclesGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/basicgen/KmlLinesGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/basicgen/KmlPointsGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/basicgen/KmlRectGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/basicgen/KmlStringsGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlCanvasRenderingExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlColormappedImage.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlColormappedImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlGroundOverlayGenerator.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlImage.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMapMeshExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMesh.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMosaicImage.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMosaicImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMosaicMaxValImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlMosaicOrderedImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlRasterImage.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlRasterImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlSingleColorImage.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/KmlSingleColorImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/point/KmlPointImageExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/ext/radar/KmlRadialMeshExtension.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/io/KmlFolderOutputManager.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/io/KmlOutputManager.java create mode 100644 cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/io/KmlRootOutputManager.java create mode 100644 cots/de.micromata.opengis.kml/.classpath create mode 100644 cots/de.micromata.opengis.kml/.project create mode 100644 cots/de.micromata.opengis.kml/.settings/org.eclipse.jdt.core.prefs create mode 100644 cots/de.micromata.opengis.kml/JavaAPIforKml-sources.jar create mode 100644 cots/de.micromata.opengis.kml/JavaAPIforKml.jar create mode 100644 cots/de.micromata.opengis.kml/META-INF/MANIFEST.MF create mode 100644 cots/de.micromata.opengis.kml/build.properties diff --git a/cave/build/cave/customTargets.xml b/cave/build/cave/customTargets.xml index 612a856854..e3644b19ad 100644 --- a/cave/build/cave/customTargets.xml +++ b/cave/build/cave/customTargets.xml @@ -112,6 +112,10 @@ + + + + diff --git a/cave/build/p2-build.xml b/cave/build/p2-build.xml index 7acd223efc..ffa3684862 100644 --- a/cave/build/p2-build.xml +++ b/cave/build/p2-build.xml @@ -107,6 +107,12 @@ + + + + + @@ -266,7 +272,11 @@ - + + + + diff --git a/cave/com.raytheon.uf.viz.kml.export.feature/.project b/cave/com.raytheon.uf.viz.kml.export.feature/.project new file mode 100644 index 0000000000..31141696dc --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export.feature/.project @@ -0,0 +1,11 @@ + + + com.raytheon.uf.viz.kml.export.feature + + + + + + + + diff --git a/cave/com.raytheon.uf.viz.kml.export.feature/build.properties b/cave/com.raytheon.uf.viz.kml.export.feature/build.properties new file mode 100755 index 0000000000..64f93a9f0b --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/cave/com.raytheon.uf.viz.kml.export.feature/feature.xml b/cave/com.raytheon.uf.viz.kml.export.feature/feature.xml new file mode 100755 index 0000000000..2a68be49e2 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export.feature/feature.xml @@ -0,0 +1,32 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + diff --git a/cave/com.raytheon.uf.viz.kml.export/.classpath b/cave/com.raytheon.uf.viz.kml.export/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cave/com.raytheon.uf.viz.kml.export/.project b/cave/com.raytheon.uf.viz.kml.export/.project new file mode 100644 index 0000000000..ac1ac33ee2 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.viz.kml.export + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cave/com.raytheon.uf.viz.kml.export/.settings/org.eclipse.jdt.core.prefs b/cave/com.raytheon.uf.viz.kml.export/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..9a05f5f33c --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Wed May 30 15:50:31 CDT 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/cave/com.raytheon.uf.viz.kml.export/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.kml.export/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..f5ee20d888 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/META-INF/MANIFEST.MF @@ -0,0 +1,27 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: KML Export +Bundle-SymbolicName: com.raytheon.uf.viz.kml.export;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: com.raytheon.uf.viz.kml.export.Activator +Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization +Bundle-Vendor: RAYTHEON +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + com.raytheon.uf.common.serialization;bundle-version="1.12.1174", + org.geotools;bundle-version="2.6.4", + com.raytheon.uf.viz.core;bundle-version="1.12.1174", + com.raytheon.uf.viz.core.rsc;bundle-version="1.0.0", + com.raytheon.uf.common.geospatial;bundle-version="1.12.1174", + com.raytheon.uf.common.colormap;bundle-version="1.12.1174", + com.raytheon.uf.common.time;bundle-version="1.12.1174", + com.raytheon.viz.ui;bundle-version="1.12.1174", + com.raytheon.uf.viz.core.maps;bundle-version="1.12.1174", + de.micromata.opengis.kml;bundle-version="1.0.0", + com.raytheon.viz.pointdata;bundle-version="1.12.1174", + com.raytheon.viz.radar;bundle-version="1.12.1174", + com.raytheon.uf.common.dataplugin.radar;bundle-version="1.0.0", + javax.measure;bundle-version="1.0.0", + javax.vecmath;bundle-version="1.3.1" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy diff --git a/cave/com.raytheon.uf.viz.kml.export/build.properties b/cave/com.raytheon.uf.viz.kml.export/build.properties new file mode 100644 index 0000000000..e9863e281e --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/cave/com.raytheon.uf.viz.kml.export/plugin.xml b/cave/com.raytheon.uf.viz.kml.export/plugin.xml new file mode 100644 index 0000000000..be0787b52b --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/plugin.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/Activator.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/Activator.java new file mode 100644 index 0000000000..565c20c8ce --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/Activator.java @@ -0,0 +1,50 @@ +package com.raytheon.uf.viz.kml.export; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.raytheon.uf.viz.kml.export"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportDialog.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportDialog.java new file mode 100644 index 0000000000..da710ea2ad --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportDialog.java @@ -0,0 +1,606 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; + +import com.raytheon.uf.viz.core.drawables.ResourcePair; +import com.raytheon.uf.viz.kml.export.KmlExportOptions.KmlExportTimeMode; +import com.raytheon.viz.ui.dialogs.CaveSWTDialog; + +/** + * Allow user to select options for export and starts the KmlExportJob. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 5, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ + +public class KmlExportDialog extends CaveSWTDialog { + + private final KmlExportOptions options; + + private Text locationText; + + private Tree productTree; + + private Button exportHiddenButton; + + private Button exportMapsButton; + + private Button shadeEarthButton; + + private Button setTimesButton; + + private Button timeSpanButton; + + private Button timeStampButton; + + private Button fillPlotsButton; + + private Button selectedFramesButton; + + private Button currentFramesButton; + + private Button allFramesButton; + + private Text framesFromText; + + private Text framesToText; + + public KmlExportDialog(Shell shell, KmlExportOptions options) { + super(shell, SWT.RESIZE | SWT.DIALOG_TRIM); + this.setText("Export KML"); + this.options = options; + } + + @Override + protected void initializeComponents(Shell shell) { + + Composite leftComposite = new Composite(shell, SWT.NONE); + leftComposite.setLayoutData(new GridData(SWT.NONE, SWT.FILL, false, + true)); + RowLayout layout = new RowLayout(SWT.VERTICAL); + layout.fill = true; + leftComposite.setLayout(layout); + + Group locationGroup = new Group(leftComposite, SWT.NONE); + initializeLocationGroup(locationGroup); + + Group framesGroup = new Group(leftComposite, SWT.NONE); + initializeFramesGroup(framesGroup); + + Group optionsGroup = new Group(leftComposite, SWT.NONE); + initializeOptionsGroup(optionsGroup); + + // Group timeOptionsGroup = new Group(leftComposite, SWT.NONE); + // initializeTimeOptionsGroup(timeOptionsGroup); + + Group productsGroup = new Group(shell, SWT.NONE); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.widthHint = 250; + productsGroup.setLayoutData(gridData); + initializeProductsGroup(productsGroup); + + Composite buttonComposite = new Composite(shell, SWT.NONE); + gridData = new GridData(SWT.FILL, SWT.NONE, true, false, 2, 1); + gridData.horizontalAlignment = SWT.CENTER; + buttonComposite.setLayoutData(gridData); + initializeButtons(buttonComposite); + + populateProductTree(); + if (productTree.getItemCount() == 0) { + // for the intial load change this option so there is something to + // export. + exportMapsButton.setSelection(true); + populateProductTree(); + } + + shell.pack(); + shell.setMinimumSize(shell.getSize()); + } + + @Override + protected Layout constructShellLayout() { + GridLayout mainLayout = new GridLayout(2, false); + mainLayout.marginHeight = 3; + mainLayout.marginWidth = 3; + return mainLayout; + } + + protected void initializeLocationGroup(Group group) { + group.setLayout(new GridLayout(2, false)); + group.setText("Export Location"); + locationText = new Text(group, SWT.BORDER); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.widthHint = 250; + locationText.setLayoutData(gridData); + locationText.setText(options.getKmzFileLocation().getAbsolutePath()); + Button button = new Button(group, SWT.PUSH); + button.setText("Browse ..."); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + selectDestinationFile(); + } + }); + } + + protected void initializeFramesGroup(Group group) { + group.setLayout(new GridLayout(5, false)); + group.setText("Export Location"); + + allFramesButton = new Button(group, SWT.RADIO); + allFramesButton.setText("All Frames"); + GridData gridData = new GridData(); + gridData.horizontalSpan = 5; + allFramesButton.setLayoutData(gridData); + allFramesButton.setSelection(true); + + currentFramesButton = new Button(group, SWT.RADIO); + currentFramesButton.setText("Current Frame"); + gridData = new GridData(); + gridData.horizontalSpan = 5; + currentFramesButton.setLayoutData(gridData); + + selectedFramesButton = new Button(group, SWT.RADIO); + selectedFramesButton.setText("Frames"); + + new Label(group, SWT.NONE).setText("from:"); + framesFromText = new Text(group, SWT.BORDER); + gridData = new GridData(); + gridData.widthHint = 24; + framesFromText.setLayoutData(gridData); + framesFromText.setEnabled(false); + framesFromText.setText("1"); + new Label(group, SWT.NONE).setText("to:"); + framesToText = new Text(group, SWT.BORDER); + gridData = new GridData(); + gridData.widthHint = 24; + framesToText.setLayoutData(gridData); + framesToText.setEnabled(false); + int numFrames = 1; + for (KmlPane pane : options.getPanes()) { + int frames = pane.getDisplay().getDescriptor().getFramesInfo() + .getFrameCount(); + numFrames = Math.max(frames, numFrames); + } + framesToText.setText(Integer.toString(numFrames)); + selectedFramesButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + framesToText.setEnabled(selectedFramesButton.getSelection()); + framesFromText.setEnabled(selectedFramesButton.getSelection()); + } + + }); + } + + protected void initializeOptionsGroup(Group group) { + group.setText("Other Options"); + group.setLayout(new RowLayout(SWT.VERTICAL)); + exportHiddenButton = new Button(group, SWT.CHECK); + exportHiddenButton.setText("Export Hidden"); + exportHiddenButton.setSelection(true); + exportHiddenButton + .setToolTipText("Include hidden products in the selection of products to export."); + exportHiddenButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + populateProductTree(); + } + }); + exportMapsButton = new Button(group, SWT.CHECK); + exportMapsButton.setText("Export Maps"); + exportMapsButton.setSelection(false); + exportMapsButton + .setToolTipText("Include maps in the selection of products to export."); + exportMapsButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + populateProductTree(); + } + }); + shadeEarthButton = new Button(group, SWT.CHECK); + shadeEarthButton.setText("Shade Earth"); + shadeEarthButton.setSelection(options.isShadeEarth()); + shadeEarthButton + .setToolTipText("Hides the Google Earth surface imagery."); + fillPlotsButton = new Button(group, SWT.CHECK); + fillPlotsButton.setText("Show Background Tiles"); + fillPlotsButton.setSelection(options.isFillPlotBackground()); + fillPlotsButton + .setToolTipText("Displays an opaque background tile behind point observations"); + } + + protected void initializeTimeOptionsGroup(Group group) { + group.setText("Time Options"); + group.setLayout(new RowLayout(SWT.VERTICAL)); + setTimesButton = new Button(group, SWT.CHECK); + setTimesButton.setText("Set KML Time"); + setTimesButton + .setSelection(options.getTimeMode() != KmlExportTimeMode.NONE); + setTimesButton + .setToolTipText("Causes Google Earth to display a time slider."); + Composite timeComposite = new Composite(group, SWT.NONE); + RowLayout layout = new RowLayout(SWT.VERTICAL); + layout.marginLeft = 20; + timeComposite.setLayout(layout); + timeSpanButton = new Button(timeComposite, SWT.RADIO); + timeSpanButton.setText("Time Span"); + timeSpanButton + .setSelection(options.getTimeMode() != KmlExportTimeMode.TIME_STAMP); + timeSpanButton.setEnabled(setTimesButton.getSelection()); + timeSpanButton + .setToolTipText("Allow products to be visible over a time range."); + timeStampButton = new Button(timeComposite, SWT.RADIO); + timeStampButton.setText("Time Stamp"); + timeStampButton + .setSelection(options.getTimeMode() == KmlExportTimeMode.TIME_STAMP); + timeStampButton.setEnabled(setTimesButton.getSelection()); + timeStampButton + .setToolTipText("Makes each product visible only at its exact valid time."); + setTimesButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + timeSpanButton.setEnabled(setTimesButton.getSelection()); + timeStampButton.setEnabled(setTimesButton.getSelection()); + } + + }); + } + + protected void initializeProductsGroup(Group group) { + group.setText("Products"); + group.setLayout(new FillLayout()); + productTree = new Tree(group, SWT.CHECK); + productTree.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + if (e.detail == SWT.CHECK) { + treeItemChecked((TreeItem) e.item); + } + super.widgetSelected(e); + } + + }); + } + + protected void initializeButtons(Composite comp) { + comp.setLayout(new RowLayout(SWT.HORIZONTAL)); + Button okButton = new Button(comp, SWT.PUSH); + okButton.setText("OK"); + okButton.setLayoutData(new RowData(100, SWT.DEFAULT)); + okButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + okPressed(); + } + + }); + + Button cancelButton = new Button(comp, SWT.PUSH); + cancelButton.setText("Cancel"); + cancelButton.setLayoutData(new RowData(100, SWT.DEFAULT)); + cancelButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + close(); + } + + }); + } + + protected void populateProductTree() { + boolean exportMaps = exportMapsButton.getSelection(); + boolean exportHidden = exportHiddenButton.getSelection(); + if (options.isSinglePane()) { + List rscList = options.getSinglPane().getResources( + exportMaps, exportHidden); + populateProductSubTree(rscList, null); + } else { + int index = 0; + for (KmlPane pane : options.getPanes()) { + List rscList = pane.getResources(exportMaps, + exportHidden); + TreeItem item = null; + if (index < productTree.getItemCount()) { + item = productTree.getItem(index); + } + if (!rscList.isEmpty()) { + if (item == null || item.getData() != pane) { + item = new TreeItem(productTree, SWT.NONE, index); + item.setText("Pane " + (index + 1)); + item.setData(pane); + populateProductSubTree(rscList, item); + item.setExpanded(true); + } else { + populateProductSubTree(rscList, item); + } + index += 1; + } else { + if (item != null && item.getData() == pane) { + item.dispose(); + } + } + } + } + } + + private void populateProductSubTree(List rscList, + final TreeItem parent) { + TreeItem[] items = parent != null ? parent.getItems() : productTree + .getItems(); + int itemIndex = 0; + int rscIndex = 0; + while (itemIndex < items.length || rscIndex < rscList.size()) { + TreeItem item = null; + if (itemIndex < items.length) { + item = items[itemIndex]; + } + ResourcePair pair = null; + if (rscIndex < rscList.size()) { + pair = rscList.get(rscIndex); + } + if (item != null && item.getData() == pair) { + itemIndex += 1; + rscIndex += 1; + } else if (item != null && !rscList.contains(item.getData())) { + item.dispose(); + itemIndex += 1; + } else { + if (parent != null) { + item = new TreeItem(parent, SWT.NONE, rscIndex); + } else { + item = new TreeItem(productTree, SWT.NONE, rscIndex); + } + String name = pair.getResource().getName(); + if (name == null) { + name = pair.getResource().getClass().getSimpleName(); + } + item.setText(name); + item.setData(pair); + item.setChecked(true); + treeItemChecked(item); + rscIndex += 1; + } + } + } + + private void treeItemChecked(TreeItem item) { + for (TreeItem ti : item.getItems()) { + ti.setChecked(item.getChecked()); + } + TreeItem parent = item.getParentItem(); + while (parent != null) { + parent.setChecked(true); + for (TreeItem ti : parent.getItems()) { + if (!ti.getChecked()) { + parent.setChecked(false); + break; + } + } + parent = parent.getParentItem(); + } + } + + protected void selectDestinationFile() { + FileDialog fileDialog = new FileDialog(this.shell, SWT.SAVE); + File file = new File(locationText.getText()); + fileDialog.setFileName(file.getName()); + if (file.getParentFile() != null && file.getParentFile().isDirectory()) { + fileDialog.setFilterPath(file.getParent()); + } + fileDialog.setFilterExtensions(new String[] { ".kmz" }); + fileDialog.open(); + + String filterPath = fileDialog.getFilterPath(); + String selectedFile = fileDialog.getFileName(); + /* + * Ensure that the user has entered a name for the file. + */ + if (selectedFile.equalsIgnoreCase("")) { + return; + } + + if (!filterPath.endsWith("/")) { + filterPath += "/"; + } + String destinationFile = filterPath + selectedFile; + this.locationText.setText(destinationFile); + this.locationText.setToolTipText(destinationFile); + } + + protected void okPressed() { + if (allFramesButton.getSelection()) { + options.setFirstFrameIndex(Integer.MIN_VALUE); + options.setLastFrameIndex(Integer.MAX_VALUE); + } else if (currentFramesButton.getSelection()) { + for (KmlPane pane : options.getPanes()) { + int frame = pane.getDisplay().getDescriptor().getFramesInfo() + .getFrameIndex(); + frame = Math.max(0, frame); + options.setFirstFrameIndex(frame); + options.setLastFrameIndex(frame + 1); + } + } else { + try { + int from = Integer.parseInt(framesFromText.getText()) - 1; + options.setFirstFrameIndex(from); + } catch (NumberFormatException e) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR + | SWT.OK); + mb.setText("Invalid Number"); + mb.setMessage(framesFromText.getText() + + " is not a valid number, please enter a valid number for the starting frame."); + mb.open(); + return; + } + try { + int to = Integer.parseInt(framesToText.getText()); + options.setLastFrameIndex(to); + } catch (NumberFormatException e) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR + | SWT.OK); + mb.setText("Invalid Number"); + mb.setMessage(framesFromText.getText() + + " is not a valid number, please enter a valid number for the ending frame."); + mb.open(); + return; + } + } + options.setKmzFileLocation(new File(locationText.getText())); + options.setShadeEarth(shadeEarthButton.getSelection()); + // if (!setTimesButton.getSelection()) { + // options.setTimeMode(KmlExportTimeMode.NONE); + // } else if (timeSpanButton.getSelection()) { + // options.setTimeMode(KmlExportTimeMode.TIME_SPAN); + // } else if (timeStampButton.getSelection()) { + // options.setTimeMode(KmlExportTimeMode.TIME_STAMP); + // + // } + options.setFillPlotBackground(fillPlotsButton.getSelection()); + if (options.isSinglePane()) { + List resourcesToExport = new ArrayList(); + for (TreeItem ti : productTree.getItems()) { + if (ti.getChecked()) { + resourcesToExport.add((ResourcePair) ti.getData()); + } + } + options.getSinglPane().setResourcesToExport(resourcesToExport); + } else { + for (TreeItem paneitem : productTree.getItems()) { + KmlPane pane = (KmlPane) paneitem.getData(); + List resourcesToExport = new ArrayList(); + for (TreeItem ti : paneitem.getItems()) { + if (ti.getChecked()) { + resourcesToExport.add((ResourcePair) ti.getData()); + } + } + pane.setResourcesToExport(resourcesToExport); + } + } + if (!validate()) { + // clear the current selection + for (KmlPane pane : options.getPanes()) { + pane.setResourcesToExport(null); + } + return; + } + new KmlExportJob(options).schedule(); + close(); + } + + protected boolean validate() { + boolean products = false; + for (KmlPane pane : options.getPanes()) { + if (pane.getResourcesToExport() != null + && !pane.getResourcesToExport().isEmpty()) { + products = true; + break; + } + } + if (!products) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText("No Products"); + mb.setMessage("No products are selected."); + mb.open(); + return false; + } + if (options.getFirstFrameIndex() > options.getLastFrameIndex() + || options.getLastFrameIndex() < 0) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText("Invalid Range"); + mb.setMessage("The frame range you entered is invalid, please enter a valid range"); + mb.open(); + return false; + } + File file = options.getKmzFileLocation(); + if (!file.getParentFile().exists()) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_QUESTION + | SWT.YES | SWT.NO); + mb.setText("Create Directory"); + mb.setMessage("The directory " + file.getParent() + + " does not exist, would you like to create it."); + int result = mb.open(); + if (result == SWT.YES) { + if (!file.getParentFile().mkdirs()) { + mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText("Error Creating Directory"); + mb.setMessage("An unspecified error has occured creating the directory, please select a new file location."); + mb.open(); + return false; + } + } else { + return false; + } + } + + if (file.exists()) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_WARNING + | SWT.YES | SWT.NO); + mb.setText("Overwrite file"); + mb.setMessage("The specified file already exist. Would you like to overwrite it?"); + int result = mb.open(); + if (result == SWT.NO) { + return false; + } + } + return true; + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportHandler.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportHandler.java new file mode 100644 index 0000000000..087bcceca8 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportHandler.java @@ -0,0 +1,103 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.IDisplayPaneContainer; +import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; +import com.raytheon.uf.viz.core.maps.display.MapRenderableDisplay; +import com.raytheon.uf.viz.kml.export.KmlExportOptions.KmlExportTimeMode; +import com.raytheon.viz.ui.EditorUtil; + +/** + * + * Handler for events from the KML Export menu item. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 1, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ +public class KmlExportHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + new KmlExportDialog(HandlerUtil.getActiveShell(event), + getDefaultOptions()).open(); + return null; + } + + protected static KmlExportOptions getDefaultOptions() { + KmlExportOptions options = new KmlExportOptions(); + options.setFirstFrameIndex(Integer.MIN_VALUE); + options.setLastFrameIndex(Integer.MAX_VALUE); + options.setPreserveVisibility(true); + options.setShadeEarth(false); + options.setTimeMode(KmlExportTimeMode.TIME_SPAN); + options.setKmzFileLocation(new File(System.getProperty("user.home"), + "caveExport.kmz")); + options.setPlotIconScale(3.5); + options.setFillPlotBackground(false); + options.setPaintSleepMillis(10); + options.setMaxRefreshSeconds(60); + IDisplayPaneContainer container = EditorUtil.getActiveVizContainer(); + List panes = new ArrayList(); + for (IDisplayPane pane : container.getDisplayPanes()) { + AbstractRenderableDisplay display = (AbstractRenderableDisplay) pane + .getRenderableDisplay(); + panes.add(new KmlPane(display, pane.getBounds())); + } + options.setPanes(panes); + return options; + } + + @Override + public void setEnabled(Object evaluationContext) { + IDisplayPaneContainer container = EditorUtil.getActiveVizContainer(); + if (container == null) { + super.setBaseEnabled(false); + return; + } + IDisplayPane pane = container.getActiveDisplayPane(); + if (pane == null) { + super.setBaseEnabled(false); + return; + } + super.setBaseEnabled(pane.getRenderableDisplay() instanceof MapRenderableDisplay); + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportJob.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportJob.java new file mode 100644 index 0000000000..74a10c515a --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportJob.java @@ -0,0 +1,676 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.awt.Graphics; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.TimeZone; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swt.graphics.RGB; +import org.geotools.geometry.DirectPosition2D; +import org.geotools.referencing.GeodeticCalculator; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.datum.PixelInCell; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; + +import com.raytheon.uf.common.colormap.Color; +import com.raytheon.uf.common.colormap.IColorMap; +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.common.geospatial.TransformFactory; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.IExtent; +import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; +import com.raytheon.uf.viz.core.drawables.ColorMapParameters; +import com.raytheon.uf.viz.core.drawables.ColorMapParameters.LabelEntry; +import com.raytheon.uf.viz.core.drawables.IDescriptor; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; +import com.raytheon.uf.viz.core.drawables.PaintProperties; +import com.raytheon.uf.viz.core.drawables.PaintStatus; +import com.raytheon.uf.viz.core.drawables.ResourcePair; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.jobs.JobPool; +import com.raytheon.uf.viz.core.rsc.AbstractVizResource; +import com.raytheon.uf.viz.core.rsc.IResourceGroup; +import com.raytheon.uf.viz.core.rsc.ResourceList; +import com.raytheon.uf.viz.core.rsc.capabilities.BlendableCapability; +import com.raytheon.uf.viz.core.rsc.capabilities.BlendedCapability; +import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability; +import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsFactoryAdapter; +import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget; +import com.raytheon.uf.viz.kml.export.io.KmlOutputManager; +import com.raytheon.uf.viz.kml.export.io.KmlRootOutputManager; + +import de.micromata.opengis.kml.v_2_2_0.AbstractObject; +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.LinearRing; +import de.micromata.opengis.kml.v_2_2_0.LookAt; +import de.micromata.opengis.kml.v_2_2_0.MultiGeometry; +import de.micromata.opengis.kml.v_2_2_0.Placemark; +import de.micromata.opengis.kml.v_2_2_0.PolyStyle; +import de.micromata.opengis.kml.v_2_2_0.ScreenOverlay; +import de.micromata.opengis.kml.v_2_2_0.Style; +import de.micromata.opengis.kml.v_2_2_0.TimePrimitive; +import de.micromata.opengis.kml.v_2_2_0.TimeSpan; +import de.micromata.opengis.kml.v_2_2_0.TimeStamp; +import de.micromata.opengis.kml.v_2_2_0.Units; +import de.micromata.opengis.kml.v_2_2_0.Vec2; + +/** + * The main Job for exporting KML in a background thread + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 6, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ + +public class KmlExportJob extends Job { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(KmlExportJob.class); + + private static final SimpleDateFormat KML_TIME_FORMAT = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + + private final KmlExportOptions options; + + private final JobPool backgroundPool = new JobPool("Exporting KML", 4, + true, Job.INTERACTIVE); + + public KmlExportJob(KmlExportOptions options) { + super("Generating Kml"); + setUser(true); + this.options = options; + KML_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + SubMonitor smonitor = SubMonitor + .convert(monitor, "Generating KML", 800); + + try { + copyPanes(smonitor.newChild(20, SubMonitor.SUPPRESS_NONE)); + + initPanes(smonitor.newChild(80, SubMonitor.SUPPRESS_NONE)); + + KmlRootOutputManager out = new KmlRootOutputManager( + options.getKmzFileLocation()); + + exportPanes(smonitor.newChild(500, SubMonitor.SUPPRESS_NONE), out); + joinBackground(smonitor.newChild(150, SubMonitor.SUPPRESS_NONE)); + // Do not dispose until all background processes are done + for (KmlPane pane : options.getPanes()) { + pane.getDisplay().dispose(); + } + recursiveInvisibility(out.getContainer(), true); + out.close(); + smonitor.worked(50); + } catch (IOException e) { + statusHandler.handle(Priority.PROBLEM, "Error writing KML", e); + } + smonitor.done(); + return Status.OK_STATUS; + } + + /** + * Copy each pane and remove any panes that aren't being exported. + * + * @param monitor + */ + private void copyPanes(IProgressMonitor monitor) { + // Keep this code as fast as possible, if the user runs kml export in + // the background and modifies the main display it will affect kml if + // copy is not done. + List panes = options.getPanes(); + monitor.beginTask("Copying Displays", panes.size()); + Iterator paneIt = panes.iterator(); + while (paneIt.hasNext()) { + KmlPane pane = paneIt.next(); + List exports = pane.getResourcesToExport(); + if (exports == null || exports.isEmpty()) { + paneIt.remove(); + } else { + try { + AbstractRenderableDisplay display = pane.getDisplay(); + // copy the current time before clone + FramesInfo fi = display.getDescriptor().getFramesInfo(); + if (fi.getFrameTimes() != null) { + int index = fi.getFrameIndex(); + if (index > options.getFirstFrameIndex() + && index < options.getLastFrameIndex()) { + pane.setDisplayedTime(fi.getFrameTimes()[fi + .getFrameIndex()]); + } + } + display = display.cloneDisplay(); + pane.setDisplay(display); + KmlGraphicsFactoryAdapter graphicsAdapter = new KmlGraphicsFactoryAdapter( + display.getView().getExtent(), pane.getBounds()); + display.setGraphicsAdapter(graphicsAdapter); + KmlGraphicsTarget target = graphicsAdapter.constructTarget( + null, 0.0f, 0.0f); + target.setBackgroundColor(display.getBackgroundColor()); + display.setup(target); + pane.setTarget(target); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + paneIt.remove(); + } + } + monitor.worked(1); + } + monitor.done(); + } + + private void initPanes(IProgressMonitor monitor) { + List panes = options.getPanes(); + monitor.beginTask("Initializing Displays", panes.size()); + Iterator paneIt = panes.iterator(); + while (paneIt.hasNext()) { + KmlPane pane = paneIt.next(); + try { + AbstractRenderableDisplay display = pane.getDisplay(); + + IDescriptor descriptor = display.getDescriptor(); + descriptor.setRenderableDisplay(display); + descriptor.getResourceList().instantiateResources(descriptor, + true); + for (ResourcePair rp : descriptor.getResourceList()) { + rp.getResource().init(pane.getTarget()); + monitor.worked(1); + } + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), + e); + paneIt.remove(); + } + monitor.worked(1); + } + monitor.done(); + } + + private void exportPanes(IProgressMonitor monitor, KmlOutputManager out) + throws IOException { + List panes = options.getPanes(); + SubMonitor smonitor = SubMonitor.convert(monitor, "Exporting Displays", + panes.size() * 100); + int paneNumber = 1; + for (KmlPane pane : options.getPanes()) { + KmlOutputManager displayOut = out; + if (!options.isSinglePane()) { + displayOut = out.createFolder("Pane " + (paneNumber++)); + } + AbstractRenderableDisplay display = pane.getDisplay(); + setView(pane, displayOut); + if (options.isShadeEarth()) { + shadeEarth(displayOut, display.getBackgroundColor()); + } + IDescriptor descriptor = display.getDescriptor(); + List exports = new ArrayList(); + for (ResourcePair rp : descriptor.getResourceList()) { + if (pane.getResourcesToExport().contains(rp)) { + exports.add(rp); + } else { + rp.getProperties().setVisible(false); + } + } + exportResources(smonitor.newChild(100, SubMonitor.SUPPRESS_NONE), + displayOut, exports, pane); + if (smonitor.isCanceled()) { + break; + } + } + smonitor.done(); + } + + private void exportResources(IProgressMonitor monitor, + KmlOutputManager out, List exports, KmlPane pane) + throws IOException { + SubMonitor smonitor = SubMonitor.convert(monitor, "Exporting Products", + exports.size() * 100); + KmlGraphicsTarget target = pane.getTarget(); + AbstractRenderableDisplay display = pane.getDisplay(); + IDescriptor descriptor = display.getDescriptor(); + List visibility = new ArrayList(); + for (ResourcePair rp : exports) { + visibility.add(rp.getProperties().isVisible()); + rp.getProperties().setVisible(false); + } + for (int c = 0; c < exports.size(); c++) { + ResourcePair rp = exports.get(c); + AbstractVizResource rsc = rp.getResource(); + rp.getProperties().setVisible(true); + String name = rp.getResource().getName(); + if (name == null) { + name = rp.getResource().getClass().getSimpleName(); + } + KmlOutputManager resourceOut = out.createFolder(name.trim()); + SubMonitor rscmonitor = smonitor.newChild(100, + SubMonitor.SUPPRESS_NONE); + if (rsc.hasCapability(BlendableCapability.class)) { + ResourceList list = rsc + .getCapability(BlendableCapability.class) + .getResourceList(); + exportResources(rscmonitor, resourceOut, list, pane); + } else { + int startIndex = options.getFirstFrameIndex(); + startIndex = Math.max(startIndex, 0); + int lastIndex = options.getLastFrameIndex(); + lastIndex = Math.min(lastIndex, descriptor.getNumberOfFrames()); + rscmonitor.beginTask("Saving " + rsc.getName(), lastIndex + - startIndex); + addColorMap(resourceOut, display.getBackgroundColor(), rsc); + DataTime[] times = descriptor.getFramesInfo().getTimeMap() + .get(rsc); + if ((times == null || times.length == 0) + && rsc instanceof IResourceGroup) { + ResourceList list = ((IResourceGroup) rsc) + .getResourceList(); + for (ResourcePair pair : list) { + times = descriptor.getFramesInfo().getTimeMap() + .get(pair.getResource()); + if (times != null && times.length > 0) { + break; + } + } + } + List pastFrames = new ArrayList(); + for (int i = startIndex; i < lastIndex; i += 1) { + descriptor.setFramesInfo(new FramesInfo(i)); + KmlOutputManager timeOut = resourceOut; + if (rsc.isTimeAgnostic() + && (times == null || times.length == 0)) { + i = lastIndex - 1; + } else { + if (i < 0 || times == null || i >= times.length) { + rscmonitor.worked(1); + continue; + } + DataTime time = times[i]; + if (time == null || pastFrames.contains(time)) { + rscmonitor.worked(1); + continue; + } + timeOut = resourceOut.createFolder(time + .getLegendString()); + timeOut.getContainer().setTimePrimitive( + getTimePrimitive(times, i)); + pastFrames.add(time); + } + PaintProperties paintProps = new PaintProperties(1.0f, + (float) display.getZoom(), display.getView(), + pane.getBounds(), false, descriptor.getFramesInfo()); + paintResource(rscmonitor, timeOut, display, target, rsc, + paintProps); + rscmonitor.worked(1); + if (rscmonitor.isCanceled()) { + return; + } + } + } + rp.getProperties().setVisible(false); + if (options.isPreserveVisibility() && !visibility.get(c)) { + resourceOut.getContainer().setVisibility(false); + } + rscmonitor.done(); + } + } + + private void setView(KmlPane pane, KmlOutputManager out) { + IExtent extent = pane.getDisplay().getView().getExtent(); + try { + DirectPosition2D center = new DirectPosition2D( + extent.getCenter()[0], extent.getCenter()[1]); + DirectPosition2D corner = new DirectPosition2D(extent.getMaxX(), + extent.getMinX()); + MathTransform gridToLatLon = TransformFactory.gridToLatLon(pane + .getDisplay().getDescriptor().getGridGeometry(), + PixelInCell.CELL_CENTER); + gridToLatLon.transform(center, center); + gridToLatLon.transform(corner, corner); + + GeodeticCalculator gc = new GeodeticCalculator(); + gc.setStartingGeographicPoint(MapUtil.correctLon(center.x), + center.y); + gc.setDestinationGeographicPoint(MapUtil.correctLon(corner.x), + corner.y); + LookAt lookAt = out.getContainer().createAndSetLookAt(); + lookAt.setLongitude(center.x); + lookAt.setLatitude(center.y); + lookAt.setRange(gc.getOrthodromicDistance()); + if (pane.getDisplayedTime() != null) { + DataTime time = pane.getDisplayedTime(); + TimeStamp ts = new TimeStamp(); + ts.setWhen(KML_TIME_FORMAT.format(new Date(time.getMatchValid()))); + // At the time of this writing the current api doesn't allow + // setting time primitive for AbstractView + lookAt.setAbstractViewObjectExtension(Arrays + .asList((AbstractObject) ts)); + } + } catch (TransformException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); + } catch (FactoryException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); + } + } + + /** + * Given a list of times for a resource and the index of the current time, + * generate a KML TimePrimitive for a resource. When the time mode is SPAN + * the times in the array are used to calculate a span such that the spans + * for every time create a continuos time line. + * + * @param times + * @param index + * @return + */ + private TimePrimitive getTimePrimitive(DataTime[] times, int index) { + long validTime = times[index].getMatchValid(); + switch (options.getTimeMode()) { + case TIME_STAMP: { + TimeStamp ts = new TimeStamp(); + ts.setWhen(KML_TIME_FORMAT.format(new Date(validTime))); + return ts; + } + case TIME_SPAN: { + long prevValid = 0; + long nextValid = 0; + for (DataTime t : times) { + if (t == null) { + continue; + } + long valid = t.getMatchValid(); + if (valid < validTime) { + if (prevValid == 0 || prevValid < valid) { + prevValid = valid; + } + } else if (valid > validTime) { + if (nextValid == 0 || nextValid > valid) { + nextValid = valid; + } + } + } + long prevDist = 0; + long nextDist = 0; + if (prevValid != 0) { + nextDist = prevDist = (validTime - prevValid) / 2; + } + if (nextValid != 0) { + nextDist = (nextValid - validTime) / 2; + if (prevDist == 0) { + prevDist = nextDist; + } + } + TimeSpan span = new TimeSpan(); + span.setBegin(KML_TIME_FORMAT + .format(new Date(validTime - prevDist))); + span.setEnd(KML_TIME_FORMAT.format(new Date(validTime + nextDist))); + return span; + } + default: + return null; + } + } + + /** + * KML reference documentation from google clearly states that a feature is + * visible only if all of it's ancestors are also visible. Google + * Earth(tested on version 6.2) ignores this and displays everything as + * visible unless that item is specifically set to invisible even when + * ancestors are invisible. This function makes google earth work properly + * by finding invisible features and making all their children invisible. + * + * @param feature + * @param parentVisibility + */ + private void recursiveInvisibility(Feature feature, boolean parentVisibility) { + if (!parentVisibility) { + feature.setVisibility(false); + } + List features = null; + if (feature instanceof Folder) { + features = ((Folder) feature).getFeature(); + } else if (feature instanceof Document) { + features = ((Document) feature).getFeature(); + } + if (features == null) { + return; + } + for (Feature f : features) { + if (f == null) { + continue; + } + recursiveInvisibility(f, + !Boolean.FALSE.equals(feature.isVisibility())); + } + } + + private void paintResource(IProgressMonitor monitor, KmlOutputManager out, + AbstractRenderableDisplay display, KmlGraphicsTarget target, + AbstractVizResource resource, PaintProperties paintProps) { + target.setNeedsRefresh(true); + long startTime = System.currentTimeMillis(); + while (target.isNeedsRefresh() + || resource.getPaintStatus() != PaintStatus.PAINTED) { + if (target.isNeedsRefresh()) { + target.beginFrame(paintProps.getView(), false); + try { + display.paint(target, paintProps); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + return; + } + target.endFrame(); + } + if (System.currentTimeMillis() - startTime > options + .getMaxRefreshSeconds() * 1000) { + statusHandler.handle(Priority.PROBLEM, resource.getName() + + " took more than " + options.getMaxRefreshSeconds() + + " seconds to paint, KML may be incomplete."); + break; + } + try { + Thread.sleep(options.getPaintSleepMillis()); + } catch (InterruptedException e) { + } + if (monitor.isCanceled()) { + break; + } + } + List generators = new ArrayList( + target.getGenerators()); + for (KmlFeatureGenerator generator : generators) { + generator + .setGridGeometry(display.getDescriptor().getGridGeometry()); + generator.setBackgroundColor(display.getBackgroundColor()); + generator.setOptions(options); + } + backgroundPool.schedule(new GenerateRunnable(generators, out)); + } + + private void addColorMap(KmlOutputManager out, RGB backcolor, + AbstractVizResource rsc) throws IOException { + ColorMapParameters parameters = null; + if (rsc.hasCapability(ColorMapCapability.class)) { + ColorMapCapability cap = rsc + .getCapability(ColorMapCapability.class); + parameters = cap.getColorMapParameters(); + } else { + return; + } + double xAnchor = 0; + if (rsc.hasCapability(BlendedCapability.class)) { + BlendedCapability cap = rsc.getCapability(BlendedCapability.class); + xAnchor = Math.min(1, cap.getResourceIndex()); + } + IColorMap colorMap = parameters.getColorMap(); + BufferedImage bi = new BufferedImage(colorMap.getSize() * 2, 25, + BufferedImage.TYPE_INT_RGB); + Graphics graphics = bi.getGraphics(); + graphics.setColor(new java.awt.Color(backcolor.red, backcolor.green, + backcolor.blue)); + graphics.fillRect(0, 0, bi.getWidth(), 25); + int x = 0; + for (Color color : colorMap.getColors()) { + graphics.setColor(new java.awt.Color(color.getRed(), color + .getGreen(), color.getBlue(), color.getAlpha())); + graphics.drawLine(x, 0, x, 25); + x += 1; + graphics.drawLine(x, 0, x, 25); + x += 1; + } + for (LabelEntry label : parameters.getLabels()) { + if (label.getText().isEmpty()) { + continue; + } + Rectangle2D bounds = graphics.getFontMetrics().getStringBounds( + label.getText(), graphics); + int centerX = (int) (bi.getWidth() * label.getLocation()); + int leftX = (int) (centerX - bounds.getWidth() / 2); + if (leftX < 0) { + leftX = 0; + } else if (leftX + bounds.getWidth() > bi.getWidth()) { + leftX = (int) (bi.getWidth() - bounds.getWidth()); + } + graphics.setColor(java.awt.Color.BLACK); + graphics.fillRect(leftX - 1, 2, (int) bounds.getWidth() + 2, + (int) bounds.getHeight() + 2); + graphics.setColor(java.awt.Color.WHITE); + graphics.drawString(label.getText(), leftX, + (int) bounds.getHeight() + 1); + } + graphics.dispose(); + ScreenOverlay overlay = new ScreenOverlay(); + overlay.setName("ColorMap"); + Vec2 overlayxy = overlay.createAndSetOverlayXY(); + overlayxy.withX(xAnchor).withXunits(Units.FRACTION); + overlayxy.withY(1).withYunits(Units.FRACTION); + Vec2 screenxy = overlay.createAndSetScreenXY(); + screenxy.withX(xAnchor).withXunits(Units.FRACTION); + screenxy.withY(1).withYunits(Units.FRACTION); + overlay.createAndSetIcon().setHref( + out.addImage(bi, "colormap" + xAnchor + ".png")); + out.addFeature(overlay); + } + + private void shadeEarth(KmlOutputManager out, RGB color) { + Placemark placemark = new Placemark(); + placemark.setName("Background Color"); + Style style = new Style(); + style.createAndSetIconStyle().setScale(0.0); + PolyStyle polyStyle = style.createAndSetPolyStyle(); + polyStyle.setFill(true); + polyStyle.setOutline(false); + polyStyle.setColor(KmlFeatureGenerator.toColorStr(1.0, color)); + placemark.setStyleUrl(out.getStyleUrl(style)); + // Google earth seems to do a weird things with one big polygon when you + // zoom way out, specifically there is lots of flickering and it misses + // big pieces towards the back of the sphere, lots of smaller polygons + // helps avoid the missing hunks but I still see a lot of flickering. + MultiGeometry multi = placemark.createAndSetMultiGeometry(); + for (int i = -180; i < 180; i += 10) { + for (int j = -90; j < 90; j += 10) { + LinearRing ring = multi.createAndAddPolygon() + .createAndSetOuterBoundaryIs().createAndSetLinearRing(); + ring.addToCoordinates(i, j); + ring.addToCoordinates(i, j + 10); + ring.addToCoordinates(i + 10, j + 10); + ring.addToCoordinates(i + 10, j); + ring.addToCoordinates(i, j); + } + + } + out.addFeature(placemark); + } + + private void joinBackground(IProgressMonitor monitor) { + // some tasks(like radar mosaic) can take a very long time to finish the + // background task, so this waits for those to finish and makes an + // attempt to let the user know how it is going. + int remaining = backgroundPool.getWorkRemaining(); + monitor.beginTask("Finalizing KML", remaining); + while (remaining > 0) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + } + int r = backgroundPool.getWorkRemaining(); + monitor.worked(remaining - r); + remaining = r; + if (monitor.isCanceled()) { + monitor.subTask("Canceling"); + backgroundPool.cancel(); + break; + } + } + backgroundPool.join(); + } + + private static class GenerateRunnable implements Runnable { + + private final List generators; + + private final KmlOutputManager outputManager; + + public GenerateRunnable(List generators, + KmlOutputManager outputManager) { + this.generators = generators; + this.outputManager = outputManager; + } + + @Override + public void run() { + for (KmlFeatureGenerator generator : generators) { + generator.addFeature(outputManager); + } + } + + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportOptions.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportOptions.java new file mode 100644 index 0000000000..e1f98cc73c --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlExportOptions.java @@ -0,0 +1,172 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.io.File; +import java.util.List; + +/** + * Contains any options which can be configured for KML export. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 4, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ + +public class KmlExportOptions { + + public enum KmlExportTimeMode { + NONE, TIME_STAMP, TIME_SPAN; + } + + private File kmzFileLocation; + + private int firstFrameIndex; + + private int lastFrameIndex; + + private boolean shadeEarth; + + // Google Earth requires a fairly large plot scale to make plots look nice + // but World Wind prefers a smaller scale. + private double plotIconScale; + + private boolean fillPlotBackground; + + private boolean preserveVisibility; + + private KmlExportTimeMode timeMode; + + private List panes; + + private int paintSleepMillis; + + private int maxRefreshSeconds; + + public File getKmzFileLocation() { + return kmzFileLocation; + } + + public void setKmzFileLocation(File kmzFileLocation) { + this.kmzFileLocation = kmzFileLocation; + } + + public int getFirstFrameIndex() { + return firstFrameIndex; + } + + public void setFirstFrameIndex(int firstFrameIndex) { + this.firstFrameIndex = firstFrameIndex; + } + + public int getLastFrameIndex() { + return lastFrameIndex; + } + + public void setLastFrameIndex(int lastFrameIndex) { + this.lastFrameIndex = lastFrameIndex; + } + + public boolean isShadeEarth() { + return shadeEarth; + } + + public void setShadeEarth(boolean shadeEarth) { + this.shadeEarth = shadeEarth; + } + + public boolean isFillPlotBackground() { + return fillPlotBackground; + } + + public void setFillPlotBackground(boolean fillPlotBackground) { + this.fillPlotBackground = fillPlotBackground; + } + + public boolean isPreserveVisibility() { + return preserveVisibility; + } + + public void setPreserveVisibility(boolean preserveVisibility) { + this.preserveVisibility = preserveVisibility; + } + + public KmlExportTimeMode getTimeMode() { + return timeMode; + } + + public void setTimeMode(KmlExportTimeMode timeMode) { + this.timeMode = timeMode; + } + + public List getPanes() { + return panes; + } + + public void setPanes(List panes) { + this.panes = panes; + } + + public boolean isSinglePane() { + return panes != null && panes.size() == 1; + } + + public KmlPane getSinglPane() { + if (isSinglePane()) { + return panes.get(0); + } else { + return null; + } + } + + public int getPaintSleepMillis() { + return paintSleepMillis; + } + + public void setPaintSleepMillis(int paintSleepMillis) { + this.paintSleepMillis = paintSleepMillis; + } + + public int getMaxRefreshSeconds() { + return maxRefreshSeconds; + } + + public void setMaxRefreshSeconds(int maxRefreshSeconds) { + this.maxRefreshSeconds = maxRefreshSeconds; + } + + public double getPlotIconScale() { + return plotIconScale; + } + + public void setPlotIconScale(double plotIconScale) { + this.plotIconScale = plotIconScale; + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlFeatureGenerator.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlFeatureGenerator.java new file mode 100644 index 0000000000..5bdb52ba34 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlFeatureGenerator.java @@ -0,0 +1,111 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.graphics.RGB; +import org.geotools.coverage.grid.GeneralGridGeometry; +import org.geotools.coverage.grid.GridGeometry2D; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.datum.PixelInCell; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; + +import com.raytheon.uf.common.geospatial.TransformFactory; +import com.raytheon.uf.viz.kml.export.io.KmlOutputManager; + +import de.micromata.opengis.kml.v_2_2_0.Coordinate; + +/** + * Anything that can be drawn on the screen can also be used to create a KML + * feature, this class provides some basic utility functions as well as an + * interface for classes that generate KML. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 14, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ + +public abstract class KmlFeatureGenerator { + + protected GridGeometry2D gridGeometry; + + protected MathTransform gridToLatLon; + + protected RGB backgroundColor; + + protected KmlExportOptions options; + + public void setGridGeometry(GeneralGridGeometry gridGeometry) { + this.gridGeometry = GridGeometry2D.wrap(gridGeometry); + } + + public void setBackgroundColor(RGB backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public void setOptions(KmlExportOptions options) { + this.options = options; + } + + public Coordinate transformToLatLon(double gridX, double gridY) + throws TransformException, FactoryException { + return transformToLatLon(new double[] { gridX, gridY }); + } + + public Coordinate transformToLatLon(double[] gridPixel) + throws TransformException, FactoryException { + if (gridToLatLon == null) { + gridToLatLon = TransformFactory.gridToLatLon(gridGeometry, + PixelInCell.CELL_CENTER); + } + double[] out = new double[2]; + gridToLatLon.transform(gridPixel, 0, out, 0, 1); + return new Coordinate(out[0], out[1]); + } + + public List transformToLatLon(List gridPixels) + throws TransformException, FactoryException { + List result = new ArrayList(); + for (double[] gridPixel : gridPixels) { + result.add(transformToLatLon(gridPixel)); + } + return result; + } + + public abstract void addFeature(KmlOutputManager outputManager); + + public static String toColorStr(double alpha, RGB rgb) { + return String.format("%02x%02x%02x%02x", (int) (alpha * 255), rgb.blue, + rgb.green, rgb.red); + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlPane.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlPane.java new file mode 100644 index 0000000000..a889a562d3 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/KmlPane.java @@ -0,0 +1,123 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.graphics.Rectangle; + +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; +import com.raytheon.uf.viz.core.drawables.ResourcePair; +import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget; + +/** + * VizDisplayPane but for KML! + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 5, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ + +public class KmlPane { + + private List resourcesToExport; + + private AbstractRenderableDisplay display; + + private Rectangle bounds; + + private KmlGraphicsTarget target; + + private DataTime displayedTime; + + public KmlPane(AbstractRenderableDisplay display, Rectangle bounds) { + this.display = display; + this.bounds = bounds; + } + + public List getResources(boolean includeMaps, + boolean includeHidden) { + List rscList = new ArrayList(); + for (ResourcePair rp : display.getDescriptor().getResourceList()) { + if (!rp.getResourceData().equals(rp.getResourceData())) { + // A special check for those special resources which will never + // work with KML because they don't properly implement equals. + // ... like GFE + continue; + } else if (rp.getProperties().isSystemResource()) { + continue; + } else if (!includeMaps && rp.getProperties().isMapLayer()) { + continue; + } else if (!includeHidden && !rp.getProperties().isVisible()) { + continue; + } + rscList.add(rp); + } + return rscList; + } + + public void setDisplay(AbstractRenderableDisplay display) { + this.display = display; + } + + public void setTarget(KmlGraphicsTarget target) { + this.target = target; + } + + public List getResourcesToExport() { + return resourcesToExport; + } + + public void setResourcesToExport(List resourcesToExport) { + this.resourcesToExport = resourcesToExport; + } + + public AbstractRenderableDisplay getDisplay() { + return display; + } + + public Rectangle getBounds() { + return bounds; + } + + public KmlGraphicsTarget getTarget() { + return target; + } + + public DataTime getDisplayedTime() { + return displayedTime; + } + + public void setDisplayedTime(DataTime displayedTime) { + this.displayedTime = displayedTime; + } + +} diff --git a/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlFont.java b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlFont.java new file mode 100644 index 0000000000..51883cc759 --- /dev/null +++ b/cave/com.raytheon.uf.viz.kml.export/src/com/raytheon/uf/viz/kml/export/graphics/KmlFont.java @@ -0,0 +1,185 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.kml.export.graphics; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.raytheon.uf.viz.core.drawables.IFont; + +/** + * + * KML has really bad font support so only support the minimum operations + * required to avoid errors. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 1, 2012            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ +public class KmlFont implements IFont { + + private Font font; + + private float magnification; + + private boolean scaleFont; + + private boolean smoothing; + + public KmlFont(Font font) { + this.font = font; + this.magnification = 1.0f; + } + + public KmlFont() { + this(new Font(java.awt.Font.MONOSPACED, Font.BOLD, 14)); + } + + public KmlFont(String fontName) { + this(new Font(fontName, Font.PLAIN, 10)); + + } + + public KmlFont(String fontName, float fontSize) { + this(new Font(fontName, Font.PLAIN, (int) fontSize)); + } + + public KmlFont(String fontName, float fontSize, Style[] styles) { + this(new Font(fontName, toAwtStyle(styles), (int) fontSize)); + } + + public KmlFont(File fontFile, float fontSize, Style[] styles) + throws FontFormatException, IOException { + this(Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(fontSize) + .deriveFont(toAwtStyle(styles))); + } + + @Override + public String getFontName() { + return this.font.getFontName(); + } + + @Override + public float getFontSize() { + return this.font.getSize2D(); + } + + @Override + public Style[] getStyle() { + return toVizStyles(font.getStyle()); + } + + @Override + public void dispose() { + + } + + @Override + public IFont deriveWithSize(float size) { + return new KmlFont(font.deriveFont(size)); + } + + @Override + public void setMagnification(float magnification) { + setMagnification(magnification, true); + } + + @Override + public void setMagnification(float magnification, boolean scaleFont) { + if (scaleFont) { + this.font = font.deriveFont(font.getSize2D() * magnification); + } else { + this.magnification = magnification; + } + } + + @Override + public float getMagnification() { + return magnification; + } + + @Override + public void setSmoothing(boolean smooth) { + this.smoothing = smooth; + } + + @Override + public boolean getSmoothing() { + return smoothing; + } + + @Override + public boolean isScaleFont() { + return scaleFont; + } + + @Override + public void setScaleFont(boolean scaleFont) { + this.scaleFont = scaleFont; + } + + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + + private static int toAwtStyle(Style[] styles) { + int styleInt = Font.PLAIN; + if (styles == null || styles.length == 0) { + return styleInt; + } + for (Style style : styles) { + if (style == Style.BOLD) { + styleInt |= Font.BOLD; + } else if (style == Style.ITALIC) { + styleInt |= Font.ITALIC; + } + } + return styleInt; + } + + private static Style[] toVizStyles(int style) { + List