Issue #1141 - Merging KML into the Common Baseline

Former-commit-id: 7b45633097 [formerly c3f584fdc5f53ecd62afe41c481aaa96cf532009]
Former-commit-id: 3180ae0c57
This commit is contained in:
Bryan Kowal 2012-09-05 18:39:08 -05:00
parent 35aff16e89
commit 8d444b35d3
56 changed files with 6755 additions and 1 deletions

View file

@ -112,6 +112,10 @@
<copy todir="${buildDirectory}/plugins">
<fileset dir="${buildDirectory}/../../../" includes="edu.*/**"/>
</copy>
<echo message="de.*/**"/>
<copy todir="${buildDirectory}/plugins">
<fileset dir="${buildDirectory}/../../../" includes="de.*/**"/>
</copy>
<antcall target="getBaseComponents" />
</target>

View file

@ -107,6 +107,12 @@
<fileset dir="${workspace.dir}"
includes="edu.*/**" />
</copy>
<echo message="PLUGINS: de.*/**" />
<copy todir="${basedir}/cave/p2/plugins">
<fileset dir="${workspace.dir}"
includes="de.*/**" />
</copy>
<!-- END: Copy The Plugins -->
<!-- Copy The Features -->
@ -266,7 +272,11 @@
<param name="feature"
value="com.raytheon.uf.viz.thinclient.feature" />
</antcall>
<antcall target="p2.build.repo">
<param name="feature"
value="com.raytheon.uf.viz.kml.export.feature" />
</antcall>
<antcall target="cleanup.features" />
</target>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.viz.kml.export.feature</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

View file

@ -0,0 +1 @@
bin.includes = feature.xml

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="com.raytheon.uf.viz.kml.export.feature"
label="Kml Export Feature"
version="1.0.0.qualifier">
<description url="http://www.example.com/description">
[Enter Feature Description here.]
</description>
<copyright url="http://www.example.com/copyright">
[Enter Copyright Description here.]
</copyright>
<license url="http://www.example.com/license">
[Enter License Description here.]
</license>
<plugin
id="de.micromata.opengis.kml"
download-size="0"
install-size="0"
version="0.0.0"/>
<plugin
id="com.raytheon.uf.viz.kml.export"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.viz.kml.export</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="menu:export">
<command
commandId="com.raytheon.uf.viz.kml.export.exportKML"
label="KML"
style="push">
</command>
</menuContribution>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="com.raytheon.uf.viz.kml.export.exportKML"
name="Export KML">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="com.raytheon.uf.viz.kml.export.KmlExportHandler"
commandId="com.raytheon.uf.viz.kml.export.exportKML">
</handler>
</extension>
<extension
point="com.raytheon.uf.viz.core.graphicsExtension">
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.point.KmlPointImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlSingleColorImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlColormappedImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlMapMeshExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.radar.KmlRadialMeshExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlMosaicImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlMosaicMaxValImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlMosaicOrderedImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.uf.viz.kml.export.graphics.ext.KmlCanvasRenderingExtension">
</graphicsExtension>
</extension>
</plugin>

View file

@ -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;
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 5, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<ResourcePair> rscList = options.getSinglPane().getResources(
exportMaps, exportHidden);
populateProductSubTree(rscList, null);
} else {
int index = 0;
for (KmlPane pane : options.getPanes()) {
List<ResourcePair> 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<ResourcePair> 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<ResourcePair> resourcesToExport = new ArrayList<ResourcePair>();
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<ResourcePair> resourcesToExport = new ArrayList<ResourcePair>();
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;
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<KmlPane> panes = new ArrayList<KmlPane>();
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);
}
}

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 6, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<KmlPane> panes = options.getPanes();
monitor.beginTask("Copying Displays", panes.size());
Iterator<KmlPane> paneIt = panes.iterator();
while (paneIt.hasNext()) {
KmlPane pane = paneIt.next();
List<ResourcePair> 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<KmlPane> panes = options.getPanes();
monitor.beginTask("Initializing Displays", panes.size());
Iterator<KmlPane> 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<KmlPane> 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<ResourcePair> exports = new ArrayList<ResourcePair>();
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<ResourcePair> 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<Boolean> visibility = new ArrayList<Boolean>();
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<DataTime> pastFrames = new ArrayList<DataTime>();
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<Feature> 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<KmlFeatureGenerator> generators = new ArrayList<KmlFeatureGenerator>(
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<KmlFeatureGenerator> generators;
private final KmlOutputManager outputManager;
public GenerateRunnable(List<KmlFeatureGenerator> generators,
KmlOutputManager outputManager) {
this.generators = generators;
this.outputManager = outputManager;
}
@Override
public void run() {
for (KmlFeatureGenerator generator : generators) {
generator.addFeature(outputManager);
}
}
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 4, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<KmlPane> 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<KmlPane> getPanes() {
return panes;
}
public void setPanes(List<KmlPane> 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;
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<Coordinate> transformToLatLon(List<double[]> gridPixels)
throws TransformException, FactoryException {
List<Coordinate> result = new ArrayList<Coordinate>();
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);
}
}

View file

@ -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!
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 5, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPane {
private List<ResourcePair> 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<ResourcePair> getResources(boolean includeMaps,
boolean includeHidden) {
List<ResourcePair> rscList = new ArrayList<ResourcePair>();
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<ResourcePair> getResourcesToExport() {
return resourcesToExport;
}
public void setResourcesToExport(List<ResourcePair> 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;
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @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<Style> styles = new ArrayList<Style>();
if ((style & Font.BOLD) != 0) {
styles.add(Style.BOLD);
}
if ((style & Font.ITALIC) != 0) {
styles.add(Style.ITALIC);
}
return styles.toArray(new Style[0]);
}
}

View file

@ -0,0 +1,101 @@
/**
* 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 org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.opengis.coverage.grid.GridEnvelope;
import com.raytheon.uf.viz.core.AbstractGraphicsFactoryAdapter;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.PixelExtent;
import com.raytheon.uf.viz.core.exception.VizException;
import com.vividsolutions.jts.geom.Coordinate;
/**
*
* Not very interesting, just constructs KML things
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlGraphicsFactoryAdapter extends AbstractGraphicsFactoryAdapter {
// The view needs to know the extent and canvas bounds from the source pane.
private final IExtent extent;
private final Rectangle canvasBounds;
public KmlGraphicsFactoryAdapter(IExtent extent, Rectangle canvasBounds) {
this.extent = extent;
this.canvasBounds = canvasBounds;
}
@Override
public KmlView constructView() {
return new KmlView(extent, canvasBounds);
}
@Override
public KmlGraphicsTarget constructTarget(Canvas canvas, float width,
float height) throws VizException {
return new KmlGraphicsTarget();
}
@Override
public IExtent constructExtent(Coordinate[] coords) throws VizException {
return new PixelExtent(coords);
}
@Override
public IExtent constructExtent(double aMinX, double aMaxX, double aMinY,
double aMaxY) throws VizException {
return new PixelExtent(aMinX, aMaxX, aMinY, aMaxY);
}
@Override
public IExtent constructExtent(Rectangle rect) throws VizException {
return new PixelExtent(rect);
}
@Override
public IExtent constructExtent(GridEnvelope range) throws VizException {
return new PixelExtent(range);
}
@Override
public Canvas constrcutCanvas(Composite canvasComp) throws VizException {
// Its possible we should just return null and not worry so much
throw new UnsupportedOperationException(
"KmlGraphicsFactoryAdapter does not support creating a canvas");
}
}

View file

@ -0,0 +1,333 @@
/**
* 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.FontFormatException;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.PlatformUI;
import org.geotools.coverage.grid.GeneralGridGeometry;
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.viz.core.AbstractGraphicsTarget;
import com.raytheon.uf.viz.core.DrawableCircle;
import com.raytheon.uf.viz.core.DrawableColorMap;
import com.raytheon.uf.viz.core.DrawableLine;
import com.raytheon.uf.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IView;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.IFont;
import com.raytheon.uf.viz.core.drawables.IFont.Style;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.IShadedShape;
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.graphics.basicgen.KmlCirclesGenerator;
import com.raytheon.uf.viz.kml.export.graphics.basicgen.KmlLinesGenerator;
import com.raytheon.uf.viz.kml.export.graphics.basicgen.KmlPointsGenerator;
import com.raytheon.uf.viz.kml.export.graphics.basicgen.KmlRectGenerator;
import com.raytheon.uf.viz.kml.export.graphics.basicgen.KmlStringsGenerator;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImage;
/**
*
* Takes graphics operations and produces a list of KmlFeatureGenerators that
* can be used to make KML.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlGraphicsTarget extends AbstractGraphicsTarget {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlGraphicsTarget.class);
private final KmlFont defaultFont = new KmlFont();
private List<KmlFeatureGenerator> generators = new ArrayList<KmlFeatureGenerator>(
256);
protected IView view;
public KmlGraphicsTarget() {
super();
}
public void setView(IView view) {
this.view = view;
}
@Override
public KmlFont initializeFont(String fontId) {
FontRegistry registry = PlatformUI.getWorkbench().getThemeManager()
.getCurrentTheme().getFontRegistry();
if (registry.hasValueFor(fontId)) {
FontData[] data = registry.getFontData(fontId);
FontData fd = data[0];
if (fd == null) {
statusHandler.handle(Priority.PROBLEM,
"No font data found for id: " + fontId);
}
float size = fd.height;
String name = fd.getName();
List<IFont.Style> styles = new ArrayList<IFont.Style>();
int style = fd.getStyle();
if ((style & SWT.BOLD) != 0) {
styles.add(IFont.Style.BOLD);
}
if ((style & SWT.ITALIC) != 0) {
styles.add(IFont.Style.ITALIC);
}
return new KmlFont(name, size,
styles.toArray(new IFont.Style[styles.size()]));
} else {
return getDefaultFont();
}
}
@Override
public KmlFont initializeFont(String fontName, float size, Style[] styles) {
return new KmlFont(fontName, size, styles);
}
@Override
public KmlFont initializeFont(File fontFile, float size, Style[] styles) {
try {
return new KmlFont(fontFile, size, styles);
} catch (FontFormatException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (IOException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
return new KmlFont((String) null, size, styles);
}
@Override
public void drawWireframeShape(IWireframeShape shape, RGB color,
float lineWidth, LineStyle lineStyle, IFont font, float alpha)
throws VizException {
addGenerator(new KmlWireframeShape.Generator((KmlWireframeShape) shape,
alpha, color, lineWidth));
}
@Override
public KmlWireframeShape createWireframeShape(boolean mutable,
GeneralGridGeometry geom, float simplificationLevel) {
return new KmlWireframeShape(geom);
}
@Override
public KmlWireframeShape createWireframeShape(boolean mutableFlag,
GeneralGridGeometry geom) {
return new KmlWireframeShape(geom);
}
@Override
public KmlWireframeShape createWireframeShape(boolean mutable,
GeneralGridGeometry geom, float simplificationLevel,
boolean spatialChopFlag, IExtent extent) {
return new KmlWireframeShape(geom);
}
@Override
public KmlFont getDefaultFont() {
return defaultFont;
}
public RGB getBackgroundColor() {
return backgroundColor;
}
@Override
public Rectangle2D getStringsBounds(DrawableString parameters, String string) {
KmlFont kmlFont = (KmlFont) parameters.font;
if (kmlFont == null) {
kmlFont = getDefaultFont();
}
FontRenderContext frc = new FontRenderContext(null, false, false);
Rectangle2D rect = kmlFont.getFont().getStringBounds(string, frc);
double width = rect.getWidth() * kmlFont.getMagnification();
double height = rect.getHeight() * kmlFont.getMagnification();
return new Rectangle2D.Double(0, 0, width, height);
}
@Override
public void drawStrings(Collection<DrawableString> parameters)
throws VizException {
addGenerator(new KmlStringsGenerator(parameters));
}
@Override
public void drawPoints(Collection<double[]> locations, RGB color,
PointStyle pointStyle, float magnification) throws VizException {
addGenerator(new KmlPointsGenerator(locations, color, pointStyle,
magnification));
}
@Override
public void drawLine(DrawableLine... lines) throws VizException {
addGenerator(new KmlLinesGenerator(lines));
}
@Override
public void drawCircle(DrawableCircle... circles) throws VizException {
addGenerator(new KmlCirclesGenerator(circles));
}
@Override
public IImage initializeRaster(IRenderedImageCallback imageCallback) {
return new KmlRasterImage(imageCallback);
}
@Override
public IShadedShape createShadedShape(boolean mutable,
GeneralGridGeometry targetGeometry, boolean tesselate) {
return new KmlShadedShape(targetGeometry);
}
@Override
public void drawShadedShapes(float alpha, float brightness,
IShadedShape... shapes) throws VizException {
for (IShadedShape shape : shapes) {
addGenerator(new KmlShadedShape.Generator(alpha,
(KmlShadedShape) shape));
}
}
@Override
public void drawRect(IExtent pe, RGB color, float lineWidth, double alpha)
throws VizException {
addGenerator(new KmlRectGenerator(pe, color, alpha, lineWidth, false));
}
@Override
public void drawShadedRect(IExtent pe, RGB color, double alpha,
byte[] pattern) throws VizException {
addGenerator(new KmlRectGenerator(pe, color, alpha, 1.0f, true));
}
@Override
public void init() {
// this function intentionally left blank
}
@Override
public void beginFrame(IView view, boolean isClearBackground) {
setNeedsRefresh(false);
generators.clear();
}
@Override
public void endFrame() {
// this function intentionally left blank
}
@Override
public void resize() {
// no need
}
@Override
public void dispose() {
// nothing
}
@Override
public BufferedImage screenshot() {
// No one should be doing this.
return null;
}
@Override
public void setupClippingPlane(IExtent extent) {
// for now always ignore cliiping panes
}
@Override
public void clearClippingPlane() {
// for now always ignore cliiping panes
}
@Override
public void drawColorRamp(DrawableColorMap colorMap) throws VizException {
// currently this is handled outside the target, it might move here some
// day but screen overlay rendering through the target is a bit
// difficult for labels and things.
}
/**
* Used by graphics extensions to add generators to the current frame.
*
* @param generator
*/
public void addGenerator(KmlFeatureGenerator generator) {
generators.add(generator);
}
/**
* Get the generators used during the last frame paint.
*
* @return
*/
public List<KmlFeatureGenerator> getGenerators() {
return generators;
}
@Override
public void drawWireframeShape(IWireframeShape shape, RGB color,
float lineWidth, LineStyle lineStyle, float alpha)
throws VizException {
drawWireframeShape(shape, color, lineWidth, lineStyle,
getDefaultFont(), alpha);
}
@Override
public IView getView() {
return view;
}
}

View file

@ -0,0 +1,208 @@
/**
* 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry;
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.core.drawables.IShadedShape;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Geometry;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Polygon;
/**
* Implementation of shaded shape that can create a generator for making KML
* filled polygons. KML has no concept of a fill pattern so it is completly
* ignored and all polygons are filled with color.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlShadedShape implements IShadedShape {
private Map<RGB, List<Polygon>> polygons = new HashMap<RGB, List<Polygon>>();
private final GeneralGridGeometry gridGeometry;
public KmlShadedShape(GeneralGridGeometry gridGeometry) {
this.gridGeometry = gridGeometry;
}
@Override
public void compile() {
}
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean isDrawable() {
return true;
}
@Override
public void dispose() {
polygons.clear();
}
@Override
public void reset() {
polygons.clear();
}
@Override
public void addPolygon(LineString[] lineString, RGB color) {
Polygon p = new Polygon();
LinearRing outer = p.createAndSetOuterBoundaryIs()
.createAndSetLinearRing();
for (Coordinate c : lineString[0].getCoordinates()) {
outer.addToCoordinates(c.x, c.y);
}
for (int i = 1; i < lineString.length; i += 1) {
LinearRing inner = p.createAndAddInnerBoundaryIs()
.createAndSetLinearRing();
for (Coordinate c : lineString[i].getCoordinates()) {
inner.addToCoordinates(c.x, c.y);
}
}
List<Polygon> polygons = this.polygons.get(color);
if (polygons == null) {
polygons = new ArrayList<Polygon>();
this.polygons.put(color, polygons);
}
polygons.add(p);
}
@Override
public void addPolygonPixelSpace(LineString[] contours, RGB color) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
double[] loc = new double[2];
LineString[] newContours = new LineString[contours.length];
for (int i = 0; i < contours.length; i += 1) {
List<Coordinate> newCoordinates = new ArrayList<Coordinate>();
for (Coordinate c : contours[i].getCoordinates()) {
loc = new double[] { c.x, c.y };
transform.transform(loc, 0, loc, 0, 1);
newCoordinates.add(new Coordinate(loc[0], loc[1]));
}
newContours[i] = contours[i].getFactory().createLineString(
newCoordinates.toArray(new Coordinate[0]));
}
addPolygon(newContours, color);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
@Override
public void setFillPattern(byte[] pattern) {
}
public static class Generator extends KmlFeatureGenerator {
private final double alpha;
private final Map<RGB, List<Polygon>> polygons;
public Generator(double alpha, KmlShadedShape shape) {
this.alpha = alpha;
this.polygons = new HashMap<RGB, List<Polygon>>(shape.polygons);
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (polygons.size() == 1) {
Entry<RGB, List<Polygon>> entry = polygons.entrySet()
.iterator().next();
outputManager.addFeature(getPlacemark(outputManager,
entry.getKey(), entry.getValue()));
} else if (!polygons.isEmpty()) {
Folder folder = new Folder();
folder.setName("Shaded Shapes");
for (Entry<RGB, List<Polygon>> entry : polygons.entrySet()) {
folder.addToFeature(getPlacemark(outputManager,
entry.getKey(), entry.getValue()));
}
outputManager.addFeature(folder);
}
}
private Placemark getPlacemark(KmlOutputManager out, RGB color,
List<Polygon> polygons) {
Placemark placemark = new Placemark();
placemark.setName("Shaded Shape");
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetPolyStyle().withFill(true)
.withColor(toColorStr(alpha, color));
kmlStyle.createAndSetLineStyle()
.withColor(toColorStr(alpha, color));
placemark.setStyleUrl(out.getStyleUrl(kmlStyle));
if (polygons.size() == 1) {
placemark.setGeometry(polygons.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(
new ArrayList<Geometry>(polygons));
}
return placemark;
}
}
}

View file

@ -0,0 +1,108 @@
/**
* 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 org.eclipse.swt.graphics.Rectangle;
import com.raytheon.uf.viz.core.AbstractView;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget;
/**
*
* Minimalistic implementation of a view for KML. Can not be shifted or
* modified, so KML does not supprt Pan/Zoom.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlView extends AbstractView {
private final Rectangle canvasBounds;
public KmlView(IExtent extent, Rectangle canvasBounds) {
super(extent);
this.canvasBounds = canvasBounds;
}
@Override
public void setupView(IGraphicsTarget target) {
if (target instanceof KmlGraphicsTarget) {
((KmlGraphicsTarget) target).setView(this);
return;
}
throw new IllegalArgumentException(
"KmlView was expecting a KmlGraphicsTarget but recieved "
+ target.getClass().getSimpleName());
}
@Override
public double recalcZoomLevel(int[] dimensions) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void zoom(double zoomLevel) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void scaleAndBias(double factor, double screenX, double screenY,
IGraphicsTarget target) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void setExtent(IExtent pe) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void shiftExtent(double[] startScreen, double[] endScreen,
IGraphicsTarget target) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void scaleToClientArea(Rectangle clientArea, int[] dimensions) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public KmlView clone() {
return new KmlView(extent.clone(), canvasBounds);
}
@Override
public Rectangle getCanvasBounds(IGraphicsTarget target) {
return canvasBounds;
}
}

View file

@ -0,0 +1,284 @@
/**
* 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry;
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.core.drawables.IWireframeShape;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.vividsolutions.jts.geom.Coordinate;
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.Geometry;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
import de.micromata.opengis.kml.v_2_2_0.LineString;
import de.micromata.opengis.kml.v_2_2_0.LineStyle;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
*
* Converts a wireframe shape into KML LineStrings and Labels.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlWireframeShape implements IWireframeShape {
private List<Geometry> segments = new ArrayList<Geometry>();
private Map<String, List<Geometry>> labels = new HashMap<String, List<Geometry>>();
private final GeneralGridGeometry gridGeometry;
public KmlWireframeShape(GeneralGridGeometry gridGeometry) {
this.gridGeometry = gridGeometry;
}
@Override
public void compile() {
}
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean isDrawable() {
return true;
}
@Override
public void dispose() {
segments.clear();
labels.clear();
}
@Override
public void reset() {
segments.clear();
labels.clear();
}
@Override
public void addLineSegment(Coordinate[] latLong) {
LineString line = new LineString();
for (Coordinate c : latLong) {
line.addToCoordinates(round(c.x), round(c.y));
}
segments.add(line);
}
@Override
public void addLineSegment(double[][] screenCoordinates) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
LineString line = new LineString();
double[] out = new double[2];
for (int i = 0; i < screenCoordinates.length; i += 1) {
transform.transform(screenCoordinates[i], 0, out, 0, 1);
line.addToCoordinates(round(out[0]), round(out[1]));
}
segments.add(line);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
/**
* round a latitude or longitude, rounding can cut the size of the generated
* kml and only moves the actual line by less than a meter.
*
* @param value
* @return
*/
private double round(double value) {
return ((long) (value * 100000)) / 100000.0;
}
@Override
public void addLabel(String label, double[] screenCoordinate) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
double[] out = new double[2];
transform.transform(screenCoordinate, 0, out, 0, 1);
Point point = new Point();
point.addToCoordinates(round(out[0]), round(out[1]));
List<Geometry> points = labels.get(label);
if (points == null) {
points = new ArrayList<Geometry>();
labels.put(label, points);
}
points.add(point);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
@Override
public void clearLabels() {
labels.clear();
}
@Override
public void allocate(int points) {
}
public static class Generator extends KmlFeatureGenerator {
private final List<Geometry> segments;
private final Map<String, List<Geometry>> labels;
private final float alpha;
private final RGB color;
private final float lineWidth;
public Generator(KmlWireframeShape shape, float alpha, RGB color,
float lineWidth) {
this.segments = new ArrayList<Geometry>(shape.segments);
this.labels = new HashMap<String, List<Geometry>>(shape.labels);
this.alpha = alpha;
this.color = color;
this.lineWidth = lineWidth;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (segments.isEmpty() && labels.isEmpty()) {
return;
}
String styleUrl = outputManager.getStyleUrl(getStyle());
Feature lineFeature = getLineFeature(styleUrl);
Feature labelFeature = getLabelFeature(styleUrl);
if (lineFeature == null) {
outputManager.addFeature(labelFeature);
} else if (labelFeature == null) {
outputManager.addFeature(lineFeature);
} else {
Folder folder = new Folder();
folder.setName("LinesAndLabels");
folder.addToFeature(lineFeature);
folder.addToFeature(labelFeature);
outputManager.addFeature(folder);
}
}
private Style getStyle() {
Style style = new de.micromata.opengis.kml.v_2_2_0.Style();
LineStyle lineStyle = style.createAndSetLineStyle();
LabelStyle labelStyle = style.createAndSetLabelStyle();
style.createAndSetIconStyle().setScale(0);
String colorStr = toColorStr(alpha, color);
lineStyle.setColor(colorStr);
lineStyle.setWidth(lineWidth);
labelStyle.setColor(colorStr);
labelStyle.setScale(1.0);
return style;
}
private Feature getLineFeature(String styleUrl) {
if (segments.isEmpty()) {
return null;
}
Placemark placemark = new Placemark();
placemark.setName("Lines");
placemark.setStyleUrl(styleUrl);
if (segments.size() == 1) {
placemark.setGeometry(segments.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(
new ArrayList<Geometry>(segments));
}
return placemark;
}
private Feature getLabelFeature(String styleUrl) {
if (labels.size() == 1) {
for (Entry<String, List<Geometry>> entry : labels.entrySet()) {
return createLabelPlacemark(entry.getKey(),
entry.getValue(), styleUrl);
}
} else if (!labels.isEmpty()) {
Folder folder = new Folder();
folder.setName("Labels");
for (Entry<String, List<Geometry>> entry : labels.entrySet()) {
Placemark placemark = createLabelPlacemark(entry.getKey(),
entry.getValue(), styleUrl);
folder.addToFeature(placemark);
}
return folder;
}
return null;
}
private Placemark createLabelPlacemark(String label,
List<Geometry> points, String styleUrl) {
Placemark placemark = new Placemark();
placemark.setName(label);
placemark.setStyleUrl(styleUrl);
if (points.size() == 1) {
placemark.setGeometry(points.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(points);
}
return placemark;
}
}
}

View file

@ -0,0 +1,119 @@
/**
* 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.basicgen;
import java.util.ArrayList;
import java.util.List;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
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.viz.core.DrawableCircle;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
/**
* Generates KML polygons for DrawableCircles.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlCirclesGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlLinesGenerator.class);
private final DrawableCircle[] circles;
public KmlCirclesGenerator(DrawableCircle[] circles) {
this.circles = circles;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (circles.length > 1) {
outputManager = outputManager.createFolder("Circles");
}
for (DrawableCircle circle : circles) {
String colorStr = toColorStr(circle.basics.alpha,
circle.basics.color);
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetLabelStyle().setScale(0);
kmlStyle.createAndSetIconStyle().setScale(0);
if (circle.filled) {
kmlStyle.createAndSetPolyStyle().withFill(true)
.withColor(colorStr);
} else {
kmlStyle.createAndSetLineStyle().withWidth(circle.lineWidth)
.withColor(colorStr);
}
Placemark placemark = new Placemark();
placemark.setName("Circle");
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
List<double[]> pts = new ArrayList<double[]>();
double step = 360.0 / (circle.numberOfPoints);
double radius = circle.radius == null ? circle.screenRadius
: circle.radius;
try {
for (double i = 0; i <= circle.numberOfPoints; i++) {
double[] pt = new double[2];
pt[0] = circle.basics.x + radius
* Math.cos(Math.toRadians(i * step));
pt[1] = circle.basics.y + radius
* Math.sin(Math.toRadians(i * step));
pts.add(pt);
}
if (circle.filled) {
placemark.createAndSetPolygon()
.createAndSetOuterBoundaryIs()
.createAndSetLinearRing()
.withCoordinates(transformToLatLon(pts));
} else {
placemark.createAndSetLineString().withCoordinates(
transformToLatLon(pts));
}
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
outputManager.addFeature(placemark);
}
}
}

View file

@ -0,0 +1,92 @@
/**
* 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.basicgen;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
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.viz.core.DrawableLine;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
/**
* Generates KML line strings for DrawableLine.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlLinesGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlLinesGenerator.class);
private final DrawableLine[] lines;
public KmlLinesGenerator(DrawableLine[] lines) {
super();
this.lines = lines;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (lines.length > 1) {
outputManager = outputManager.createFolder("Lines");
}
for (DrawableLine line : lines) {
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetLabelStyle().setScale(0);
kmlStyle.createAndSetIconStyle().setScale(0);
kmlStyle.createAndSetLineStyle()
.withWidth(line.width)
.withColor(toColorStr(line.basics.alpha, line.basics.color));
Placemark placemark = new Placemark();
placemark.setName("Line");
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
try {
placemark.createAndSetLineString().withCoordinates(
transformToLatLon(line.points));
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
}

View file

@ -0,0 +1,162 @@
/**
* 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.basicgen;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Collection;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
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.viz.core.IGraphicsTarget.PointStyle;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
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.Point;
/**
* Generates KML point icons.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPointsGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlStringsGenerator.class);
private final Collection<double[]> locations;
private final RGB color;
private final PointStyle pointStyle;
private final float magnification;
public KmlPointsGenerator(Collection<double[]> locations, RGB color,
PointStyle pointStyle, float magnification) {
super();
this.locations = locations;
this.color = color;
this.pointStyle = pointStyle;
this.magnification = magnification;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
BufferedImage image = new BufferedImage(15, 15,
BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.getGraphics();
if (graphics instanceof Graphics2D) {
((Graphics2D) graphics).setStroke(new BasicStroke(3.0f));
}
graphics.setColor(new java.awt.Color(0, 0, 0, 0));
graphics.fillRect(0, 0, 24, 24);
graphics.setColor(new java.awt.Color(color.red, color.green, color.blue));
switch (pointStyle) {
case NONE:
graphics.dispose();
return;
case SQUARE:
graphics.fillRect(1, 1, 13, 13);
break;
case CIRCLE:
graphics.drawOval(1, 1, 13, 13);
break;
case CROSS:
graphics.drawLine(7, 0, 7, 14);
graphics.drawLine(0, 7, 14, 7);
break;
case DASH:
graphics.drawLine(0, 7, 14, 7);
break;
case POINT:
graphics.fillOval(5, 5, 5, 5);
break;
case BOX:
graphics.drawRect(1, 1, 13, 13);
break;
case STAR:
graphics.drawLine(7, 0, 7, 14);
case X:
graphics.drawLine(0, 0, 14, 14);
graphics.drawLine(0, 14, 14, 0);
break;
case DISC:
default:
graphics.fillOval(1, 1, 13, 13);
break;
}
graphics.dispose();
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
LabelStyle kmlLabelStyle = kmlStyle.createAndSetLabelStyle();
IconStyle kmlIconStyle = kmlStyle.createAndSetIconStyle();
kmlIconStyle.createAndSetIcon().setHref(outputManager.addImage(image));
kmlLabelStyle.setScale(0);
kmlIconStyle.setScale(magnification * 0.5);
Placemark placemark = new Placemark();
placemark.setName(pointStyle.toString());
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
try {
if (locations.size() == 1) {
Point p = placemark.createAndSetPoint();
Coordinate loc = transformToLatLon(locations.iterator().next());
p.addToCoordinates(loc.getLongitude(), loc.getLatitude());
} else {
MultiGeometry multi = placemark.createAndSetMultiGeometry();
for (double[] location : locations) {
Point p = multi.createAndAddPoint();
Coordinate loc = transformToLatLon(location);
p.addToCoordinates(loc.getLongitude(), loc.getLatitude());
}
}
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
}

View file

@ -0,0 +1,113 @@
/**
* 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.basicgen;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
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.viz.core.IExtent;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* Generates kml Polygon for both filled and not filled rectangles.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRectGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRectGenerator.class);
private final IExtent pe;
private final RGB color;
private final double alpha;
private final float lineWidth;
private final boolean filled;
public KmlRectGenerator(IExtent pe, RGB color, double alpha,
float lineWidth, boolean filled) {
this.pe = pe;
this.color = color;
this.alpha = alpha;
this.lineWidth = lineWidth;
this.filled = filled;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
Placemark placemark = new Placemark();
placemark.setName("Rectangle");
Style style = new de.micromata.opengis.kml.v_2_2_0.Style();
style.createAndSetLabelStyle().setScale(0);
style.createAndSetIconStyle().setScale(0);
style.createAndSetLineStyle().withWidth(lineWidth)
.withColor(toColorStr(alpha, color));
style.createAndSetPolyStyle().withFill(filled)
.withColor(toColorStr(alpha, color));
try {
LinearRing ring = placemark.createAndSetPolygon()
.createAndSetOuterBoundaryIs().createAndSetLinearRing();
Coordinate corner = transformToLatLon(pe.getMinX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMaxX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMaxX(), pe.getMaxY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMinX(), pe.getMaxY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMinX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
placemark.setStyleUrl(outputManager.getStyleUrl(style));
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
}

View file

@ -0,0 +1,189 @@
/**
* 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.basicgen;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
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.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
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.Point;
/**
* Generates KML Placemark Labels for DrawableStrings.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlStringsGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlStringsGenerator.class);
private final Collection<DrawableString> parameters;
public KmlStringsGenerator(Collection<DrawableString> parameters) {
this.parameters = parameters;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
Collection<DrawableString> parameters = mergeDuplicatePoints();
if (parameters.size() > 1) {
outputManager = outputManager.createFolder("Labels");
}
Map<String, Placemark> redundantPlacemarks = new HashMap<String, Placemark>();
for (DrawableString dstring : parameters) {
RGB color = dstring.getColors()[0];
for (RGB dcolor : dstring.getColors()) {
if (!dcolor.equals(color)) {
statusHandler.handle(Priority.INFO,
"Multicolor labels will be one color in kml");
}
break;
}
String colorStr = toColorStr(dstring.basics.alpha, color);
StringBuilder text = new StringBuilder(dstring.getText()[0]);
for (int i = 1; i < dstring.getText().length; i++) {
text.append(" ");
text.append(dstring.getText()[i]);
}
Placemark placemark = redundantPlacemarks.get(text.toString()
+ colorStr + dstring.magnification);
if (placemark == null) {
// google earth handles multiple points in a single placemark
// faster than multiple placemarks with a single point, so
// combine wherever possible
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
LabelStyle kmlLabelStyle = kmlStyle.createAndSetLabelStyle();
IconStyle kmlIconStyle = kmlStyle.createAndSetIconStyle();
kmlLabelStyle.setColor(colorStr);
double magnifiaction = dstring.magnification;
if (dstring.font != null) {
magnifiaction *= dstring.font.getMagnification();
}
kmlLabelStyle.setScale(magnifiaction);
kmlIconStyle.setScale(0);
placemark = new Placemark();
placemark.setName(text.toString());
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
outputManager.addFeature(placemark);
redundantPlacemarks.put(text.toString() + colorStr
+ dstring.magnification, placemark);
}
Point point = null;
if (placemark.getGeometry() == null) {
point = placemark.createAndSetPoint();
} else if (placemark.getGeometry() instanceof Point) {
point = (Point) placemark.getGeometry();
MultiGeometry multi = placemark.createAndSetMultiGeometry();
multi.addToGeometry(point);
point = multi.createAndAddPoint();
} else {
MultiGeometry multi = (MultiGeometry) placemark.getGeometry();
point = multi.createAndAddPoint();
}
try {
Coordinate loc = transformToLatLon(dstring.basics.x,
dstring.basics.y);
point.addToCoordinates(loc.getLongitude(), loc.getLatitude());
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
private Collection<DrawableString> mergeDuplicatePoints() {
Map<Coordinate, DrawableString> pointMap = new HashMap<Coordinate, DrawableString>();
for (DrawableString dstring : parameters) {
Coordinate c = new Coordinate(dstring.basics.x, dstring.basics.y);
if (pointMap.containsKey(c)) {
DrawableString inMap = pointMap.get(c);
DrawableString dstring2 = inMap;
// try determine which of the two dtrings would be considered
// "first"
if (dstring2.verticallAlignment != dstring.verticallAlignment) {
if (dstring2.verticallAlignment == VerticalAlignment.BOTTOM
|| dstring.verticallAlignment == VerticalAlignment.TOP) {
DrawableString tmp = dstring2;
dstring2 = dstring;
dstring = tmp;
}
} else if (dstring2.horizontalAlignment != dstring.horizontalAlignment) {
if (dstring2.horizontalAlignment == HorizontalAlignment.RIGHT
|| dstring.horizontalAlignment == HorizontalAlignment.LEFT) {
DrawableString tmp = dstring2;
dstring2 = dstring;
dstring = tmp;
}
}
String[] text1 = dstring.getText();
String[] text2 = dstring2.getText();
RGB[] colors1 = dstring.getColors();
RGB[] colors2 = dstring2.getColors();
String[] text = Arrays.copyOf(text1, text1.length
+ text2.length);
System.arraycopy(text2, 0, text, text1.length, text2.length);
RGB[] colors = Arrays.copyOf(colors1, colors1.length
+ colors2.length);
System.arraycopy(colors2, 0, colors, colors1.length,
colors2.length);
inMap.setText(text, colors);
} else {
pointMap.put(c, dstring);
}
}
return pointMap.values();
}
}

View file

@ -0,0 +1,412 @@
/**
* 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.ext;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import com.raytheon.uf.viz.core.DrawableColorMap;
import com.raytheon.uf.viz.core.DrawableLine;
import com.raytheon.uf.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
import com.raytheon.uf.viz.core.IGraphicsTarget.TextStyle;
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.drawables.ext.ICanvasRenderingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.graphics.KmlFont;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.ScreenOverlay;
import de.micromata.opengis.kml.v_2_2_0.Units;
import de.micromata.opengis.kml.v_2_2_0.Vec2;
/**
* Converts canvas rendering into KML screen overlays.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 26, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlCanvasRenderingExtension extends
GraphicsExtension<KmlGraphicsTarget> implements
ICanvasRenderingExtension {
@Override
public void drawStrings(PaintProperties paintProps,
DrawableString... parameters) throws VizException {
getGenerator(paintProps).addStrings(parameters);
}
@Override
public void drawLines(PaintProperties paintProps,
DrawableLine... parameters) throws VizException {
getGenerator(paintProps).addLines(parameters);
}
@Override
public void drawColorRamp(PaintProperties paintProps,
DrawableColorMap colorMap) throws VizException {
getGenerator(paintProps).addColorMaps(colorMap);
}
protected Generator getGenerator(PaintProperties paintProps) {
for (KmlFeatureGenerator generator : target.getGenerators()) {
if (generator instanceof Generator) {
return (Generator) generator;
}
}
Generator generator = new Generator(paintProps.getCanvasBounds());
target.addGenerator(generator);
return generator;
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
/**
*
* Renders all canvas drawables to one or more screen overlays. The number
* of screen overlays is determined by overlapping the rendering area all
* objects and drawing any overlapping objects to a single overlay. This
* provides a good compromise between a single overlay which does not work
* well on different sized clients and one screen overlay per object, which
* causes problems when nearby objects do not line up(such as radar tables).
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 26, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
private static class Generator extends KmlFeatureGenerator {
private final Rectangle canvasBounds;
private final List<Object> objects = new ArrayList<Object>();
public Generator(Rectangle canvasBounds) {
this.canvasBounds = canvasBounds;
}
public void addStrings(DrawableString... strings) {
this.objects.addAll(Arrays.asList(strings));
}
public void addLines(DrawableLine... lines) {
this.objects.addAll(Arrays.asList(lines));
}
public void addColorMaps(DrawableColorMap... colorMaps) {
this.objects.addAll(Arrays.asList(colorMaps));
}
@Override
public void addFeature(KmlOutputManager outputManager) {
Map<Object, Rectangle2D> boundsMap = new IdentityHashMap<Object, Rectangle2D>();
List<Rectangle2D> combinedBounds = new ArrayList<Rectangle2D>();
for (Object object : objects) {
Rectangle2D bounds = getBounds(object);
boundsMap.put(object, bounds);
addBounds(combinedBounds, bounds);
}
for (Rectangle2D bounds : combinedBounds) {
BufferedImage bi = new BufferedImage((int) Math.ceil(bounds
.getWidth()), (int) Math.ceil(bounds.getHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics graphics = bi.getGraphics();
for (Object object : objects) {
if (bounds.contains(boundsMap.get(object))) {
draw(graphics, bounds, object);
}
}
graphics.dispose();
graphics.finalize();
bi.flush();
ScreenOverlay overlay = new ScreenOverlay();
overlay.setName("ScreenOverlay");
Vec2 overlayxy = overlay.createAndSetOverlayXY();
overlayxy.withXunits(Units.FRACTION).withYunits(Units.FRACTION);
Vec2 screenxy = overlay.createAndSetScreenXY();
screenxy.withXunits(Units.FRACTION).withYunits(Units.FRACTION);
// This is fairly complex placement code but it produces rather
// nice results on any size of display. Basically if something
// is flush against either the left or right of the screen it
// ends up anchored on that side, if some is smack in the center
// than the anchor point is in the middle of both the overlay
// and the display. Now if an object is offcenter to the left or
// right than the anchor point moves in the correct direction in
// proportion to how far off center it is, its hard to explain
// without a picture but at the end of the day it produces a
// nice result.
double leftFrac = bounds.getMinX() / canvasBounds.width;
double rightFrac = 1.0 - bounds.getMaxX() / canvasBounds.width;
if (leftFrac < rightFrac) {
overlayxy.setX(leftFrac / rightFrac / 2);
} else {
overlayxy.setX(1.0 - rightFrac / leftFrac / 2);
}
double x = (bounds.getX() + bounds.getWidth()
* overlayxy.getX())
/ canvasBounds.width;
screenxy.setX(x);
double topFrac = bounds.getMinY() / canvasBounds.height;
double botFrac = 1.0 - bounds.getMaxY() / canvasBounds.height;
if (topFrac < botFrac) {
overlayxy.setY(1.0 - topFrac / botFrac / 2);
} else {
overlayxy.setY(botFrac / topFrac / 2);
}
// all this 1.0 - stuff is because the math is mostly assuming 0
// is up and 1.0 is down but kml expects the opposite.
double y = 1.0
- (bounds.getY() + bounds.getHeight()
* (1.0 - overlayxy.getY()))
/ canvasBounds.height;
screenxy.setY(y);
overlay.createAndSetIcon().setHref(
outputManager.addImage(bi, "ScreenOverlay.png"));
outputManager.addFeature(overlay);
}
}
private void addBounds(List<Rectangle2D> allBounds, Rectangle2D bounds) {
Iterator<Rectangle2D> it = allBounds.iterator();
while (it.hasNext()) {
Rectangle2D b = it.next();
if (b.intersects(bounds)) {
if (!b.contains(bounds)) {
// need to recheck the larger rectangle of b for any new
// intersections.
it.remove();
b.add(bounds);
addBounds(allBounds, b);
}
return;
}
}
allBounds.add(bounds);
}
protected void draw(Graphics graphics, Rectangle2D imageBounds,
Object object) {
if (object instanceof DrawableString) {
drawStrings(graphics, imageBounds, (DrawableString) object);
} else if (object instanceof DrawableLine) {
drawLines(graphics, imageBounds, (DrawableLine) object);
} else if (object instanceof DrawableColorMap) {
drawColorMap(graphics, imageBounds, (DrawableColorMap) object);
}
}
protected void drawStrings(Graphics graphics, Rectangle2D imageBounds,
DrawableString string) {
KmlFont kmlFont = (KmlFont) string.font;
if (kmlFont == null) {
kmlFont = new KmlFont();
}
graphics.setFont(kmlFont.getFont());
double x = (string.basics.x - imageBounds.getX());
double y = (string.basics.y - imageBounds.getY());
String[] text = string.getText();
RGB[] colors = string.getColors();
for (int i = 0; i < text.length; i += 1) {
Rectangle2D bounds = graphics.getFontMetrics().getStringBounds(
text[i], graphics);
double realX = x;
double realY = y;
if (HorizontalAlignment.RIGHT == string.horizontalAlignment) {
realX -= bounds.getWidth();
} else if (HorizontalAlignment.CENTER == string.horizontalAlignment) {
realX -= bounds.getWidth() / 2;
}
if (VerticalAlignment.TOP == string.verticallAlignment) {
realY -= bounds.getY();
} else if (VerticalAlignment.MIDDLE == string.verticallAlignment) {
realY -= bounds.getY() / 2;
}
if (string.textStyle == TextStyle.BLANKED) {
setColor(graphics, backgroundColor);
graphics.fillRect((int) realX,
(int) (realY + bounds.getY()),
(int) bounds.getWidth(),
(int) bounds.getHeight() + 1);
}
setColor(graphics, colors[i]);
graphics.drawString(text[i], (int) realX, (int) realY);
y += bounds.getHeight();
}
}
protected void drawLines(Graphics graphics, Rectangle2D imageBounds,
DrawableLine line) {
setColor(graphics, line.basics.color);
double[] pt1 = line.points.get(0);
pt1[0] -= imageBounds.getX();
pt1[1] -= imageBounds.getY();
for (int i = 1; i < line.points.size(); i++) {
double[] pt2 = line.points.get(i);
pt2[0] -= imageBounds.getX();
pt2[1] -= imageBounds.getY();
graphics.drawLine((int) pt1[0], (int) pt1[1], (int) pt2[0],
(int) pt2[1]);
pt1 = pt2;
}
}
protected void drawColorMap(Graphics graphics, Rectangle2D imageBounds,
DrawableColorMap colorMap) {
double xStart = colorMap.extent.getMinX() - imageBounds.getX();
double yStart = colorMap.extent.getMinY() - imageBounds.getY();
setColor(graphics, backgroundColor);
graphics.fillRect((int) xStart, (int) yStart,
(int) colorMap.extent.getWidth(),
(int) colorMap.extent.getHeight());
double x1 = xStart;
double xd = colorMap.extent.getWidth()
/ colorMap.getColorMapParams().getColorMap().getSize();
for (com.raytheon.uf.common.colormap.Color color : colorMap
.getColorMapParams().getColorMap().getColors()) {
graphics.setColor(new Color(color.getRed(), color.getGreen(),
color.getBlue(), color.getAlpha()));
graphics.fillRect((int) x1, (int) yStart, (int) Math.ceil(xd),
(int) colorMap.extent.getHeight());
x1 += xd;
}
}
protected void setColor(Graphics graphics, RGB color) {
graphics.setColor(new Color(color.red, color.green, color.blue));
}
protected Rectangle2D getBounds(Object object) {
if (object instanceof DrawableString) {
return getStringBounds((DrawableString) object);
} else if (object instanceof DrawableLine) {
return getLineBounds((DrawableLine) object);
} else if (object instanceof DrawableColorMap) {
return getColorMapBounds((DrawableColorMap) object);
}
return null;
}
protected Rectangle2D getLineBounds(DrawableLine line) {
Rectangle2D bounds = null;
for (double[] point : line.points) {
if (bounds == null) {
bounds = new Rectangle2D.Double(point[0], point[1], 0, 0);
} else {
bounds.add(point[0], point[1]);
}
}
// add a buffer region to ensure we have room for wide lines on
// the edge.
bounds.add(bounds.getMinX() - line.width, bounds.getMinY()
- line.width);
bounds.add(bounds.getMaxX() + line.width, bounds.getMaxY()
+ line.width);
return bounds;
}
protected Rectangle2D getStringBounds(DrawableString string) {
KmlFont kmlFont = (KmlFont) string.font;
if (kmlFont == null) {
kmlFont = new KmlFont();
}
FontRenderContext frc = new FontRenderContext(null, false, false);
Rectangle2D bounds = null;
String[] text = string.getText();
double x = string.basics.x;
double y = string.basics.y;
for (int i = 0; i < text.length; i += 1) {
Rectangle2D b = kmlFont.getFont().getStringBounds(text[i], frc);
b.setFrame(x, y, b.getWidth(), b.getHeight());
y += b.getHeight();
if (bounds == null) {
bounds = b;
} else {
bounds.add(b);
}
}
if (HorizontalAlignment.RIGHT == string.horizontalAlignment) {
bounds.setFrame(bounds.getMinX() - bounds.getWidth(),
bounds.getMinY(), bounds.getWidth(), bounds.getHeight());
} else if (HorizontalAlignment.CENTER == string.horizontalAlignment) {
bounds.setFrame(bounds.getMinX() - bounds.getWidth() / 2,
bounds.getMinY(), bounds.getWidth(), bounds.getHeight());
}
if (VerticalAlignment.BOTTOM == string.verticallAlignment) {
bounds.setFrame(bounds.getMinX(),
bounds.getMinY() - bounds.getHeight(),
bounds.getWidth(), bounds.getHeight());
} else if (VerticalAlignment.MIDDLE == string.verticallAlignment) {
bounds.setFrame(bounds.getMinX(),
bounds.getMinY() - bounds.getHeight() / 2,
bounds.getWidth(), bounds.getHeight());
}
return bounds;
}
protected Rectangle2D getColorMapBounds(DrawableColorMap colorMap) {
return new Rectangle2D.Double(colorMap.extent.getMinX(),
colorMap.extent.getMinY(), colorMap.extent.getWidth(),
colorMap.extent.getHeight());
}
}
}

View file

@ -0,0 +1,125 @@
/**
* 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.ext;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.IntBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.ShortBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.UnsignedByteBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.UnsignedShortBufferWrapper;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback.ColorMapData;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Implements the interface and converts all data callbacks into raw float
* arrays.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlColormappedImage extends KmlImage implements IColormappedImage {
private final IColorMapDataRetrievalCallback dataCallback;
private ColorMapParameters colorMapParameters;
public KmlColormappedImage(IColorMapDataRetrievalCallback dataCallback,
ColorMapParameters colorMapParameters) {
this.dataCallback = dataCallback;
this.colorMapParameters = colorMapParameters;
}
public DataSource getData(GridGeometry2D geometry) throws VizException {
ColorMapData data = dataCallback.getColorMapData();
switch (data.getDataType()) {
case FLOAT:
return new FloatBufferWrapper(((FloatBuffer) data.getBuffer()),
geometry);
case BYTE: {
return new UnsignedByteBufferWrapper(
((ByteBuffer) data.getBuffer()), geometry);
}
case SIGNED_BYTE: {
return new ByteBufferWrapper(((ByteBuffer) data.getBuffer()),
geometry);
}
case INT: {
return new IntBufferWrapper(((IntBuffer) data.getBuffer()),
geometry);
}
case SHORT: {
return new ShortBufferWrapper(((ShortBuffer) data.getBuffer()),
geometry);
}
case UNSIGNED_SHORT: {
return new UnsignedShortBufferWrapper(
((ShortBuffer) data.getBuffer()), geometry);
}
}
throw new UnsupportedOperationException(
"Kml Export does not supprt image type: " + data.getDataType());
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlColormappedImageExtension.class;
}
@Override
public ColorMapParameters getColorMapParameters() {
return colorMapParameters;
}
@Override
public void setColorMapParameters(ColorMapParameters params) {
this.colorMapParameters = params;
}
@Override
public double getValue(int x, int y) {
return 0;
}
}

View file

@ -0,0 +1,337 @@
/**
* 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.ext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.InvalidGridGeometryException;
import org.geotools.geometry.Envelope2D;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
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.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IColormappedImageExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
/**
*
* Responsible for creating KML Ground Overlays from colormapped images.
* Converts all raw data to floats, reproject to LatLon using an Interpolation
* and use the Colormapper to generate a RenderedImage.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlColormappedImageExtension extends
GraphicsExtension<KmlGraphicsTarget> implements
IColormappedImageExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlColormappedImageExtension.class);
@Override
public boolean drawRasters(PaintProperties paintProps,
DrawableImage... images) throws VizException {
target.addGenerator(new Generator(paintProps.getAlpha(), images));
return true;
}
@Override
public IColormappedImage initializeRaster(
IColorMapDataRetrievalCallback dataCallback,
ColorMapParameters colorMapParameters) {
return new KmlColormappedImage(dataCallback, colorMapParameters);
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlGroundOverlayGenerator {
private final DrawableImage[] images;
public Generator(float alpha, DrawableImage[] images) {
super(alpha);
this.images = images;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
drawRasters(outputManager, Arrays.asList(images));
}
private void drawRasters(KmlOutputManager out,
List<DrawableImage> images) {
Map<GridGeometry2D, DataSource> matches = new HashMap<GridGeometry2D, DataSource>();
List<DrawableImage> others = new ArrayList<DrawableImage>();
ColorMapParameters params = null;
boolean interpolated = false;
// find candidates for merging tiles, matches must have the same
// color map parameters and interpolations state.
for (DrawableImage image : images) {
KmlColormappedImage kmlImage = (KmlColormappedImage) image
.getImage();
KmlMesh mesh = (KmlMesh) image.getCoverage().getMesh();
try {
if (params == null) {
params = kmlImage.getColorMapParameters();
interpolated = kmlImage.isInterpolated();
matches.put(mesh.getImageGeometry(),
kmlImage.getData(mesh.getImageGeometry()));
} else if (!params.equals(kmlImage.getColorMapParameters())) {
others.add(image);
} else if (interpolated != kmlImage.isInterpolated()) {
others.add(image);
} else {
matches.put(mesh.getImageGeometry(),
kmlImage.getData(mesh.getImageGeometry()));
}
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
if (!others.isEmpty()) {
drawRasters(out, others);
}
try {
drawRastersInternal(out, matches, params, interpolated);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
/**
* images must all have the same colormap parameters and interpolation
*
* @param paintProps
* @param images
* @return
* @throws TransformException
* @throws FactoryException
* @throws VizException
*/
private void drawRastersInternal(KmlOutputManager out,
Map<GridGeometry2D, DataSource> map,
ColorMapParameters parameters, boolean interpolated)
throws FactoryException, TransformException {
// attempt to merge
map = mergeTiles(map);
// and then draw any that were merged.
for (Entry<GridGeometry2D, DataSource> entry : map.entrySet()) {
reprojectAndMakeOverlay(out, entry.getKey(), entry.getValue(),
parameters, interpolated);
}
}
/**
* make the kml overlay object.
*
* @param paintProps
* @param geometry
* @param images
* @throws TransformException
* @throws FactoryException
* @throws VizException
*/
private void reprojectAndMakeOverlay(KmlOutputManager out,
GridGeometry2D geometry, DataSource data,
ColorMapParameters parameters, boolean interpolated)
throws FactoryException, TransformException {
Envelope env = new Envelope2D(MapUtil.LATLON_PROJECTION, -180, -90,
360, 180);
GridGeometry2D projectedGeometry;
projectedGeometry = GridGeometry2D.wrap(MapUtil.reprojectGeometry(
geometry, env));
float[] fdata = reproject(geometry, projectedGeometry, data,
interpolated);
makeOverlay(out, projectedGeometry, fdata, parameters);
}
private Map<GridGeometry2D, DataSource> mergeTiles(
Map<GridGeometry2D, DataSource> map) {
Map<GridGeometry2D, DataSource> newmap = new HashMap<GridGeometry2D, DataSource>();
while (!map.isEmpty()) {
// each iteration removes a single entry and also any entries
// that are representable in the same grid space.
Iterator<Entry<GridGeometry2D, DataSource>> it = map.entrySet()
.iterator();
Entry<GridGeometry2D, DataSource> entry = it.next();
it.remove();
GridGeometry2D geom = entry.getKey();
CoordinateReferenceSystem crs = geom
.getCoordinateReferenceSystem();
Envelope2D env = geom.getEnvelope2D();
// bigenv will be an envelope big enopugh to hold all compatible
// grids.
Envelope2D bigenv = null;
Map<Envelope2D, DataSource> envmap = new HashMap<Envelope2D, DataSource>();
envmap.put(env, entry.getValue());
float dx = (float) (env.width / geom.getGridRange2D().width);
float dy = (float) (env.height / geom.getGridRange2D().height);
// loop through remaining entries to find any matches, a match
// will have the same crs, grid spacing and the distance between
// the envelopes will be a multiple of the grid spacing.
while (it.hasNext()) {
entry = it.next();
GridGeometry2D geom2 = entry.getKey();
CoordinateReferenceSystem crs2 = geom2
.getCoordinateReferenceSystem();
Envelope2D env2 = geom2.getEnvelope2D();
float dx2 = (float) (env2.width / geom2.getGridRange2D().width);
float dy2 = (float) (env2.height / geom2.getGridRange2D().height);
// numeric comparisons are done using floats because float
// precision is considered "close enough" and double
// precision results in very small inconsitencies.
if (!crs.equals(crs2) || dx != dx2 || dy != dy2) {
continue;
}
// Make sure that the two grids line up, the distance
// between the envelopes should be an even multiple of dx
// and dy otherwise the grids are slightly offset from
// eachother and incompatible.
float xoffset = (float) ((env.x - env2.x) / dx);
float yoffset = (float) ((env.y - env2.y) / dy);
if (xoffset != (int) xoffset || yoffset != (int) yoffset) {
continue;
}
// at this point the two grids are compatible so we add them
// to the bigenv.
if (bigenv == null) {
bigenv = new Envelope2D(env);
}
it.remove();
envmap.put(env2, entry.getValue());
bigenv.add(env2);
}
if (bigenv != null) {
// determine GridEnvelope mapping needed to put all the
// matching grids into the same space.
try {
GridEnvelope2D range = geom.worldToGrid(bigenv);
range.x = 0;
range.y = 0;
GridGeometry2D newGeom = new GridGeometry2D(
(GridEnvelope) range, bigenv);
Map<GridEnvelope2D, DataSource> rangemap = new HashMap<GridEnvelope2D, DataSource>();
for (Entry<Envelope2D, DataSource> envent : envmap
.entrySet()) {
rangemap.put(newGeom.worldToGrid(envent.getKey()),
envent.getValue());
}
newmap.put(newGeom, new MergedDataSource(rangemap));
} catch (InvalidGridGeometryException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
} else {
// if there are no compatible grids than this grid must be
// handled all alone.
newmap.put(geom, envmap.get(env));
}
}
return newmap;
}
}
/**
*
* Wraps multiple data sources that each cover a tile into a single data
* source so it can all be reprojected in a single pass.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 25, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
private static class MergedDataSource implements DataSource {
private final Map<GridEnvelope2D, DataSource> sources;
public MergedDataSource(Map<GridEnvelope2D, DataSource> sources) {
this.sources = sources;
}
@Override
public double getDataValue(int x, int y) {
for (Entry<GridEnvelope2D, DataSource> entry : sources.entrySet()) {
GridEnvelope2D env = entry.getKey();
if (env.contains(x, y)) {
x -= env.x;
y -= env.y;
return entry.getValue().getDataValue(x, y);
}
}
return Double.NaN;
}
}
}

View file

@ -0,0 +1,143 @@
/**
* 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.ext;
import java.awt.image.RenderedImage;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.keyvalue.MultiKey;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
import com.raytheon.uf.common.geospatial.interpolation.GridReprojection;
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback.ColorMapData;
import com.raytheon.uf.viz.core.data.prep.Colormapper;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.GroundOverlay;
import de.micromata.opengis.kml.v_2_2_0.LatLonBox;
/**
* Base class for any feature generator that is creating a ground overlay,
* provides the reproject logic as well as logic for actually making the
* overlay.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class KmlGroundOverlayGenerator extends KmlFeatureGenerator {
private static Map<MultiKey, Reference<GridReprojection>> reprojCache = new HashMap<MultiKey, Reference<GridReprojection>>();
protected final double alpha;
public KmlGroundOverlayGenerator(double alpha) {
this.alpha = alpha;
}
protected void makeOverlay(KmlOutputManager out, GridGeometry2D geometry,
float[] fdata, ColorMapParameters parameters) {
GridEnvelope2D range = geometry.getGridRange2D();
int[] dimensions = { range.width, range.height };
ColorMapData data = new ColorMapData(FloatBuffer.wrap(fdata),
dimensions);
RenderedImage image = Colormapper.colorMap(data, parameters);
makeOverlay(out, image, geometry.getEnvelope2D());
}
protected void makeOverlay(KmlOutputManager out, RenderedImage image,
Envelope2D envelope) {
GroundOverlay overlay = new GroundOverlay();
overlay.setColor(toColorStr(alpha, new RGB(255, 255, 255)));
overlay.setName("Image");
overlay.createAndSetIcon().setHref(out.addImage(image));
LatLonBox box = overlay.createAndSetLatLonBox();
box.setNorth(envelope.getMaxY());
box.setEast(envelope.getMaxX());
box.setSouth(envelope.getMinY());
box.setWest(envelope.getMinX());
out.addFeature(overlay);
}
protected float[] reproject(GridGeometry2D src, GridGeometry2D dest,
DataSource data, Boolean interpolated) throws FactoryException,
TransformException {
GridReprojection reproj = getReprojection(src, dest);
Interpolation interp = null;
if (interpolated) {
interp = new BilinearInterpolation();
} else {
interp = new NearestNeighborInterpolation();
}
FloatArrayWrapper dst = new FloatArrayWrapper(dest);
return reproj.reprojectedGrid(interp, data, dst).getArray();
}
protected GridReprojection getReprojection(GridGeometry2D src,
GridGeometry2D dest) throws FactoryException, TransformException {
MultiKey key = new MultiKey(src, dest);
GridReprojection reproj = null;
boolean needsCompute = false;
synchronized (reprojCache) {
Reference<GridReprojection> reprojRef = reprojCache.get(key);
if (reprojRef != null) {
reproj = reprojRef.get();
}
if (reproj == null) {
reproj = new GridReprojection(src, dest);
needsCompute = true;
reprojCache.put(key,
new SoftReference<GridReprojection>(reproj));
}
}
synchronized (reproj) {
if (needsCompute) {
reproj.computeTransformTable();
}
}
return reproj;
}
}

View file

@ -0,0 +1,96 @@
/**
* 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.ext;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* Base image class for KML that does almost nothing and ignores any of the
* methods that aren't important to KML.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class KmlImage implements IImage {
private boolean interpolated;
@Override
public void stage() throws VizException {
}
@Override
public Status getStatus() {
return Status.LOADED;
}
@Override
public void setInterpolated(boolean isInterpolated) {
this.interpolated = isInterpolated;
}
public boolean isInterpolated() {
return interpolated;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IImage#dispose()
*/
@Override
public void dispose() {
}
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
@Override
public void setBrightness(float brightness) {
}
@Override
public void setContrast(float contrast) {
}
}

View file

@ -0,0 +1,77 @@
/**
* 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.ext;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.opengis.coverage.grid.GridEnvelope;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.drawables.IDescriptor;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.map.IMapMeshExtension;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
/**
*
* Creates meshes.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMapMeshExtension extends GraphicsExtension<KmlGraphicsTarget>
implements IMapMeshExtension {
@Override
public IMesh constructMesh(GridGeometry2D imageGeometry,
GeneralGridGeometry targetGeometry) throws VizException {
GridEnvelope2D range = imageGeometry.getGridRange2D();
Envelope2D envelope = imageGeometry.getEnvelope2D();
range.x = 0;
range.y = 0;
imageGeometry = new GridGeometry2D((GridEnvelope) range, envelope);
return new KmlMesh(imageGeometry);
}
@Override
public IMesh constructMesh(GridGeometry2D imageGeometry,
IDescriptor targetDescriptor) throws VizException {
return constructMesh(imageGeometry, targetDescriptor.getGridGeometry());
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
}

View file

@ -0,0 +1,101 @@
/**
* 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.ext;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Basically just a container for a grid geometry.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMesh implements IMesh {
private final GridGeometry2D imageGeometry;
private Envelope latLonEnvelope;
public KmlMesh(GridGeometry2D imageGeometry) {
this.imageGeometry = imageGeometry;
}
public GridGeometry2D getImageGeometry() {
return imageGeometry;
}
@Override
public void dispose() {
}
@Override
public boolean intersects(IExtent extent) {
return false;
}
@Override
public KmlMesh reproject(GeneralGridGeometry targetGeometry)
throws VizException {
return clone(targetGeometry);
}
@Override
public KmlMesh clone(GeneralGridGeometry targetGeometry)
throws VizException {
return this;
}
public Envelope getLatLonEnvelope() throws TransformException {
if (latLonEnvelope == null) {
ReferencedEnvelope env = new ReferencedEnvelope(
imageGeometry.getEnvelope());
try {
latLonEnvelope = env.transform(MapUtil.LATLON_PROJECTION, true,
500);
} catch (FactoryException e) {
throw new TransformException(e.getLocalizedMessage(), e);
}
}
return latLonEnvelope;
}
}

View file

@ -0,0 +1,149 @@
/**
* 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.ext;
import java.util.Comparator;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension.IMosaicImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Keeps track of the images that are to be mosaiced so that the extension can
* handle rendering them.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 20, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
class KmlMosaicImage implements IMosaicImage {
private ColorMapParameters colorMapParameters;
private int[] bounds;
private IExtent imageExtent;
private DrawableImage[] imagesToMosaic;
private Comparator<Double> mosaicComparator;
public KmlMosaicImage(int[] imageBounds, IExtent imageExtent,
ColorMapParameters params, Comparator<Double> mosaicComparator) {
this.colorMapParameters = params;
this.bounds = imageBounds;
this.imageExtent = imageExtent;
this.mosaicComparator = mosaicComparator;
}
@Override
public ColorMapParameters getColorMapParameters() {
return colorMapParameters;
}
@Override
public void setColorMapParameters(ColorMapParameters params) {
this.colorMapParameters = params;
}
@Override
public double getValue(int x, int y) {
// TODO do I need this?
return 0;
}
@Override
public void stage() throws VizException {
// TODO do I need this?
}
@Override
public Status getStatus() {
// TODO do I need this?
return Status.LOADED;
}
@Override
public void setInterpolated(boolean isInterpolated) {
// TODO do I need this?
}
@Override
public void dispose() {
// TODO do I need this?
}
@Override
public int getWidth() {
return bounds[0];
}
@Override
public int getHeight() {
return bounds[1];
}
@Override
public void setBrightness(float brightness) {
// TODO do I need this?
}
@Override
public void setContrast(float contrast) {
// TODO do I need this?
}
@Override
public Class<? extends IMosaicImageExtension> getExtensionClass() {
return IMosaicImageExtension.class;
}
public Comparator<Double> getMosaicComparator() {
return mosaicComparator;
}
@Override
public void setImagesToMosaic(DrawableImage... images) {
this.imagesToMosaic = images;
}
public DrawableImage[] getImagesToMosaic() {
return this.imagesToMosaic;
}
@Override
public void setImageExtent(IExtent imageExtent) {
this.imageExtent = imageExtent;
}
}

View file

@ -0,0 +1,255 @@
/**
* 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.ext;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Comparator;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
import com.raytheon.uf.common.geospatial.interpolation.data.AbstractDataWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.DataDestination;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
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.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
/**
* Generates a KMLGroundOverlay for mosaic by reprojecting all the images to a
* common Lat/Lon space and performing a MaxVal algorithm.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 8, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMosaicImageExtension extends
GraphicsExtension<KmlGraphicsTarget> implements IMosaicImageExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlMosaicImageExtension.class);
@Override
public boolean drawRasters(PaintProperties paintProps,
DrawableImage... images) throws VizException {
for (DrawableImage image : images) {
target.addGenerator(new Generator(paintProps.getAlpha(),
(KmlMosaicImage) image.getImage()));
}
return true;
}
@Override
public IMosaicImage initializeRaster(int[] imageBounds,
IExtent imageExtent, ColorMapParameters params) throws VizException {
return new KmlMosaicImage(imageBounds, imageExtent, params,
getMosaicComparator());
}
/**
* The mosaic comparator is used to implement different mosaicing
* algorithms. The first Double will be the current value, and the second
* double will be the dataValue, the dataValue will only be used if it is
* greater than the existing value.
*
* @return
*/
protected Comparator<Double> getMosaicComparator() {
return new Comparator<Double>() {
@Override
public int compare(Double o1, Double o2) {
// always use data value.
return -1;
}
};
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlGroundOverlayGenerator {
private final Comparator<Double> mosaicComparator;
private final ColorMapParameters parameters;
private final DrawableImage[] images;
public Generator(float alpha, KmlMosaicImage image) {
super(alpha);
this.images = image.getImagesToMosaic();
this.parameters = image.getColorMapParameters();
this.mosaicComparator = image.getMosaicComparator();
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (images.length == 0) {
return;
}
long startTime = System.currentTimeMillis();
// make a big envelope in lat lon space that is large enough to hold
// all radar sites.
ReferencedEnvelope bigenv = null;
for (DrawableImage image : images) {
KmlMesh mesh = (KmlMesh) image.getCoverage().getMesh();
try {
ReferencedEnvelope env = new ReferencedEnvelope(
mesh.getLatLonEnvelope());
if (bigenv == null) {
bigenv = env;
} else {
bigenv.expandToInclude(env);
}
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
// create a range that preserves aspect ratio with the larger
// dimension as 1024 pixels, 1024 is a randomly chosen number.
GridEnvelope2D range = new GridEnvelope2D(0, 0, 1024, 1024);
if (bigenv.getWidth() > bigenv.getHeight()) {
range.height = (int) (range.width * bigenv.getHeight() / bigenv
.getWidth());
} else {
range.width = (int) (range.height * bigenv.getWidth() / bigenv
.getHeight());
}
GridGeometry2D geom = new GridGeometry2D(range, bigenv);
// fullDest is the end location of reprojected data values
FloatArrayWrapper fullDest = new FloatArrayWrapper(geom);
Arrays.fill(fullDest.getArray(), Float.NaN);
Interpolation interp = new NearestNeighborInterpolation();
for (DrawableImage image : images) {
KmlMesh mesh = (KmlMesh) image.getCoverage().getMesh();
KmlColormappedImage kmlImage = (KmlColormappedImage) image
.getImage();
try {
// Reproject a subgrid rather than the full grid because it
// is faster. The MosaicDataDestination maps the subgrid to
// the larger grid.
GridEnvelope2D gridenv = geom.worldToGrid(new Envelope2D(
mesh.getLatLonEnvelope()));
DataDestination dest = new MosaicDataDestination(
mosaicComparator, fullDest, gridenv.clone());
Envelope2D env = geom.gridToWorld(gridenv);
gridenv.x = 0;
gridenv.y = 0;
GridGeometry2D newGeom = new GridGeometry2D(
(GridEnvelope) gridenv, env);
GridGeometry2D oldGeom = mesh.getImageGeometry();
DataSource source = kmlImage.getData(oldGeom);
getReprojection(oldGeom, newGeom).reprojectedGrid(interp,
source, dest);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
makeOverlay(outputManager, geom, fullDest.getArray(), parameters);
System.out.println(System.currentTimeMillis() - startTime);
}
}
/**
*
* Provides a mapping into a subgrid of a larger destination and performs
* maxVal mosaic algorithm when multiple radars map t a single grid cell.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 25, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
private static class MosaicDataDestination implements DataDestination {
private final Comparator<Double> mosaicComparator;
private final AbstractDataWrapper fullDest;
private final GridEnvelope2D envelope;
public MosaicDataDestination(Comparator<Double> mosaicComparator,
AbstractDataWrapper fullDest, GridEnvelope2D envelope) {
this.mosaicComparator = mosaicComparator;
this.fullDest = fullDest;
this.envelope = envelope;
}
@Override
public void setDataValue(double dataValue, int x, int y) {
x = x + envelope.x;
y = y + envelope.y;
// shift the data and apply maxVal algorithm
double oldValue = fullDest.getDataValue(x, y);
if (mosaicComparator.compare(oldValue, dataValue) < 0) {
fullDest.setDataValue(dataValue, x, y);
}
}
}
}

View file

@ -0,0 +1,62 @@
/**
* 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.ext;
import java.util.Comparator;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicMaxValImageExtension;
/**
* Extends mosaic extesnion to perform maxVal mosaicing.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 10, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMosaicMaxValImageExtension extends KmlMosaicImageExtension
implements IMosaicMaxValImageExtension {
@Override
protected Comparator<Double> getMosaicComparator() {
return new Comparator<Double>() {
@Override
public int compare(Double o1, Double o2) {
if (Double.isNaN(o2)) {
return 1;
} else if (Double.isNaN(o1)) {
return -1;
} else {
return Double.compare(o1, o2);
}
}
};
}
}

View file

@ -0,0 +1,59 @@
/**
* 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.ext;
import java.util.Comparator;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicOrderedImageExtension;
/**
* Extends mosaic extesnion to perform ordered mosaicing.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 10, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMosaicOrderedImageExtension extends KmlMosaicImageExtension
implements IMosaicOrderedImageExtension {
@Override
protected Comparator<Double> getMosaicComparator() {
return new Comparator<Double>() {
@Override
public int compare(Double o1, Double o2) {
if (o2 != 0 && !Double.isNaN(o2)) {
return -1;
}
return 1;
}
};
}
}

View file

@ -0,0 +1,130 @@
/**
* 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.ext;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* Basically a wrapper around a RenderedImageCallback but also has logic for
* filling in transparent parts of plots.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRasterImage extends KmlImage {
protected final IRenderedImageCallback callback;
/**
* @param imageCallback
*/
public KmlRasterImage(IRenderedImageCallback imageCallback) {
this.callback = imageCallback;
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlRasterImageExtension.class;
}
/**
* get the image for a ground overlay
*
* @return
* @throws VizException
*/
public RenderedImage getImage() throws VizException {
return callback.getImage();
}
/**
* get the image for a plot
*
* @param target
* @return
* @throws VizException
*/
public RenderedImage getImage(RGB backcolor) throws VizException {
RenderedImage ri = getImage();
BufferedImage bi = cloneRenderedImage(ri);
applyFill(bi, backcolor);
return bi;
}
protected BufferedImage cloneRenderedImage(RenderedImage ri)
throws VizException {
BufferedImage bi = new BufferedImage(ri.getWidth(), ri.getHeight(),
BufferedImage.TYPE_INT_ARGB);
if (ri instanceof Image) {
bi.getGraphics().drawImage((Image) ri, 0, 0, null);
} else {
throw new VizException("Cannot handle image of type "
+ ri.getClass().getSimpleName());
}
return bi;
}
protected void applyFill(BufferedImage bi, RGB backcolor) {
int backint = (0xFF << 24) | (backcolor.red << 16)
| (backcolor.green << 8) | backcolor.blue;
for (int i = 0; i < bi.getWidth(); i++) {
for (int j = 0; j < bi.getHeight(); j++) {
int argb = bi.getRGB(i, j);
int alphaint = ((argb >> 24) & 0xFF);
if (alphaint == 0) {
argb = backint;
} else if (alphaint != 255) {
// blend the colors.
double alpha = alphaint / 255.0;
int red = (argb >> 16) & 0xFF;
int green = (argb >> 8) & 0xFF;
int blue = (argb >> 0) & 0xFF;
red = (int) (red * alpha + backcolor.red * (1.0 - alpha));
green = (int) (green * alpha + backcolor.green
* (1.0 - alpha));
blue = (int) (blue * alpha + backcolor.blue * (1.0 - alpha));
argb = (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
bi.setRGB(i, j, argb);
}
}
}
}

View file

@ -0,0 +1,122 @@
/**
* 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.ext;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.processing.Operations;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
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.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.PixelCoverage;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
/**
* Extension for creating KML Ground Overlay from raster images.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRasterImageExtension extends
GraphicsExtension<KmlGraphicsTarget> implements IImagingExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRasterImageExtension.class);
@Override
public boolean drawRasters(PaintProperties paintProps,
DrawableImage... images) throws VizException {
target.addGenerator(new Generator(paintProps.getAlpha(), images));
return true;
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlGroundOverlayGenerator {
private final DrawableImage[] images;
public Generator(float alpha, DrawableImage[] images) {
super(alpha);
this.images = images;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
GridCoverageFactory coverageFactory = new GridCoverageFactory();
for (DrawableImage image : images) {
KmlRasterImage kmlImage = (KmlRasterImage) image.getImage();
PixelCoverage coverage = image.getCoverage();
MathTransform transform = gridGeometry.getGridToCRS();
DirectPosition2D min = new DirectPosition2D(coverage.getMinX(),
coverage.getMinY());
DirectPosition2D max = new DirectPosition2D(coverage.getMaxX(),
coverage.getMaxY());
try {
transform.transform(min, min);
transform.transform(max, max);
ReferencedEnvelope env = new ReferencedEnvelope(
new Envelope2D(min, max),
gridGeometry.getCoordinateReferenceSystem());
GridCoverage2D source = coverageFactory.create("Test",
kmlImage.getImage(), env);
GridCoverage2D result = (GridCoverage2D) new Operations(
null).resample(source, MapUtil.LATLON_PROJECTION);
makeOverlay(outputManager, result.getRenderedImage(),
result.getEnvelope2D());
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
}
}
}

View file

@ -0,0 +1,90 @@
/**
* 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.ext;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension.ISingleColorImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Adds logic to change colors to KmlRasterIamge.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlSingleColorImage extends KmlRasterImage implements
ISingleColorImage {
private RGB color;
public KmlSingleColorImage(IRenderedImageCallback callback, RGB color) {
super(callback);
this.color = color;
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlSingleColorImageExtension.class;
}
@Override
public void setColor(RGB color) {
this.color = color;
}
@Override
public RenderedImage getImage() throws VizException {
RenderedImage ri = callback.getImage();
BufferedImage bi = cloneRenderedImage(ri);
makeSingleColor(bi);
return bi;
}
protected void makeSingleColor(BufferedImage bi) {
int colorint = (0xFF << 24) | (color.red << 16) | (color.green << 8)
| color.blue;
for (int i = 0; i < bi.getWidth(); i++) {
for (int j = 0; j < bi.getHeight(); j++) {
int argb = bi.getRGB(i, j);
// preserve alpha but color becomes color.
argb = (0xFF000000 & argb) | (0x00FFFFFF & colorint);
bi.setRGB(i, j, argb);
}
}
}
}

View file

@ -0,0 +1,53 @@
/**
* 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.ext;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension;
/**
* Extesnion for creating single color images.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlSingleColorImageExtension extends KmlRasterImageExtension
implements ISingleColorImageExtension {
@Override
public ISingleColorImage constructImage(IRenderedImageCallback callback,
RGB color) {
return new KmlSingleColorImage(callback, color);
}
}

View file

@ -0,0 +1,153 @@
/**
* 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.ext.point;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Collection;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
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.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImage;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImageExtension;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.raytheon.viz.pointdata.drawables.IPointImageExtension;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Icon;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
*
* Renders images at points as placemark icons in KML
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPointImageExtension extends GraphicsExtension<KmlGraphicsTarget>
implements IPointImageExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRasterImageExtension.class);
@Override
public void drawPointImages(PaintProperties paintProps,
PointImage... images) throws VizException {
drawPointImages(paintProps, Arrays.asList(images));
}
@Override
public void drawPointImages(PaintProperties paintProps,
Collection<PointImage> images) throws VizException {
target.addGenerator(new Generator(images));
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlFeatureGenerator {
private final Collection<PointImage> images;
public Generator(Collection<PointImage> images) {
this.images = images;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (images.size() > 1) {
outputManager = outputManager.createFolder("Points");
}
for (PointImage image : images) {
try {
Placemark placemark = new Placemark();
placemark.setName(image.getSiteId());
Coordinate loc = transformToLatLon(image.getX(),
image.getY());
Point point = placemark.createAndSetPoint();
point.addToCoordinates(loc.getLongitude(),
loc.getLatitude());
Style style = new Style();
style.createAndSetLabelStyle().setScale(0);
IconStyle iconStyle = style.createAndSetIconStyle();
iconStyle.setScale(options.getPlotIconScale());
double heading = 180 + MapUtil.rotation(
new com.vividsolutions.jts.geom.Coordinate(loc
.getLongitude(), loc.getLatitude()),
gridGeometry);
iconStyle.setHeading(heading);
Icon icon = iconStyle.createAndSetIcon();
RenderedImage rImage = null;
if (options.isFillPlotBackground()) {
rImage = ((KmlRasterImage) image.getImage())
.getImage(backgroundColor);
} else {
rImage = ((KmlRasterImage) image.getImage()).getImage();
}
String siteId = image.getSiteId();
if (siteId == null) {
icon.setHref(outputManager.addImage(rImage));
} else {
siteId = siteId.replaceAll("\\?", "QuestionMark");
icon.setHref(outputManager.addImage(rImage,
"pointIcons/" + siteId + ".png"));
}
placemark.setStyleUrl(outputManager.getStyleUrl(style));
outputManager.addFeature(placemark);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
}
}
}

View file

@ -0,0 +1,78 @@
/**
* 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.ext.radar;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.referencing.FactoryException;
import com.raytheon.uf.common.dataplugin.radar.RadarRecord;
import com.raytheon.uf.common.dataplugin.radar.projection.RadarProjectionFactory;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlMesh;
import com.raytheon.viz.radar.rsc.image.IRadialMeshExtension;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Creates a KMLMesh by constructing a RadialBinCRS based CrigGeometry object.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 6, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRadialMeshExtension extends
GraphicsExtension<KmlGraphicsTarget> implements IRadialMeshExtension {
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
@Override
public IMesh constructMesh(RadarRecord record,
GeneralGridGeometry targetGeometry) throws VizException {
GridGeometry2D imageGeometry;
try {
imageGeometry = RadarProjectionFactory
.constructGridGeometry(new Coordinate(
record.getLongitude(), record.getLatitude()),
record.getAngleData(), record.getGateResolution(),
record.getTrueElevationAngle(),
record.getNumBins(), true);
} catch (FactoryException e) {
throw new VizException(e);
}
return new KmlMesh(imageGeometry);
}
}

View file

@ -0,0 +1,96 @@
/**
* 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.io;
import java.awt.image.RenderedImage;
import de.micromata.opengis.kml.v_2_2_0.Container;
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.Style;
/**
* The Folder output does not actually contain a KMZ stream but allows the
* parent to handle all file io.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlFolderOutputManager implements KmlOutputManager {
protected final KmlOutputManager parent;
protected final Folder folder;
private int imageCounter = 1;
public KmlFolderOutputManager(KmlOutputManager parent, Folder folder) {
this.parent = parent;
this.folder = folder;
}
@Override
public KmlOutputManager createFolder(String name) {
return new KmlFolderOutputManager(this, folder.createAndAddFolder()
.withName(name));
}
@Override
public String addImage(RenderedImage image) {
return addImage(image, "image" + (imageCounter++) + ".png");
}
@Override
public String addImage(RenderedImage image, String name) {
return parent.addImage(image, folder.getName() + "/" + name);
}
@Override
public String resolvePath(String name) {
return parent.resolvePath(folder.getName() + "/" + name);
}
@Override
public String getStyleUrl(Style style) {
return parent.getStyleUrl(style);
}
@Override
public void addFeature(Feature feature) {
folder.addToFeature(feature);
}
@Override
public Container getContainer() {
return folder;
}
}

View file

@ -0,0 +1,63 @@
/**
* 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.io;
import java.awt.image.RenderedImage;
import de.micromata.opengis.kml.v_2_2_0.Container;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* Wrapper around a KMZ file as well as a container java object, each folder an
* outputManager creates will be a folder in the KML view as well as a folder in
* the kmz file for any image resources that are stored.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public interface KmlOutputManager {
public KmlOutputManager createFolder(String name);
public String addImage(RenderedImage image);
public String addImage(RenderedImage image, String name);
public String resolvePath(String name);
public String getStyleUrl(Style style);
public void addFeature(Feature feature);
public Container getContainer();
}

View file

@ -0,0 +1,164 @@
/**
* 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.io;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import javax.xml.bind.JAXB;
import de.micromata.opengis.kml.v_2_2_0.Container;
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.Kml;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* The root output manager holds a the base output stream as well as the root
* KML Document.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRootOutputManager implements KmlOutputManager {
private Set<String> names = new HashSet<String>();
private final Kml kml;
private final Document document;
private IOException exception;
private int imageCounter = 1;
private int styleCounter = 1;
private Map<Style, String> styleMap = new HashMap<Style, String>();
private final ZipOutputStream zos;
public KmlRootOutputManager(File kmzFile) throws FileNotFoundException {
this.zos = new ZipOutputStream(new FileOutputStream(kmzFile));
this.kml = new Kml();
this.document = this.kml.createAndSetDocument();
}
@Override
public KmlOutputManager createFolder(String name) {
return new KmlFolderOutputManager(this, document.createAndAddFolder()
.withName(name));
}
@Override
public String addImage(RenderedImage image) {
return addImage(image, "image" + (imageCounter++) + ".png");
}
@Override
public String addImage(RenderedImage image, String name) {
if (names.contains(name)) {
String newName = name;
for (int i = 1; names.contains(newName); i++) {
newName = name.replace(".png", "-" + i + ".png");
}
name = newName;
}
names.add(name);
synchronized (zos) {
try {
zos.putNextEntry(new ZipEntry(name));
ImageIO.write(image, "png", zos);
zos.closeEntry();
} catch (IOException e) {
exception = e;
}
}
return name;
}
@Override
public String resolvePath(String name) {
return name;
}
@Override
public synchronized String getStyleUrl(Style style) {
Style key = style.clone().withId(null);
String id = styleMap.get(key);
if (id == null) {
id = style.getId();
if (id == null) {
id = "style" + this.styleCounter++;
}
styleMap.put(key, id);
style.setId(id);
document.addToStyleSelector(style);
}
return "#" + id;
}
@Override
public void addFeature(Feature feature) {
document.addToFeature(feature);
}
@Override
public Container getContainer() {
return document;
}
/**
* Closes the kmz stream and serializes the kml document.
*
* @throws IOException
*/
public void close() throws IOException {
if (exception != null) {
throw exception;
}
zos.putNextEntry(new ZipEntry("doc.kml"));
JAXB.marshal(kml, zos);
zos.closeEntry();
zos.close();
}
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="JavaAPIforKml.jar" sourcepath="JavaAPIforKml-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>de.micromata.opengis.kml</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,8 @@
#Wed May 30 18:56:22 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

Binary file not shown.

View file

@ -0,0 +1,13 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Kml
Bundle-SymbolicName: de.micromata.opengis.kml
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ClassPath: JavaAPIforKml.jar,
.
Export-Package: de.micromata.opengis.kml.v_2_2_0,
de.micromata.opengis.kml.v_2_2_0.annotations,
de.micromata.opengis.kml.v_2_2_0.atom,
de.micromata.opengis.kml.v_2_2_0.gx,
de.micromata.opengis.kml.v_2_2_0.xal

View file

@ -0,0 +1,3 @@
bin.includes = META-INF/,\
.,\
JavaAPIforKml.jar