Change-Id: I4333c27b7b10bf3fb5a78509a9f8cf752519083b Former-commit-id:f5dd6a6d93
[formerlyf5dd6a6d93
[formerly 546a3a1ec028f3ee72fa94c8525d4c92902319c3]] Former-commit-id:992cb6506f
Former-commit-id:e1cb0fc2da
|
@ -68,6 +68,7 @@ import com.raytheon.viz.core.graphing.xy.XYWindImageData;
|
|||
* May 07, 2010 bsteffen Initial creation
|
||||
* Feb 17, 2014 2661 bsteffen Use only u,v for vectors.
|
||||
* Jun 18, 2014 3242 njensen Overrode getEnsembleId()
|
||||
* Nov 19, 2014 5056 jing Added get arbitrary record
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -356,4 +357,20 @@ public class GridTimeSeriesAdapter extends
|
|||
public String getEnsembleId() {
|
||||
return ensembleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets an arbitrary record from the cache.
|
||||
*
|
||||
* @return - A grid record.
|
||||
*/
|
||||
public GridRecord getArbitraryRecord() {
|
||||
|
||||
synchronized (cache) {
|
||||
if (cache.keySet().isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (GridRecord) cache.keySet().toArray()[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ import com.vividsolutions.jts.geom.Geometry;
|
|||
* Dec 19, 2013 DR 16795 D. Friedman Transform pixel coordinate in inspect
|
||||
* Jun 18, 2014 3242 njensen Added ensembleId to legend
|
||||
* Aug 15, 2014 3535 njensen Bigger inset map point
|
||||
* Nov 19, 2014 5056 jing added getAdapter method, and
|
||||
* changed getName to add level
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -134,7 +136,7 @@ public class TimeSeriesResource extends
|
|||
|
||||
protected CombineOperation combineOperation;
|
||||
|
||||
private Set<DataTime> dataTimes = new TreeSet<DataTime>();
|
||||
protected Set<DataTime> dataTimes = new TreeSet<DataTime>();
|
||||
|
||||
private Job dataRequestJob = new Job("Requesting Time Series Data") {
|
||||
|
||||
|
@ -255,6 +257,10 @@ public class TimeSeriesResource extends
|
|||
});
|
||||
}
|
||||
|
||||
public AbstractTimeSeriesAdapter<?> getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
if (secondaryResource != null) {
|
||||
|
@ -485,22 +491,26 @@ public class TimeSeriesResource extends
|
|||
}
|
||||
|
||||
String levelKey = resourceData.getLevelKey();
|
||||
String levelUnit = levelKey.replaceAll("[^a-zA-Z]", "");
|
||||
boolean isHeight = levelUnit.equalsIgnoreCase("mb")
|
||||
|| levelUnit.equalsIgnoreCase("agl")
|
||||
|| levelUnit.contains("Agl");
|
||||
// String levelUnit = levelKey.replaceAll("[^a-zA-Z]", "");
|
||||
// boolean isHeight = levelUnit.equalsIgnoreCase("mb")
|
||||
// || levelUnit.equalsIgnoreCase("agl")
|
||||
// || levelUnit.contains("Agl");
|
||||
|
||||
// Make legend for point data
|
||||
StringBuilder sb = new StringBuilder(String.format("%s pt%s %s%s %s%s",
|
||||
source, resourceData.getPointLetter(), lat, y >= 0 ? "N" : "S",
|
||||
lon, x >= 0 ? "E" : "W"));
|
||||
// add level in x legend only if levelKey is not empty
|
||||
StringBuilder sb = new StringBuilder(String.format(
|
||||
"%s %s pt%s %s%s %s%s", source, levelKey != null ? levelKey
|
||||
: "", resourceData.getPointLetter(), lat, y >= 0 ? "N"
|
||||
: "S", lon, x >= 0 ? "E" : "W"));
|
||||
|
||||
if (stnID != null) {
|
||||
sb.append(" ").append(stnID);
|
||||
}
|
||||
if (!isHeight) {
|
||||
sb.append(" ").append(resourceData.getLevelKey());
|
||||
}
|
||||
|
||||
// if (!isHeight) {
|
||||
// sb.append(" ").append(resourceData.getLevelKey());
|
||||
// }
|
||||
|
||||
sb.append(String.format(" %s %s %s", adapter.getParameterName(),
|
||||
"TSer", units != null && units.equals("") == false ? "("
|
||||
+ units + ")" : ""));
|
||||
|
|
|
@ -131,6 +131,7 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
* Feb 28, 2014 2791 bsteffen Switch all data to use data source.
|
||||
* Aug 21, 2014 DR 17313 jgerth Implements ImageProvider
|
||||
* Oct 07, 2014 3668 bclement Renamed requestJob to requestRunner
|
||||
* Dec 09, 2014 5056 jing Added data access interfaces
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -643,7 +644,7 @@ public abstract class AbstractGridResource<T extends AbstractResourceData>
|
|||
public abstract List<GeneralGridData> getData(DataTime time,
|
||||
List<PluginDataObject> pdos) throws VizException;
|
||||
|
||||
protected List<GeneralGridData> requestData(DataTime time) {
|
||||
public List<GeneralGridData> requestData(DataTime time) {
|
||||
synchronized (requestRunner) {
|
||||
List<GeneralGridData> data = this.dataMap.get(time);
|
||||
if (data == null) {
|
||||
|
@ -968,18 +969,22 @@ public abstract class AbstractGridResource<T extends AbstractResourceData>
|
|||
return new ArrayList<PluginDataObject>(list);
|
||||
}
|
||||
|
||||
public Collection<DrawableImage> getImages(IGraphicsTarget target, PaintProperties paintProps) throws VizException {
|
||||
public Collection<DrawableImage> getImages(IGraphicsTarget target,
|
||||
PaintProperties paintProps) throws VizException {
|
||||
if (getCapability(DisplayTypeCapability.class).getDisplayType() != DisplayType.IMAGE) {
|
||||
throw new VizException("Grid resource not configured for image rendering");
|
||||
throw new VizException(
|
||||
"Grid resource not configured for image rendering");
|
||||
}
|
||||
Collection<IRenderable> renderables = getOrCreateRenderables(target, paintProps);
|
||||
Collection<IRenderable> renderables = getOrCreateRenderables(target,
|
||||
paintProps);
|
||||
if (renderables.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<DrawableImage> images = new ArrayList<DrawableImage>();
|
||||
for (IRenderable renderable : renderables) {
|
||||
images.addAll(((TileSetRenderable)renderable).getImagesToRender(target, paintProps));
|
||||
images.addAll(((TileSetRenderable) renderable).getImagesToRender(
|
||||
target, paintProps));
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ import com.raytheon.uf.viz.datacube.DataCubeContainer;
|
|||
* Sep 24, 2013 2404 bclement match criteria built using GridStyleUtil
|
||||
* Jan 14, 2014 2661 bsteffen Switch vectors to u,v only.
|
||||
* May 05, 2014 3026 mpduff Made getCurrentGribRecord() public
|
||||
* Nov 19, 2014 5056 jing changed access modifier on getAnyGridRecord
|
||||
* from private to public
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -159,7 +161,7 @@ public class GridResource<T extends AbstractResourceData> extends
|
|||
return (GridRecord) pdos.get(0);
|
||||
}
|
||||
|
||||
protected GridRecord getAnyGridRecord() {
|
||||
public GridRecord getAnyGridRecord() {
|
||||
GridRecord record = getCurrentGridRecord();
|
||||
if (record == null) {
|
||||
for (DataTime time : getDataTimes()) {
|
||||
|
|
|
@ -142,12 +142,20 @@ public class VbSource {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
return that instanceof VbSource ? this.key.equals(((VbSource) that)
|
||||
.getKey()) : false;
|
||||
|
||||
if (that instanceof VbSource) {
|
||||
if ((this.key.equals(((VbSource) that).getKey()) && (this
|
||||
.getCategory().compareTo(((VbSource) that).getCategory()) == 0))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
String newKey = key.concat(category);
|
||||
return newKey.hashCode();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
17
gsd/gov.noaa.gsd.viz.ensemble.feature/.project
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>gov.noaa.gsd.viz.ensemble.feature</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.FeatureBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.FeatureNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
1
gsd/gov.noaa.gsd.viz.ensemble.feature/build.properties
Normal file
|
@ -0,0 +1 @@
|
|||
bin.includes = feature.xml
|
27
gsd/gov.noaa.gsd.viz.ensemble.feature/feature.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feature
|
||||
id="gov.noaa.gsd.viz.ensemble.feature"
|
||||
label="Ensemble Tool Feature"
|
||||
version="1.0.0.qualifier"
|
||||
provider-name="GSD">
|
||||
|
||||
<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="gov.noaa.gsd.viz.ensemble"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
||||
</feature>
|
7
gsd/gov.noaa.gsd.viz.ensemble/.classpath
Normal 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.7"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
28
gsd/gov.noaa.gsd.viz.ensemble/.project
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>gov.noaa.gsd.viz.ensemble</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>
|
36
gsd/gov.noaa.gsd.viz.ensemble/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,36 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Ensemble-Tool
|
||||
Bundle-SymbolicName: gov.noaa.gsd.viz.ensemble; singleton:=true
|
||||
Bundle-Version: 1.14.0401.qualifier
|
||||
Bundle-Activator: gov.noaa.gsd.viz.ensemble.Activator
|
||||
Bundle-Vendor: NOAA-ESL-GSD
|
||||
Eclipse-RegisterBuddy: com.raytheon.uf.viz.core.rsc
|
||||
Require-Bundle: org.eclipse.ui,
|
||||
org.eclipse.core.runtime,
|
||||
com.raytheon.viz.grid,
|
||||
com.raytheon.uf.common.serialization;bundle-version="1.12.1174",
|
||||
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174",
|
||||
javax.measure;bundle-version="1.0.0",
|
||||
com.raytheon.uf.common.parameter,
|
||||
com.raytheon.viz.core.contours,
|
||||
com.raytheon.uf.common.colormap;bundle-version="1.12.1174",
|
||||
com.raytheon.viz.core.graphing;bundle-version="1.12.1174",
|
||||
com.raytheon.uf.common.dataplugin.level,
|
||||
com.raytheon.uf.viz.d2d.core,
|
||||
com.raytheon.uf.common.style;bundle-version="1.0.0",
|
||||
com.raytheon.uf.common.numeric;bundle-version="1.14.0",
|
||||
com.raytheon.viz.core,
|
||||
com.raytheon.viz.ui,
|
||||
com.raytheon.uf.common.comm;bundle-version="1.12.1174",
|
||||
com.raytheon.uf.viz.xy.timeseries;bundle-version="1.13.0",
|
||||
com.raytheon.uf.viz.core.rsc,
|
||||
com.raytheon.uf.viz.xy;bundle-version="1.12.1174",
|
||||
com.raytheon.uf.viz.d2d.xy.adapters;bundle-version="1.14.0",
|
||||
com.raytheon.viz.volumebrowser;bundle-version="1.13.0",
|
||||
com.raytheon.uf.common.derivparam;bundle-version="1.14.0",
|
||||
com.raytheon.uf.common.inventory;bundle-version="1.14.0"
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: gov.noaa.gsd.viz.ensemble.display.control.load,
|
||||
gov.noaa.gsd.viz.ensemble.navigator.ui.layer
|
7
gsd/gov.noaa.gsd.viz.ensemble/build.properties
Normal file
|
@ -0,0 +1,7 @@
|
|||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = plugin.xml,\
|
||||
META-INF/,\
|
||||
.,\
|
||||
icons/,\
|
||||
localization/
|
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/EnsembleTool.gif
Normal file
After Width: | Height: | Size: 526 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/a-to-z-sort.gif
Normal file
After Width: | Height: | Size: 159 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/calculate-gear-40x24px.gif
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/ensemble-tool-3.gif
Normal file
After Width: | Height: | Size: 952 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/folder.gif
Normal file
After Width: | Height: | Size: 332 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/help.gif
Normal file
After Width: | Height: | Size: 259 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/information.gif
Normal file
After Width: | Height: | Size: 267 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/magic-wand-off.gif
Normal file
After Width: | Height: | Size: 523 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/magic-wand-on.gif
Normal file
After Width: | Height: | Size: 560 B |
BIN
gsd/gov.noaa.gsd.viz.ensemble/icons/magic-wand.gif
Normal file
After Width: | Height: | Size: 539 B |
After Width: | Height: | Size: 314 B |
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<vbSourceList>
|
||||
<!-- GFS Ensemble -->
|
||||
<vbSource key="GEFS" name="GFS Ensemble" category="Ensemble" views="PLANVIEW TIMESERIES" />
|
||||
<!-- SREF Ensemble -->
|
||||
<vbSource key="SREF212" name="SREF Ensemble" category="Ensemble" views="PLANVIEW TIMESERIES"/>
|
||||
</vbSourceList>
|
80
gsd/gov.noaa.gsd.viz.ensemble/plugin.xml
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.4"?>
|
||||
<plugin>
|
||||
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.commands">
|
||||
<command
|
||||
id="gov.noaa.gsd.viz.ensemble.activate.layer"
|
||||
name="Ensembles Tool">
|
||||
</command>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.handlers">
|
||||
<handler
|
||||
class="gov.noaa.gsd.viz.ensemble.navigator.action.EnsembleToolLayerManagerAction"
|
||||
commandId="gov.noaa.gsd.viz.ensemble.activate.layer">
|
||||
</handler>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.menus">
|
||||
|
||||
<!--
|
||||
<menuContribution
|
||||
locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
|
||||
<toolbar id="ensemblesToolbar">
|
||||
<visibleWhen>
|
||||
<reference
|
||||
definitionId="com.raytheon.uf.viz.d2d.ui.inD2DActionSet">
|
||||
</reference>
|
||||
</visibleWhen>
|
||||
<command
|
||||
commandId="gov.noaa.gsd.viz.ensemble.activate.layer"
|
||||
icon="icons/EnsembleTool.gif"
|
||||
id="gov.noaa.gsd.viz.ensemble.tool.viewer"
|
||||
label="Ensembles"
|
||||
style="push"
|
||||
tooltip="Ensemble Tools">
|
||||
</command>
|
||||
<separator
|
||||
name="gov.noaa.gsd.viz.ensemble.separator_post"
|
||||
visible="true">
|
||||
</separator>
|
||||
</toolbar>
|
||||
</menuContribution>
|
||||
-->
|
||||
<menuContribution
|
||||
allPopups="false"
|
||||
locationURI="menu:tools">
|
||||
<command
|
||||
commandId="gov.noaa.gsd.viz.ensemble.activate.layer"
|
||||
style="push">
|
||||
</command>
|
||||
</menuContribution>
|
||||
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.views">
|
||||
<view
|
||||
allowMultiple="false"
|
||||
class="gov.noaa.gsd.viz.ensemble.navigator.ui.viewer.EnsembleToolViewer"
|
||||
fastViewWidthRatio="0.26"
|
||||
icon="icons/ensemble-tool-3.gif"
|
||||
id="gov.noaa.gsd.viz.ensemble.tool.viewer"
|
||||
name="Ensemble Tool"
|
||||
restorable="false">
|
||||
</view>
|
||||
</extension>
|
||||
<extension
|
||||
point="com.raytheon.viz.ui.displayCustomizer">
|
||||
<displayCustomizer
|
||||
customizer="gov.noaa.gsd.viz.ensemble.display.control.EnsembleToolDisplayCustomizer"
|
||||
perspective="D2D">
|
||||
</displayCustomizer>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
|
@ -0,0 +1,83 @@
|
|||
package gov.noaa.gsd.viz.ensemble;
|
||||
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* The activator class controls the plug-in life cycle
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 10, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Activator extends AbstractUIPlugin {
|
||||
|
||||
// The plug-in ID
|
||||
public static final String PLUGIN_ID = "gov.noaa.gsd.viz.ensemble"; //$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an image descriptor for the image file at the given plug-in
|
||||
* relative path
|
||||
*
|
||||
* @param path
|
||||
* the path
|
||||
* @return the image descriptor
|
||||
*/
|
||||
public static ImageDescriptor getImageDescriptor(String path) {
|
||||
return imageDescriptorFromPlugin(PLUGIN_ID, path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate mean - std dev for different display types. The algorithm is
|
||||
* referred to ALPS ensemble.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class AvgM1StddevCalculator extends EnsembleCalculator {
|
||||
public AvgM1StddevCalculator() {
|
||||
super(Calculation.AVG_MINUS_STD_DEV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the "mean - std dev" calculation.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint(float[],
|
||||
* int)
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
int count = 0;
|
||||
float result = Float.NaN;
|
||||
float sum = 0;
|
||||
float scr0 = 0;
|
||||
/**
|
||||
* Prepare the sum, sum by sum, and how many data available.
|
||||
*/
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(workValue[i])) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
sum += workValue[i];
|
||||
scr0 = workValue[i] * workValue[i];
|
||||
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the "mean - std dev".
|
||||
*/
|
||||
sum /= count;
|
||||
scr0 = scr0 / count - sum * sum;
|
||||
result = (scr0 > 0) ? (float) (sum - Math.sqrt(scr0)) : sum;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate "mean + std dev" for different display types. The algorithm is
|
||||
* referred to ALPS ensemble.
|
||||
*
|
||||
* @author jing
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 2, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class AvgP1StddevCalculator extends EnsembleCalculator {
|
||||
public AvgP1StddevCalculator() {
|
||||
super(Calculation.AVG_PLUS_STD_DEV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the "mean - std dev" calculation. (non-Javadoc)
|
||||
*
|
||||
* @see gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint(float[],
|
||||
* int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
int count = 0;
|
||||
float result = Float.NaN;
|
||||
float sum = 0;
|
||||
float scr0 = 0;
|
||||
/**
|
||||
* Prepare the sum, sum by sum, and how many data available.
|
||||
*/
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(workValue[i])) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
sum += workValue[i];
|
||||
scr0 = workValue[i] * workValue[i];
|
||||
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return result;
|
||||
/**
|
||||
* What is the "mean + std dev".
|
||||
*/
|
||||
sum /= count;
|
||||
scr0 = scr0 / count - sum * sum;
|
||||
result = (scr0 > 0) ? (float) (sum + Math.sqrt(scr0)) : sum;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Define the calculation types as constants used in ensemble display and GUI.
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July 1, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public enum Calculation {
|
||||
|
||||
AVG_MINUS_STD_DEV("Avg - 1 Std dev"), //
|
||||
AVG_PLUS_STD_DEV("Avg + 1 Std dev"), //
|
||||
COMBINED_ENS_REL_FREQ("Combined ERF"), //
|
||||
DIFFERENCE("Diff"), //
|
||||
ENSEMBLE_RELATIVE_FREQUENCY("Ens Rel Freq"), //
|
||||
HISTOGRAM_SAMPLING("Histogram sampling"), //
|
||||
HISTOGRAM_TEXT("Histogram text"), //
|
||||
MAX("Max"), //
|
||||
MEAN("Mean"), //
|
||||
MIN("Min"), //
|
||||
MEDIAN("Median"), //
|
||||
MODE("Mode"), //
|
||||
NONE("<undefined>"), //
|
||||
RANGE("Range"), //
|
||||
SUMMATION("Sum"), //
|
||||
STANDARD_DEVIATION("Std dev"), //
|
||||
TRIPLET_ENS_REL_FREQ("Triplet ERF"); //
|
||||
|
||||
private String title;
|
||||
|
||||
private Calculation(String t) {
|
||||
title = t;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Value of Relative Frequency of an ensemble set. The range values for the
|
||||
* calculation, such as minimum, maximum... are in the GUI, should be passed in.
|
||||
* The definition of the minimum, maximum is the condition, "minimum < maximum"
|
||||
* as the input for the REF. The concept is from AWIPS I ALPS ensemble GUI.
|
||||
*
|
||||
* In the current Ensemble Tool, the GUI use Range, which is passed in and
|
||||
* converted into the "minimum < maximum" condition.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 2, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class ERFCalculator extends EnsembleCalculator {
|
||||
|
||||
/**
|
||||
* None value flag
|
||||
*/
|
||||
public final static double MAX_OR_MIN_NO_VALUE = -999999.0;
|
||||
|
||||
/**
|
||||
* Minimum value of the condition from GUI
|
||||
*/
|
||||
private double min = 0.25;
|
||||
|
||||
/**
|
||||
* Maximum value of the condition from GUI
|
||||
*/
|
||||
private double max = 0.0;
|
||||
|
||||
// Segregation Strategies can be default, altSREF, ekdmos25, ekdmos10
|
||||
private String SegregationStrategies = "default";
|
||||
|
||||
/**
|
||||
* Range description
|
||||
*/
|
||||
private String rangeDescription = null;
|
||||
|
||||
/**
|
||||
* Range from GUI
|
||||
*/
|
||||
private Range range = null;
|
||||
|
||||
/**
|
||||
* Set the Range description.
|
||||
*
|
||||
* @param rd
|
||||
* - Range description
|
||||
*/
|
||||
private void setRangeDescription(String rd) {
|
||||
rangeDescription = rd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Range description.
|
||||
*
|
||||
* @return - the Range description.
|
||||
*/
|
||||
public String getRangeDescription() {
|
||||
return rangeDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial the ERF calculator by processing the ERF condition.
|
||||
*
|
||||
* @param r
|
||||
* - rang to be pass in when constructing the object
|
||||
*/
|
||||
public ERFCalculator(Range r) {
|
||||
|
||||
// Set the Calculation flag
|
||||
super(Calculation.RANGE);
|
||||
|
||||
range = r;
|
||||
|
||||
double minValue = Double.MIN_VALUE;
|
||||
double maxValue = Double.MAX_VALUE;
|
||||
|
||||
// Convert the range to the minimum and maximum.
|
||||
if ((r.getRangeType() == RangeType.INNER_RANGE)
|
||||
|| (r.getRangeType() == RangeType.OUTER_RANGE)) {
|
||||
minValue = r.getLowerRangeThreshold();
|
||||
maxValue = r.getUpperRangeThreshold();
|
||||
} else if (r.getRangeType() == RangeType.ABOVE_THRESHOLD) {
|
||||
minValue = MAX_OR_MIN_NO_VALUE;
|
||||
maxValue = r.getThreshold();
|
||||
} else if (r.getRangeType() == RangeType.BELOW_THRESHOLD) {
|
||||
minValue = r.getThreshold();
|
||||
maxValue = MAX_OR_MIN_NO_VALUE;
|
||||
}
|
||||
|
||||
min = minValue;
|
||||
max = maxValue;
|
||||
|
||||
// Processing the condition for ERF
|
||||
if (this.min == MAX_OR_MIN_NO_VALUE && this.max == MAX_OR_MIN_NO_VALUE) {
|
||||
setRangeDescription("ERF Median ");
|
||||
} else if (this.min != MAX_OR_MIN_NO_VALUE
|
||||
&& this.max == MAX_OR_MIN_NO_VALUE) {
|
||||
setRangeDescription("ERF >" + this.min);
|
||||
} else if (this.min == MAX_OR_MIN_NO_VALUE
|
||||
&& this.max != MAX_OR_MIN_NO_VALUE) {
|
||||
setRangeDescription("ERF <" + this.max);
|
||||
} else if (this.min != MAX_OR_MIN_NO_VALUE
|
||||
&& this.max != MAX_OR_MIN_NO_VALUE) {
|
||||
setRangeDescription("ERF >" + this.min + " & <" + this.max);
|
||||
}
|
||||
}
|
||||
|
||||
public Range getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do ERF calculation for one point.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint(float[],
|
||||
* int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
float[] poitValues = new float[length];
|
||||
int totalNum = 0;
|
||||
|
||||
// Sum of the data set
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (!Float.isNaN(workValue[i])) {
|
||||
poitValues[totalNum] = workValue[i];
|
||||
totalNum++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// What is the ERF of this point
|
||||
|
||||
// Do nothing if no data
|
||||
if (totalNum == 0) {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
// How many data match with the conditions?
|
||||
int matchedNum = 0;
|
||||
float median = 0;
|
||||
if (this.min == MAX_OR_MIN_NO_VALUE && this.max == MAX_OR_MIN_NO_VALUE) {
|
||||
median = getMedian(poitValues);
|
||||
}
|
||||
for (int k = 0; k < totalNum; k++) {
|
||||
if (this.min == MAX_OR_MIN_NO_VALUE
|
||||
&& this.max == MAX_OR_MIN_NO_VALUE
|
||||
&& median == poitValues[k]) {
|
||||
|
||||
// Most close to mean
|
||||
setRangeDescription("ERF Median ");
|
||||
} else if (this.min != MAX_OR_MIN_NO_VALUE
|
||||
&& this.max == MAX_OR_MIN_NO_VALUE
|
||||
&& poitValues[k] > this.min) {
|
||||
matchedNum++;
|
||||
} else if (this.min == MAX_OR_MIN_NO_VALUE
|
||||
&& this.max != MAX_OR_MIN_NO_VALUE
|
||||
&& poitValues[k] < this.max) {
|
||||
matchedNum++;
|
||||
} else if (this.min != MAX_OR_MIN_NO_VALUE
|
||||
&& this.max != MAX_OR_MIN_NO_VALUE
|
||||
&& poitValues[k] > this.min && poitValues[k] < this.max) {
|
||||
matchedNum++;
|
||||
}
|
||||
}
|
||||
|
||||
// ERF of this point in %
|
||||
float erf = (Float) (matchedNum * 1.0f / totalNum);
|
||||
erf = (float) Math.round(erf * 100);
|
||||
|
||||
return erf;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the median of a data set.
|
||||
*
|
||||
* @param a
|
||||
* - A data set as the input data.
|
||||
* @return
|
||||
*/
|
||||
private float getMedian(float[] a) {
|
||||
float[] b = new float[a.length];
|
||||
System.arraycopy(a, 0, b, 0, b.length);
|
||||
Arrays.sort(b);
|
||||
|
||||
if (a.length % 2 == 0) {
|
||||
return (b[(b.length / 2) - 1] + b[b.length / 2]) / 2.0f;
|
||||
} else {
|
||||
return b[b.length / 2];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,462 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.geotools.coverage.grid.GridEnvelope2D;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.operation.TransformException;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.data.GeographicDataSource;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
|
||||
import com.raytheon.uf.common.numeric.buffer.FloatBufferWrapper;
|
||||
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.viz.core.graphing.xy.XYData;
|
||||
import com.raytheon.viz.core.graphing.xy.XYDataList;
|
||||
import com.raytheon.viz.grid.rsc.general.GeneralGridData;
|
||||
import com.raytheon.viz.grid.rsc.general.GridMemoryManager;
|
||||
|
||||
/**
|
||||
* Ensemble calculator for loaded products, which is the base class to process
|
||||
* and prepare the data for calculating of different display types. The input
|
||||
* data is one frame data of all ensemble members(generic members, can be any
|
||||
* loaded same level and same unit product data). The output data is calculation
|
||||
* result, like mean, mode, max and so on.. The derived classes implements the
|
||||
* real calculations with interfaces calculatePoint(). Currently implemented
|
||||
* display types are the plan view and time series, others like time-high,
|
||||
* cross-section... will be implemented in next Version. Each type is with its
|
||||
* own data format. plan view is grid and time series is xy points. So the data
|
||||
* processing is different.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 5, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public abstract class EnsembleCalculator {
|
||||
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(EnsembleCalculator.class);
|
||||
|
||||
/**
|
||||
* What's calculation, like MEAM, ERF, MAX... Is used by GUI
|
||||
*/
|
||||
protected Calculation calculationType;
|
||||
|
||||
/**
|
||||
* The display type id load mode, like plan view, time series... Is used by
|
||||
* ensemble displaying
|
||||
*/
|
||||
protected DisplayType displayType;
|
||||
|
||||
/**
|
||||
* Define the display type.
|
||||
*/
|
||||
public enum DisplayType {
|
||||
PLANVIEW, TIMESERIES
|
||||
}
|
||||
|
||||
public EnsembleCalculator(Calculation c, DisplayType displayType) {
|
||||
calculationType = c;
|
||||
this.displayType = displayType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param c
|
||||
* : What's calculation
|
||||
*/
|
||||
public EnsembleCalculator(Calculation c) {
|
||||
calculationType = c;
|
||||
}
|
||||
|
||||
public EnsembleCalculator() {
|
||||
|
||||
}
|
||||
|
||||
public DisplayType getDisplayType() {
|
||||
return displayType;
|
||||
}
|
||||
|
||||
public void setDisplayType(DisplayType displayType) {
|
||||
this.displayType = displayType;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return calculationType.getTitle();
|
||||
}
|
||||
|
||||
public Calculation getCalculation() {
|
||||
return calculationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate grid data for plan view display. The input data may with
|
||||
* different geometries, need do the geometry matching process before
|
||||
* calculating to make all member grids are in same domain. This makes
|
||||
* calculation easier and faster, but may cost more memory in some cases.
|
||||
* Calculating with different geometries is no extra memory cost, but is
|
||||
* very complicated and slow. The calculation result data is added into the
|
||||
* grid data monitor.
|
||||
*
|
||||
* @param inputData
|
||||
* - loaded grid data of all members in one frame
|
||||
* @return - Calculation result grid data
|
||||
*/
|
||||
public List<GeneralGridData> calculate(List<List<GeneralGridData>> inputData) {
|
||||
|
||||
if (inputData == null || inputData.size() == 0
|
||||
|| inputData.get(0) == null || inputData.get(0).size() == 0)
|
||||
return null;
|
||||
|
||||
GridGeometry2D geometry = matchGeometry(inputData);
|
||||
|
||||
/**
|
||||
* Suppose the grid data is in same domain and unit, therefore the grid
|
||||
* size of the result is same as any input member.
|
||||
*
|
||||
*/
|
||||
GeneralGridData[] resaultGridData = new GeneralGridData[inputData
|
||||
.get(0).size()];
|
||||
|
||||
for (int k = 0; k < inputData.get(0).size(); k++) {// List
|
||||
|
||||
int imax = inputData.size();
|
||||
|
||||
if (inputData.get(0).get(0).isVector()) {
|
||||
/**
|
||||
* Vector grid data case Is not used in current implementation
|
||||
*/
|
||||
|
||||
// Get U component data
|
||||
GeographicDataSource[] dataU = new GeographicDataSource[imax];
|
||||
for (int i = 0; i < imax; i++) {
|
||||
dataU[i] = inputData.get(i).get(k).getUComponent();
|
||||
}
|
||||
|
||||
// Get V component data
|
||||
GeographicDataSource[] dataV = new GeographicDataSource[imax];
|
||||
for (int i = 0; i < imax; i++) {
|
||||
dataV[i] = inputData.get(i).get(k).getVComponent();
|
||||
}
|
||||
|
||||
// Do Calculation
|
||||
GeneralGridData resultData = GeneralGridData
|
||||
.createVectorDataUV(geometry,
|
||||
doGridCalculation(dataU, imax, geometry),
|
||||
doGridCalculation(dataV, imax, geometry),
|
||||
inputData.get(0).get(0).getDataUnit());
|
||||
|
||||
// To be monitored by GridMemoryManager
|
||||
resultData = GridMemoryManager.getInstance().manage(resultData);
|
||||
|
||||
resaultGridData[k] = resultData;
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* Generic grid data case
|
||||
*/
|
||||
|
||||
// Get the grid data
|
||||
GeographicDataSource[] data = new GeographicDataSource[imax];
|
||||
for (int i = 0; i < imax; i++) {// ArrayList
|
||||
data[i] = inputData.get(i).get(k).getScalarData();
|
||||
}
|
||||
|
||||
// Do Calculation
|
||||
GeneralGridData resultData = GeneralGridData.createScalarData(
|
||||
geometry, doGridCalculation(data, imax, geometry),
|
||||
inputData.get(0).get(0).getDataUnit());
|
||||
|
||||
// To be monitored by GridMemoryManager
|
||||
resultData = GridMemoryManager.getInstance().manage(resultData);
|
||||
|
||||
resaultGridData[k] = resultData;
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(resaultGridData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a grid calculation with members' data. loop through each xy point, get
|
||||
* all member data and calculate the data set.
|
||||
*
|
||||
* @param data
|
||||
* - member grids
|
||||
* @param imax
|
||||
* - How many members
|
||||
* @param geometry
|
||||
* - the geometry of the grids
|
||||
* @return - the grid buffer of the calculation result
|
||||
*/
|
||||
protected FloatBufferWrapper doGridCalculation(GeographicDataSource[] data,
|
||||
int imax, GridGeometry2D geometry) {
|
||||
if (data == null || imax < 1)
|
||||
return null;
|
||||
|
||||
GridEnvelope2D gridRange = geometry.getGridRange2D();
|
||||
int numGridPoints = gridRange.width * gridRange.height;
|
||||
int sizeInBytes = numGridPoints * 4;
|
||||
|
||||
float[] result = new float[gridRange.width * gridRange.height];
|
||||
float[] workValue = new float[imax];
|
||||
|
||||
// loop through each xy poit of the grids
|
||||
for (int y = 0; y < gridRange.height; y++) {
|
||||
for (int x = 0; x < gridRange.width; x++) {
|
||||
int countJ = 0;
|
||||
|
||||
// Read out all available member data at same location
|
||||
for (int i = 0; i < imax; i++)
|
||||
if (!Float.isNaN((float) (data[i].getDataValue(x, y))))
|
||||
workValue[countJ++] = (float) (data[i].getDataValue(x,
|
||||
y));
|
||||
|
||||
// Do real calculation at this location
|
||||
result[y * gridRange.width + x] = calculatePoint(workValue,
|
||||
countJ);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer directBuffer = ByteBuffer.allocateDirect(sizeInBytes);
|
||||
directBuffer.order(ByteOrder.nativeOrder());
|
||||
FloatBuffer dataBuffer = directBuffer.asFloatBuffer();
|
||||
dataBuffer.put(result);
|
||||
dataBuffer.position(0);
|
||||
FloatBufferWrapper wrapper = new FloatBufferWrapper(dataBuffer,
|
||||
gridRange);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all member grid data with same geometry. Currently, we use the
|
||||
* geometry of the input member with biggest domain.
|
||||
*
|
||||
* @param inputData
|
||||
* - loaded grid data of all members in one frame
|
||||
* @return-
|
||||
*/
|
||||
private GridGeometry2D matchGeometry(List<List<GeneralGridData>> inputData) {
|
||||
|
||||
/**
|
||||
* Search the biggest one as main geometry, if the members are with
|
||||
* different geometries. Go through each grid and do re-projection if
|
||||
* its geometry is different then the main geometry.
|
||||
*/
|
||||
|
||||
// Look for a geometry with most coverage
|
||||
GridGeometry2D geometry = inputData.get(0).get(0).getGridGeometry();
|
||||
int maxSize = 0;
|
||||
for (int k = 0; k < inputData.get(0).size(); k++) {
|
||||
int imax = inputData.size();
|
||||
int gridSize = 0;
|
||||
for (int i = 0; i < imax; i++) {
|
||||
gridSize = inputData.get(i).get(k).getScalarData()
|
||||
.getGridGeometry().getGridRange2D().height
|
||||
* inputData.get(i).get(k).getScalarData()
|
||||
.getGridGeometry().getGridRange2D().width;
|
||||
if (gridSize <= 1)
|
||||
continue;
|
||||
|
||||
if (maxSize < gridSize) {
|
||||
maxSize = gridSize;
|
||||
geometry = inputData.get(i).get(k).getGridGeometry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxSize < 0 || geometry == null)
|
||||
return null;
|
||||
|
||||
// Make sure all data with same geometry by re-projecting
|
||||
BilinearInterpolation bilinear = new BilinearInterpolation();
|
||||
bilinear.setMissingThreshold(1.0f);
|
||||
|
||||
for (int k = 0; k < inputData.get(0).size(); k++) {
|
||||
int imax = inputData.size();
|
||||
|
||||
for (int i = 0; i < imax; i++) {
|
||||
|
||||
if (geometry.equals(inputData.get(i).get(k).getGridGeometry()) == true) {
|
||||
// do nothing for same geometry
|
||||
} else {
|
||||
|
||||
// Do re-projection
|
||||
try {
|
||||
inputData.get(i).set(
|
||||
k,
|
||||
(inputData.get(i).get(k).reproject(geometry,
|
||||
bilinear)));
|
||||
} catch (FactoryException | TransformException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculation for time series display. Actually it prepares the data. The
|
||||
* data processing deals special cases like miss data and time match. Use
|
||||
* valid time when doing time match. Suppose all members are with same point
|
||||
* data XYDataList but y can be NaN. Now, We consider the same product
|
||||
* different size case that each member maybe with different number of
|
||||
* values on the X axis. For different products case, calculate at all valid
|
||||
* times with available data.
|
||||
*
|
||||
* @param inputData
|
||||
* - xy point data sets of time series resource members
|
||||
* @return- xy - the calculated point data set.
|
||||
*/
|
||||
public XYDataList calculateTimeSeries(List<XYDataList> inputData) {
|
||||
XYDataList result = new XYDataList();
|
||||
if (inputData == null || inputData.isEmpty())
|
||||
return result;
|
||||
|
||||
// Prepare data by using all X axis values, matching time.
|
||||
ArrayList<Object> xlist = new ArrayList<Object>();
|
||||
for (XYDataList xyList : inputData) {
|
||||
ArrayList<XYData> data = xyList.getData();
|
||||
|
||||
for (int j = 0; j < xyList.getData().size(); j++) {
|
||||
|
||||
if (data.get(j).getX() != null && data.get(j).getY() != null
|
||||
&& !xlist.contains(data.get(j).getX())) {
|
||||
boolean matched = false;
|
||||
for (int k = 0; k < xlist.size(); k++) {
|
||||
|
||||
// Remove different object with same valid time
|
||||
if (((DataTime) xlist.get(k)).getValidTime()
|
||||
.getTimeInMillis() == ((DataTime) (data.get(j)
|
||||
.getX())).getValidTime().getTimeInMillis()) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
xlist.add(data.get(j).getX());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xlist.isEmpty())
|
||||
return result;
|
||||
|
||||
// Sort times
|
||||
|
||||
Object[] xValues = xlist.toArray(new Object[xlist.size()]);
|
||||
// Arrays.sort(xValues); doesn't works
|
||||
// Temporary solution for sort it, to support Datatime only
|
||||
Object temp;
|
||||
for (int i = 0; i < xValues.length; i++) {
|
||||
for (int j = i + 1; j < xValues.length; j++) {
|
||||
|
||||
if (((DataTime) xValues[i]).getValidTime().compareTo(
|
||||
((DataTime) xValues[j]).getValidTime()) > 0) {
|
||||
temp = xValues[i];
|
||||
xValues[i] = xValues[j];
|
||||
xValues[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate all points.
|
||||
result.setData((ArrayList<XYData>) doTimeSeriesCalculation(inputData,
|
||||
xValues));
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through each time/x point, do calculating for time series display.
|
||||
*
|
||||
* @param inputData
|
||||
* - xy point data sets of time series resource members
|
||||
* @param xValues
|
||||
* - time/x values for calculated resource.
|
||||
* @return- The calculated xy data set.
|
||||
*/
|
||||
protected List<XYData> doTimeSeriesCalculation(List<XYDataList> inputData,
|
||||
Object[] xValues) {
|
||||
|
||||
ArrayList<XYData> dataList = new ArrayList<XYData>();
|
||||
|
||||
// Calculate for all point
|
||||
for (int i = 0; i < xValues.length; i++) {
|
||||
|
||||
// Calculate for one x point. Look for y data of this x point first.
|
||||
ArrayList<Float> yValues = new ArrayList<Float>();
|
||||
for (XYDataList xyList : inputData) {
|
||||
ArrayList<XYData> data = xyList.getData();
|
||||
|
||||
for (int j = 0; j < xyList.getData().size(); j++) {
|
||||
if (data.get(j).getX() == null
|
||||
&& data.get(j).getY() == null)
|
||||
continue;
|
||||
|
||||
if (xValues[i].equals(data.get(j).getX())) {
|
||||
yValues.add(Float.parseFloat(data.get(j).getY()
|
||||
.toString()));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (yValues.isEmpty())
|
||||
continue;
|
||||
|
||||
// Put the y values in the work buffer and do calculate the point.
|
||||
float[] workValue = new float[yValues.size()];
|
||||
for (int k = 0; k < yValues.size(); k++)
|
||||
workValue[k] = (float) yValues.get(k);
|
||||
XYData xy = new XYData(xValues[i], calculatePoint(workValue,
|
||||
yValues.size()));
|
||||
|
||||
dataList.add(xy);
|
||||
|
||||
}
|
||||
|
||||
return dataList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do real calculation for one data set, This interface is implemented in
|
||||
* the derived classes.
|
||||
*
|
||||
* @param workValue
|
||||
* - inputed data set as a work buffer
|
||||
* @param length
|
||||
* - how many data in the work buffer.
|
||||
* @return- calculated result.
|
||||
*/
|
||||
abstract protected float calculatePoint(float[] workValue, int length);
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate maximum for different display types.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class MaxCalculator extends EnsembleCalculator {
|
||||
public MaxCalculator() {
|
||||
super(Calculation.MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
float max = Float.NaN;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(max)) {
|
||||
max = workValue[i];
|
||||
continue;
|
||||
}
|
||||
if (max < workValue[i])
|
||||
max = workValue[i];
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate mean for different display types.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class MeanCalculator extends EnsembleCalculator {
|
||||
public MeanCalculator() {
|
||||
super(Calculation.MEAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
float mean = Float.NaN;
|
||||
int count = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(workValue[i]))
|
||||
continue;
|
||||
count++;
|
||||
if (Float.isNaN(mean)) {
|
||||
mean = workValue[i];
|
||||
|
||||
continue;
|
||||
}
|
||||
mean += workValue[i];
|
||||
}
|
||||
if (!Float.isNaN(mean) && count > 0)
|
||||
mean = mean / count;
|
||||
|
||||
return mean;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate median for different display types.
|
||||
*
|
||||
* The algorithm is referred to ALPS ensemble.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class MedianCalculator extends EnsembleCalculator {
|
||||
public MedianCalculator() {
|
||||
super(Calculation.MEDIAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
float[] workValue2 = new float[length];
|
||||
int length2 = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(workValue[i]))
|
||||
continue;
|
||||
workValue2[length2++] = workValue[i];
|
||||
}
|
||||
if (length2 < 1)
|
||||
return Float.NaN;
|
||||
if (length2 == 1)
|
||||
return workValue2[0];
|
||||
|
||||
int ni = length2 - 1;
|
||||
float tempValue;
|
||||
for (int i = 0; i < ni; i++) {
|
||||
for (int k = i + 1; k < ni; k++) {
|
||||
if (workValue[i] < workValue[k])
|
||||
continue;
|
||||
tempValue = workValue[i];
|
||||
workValue[i] = workValue[k];
|
||||
workValue[k] = tempValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (length % 2 == 0) {
|
||||
return (workValue[(length / 2) - 1] + workValue[length / 2]) / 2.0f;
|
||||
}
|
||||
return workValue[length / 2];
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate minimum for different display types.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class MinCalculator extends EnsembleCalculator {
|
||||
public MinCalculator() {
|
||||
super(Calculation.MIN);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
float min = Float.NaN;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(min)) {
|
||||
min = workValue[i];
|
||||
continue;
|
||||
}
|
||||
if (min > workValue[i])
|
||||
min = workValue[i];
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate mode for different display types. The algorithm is referred to ALPS
|
||||
* ensemble developed by James Ramer. It's good for some products in AWIPS, but
|
||||
* isn't generic. We are checking on other algorithms such as in GEMPAK, to
|
||||
* determine the final one in later release.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class ModeCalculator extends EnsembleCalculator {
|
||||
public ModeCalculator() {
|
||||
super(Calculation.MODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
|
||||
float mode = Float.NaN;
|
||||
float vmax = Float.MIN_VALUE;
|
||||
float vmin = Float.MAX_VALUE;
|
||||
int nok = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (Float.isNaN(workValue[i]))
|
||||
continue;
|
||||
nok++;
|
||||
if (workValue[i] > vmax)
|
||||
vmax = workValue[i];
|
||||
if (workValue[i] < vmin)
|
||||
vmin = workValue[i];
|
||||
}
|
||||
|
||||
if (nok == 0)
|
||||
return mode;
|
||||
if (vmax <= vmin)
|
||||
return vmax;
|
||||
|
||||
short[] counts = new short[144];
|
||||
float vstep = (vmax - vmin) / 11;
|
||||
vmin -= vstep;
|
||||
vstep /= 11;
|
||||
int nmax = 0, icen;
|
||||
for (int j = 0; j < length; j++) {
|
||||
if (Float.isNaN(workValue[j]))
|
||||
continue;
|
||||
icen = (int) ((workValue[j] - vmin) / vstep);
|
||||
for (int i = icen - 5; i <= icen + 5; i++) {
|
||||
counts[i]++;
|
||||
if (counts[i] > nmax)
|
||||
nmax = counts[i];
|
||||
}
|
||||
}
|
||||
|
||||
int i1b, i2b;
|
||||
i1b = i2b = 0;
|
||||
for (int i1 = 0; i1 < 144; i1++) {
|
||||
if (counts[i1] < nmax)
|
||||
continue;
|
||||
for (int i2 = i1 + 1; counts[i1] >= nmax; i2++) {
|
||||
if (i2 - i1 < i2b - i1b)
|
||||
continue;
|
||||
i2b = i2;
|
||||
i1b = i1;
|
||||
}
|
||||
}
|
||||
mode = (float) ((i2b + i1b) * 0.5 * vstep + vmin);
|
||||
|
||||
return mode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* The Range is used to pass information between GUI and display in the
|
||||
* interactive ensemble calculations.
|
||||
*
|
||||
*
|
||||
* @author polster
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July 1, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class Range {
|
||||
|
||||
private double lowerThreshold = Integer.MIN_VALUE;
|
||||
|
||||
private double higherThreshold = Integer.MAX_VALUE;
|
||||
|
||||
private double onlyThreshold = Double.MIN_NORMAL;
|
||||
|
||||
private RangeType rangeType = RangeType.NONE;
|
||||
|
||||
public Range(RangeType rt) {
|
||||
rangeType = rt;
|
||||
}
|
||||
|
||||
public void setRange(double lowerValue, double higherValue)
|
||||
throws IllegalArgumentException {
|
||||
if (lowerValue >= higherValue) {
|
||||
throw new IllegalArgumentException(
|
||||
"Low value must be less than high value.");
|
||||
}
|
||||
lowerThreshold = lowerValue;
|
||||
higherThreshold = higherValue;
|
||||
}
|
||||
|
||||
public RangeType getRangeType() {
|
||||
return rangeType;
|
||||
}
|
||||
|
||||
public double getLowerRangeThreshold() {
|
||||
return lowerThreshold;
|
||||
}
|
||||
|
||||
public double getUpperRangeThreshold() {
|
||||
return higherThreshold;
|
||||
}
|
||||
|
||||
public void setThreshold(double t) throws IllegalArgumentException {
|
||||
|
||||
if ((rangeType == RangeType.ABOVE_THRESHOLD)
|
||||
|| (rangeType == RangeType.BELOW_THRESHOLD)) {
|
||||
onlyThreshold = t;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"RangeType requires two arguments.");
|
||||
}
|
||||
}
|
||||
|
||||
public double getThreshold() {
|
||||
return onlyThreshold;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate range.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
|
||||
public class RangeCalculator extends EnsembleCalculator {
|
||||
public RangeCalculator() {
|
||||
super(Calculation.RANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
if (workValue == null || length < 1)
|
||||
return Float.NaN;
|
||||
|
||||
float range = Float.NaN;
|
||||
|
||||
float min = Float.NaN;
|
||||
float max = Float.NaN;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
if (Float.isNaN(workValue[i]))
|
||||
continue;
|
||||
|
||||
if (Float.isNaN(max) && Float.isNaN(min)) {
|
||||
max = min = workValue[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max < workValue[i])
|
||||
max = workValue[i];
|
||||
if (min > workValue[i])
|
||||
min = workValue[i];
|
||||
|
||||
}
|
||||
if (Float.isNaN(max) || Float.isNaN(min)) {
|
||||
range = Float.NaN;
|
||||
} else {
|
||||
range = max - min;
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Define the range types which are the interactive calculation conditions.
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July 1, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public enum RangeType {
|
||||
NONE, // no value
|
||||
INNER_RANGE, // low-value <= x && high-value >= x
|
||||
OUTER_RANGE, // low-value >= x || high-value <= x
|
||||
ABOVE_THRESHOLD, // x >= value
|
||||
BELOW_THRESHOLD; // x <= value
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate STDDEV for different display types. The algorithm is referred to
|
||||
* ALPS ensemble.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class StddevCalculator extends EnsembleCalculator {
|
||||
public StddevCalculator() {
|
||||
super(Calculation.STANDARD_DEVIATION);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
if (workValue == null || length < 1)
|
||||
return Float.NaN;
|
||||
|
||||
float stddev;
|
||||
|
||||
int countJ = 0;
|
||||
float sum = 0;
|
||||
float scr0 = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
if (!Float.isNaN(workValue[i])) {
|
||||
countJ++;
|
||||
sum += workValue[i];
|
||||
scr0 += workValue[i] * workValue[i];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (countJ == 0) {
|
||||
stddev = Float.NaN;
|
||||
} else {
|
||||
sum /= countJ;
|
||||
scr0 = scr0 / countJ - sum * sum;
|
||||
stddev = scr0 > 0 ? (float) Math.sqrt(scr0) : 0;
|
||||
}
|
||||
|
||||
return stddev;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.calculate;
|
||||
|
||||
/**
|
||||
* Calculate sum.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 1, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class SumCalculator extends EnsembleCalculator {
|
||||
public SumCalculator() {
|
||||
super(Calculation.SUMMATION);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator#calculatePoint
|
||||
* (float[], int)
|
||||
*/
|
||||
@Override
|
||||
protected float calculatePoint(float[] workValue, int length) {
|
||||
if (workValue == null || length < 1)
|
||||
return Float.NaN;
|
||||
|
||||
float sum = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
// This solution is for same GridGeometry grids
|
||||
if (!Float.isNaN(workValue[i]))
|
||||
sum += workValue[i];
|
||||
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
|
||||
/**
|
||||
* Force implementers of derived concrete classes to provide the metadata
|
||||
* getters for all the common meteorological components of a resource.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public abstract class AbstractLegendComponentsProvider {
|
||||
|
||||
public AbstractLegendComponentsProvider() {
|
||||
}
|
||||
|
||||
// this will be a root name e.g. for an ensemble group
|
||||
abstract public String getGroupName();
|
||||
|
||||
// this will be unique between resources within a group
|
||||
// or it will be identical to the getGroupName() method.
|
||||
abstract public String getUniqueName();
|
||||
|
||||
abstract public String getModel();
|
||||
|
||||
abstract public String getLocation();
|
||||
|
||||
abstract public String getLevel();
|
||||
|
||||
abstract public String getParameter();
|
||||
|
||||
abstract public String getUnits();
|
||||
|
||||
abstract public String getDataTime();
|
||||
|
||||
abstract public String getType();
|
||||
|
||||
abstract public String getEnsembleId();
|
||||
|
||||
abstract public String getEnsembleIdRaw();
|
||||
|
||||
abstract public String getStationId();
|
||||
|
||||
abstract public Calculation getCalculation();
|
||||
|
||||
/*
|
||||
* An abstract place to put the SREF prettifier.
|
||||
*/
|
||||
protected String srefPerturbationPrettyfied(String pert) {
|
||||
|
||||
String niceName = "<undef>";
|
||||
|
||||
if (pert == null) {
|
||||
return niceName;
|
||||
}
|
||||
|
||||
String pertPrefix = pert.replaceAll("[0-9]", "");
|
||||
String pertNumStr = pert.replaceAll("[^0-9]", "");
|
||||
|
||||
int pertNumber = Integer.parseInt(pertNumStr);
|
||||
|
||||
if ((pertNumber >= 1) && (pertNumber <= 7)) {
|
||||
|
||||
if (pertPrefix.startsWith("ctll")) {
|
||||
niceName = "nmm ctrl-1";
|
||||
} else if (pertPrefix.startsWith("n")) {
|
||||
niceName = "nmm n-" + pertNumber;
|
||||
} else if (pertPrefix.startsWith("p")) {
|
||||
niceName = "nmm p-" + pertNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pertNumber >= 8) && (pertNumber <= 14)) {
|
||||
|
||||
if (pertPrefix.startsWith("ctll")) {
|
||||
niceName = "nmb ctrl-1";
|
||||
} else if (pertPrefix.startsWith("n")) {
|
||||
niceName = "nmb n-" + (pertNumber - 7);
|
||||
} else if (pertPrefix.startsWith("p")) {
|
||||
niceName = "nmb p-" + (pertNumber - 7);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((pertNumber >= 15) && (pertNumber <= 21)) {
|
||||
|
||||
if (pertPrefix.startsWith("ctll")) {
|
||||
niceName = "em ctrl-1";
|
||||
} else if (pertPrefix.startsWith("n")) {
|
||||
niceName = "em n-" + (pertNumber - 14);
|
||||
} else if (pertPrefix.startsWith("p")) {
|
||||
niceName = "em p-" + (pertNumber - 14);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
niceName = String.format("%-10s", niceName);
|
||||
|
||||
return niceName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.ERFCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Range;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.GeneratedEnsembleGridResource;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.GeneratedEnsembleGridResourceData;
|
||||
import gov.noaa.gsd.viz.ensemble.util.Utilities;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
|
||||
/**
|
||||
* Concrete resolution of accessors of generated grid resource attributes.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GeneratedGridResourceHolder extends GenericResourceHolder {
|
||||
|
||||
GeneratedEnsembleGridResource<?> currRsc = null;
|
||||
|
||||
protected GeneratedGridResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
super(rsc, isSelected);
|
||||
currRsc = (GeneratedEnsembleGridResource<?>) rsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevel() {
|
||||
String level;
|
||||
|
||||
if ((currRsc.getName() == null) || (currRsc.getName().length() == 0)) {
|
||||
level = "<level missing>";
|
||||
} else {
|
||||
StringTokenizer st = new StringTokenizer(currRsc.getName());
|
||||
level = st.nextToken();
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter() {
|
||||
String parameter;
|
||||
if ((currRsc.getName() == null) || (currRsc.getName().length() == 0)) {
|
||||
parameter = "<parameter missing>";
|
||||
} else {
|
||||
StringTokenizer st = new StringTokenizer(currRsc.getName());
|
||||
st.nextToken();
|
||||
st.nextToken();
|
||||
parameter = st.nextToken();
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTime() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnits() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calculation getCalculation() {
|
||||
return currRsc.getCalculation();
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
|
||||
return getUniqueName();
|
||||
}
|
||||
|
||||
public String getUniqueName() {
|
||||
|
||||
String s = currRsc.getName();
|
||||
String nodeLabel = Utilities.removeExtraSpaces(s);
|
||||
|
||||
return nodeLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocation() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleIdRaw() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStationId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getUniqueName().hashCode();
|
||||
}
|
||||
|
||||
public Range getRange() {
|
||||
Range r = null;
|
||||
if (GeneratedEnsembleGridResourceData.class.isAssignableFrom(currRsc
|
||||
.getResourceData().getClass())) {
|
||||
GeneratedEnsembleGridResourceData grd = (GeneratedEnsembleGridResourceData) currRsc
|
||||
.getResourceData();
|
||||
if (ERFCalculator.class.isAssignableFrom(grd.getCalculator()
|
||||
.getClass())) {
|
||||
ERFCalculator erf = (ERFCalculator) grd.getCalculator();
|
||||
r = erf.getRange();
|
||||
}
|
||||
grd.getCalculator();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.timeseries.GeneratedTimeSeriesResource;
|
||||
import gov.noaa.gsd.viz.ensemble.util.Utilities;
|
||||
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
|
||||
/**
|
||||
* Concrete resolution of accessors of typical time series resource attributes.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
public class GeneratedTimeSeriesResourceHolder extends TimeSeriesResourceHolder {
|
||||
|
||||
GeneratedTimeSeriesResource<?> currRsc = null;
|
||||
|
||||
protected GeneratedTimeSeriesResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
super(rsc, isSelected);
|
||||
currRsc = (GeneratedTimeSeriesResource<?>) rsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calculation getCalculation() {
|
||||
return currRsc.getCalculation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter() {
|
||||
|
||||
String p = "";
|
||||
if (currRsc.getParameterName() != null) {
|
||||
p = currRsc.getParameterName();
|
||||
if (p.compareTo("Height") == 0) {
|
||||
p = "Hgt";
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueName() {
|
||||
|
||||
String s = currRsc.getName();
|
||||
String nodeLabel = Utilities.removeExtraSpaces(s);
|
||||
return nodeLabel;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.GeneratedEnsembleGridResource;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.histogram.HistogramResource;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.timeseries.GeneratedTimeSeriesResource;
|
||||
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator;
|
||||
|
||||
/**
|
||||
* This class represents the abstract container which encapulates an
|
||||
* AbstractVizResource (that happens to be associated with the Ensemble Tool).
|
||||
* It provides a poor-man's approach at defining how to parse and extract common
|
||||
* resource metadata, an interface that doesn't already exist in the viz
|
||||
* resource class. Similar approaches have been attempted in other resource data
|
||||
* classes (e.g. getMetaDataMap) but were not necessarily reusable. This class
|
||||
* exists to attempt to fill an unusual void in the hierarchy of an
|
||||
* AbstractVizResource as there is no convenient way to extract commonly known
|
||||
* meteorological metadata information from the resource (needs verification).
|
||||
*
|
||||
* This abstact class forces derived classes to define the equals() and hashCode
|
||||
* methods, among other notable getters.
|
||||
*
|
||||
* In order to create a class of this type call the factory method (see
|
||||
* createResourceHolder).
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public abstract class GenericResourceHolder extends
|
||||
AbstractLegendComponentsProvider {
|
||||
|
||||
AbstractVizResource<?, ?> rsc;
|
||||
|
||||
boolean isSelected = false; // either selected or unselected
|
||||
|
||||
boolean isGenerated = false; // either generated or a basic (normally
|
||||
// loaded) resource
|
||||
|
||||
public static GenericResourceHolder createResourceHolder(
|
||||
AbstractVizResource<?, ?> rsc, boolean isSelected) {
|
||||
|
||||
GenericResourceHolder genericRsc = null;
|
||||
|
||||
if (GeneratedEnsembleGridResource.class
|
||||
.isAssignableFrom(rsc.getClass())) {
|
||||
genericRsc = new GeneratedGridResourceHolder(rsc, isSelected);
|
||||
} else if (GeneratedTimeSeriesResource.class.isAssignableFrom(rsc
|
||||
.getClass())) {
|
||||
genericRsc = new GeneratedTimeSeriesResourceHolder(rsc, isSelected);
|
||||
} else if ((rsc instanceof AbstractVizResource<?, ?>)
|
||||
&& (rsc instanceof GridNameGenerator.IGridNameResource)) {
|
||||
genericRsc = new GridResourceHolder(rsc, isSelected);
|
||||
} else if (TimeSeriesResource.class.isAssignableFrom(rsc.getClass())) {
|
||||
genericRsc = new TimeSeriesResourceHolder(rsc, isSelected);
|
||||
} else if (HistogramResource.class.isAssignableFrom(rsc.getClass())) {
|
||||
genericRsc = new HistogramGridResourceHolder(rsc, isSelected);
|
||||
}
|
||||
return genericRsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
boolean equals = false;
|
||||
if (o instanceof GenericResourceHolder) {
|
||||
GenericResourceHolder gr = (GenericResourceHolder) o;
|
||||
equals = this.getUniqueName().equals(gr.getUniqueName());
|
||||
} else {
|
||||
equals = false;
|
||||
}
|
||||
return equals;
|
||||
}
|
||||
|
||||
public abstract int hashCode();
|
||||
|
||||
protected GenericResourceHolder() {
|
||||
|
||||
}
|
||||
|
||||
protected GenericResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
this.rsc = rsc;
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
|
||||
public AbstractVizResource<?, ?> getRsc() {
|
||||
return rsc;
|
||||
}
|
||||
|
||||
public void setRsc(AbstractVizResource<?, ?> rsc) {
|
||||
this.rsc = rsc;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public void setSelected(boolean isSelected) {
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
|
||||
public boolean isGenerated() {
|
||||
return isGenerated;
|
||||
}
|
||||
|
||||
public void setGenerated(boolean isEnsGenerated) {
|
||||
this.isGenerated = isEnsGenerated;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.util.Utilities;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.level.Level;
|
||||
import com.raytheon.uf.common.dataplugin.level.mapping.LevelMapping;
|
||||
import com.raytheon.uf.common.dataplugin.level.mapping.LevelMappingFactory;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator.IGridNameResource;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator.LegendParameters;
|
||||
|
||||
/**
|
||||
* Concrete resolution of accessors of typical grid resource attributes.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
public class GridResourceHolder extends GenericResourceHolder {
|
||||
|
||||
GridNameGenerator.IGridNameResource currRsc = null;
|
||||
|
||||
protected GridResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
super(rsc, isSelected);
|
||||
currRsc = (GridNameGenerator.IGridNameResource) rsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
String model;
|
||||
if (currRsc.getLegendParameters() == null) {
|
||||
model = "<model missing>";
|
||||
} else {
|
||||
model = currRsc.getLegendParameters().model;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevel() {
|
||||
String level;
|
||||
if (currRsc.getLegendParameters() == null) {
|
||||
level = "<level missing>";
|
||||
} else {
|
||||
level = lookupPlane(currRsc.getLegendParameters().level);
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter() {
|
||||
String parameter;
|
||||
if (currRsc.getLegendParameters() == null) {
|
||||
parameter = "<param missing>";
|
||||
} else {
|
||||
parameter = currRsc.getLegendParameters().parameter;
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTime() {
|
||||
String datatime;
|
||||
if ((currRsc.getLegendParameters() == null)
|
||||
|| (currRsc.getLegendParameters().dataTime == null)) {
|
||||
datatime = "<datatime missing>";
|
||||
} else {
|
||||
LegendParameters legendParams = ((IGridNameResource) rsc)
|
||||
.getLegendParameters();
|
||||
datatime = legendParams.dataTime.getLegendString();
|
||||
}
|
||||
return datatime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnits() {
|
||||
String units;
|
||||
if (currRsc.getLegendParameters() == null) {
|
||||
units = "<units missing>";
|
||||
} else {
|
||||
units = currRsc.getLegendParameters().unit;
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
String type;
|
||||
if (currRsc.getLegendParameters() == null) {
|
||||
type = "<type missing>";
|
||||
} else {
|
||||
type = currRsc.getLegendParameters().type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleId() {
|
||||
|
||||
String ensId = "<ensemble id missing>";
|
||||
if ((currRsc.getLegendParameters() != null) && (getModel() != null)) {
|
||||
ensId = currRsc.getLegendParameters().ensembleId;
|
||||
if ((ensId != null) && (getModel().indexOf("SREF") >= 0)) {
|
||||
ensId = srefPerturbationPrettyfied(ensId);
|
||||
}
|
||||
}
|
||||
return ensId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleIdRaw() {
|
||||
String ensId = "";
|
||||
if ((currRsc.getLegendParameters() != null) && (getModel() != null)) {
|
||||
ensId = currRsc.getLegendParameters().ensembleId;
|
||||
}
|
||||
return ensId;
|
||||
}
|
||||
|
||||
private String lookupPlane(Level level) {
|
||||
LevelMapping mapping = LevelMappingFactory.getInstance(
|
||||
LevelMappingFactory.VOLUMEBROWSER_LEVEL_MAPPING_FILE)
|
||||
.getLevelMappingForLevel(level);
|
||||
if (mapping == null) {
|
||||
return level.getMasterLevel().getName();
|
||||
}
|
||||
return mapping.getDisplayName();
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
|
||||
String sb = String.format("%s %s %s %s", getModel(), getLevel(),
|
||||
getParameter(), getUnits() != null
|
||||
&& getUnits().equals("") == false ? "(" + getUnits()
|
||||
+ ")" : "");
|
||||
return sb;
|
||||
}
|
||||
|
||||
public String getUniqueName() {
|
||||
|
||||
String sb = String
|
||||
.format("%s %s %s %s %s",
|
||||
getModel(),
|
||||
getLevel(),
|
||||
getParameter(),
|
||||
getUnits() != null && getUnits().equals("") == false ? "("
|
||||
+ getUnits() + ")"
|
||||
: "",
|
||||
getEnsembleId() != null
|
||||
&& getEnsembleId().equals("") == false ? getEnsembleId()
|
||||
: "");
|
||||
|
||||
String nodeLabel = Utilities.removeExtraSpaces(sb.toString());
|
||||
return nodeLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocation() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStationId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calculation getCalculation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getUniqueName().hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.histogram.HistogramResource;
|
||||
import gov.noaa.gsd.viz.ensemble.util.Utilities;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
|
||||
/**
|
||||
* Concrete resolution of accessors of histogram resource attributes.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class HistogramGridResourceHolder extends GenericResourceHolder {
|
||||
|
||||
private HistogramResource<?> currRsc = null;
|
||||
|
||||
protected HistogramGridResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
super(rsc, isSelected);
|
||||
currRsc = (HistogramResource<?>) rsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
String model = "";
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevel() {
|
||||
String level;
|
||||
|
||||
if ((currRsc.getName() == null) || (currRsc.getName().length() == 0)) {
|
||||
level = "<level missing>";
|
||||
} else {
|
||||
StringTokenizer st = new StringTokenizer(currRsc.getName());
|
||||
level = st.nextToken();
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter() {
|
||||
String parameter = "";
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTime() {
|
||||
String datatime = "";
|
||||
return datatime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnits() {
|
||||
String units = "";
|
||||
if ((currRsc.getName() == null) || (currRsc.getName().length() == 0)) {
|
||||
units = "<level missing>";
|
||||
} else {
|
||||
StringTokenizer st = new StringTokenizer(currRsc.getName());
|
||||
st.nextToken();
|
||||
units = st.nextToken();
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calculation getCalculation() {
|
||||
// return "color histogram";
|
||||
if (((HistogramResource<?>) this.rsc).getMode() == HistogramResource.DisplayMode.SAMPLING)
|
||||
return Calculation.HISTOGRAM_SAMPLING;
|
||||
else
|
||||
return Calculation.HISTOGRAM_TEXT;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
|
||||
return getUniqueName();
|
||||
}
|
||||
|
||||
public String getUniqueName() {
|
||||
|
||||
String s = currRsc.getName();
|
||||
String nodeLabel = Utilities.removeExtraSpaces(s);
|
||||
|
||||
return nodeLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocation() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleIdRaw() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStationId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getUniqueName().hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,521 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.xy.timeseries.display.TimeSeriesDescriptor;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Access and operate the Ensemble Tool resources. Any resources contained in
|
||||
* this list class will be associated with an editor and is assumed to be
|
||||
* controlled by the Ensemble Tool.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class NavigatorResourceList {
|
||||
|
||||
private List<GenericResourceHolder> ensembleToolResources;
|
||||
|
||||
private AbstractEditor theEditor;
|
||||
|
||||
// contains which ensemble resource is currently used as
|
||||
// the calculation resource ...
|
||||
String calculationEnsembleName = null;
|
||||
|
||||
public NavigatorResourceList(AbstractEditor editor) {
|
||||
ensembleToolResources = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
theEditor = editor;
|
||||
}
|
||||
|
||||
public boolean add(GenericResourceHolder emr) {
|
||||
|
||||
if (!containsResource(emr)) {
|
||||
ensembleToolResources.add(emr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean remove(GenericResourceHolder emr) {
|
||||
|
||||
boolean removed = false;
|
||||
for (GenericResourceHolder gr : ensembleToolResources) {
|
||||
if (gr == emr) {
|
||||
ensembleToolResources.remove(gr);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public boolean remove(AbstractVizResource<?, ?> rcs) {
|
||||
|
||||
boolean removed = false;
|
||||
for (GenericResourceHolder gr : ensembleToolResources) {
|
||||
if (gr.getRsc() == rcs) {
|
||||
ensembleToolResources.remove(gr);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ensembleToolResources.clear();
|
||||
}
|
||||
|
||||
public List<GenericResourceHolder> getResourceHolders() {
|
||||
return ensembleToolResources;
|
||||
}
|
||||
|
||||
public boolean containsResource(GenericResourceHolder rsc) {
|
||||
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (emr.equals(rsc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsResource(AbstractVizResource<?, ?> rsc) {
|
||||
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (emr.getRsc().equals(rsc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* All resources
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<GenericResourceHolder> getAllRscsAsList() {
|
||||
List<GenericResourceHolder> rscs = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
rscs.add(emr);
|
||||
}
|
||||
|
||||
return rscs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all loaded and generated resources as GenericResourceHolder
|
||||
* instances.
|
||||
*/
|
||||
public Map<String, List<GenericResourceHolder>> getAllRscsAsMap() {
|
||||
|
||||
Map<String, List<GenericResourceHolder>> rscMap = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
List<GenericResourceHolder> rscs = EnsembleResourceManager.instance
|
||||
.getResourceList(theEditor).getUserLoadedRscs();
|
||||
|
||||
String currRscName = null;
|
||||
|
||||
// let's loop through and find the group names
|
||||
// and store them in a set of strings (no duplicates
|
||||
// allowed) so sub-members such as perturbations will
|
||||
// only be counted once.
|
||||
Set<String> rscGroupNames = new HashSet<String>();
|
||||
for (GenericResourceHolder rsc : rscs) {
|
||||
currRscName = rsc.getGroupName();
|
||||
if (!rscGroupNames.contains(currRscName)) {
|
||||
rscGroupNames.add(currRscName);
|
||||
}
|
||||
}
|
||||
Iterator<String> iter = rscGroupNames.iterator();
|
||||
while (iter.hasNext()) {
|
||||
String currRsc = iter.next();
|
||||
List<GenericResourceHolder> members = findAssociatedMembers(currRsc);
|
||||
if (!members.isEmpty()) {
|
||||
rscMap.put(currRsc, members);
|
||||
}
|
||||
}
|
||||
|
||||
// Generated resource add on
|
||||
rscs = EnsembleResourceManager.instance.getResourceList(theEditor)
|
||||
.getUserGeneratedRscs();
|
||||
for (GenericResourceHolder rsc : rscs) {
|
||||
currRscName = rsc.getUniqueName();
|
||||
if ((currRscName == null) || (currRscName.length() == 0)) {
|
||||
currRscName = rsc.getRsc().getName();
|
||||
}
|
||||
List<GenericResourceHolder> members = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
members.add(rsc);
|
||||
|
||||
rscMap.put(currRscName, members);
|
||||
}
|
||||
|
||||
return rscMap;
|
||||
}
|
||||
|
||||
private List<GenericResourceHolder> findAssociatedMembers(
|
||||
String resourceGroupName) {
|
||||
|
||||
List<GenericResourceHolder> rscs = EnsembleResourceManager.instance
|
||||
.getResourceList(theEditor).getUserLoadedRscs();
|
||||
|
||||
List<GenericResourceHolder> members = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
|
||||
for (GenericResourceHolder rsc : rscs) {
|
||||
|
||||
if (rsc.getUniqueName().startsWith(resourceGroupName)) {
|
||||
members.add(rsc);
|
||||
}
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* All resources for an editor that were not generated.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<GenericResourceHolder> getUserLoadedRscs() {
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
List<GenericResourceHolder> rscs = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated()) {
|
||||
rscs.add(emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscs;
|
||||
}
|
||||
|
||||
/**
|
||||
* All loaded resources of an ensemble model using its unique name (e.g
|
||||
* "SREF 500MB").
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<GenericResourceHolder> getUserLoadedRscs(
|
||||
String uniqueResourceName) {
|
||||
if (uniqueResourceName == null)
|
||||
return null;
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
List<GenericResourceHolder> rscs = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated) {
|
||||
String fullName = emr.getGroupName();
|
||||
if (fullName.equals(uniqueResourceName)) {
|
||||
rscs.add(emr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rscs;
|
||||
}
|
||||
|
||||
/**
|
||||
* All loaded resources for ensemble.
|
||||
*
|
||||
* @param descriptor
|
||||
* : the descriptor of the resource
|
||||
* @param selected
|
||||
* :if it's selected.
|
||||
* @return
|
||||
*/
|
||||
public Map<String, List<GenericResourceHolder>> getUserLoadedRscs(
|
||||
IDescriptor descriptor, boolean selected) {
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
Map<String, List<GenericResourceHolder>> rscMap = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated
|
||||
&& emr.isSelected == selected
|
||||
&& emr.getRsc().getDescriptor().getClass() == descriptor
|
||||
.getClass()) { // same type descriptor like Map
|
||||
if (emr.getRsc().getName() == null
|
||||
|| emr.getRsc().getName().equals(""))
|
||||
continue;
|
||||
String model = emr.getModel();
|
||||
addResource2Map(rscMap, model, emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* All loaded resources for ensemble.
|
||||
*
|
||||
* @param descriptor
|
||||
* :the descriptor of the resource
|
||||
* @param selected
|
||||
* :if it's selected.
|
||||
* @param level
|
||||
* :level of the resource.
|
||||
* @param unit
|
||||
* : unit of the resource.
|
||||
* @return
|
||||
*/
|
||||
public Map<String, List<GenericResourceHolder>> getUserLoadedRscs(
|
||||
IDescriptor descriptor, boolean selected, String level, String unit) {
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
Map<String, List<GenericResourceHolder>> rscMap = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (descriptor instanceof IMapDescriptor
|
||||
&& emr.getRsc().getDescriptor() instanceof IMapDescriptor) {
|
||||
|
||||
if (!emr.isGenerated
|
||||
&& emr.isSelected == selected
|
||||
&& level.equals(emr.getLevel())
|
||||
&& unit.equals(emr.getUnits())
|
||||
// same type descriptor like Map
|
||||
&& emr.getRsc().getDescriptor().getClass() == descriptor
|
||||
.getClass()) {
|
||||
|
||||
// Model name is the first string
|
||||
if (emr.getRsc().getName() == null
|
||||
|| emr.getRsc().getName().equals(""))
|
||||
continue;
|
||||
String model = emr.getModel();
|
||||
addResource2Map(rscMap, model, emr);
|
||||
}
|
||||
} else if (descriptor instanceof TimeSeriesDescriptor
|
||||
&& emr.getRsc().getDescriptor() instanceof TimeSeriesDescriptor) {
|
||||
|
||||
if (!emr.isGenerated
|
||||
&& emr.isSelected == selected
|
||||
&& level.equals(((TimeSeriesResource) (emr.getRsc()))
|
||||
.getResourceData().getLevelKey())
|
||||
&& unit.equals(((TimeSeriesResource) (emr.getRsc()))
|
||||
.getUnits())
|
||||
&& emr.getRsc().getDescriptor().getClass() == descriptor
|
||||
.getClass()) { // same type descriptor like Map
|
||||
|
||||
// Model name is the first string
|
||||
if (emr.getRsc().getName() == null
|
||||
|| emr.getRsc().getName().equals(""))
|
||||
continue;
|
||||
String model = emr.getModel();
|
||||
addResource2Map(rscMap, model, emr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rscMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* All loaded resources for ensemble.
|
||||
*
|
||||
* @param descriptor
|
||||
* :the descriptor of the resource
|
||||
* @param selected
|
||||
* :if it's selected.
|
||||
* @param unit
|
||||
* : unit of the resource.
|
||||
* @return
|
||||
*/
|
||||
public Map<String, List<GenericResourceHolder>> getUserLoadedRscs(
|
||||
IDescriptor descriptor, boolean selected, String unit) {
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
Map<String, List<GenericResourceHolder>> rscMap = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated
|
||||
&& emr.isSelected == selected
|
||||
&& unit.equals(emr.getUnits())
|
||||
// same type descriptor like Map
|
||||
&& emr.getRsc().getDescriptor().getClass() == descriptor
|
||||
.getClass()) {
|
||||
|
||||
if (emr.getRsc().getName() == null
|
||||
|| emr.getRsc().getName().equals(""))
|
||||
continue;
|
||||
String model = emr.getModel();
|
||||
addResource2Map(rscMap, model, emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* All generated resources by ensemble display
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<GenericResourceHolder> getUserGeneratedRscs() {
|
||||
List<GenericResourceHolder> rscs = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (emr.isGenerated) {
|
||||
rscs.add(emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscs;
|
||||
}
|
||||
|
||||
public List<GenericResourceHolder> getUserGeneratedRscs(boolean selected) {
|
||||
List<GenericResourceHolder> rscs = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated && emr.isSelected == selected) {
|
||||
rscs.add(emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscs;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rscMap
|
||||
* @param model
|
||||
* @param gr
|
||||
*/
|
||||
private void addResource2Map(
|
||||
Map<String, List<GenericResourceHolder>> rscMap, String model,
|
||||
GenericResourceHolder gr) {
|
||||
if (rscMap.containsKey(model)) {
|
||||
rscMap.get(model).add(gr);
|
||||
} else {
|
||||
List<GenericResourceHolder> rscList = new CopyOnWriteArrayList<GenericResourceHolder>();
|
||||
rscList.add(gr);
|
||||
rscMap.put(model, rscList);
|
||||
}
|
||||
}
|
||||
|
||||
private final static String TIME_BASIS_EMPTY_STR = "<no associated time>";
|
||||
|
||||
public boolean isEmpty() {
|
||||
return ensembleToolResources.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isTimeEmpty(String timeBasisLegend) {
|
||||
return (timeBasisLegend.compareTo(TIME_BASIS_EMPTY_STR) == 0);
|
||||
}
|
||||
|
||||
// Currently get the first resource loaded to get time from
|
||||
public String getTimeBasisLegendTime() {
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
// for now this is the first resource name loaded into this editor
|
||||
String timeBasisLegendTime = null;
|
||||
|
||||
if (ensembleToolResources.isEmpty()) {
|
||||
timeBasisLegendTime = TIME_BASIS_EMPTY_STR;
|
||||
} else {
|
||||
GenericResourceHolder g = ensembleToolResources.get(0);
|
||||
timeBasisLegendTime = g.getDataTime();
|
||||
}
|
||||
|
||||
return timeBasisLegendTime;
|
||||
}
|
||||
|
||||
public String getTimeBasisResourceName() {
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
// for now this is the first resource name loaded into this editor
|
||||
String timeBasisResourceName = null;
|
||||
|
||||
if (ensembleToolResources.isEmpty()) {
|
||||
timeBasisResourceName = "";
|
||||
} else {
|
||||
GenericResourceHolder g = ensembleToolResources.get(0);
|
||||
timeBasisResourceName = g.getGroupName();
|
||||
}
|
||||
|
||||
return timeBasisResourceName;
|
||||
}
|
||||
|
||||
synchronized public void setEnsembleCalculationResource(String rscGroupName) {
|
||||
calculationEnsembleName = rscGroupName;
|
||||
}
|
||||
|
||||
synchronized public String getEnsembleCalculationResource() {
|
||||
return calculationEnsembleName;
|
||||
}
|
||||
|
||||
// only update if the calculationEnsembleName is not already
|
||||
// set ... this will guarantee that only the first actual ensemble
|
||||
// resource will get set as the ensemble calculation resource.
|
||||
public void updateEnsembleCalculationResource() {
|
||||
if (calculationEnsembleName != null) {
|
||||
return;
|
||||
} else {
|
||||
Map<String, List<GenericResourceHolder>> resourceMap = getAllRscsAsMap();
|
||||
|
||||
List<GenericResourceHolder> resources = null;
|
||||
Set<String> keys = resourceMap.keySet();
|
||||
Iterator<String> keyNames = keys.iterator();
|
||||
String currKey = null;
|
||||
while (keyNames.hasNext()) {
|
||||
currKey = keyNames.next();
|
||||
resources = resourceMap.get(currKey);
|
||||
// ensemble resource found
|
||||
if (resources.size() > 1) {
|
||||
calculationEnsembleName = currKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, List<GenericResourceHolder>> getCalculationLoadedRscs(
|
||||
IDescriptor descriptor, boolean selected) {
|
||||
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(theEditor);
|
||||
|
||||
Map<String, List<GenericResourceHolder>> rscMap = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
for (GenericResourceHolder emr : ensembleToolResources) {
|
||||
if (!emr.isGenerated
|
||||
&& emr.isSelected == selected
|
||||
&& emr.getGroupName().equals(calculationEnsembleName)
|
||||
// same type descriptor like Map
|
||||
&& emr.getRsc().getDescriptor().getClass() == descriptor
|
||||
.getClass()) {
|
||||
|
||||
if (emr.getRsc().getName() == null
|
||||
|| emr.getRsc().getName().equals(""))
|
||||
continue;
|
||||
String model = emr.getModel();
|
||||
addResource2Map(rscMap, model, emr);
|
||||
}
|
||||
}
|
||||
|
||||
return rscMap;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.util.Utilities;
|
||||
|
||||
import com.raytheon.uf.common.style.level.SingleLevel;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.d2d.xy.adapters.timeseries.GridTimeSeriesAdapter;
|
||||
import com.raytheon.uf.viz.xy.timeseries.adapter.AbstractTimeSeriesAdapter;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* Concrete resolution of accessors of time series resource attributes.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class TimeSeriesResourceHolder extends GenericResourceHolder {
|
||||
|
||||
TimeSeriesResource currRsc = null;
|
||||
|
||||
protected TimeSeriesResourceHolder(AbstractVizResource<?, ?> rsc,
|
||||
boolean isSelected) {
|
||||
|
||||
super(rsc, isSelected);
|
||||
currRsc = (TimeSeriesResource) rsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
String model;
|
||||
if ((currRsc.getResourceData() == null)
|
||||
|| (currRsc.getResourceData().getSource() == null)) {
|
||||
model = "<Could not obtain model name>";
|
||||
} else {
|
||||
model = currRsc.getResourceData().getSource();
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocation() {
|
||||
|
||||
String latlon = "";
|
||||
|
||||
if ((currRsc.getResourceData() != null)
|
||||
&& (currRsc.getResourceData().getCoordinate() != null)) {
|
||||
Coordinate c = currRsc.getResourceData().getCoordinate();
|
||||
String ns = c.y >= 0 ? "N" : "S";
|
||||
String ew = c.x >= 0 ? "E" : "W";
|
||||
latlon = String.format("pt%s %d%s %d%s", currRsc.getResourceData()
|
||||
.getPointLetter(), Math.round(Math.abs(c.y)), ns, Math
|
||||
.round(Math.abs(c.x)), ew);
|
||||
}
|
||||
|
||||
return latlon;
|
||||
}
|
||||
|
||||
@Override
|
||||
// don't return a level if this is a height time series -- see
|
||||
// TimeSeriesResource::getName()
|
||||
public String getLevel() {
|
||||
|
||||
String levelKey = currRsc.getResourceData().getLevelKey();
|
||||
String levelUnit = levelKey.replaceAll("[^a-zA-Z]", "");
|
||||
boolean isHeight = levelUnit.equalsIgnoreCase("mb")
|
||||
|| levelUnit.equalsIgnoreCase("agl")
|
||||
|| levelUnit.contains("Agl");
|
||||
|
||||
if (currRsc.getAdapter() != null) {
|
||||
if (!isHeight) {
|
||||
SingleLevel level = currRsc.getAdapter().getLevel();
|
||||
levelKey = (int) level.getValue() + level.getTypeString();
|
||||
} else {
|
||||
levelKey = "";
|
||||
}
|
||||
} else {
|
||||
levelKey = "";
|
||||
}
|
||||
return levelKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnits() {
|
||||
|
||||
String units = currRsc.getUnits();
|
||||
if (units == null) {
|
||||
units = "";
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter() {
|
||||
|
||||
String p = "";
|
||||
if (currRsc.getAdapter() != null) {
|
||||
p = currRsc.getAdapter().getParameterName();
|
||||
if (p == null)
|
||||
p = "";
|
||||
if (p.compareTo("Height") == 0) {
|
||||
p = "Hgt";
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleId() {
|
||||
String ensId = "<undef perturbation>";
|
||||
|
||||
if (currRsc.getAdapter() instanceof GridTimeSeriesAdapter) {
|
||||
try {
|
||||
AbstractTimeSeriesAdapter<?> adapter = currRsc.getAdapter();
|
||||
if ((((GridTimeSeriesAdapter) adapter) != null)
|
||||
&& ((((GridTimeSeriesAdapter) adapter)
|
||||
.getArbitraryRecord()) != null)
|
||||
&& ((((GridTimeSeriesAdapter) adapter)
|
||||
.getArbitraryRecord().getInfo()) != null)) {
|
||||
|
||||
if (((GridTimeSeriesAdapter) adapter)
|
||||
.getArbitraryRecord().getInfo()
|
||||
.getEnsembleId() != null) {
|
||||
ensId = ((GridTimeSeriesAdapter) adapter)
|
||||
.getArbitraryRecord().getInfo()
|
||||
.getEnsembleId();
|
||||
} else {
|
||||
ensId = currRsc.getName();
|
||||
}
|
||||
|
||||
if ((getModel() != null)
|
||||
&& ((ensId != null) && (getModel().indexOf("SREF") >= 0))) {
|
||||
ensId = srefPerturbationPrettyfied(ensId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return ensId;
|
||||
}
|
||||
}
|
||||
|
||||
return ensId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnsembleIdRaw() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStationId() {
|
||||
String stnID = "";
|
||||
if (currRsc.getResourceData().getMetadataMap()
|
||||
.get("location.stationId") != null) {
|
||||
stnID = currRsc.getResourceData().getMetadataMap()
|
||||
.get("location.stationId").getConstraintValue();
|
||||
}
|
||||
return stnID;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
|
||||
String sb = String.format("%s %s %s %s %s", getModel(), getLevel(),
|
||||
getParameter(), getLocation(), getUnits() != null
|
||||
&& getUnits().equals("") == false ? "(" + getUnits()
|
||||
+ ")" : "");
|
||||
String nodeLabel = Utilities.removeExtraSpaces(sb);
|
||||
return nodeLabel;
|
||||
|
||||
}
|
||||
|
||||
public String getUniqueName() {
|
||||
|
||||
String sb = String
|
||||
.format("%s %s %s %s %s %s",
|
||||
getModel(),
|
||||
getLevel(),
|
||||
getParameter(),
|
||||
getLocation(),
|
||||
getUnits() != null && getUnits().equals("") == false ? "("
|
||||
+ getUnits() + ")"
|
||||
: "",
|
||||
getEnsembleId() != null
|
||||
&& getEnsembleId().equals("") == false ? getEnsembleId()
|
||||
: "");
|
||||
String nodeLabel = Utilities.removeExtraSpaces(sb);
|
||||
return nodeLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTime() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calculation getCalculation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getUniqueName().hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.common;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.GeneratedEnsembleGridResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.DisplayType;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.DensityCapability;
|
||||
import com.raytheon.viz.grid.rsc.general.AbstractGridResource;
|
||||
import com.raytheon.viz.grid.rsc.general.D2DGridResource;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Utilities for the ensemble display.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 9, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Utilities {
|
||||
|
||||
private Utilities() {
|
||||
super();
|
||||
}
|
||||
|
||||
/*
|
||||
* All ensemble resources of all ensemble model products.
|
||||
*/
|
||||
public static List<D2DGridResource> getResourcesEnsembleModels() {
|
||||
ArrayList<D2DGridResource> ensembleResources = new ArrayList<D2DGridResource>();
|
||||
|
||||
// check all resources
|
||||
IMapDescriptor desc = (IMapDescriptor) (getEditor()
|
||||
.getActiveDisplayPane().getDescriptor());
|
||||
ResourceList rscList = desc.getResourceList();
|
||||
for (ResourcePair rp : rscList) {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
continue;
|
||||
if (rsc instanceof GeneratedEnsembleGridResource)
|
||||
continue;
|
||||
if (!isResourceEnsemble((D2DGridResource) rsc))
|
||||
continue;
|
||||
|
||||
D2DGridResource ensembleResource = ((D2DGridResource) rsc);
|
||||
ensembleResources.add(ensembleResource);
|
||||
}
|
||||
|
||||
return ensembleResources;
|
||||
}
|
||||
|
||||
/*
|
||||
* All ensemble resources of one ensemble model products.
|
||||
*/
|
||||
public static List<D2DGridResource> getResourcesEnsembleModel(String model) {
|
||||
ArrayList<D2DGridResource> ensembleResources = new ArrayList<D2DGridResource>();
|
||||
|
||||
// check all resources
|
||||
IMapDescriptor desc = (IMapDescriptor) (getEditor()
|
||||
.getActiveDisplayPane().getDescriptor());
|
||||
ResourceList rscList = desc.getResourceList();
|
||||
for (ResourcePair rp : rscList) {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
continue;
|
||||
if (rsc instanceof GeneratedEnsembleGridResource)
|
||||
continue;
|
||||
if (!isResourceEnsemble((D2DGridResource) rsc))
|
||||
continue;
|
||||
if (!((D2DGridResource) rsc).getLegendParameters().model
|
||||
.equals(model))
|
||||
continue;
|
||||
D2DGridResource ensembleResource = ((D2DGridResource) rsc);
|
||||
ensembleResources.add(ensembleResource);
|
||||
|
||||
}
|
||||
return ensembleResources;
|
||||
}
|
||||
|
||||
/*
|
||||
* All resources of different models same time.
|
||||
*/
|
||||
|
||||
// get density base on the number of a ensemble products
|
||||
public static double getEnsembleDensityRsc(AbstractGridResource<?> rsc) {
|
||||
if (!isResourceEnsemble((D2DGridResource) rsc)) {
|
||||
return ((D2DGridResource) rsc).getCapability(
|
||||
DensityCapability.class).getDensity();
|
||||
}
|
||||
// this rsc belong to which products
|
||||
String model = ((D2DGridResource) rsc).getLegendParameters().model;
|
||||
|
||||
// How many member of the model
|
||||
List<String> members = Utilities.getEnsembleMembers(model);
|
||||
if (members == null)
|
||||
return ((D2DGridResource) rsc).getCapability(
|
||||
DensityCapability.class).getDensity();
|
||||
|
||||
// Which density is better, temp. table to assign densities
|
||||
double density = .33;
|
||||
if (members.size() < 10) {
|
||||
density = 2.0;
|
||||
} else if (members.size() < 20) {
|
||||
density = 1.5;
|
||||
} else if (members.size() < 40) {
|
||||
density = 1.0;
|
||||
} else if (members.size() < 60) {
|
||||
density = .75;
|
||||
} else if (members.size() < 80) {
|
||||
density = .5;
|
||||
}
|
||||
|
||||
return density;
|
||||
|
||||
}
|
||||
|
||||
// Get loaded ensemble models. This function will be used by other without
|
||||
// have a object
|
||||
public static List<String> getEnsembleModels() {
|
||||
ArrayList<String> models = new ArrayList<String>();
|
||||
|
||||
// check all resources
|
||||
IDescriptor desc = (getEditor().getActiveDisplayPane().getDescriptor());
|
||||
ResourceList rscList = desc.getResourceList();
|
||||
for (ResourcePair rp : rscList) {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
continue;
|
||||
if (rsc instanceof GeneratedEnsembleGridResource)
|
||||
continue;
|
||||
if (!isResourceEnsemble((D2DGridResource) rsc))
|
||||
continue;
|
||||
|
||||
String model = ((D2DGridResource) rsc).getLegendParameters().model;
|
||||
if (models.contains(model))
|
||||
continue;
|
||||
models.add(model);
|
||||
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
// Get ensemble members of a model. This function will be used by other
|
||||
// without have a object
|
||||
public static List<String> getEnsembleMembers(String model) {
|
||||
ArrayList<String> members = new ArrayList<String>();
|
||||
|
||||
// check all resources
|
||||
IMapDescriptor desc = (IMapDescriptor) (getEditor()
|
||||
.getActiveDisplayPane().getDescriptor());
|
||||
ResourceList rscList = desc.getResourceList();
|
||||
for (ResourcePair rp : rscList) {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
continue;
|
||||
if (rsc instanceof GeneratedEnsembleGridResource)
|
||||
continue;
|
||||
if (!isResourceEnsemble((D2DGridResource) rsc))
|
||||
continue;
|
||||
if (!((D2DGridResource) rsc).getLegendParameters().model
|
||||
.equals(model))
|
||||
continue;
|
||||
|
||||
String member = ((D2DGridResource) rsc).getLegendParameters().ensembleId;
|
||||
if (members.contains(member))
|
||||
continue;
|
||||
members.add(member);
|
||||
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
// If it is a contour ensemble resource
|
||||
public static boolean isResourceEnsemble(D2DGridResource rsc) {
|
||||
// What display type?
|
||||
// AbstractGriddedDisplay gridDisplay=
|
||||
// (AbstractGriddedDisplay) rsc.getDescriptor().getRenderableDisplay();
|
||||
if (!rsc.getDisplayType().equals(DisplayType.CONTOUR))
|
||||
return false;
|
||||
|
||||
// Is it ensemble grid? Just use the getLegendParameters().ensembleId
|
||||
// now
|
||||
// Should check on grid data records later
|
||||
if (rsc.getLegendParameters().ensembleId == null
|
||||
|| rsc.getLegendParameters().ensembleId.isEmpty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Editor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static AbstractEditor getEditor() {
|
||||
AbstractEditor editor = (AbstractEditor) EditorUtil.getActiveEditor();
|
||||
return editor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,625 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.control;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.NavigatorResourceList;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.histogram.HistogramResource;
|
||||
import gov.noaa.gsd.viz.ensemble.navigator.ui.layer.EnsembleToolManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.IDisposeListener;
|
||||
import com.raytheon.uf.viz.core.rsc.IRefreshListener;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.DensityCapability;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.grid.rsc.general.AbstractGridResource;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
//jing test
|
||||
|
||||
/**
|
||||
* Handle all ensemble products member resources, reference to any loaded grid
|
||||
* product may be treated as ensemble member, and ensemble calculation result
|
||||
* resources. This is the key architectural support class connecting the
|
||||
* ensemble display, GUI and D2D core. It tracks and the status of the handled
|
||||
* resources, controls them, keeps the ensemble tool works with D2D core display
|
||||
* synchronously. All registered resources are in the ensembleToolResourcesMap.
|
||||
*
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class EnsembleResourceManager implements IRefreshListener,
|
||||
IDisposeListener {
|
||||
private final static double DEFAULT_DENSITY = 0.15;
|
||||
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(EnsembleResourceManager.class);
|
||||
|
||||
/**
|
||||
* The ensemble marked resource list holds the loaded and generated
|
||||
* resources and flags, is used by ensemble display, GUI and calculation.
|
||||
*/
|
||||
private ConcurrentHashMap<AbstractEditor, NavigatorResourceList> ensembleToolResourcesMap;
|
||||
|
||||
/**
|
||||
* The instance of the manager, a singleton.
|
||||
*/
|
||||
public static EnsembleResourceManager instance = null;
|
||||
|
||||
/**
|
||||
* The listeners to any resource, GUI... change event Register to any bus or
|
||||
* event list for to catch interesting events
|
||||
*/
|
||||
private EnsembleResourceManager() {
|
||||
ensembleToolResourcesMap = new ConcurrentHashMap<AbstractEditor, NavigatorResourceList>();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource manager.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static EnsembleResourceManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new EnsembleResourceManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* call this, for example, at EnsembleToolManager initialization time when a
|
||||
* new tool layer is created but there are no resources yet added to it.
|
||||
*
|
||||
* @param editor
|
||||
* - The product is loaded into which editor/window.
|
||||
*/
|
||||
public void registerToolLayer(AbstractEditor editor) {
|
||||
if (ensembleToolResourcesMap.get(editor) == null) {
|
||||
ensembleToolResourcesMap.put(editor, new NavigatorResourceList(
|
||||
editor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resources in an editor.
|
||||
*
|
||||
* @param editor
|
||||
* - The product is loaded into which editor/window.
|
||||
* @return - list of resources.
|
||||
*/
|
||||
public NavigatorResourceList getResourceList(AbstractEditor editor) {
|
||||
|
||||
NavigatorResourceList list = null;
|
||||
|
||||
if (editor != null) {
|
||||
list = ensembleToolResourcesMap.get(editor);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the resources in an editor.
|
||||
*
|
||||
* @param editor
|
||||
* - The product is loaded into which editor/window.
|
||||
*/
|
||||
public void clearResourceList(AbstractEditor editor) {
|
||||
ensembleToolResourcesMap.get(editor).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a loaded model product in ensemble status
|
||||
*
|
||||
* @param rsc
|
||||
* - the loaded product resource
|
||||
* @param guiUpdate
|
||||
* - if need update GUI
|
||||
*/
|
||||
public void registerResource(AbstractVizResource<?, ?> rsc,
|
||||
AbstractEditor editor, boolean guiUpdate) {
|
||||
|
||||
if ((rsc == null) || (!isToolLayerReady()))
|
||||
return;
|
||||
|
||||
// if this is the first resource ever registered using this editor
|
||||
// then create the resource list and map it to the editor ...
|
||||
if (ensembleToolResourcesMap.get(editor) == null) {
|
||||
ensembleToolResourcesMap.put(editor, new NavigatorResourceList(
|
||||
editor));
|
||||
|
||||
if (!EnsembleToolManager.getInstance().hasToolLayer(editor)) {
|
||||
EnsembleToolManager.getInstance().addToolLayer(editor);
|
||||
}
|
||||
}
|
||||
|
||||
// no duplicates
|
||||
if (rsc == null
|
||||
|| (ensembleToolResourcesMap.get(editor).containsResource(rsc))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Must refactor so we don't use setSystemResource(boolean)
|
||||
// method.
|
||||
rsc.getProperties().setSystemResource(true);
|
||||
rsc.registerListener((IRefreshListener) this);
|
||||
rsc.registerListener((IDisposeListener) this);
|
||||
|
||||
// Set to default density for all loaded resources if can
|
||||
// But it may be unmatched with current display. Fix it later
|
||||
if (rsc.getCapability(DensityCapability.class) != null) {
|
||||
DensityCapability densityCapability = (DensityCapability) rsc
|
||||
.getCapability(DensityCapability.class);
|
||||
densityCapability.setDensity(DEFAULT_DENSITY);
|
||||
}
|
||||
|
||||
GenericResourceHolder ensToolResource = GenericResourceHolder
|
||||
.createResourceHolder(rsc, true);
|
||||
ensToolResource.setGenerated(false);
|
||||
ensembleToolResourcesMap.get(editor).add(ensToolResource);
|
||||
|
||||
syncRegisteredResource(editor);
|
||||
|
||||
if (guiUpdate) {
|
||||
notifyClientListChanged();
|
||||
// now update the calculation ensemble resource, if not already
|
||||
// set ... there can only be one, and it will be the first
|
||||
// ensemble resource loaded into this editor ...
|
||||
ensembleToolResourcesMap.get(editor)
|
||||
.updateEnsembleCalculationResource();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a resource from the tracking list.
|
||||
*
|
||||
* @param gr
|
||||
* - the tracked resource.
|
||||
* @param editor
|
||||
* - loaded editor.
|
||||
* @param notifyGUI
|
||||
* - if update the GUI.
|
||||
*/
|
||||
public void unregisterResource(GenericResourceHolder gr,
|
||||
AbstractEditor editor, boolean notifyGUI) {
|
||||
if (gr == null
|
||||
|| ensembleToolResourcesMap.get(editor).getResourceHolders()
|
||||
.isEmpty())
|
||||
return;
|
||||
ensembleToolResourcesMap.get(editor).remove(gr);
|
||||
gr.getRsc().unregisterListener((IRefreshListener) this);
|
||||
gr.getRsc().unregisterListener((IDisposeListener) this);
|
||||
|
||||
syncRegisteredResource(editor);
|
||||
|
||||
// if requested, notify client the known loaded resources have changed
|
||||
if (notifyGUI) {
|
||||
notifyClientListChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Ensemble generated resource. after creating or deleting a
|
||||
* ensemble generated resource.
|
||||
*
|
||||
* @param rsc
|
||||
* - the generated resource by calculation.
|
||||
*/
|
||||
public void registerGenerated(AbstractVizResource<?, ?> rsc,
|
||||
AbstractEditor editor) {
|
||||
|
||||
if ((rsc == null) || (!isToolLayerReady()))
|
||||
return;
|
||||
|
||||
// This may be the first resource ever registered using this editor. If
|
||||
// so, then create the resource list and associate it with the editor
|
||||
// using the map ...
|
||||
|
||||
if (ensembleToolResourcesMap.get(editor) == null) {
|
||||
ensembleToolResourcesMap.put(editor, new NavigatorResourceList(
|
||||
editor));
|
||||
|
||||
if (!EnsembleToolManager.getInstance().hasToolLayer(editor)) {
|
||||
EnsembleToolManager.getInstance().addToolLayer(editor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Only one instance of a generated resource is saved. If a duplicate is
|
||||
// created then have it overwrite the existing one.
|
||||
for (GenericResourceHolder gr : ensembleToolResourcesMap.get(editor)
|
||||
.getUserGeneratedRscs()) {
|
||||
|
||||
// Remove any resource in this list, since it was unloaded/ isn't
|
||||
// existing.
|
||||
if (!gr.getRsc().getDescriptor().getResourceList()
|
||||
.containsRsc(gr.getRsc())) {
|
||||
ensembleToolResourcesMap.get(editor).remove(gr);
|
||||
|
||||
} else if (rsc.getClass().cast(rsc).getName()
|
||||
.equals(gr.getRsc().getClass().cast(gr.getRsc()).getName())) {
|
||||
// Same generated resource name, unload old one
|
||||
ensembleToolResourcesMap.get(editor).remove(gr);
|
||||
gr.getRsc().getDescriptor().getResourceList()
|
||||
.removeRsc(gr.getRsc());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set to default density for all loaded resources if can
|
||||
// But it may be unmatched with current display. Fix it later
|
||||
|
||||
// TODO: why are we testing for this for tool layer ready yet again?
|
||||
// Set resource as a system resource so we don't show the legend
|
||||
// in the main map, because we will display it in the ensemble
|
||||
// navigator view.
|
||||
if (isToolLayerReady()) {
|
||||
// TODO: Must refactor so we don't use setSystemResource(boolean)
|
||||
// method.
|
||||
rsc.getProperties().setSystemResource(true);
|
||||
rsc.registerListener((IRefreshListener) this);
|
||||
rsc.registerListener((IDisposeListener) this);
|
||||
}
|
||||
|
||||
GenericResourceHolder ensToolResource = GenericResourceHolder
|
||||
.createResourceHolder(rsc, true);
|
||||
ensToolResource.setGenerated(true);
|
||||
ensembleToolResourcesMap.get(editor).add(ensToolResource);
|
||||
|
||||
syncRegisteredResource(editor);
|
||||
|
||||
// notify any client?
|
||||
notifyClientListChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a generated resource from the tracking list.
|
||||
*
|
||||
* @param gr
|
||||
* - the tracked resource.
|
||||
* @param editor
|
||||
* - loaded editor.
|
||||
* @param notifyGUI
|
||||
* - if update the GUI.
|
||||
*/
|
||||
public void unregisterGenerated(GenericResourceHolder gr,
|
||||
AbstractEditor editor, boolean notifyGUI) {
|
||||
if (gr == null
|
||||
|| ensembleToolResourcesMap.get(editor).getResourceHolders()
|
||||
.isEmpty())
|
||||
return;
|
||||
ensembleToolResourcesMap.get(editor).remove(gr);
|
||||
gr.getRsc().unregisterListener((IRefreshListener) this);
|
||||
gr.getRsc().unregisterListener((IDisposeListener) this);
|
||||
|
||||
// notify client the generated resource change?
|
||||
|
||||
syncRegisteredResource(editor);
|
||||
|
||||
// if requested, notify client the known loaded resources have changed
|
||||
if (notifyGUI) {
|
||||
notifyClientListChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource name string
|
||||
*
|
||||
* @param editor
|
||||
* - resource editor
|
||||
* @return- resource name
|
||||
*/
|
||||
public String getTimeBasisResourceName(AbstractEditor editor) {
|
||||
|
||||
return getResourceList(editor).getTimeBasisResourceName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource legend time
|
||||
*
|
||||
* @param editorr
|
||||
* - resource editor
|
||||
* @return- legend time
|
||||
*/
|
||||
public String getTimeBasisLegendTime(AbstractEditor editor) {
|
||||
|
||||
return getResourceList(editor).getTimeBasisLegendTime();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ENS GUI change
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
public void updateFrameChanges(AbstractEditor editor) {
|
||||
syncRegisteredResource(editor);
|
||||
|
||||
// update generated ensemble Resource if need
|
||||
updateGenerated(editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous the registered resource list within editor(s) and GUI.
|
||||
* --verify if the resources in the list are existing. --Remove any resource
|
||||
* in this list, if it was unloaded. --notify GUI if there is any change.
|
||||
*/
|
||||
public void syncRegisteredResource(AbstractEditor editor) {
|
||||
|
||||
if (ensembleToolResourcesMap.get(editor) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ensembleToolResourcesMap.get(editor).getAllRscsAsList() == null
|
||||
|| ensembleToolResourcesMap.get(editor).getAllRscsAsList()
|
||||
.isEmpty())
|
||||
return;
|
||||
|
||||
for (GenericResourceHolder gr : ensembleToolResourcesMap.get(editor)
|
||||
.getAllRscsAsList()) {
|
||||
// verify if the resources in the list are existing.
|
||||
if (!gr.getRsc().getDescriptor().getResourceList()
|
||||
.containsRsc(gr.getRsc())) {
|
||||
|
||||
// Remove any resource in this list, since it was unloaded/
|
||||
// isn't existing.
|
||||
ensembleToolResourcesMap.get(editor).remove(gr);
|
||||
|
||||
// notify GUI if there is any change.
|
||||
notifyClientListChanged();
|
||||
} else {
|
||||
// don't show legend if Tool Layer is editable
|
||||
if (isToolLayerReady()) {
|
||||
gr.getRsc().getProperties().setSystemResource(true);
|
||||
}
|
||||
|
||||
// Marks to unselected if the resource is not visible
|
||||
// set resource selection to true.
|
||||
if (gr.getRsc().getProperties().isVisible()) {
|
||||
gr.setSelected(true);
|
||||
} else {
|
||||
gr.setSelected(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * check for all ensemble interested resources if they are out of control
|
||||
* by the ensemble resource manager. Current interested resources are
|
||||
* AbstractGridResource ETimeSeriesResouece, HistogramResource
|
||||
*
|
||||
* @param editor
|
||||
* @return
|
||||
*/
|
||||
public ResourceList searchUnryncRegisteredResource(AbstractEditor editor) {
|
||||
|
||||
ResourceList unRegisteredResources = new ResourceList();
|
||||
|
||||
// The registered resources for this editor in the manager
|
||||
List<GenericResourceHolder> resourceList = ensembleToolResourcesMap
|
||||
.get(editor).getAllRscsAsList();
|
||||
|
||||
IDescriptor desc = (editor.getActiveDisplayPane().getDescriptor());
|
||||
ResourceList rscList = desc.getResourceList();
|
||||
for (ResourcePair rp : rscList) {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if ((rsc instanceof AbstractGridResource)
|
||||
|| (rsc instanceof TimeSeriesResource)
|
||||
|| (rsc instanceof HistogramResource)) {
|
||||
|
||||
boolean isRegistered = false;
|
||||
for (GenericResourceHolder rcsHolder : resourceList) {
|
||||
if (rcsHolder.getRsc() == rsc) {
|
||||
isRegistered = true;
|
||||
}
|
||||
}
|
||||
if (!isRegistered) {
|
||||
unRegisteredResources.add(rp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unRegisteredResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the ensemble GUI is reday
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isToolLayerReady() {
|
||||
return EnsembleToolManager.getInstance().isReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check generated resources update data and display if need
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
public void updateGenerated(AbstractEditor editor) {
|
||||
if (ensembleToolResourcesMap.get(editor) == null) {
|
||||
return;
|
||||
}
|
||||
if (ensembleToolResourcesMap.get(editor).getUserGeneratedRscs() == null
|
||||
|| ensembleToolResourcesMap.get(editor).getUserGeneratedRscs()
|
||||
.isEmpty())
|
||||
return;
|
||||
// Check each resource if need update
|
||||
for (GenericResourceHolder rsc : ensembleToolResourcesMap.get(editor)
|
||||
.getUserGeneratedRscs()) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* post process in this level
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
public void disposal(AbstractEditor editor) {
|
||||
clearResourceList(editor);
|
||||
saveResourceList(editor);
|
||||
|
||||
// notify client
|
||||
notifyClientListChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marked ResourceList change event should be sent to client by the event
|
||||
* bus. The client can be GUI, calculator, etc, ...
|
||||
*/
|
||||
private void notifyClientListChanged() {
|
||||
|
||||
if (isToolLayerReady()) {
|
||||
EnsembleToolManager.getInstance().refreshView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the registered resource list into a file
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
private void saveResourceList(AbstractEditor editor) {
|
||||
clearResourceList(editor);
|
||||
|
||||
// notify client
|
||||
notifyClientListChanged();
|
||||
}
|
||||
|
||||
private static long LAST_TIME = 0;
|
||||
|
||||
private final int BUNCH_REFRESH_REQUESTS_PERIOD = 500;
|
||||
|
||||
private Thread forceReset = null;
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
|
||||
// but wait for other resource pairs to catch up ...
|
||||
if (((LAST_TIME == 0) || ((System.currentTimeMillis() - LAST_TIME) > BUNCH_REFRESH_REQUESTS_PERIOD))) {
|
||||
|
||||
if (LAST_TIME == 0) {
|
||||
// TODO: wait for the resource (e.g. unit conversion) to
|
||||
// update. We probably need to look for a better solution.
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
LAST_TIME = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Register the resource in to the resource manager
|
||||
*/
|
||||
if (forceReset != null) {
|
||||
synchronized (forceReset) {
|
||||
// restart the timer for another interval to pass
|
||||
// before forcing a "final" refresh
|
||||
if (forceReset.isAlive()) {
|
||||
forceReset.interrupt();
|
||||
}
|
||||
forceReset = null;
|
||||
forceReset = new Thread(new ForceRefreshIfNecessary(
|
||||
BUNCH_REFRESH_REQUESTS_PERIOD));
|
||||
forceReset.start();
|
||||
}
|
||||
} else {
|
||||
forceReset = new Thread(new ForceRefreshIfNecessary(
|
||||
BUNCH_REFRESH_REQUESTS_PERIOD));
|
||||
forceReset.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ForceRefreshIfNecessary implements Runnable {
|
||||
|
||||
int waitForReset = 0;
|
||||
|
||||
ForceRefreshIfNecessary(int waitTime) {
|
||||
waitForReset = waitTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(waitForReset);
|
||||
notifyClientListChanged();
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* post process for other interfaces
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void disposed(AbstractVizResource<?, ?> rsc) {
|
||||
|
||||
// TODO Find editor for resource ...
|
||||
|
||||
// TODO ResourceManager.getInstance().unregisterResource(rsc);
|
||||
notifyClientListChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ensemble calculation resource name.
|
||||
*
|
||||
* @param editor
|
||||
* @param rscGroupName
|
||||
*/
|
||||
public void setEnsembleCalculationResourceName(AbstractEditor editor,
|
||||
String rscGroupName) {
|
||||
|
||||
if (ensembleToolResourcesMap.get(editor) != null) {
|
||||
ensembleToolResourcesMap.get(editor)
|
||||
.setEnsembleCalculationResource(rscGroupName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ensemble calculation resource name.
|
||||
*
|
||||
* @param editor
|
||||
* @return
|
||||
*/
|
||||
public String getEnsembleCalculationResourceName(AbstractEditor editor) {
|
||||
|
||||
String name = "";
|
||||
if (ensembleToolResourcesMap.get(editor) != null) {
|
||||
name = ensembleToolResourcesMap.get(editor)
|
||||
.getEnsembleCalculationResource();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,337 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.control;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.IRenderableDisplay;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.IInitListener;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList.AddListener;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList.RemoveListener;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.grid.rsc.general.GridResource;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
import com.raytheon.viz.ui.perspectives.IRenderableDisplayCustomizer;
|
||||
|
||||
/**
|
||||
* Notice ensemble resource manager a resource has been changed. TODO This
|
||||
* description needs to be improved once we do an improvement DR.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 9, 2014 5056 epolster jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleToolDisplayCustomizer implements
|
||||
IRenderableDisplayCustomizer {
|
||||
|
||||
/**
|
||||
* The ensemble marked resource list holds the loaded and generated
|
||||
* resources and flags, is used by ensemble display, GUI and calculation.
|
||||
*/
|
||||
static final private List<ResourcePair> batchedPairs = new CopyOnWriteArrayList<ResourcePair>();
|
||||
|
||||
/** List of listeners we have for renderable displays */
|
||||
private final List<EnsembleToolRscLoadListener> listeners = new ArrayList<EnsembleToolRscLoadListener>();
|
||||
|
||||
@Override
|
||||
public void customizeDisplay(IRenderableDisplay display) {
|
||||
|
||||
boolean add = true;
|
||||
for (EnsembleToolRscLoadListener listener : listeners) {
|
||||
if (display == listener.getDisplay()) {
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
listeners.add(new EnsembleToolRscLoadListener(display));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncustomizeDisplay(IRenderableDisplay display) {
|
||||
EnsembleToolRscLoadListener toRemove = null;
|
||||
for (EnsembleToolRscLoadListener listener : listeners) {
|
||||
if (listener.getDisplay() == display) {
|
||||
toRemove = listener;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
toRemove.dispose();
|
||||
listeners.remove(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnsembleToolRscLoadListener implements AddListener,
|
||||
RemoveListener, IInitListener {
|
||||
|
||||
// for batching purposes, keep track of the amount of time spent between
|
||||
// requests
|
||||
private static long LAST_TIME = 0;
|
||||
|
||||
// maximum wait period for batching
|
||||
private final int ALLOW_FOR_BUNCHED_REQUESTS_PERIOD = 1400;
|
||||
|
||||
// thread which acts upon batched requests
|
||||
private Thread forceReset = null;
|
||||
|
||||
// the display we are listening to
|
||||
private final IRenderableDisplay display;
|
||||
|
||||
private boolean resourcesAdded = false;
|
||||
|
||||
public EnsembleToolRscLoadListener(IRenderableDisplay display) {
|
||||
this.display = display;
|
||||
IDescriptor descriptor = display.getDescriptor();
|
||||
ResourceList list = descriptor.getResourceList();
|
||||
if (hasCompatibleResource(list)) {
|
||||
addResources(descriptor);
|
||||
}
|
||||
list.addPostAddListener(this);
|
||||
list.addPostRemoveListener(this);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
ResourceList list = display.getDescriptor().getResourceList();
|
||||
list.removePostAddListener(this);
|
||||
list.removePostRemoveListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice a resource has been removed. (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.core.rsc.ResourceList.RemoveListener#notifyRemove
|
||||
* (com.raytheon.uf.viz.core.drawables.ResourcePair) TODO: This
|
||||
* approach will be improved in an upcoming DR
|
||||
*/
|
||||
@Override
|
||||
public synchronized void notifyRemove(ResourcePair rp)
|
||||
throws VizException {
|
||||
/**
|
||||
* Pass,if the resource is not interested by ensemble tool
|
||||
*
|
||||
*/
|
||||
if (!isCompatibleResource(rp)) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Remove it from the resource manager and update GUI Should notice
|
||||
* GUI
|
||||
*/
|
||||
if (getEditor() != null) {
|
||||
EnsembleResourceManager.getInstance().syncRegisteredResource(
|
||||
getEditor());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice a resource has been added. (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.core.rsc.ResourceList.AddListener#notifyAdd(com
|
||||
* .raytheon .uf.viz.core.drawables.ResourcePair)
|
||||
*/
|
||||
@Override
|
||||
public void notifyAdd(ResourcePair rp) throws VizException {
|
||||
|
||||
/**
|
||||
* Return if the resource is not interested by ensemble tool
|
||||
*
|
||||
*/
|
||||
if (!isCompatibleResource(rp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add the resource pair to the staging list ...
|
||||
addButNoDuplicates(rp);
|
||||
|
||||
// but wait for other resource pairs to catch up ...
|
||||
if (((LAST_TIME == 0) || ((System.currentTimeMillis() - LAST_TIME) > ALLOW_FOR_BUNCHED_REQUESTS_PERIOD))) {
|
||||
|
||||
if (LAST_TIME == 0) {
|
||||
// TODO: wait for the resource (e.g. unit conversion) to
|
||||
// update. We probably need to look for a better solution.
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
LAST_TIME = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Register the resource in to the resource manager
|
||||
*/
|
||||
if (forceReset != null) {
|
||||
synchronized (forceReset) {
|
||||
// restart the timer for another interval to pass
|
||||
// before forcing a "final" refresh
|
||||
if (forceReset.isAlive()) {
|
||||
forceReset.interrupt();
|
||||
}
|
||||
forceReset = null;
|
||||
forceReset = new Thread(new ForceRefreshIfNecessary(
|
||||
ALLOW_FOR_BUNCHED_REQUESTS_PERIOD));
|
||||
forceReset.start();
|
||||
}
|
||||
} else {
|
||||
forceReset = new Thread(new ForceRefreshIfNecessary(
|
||||
ALLOW_FOR_BUNCHED_REQUESTS_PERIOD));
|
||||
forceReset.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the resource pair if it is not already in the list.
|
||||
private void addButNoDuplicates(ResourcePair rp) {
|
||||
|
||||
boolean found = false;
|
||||
for (ResourcePair orp : EnsembleToolDisplayCustomizer.batchedPairs) {
|
||||
if (orp.getResource().getName()
|
||||
.compareTo(rp.getResource().getName()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
EnsembleToolDisplayCustomizer.batchedPairs.add(rp);
|
||||
}
|
||||
}
|
||||
|
||||
private class ForceRefreshIfNecessary implements Runnable {
|
||||
|
||||
int waitForReset = 0;
|
||||
|
||||
ForceRefreshIfNecessary(int waitTime) {
|
||||
waitForReset = waitTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(waitForReset);
|
||||
|
||||
addResourceToManager(EnsembleToolDisplayCustomizer.batchedPairs);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a resource into the ensemble resource manager.
|
||||
*
|
||||
* @param resourcePairs
|
||||
*/
|
||||
private void addResourceToManager(List<ResourcePair> resourcePairs) {
|
||||
|
||||
Iterator<ResourcePair> pairsIter = resourcePairs.iterator();
|
||||
ResourcePair rp = null;
|
||||
while (pairsIter.hasNext()) {
|
||||
|
||||
rp = pairsIter.next();
|
||||
if (pairsIter.hasNext()) {
|
||||
EnsembleResourceManager.getInstance().registerResource(
|
||||
rp.getResource(), getEditor(), false);
|
||||
|
||||
} else {
|
||||
EnsembleResourceManager.getInstance().registerResource(
|
||||
rp.getResource(), getEditor(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Editor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static AbstractEditor getEditor() {
|
||||
AbstractEditor editor = (AbstractEditor) EditorUtil
|
||||
.getActiveEditor();
|
||||
return editor;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
|
||||
private boolean hasCompatibleResource(ResourceList list) {
|
||||
for (ResourcePair rp : list) {
|
||||
if (isCompatibleResource(rp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCompatibleResource(ResourcePair rp) {
|
||||
AbstractVizResource<?, ?> resource = rp.getResource();
|
||||
if (resource != null) {
|
||||
if (resource instanceof GridResource
|
||||
|| resource instanceof TimeSeriesResource) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private synchronized void addResources(IDescriptor descriptor) {
|
||||
if (!resourcesAdded) {
|
||||
ResourceList list = descriptor.getResourceList();
|
||||
list.instantiateResources(descriptor, true);
|
||||
resourcesAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.viz.core.rsc.IInitListener#inited(com.raytheon.uf
|
||||
* .viz.core.rsc.AbstractVizResource)
|
||||
*/
|
||||
@Override
|
||||
public synchronized void inited(AbstractVizResource<?, ?> rsc) {
|
||||
if (rsc instanceof GridResource) {
|
||||
if (!resourcesAdded) {
|
||||
addResources(rsc.getDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IRenderableDisplay
|
||||
*
|
||||
* @return the display
|
||||
*/
|
||||
public IRenderableDisplay getDisplay() {
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,430 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.control.load;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.TimeSeriesResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.GeneratedEnsembleGridResourceData;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.histogram.HistogramResource;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.histogram.HistogramResourceData;
|
||||
import gov.noaa.gsd.viz.ensemble.display.rsc.timeseries.GeneratedTimeSeriesResourceData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.xy.timeseries.display.TimeSeriesDescriptor;
|
||||
import com.raytheon.viz.ui.VizWorkbenchManager;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Loads the generated ensemble resource(s) into active or specified display
|
||||
* editor and panel. The resource type is dependent upon the display type. The
|
||||
* resource(s) will be registered in the Resource manager;
|
||||
*
|
||||
* @author jing
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class GeneratedDataLoader {
|
||||
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(GeneratedDataLoader.class);
|
||||
|
||||
public enum GeneratedloadMode {
|
||||
SAME_UNIT, SAME_UNIT_AND_LEVEL
|
||||
}
|
||||
|
||||
private GeneratedloadMode generatedloadMode = GeneratedloadMode.SAME_UNIT_AND_LEVEL;
|
||||
|
||||
private AbstractEditor editor = null;
|
||||
|
||||
// levels includes: Level + Parameter (e.g. 500MB)
|
||||
private List<String> levels;
|
||||
|
||||
private List<String> units;
|
||||
|
||||
public GeneratedDataLoader(AbstractEditor e, GeneratedloadMode glm) {
|
||||
generatedloadMode = glm;
|
||||
levels = new ArrayList<String>();
|
||||
units = new ArrayList<String>();
|
||||
editor = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load into current active editor and panel of Plan-View
|
||||
*
|
||||
* @param calculator
|
||||
* - the calculator of the loading overlay.
|
||||
*/
|
||||
public void loadToMapEditor(final EnsembleCalculator calculator) {
|
||||
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane().getDescriptor() instanceof IMapDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
searchLoadedResourcesMapEditor(theEditor);
|
||||
if (units.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (generatedloadMode == GeneratedloadMode.SAME_UNIT_AND_LEVEL
|
||||
&& !levels.isEmpty()) {
|
||||
|
||||
Thread t = null;
|
||||
for (final String level : levels) {
|
||||
for (final String unit : units) {
|
||||
// load to the map editor
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane()
|
||||
.getDescriptor() instanceof IMapDescriptor))
|
||||
return;
|
||||
GeneratedEnsembleGridResourceData ensembleData = new GeneratedEnsembleGridResourceData(
|
||||
calculator,
|
||||
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor(), level, unit);
|
||||
|
||||
LoadProperties loadProperties = new LoadProperties();
|
||||
|
||||
try {
|
||||
ensembleData.construct(loadProperties,
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor());
|
||||
} catch (VizException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
theEditor.refresh();
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load into current active editor and panel of Time Series
|
||||
*
|
||||
* @param calculator
|
||||
* - the calculator of the loading overlay.
|
||||
*/
|
||||
public void loadToTimeSeriesEditor(final EnsembleCalculator calculator) {
|
||||
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane().getDescriptor() instanceof TimeSeriesDescriptor))
|
||||
return;
|
||||
|
||||
searchLoadedResourcesTimeSeriesEditor(theEditor);
|
||||
|
||||
if (units.isEmpty())
|
||||
return;
|
||||
|
||||
if (generatedloadMode == GeneratedloadMode.SAME_UNIT_AND_LEVEL
|
||||
&& !levels.isEmpty()) {
|
||||
|
||||
Thread t = null;
|
||||
for (final String level : levels) {
|
||||
for (final String unit : units) {
|
||||
// load to the map editor
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
// Temp solution!!!!
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane()
|
||||
.getDescriptor() instanceof TimeSeriesDescriptor))
|
||||
return;
|
||||
GeneratedTimeSeriesResourceData ensembleData = new GeneratedTimeSeriesResourceData(
|
||||
calculator, level, unit);
|
||||
|
||||
LoadProperties loadProperties = new LoadProperties();
|
||||
|
||||
try {
|
||||
ensembleData.construct(loadProperties,
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor());
|
||||
} catch (VizException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
theEditor.refresh();
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load into current active editor and panel
|
||||
// of ...
|
||||
|
||||
/**
|
||||
* Load into editor
|
||||
*
|
||||
* @param calculator
|
||||
*/
|
||||
public void load(final EnsembleCalculator calculator) {
|
||||
if (editor.getActiveDisplayPane().getDescriptor() instanceof TimeSeriesDescriptor) {
|
||||
loadToTimeSeriesEditor(calculator);
|
||||
} else if (editor.getActiveDisplayPane().getDescriptor() instanceof IMapDescriptor) {
|
||||
loadToMapEditor(calculator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a overlay, such the histogram,,fire weather...
|
||||
*
|
||||
* @param overlay
|
||||
*/
|
||||
public void loadOverlay(final Calculation overlay) {
|
||||
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane().getDescriptor() instanceof IMapDescriptor)) {
|
||||
return;
|
||||
}
|
||||
searchLoadedResourcesMapEditor(theEditor);
|
||||
if (units.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (generatedloadMode == GeneratedloadMode.SAME_UNIT_AND_LEVEL
|
||||
&& !levels.isEmpty()) {
|
||||
|
||||
Thread t = null;
|
||||
for (final String level : levels) {
|
||||
for (final String unit : units) {
|
||||
// load to the map editor
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
AbstractEditor theEditor = (AbstractEditor) VizWorkbenchManager
|
||||
.getInstance().getActiveEditor();
|
||||
if (!(theEditor.getActiveDisplayPane()
|
||||
.getDescriptor() instanceof IMapDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (overlay == Calculation.HISTOGRAM_SAMPLING) {
|
||||
// how to pass the level and unit into the
|
||||
// HistogramResource
|
||||
HistogramResourceData resourceData = new HistogramResourceData(
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor(), level, unit,
|
||||
HistogramResource.DisplayMode.SAMPLING);
|
||||
|
||||
LoadProperties loadProperties = new LoadProperties();
|
||||
|
||||
try {
|
||||
resourceData.construct(loadProperties,
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor());
|
||||
} catch (VizException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
} else if (overlay == Calculation.HISTOGRAM_TEXT) {
|
||||
// how to pass the level and unit into the
|
||||
// HistogramResource
|
||||
HistogramResourceData resourceData = new HistogramResourceData(
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor(),
|
||||
level,
|
||||
unit,
|
||||
HistogramResource.DisplayMode.TEXT_HISTGRAM);
|
||||
|
||||
LoadProperties loadProperties = new LoadProperties();
|
||||
|
||||
try {
|
||||
resourceData.construct(loadProperties,
|
||||
theEditor.getActiveDisplayPane()
|
||||
.getDescriptor());
|
||||
} catch (VizException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
theEditor.refresh();
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load into current active panel of all editors in the main window
|
||||
*
|
||||
* @param calculator
|
||||
*/
|
||||
public void loadToMultipleEditors(EnsembleCalculator calculator) {
|
||||
// TODO
|
||||
// searchLoadedResources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load into all panels of current active editor. Each panel may with
|
||||
* different display type, such as Plan-view and Time-Series. This is for
|
||||
* supporting interactive * @param calculator
|
||||
*/
|
||||
public void loadToMultiplePanels(EnsembleCalculator calculator) {
|
||||
|
||||
// TODO
|
||||
// searchLoadedResources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the load mode of the generated resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GeneratedloadMode getGeneratedloadMode() {
|
||||
return generatedloadMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the load mode of the generated resource.
|
||||
*
|
||||
* @param generatedloadMode
|
||||
* - load mode
|
||||
*/
|
||||
public void setGeneratedloadMode(GeneratedloadMode generatedloadMode) {
|
||||
this.generatedloadMode = generatedloadMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all levels of the resources.
|
||||
*
|
||||
* @return- levels string list
|
||||
*/
|
||||
public List<String> getLevels() {
|
||||
return levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* set levels of the resources.
|
||||
*
|
||||
* @param levels
|
||||
*/
|
||||
public void setLevel(List<String> levels) {
|
||||
this.levels = levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get units of the resources.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<String> getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set units of the resources.
|
||||
*
|
||||
* @param units
|
||||
*/
|
||||
public void setUnits(List<String> units) {
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based current generated ensemble load mode, search the level and unit in
|
||||
* the loaded resource, which are used to decide the generated ensemble
|
||||
* resource(s)
|
||||
*/
|
||||
private void searchLoadedResourcesMapEditor(AbstractEditor editor) {
|
||||
levels.clear();
|
||||
units.clear();
|
||||
List<GenericResourceHolder> rscs = EnsembleResourceManager.instance
|
||||
.getResourceList(editor).getUserLoadedRscs();
|
||||
|
||||
// Search levels and units in the current loaded resource
|
||||
for (GenericResourceHolder gr : rscs) {
|
||||
|
||||
// TODO: How about resource with other descriptors?
|
||||
if (gr.getUniqueName() == null || gr.getUniqueName().equals(""))
|
||||
continue;
|
||||
|
||||
// levels.add(..)
|
||||
String level = gr.getLevel();
|
||||
if (!levels.contains(level)) {
|
||||
levels.add(level);
|
||||
}
|
||||
|
||||
// units.add(...)
|
||||
String unit = gr.getUnits();
|
||||
if (!units.contains(unit)) {
|
||||
units.add(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the levels and units in the loaded resources
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
private void searchLoadedResourcesTimeSeriesEditor(AbstractEditor editor) {
|
||||
levels.clear();
|
||||
units.clear();
|
||||
List<GenericResourceHolder> rscs = EnsembleResourceManager.instance
|
||||
.getResourceList(editor).getUserLoadedRscs();
|
||||
|
||||
// Search levels and units in the current loaded resource
|
||||
for (GenericResourceHolder gr : rscs) {
|
||||
|
||||
if (gr instanceof TimeSeriesResourceHolder) {
|
||||
|
||||
if (gr.getRsc().getName() == null || gr.getRsc().equals(""))
|
||||
continue;
|
||||
|
||||
// levels.add(..)
|
||||
String level = gr.getLevel();
|
||||
if (!levels.contains(level)) {
|
||||
levels.add(level);
|
||||
}
|
||||
|
||||
// units.add(...)
|
||||
String unit = gr.getUnits();
|
||||
if (!units.contains(unit))
|
||||
units.add(unit);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.control.multipanels;
|
||||
|
||||
import com.raytheon.uf.viz.core.IDisplayPane;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Manage ensemble display Panes. Support the multiple panel display in the
|
||||
* ensemble. For example show up the plan view and time series windows at same
|
||||
* time, select a location and update the point in the time series.
|
||||
*
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class EnsemblePanelManager {
|
||||
AbstractEditor theEditor;
|
||||
|
||||
public void load(IDisplayPane pane, AbstractVizResource<?, ?> rsc) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void unload(IDisplayPane pane, AbstractVizResource<?, ?> rsc) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void unloadAll(IDisplayPane pane, AbstractVizResource<?, ?> rsc) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void cleanPanes(IDisplayPane pane, AbstractVizResource<?, ?> rsc) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.measure.unit.Unit;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
|
||||
import com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfo;
|
||||
import com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfoLookup;
|
||||
import com.raytheon.uf.common.dataplugin.grid.util.GridLevelTranslator;
|
||||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||
import com.raytheon.uf.common.parameter.Parameter;
|
||||
import com.raytheon.uf.common.style.ParamLevelMatchCriteria;
|
||||
import com.raytheon.uf.common.style.level.Level;
|
||||
import com.raytheon.uf.common.style.level.SingleLevel;
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractNameGenerator;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.DisplayType;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.RenderingOrderFactory.ResourceOrder;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.DisplayTypeCapability;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator.IGridNameResource;
|
||||
import com.raytheon.viz.grid.rsc.GridNameGenerator.LegendParameters;
|
||||
import com.raytheon.viz.grid.rsc.GridResourceData;
|
||||
import com.raytheon.viz.grid.rsc.general.GeneralGridData;
|
||||
import com.raytheon.viz.grid.rsc.general.GridResource;
|
||||
import com.raytheon.viz.grid.xml.FieldDisplayTypesFactory;
|
||||
|
||||
/**
|
||||
* Based on the loaded ensemble product(s) data generated new resource with a
|
||||
* calculate method. Implement steps: First-Basic contour display. Second-
|
||||
* Vector-wind bar display. Third- Image display and sampling. Forth-
|
||||
* Auto-updating and other. Issue:Since extend the GridResource, how to black
|
||||
* request data from EDEX? Current solution is to override and minor change
|
||||
* related
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@SuppressWarnings({ "hiding", "rawtypes", "unchecked" })
|
||||
public class GeneratedEnsembleGridResource<GeneratedEnsembleGridResourceData>
|
||||
extends GridResource implements IGridNameResource {
|
||||
|
||||
private Parameter parameter = null;
|
||||
|
||||
private GridRecord randomRec = null;
|
||||
|
||||
private ParamLevelMatchCriteria paramLevelMatchCriteria = null;
|
||||
|
||||
private ArrayList<String> models = null;
|
||||
|
||||
private Calculation calculation = Calculation.NONE;
|
||||
|
||||
protected Random rand;
|
||||
|
||||
/**
|
||||
* Calculate method like mean
|
||||
*/
|
||||
// protected EnsembleCalculator calculator;
|
||||
|
||||
/**
|
||||
* The descriptor for plan view;
|
||||
*/
|
||||
protected IDescriptor mapDescriptor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param resourceData
|
||||
* - resource data to construct the generated grid resource.
|
||||
* @param loadProperties
|
||||
* @param calculator
|
||||
*/
|
||||
public GeneratedEnsembleGridResource(
|
||||
GeneratedEnsembleGridResourceData resourceData,
|
||||
LoadProperties loadProperties, IMapDescriptor mapDescriptor) {
|
||||
|
||||
super((GridResourceData) resourceData, loadProperties);
|
||||
this.setDescriptor(mapDescriptor);
|
||||
|
||||
// pass name generator. not works, May implement it later
|
||||
if (((AbstractResourceData) resourceData).getNameGenerator() == null) {
|
||||
((AbstractResourceData) resourceData)
|
||||
.setNameGenerator(new GridNameGenerator());
|
||||
}
|
||||
|
||||
this.getProperties().setSystemResource(true);
|
||||
|
||||
// Set color
|
||||
ColorableCapability colorable = (ColorableCapability) this
|
||||
.getCapability(ColorableCapability.class);
|
||||
rand = new Random();
|
||||
RGB color = new RGB(rand.nextInt(206) + 50, rand.nextInt(206) + 50,
|
||||
rand.nextInt(206) + 50);
|
||||
colorable.setColor(color);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param resourceData
|
||||
* - resource data to construct the generated grid resource.
|
||||
* @param loadProperties
|
||||
*/
|
||||
public GeneratedEnsembleGridResource(
|
||||
GeneratedEnsembleGridResourceData resourceData,
|
||||
LoadProperties loadProperties) {
|
||||
|
||||
super((GridResourceData) resourceData, loadProperties);
|
||||
|
||||
ColorableCapability colorable = (ColorableCapability) this
|
||||
.getCapability(ColorableCapability.class);
|
||||
RGB color = getRandomColor();
|
||||
colorable.setColor(color);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a random color
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private RGB getRandomColor() {
|
||||
|
||||
rand = new Random();
|
||||
final int lowerFilter = 80;
|
||||
final int upperFilter = 200;
|
||||
final int skewToBrightness = 256 - upperFilter;
|
||||
|
||||
int r = rand.nextInt(upperFilter);
|
||||
if (r < lowerFilter) {
|
||||
r = lowerFilter;
|
||||
}
|
||||
|
||||
int g = rand.nextInt(upperFilter);
|
||||
if (g < lowerFilter) {
|
||||
g = lowerFilter;
|
||||
}
|
||||
|
||||
int b = rand.nextInt(upperFilter);
|
||||
if (b < lowerFilter) {
|
||||
b = lowerFilter;
|
||||
}
|
||||
|
||||
r += skewToBrightness;
|
||||
g += skewToBrightness;
|
||||
b += skewToBrightness;
|
||||
|
||||
return new RGB(r, g, b);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.viz.grid.rsc.general.AbstractGridResource#initInternal(com
|
||||
* .raytheon.uf.viz.core.IGraphicsTarget)
|
||||
*/
|
||||
@Override
|
||||
protected void initInternal(IGraphicsTarget target) throws VizException {
|
||||
|
||||
// Set DisplayTypeCapability with CONTOUR IMAGE
|
||||
if (parameter != null) {
|
||||
String paramAbbrev = parameter.getAbbreviation();
|
||||
((DisplayTypeCapability) this
|
||||
.getCapability(DisplayTypeCapability.class))
|
||||
.setAlternativeDisplayTypes(FieldDisplayTypesFactory
|
||||
.getInstance().getDisplayTypes(paramAbbrev));
|
||||
}
|
||||
|
||||
super.initInternal(target);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.grid.rsc.GridNameGenerator.IGridNameResource#
|
||||
* getLegendParameters()
|
||||
*/
|
||||
@Override
|
||||
public LegendParameters getLegendParameters() {
|
||||
GridRecord record = getCurrentGridRecord();
|
||||
if (record == null) {
|
||||
record = getAnyGridRecord();
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
LegendParameters legendParams = new LegendParameters();
|
||||
DatasetInfo info = DatasetInfoLookup.getInstance().getInfo(
|
||||
record.getDatasetId());
|
||||
if (info == null) {
|
||||
legendParams.model = record.getDatasetId();
|
||||
} else {
|
||||
legendParams.model = info.getTitle();
|
||||
}
|
||||
legendParams.level = record.getLevel();
|
||||
legendParams.parameter = record.getParameter().getName();
|
||||
legendParams.ensembleId = record.getEnsembleId();
|
||||
legendParams.dataTime = descriptor.getFramesInfo().getTimeForResource(
|
||||
this);
|
||||
|
||||
if (stylePreferences != null) {
|
||||
legendParams.unit = stylePreferences.getDisplayUnitLabel();
|
||||
}
|
||||
|
||||
if (legendParams.unit == null || legendParams.unit.isEmpty()) {
|
||||
if (record.getParameter().getUnit().equals(Unit.ONE)) {
|
||||
legendParams.unit = "";
|
||||
} else {
|
||||
legendParams.unit = record.getParameter().getUnitString();
|
||||
}
|
||||
}
|
||||
List<DisplayType> displayTypes = FieldDisplayTypesFactory.getInstance()
|
||||
.getDisplayTypes(record.getParameter().getAbbreviation());
|
||||
DisplayType displayType = getDisplayType();
|
||||
if (displayTypes != null && !displayTypes.isEmpty()
|
||||
&& displayTypes.get(0).equals(displayType)) {
|
||||
// The default type does not display in the legend
|
||||
legendParams.type = "";
|
||||
} else if (displayType == DisplayType.STREAMLINE) {
|
||||
legendParams.type = "Streamlines";
|
||||
} else if (displayType == DisplayType.BARB) {
|
||||
legendParams.type = "Wind Barbs";
|
||||
} else if (displayType == DisplayType.ARROW) {
|
||||
legendParams.type = "Arrows";
|
||||
} else if (displayType == DisplayType.IMAGE) {
|
||||
legendParams.type = "Img";
|
||||
}
|
||||
return legendParams;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.grid.rsc.general.GridResource#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
if (resourceData == null) {
|
||||
return super.getName();
|
||||
}
|
||||
AbstractNameGenerator generator = resourceData.getNameGenerator();
|
||||
if (generator == null) {
|
||||
|
||||
return (int) (randomRec.getLevel().getLevelonevalue())
|
||||
+ randomRec.getLevel().getMasterLevel().getName() + " "
|
||||
+ calculation.getTitle() + " " + parameter.getName();
|
||||
|
||||
}
|
||||
return calculation.getTitle() + " " + generator.getName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a calculation display if the data is changed The real update will
|
||||
* be implemented later.
|
||||
*
|
||||
* @param dataMap
|
||||
* -The loaded member data
|
||||
*
|
||||
* TODO
|
||||
*/
|
||||
public void updateData(Map<DataTime, List<GeneralGridData>> dataMap) {
|
||||
|
||||
// Replace the data. Clear all the data and related before setting
|
||||
clearRequestedData();
|
||||
this.setData(dataMap);
|
||||
|
||||
// Set the data times
|
||||
this.dataTimes.addAll(dataMap.keySet());
|
||||
|
||||
// If there is no any ensemble member, unload this resource
|
||||
|
||||
// If any member data is changed re-calculate and update display
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<String> getModels() {
|
||||
return models;
|
||||
}
|
||||
|
||||
public void setModels(ArrayList<String> models) {
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
public Calculation getCalculation() {
|
||||
return calculation;
|
||||
}
|
||||
|
||||
public void setCalculation(Calculation calculation) {
|
||||
this.calculation = calculation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set parameter of any grid resource
|
||||
*/
|
||||
public void setParameter(GridResource rcs) {
|
||||
if (parameter != null)
|
||||
return;
|
||||
|
||||
GridRecord randomRec = rcs.getAnyGridRecord();
|
||||
|
||||
setMatchCriteria(randomRec);
|
||||
|
||||
if (randomRec != null) {
|
||||
parameter = randomRec.getParameter();
|
||||
this.randomRec = randomRec;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.grid.rsc.general.GridResource#getMatchCriteria()
|
||||
*/
|
||||
@Override
|
||||
public ParamLevelMatchCriteria getMatchCriteria() {
|
||||
return paramLevelMatchCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match criteria for generated grid displaying.
|
||||
*
|
||||
* @param record
|
||||
* - any grid record for get the parameters
|
||||
*/
|
||||
private void setMatchCriteria(GridRecord record) {
|
||||
|
||||
if (record == null) {
|
||||
return;
|
||||
}
|
||||
ParamLevelMatchCriteria matchCriteria = new ParamLevelMatchCriteria();
|
||||
matchCriteria.setParameterName(new ArrayList<String>());
|
||||
matchCriteria.setLevels(new ArrayList<Level>());
|
||||
matchCriteria.setCreatingEntityNames(new ArrayList<String>());
|
||||
String parameter = record.getParameter().getAbbreviation();
|
||||
SingleLevel level = GridLevelTranslator.constructMatching(record
|
||||
.getLevel());
|
||||
String creatingEntity = record.getDatasetId();
|
||||
if (!matchCriteria.getParameterNames().contains(parameter)) {
|
||||
matchCriteria.getParameterNames().add(parameter);
|
||||
}
|
||||
if (!matchCriteria.getLevels().contains(level)) {
|
||||
matchCriteria.getLevels().add(level);
|
||||
}
|
||||
if (!matchCriteria.getCreatingEntityNames().contains(creatingEntity)) {
|
||||
matchCriteria.getCreatingEntityNames().add(creatingEntity);
|
||||
}
|
||||
paramLevelMatchCriteria = matchCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement later(after image loading), see D2DGridResource Data
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.grid.rsc.general.AbstractGridResource#inspect(com.raytheon
|
||||
* .uf.common.geospatial.ReferencedCoordinate)
|
||||
*/
|
||||
@Override
|
||||
public String inspect(ReferencedCoordinate coord) throws VizException {
|
||||
// TODO
|
||||
return "Not implemented";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceOrder getResourceOrder() {
|
||||
return ResourceOrder.HIGHEST;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.Utilities;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.map.MapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.viz.grid.rsc.GridResourceData;
|
||||
import com.raytheon.viz.grid.rsc.general.D2DGridResource;
|
||||
import com.raytheon.viz.grid.rsc.general.GeneralGridData;
|
||||
import com.raytheon.viz.grid.rsc.general.GridResource;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Construct the GeneratedEnsembleGridResource and provide data for it by
|
||||
* calculating with member data
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class GeneratedEnsembleGridResourceData extends GridResourceData {
|
||||
private IDescriptor mapDescriptor = null;
|
||||
|
||||
/**
|
||||
* The grid resources holding the ensemble data for input to the ensemble
|
||||
* calculator The String key is the loaded model name of an ensemble
|
||||
* product, same model ran multiple times or multiple models ran same time.
|
||||
* Consider the last two case later. Need an ensemble manager to handle the
|
||||
* resources, so the loaded products can register and unregister when
|
||||
* loading and unloading. To do so, may be need extend D2DGridResource to
|
||||
* EnsembleGridResource(need EnsembleGridResourceData too) which can provide
|
||||
* more interfaces
|
||||
*
|
||||
*/
|
||||
private Map<String, List<GenericResourceHolder>> dataHolders = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
/**
|
||||
* Calculate loaded ensemble data to generate new data, such as mean.
|
||||
*/
|
||||
protected EnsembleCalculator calculator = null;
|
||||
|
||||
/**
|
||||
* Flag if frozen loaded data of members
|
||||
*/
|
||||
private boolean isFrozenData = false;
|
||||
|
||||
/**
|
||||
* Currently consider one resource case only. The multiple generated
|
||||
* resource may be created for difference level or unit. Do this later with
|
||||
* List<GeneratedEnsembleGridResource<GeneratedEnsembleGridResourceData>>
|
||||
* resources.
|
||||
*/
|
||||
protected GeneratedEnsembleGridResource<GeneratedEnsembleGridResourceData> resource = null;
|
||||
|
||||
// like "500MB", "" is not available or don't care.
|
||||
protected String level = "";
|
||||
|
||||
// Like "Height", "" is not available or don't care.
|
||||
protected String unit = "";
|
||||
|
||||
// create an empty metadata map
|
||||
protected HashMap<String, RequestConstraint> metadataMap = new HashMap<String, RequestConstraint>();
|
||||
|
||||
public GeneratedEnsembleGridResourceData() {
|
||||
super();
|
||||
|
||||
this.setMetadataMap(metadataMap);
|
||||
setRetrieveData(false);
|
||||
}
|
||||
|
||||
public GeneratedEnsembleGridResourceData(EnsembleCalculator calculator,
|
||||
IDescriptor md) {
|
||||
|
||||
super();
|
||||
this.mapDescriptor = md;
|
||||
this.calculator = calculator;
|
||||
this.setRetrieveData(false);
|
||||
// No time request in time matching
|
||||
this.setRequeryNecessaryOnTimeMatch(false);
|
||||
this.setMetadataMap(metadataMap);
|
||||
}
|
||||
|
||||
public GeneratedEnsembleGridResourceData(EnsembleCalculator calculator,
|
||||
IDescriptor md, String level, String unit) {
|
||||
|
||||
super();
|
||||
this.mapDescriptor = md;
|
||||
this.calculator = calculator;
|
||||
this.level = level;
|
||||
this.unit = unit;
|
||||
// the interface to disable the request
|
||||
this.setRetrieveData(false);
|
||||
// No time request in time matching
|
||||
this.setRequeryNecessaryOnTimeMatch(false);
|
||||
this.setMetadataMap(metadataMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the resource whatever level and unit
|
||||
*/
|
||||
@Override
|
||||
public AbstractVizResource<?, ?> construct(LoadProperties loadProperties,
|
||||
IDescriptor descriptor) throws VizException {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = null;
|
||||
|
||||
rsc = new GeneratedEnsembleGridResource<Object>(this, loadProperties);
|
||||
resource = (GeneratedEnsembleGridResource<GeneratedEnsembleGridResourceData>) rsc;
|
||||
|
||||
resource.setCalculation(calculator.getCalculation());
|
||||
|
||||
update();
|
||||
ResourceProperties rp = new ResourceProperties();
|
||||
|
||||
ResourcePair pair = new ResourcePair();
|
||||
pair.setResource(rsc);
|
||||
pair.setProperties(rp);
|
||||
descriptor.getResourceList().add(pair);
|
||||
|
||||
// TODO: Is this the correct way to associate the editor with the
|
||||
// resource?
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
EnsembleResourceManager.getInstance().registerGenerated(
|
||||
(AbstractVizResource<?, ?>) resource, editor);
|
||||
|
||||
return rsc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the dataHolders to generate the new data for ensemble display
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<DataTime, List<GeneralGridData>> calculate() {
|
||||
|
||||
// searchDataHolders();
|
||||
|
||||
// Do calculation with members of all models by looping
|
||||
Map<DataTime, List<GeneralGridData>> dataMap = new ConcurrentHashMap<DataTime, List<GeneralGridData>>();
|
||||
|
||||
// Loop calculate. This solution is re-calculating all frames.
|
||||
// The second solution is just re-calculating changed or new frames
|
||||
List<DataTime> dataTimes = getAllMemberDataTimes();
|
||||
for (DataTime time : dataTimes) {
|
||||
|
||||
List<List<GeneralGridData>> inputData = getAllData(time);
|
||||
if (inputData == null || inputData.size() < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<GeneralGridData> grids = calculator.calculate(inputData);
|
||||
if (grids == null || grids.size() < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dataMap.put(time, grids);
|
||||
|
||||
}
|
||||
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search ensemble members resources grouped by model used for test
|
||||
*/
|
||||
private void searchDataHolders() {
|
||||
// search models of ensemble
|
||||
List<String> models = Utilities.getEnsembleModels();
|
||||
if (models == null || models.size() < 1 || resource == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dataHolders.isEmpty()) {
|
||||
dataHolders.clear();
|
||||
}
|
||||
|
||||
// Add all ensemble member resources into the dataHolders
|
||||
for (String model : models) {
|
||||
List<D2DGridResource> rcsList = Utilities
|
||||
.getResourcesEnsembleModel(model);
|
||||
|
||||
if (rcsList != null) {
|
||||
|
||||
if (rcsList.size() > 0) {
|
||||
resource.setParameter(rcsList.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add loaded product(s) which are not ensemble product(s)
|
||||
// but same level and type of data(same unit) into the dataHolders
|
||||
|
||||
// We can load same model with different run time to treat it as
|
||||
// an ensemble products. Add the members in the dataHolders too.
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all member resources in the manager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<D2DGridResource> getMemberResources() {
|
||||
|
||||
// whatever level or unit in this implementation
|
||||
Set<String> keys = dataHolders.keySet();
|
||||
List<D2DGridResource> members = new ArrayList<D2DGridResource>();
|
||||
for (String key : keys) {
|
||||
List<GenericResourceHolder> rcsList = dataHolders.get(key);
|
||||
if (rcsList == null || rcsList.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rcsList.size(); i++) {
|
||||
if (rcsList.get(i).getRsc() instanceof D2DGridResource) {
|
||||
members.add((D2DGridResource) rcsList.get(i).getRsc());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Available Data Times of all members
|
||||
*/
|
||||
private List<DataTime> getAllMemberDataTimes() {
|
||||
// Test just use frame time instead real data time
|
||||
DataTime[] dataTimes = this.mapDescriptor.getFramesInfo()
|
||||
.getFrameTimes();
|
||||
|
||||
List<DataTime> times = new ArrayList<DataTime>(Arrays.asList(dataTimes));
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data set in all member of one frame. The calculation should deal with
|
||||
* issues, -In same ensemble products, different grid data number of member.
|
||||
* -Different products for same level and unit are treated as ensemble
|
||||
* members. -Should keep members in same geometry(cover biggest area) by
|
||||
* re-projecting some members. The re-projection in once only if need.
|
||||
* -Whatever time matched data of the frames, just use them for calculation.
|
||||
*/
|
||||
private List<List<GeneralGridData>> getAllData(DataTime time) {
|
||||
ArrayList<List<GeneralGridData>> allData = new ArrayList<List<GeneralGridData>>();
|
||||
List<D2DGridResource> members = getMemberResources();
|
||||
|
||||
// Get the frame index by the frame time
|
||||
DataTime[] frameTimes = this.mapDescriptor.getFramesInfo()
|
||||
.getFrameTimes();
|
||||
|
||||
if (frameTimes == null || frameTimes.length < 1) {
|
||||
return allData;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < frameTimes.length; i++)
|
||||
if (time.equals(frameTimes[i])) {
|
||||
break;
|
||||
}
|
||||
if (i >= frameTimes.length) {
|
||||
return allData;
|
||||
}
|
||||
|
||||
for (D2DGridResource member : members) {
|
||||
// Get a data time matched the frame, an option
|
||||
// DataTime[] dataTimes =member.getDataTimes();
|
||||
|
||||
// use requestData()
|
||||
// Whatever matched time in the frame, just use it for calculation.
|
||||
// User can
|
||||
// control the matching from D2D GUI
|
||||
DataTime memberTime = this.mapDescriptor.getFramesInfo()
|
||||
.getTimeForResource(member, i);
|
||||
if (memberTime == null
|
||||
|| memberTime.compareTo(frameTimes[0]) < 0
|
||||
|| memberTime.compareTo(frameTimes[frameTimes.length - 1]) > 0) {
|
||||
continue;
|
||||
}
|
||||
List<GeneralGridData> data = member.requestData(memberTime);
|
||||
if (data != null) {
|
||||
allData.add(data);
|
||||
}
|
||||
}
|
||||
return allData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable retrieve data in all members
|
||||
*/
|
||||
private void disableMembersRetrieveData() {
|
||||
if (isFrozenData()) {
|
||||
List<D2DGridResource> members = getMemberResources();
|
||||
for (D2DGridResource member : members) {
|
||||
// It doesn't work? Check out later
|
||||
member.getResourceData().setRetrieveData(false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable retrieve data in all members
|
||||
*/
|
||||
private void enableMembersRetrieveData() {
|
||||
|
||||
List<D2DGridResource> members = getMemberResources();
|
||||
for (D2DGridResource member : members) {
|
||||
member.getResourceData().setRetrieveData(true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update by checking on the loaded ensemble product resources Re-calculate
|
||||
* with the ensemble calculator to generate a new product(like mean), update
|
||||
* the dataMap in the AbstractGridResource Is it possible to update the
|
||||
* dataMap? The AbstractGridResource methods can be over written?
|
||||
* UsesetData(Map<DataTime, List<GeneralGridData>> data)
|
||||
*
|
||||
* @throws VizException
|
||||
*/
|
||||
public void update() throws VizException {
|
||||
|
||||
// TODO: Is this the correct way to associate the editor with the
|
||||
// resource?
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
|
||||
if (level != null && !level.equals("") && unit != null
|
||||
&& !unit.equals("")) {
|
||||
// Same level and unit case
|
||||
dataHolders = EnsembleResourceManager
|
||||
.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs((IDescriptor) new MapDescriptor(), true,
|
||||
level, unit);
|
||||
// dataHolders =
|
||||
// ResourceManager.getInstance().getResourceList(editor).getCalculationLoadedRscs((IDescriptor)new
|
||||
// MapDescriptor(), true);
|
||||
} else if (unit != null && !unit.equals("")) {
|
||||
// same unit whatever level case
|
||||
dataHolders = EnsembleResourceManager
|
||||
.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs((IDescriptor) new MapDescriptor(), true,
|
||||
unit);
|
||||
} else {
|
||||
// whatever level or unit,for test only
|
||||
dataHolders = EnsembleResourceManager.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs((IDescriptor) new MapDescriptor(), true);
|
||||
}
|
||||
|
||||
if (!dataHolders.isEmpty() && !dataHolders.keySet().isEmpty()) {
|
||||
disableMembersRetrieveData();
|
||||
resource.setParameter((GridResource<?>) (dataHolders.get(
|
||||
(dataHolders.keySet().toArray())[0]).get(0).getRsc()));
|
||||
resource.updateData(calculate());
|
||||
enableMembersRetrieveData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public EnsembleCalculator getCalculator() {
|
||||
return calculator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isFrozenData() {
|
||||
return isFrozenData;
|
||||
}
|
||||
|
||||
/**
|
||||
* For GUI controls data updating.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public void setFrozenData(boolean isFrozenData) {
|
||||
this.isFrozenData = isFrozenData;
|
||||
}
|
||||
|
||||
public Map<String, List<GenericResourceHolder>> getDataHolders() {
|
||||
return dataHolders;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* 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 gov.noaa.gsd.viz.ensemble.display.rsc.histogram;
|
||||
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
|
||||
import com.raytheon.viz.ui.input.InputAdapter;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* Ensemble default input handler for sampling. Is a modification of the
|
||||
* SamplingInputAdapter.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July, 2014 5056 jing Initial creation
|
||||
* </pre>
|
||||
* @param <T>
|
||||
*/
|
||||
public class EnsSamplingInputAdapter<T extends EnsSamplingResource> extends
|
||||
InputAdapter {
|
||||
|
||||
private T resource;
|
||||
|
||||
public EnsSamplingInputAdapter(T resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseMove(int x, int y) {
|
||||
IDisplayPaneContainer container = resource.getResourceContainer();
|
||||
Coordinate c = container.translateClick(x, y);
|
||||
if (c != null) {
|
||||
resource.sampleCoord = new ReferencedCoordinate(c);
|
||||
} else {
|
||||
resource.sampleCoord = null;
|
||||
}
|
||||
if (resource.isSampling()) {
|
||||
resource.issueRefresh();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseDownMove(int x, int y, int mouseButton) {
|
||||
return handleMouseMove(x, y);
|
||||
}
|
||||
|
||||
public boolean handleMouseExit(Event event) {
|
||||
resource.sampleCoord = null;
|
||||
if (resource.isSampling()) {
|
||||
resource.issueRefresh();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean handleMouseEnter(Event event) {
|
||||
return handleMouseMove(event.x, event.y);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,563 @@
|
|||
/**
|
||||
* 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 gov.noaa.gsd.viz.ensemble.display.rsc.histogram;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||
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.IDisplayPaneContainer;
|
||||
import com.raytheon.uf.viz.core.IExtent;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
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.AbstractRenderableDisplay;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.IFont;
|
||||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.IInputHandler;
|
||||
import com.raytheon.uf.viz.core.rsc.IInputHandler.InputPriority;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.RenderingOrderFactory.ResourceOrder;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability;
|
||||
import com.raytheon.uf.viz.core.sampling.ISamplingResource;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* Ensemble sampling resource, draws sample text to the screen. also picks up
|
||||
* mouse events Is a modification of the SamplingResource.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July, 2014 5056 jing Initial creation
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class EnsSamplingResource extends
|
||||
AbstractVizResource<AbstractResourceData, IDescriptor> implements
|
||||
ISamplingResource {
|
||||
protected static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(EnsSamplingResource.class);
|
||||
|
||||
/**
|
||||
* The result of a hover operation: a set of strings and corresponding
|
||||
* colors
|
||||
*
|
||||
*/
|
||||
protected static class SampleResult {
|
||||
|
||||
public SampleResult() {
|
||||
|
||||
}
|
||||
|
||||
public String[] labels;
|
||||
|
||||
public RGB[] colors;
|
||||
}
|
||||
|
||||
boolean sampling = false;
|
||||
|
||||
private IInputHandler inputAdapter = getSamplingInputHandler();
|
||||
|
||||
protected ReferencedCoordinate sampleCoord;
|
||||
|
||||
// private IFont hoverFont = null;
|
||||
protected IFont hoverFont = null;
|
||||
|
||||
private boolean errorInHovering = false;
|
||||
|
||||
private VerticalAlignment verticalAlignment = VerticalAlignment.TOP;
|
||||
|
||||
/**
|
||||
* @param resourceData
|
||||
* @param loadProperties
|
||||
*/
|
||||
// public EnsSamplingResource(GenericResourceData resourceData,
|
||||
public EnsSamplingResource(AbstractResourceData resourceData,
|
||||
LoadProperties loadProperties) {
|
||||
super(resourceData, loadProperties);
|
||||
|
||||
}
|
||||
|
||||
protected IInputHandler getSamplingInputHandler() {
|
||||
return new EnsSamplingInputAdapter<EnsSamplingResource>(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.core.rsc.AbstractVizResource#disposeInternal()
|
||||
*/
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
IDisplayPaneContainer container = getResourceContainer();
|
||||
if (container != null) {
|
||||
container.unregisterMouseHandler(inputAdapter);
|
||||
}
|
||||
|
||||
if (hoverFont != null) {
|
||||
hoverFont.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.viz.core.rsc.AbstractVizResource#initInternal(com.raytheon
|
||||
* .uf.viz.core.IGraphicsTarget)
|
||||
*/
|
||||
@Override
|
||||
protected void initInternal(IGraphicsTarget target) throws VizException {
|
||||
IDisplayPaneContainer container = getResourceContainer();
|
||||
if (container != null) {
|
||||
container.registerMouseHandler(inputAdapter,
|
||||
InputPriority.SYSTEM_RESOURCE);
|
||||
}
|
||||
hoverFont = target.initializeFont(getClass().getName());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.core.rsc.sampling.ISamplingResource#isSampling()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSampling() {
|
||||
return sampling;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.viz.core.rsc.sampling.ISamplingResource#setSampling(boolean
|
||||
* )
|
||||
*/
|
||||
@Override
|
||||
public void setSampling(boolean sampling) {
|
||||
this.sampling = sampling;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.viz.core.rsc.AbstractVizResource#paintInternal(com.raytheon
|
||||
* .uf.viz.core.IGraphicsTarget,
|
||||
* com.raytheon.uf.viz.core.drawables.PaintProperties)
|
||||
*/
|
||||
@Override
|
||||
protected void paintInternal(IGraphicsTarget target,
|
||||
PaintProperties paintProps) throws VizException {
|
||||
if (sampleCoord == null || isSampling() == false
|
||||
|| !(EnsembleResourceManager.getInstance().isToolLayerReady())) {
|
||||
return;
|
||||
}
|
||||
|
||||
hoverFont.setMagnification(getCapability(MagnificationCapability.class)
|
||||
.getMagnification().floatValue());
|
||||
SampleResult result = doHover(sampleCoord, descriptor.getResourceList());
|
||||
paintResult(target, paintProps, sampleCoord, result);
|
||||
}
|
||||
|
||||
protected SampleResult doHover(ReferencedCoordinate coord,
|
||||
ResourceList resources) throws VizException {
|
||||
SampleResult result = new SampleResult();
|
||||
List<String> labelList = new ArrayList<String>();
|
||||
List<RGB> colorList = new ArrayList<RGB>();
|
||||
try {
|
||||
int size = resources.size();
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
ResourcePair rp = resources.get(i);
|
||||
String retVal = recursiveHoverSearch(rp, coord);
|
||||
if (retVal != null && retVal.length() > 0) {
|
||||
RGB color = null;
|
||||
if (rp.getResource().hasCapability(
|
||||
ColorableCapability.class)) {
|
||||
color = rp.getResource()
|
||||
.getCapability(ColorableCapability.class)
|
||||
.getColor();
|
||||
}
|
||||
int p1, p2;
|
||||
p1 = 0;
|
||||
while ((p2 = retVal.indexOf('\n', p1)) >= 0) {
|
||||
colorList.add(color);
|
||||
labelList.add(retVal.substring(p1, p2));
|
||||
p1 = p2 + 1;
|
||||
}
|
||||
String s = retVal.substring(p1);
|
||||
if (s.length() > 0) {
|
||||
colorList.add(color);
|
||||
labelList.add(retVal.substring(p1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
statusHandler.handle(Priority.PROBLEM, "Error sampling resources: "
|
||||
+ t.getLocalizedMessage(), t);
|
||||
}
|
||||
|
||||
result.labels = labelList.toArray(new String[labelList.size()]);
|
||||
result.colors = colorList.toArray(new RGB[colorList.size()]);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String recursiveHoverSearch(ResourcePair rp,
|
||||
ReferencedCoordinate coordinate) throws VizException {
|
||||
ResourceProperties props = rp.getProperties();
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
|
||||
if (rsc != null && rsc.getStatus() == ResourceStatus.INITIALIZED
|
||||
&& props.isVisible()) {
|
||||
String curVal = rsc.inspect(coordinate);
|
||||
|
||||
if (curVal != null && curVal.length() > 0) {
|
||||
return curVal;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void paintResult(IGraphicsTarget target,
|
||||
PaintProperties paintProps, ReferencedCoordinate coord,
|
||||
SampleResult result) throws VizException {
|
||||
verticalAlignment = VerticalAlignment.TOP;
|
||||
target.clearClippingPlane();
|
||||
try {
|
||||
if (result != null) {
|
||||
double[] world = new double[] { coord.getObject().x,
|
||||
coord.getObject().y };
|
||||
double[] pixel = descriptor.worldToPixel(world);
|
||||
Coordinate c = new Coordinate(pixel[0], pixel[1]);
|
||||
int canvasWidth = paintProps.getCanvasBounds().width;
|
||||
double extentWidth = paintProps.getView().getExtent()
|
||||
.getWidth();
|
||||
double ratioX = canvasWidth / extentWidth;
|
||||
|
||||
if (result.labels.length > 0) {
|
||||
List<String[]> strsToUse = new ArrayList<String[]>();
|
||||
List<RGB> colorsToUse = new ArrayList<RGB>();
|
||||
HorizontalAlignment[] alignments = new HorizontalAlignment[result.labels.length];
|
||||
boolean[] modified = new boolean[result.labels.length];
|
||||
for (int i = 0; i < modified.length; ++i) {
|
||||
modified[i] = false;
|
||||
alignments[i] = HorizontalAlignment.LEFT;
|
||||
String[] tmp = new String[] { result.labels[i],
|
||||
result.labels[i] };
|
||||
strsToUse.add(tmp);
|
||||
}
|
||||
|
||||
adjustStrings(target, paintProps, strsToUse, modified,
|
||||
alignments, c, ratioX, null);
|
||||
|
||||
HorizontalAlignment horizontalAlignment = alignments[0];
|
||||
boolean good = true;
|
||||
for (int i = 1; i < alignments.length && good; ++i) {
|
||||
if (horizontalAlignment != alignments[i]) {
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
// not all the same, figure out alignments!!!
|
||||
int maxLen = 0;
|
||||
int i = 0;
|
||||
for (String[] s : strsToUse) {
|
||||
if (s[0].length() > maxLen) {
|
||||
maxLen = s[0].length();
|
||||
horizontalAlignment = alignments[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
adjustStrings(target, paintProps, strsToUse, modified,
|
||||
alignments, c, ratioX, horizontalAlignment);
|
||||
}
|
||||
|
||||
List<String> actualStrs = new ArrayList<String>();
|
||||
for (int i = 0; i < strsToUse.size(); ++i) {
|
||||
String[] strs = strsToUse.get(i);
|
||||
for (int j = 1; j < strs.length; ++j) {
|
||||
actualStrs.add(strs[j]);
|
||||
colorsToUse.add(result.colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
String[] newStrs = actualStrs.toArray(new String[actualStrs
|
||||
.size()]);
|
||||
|
||||
double referencePtY = adjustLabelWrapY(
|
||||
target,
|
||||
newStrs,
|
||||
c.y
|
||||
+ ((AbstractRenderableDisplay.CURSOR_HEIGHT) / ratioX),
|
||||
paintProps.getView().getExtent(), ratioX);
|
||||
|
||||
if (horizontalAlignment == HorizontalAlignment.RIGHT) {
|
||||
c.x -= (target.getStringBounds(hoverFont, newStrs,
|
||||
TextStyle.BLANKED).getWidth() / ratioX);
|
||||
}
|
||||
|
||||
target.drawStrings(hoverFont, newStrs, c.x, referencePtY,
|
||||
0.0, IGraphicsTarget.TextStyle.BLANKED,
|
||||
colorsToUse.toArray(new RGB[colorsToUse.size()]),
|
||||
HorizontalAlignment.LEFT, verticalAlignment);
|
||||
}
|
||||
}
|
||||
errorInHovering = false;
|
||||
} catch (Exception e) {
|
||||
if (errorInHovering) {
|
||||
// Keep down the number of error messages
|
||||
statusHandler.handle(
|
||||
Priority.PROBLEM,
|
||||
"Error painting sample text: "
|
||||
+ e.getLocalizedMessage(), e);
|
||||
}
|
||||
errorInHovering = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustStrings(IGraphicsTarget target,
|
||||
PaintProperties paintProps, List<String[]> strsToUse,
|
||||
boolean[] modified, HorizontalAlignment[] alignments, Coordinate c,
|
||||
double ratio, HorizontalAlignment targetAlignment) {
|
||||
|
||||
List<String[]> strsToUseInternal = new ArrayList<String[]>();
|
||||
|
||||
for (int i = 0; i < strsToUse.size(); ++i) {
|
||||
String str = strsToUse.get(i)[0];
|
||||
String[] split = str.split("[ ]");
|
||||
boolean done = false;
|
||||
|
||||
if ((strsToUse.get(i) == null) || (strsToUse.get(i).length == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int divideBy = strsToUse.get(i).length - 1;
|
||||
int maxDivisions = 0;
|
||||
for (int j = 0; j < split.length; ++j) {
|
||||
if (split[j].isEmpty() == false) {
|
||||
++maxDivisions;
|
||||
}
|
||||
}
|
||||
|
||||
if (alignments[i] == targetAlignment) {
|
||||
strsToUseInternal.add(strsToUse.get(i));
|
||||
} else {
|
||||
String[] test = new String[] { str };
|
||||
while (!done) {
|
||||
if (divideBy > maxDivisions
|
||||
|| alignments[i] == targetAlignment) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
int approxLenPerStr = str.length() / divideBy;
|
||||
List<String> strs = new ArrayList<String>();
|
||||
|
||||
for (int j = 0; j < split.length;) {
|
||||
String line = split[j++];
|
||||
while (j < split.length) {
|
||||
String s = split[j];
|
||||
if (s.length() + line.length() <= approxLenPerStr) {
|
||||
if (!s.isEmpty()) {
|
||||
if (j == split.length - 1
|
||||
&& split[1].equalsIgnoreCase("=")) {
|
||||
line = split[split.length - 1];
|
||||
} else {
|
||||
line += " " + s;
|
||||
}
|
||||
} else {
|
||||
line += " ";
|
||||
}
|
||||
++j;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
strs.add(line);
|
||||
}
|
||||
|
||||
test = strs.toArray(new String[strs.size()]);
|
||||
|
||||
HorizontalAlignment alignment = adjustLabelWrapX(target,
|
||||
test, c.x, paintProps.getView().getExtent(), ratio,
|
||||
alignments[i]);
|
||||
if (alignment == alignments[i]
|
||||
&& (targetAlignment == null || alignment == targetAlignment)) {
|
||||
// the alignment was not changed and we are the target
|
||||
// alignment, we are done
|
||||
done = true;
|
||||
} else {
|
||||
if (targetAlignment == null) {
|
||||
// alignment changed, check to see if it changes
|
||||
// back
|
||||
HorizontalAlignment tmpAlignment = alignment;
|
||||
alignment = adjustLabelWrapX(target, test, c.x,
|
||||
paintProps.getView().getExtent(), ratio,
|
||||
alignment);
|
||||
if (alignment != tmpAlignment) {
|
||||
// we moved back, we need to divide and
|
||||
// conquer
|
||||
alignments[i] = HorizontalAlignment.LEFT;
|
||||
modified[i] = true;
|
||||
divideBy++;
|
||||
} else {
|
||||
// we are good at this alignment
|
||||
alignments[i] = alignment;
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
// we need to be the targetAlignment
|
||||
alignment = adjustLabelWrapX(target, test, c.x,
|
||||
paintProps.getView().getExtent(), ratio,
|
||||
targetAlignment);
|
||||
if (alignment == targetAlignment) {
|
||||
// we are fine at other alignment also, use it:
|
||||
alignments[i] = alignment;
|
||||
done = true;
|
||||
} else {
|
||||
alignments[i] = targetAlignment;
|
||||
modified[i] = true;
|
||||
divideBy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String[] addTo = new String[test.length + 1];
|
||||
addTo[0] = str;
|
||||
for (int j = 0; j < test.length; ++j) {
|
||||
addTo[j + 1] = test[j];
|
||||
}
|
||||
|
||||
strsToUseInternal.add(addTo);
|
||||
}
|
||||
}
|
||||
strsToUse.clear();
|
||||
strsToUse.addAll(strsToUseInternal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the x label if the width of the longest label extends the extent
|
||||
*
|
||||
* @param target
|
||||
* @param labels
|
||||
* @param x
|
||||
* @param extent
|
||||
* @param ratio
|
||||
* @return
|
||||
*/
|
||||
private HorizontalAlignment adjustLabelWrapX(IGraphicsTarget target,
|
||||
String[] labels, double x, IExtent extent, double ratio,
|
||||
HorizontalAlignment horizontalAlignment) {
|
||||
double referencePoint = x;
|
||||
|
||||
// Find the max width of the label in pixels
|
||||
double maxWidth = 0;
|
||||
IFont font = hoverFont;
|
||||
for (String label : labels) {
|
||||
Rectangle2D bounds = target.getStringBounds(font, label);
|
||||
if (bounds.getWidth() > maxWidth) {
|
||||
maxWidth = bounds.getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the width in gl space
|
||||
double widthInGl = maxWidth / ratio;
|
||||
|
||||
if (horizontalAlignment == HorizontalAlignment.LEFT) {
|
||||
// Check to see if text extends screen extent
|
||||
if (referencePoint + widthInGl > extent.getMaxX()) {
|
||||
horizontalAlignment = HorizontalAlignment.RIGHT;
|
||||
}
|
||||
} else {
|
||||
// Check to see if text extends screen extent
|
||||
if (referencePoint - widthInGl < extent.getMinX()) {
|
||||
horizontalAlignment = HorizontalAlignment.LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
return horizontalAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the y label position if the stacked labels exceeds the screen
|
||||
* extent height
|
||||
*
|
||||
* @param target
|
||||
* @param labels
|
||||
* @param y
|
||||
* @param extent
|
||||
* @param ratio
|
||||
* @return
|
||||
*/
|
||||
private double adjustLabelWrapY(IGraphicsTarget target, String[] labels,
|
||||
double y, IExtent extent, double ratio) {
|
||||
double referencePoint = y;
|
||||
|
||||
double totalHeight = target.getStringBounds(hoverFont, labels,
|
||||
TextStyle.BLANKED).getHeight();
|
||||
|
||||
// convert to gl space
|
||||
double maxHeightInGl = (totalHeight) / ratio;
|
||||
|
||||
// check to see if height extends map height
|
||||
if (referencePoint + maxHeightInGl > extent.getMaxY()) {
|
||||
verticalAlignment = VerticalAlignment.BOTTOM;
|
||||
referencePoint -= (AbstractRenderableDisplay.CURSOR_HEIGHT + 2)
|
||||
/ ratio;
|
||||
}
|
||||
|
||||
// return adjusted point
|
||||
return referencePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceOrder getResourceOrder() {
|
||||
return ResourceOrder.HIGHEST;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,604 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc.histogram;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.raytheon.uf.viz.core.IDisplayPane;
|
||||
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.IInputHandler;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.BlendableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability;
|
||||
import com.raytheon.viz.grid.rsc.general.AbstractGridResource;
|
||||
import com.raytheon.viz.grid.rsc.general.D2DGridResource;
|
||||
import com.raytheon.viz.ui.editor.IMultiPaneEditor;
|
||||
import com.raytheon.viz.ui.input.preferences.MousePreferenceManager;
|
||||
|
||||
/**
|
||||
* D2D ensemble sampling resources, supports all pane sampling and long left
|
||||
* click sampling as well Implement steps: 1, ensemble text values
|
||||
* sampling--done 100% 2, Text histogram/ color Text histogram--done 90% 3,
|
||||
* Graphics histogram/distribution view 4, interactive graphics histogram.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class HistogramResource<HistogramResoureData> extends
|
||||
EnsSamplingResource {
|
||||
|
||||
public enum DisplayMode {
|
||||
SAMPLING, TEXT_HISTGRAM, COLOR_TEXT_HISTGRAM, GRAPHIC_HISTGRAM
|
||||
}
|
||||
|
||||
// Level+name:500MB
|
||||
private String level;
|
||||
|
||||
private String unit;
|
||||
|
||||
protected Random rand;
|
||||
|
||||
protected DisplayMode mode;
|
||||
|
||||
public DisplayMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param histogramResourceData
|
||||
* @param loadProperties
|
||||
*/
|
||||
public HistogramResource(HistogramResourceData histogramResourceData,
|
||||
LoadProperties loadProperties, IDescriptor descriptor,
|
||||
String level, String unit, DisplayMode mode) {
|
||||
super(histogramResourceData, loadProperties);
|
||||
this.level = level;
|
||||
this.unit = unit;
|
||||
this.mode = mode;
|
||||
this.setSampling(true);
|
||||
this.setDescriptor(descriptor);
|
||||
|
||||
ColorableCapability colorable = this
|
||||
.getCapability(ColorableCapability.class);
|
||||
rand = new Random();
|
||||
RGB color = new RGB(rand.nextInt(206) + 50, rand.nextInt(206) + 50,
|
||||
rand.nextInt(206) + 50);
|
||||
colorable.setColor(color);
|
||||
}
|
||||
|
||||
private class D2DMouseAdapter extends
|
||||
EnsSamplingInputAdapter<HistogramResource<?>> {
|
||||
|
||||
// private static final String INSPECT_PREF =
|
||||
// "com.raytheon.viz.ui.input.inspect";
|
||||
private static final String INSPECT_PREF_HIST = "com.raytheon.viz.ui.input.inspect.hist";
|
||||
|
||||
protected Job job;
|
||||
|
||||
protected long timeUp;
|
||||
|
||||
private MousePreferenceManager prefManager = MousePreferenceManager
|
||||
.getInstance();
|
||||
|
||||
private boolean inspectForced = false;
|
||||
|
||||
D2DMouseAdapter() {
|
||||
super(HistogramResource.this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.ui.input.IInputHandler#handleMouseDown(int,
|
||||
* int, int)
|
||||
*/
|
||||
@Override
|
||||
public boolean handleMouseDown(int x, int y, int mouseButton) {
|
||||
super.handleMouseDown(x, y, mouseButton);
|
||||
if (prefManager.handleClick(INSPECT_PREF_HIST, mouseButton)
|
||||
&& isSampling() == false) {
|
||||
inspectForced = true;
|
||||
setSampling(true);
|
||||
issueRefresh();
|
||||
return false;
|
||||
} else if (prefManager.handleLongClick(INSPECT_PREF_HIST,
|
||||
mouseButton) && isSampling() == false) {
|
||||
timeUp = 0L;
|
||||
if (job == null) {
|
||||
job = new Job("InspectAdapter") {
|
||||
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
if (timeUp == 0L) {
|
||||
inspectForced = true;
|
||||
setSampling(true);
|
||||
issueRefresh();
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
if (job.getState() != Job.RUNNING) {
|
||||
job.schedule(500);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.viz.ui.input.IInputHandler#handleMouseUp(int, int,
|
||||
* int)
|
||||
*/
|
||||
@Override
|
||||
public boolean handleMouseUp(int x, int y, int mouseButton) {
|
||||
super.handleMouseUp(x, y, mouseButton);
|
||||
if (prefManager.handleLongClick(INSPECT_PREF_HIST, mouseButton)) {
|
||||
timeUp = System.currentTimeMillis();
|
||||
}
|
||||
if (inspectForced) {
|
||||
inspectForced = false;
|
||||
setSampling(false);
|
||||
issueRefresh();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean allPanelSampling = false;
|
||||
|
||||
@Override
|
||||
protected IInputHandler getSamplingInputHandler() {
|
||||
return new D2DMouseAdapter();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.d2d.core.sampling.ID2DSamplingResource#
|
||||
* setAllPanelSampling(boolean)
|
||||
*/
|
||||
// @Override
|
||||
public void setAllPanelSampling(boolean allPanelSampling) {
|
||||
this.allPanelSampling = allPanelSampling;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.viz.d2d.core.sampling.ID2DSamplingResource#isAllPanelSampling
|
||||
* ()
|
||||
*/
|
||||
// @Override
|
||||
public boolean isAllPanelSampling() {
|
||||
IDisplayPaneContainer container = getResourceContainer();
|
||||
if (container instanceof IMultiPaneEditor) {
|
||||
// Only all panel sample if we have 1 displayed pane count
|
||||
return (allPanelSampling & (((IMultiPaneEditor) container)
|
||||
.displayedPaneCount() == 1));
|
||||
}
|
||||
return allPanelSampling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate sample histogram text/graphic with grid resources
|
||||
*/
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* gov.noaa.gsd.viz.ensemble.display.rsc.histogram.EnsSamplingResource#doHover
|
||||
* (com.raytheon.uf.common.geospatial.ReferencedCoordinate,
|
||||
* com.raytheon.uf.viz.core.rsc.ResourceList)
|
||||
*/
|
||||
@Override
|
||||
protected SampleResult doHover(ReferencedCoordinate coord,
|
||||
ResourceList resources) throws VizException {
|
||||
SampleResult result = new SampleResult();
|
||||
if (this.mode == DisplayMode.SAMPLING) {
|
||||
result = doHoverSampling(coord, resources);
|
||||
} else if (this.mode == DisplayMode.TEXT_HISTGRAM) {
|
||||
result = doHoverText(coord, resources);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sampling lables and colors of current location
|
||||
*
|
||||
* @param coord
|
||||
* - current location
|
||||
* @param resources
|
||||
* - member resources of the caculations
|
||||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
protected SampleResult doHoverSampling(ReferencedCoordinate coord,
|
||||
ResourceList resources) throws VizException {
|
||||
SampleResult result = new SampleResult();
|
||||
|
||||
List<String> labelList = new ArrayList<String>();
|
||||
List<RGB> colorList = new ArrayList<RGB>();
|
||||
// List<>
|
||||
try {
|
||||
int size = resources.size();
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
ResourcePair rp = resources.get(i);
|
||||
String retVal = recursiveHoverSearchSampling(rp, coord);
|
||||
if (retVal != null && retVal.length() > 0) {
|
||||
RGB color = null;
|
||||
if (rp.getResource().hasCapability(
|
||||
ColorableCapability.class)) {
|
||||
color = rp.getResource()
|
||||
.getCapability(ColorableCapability.class)
|
||||
.getColor();
|
||||
}
|
||||
int p1, p2;
|
||||
p1 = 0;
|
||||
while ((p2 = retVal.indexOf('\n', p1)) >= 0) {
|
||||
colorList.add(color);
|
||||
labelList.add(retVal.substring(p1, p2));
|
||||
p1 = p2 + 1;
|
||||
}
|
||||
String s = retVal.substring(p1);
|
||||
if (s.length() > 0) {
|
||||
colorList.add(color);
|
||||
labelList.add(retVal.substring(p1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
statusHandler.handle(Priority.PROBLEM, "Error sampling resources: "
|
||||
+ t.getLocalizedMessage(), t);
|
||||
}
|
||||
|
||||
result.labels = labelList.toArray(new String[labelList.size()]);
|
||||
result.colors = colorList.toArray(new RGB[colorList.size()]);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sampling label for one resource.
|
||||
*
|
||||
* @param rp
|
||||
* - one resource pair
|
||||
* @param coordinate
|
||||
* - current location
|
||||
* @return - lable string
|
||||
* @throws VizException
|
||||
*/
|
||||
private String recursiveHoverSearchSampling(ResourcePair rp,
|
||||
ReferencedCoordinate coordinate) throws VizException {
|
||||
ResourceProperties props = rp.getProperties();
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
return null;
|
||||
|
||||
if (rsc != null && rsc.getStatus() == ResourceStatus.INITIALIZED
|
||||
&& props.isVisible()) {
|
||||
String curVal = null;
|
||||
Map<String, Object> result = rsc.interrogate(coordinate);
|
||||
|
||||
if (result == null || result.isEmpty())
|
||||
return null;
|
||||
|
||||
Set<String> keys = result.keySet();
|
||||
if (keys == null || keys.isEmpty())
|
||||
return null;
|
||||
|
||||
for (String key : keys) {
|
||||
if (key.contains("unit"))
|
||||
continue;
|
||||
if (curVal != null) {
|
||||
// curVal = curVal + "/"+key+ ":"+ String.format("%.2f",
|
||||
// result.get(key));
|
||||
curVal = curVal + "/"
|
||||
+ String.format("%.2f", result.get(key));
|
||||
} else {
|
||||
// curVal = key+ ":"+ String.format("%.2f",
|
||||
// result.get(key));
|
||||
|
||||
curVal = String.format("%.2f", result.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (curVal != null && curVal.length() > 0) {
|
||||
return curVal;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text histogram display by sampling each member resource and creating a
|
||||
* histogram text.
|
||||
*
|
||||
* @param coord
|
||||
* @param resources
|
||||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
protected SampleResult doHoverText(ReferencedCoordinate coord,
|
||||
ResourceList resources) throws VizException {
|
||||
SampleResult result = new SampleResult();
|
||||
|
||||
List<String> labelList = new ArrayList<String>();
|
||||
// List<RGB> colorList = new ArrayList<RGB>();
|
||||
List<Float> values = new ArrayList<Float>();
|
||||
List<AbstractVizResource<?, ?>> rscs = new ArrayList<AbstractVizResource<?, ?>>();
|
||||
|
||||
try {
|
||||
int size = resources.size();
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
ResourcePair rp = resources.get(i);
|
||||
float retVal = recursiveHoverSearchText(rp, coord);
|
||||
if (retVal != Float.NaN) {
|
||||
values.add(retVal);
|
||||
rscs.add(rp.getResource());
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
statusHandler.handle(Priority.PROBLEM, "Error sampling resources: "
|
||||
+ t.getLocalizedMessage(), t);
|
||||
}
|
||||
|
||||
TextHistogram textHistogram = new TextHistogram(false);
|
||||
labelList = textHistogram.interrogate(rscs, values, unit);
|
||||
result.labels = labelList.toArray(new String[labelList.size()]);
|
||||
|
||||
RGB color = this.getCapability(ColorableCapability.class).getColor();
|
||||
RGB[] colorList = new RGB[labelList.size()];
|
||||
for (int j = 0; j < colorList.length; j++)
|
||||
colorList[j] = color;
|
||||
result.colors = colorList;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searxh sampling data for text histogram in one resource pair
|
||||
*
|
||||
* @param rp
|
||||
* @param coordinate
|
||||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
private float recursiveHoverSearchText(ResourcePair rp,
|
||||
ReferencedCoordinate coordinate) throws VizException {
|
||||
ResourceProperties props = rp.getProperties();
|
||||
AbstractVizResource<?, ?> rsc = rp.getResource();
|
||||
if (!(rsc instanceof AbstractGridResource))
|
||||
return Float.NaN;
|
||||
|
||||
float curVal = Float.NaN;
|
||||
if (rsc != null && rsc.getStatus() == ResourceStatus.INITIALIZED
|
||||
&& props.isVisible()) {
|
||||
|
||||
Map<String, Object> result = rsc.interrogate(coordinate);
|
||||
|
||||
if (result == null || result.isEmpty())
|
||||
return Float.NaN;
|
||||
|
||||
Set<String> keys = result.keySet();
|
||||
if (keys == null || keys.isEmpty())
|
||||
return Float.NaN;
|
||||
|
||||
for (String key : keys) {
|
||||
if (key.contains("unit")) {
|
||||
this.unit = result.get(key).toString();
|
||||
} else if (key.contains("value")) {
|
||||
curVal = Float.parseFloat(result.get(key).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return curVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any resource not existing in the resource manager.
|
||||
*
|
||||
* @param resources
|
||||
* @return
|
||||
*/
|
||||
private ResourceList filterResource(ResourceList resources) {
|
||||
ResourceList filteredlist = new ResourceList();
|
||||
|
||||
try {
|
||||
((HistogramResourceData) getResourceData()).update();
|
||||
} catch (VizException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
List<D2DGridResource> matchRscs = ((HistogramResourceData) getResourceData())
|
||||
.getAllMembersResources();
|
||||
|
||||
int size = resources.size();
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
ResourcePair rp = resources.get(i);
|
||||
if (matchRscs.contains(rp.getResource()))
|
||||
filteredlist.add(rp);
|
||||
}
|
||||
|
||||
return filteredlist;
|
||||
}
|
||||
|
||||
public void setLevelUnit(String level, String unit) {
|
||||
this.level = level;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (mode == DisplayMode.SAMPLING)
|
||||
return level + " " + unit + " Ensemble Sampling";
|
||||
else
|
||||
return level + " " + unit + " Histogram Text";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see gov.noaa.gsd.viz.ensemble.display.rsc.histogram.EnsSamplingResource#
|
||||
* paintInternal(com.raytheon.uf.viz.core.IGraphicsTarget,
|
||||
* com.raytheon.uf.viz.core.drawables.PaintProperties)
|
||||
*/
|
||||
@Override
|
||||
protected void paintInternal(IGraphicsTarget target,
|
||||
PaintProperties paintProps) throws VizException {
|
||||
|
||||
if (sampleCoord == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAllPanelSampling() == false) {
|
||||
|
||||
hoverFont.setMagnification(getCapability(
|
||||
MagnificationCapability.class).getMagnification()
|
||||
.floatValue());
|
||||
SampleResult result = doHover(sampleCoord,
|
||||
filterResource(descriptor.getResourceList()));
|
||||
paintResult(target, paintProps, sampleCoord, result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSampling() == false) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IDisplayPaneContainer container = getResourceContainer();
|
||||
if (container == null) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceList rList = new ResourceList();
|
||||
|
||||
List<ResourceList> blendedLists = new ArrayList<ResourceList>();
|
||||
|
||||
List<ResourcePair> invisibleList = new ArrayList<ResourcePair>();
|
||||
|
||||
IDisplayPane[] panes = container.getDisplayPanes();
|
||||
if (panes.length == 4) {
|
||||
// Awips1 puts four panels in the wrong order.
|
||||
panes = new IDisplayPane[] { panes[0], panes[1], panes[3], panes[2] };
|
||||
}
|
||||
|
||||
for (IDisplayPane pane : panes) {
|
||||
ResourceList rscList = filterResource(pane.getDescriptor()
|
||||
.getResourceList());
|
||||
for (ResourcePair pair : rscList) {
|
||||
if (pair.getResource() == null
|
||||
|| !pair.getProperties().isVisible()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pair.getResource()
|
||||
.hasCapability(BlendableCapability.class)) {
|
||||
rList.add(pair);
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceList list = pair.getResource()
|
||||
.getCapability(BlendableCapability.class)
|
||||
.getResourceList();
|
||||
ResourcePair rp = list.get(0);
|
||||
if (!rp.getProperties().isVisible()) {
|
||||
invisibleList.add(rp);
|
||||
rp.getProperties().setVisible(true);
|
||||
}
|
||||
|
||||
rList.add(rp);
|
||||
|
||||
blendedLists.add(list);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
while (true) {
|
||||
boolean done = true;
|
||||
for (ResourceList list : blendedLists) {
|
||||
if (list.size() <= i) {
|
||||
continue;
|
||||
}
|
||||
ResourcePair rp = list.get(i);
|
||||
|
||||
if (!rp.getProperties().isVisible()) {
|
||||
invisibleList.add(rp);
|
||||
rp.getProperties().setVisible(true);
|
||||
}
|
||||
|
||||
rList.add(rp);
|
||||
|
||||
done = false;
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// doHover goes in reverse list order
|
||||
Collections.reverse(rList);
|
||||
|
||||
paintResult(target, paintProps, sampleCoord,
|
||||
doHover(sampleCoord, rList));
|
||||
for (ResourcePair pair : invisibleList) {
|
||||
pair.getProperties().setVisible(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc.histogram;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.map.MapDescriptor;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.viz.grid.rsc.general.D2DGridResource;
|
||||
import com.raytheon.viz.grid.rsc.general.GeneralGridData;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Construct D2D ensamle Sampling resources and provide data.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class HistogramResourceData extends AbstractResourceData {
|
||||
|
||||
private IDescriptor mapDescriptor = null;
|
||||
|
||||
/**
|
||||
* The grid resources holding the ensemble data for input to the ensemble
|
||||
* calculator The String key is the loaded model name of an ensemble
|
||||
* product, same model ran multiple times or multiple models ran same time.
|
||||
* Consider the last two case later. Need an ensemble manager to handle the
|
||||
* resources, so the loaded products can register and unregister when
|
||||
* loading and unloading. To do so, may be need extend D2DGridResource to
|
||||
* EnsembleGridResource(need EnsembleGridResourceData too) which can provide
|
||||
* more interfaces
|
||||
*
|
||||
*/
|
||||
private Map<String, List<GenericResourceHolder>> dataHolders = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
/**
|
||||
* Currently consider one resource case only. The multiple generated
|
||||
* resource may be created for difference level or unit. Do this later with
|
||||
* List<GeneratedEnsembleGridResource<GeneratedEnsembleGridResourceData>>
|
||||
* resources.
|
||||
*/
|
||||
protected HistogramResource<HistogramResourceData> resource = null;
|
||||
|
||||
// like "500MB", "" is not available or don't care.
|
||||
protected String level = "";
|
||||
|
||||
// Like "Height", "" is not available or don't care.
|
||||
protected String unit = "";
|
||||
|
||||
// Display mode
|
||||
protected HistogramResource.DisplayMode mode;
|
||||
|
||||
public HistogramResourceData(HistogramResource.DisplayMode mode) {
|
||||
super();
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public HistogramResourceData(IDescriptor md, String level, String unit,
|
||||
HistogramResource.DisplayMode mode) {
|
||||
|
||||
this.mapDescriptor = md;// need not at here?
|
||||
this.level = level;
|
||||
this.unit = unit;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the resource whatever level and unit
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public AbstractVizResource<?, ?> construct(LoadProperties loadProperties,
|
||||
IDescriptor descriptor) throws VizException {
|
||||
|
||||
AbstractVizResource<?, ?> rsc = null;
|
||||
|
||||
rsc = new HistogramResource<HistogramResourceData>(this,
|
||||
loadProperties, descriptor, level, unit, mode);
|
||||
|
||||
resource = (HistogramResource<HistogramResourceData>) rsc;
|
||||
|
||||
update();
|
||||
ResourceProperties rp = new ResourceProperties();
|
||||
|
||||
ResourcePair pair = new ResourcePair();
|
||||
pair.setResource(rsc);
|
||||
pair.setProperties(rp);
|
||||
descriptor.getResourceList().add(pair);
|
||||
|
||||
// Register to the ensemble resource manager
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
EnsembleResourceManager.getInstance().registerGenerated(
|
||||
(AbstractVizResource<?, ?>) resource, editor);
|
||||
|
||||
return rsc;
|
||||
}
|
||||
|
||||
public Map<String, List<GenericResourceHolder>> getDataHolders() {
|
||||
return dataHolders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search ensemble members resources grouped by model
|
||||
*
|
||||
*/
|
||||
public List<D2DGridResource> getAllMembersResources() {
|
||||
|
||||
// whatever level or unit in this implementation
|
||||
Set<String> keys = dataHolders.keySet();
|
||||
List<D2DGridResource> members = new ArrayList<D2DGridResource>();
|
||||
for (String key : keys) {
|
||||
List<GenericResourceHolder> rcsList = dataHolders.get(key);
|
||||
if (rcsList == null || rcsList.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rcsList.size(); i++) {
|
||||
|
||||
if (rcsList.get(i).getRsc() instanceof D2DGridResource) {
|
||||
members.add((D2DGridResource) rcsList.get(i).getRsc());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Available Data Times if all member may be used in future,
|
||||
*/
|
||||
private List<DataTime> getAllMemberDataTimes() {
|
||||
// Use frame time instead real data time
|
||||
DataTime[] dataTimes = this.mapDescriptor.getFramesInfo()
|
||||
.getFrameTimes();
|
||||
List<DataTime> times = new ArrayList<DataTime>(Arrays.asList(dataTimes));
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Get data set in all member; may be used in future, but the data
|
||||
* time should be checked if it's available time
|
||||
*/
|
||||
private List<List<GeneralGridData>> getAllData(DataTime time) {
|
||||
List<List<GeneralGridData>> allData = new ArrayList<List<GeneralGridData>>();
|
||||
List<D2DGridResource> members = getAllMembersResources();
|
||||
|
||||
for (D2DGridResource member : members) {
|
||||
List<GeneralGridData> data = member.requestData(time);
|
||||
|
||||
if (data != null) {
|
||||
allData.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
return allData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object updateData) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Update by checking on the loaded ensemble product resources Re-calculate
|
||||
* with the ensemble calculator to generate a new product(like mean), update
|
||||
* the dataMap in the AbstractGridResource Is it possible to update the
|
||||
* dataMap? The AbstractGridResource methods can be over written?
|
||||
* UsesetData(Map<DataTime, List<GeneralGridData>> data)
|
||||
*
|
||||
* @throws VizException
|
||||
*/
|
||||
public void update() throws VizException {
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
if (level != null && !level.equals("") && unit != null
|
||||
&& !unit.equals("")) {
|
||||
// Same level and unit case
|
||||
dataHolders = EnsembleResourceManager
|
||||
.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs((IDescriptor) new MapDescriptor(), true,
|
||||
level, unit);
|
||||
|
||||
} else if (unit != null && !unit.equals("")) {
|
||||
// TODO: same unit whatever level case
|
||||
} else {
|
||||
// TODO: whatever level or unit,for test only
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc.histogram;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
|
||||
/**
|
||||
* Generate the text of the histogram. This algorithm is from ALPS(C++) by James
|
||||
* Ramer. First step: implement single color; Second step:multi-color.
|
||||
*
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* July, 2014 5056 jing Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class TextHistogram {
|
||||
|
||||
private final int BLOCK_SIZE = 400;
|
||||
|
||||
private float _minBin = 10;
|
||||
|
||||
private float _minLbl = 10;
|
||||
|
||||
private boolean isColorHist;
|
||||
|
||||
private String unit = "";
|
||||
|
||||
public TextHistogram(boolean isColorDiagram) {
|
||||
|
||||
isColorHist = false;
|
||||
}
|
||||
|
||||
public String makeHistogram(List<Float> data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// char * defaultMultiColor()
|
||||
//
|
||||
// For a multi color sample string for which all characters will have the
|
||||
// color of the sampling overlay, put a space after all non-whitespace
|
||||
// characters. Returns pointer to terminating null.
|
||||
// -- implementation
|
||||
// ---------------------------------------------------------
|
||||
// TODO
|
||||
private char[] defaultMultiColor(char[] wrkStr) {
|
||||
int newSize = wrkStr.length;
|
||||
for (char ch : wrkStr) {
|
||||
if (ch > ' ') {
|
||||
newSize++;
|
||||
}
|
||||
}
|
||||
|
||||
char[] newStr = new char[newSize];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < wrkStr.length; i++) {
|
||||
newStr[j] = wrkStr[i];
|
||||
j++;
|
||||
if (wrkStr[i] > ' ') {
|
||||
newStr[j] = ' ';
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return newStr;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// void computeBinDelta(float & delta, float & delLbl)
|
||||
//
|
||||
// An approximate size for the bins on the ordinate of a histogram is
|
||||
// input in delta. This is changed to a rounded value for ploting, and
|
||||
// delLbl is how often to label the ordinate.
|
||||
// -- implementation
|
||||
// ---------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// private void computeBinDelta(float & delta, float & delLbl)
|
||||
private void computeBinDelta(float delta, float delLbl) {
|
||||
float ee = (float) Math.pow(10, (int) Math.log10(delta));
|
||||
delta /= ee;
|
||||
while (delta > 10) {
|
||||
delta /= 10;
|
||||
ee *= 10;
|
||||
}
|
||||
while (delta < 1) {
|
||||
delta *= 10;
|
||||
ee /= 10;
|
||||
}
|
||||
if (delta > 7) {
|
||||
delta = 10 * ee;
|
||||
delLbl = 50 * ee;
|
||||
} else if (delta < 1.414) {
|
||||
delta = ee;
|
||||
delLbl = 5 * ee;
|
||||
} else if (delta > 3.333) {
|
||||
delta = 5 * ee;
|
||||
delLbl = 20 * ee;
|
||||
} else {
|
||||
delta = 2 * ee;
|
||||
delLbl = 10 * ee;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// TextString FunctionOverlayDepict::interogate()
|
||||
// Adds one or both color bars to image data, as required.
|
||||
//
|
||||
// New multi-color sampling overlays need to have an instance added for
|
||||
// their
|
||||
// function name in DepictSeq::samplingCategory().
|
||||
// ---------------------------------------------------------------------------
|
||||
public List<String> interrogate(List<AbstractVizResource<?, ?>> rscs,
|
||||
List<Float> values, String unit) {
|
||||
List<String> histStr = new ArrayList<String>();
|
||||
// Most common case; computational overlay, sample with _implDepict
|
||||
|
||||
this.unit = unit;
|
||||
|
||||
// Check if histogram sampling is possible.
|
||||
if (rscs.size() == 0) {
|
||||
histStr.add("NO DATA");
|
||||
return histStr;
|
||||
}
|
||||
|
||||
// Show a depiction of the weights being used.
|
||||
int i, j, n, n2;
|
||||
|
||||
// Histogram case, the most complex, start by gathering the values.
|
||||
// If none are toggled on, we will base this on all inputs which exist.
|
||||
|
||||
float minVal, maxVal;
|
||||
minVal = maxVal = 0;
|
||||
n = rscs.size();
|
||||
n2 = 2 * n;
|
||||
if (values.size() == 0) {
|
||||
histStr.add("NO VALUES");
|
||||
return histStr;
|
||||
}
|
||||
for (i = j = 0; i < n2; i++) {
|
||||
j = i % n;
|
||||
if (i == j) {
|
||||
n2 = n;
|
||||
}
|
||||
|
||||
float oneval = values.get(j);
|
||||
|
||||
if (oneval == Float.NaN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (minVal == maxVal && maxVal == 0) {
|
||||
minVal = maxVal = oneval;
|
||||
} else if (oneval < minVal) {
|
||||
minVal = oneval;
|
||||
} else if (oneval > maxVal) {
|
||||
maxVal = oneval;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the best size to use for the value bins (dv).
|
||||
// This responds to density by using smaller increments along
|
||||
// the x-axis when density is larger.
|
||||
|
||||
char[] wrkstr = new char[BLOCK_SIZE];
|
||||
if (minVal >= maxVal) {
|
||||
wrkstr = (values.size() + " values of " + maxVal + "\n")
|
||||
.toCharArray();
|
||||
histStr.add(wrkstr.toString());
|
||||
return histStr;
|
||||
|
||||
}
|
||||
float dv = _minBin;
|
||||
|
||||
dv = (float) .5;
|
||||
float delLbl = _minLbl * dv / _minBin;
|
||||
if (dv == 0.5) {
|
||||
delLbl = 1;
|
||||
} else if (dv == 0 || (maxVal - minVal) > dv * 25) {
|
||||
float minDv = (maxVal > -minVal ? maxVal : -minVal) / 5000;
|
||||
if (dv < minDv) {
|
||||
dv = minDv;
|
||||
}
|
||||
computeBinDelta(dv, delLbl);
|
||||
} else if (dv != _minBin) {
|
||||
computeBinDelta(dv, delLbl);
|
||||
}
|
||||
|
||||
int nbMax = 20;
|
||||
if ((maxVal - minVal) / dv > nbMax) {
|
||||
float dvSeed, dvPrev;
|
||||
for (dvSeed = dvPrev = dv, i = 0; i < 100; i++) {
|
||||
dvSeed *= 1.4;
|
||||
dv = dvSeed;
|
||||
computeBinDelta(dv, delLbl);
|
||||
if (dv == dvPrev) {
|
||||
continue;
|
||||
}
|
||||
if ((maxVal - minVal) / dv < nbMax) {
|
||||
break;
|
||||
}
|
||||
dvPrev = dvSeed = dv;
|
||||
}
|
||||
}
|
||||
|
||||
// We want edge of the bins to be at half the bin size, containing at
|
||||
// least
|
||||
// two even values of del2.
|
||||
float del2 = delLbl * 2;
|
||||
float edge = dv * (((int) (minVal / dv)) - (float) 0.5);
|
||||
while (minVal - edge > dv) {
|
||||
edge += dv;
|
||||
}
|
||||
while (edge > minVal) {
|
||||
edge -= dv;
|
||||
}
|
||||
minVal = edge;
|
||||
edge = dv * (((int) (maxVal / dv)) + (float) 0.5);
|
||||
while (edge - maxVal > dv) {
|
||||
edge -= dv;
|
||||
}
|
||||
while (edge < maxVal) {
|
||||
edge += dv;
|
||||
}
|
||||
maxVal = edge;
|
||||
int nbins = (int) (0.5 + (maxVal - minVal) / dv);
|
||||
float mean2 = (minVal + maxVal) / 2;
|
||||
mean2 = mean2 > 0 ? del2 * (int) (0.5 + mean2 / del2) : -del2
|
||||
* (int) (0.5 - mean2 / del2);
|
||||
while (minVal > mean2 - del2 && maxVal < mean2 + del2) {
|
||||
nbins += 2;
|
||||
minVal -= dv;
|
||||
maxVal += dv;
|
||||
}
|
||||
|
||||
// Determine the proper y-axis for the counts, we want about 10 steps in
|
||||
// the vertical axis, and the max value rounded to the nearest 5 counts.
|
||||
Integer[] counts = new Integer[nbins];
|
||||
for (int k = 0; k < nbins; k++) {
|
||||
counts[k] = 0;
|
||||
}
|
||||
|
||||
nbins--;
|
||||
int maxCount = 0;
|
||||
for (i = 0; i < values.size(); i++) {
|
||||
j = (int) ((values.get(i) - minVal) / dv);
|
||||
if (j < 0) {
|
||||
j = 0;
|
||||
}
|
||||
if (j > nbins) {
|
||||
j = nbins;
|
||||
}
|
||||
counts[j]++;
|
||||
if (counts[j] > maxCount) {
|
||||
maxCount = counts[j];
|
||||
}
|
||||
|
||||
}
|
||||
maxCount = ((4 + maxCount) / 5) * 5;
|
||||
i = values.size() / 2;
|
||||
// while (maxCount<i) maxCount += 5;
|
||||
while (maxCount < i) {
|
||||
maxCount += 2;
|
||||
}
|
||||
int dCount = 1;
|
||||
int eCount = 1;
|
||||
while (maxCount > dCount * eCount * 10) {
|
||||
if (dCount == 5) {
|
||||
eCount *= 10;
|
||||
dCount = 1;
|
||||
} else {
|
||||
dCount = dCount == 1 ? 2 : 5;
|
||||
}
|
||||
}
|
||||
dCount *= eCount;
|
||||
// TextString histStr;
|
||||
|
||||
eCount = (maxCount / dCount) * dCount;
|
||||
if (eCount == maxCount) {
|
||||
eCount -= dCount;
|
||||
}
|
||||
|
||||
eCount++;
|
||||
|
||||
// First line, the top
|
||||
String tmpStr = String.format("%3d", maxCount);
|
||||
tmpStr += "| ";
|
||||
histStr.add(tmpStr);
|
||||
|
||||
while (eCount > 0) {
|
||||
int k = 0;
|
||||
for (char ch : " | ".toCharArray()) {
|
||||
wrkstr[k] = ch;
|
||||
k++;
|
||||
}
|
||||
int cp = 6;
|
||||
for (j = 0; j <= nbins; j++, cp++) {
|
||||
if (counts[j] == 0 || counts[j] < eCount) {
|
||||
wrkstr[cp] = ' ';
|
||||
} else {
|
||||
wrkstr[cp] = 'x';
|
||||
}
|
||||
}
|
||||
|
||||
wrkstr[cp++] = '\n';
|
||||
wrkstr[cp] = '\0';
|
||||
|
||||
histStr.add(String.copyValueOf(wrkstr, 0, cp - 1));
|
||||
|
||||
eCount -= dCount;
|
||||
|
||||
}
|
||||
|
||||
// X-axis line
|
||||
|
||||
int k = 0;
|
||||
for (char ch : " --".toCharArray()) {
|
||||
wrkstr[k] = ch;
|
||||
k++;
|
||||
}
|
||||
edge = minVal + dv / 2;
|
||||
|
||||
int cp = 6;
|
||||
for (j = 0; j <= nbins; j++, cp++, edge += dv) {
|
||||
float d = edge / del2;
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
}
|
||||
d -= (int) d;
|
||||
if (d < 0.01 || d > 0.99) {
|
||||
wrkstr[cp] = '|';
|
||||
} else if (d > 0.49 && d < 0.51) {
|
||||
wrkstr[cp] = ':';
|
||||
} else {
|
||||
wrkstr[cp] = '-';
|
||||
}
|
||||
}
|
||||
wrkstr[cp++] = '\n';
|
||||
wrkstr[cp] = '\0';
|
||||
|
||||
// if (idLists)
|
||||
// defaultMultiColor(wrkstr);
|
||||
|
||||
histStr.add(String.copyValueOf(wrkstr, 0, cp - 1));
|
||||
// Mark X-axis
|
||||
for (k = 0; k < BLOCK_SIZE; k++) {
|
||||
wrkstr[k] = ' ';
|
||||
}
|
||||
|
||||
String scr = "";
|
||||
for (k = 0; k < BLOCK_SIZE; k++) {
|
||||
scr += ' ';
|
||||
}
|
||||
|
||||
cp = 0;
|
||||
dCount = 0;
|
||||
edge = minVal + dv / 2;
|
||||
edge = edge > 0 ? del2 * (int) (0.5 + edge / del2) : -del2
|
||||
* (int) (0.5 - edge / del2);
|
||||
while (edge < minVal) {
|
||||
edge += del2;
|
||||
}
|
||||
|
||||
while (edge < maxVal) {
|
||||
|
||||
scr = String.format("%.4f", edge);
|
||||
scr = String.copyValueOf(scr.toCharArray(), 0, 4);
|
||||
i = scr.length();
|
||||
j = (int) ((edge - minVal) / dv) + 5 - i / 2;
|
||||
|
||||
for (k = 0; k < i; k++) {
|
||||
wrkstr[k + j] = scr.charAt(k);
|
||||
}
|
||||
cp = i + j;
|
||||
dCount++;
|
||||
edge += del2;
|
||||
}
|
||||
edge -= delLbl;
|
||||
if (dCount >= 2) {
|
||||
// TODO
|
||||
;
|
||||
} else if (edge > maxVal) {
|
||||
edge -= del2;
|
||||
|
||||
scr = String.format("%.1f", edge);
|
||||
|
||||
scr.length();
|
||||
j = (int) ((edge - minVal) / dv) + 5 - i / 2;
|
||||
for (k = 0; k < i; k++) {
|
||||
wrkstr[k + j] = scr.charAt(k);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
scr = String.format("%.1f", edge);
|
||||
scr.length();
|
||||
j = (int) ((edge - minVal) / dv) + 5 - i / 2;
|
||||
for (k = 0; k < i; k++) {
|
||||
wrkstr[k + j] = scr.charAt(k);
|
||||
}
|
||||
|
||||
cp = i + j;
|
||||
}
|
||||
wrkstr[cp++] = '\n';
|
||||
wrkstr[cp] = '\0';
|
||||
|
||||
histStr.add(String.copyValueOf(wrkstr, 0, cp - 1));
|
||||
|
||||
return histStr;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc.timeseries;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.measure.unit.Unit;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
|
||||
import com.raytheon.uf.common.dataplugin.grid.util.GridLevelTranslator;
|
||||
import com.raytheon.uf.common.dataplugin.level.Level;
|
||||
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.style.StyleException;
|
||||
import com.raytheon.uf.common.style.level.SingleLevel;
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.OutlineCapability;
|
||||
import com.raytheon.uf.viz.d2d.xy.adapters.timeseries.GridTimeSeriesAdapter;
|
||||
import com.raytheon.uf.viz.xy.timeseries.adapter.AbstractTimeSeriesAdapter;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.core.graphing.util.GraphPrefsFactory;
|
||||
import com.raytheon.viz.core.graphing.xy.XYData;
|
||||
import com.raytheon.viz.core.rsc.ICombinedResourceData.CombineOperation;
|
||||
|
||||
/**
|
||||
* Uses cached data and parameters of loaded members in the time series display,
|
||||
* generates an new data and construct a resource for it. Implement steps:
|
||||
* 1,Basic calculation display in same time points on X axis case 2, Basic
|
||||
* calculation display including different time points on X axis case
|
||||
* 3,Interactive select a location from map 4, Continuously change the location.
|
||||
* Should check on if the performance is OK, because current D2D Time series
|
||||
* display architecture makes the display very slow on getting a point data and
|
||||
* repeatedly display the background graphics. Maybe the baseline code will be
|
||||
* improved someday.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb, 2014 5056 jing Initial creation
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class GeneratedTimeSeriesResource<T extends AbstractResourceData>
|
||||
extends TimeSeriesResource {
|
||||
|
||||
private static final IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(GeneratedTimeSeriesResource.class);
|
||||
|
||||
// TODO : Needed for future use.
|
||||
// private final SimpleDateFormat timeSampleFormat = new SimpleDateFormat(
|
||||
// "HH:mm'Z' EEE");
|
||||
|
||||
private Calculation calculation;
|
||||
|
||||
/** the level I would prefer to use **/
|
||||
protected Level preferredLevel = null;
|
||||
|
||||
/** the unit to convert to, matches preferredLevel unit **/
|
||||
protected Unit<?> preferredUnit = Unit.ONE;
|
||||
|
||||
/** a map of levels to units for quick lookup **/
|
||||
protected Map<Level, Unit<?>> levelUnitMap = new HashMap<Level, Unit<?>>();
|
||||
|
||||
/** first received parameter name **/
|
||||
protected String parameterName = "";
|
||||
|
||||
protected String parameterAbbreviation = "";
|
||||
|
||||
protected Random rand;
|
||||
|
||||
protected String[] titles = null;
|
||||
|
||||
public GeneratedTimeSeriesResource(GeneratedTimeSeriesResourceData data,
|
||||
LoadProperties props) {
|
||||
super(data, props, null);
|
||||
|
||||
// remember the resource data
|
||||
resourceData = data;
|
||||
|
||||
// Set line thickness
|
||||
OutlineCapability outLine = (OutlineCapability) this
|
||||
.getCapability((OutlineCapability.class));
|
||||
outLine.setOutlineWidth(3);
|
||||
|
||||
// Set color
|
||||
ColorableCapability colorable = (ColorableCapability) this
|
||||
.getCapability(ColorableCapability.class);
|
||||
rand = new Random();
|
||||
RGB color = new RGB(rand.nextInt(206) + 50, rand.nextInt(206) + 50,
|
||||
rand.nextInt(206) + 50);
|
||||
colorable.setColor(color);
|
||||
|
||||
// Initial the data times for needing in the system, it will be updated
|
||||
this.dataTimes = new HashSet<DataTime>(data.getAllDataTimes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTitles() {
|
||||
return titles;
|
||||
}
|
||||
|
||||
public void setTitles(String[] titles) {
|
||||
this.titles = titles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the calculation generated time series resource when any member
|
||||
* resource or other changed. Will be fully implemented later.
|
||||
*/
|
||||
public void updateData() {
|
||||
// Setup generated resource
|
||||
|
||||
// TODO resource.secondaryResource? consider it later
|
||||
// TODO resource.combineOperation?consider it later
|
||||
|
||||
this.setData(((GeneratedTimeSeriesResourceData) this.getResourceData())
|
||||
.calculate());
|
||||
|
||||
// Set the data times for painting, that need changes dataTimes
|
||||
// to protected in TimeSeriesResource class.
|
||||
dataTimes = new TreeSet<DataTime>();
|
||||
for (XYData d : data.getData()) {
|
||||
dataTimes.add((DataTime) d.getX());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
public Calculation getCalculation() {
|
||||
return calculation;
|
||||
}
|
||||
|
||||
public void setCalculation(Calculation c) {
|
||||
calculation = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the parameters with any time series record.
|
||||
*/
|
||||
public void setParameters() {
|
||||
|
||||
AbstractTimeSeriesAdapter<?> adapter = ((GeneratedTimeSeriesResourceData) resourceData)
|
||||
.getAnyMembersResource().getAdapter();
|
||||
if (!(adapter instanceof GridTimeSeriesAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTitles(((GeneratedTimeSeriesResourceData) resourceData)
|
||||
.getAnyMembersResource().getTitles());
|
||||
|
||||
PluginDataObject pdo = ((GridTimeSeriesAdapter) adapter)
|
||||
.getArbitraryRecord();
|
||||
|
||||
// store off records by level
|
||||
if (pdo instanceof GridRecord) {
|
||||
|
||||
GridRecord record = (GridRecord) pdo;
|
||||
|
||||
// set preferredLevel to first level
|
||||
if (preferredLevel == null) {
|
||||
preferredLevel = record.getLevel();
|
||||
((GeneratedTimeSeriesResourceData) resourceData).level = preferredLevel
|
||||
.toString();
|
||||
preferredUnit = record.getParameter().getUnit();
|
||||
((GeneratedTimeSeriesResourceData) resourceData).unit = preferredUnit
|
||||
.toString();
|
||||
parameterName = record.getParameter().getName();
|
||||
parameterAbbreviation = record.getParameter().getAbbreviation();
|
||||
if (parameterName == null || parameterName.isEmpty()) {
|
||||
if (parameterAbbreviation == null) {
|
||||
parameterAbbreviation = "";
|
||||
}
|
||||
parameterName = parameterAbbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
// add Unit to levelUnitMap if needed ( quick look-ups )
|
||||
Level lvl = record.getLevel();
|
||||
Unit<?> unit = levelUnitMap.get(lvl);
|
||||
if (unit == null) {
|
||||
unit = record.getParameter().getUnit();
|
||||
levelUnitMap.put(lvl, unit);
|
||||
}
|
||||
|
||||
} else {
|
||||
// this shouldn't happen, code expects all pdo's for
|
||||
// GribTimeSeriesAdapter to be GridRecords
|
||||
String message = "Unexpected PluginDataObject type; got "
|
||||
+ pdo.getClass().getName() + " expected GridRecord";
|
||||
statusHandler.handle(Priority.PROBLEM, message, new Exception(
|
||||
message));
|
||||
}
|
||||
|
||||
// Added interface to TimeSeriesResource solution
|
||||
// parameterName = this.getAdapter().getParameterName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initInternal(IGraphicsTarget target) throws VizException {
|
||||
|
||||
if (secondaryResource != null) {
|
||||
secondaryResource.setDescriptor(this.descriptor);
|
||||
secondaryResource.init(target);
|
||||
}
|
||||
|
||||
// Load the Graph Preferences
|
||||
if (prefs == null) {
|
||||
try {
|
||||
String name = preferredLevel.getMasterLevel().getName();
|
||||
SingleLevel level = GridLevelTranslator.construct(name);
|
||||
level.setValue(preferredLevel.getLevelonevalue());
|
||||
prefs = GraphPrefsFactory.buildPreferences(
|
||||
((GeneratedTimeSeriesResourceData) resourceData)
|
||||
.getYParameter().code, level);
|
||||
|
||||
} catch (StyleException e) {
|
||||
throw new VizException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefs != null && prefs.getDisplayUnits() != null) {
|
||||
units = prefs.getDisplayUnitLabel();
|
||||
}
|
||||
|
||||
if (secondaryResource != null
|
||||
&& combineOperation != CombineOperation.NONE) {
|
||||
// TODO
|
||||
// combineData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* implement later for secondaryResource
|
||||
*
|
||||
* @Override private void combineData() { if (secondaryResource.prefs !=
|
||||
* null && secondaryResource.prefs.getDisplayUnits() != null && prefs !=
|
||||
* null && prefs.getDisplayUnits() != null) { }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the legend name of this resource
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
|
||||
String resultingName = "<No Generated Times Series: "
|
||||
+ calculation.getTitle() + ">";
|
||||
String levelKey = resourceData.getLevelKey();
|
||||
String levelUnit = levelKey.replaceAll("[^a-zA-Z]", "");
|
||||
boolean isHeight = levelUnit.equalsIgnoreCase("mb")
|
||||
|| levelUnit.equalsIgnoreCase("agl")
|
||||
|| levelUnit.contains("Agl");
|
||||
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setMaximumFractionDigits(1);
|
||||
String lon = "";
|
||||
String lat = "";
|
||||
if (resourceData.getCoordinate() != null) {
|
||||
double x = resourceData.getCoordinate().x;
|
||||
double y = resourceData.getCoordinate().y;
|
||||
lon = nf.format(Math.abs(x));
|
||||
lat = nf.format(Math.abs(y));
|
||||
|
||||
String stnID = "";
|
||||
|
||||
String source = calculation.getTitle();
|
||||
|
||||
// Make legend for point data
|
||||
StringBuilder sb = new StringBuilder(String.format(
|
||||
"%s pt%s %s%s %s%s", source, resourceData.getPointLetter(),
|
||||
lat, y >= 0 ? "N" : "S", lon, x >= 0 ? "E" : "W"));
|
||||
|
||||
if (stnID != null) {
|
||||
sb.append(" ").append(stnID);
|
||||
}
|
||||
if (!isHeight) {
|
||||
sb.append(" ").append(resourceData.getLevelKey());
|
||||
}
|
||||
sb.append(String.format(" %s %s %s", parameterName, "TSer",
|
||||
units != null && units.equals("") == false ? "(" + units
|
||||
+ ")" : ""));
|
||||
resultingName = sb.toString();
|
||||
}
|
||||
|
||||
return resultingName;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
package gov.noaa.gsd.viz.ensemble.display.rsc.timeseries;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.EnsembleCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.uf.viz.xy.timeseries.display.TimeSeriesDescriptor;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResourceData;
|
||||
import com.raytheon.viz.core.graphing.xy.XYDataList;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* Uses cached data of loaded members in the time series display, generates an
|
||||
* new data and construct a resource for it.
|
||||
*
|
||||
* @author jing
|
||||
* @version 1.0
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb, 2014 5056 jing Initial creation
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class GeneratedTimeSeriesResourceData extends TimeSeriesResourceData {
|
||||
|
||||
private Map<String, List<GenericResourceHolder>> dataHolders = new ConcurrentHashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
/**
|
||||
* Calculate loaded ensemble data to generate new data, such as mean.
|
||||
*/
|
||||
protected EnsembleCalculator calculator = null;
|
||||
|
||||
protected GeneratedTimeSeriesResource<GeneratedTimeSeriesResourceData> resource = null;
|
||||
|
||||
// like "500MB", "" is not available or don't care.
|
||||
protected String level;
|
||||
|
||||
// Like "Height", "" is not available or don't care.
|
||||
protected String unit;
|
||||
|
||||
// create an empty metadata map
|
||||
protected HashMap<String, RequestConstraint> metadataMap = new HashMap<String, RequestConstraint>();
|
||||
|
||||
public GeneratedTimeSeriesResourceData(EnsembleCalculator calculator,
|
||||
String level, String unit) {
|
||||
|
||||
super();
|
||||
|
||||
this.calculator = calculator;
|
||||
this.level = level;
|
||||
this.unit = unit;
|
||||
// interface to disable the request
|
||||
this.setRetrieveData(false);
|
||||
|
||||
// No time request in time matching
|
||||
this.setRequeryNecessaryOnTimeMatch(false);
|
||||
this.setMetadataMap(metadataMap);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the resource whatever level and unit
|
||||
*/
|
||||
@Override
|
||||
public AbstractVizResource<?, ?> construct(LoadProperties loadProperties,
|
||||
IDescriptor descriptor) throws VizException {
|
||||
|
||||
update();
|
||||
|
||||
// Not data, don't construct the resource for avoid problem
|
||||
if (dataHolders == null || dataHolders.isEmpty()
|
||||
|| dataHolders.keySet().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
resource = new GeneratedTimeSeriesResource<GeneratedTimeSeriesResourceData>(
|
||||
this, loadProperties);
|
||||
resource.setCalculation(calculator.getCalculation());
|
||||
resource.setDescriptor((TimeSeriesDescriptor) descriptor);
|
||||
|
||||
this.metadataMap = new HashMap<String, RequestConstraint>();
|
||||
|
||||
// set the resource
|
||||
setup();
|
||||
resource.updateData();
|
||||
|
||||
// update();
|
||||
ResourceProperties rp = new ResourceProperties();
|
||||
|
||||
ResourcePair pair = new ResourcePair();
|
||||
pair.setResource(resource);
|
||||
pair.setProperties(rp);
|
||||
descriptor.getResourceList().add(pair);
|
||||
|
||||
// TODO: Is this the correct way to associate the editor with the
|
||||
// resource?
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
EnsembleResourceManager.getInstance().registerGenerated(
|
||||
(AbstractVizResource<?, ?>) resource, editor);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
// Uses the dataHolders to generate the new data for ensemble display
|
||||
@SuppressWarnings("unchecked")
|
||||
public XYDataList calculate() {
|
||||
return calculator.calculateTimeSeries(getAllData());
|
||||
}
|
||||
|
||||
public void update() throws VizException {
|
||||
|
||||
// TODO: Is this the correct way to associate the editor with the
|
||||
// resource?
|
||||
AbstractEditor editor = EditorUtil
|
||||
.getActiveEditorAs(AbstractEditor.class);
|
||||
|
||||
if (level != null && !level.equals("") && unit != null
|
||||
&& !unit.equals("")) {
|
||||
// Same level and unit case
|
||||
dataHolders = EnsembleResourceManager
|
||||
.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs(
|
||||
(IDescriptor) new TimeSeriesDescriptor(), true,
|
||||
level, unit);
|
||||
|
||||
// TODO: Reserved for future use.
|
||||
|
||||
// dataHolders =
|
||||
// ResourceManager.getInstance().getResourceList(editor).getCalculationLoadedRscs((IDescriptor)new
|
||||
// TimeSeriesDescriptor(), true);
|
||||
// } else if (level != null && !level.equals("")
|
||||
// && unit != null && !unit.equals("")){
|
||||
// //same unit whatever level case
|
||||
// dataHolders =
|
||||
// ResourceManager.getInstance().getResourceList(editor)
|
||||
// .getUserLoadedRscs((IDescriptor)new TimeSeriesDescriptor(),
|
||||
// false, unit);
|
||||
} else {
|
||||
// TODO: Reserved for future use.
|
||||
|
||||
// whatever level or unit,for test only
|
||||
// dataHolders =
|
||||
// ResourceManager.getInstance().getResourceList(editor)
|
||||
// .getUserLoadedRscs((IDescriptor)new TimeSeriesDescriptor(),
|
||||
// false);
|
||||
dataHolders = EnsembleResourceManager
|
||||
.getInstance()
|
||||
.getResourceList(editor)
|
||||
.getUserLoadedRscs(
|
||||
(IDescriptor) new TimeSeriesDescriptor(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the generated resourceData with a member resource.
|
||||
*/
|
||||
private void setup() {
|
||||
List<TimeSeriesResource> rscs = getAllMembersResources();
|
||||
if (rscs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
resource.setParameters();
|
||||
// Set up generated resource data
|
||||
this.level = rscs.get(0).getResourceData().getLevelKey();
|
||||
|
||||
this.unit = rscs.get(0).getUnits();
|
||||
|
||||
this.setCoordinate(rscs.get(0).getResourceData().getCoordinate());
|
||||
this.setCombineOperation(rscs.get(0).getResourceData()
|
||||
.getCombineOperation());
|
||||
this.setFrozenTime(rscs.get(0).getResourceData().getFrozenTime());
|
||||
|
||||
this.setLevelKey(rscs.get(0).getResourceData().getLevelKey());
|
||||
|
||||
this.setPointCoordinate(rscs.get(0).getResourceData()
|
||||
.getPointCoordinate());
|
||||
this.setPointLetter(rscs.get(0).getResourceData().getPointLetter());
|
||||
|
||||
this.setYParameter(rscs.get(0).getResourceData().getYParameter());
|
||||
this.setXParameter(rscs.get(0).getResourceData().getXParameter());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* May need not the Adapter if the generated resource and data can be set
|
||||
* correctly using a member resource.
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
// private AbstractTimeSeriesAdapter<?> getAdapter(PluginDataObject object){
|
||||
// GeneratedTimeSeriesAdapter adapter = new GeneratedTimeSeriesAdapter();
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/**
|
||||
* get the data available times from all members
|
||||
*/
|
||||
public List<DataTime> getAllDataTimes() {
|
||||
List<DataTime> dataTimes = new ArrayList<DataTime>();
|
||||
|
||||
List<TimeSeriesResource> members = getAllMembersResources();
|
||||
for (TimeSeriesResource member : members) {
|
||||
DataTime[] meberDataTimes = member.getDataTimes();
|
||||
|
||||
if (meberDataTimes != null && meberDataTimes.length != 0) {
|
||||
for (int i = 0; i < meberDataTimes.length - 1; i++) {
|
||||
if (!dataTimes.contains(meberDataTimes[i])) {
|
||||
dataTimes.add(meberDataTimes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all data of members for calculation
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<XYDataList> getAllData() {
|
||||
List<XYDataList> allData = new ArrayList<XYDataList>();
|
||||
|
||||
List<TimeSeriesResource> members = getAllMembersResources();
|
||||
for (TimeSeriesResource member : members) {
|
||||
XYDataList data = member.getData();
|
||||
if (data != null) {
|
||||
allData.add(data);
|
||||
}
|
||||
}
|
||||
return allData;
|
||||
}
|
||||
|
||||
public TimeSeriesResource getAnyMembersResource() {
|
||||
List<TimeSeriesResource> members = getAllMembersResources();
|
||||
if (members == null || members.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return members.get(0);
|
||||
}
|
||||
|
||||
private List<TimeSeriesResource> getAllMembersResources() {
|
||||
|
||||
// whatever level or unit in this implementation
|
||||
Set<String> keys = dataHolders.keySet();
|
||||
List<TimeSeriesResource> members = new ArrayList<TimeSeriesResource>();
|
||||
for (String key : keys) {
|
||||
List<GenericResourceHolder> rcsList = dataHolders.get(key);
|
||||
if (rcsList == null || rcsList.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rcsList.size(); i++) {
|
||||
if (rcsList.get(i).getRsc() instanceof TimeSeriesResource) {
|
||||
members.add((TimeSeriesResource) rcsList.get(i).getRsc());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public void setUnit(String unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package gov.noaa.gsd.viz.ensemble.navigator.action;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.navigator.ui.layer.EnsembleToolManager;
|
||||
|
||||
import org.eclipse.core.commands.ExecutionEvent;
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
|
||||
import com.raytheon.viz.ui.tools.AbstractTool;
|
||||
|
||||
/**
|
||||
* This is how you start the Ensemble Tool.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 7, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleToolLayerManagerAction extends AbstractTool {
|
||||
|
||||
public EnsembleToolLayerManagerAction() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(ExecutionEvent event) throws ExecutionException {
|
||||
|
||||
EnsembleToolManager.getInstance().execute(event);
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package gov.noaa.gsd.viz.ensemble.navigator.ui.layer;
|
||||
|
||||
import org.eclipse.ui.IPartListener2;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.IWorkbenchPartReference;
|
||||
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
|
||||
/**
|
||||
* This is the part listener for the editors associated with Ensemble Tool.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 17, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleEditorPartListener implements IPartListener2 {
|
||||
|
||||
private AbstractEditor editor = null;
|
||||
|
||||
public EnsembleEditorPartListener(AbstractEditor editor) {
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partActivated(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
EnsembleToolManager.getInstance().switchToEditor(editor, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partDeactivated(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partBroughtToTop(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partClosed(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
EnsembleToolManager.getInstance().unloadActiveToolLayer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partOpened(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partHidden(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partVisible(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partInputChanged(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isThisPart(IWorkbenchPartReference ref) {
|
||||
IWorkbenchPart part = ref.getPart(false);
|
||||
return part != null && part.equals(editor);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,653 @@
|
|||
package gov.noaa.gsd.viz.ensemble.navigator.ui.layer;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.AvgM1StddevCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.AvgP1StddevCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Calculation;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.ERFCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.MaxCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.MeanCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.MedianCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.MinCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.ModeCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.Range;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.RangeCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.StddevCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.calculate.SumCalculator;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.GenericResourceHolder;
|
||||
import gov.noaa.gsd.viz.ensemble.display.common.NavigatorResourceList;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.EnsembleResourceManager;
|
||||
import gov.noaa.gsd.viz.ensemble.display.control.load.GeneratedDataLoader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jface.viewers.TreePath;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.time.DataTime;
|
||||
import com.raytheon.uf.viz.core.IExtent;
|
||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||
import com.raytheon.uf.viz.core.drawables.AbstractDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor;
|
||||
import com.raytheon.uf.viz.core.drawables.IDescriptor.IFrameChangedListener;
|
||||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||
import com.raytheon.uf.viz.core.drawables.ResourcePair;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractNameGenerator;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.IInitListener;
|
||||
import com.raytheon.uf.viz.core.rsc.IInputHandler;
|
||||
import com.raytheon.uf.viz.core.rsc.IRefreshListener;
|
||||
import com.raytheon.uf.viz.core.rsc.IResourceDataChanged;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.RenderingOrderFactory.ResourceOrder;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceList;
|
||||
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
|
||||
import com.raytheon.uf.viz.core.rsc.capabilities.EditableCapability;
|
||||
import com.raytheon.uf.viz.core.rsc.tools.GenericToolsResourceData;
|
||||
import com.raytheon.uf.viz.xy.timeseries.rsc.TimeSeriesResource;
|
||||
import com.raytheon.viz.ui.EditorUtil;
|
||||
import com.raytheon.viz.ui.editor.AbstractEditor;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* The EnsembleToolLayer is an AbstractVizResource that the user can turn on or
|
||||
* off (i.e. make editable or not). Typically there is one instance of this
|
||||
* class per AbstractEditor window. This class is meant to be controlled by the
|
||||
* EnsembleToolManager. Though this class is decoupled from the other classes in
|
||||
* this plug-in, the idea is that the EnsembleToolLayer is the class which knows
|
||||
* how to have access to its virtually contained resources and how to act upon
|
||||
* them. In the greater picture, the tool layer controls the entire state of the
|
||||
* Ensemble Tool; if the activel tool layer is turned off (made "not editable")
|
||||
* then the Ensemble Tool is also disabled, but if the user switches to another
|
||||
* editor that has an EnsembleToolLayer that is "editable", the manager will
|
||||
* become active again. .
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov 16, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleToolLayer extends
|
||||
AbstractVizResource<AbstractResourceData, AbstractDescriptor> implements
|
||||
IInputHandler, IResourceDataChanged, IRefreshListener,
|
||||
IFrameChangedListener, IInitListener {
|
||||
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(EnsembleToolLayer.class);
|
||||
|
||||
public static final String DEFAULT_NAME = "Ensembles";
|
||||
|
||||
protected Coordinate initialDragPos = null;
|
||||
|
||||
protected Coordinate continualDragPos = null;
|
||||
|
||||
protected IExtent activeBoundingArea = null;
|
||||
|
||||
protected boolean isClosingToolLayer = false;
|
||||
|
||||
private boolean isDisposed = true;
|
||||
|
||||
private Object[] expandedElements = new Object[0];
|
||||
|
||||
private TreePath[] expandedTreePaths = new TreePath[0];
|
||||
|
||||
// TODO: Let's try and use the ResourceManager at next sprint ...
|
||||
private Map<String, List<GenericResourceHolder>> ensemblesTree = new HashMap<String, List<GenericResourceHolder>>();
|
||||
|
||||
public EnsembleToolLayer(
|
||||
GenericToolsResourceData<EnsembleToolLayer> resourceData,
|
||||
LoadProperties loadProperties) {
|
||||
super(resourceData, loadProperties);
|
||||
registerListener((IInitListener) this);
|
||||
|
||||
resourceData
|
||||
.setNameGenerator(new EnsembleToolLayerNameGeneratorWithTimeStampBasis());
|
||||
}
|
||||
|
||||
synchronized public Map<String, List<GenericResourceHolder>> getEnsembleResources() {
|
||||
|
||||
AbstractEditor editor = EnsembleToolManager.getInstance().findEditor(
|
||||
this);
|
||||
|
||||
if (EnsembleResourceManager.getInstance().getResourceList(editor) != null) {
|
||||
ensemblesTree = EnsembleResourceManager.getInstance()
|
||||
.getResourceList(editor).getAllRscsAsMap();
|
||||
} else {
|
||||
ensemblesTree = null;
|
||||
}
|
||||
|
||||
return ensemblesTree;
|
||||
}
|
||||
|
||||
public Object[] getExpandedElements() {
|
||||
return expandedElements;
|
||||
}
|
||||
|
||||
public void setExpandedElements(Object[] ee) {
|
||||
expandedElements = ee;
|
||||
}
|
||||
|
||||
public TreePath[] getExpandedTreePaths() {
|
||||
return expandedTreePaths;
|
||||
}
|
||||
|
||||
public void setExpandedTreePaths(TreePath[] expandedTreePaths) {
|
||||
this.expandedTreePaths = expandedTreePaths;
|
||||
}
|
||||
|
||||
public void unloadAllResources(AbstractEditor editor) {
|
||||
|
||||
if (EnsembleResourceManager.getInstance().getResourceList(editor) == null)
|
||||
return;
|
||||
Map<String, List<GenericResourceHolder>> allRscs = EnsembleResourceManager
|
||||
.getInstance().getResourceList(editor).getAllRscsAsMap();
|
||||
|
||||
List<GenericResourceHolder> currEnsembleMembers = null;
|
||||
Set<String> keySet = allRscs.keySet();
|
||||
Iterator<String> iter = keySet.iterator();
|
||||
while (iter.hasNext()) {
|
||||
String currRscListName = iter.next();
|
||||
currEnsembleMembers = allRscs.get(currRscListName);
|
||||
for (GenericResourceHolder gr : currEnsembleMembers) {
|
||||
if (gr.getRsc() instanceof TimeSeriesResource) {
|
||||
gr.getRsc().unload(
|
||||
editor.getActiveDisplayPane().getDescriptor()
|
||||
.getResourceList());
|
||||
gr.getRsc().dispose();
|
||||
} else {
|
||||
gr.getRsc().unload();
|
||||
gr.getRsc().dispose();
|
||||
}
|
||||
EnsembleResourceManager.getInstance().unregisterResource(gr,
|
||||
editor, false);
|
||||
}
|
||||
}
|
||||
|
||||
EnsembleResourceManager.getInstance().updateFrameChanges(editor);
|
||||
if ((getResourceContainer() != null)
|
||||
&& (getResourceContainer().getActiveDisplayPane() != null)) {
|
||||
getResourceContainer().getActiveDisplayPane().refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ResourcePair getResourcePair(AbstractVizResource<?, ?> rsc) {
|
||||
|
||||
ResourcePair foundRp = null;
|
||||
ResourceList rscList = null;
|
||||
|
||||
if (TimeSeriesResource.class.isAssignableFrom(rsc.getClass())) {
|
||||
AbstractEditor editor = EnsembleToolManager.getInstance()
|
||||
.findEditor(this);
|
||||
rscList = editor.getActiveDisplayPane().getDescriptor()
|
||||
.getResourceList();
|
||||
} else {
|
||||
rscList = getResourceContainer().getActiveDisplayPane()
|
||||
.getDescriptor().getResourceList();
|
||||
}
|
||||
for (ResourcePair rp : rscList) {
|
||||
if (rsc.equals(rp.getResource())) {
|
||||
foundRp = rp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundRp;
|
||||
|
||||
}
|
||||
|
||||
public void unloadAllResourcesByName(String ensembleName) {
|
||||
|
||||
AbstractEditor editor = EnsembleToolManager.getInstance().findEditor(
|
||||
this);
|
||||
List<GenericResourceHolder> ensembleMembers = EnsembleResourceManager
|
||||
.getInstance().getResourceList(editor)
|
||||
.getUserLoadedRscs(ensembleName);
|
||||
int total = ensembleMembers.size();
|
||||
int count = 0;
|
||||
for (GenericResourceHolder gr : ensembleMembers) {
|
||||
count++;
|
||||
if (count < total) {
|
||||
EnsembleResourceManager.getInstance().unregisterResource(gr,
|
||||
editor, false);
|
||||
} else {
|
||||
EnsembleResourceManager.getInstance().unregisterResource(gr,
|
||||
editor, true);
|
||||
}
|
||||
gr.getRsc().unload();
|
||||
}
|
||||
|
||||
EnsembleResourceManager.getInstance().updateFrameChanges(editor);
|
||||
|
||||
getResourceContainer().getActiveDisplayPane().refresh();
|
||||
|
||||
}
|
||||
|
||||
public void propertiesChanged(ResourceProperties updatedProps) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public boolean isDisposed() {
|
||||
return isDisposed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
|
||||
descriptor.removeFrameChangedListener(this);
|
||||
|
||||
AbstractEditor editor = EnsembleToolManager.getInstance().findEditor(
|
||||
this);
|
||||
unloadAllResources(editor);
|
||||
EnsembleToolManager.getInstance().removeToolLayer(this);
|
||||
|
||||
EnsembleResourceManager.getInstance().updateFrameChanges(editor);
|
||||
isDisposed = true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initInternal(IGraphicsTarget target) throws VizException {
|
||||
isDisposed = false;
|
||||
descriptor.getResourceList().getProperties(this)
|
||||
.setRenderingOrderId("HIGHEST");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inited(AbstractVizResource<?, ?> initedRsc) {
|
||||
|
||||
descriptor.addFrameChangedListener(this);
|
||||
resourceData.addChangeListener(this);
|
||||
registerListener((IRefreshListener) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintInternal(IGraphicsTarget target,
|
||||
PaintProperties paintProps) throws VizException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceChanged(ChangeType type, Object object) {
|
||||
if (type == ChangeType.DATA_REMOVE) {
|
||||
// TODO
|
||||
}
|
||||
if (type == ChangeType.CAPABILITY) {
|
||||
Class<?> ct = object.getClass();
|
||||
// TODO
|
||||
|
||||
if (getCapability(EditableCapability.class).getClass()
|
||||
.isAssignableFrom(ct)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
issueRefresh();
|
||||
}
|
||||
|
||||
public void transferFocusToEditor() {
|
||||
|
||||
// Get the active window
|
||||
IWorkbenchWindow window = PlatformUI.getWorkbench()
|
||||
.getActiveWorkbenchWindow();
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IEditorPart editor = window.getActivePage().getActiveEditor();
|
||||
if (editor != null) {
|
||||
editor.setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseMove(int x, int y) {
|
||||
boolean handledMouseAction = false;
|
||||
// TODO
|
||||
return handledMouseAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseDownMove(int x, int y, int mouseButton) {
|
||||
boolean handledMouseAction = false;
|
||||
// TODO
|
||||
return handledMouseAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseUp(int x, int y, int mouseButton) {
|
||||
boolean alreadyHandled = false;
|
||||
// TODO
|
||||
return alreadyHandled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyUp(int keyCode) {
|
||||
|
||||
boolean handledKeyAction = false;
|
||||
// TODO
|
||||
return handledKeyAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseDown(int x, int y, int mouseButton) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseHover(int x, int y) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleDoubleClick(int x, int y, int button) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseWheel(Event event, int x, int y) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseExit(Event event) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseEnter(Event event) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyDown(int keyCode) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public void calculate(Calculation algorithm, final Range range) {
|
||||
|
||||
final AbstractEditor editor = EnsembleToolManager.getInstance()
|
||||
.findEditor(this);
|
||||
if (algorithm == Calculation.ENSEMBLE_RELATIVE_FREQUENCY) {
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
ERFCalculator erfRsc = new ERFCalculator(range);
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(erfRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void calculate(Calculation algorithm) {
|
||||
|
||||
final AbstractEditor editor = EnsembleToolManager.getInstance()
|
||||
.findEditor(this);
|
||||
if (algorithm == Calculation.MEAN) {
|
||||
|
||||
Thread t = null;
|
||||
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the mean overlay
|
||||
MeanCalculator meanRsc = new MeanCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(meanRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.MIN) {
|
||||
|
||||
Thread t = null;
|
||||
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the min overlay
|
||||
MinCalculator minRsc = new MinCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(minRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.MAX) {
|
||||
|
||||
Thread t = null;
|
||||
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the max overlay
|
||||
MaxCalculator maxRsc = new MaxCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(maxRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.MEDIAN) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the median overlay
|
||||
MedianCalculator medianRsc = new MedianCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(medianRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.MODE) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the median overlay
|
||||
ModeCalculator modeRsc = new ModeCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(modeRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.RANGE) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the range overlay
|
||||
RangeCalculator rangeRsc = new RangeCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(rangeRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.SUMMATION) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the sum overlay
|
||||
SumCalculator sumRsc = new SumCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(sumRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.STANDARD_DEVIATION) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the sum overlay
|
||||
StddevCalculator stddevRsc = new StddevCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(stddevRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.AVG_MINUS_STD_DEV) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the sum overlay
|
||||
AvgM1StddevCalculator m1StddevRsc = new AvgM1StddevCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(m1StddevRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.AVG_PLUS_STD_DEV) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
// Load the sum overlay
|
||||
AvgP1StddevCalculator p1StddevRsc = new AvgP1StddevCalculator();
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.load(p1StddevRsc);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.HISTOGRAM_SAMPLING) {
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.loadOverlay(Calculation.HISTOGRAM_SAMPLING);
|
||||
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
} else if (algorithm == Calculation.HISTOGRAM_TEXT) {
|
||||
|
||||
Thread t = null;
|
||||
t = new Thread() {
|
||||
public void run() {
|
||||
|
||||
GeneratedDataLoader loader = new GeneratedDataLoader(
|
||||
editor,
|
||||
GeneratedDataLoader.GeneratedloadMode.SAME_UNIT_AND_LEVEL);
|
||||
loader.loadOverlay(Calculation.HISTOGRAM_TEXT);
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setEditable(boolean makeEditable) {
|
||||
getCapability(EditableCapability.class).setEditable(makeEditable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frameChanged(IDescriptor descriptor, DataTime oldTime,
|
||||
DataTime newTime) {
|
||||
|
||||
EnsembleToolManager.getInstance().updateLegendTimeInfo();
|
||||
|
||||
}
|
||||
|
||||
class EnsembleToolLayerNameGeneratorWithTimeStampBasis extends
|
||||
AbstractNameGenerator {
|
||||
|
||||
@Override
|
||||
public String getName(AbstractVizResource<?, ?> resource) {
|
||||
String timeBasis = EnsembleToolManager.getInstance()
|
||||
.getTimeBasisLegendTime();
|
||||
if (NavigatorResourceList.isTimeEmpty(timeBasis)) {
|
||||
timeBasis = "";
|
||||
} else {
|
||||
timeBasis = " (" + timeBasis + ") ";
|
||||
}
|
||||
AbstractEditor editor = (AbstractEditor) EditorUtil
|
||||
.getActiveEditor();
|
||||
String fullName = EnsembleToolLayer.DEFAULT_NAME + " "
|
||||
+ editor.getTitle().trim() + timeBasis;
|
||||
return fullName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceOrder getResourceOrder() {
|
||||
return ResourceOrder.HIGHEST;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package gov.noaa.gsd.viz.ensemble.navigator.ui.viewer;
|
||||
|
||||
import gov.noaa.gsd.viz.ensemble.navigator.ui.layer.EnsembleToolManager;
|
||||
|
||||
import org.eclipse.ui.IPartListener2;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.IWorkbenchPartReference;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
|
||||
import com.raytheon.uf.viz.core.VizApp;
|
||||
|
||||
/**
|
||||
* The part listener for the EnsembleToolViewer class (ViewPart). The most
|
||||
* critical reason for this listener is to turn on/off the CAVE tool layer
|
||||
* editability flag (i.e. whether the tool layer has control of user
|
||||
* interactivity or not) when the view state changes (becomes
|
||||
* activated/deactivated).
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleViewPartListener implements IPartListener2 {
|
||||
|
||||
public static boolean isHidden = false;
|
||||
|
||||
private EnsembleToolViewer ensembleToolViewer = null;
|
||||
|
||||
public EnsembleViewPartListener(EnsembleToolViewer fsv) {
|
||||
ensembleToolViewer = fsv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partActivated(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
EnsembleToolManager.getInstance().setEditable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partDeactivated(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
VizApp.runAsync(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
if (isHidden) {
|
||||
EnsembleToolManager.getInstance().setEditable(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partHidden(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
isHidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partVisible(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
isHidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partClosed(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
|
||||
isHidden = false;
|
||||
|
||||
VizApp.runAsync(new Runnable() {
|
||||
public void run() {
|
||||
if (!PlatformUI.getWorkbench().isClosing()) {
|
||||
EnsembleToolManager.getInstance().close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partBroughtToTop(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partOpened(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partInputChanged(IWorkbenchPartReference partRef) {
|
||||
if (isThisPart(partRef)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isThisPart(IWorkbenchPartReference ref) {
|
||||
IWorkbenchPart part = ref.getPart(false);
|
||||
return part != null && part.equals(ensembleToolViewer);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package gov.noaa.gsd.viz.ensemble.navigator.ui.viewer;
|
||||
|
||||
/**
|
||||
* Convenience enumeration for ViewPart states.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum ViewerWindowState {
|
||||
|
||||
SHOW_WITH_FOCUS, SHOW_WITHOUT_FOCUS, MINIMIZED, CLOSE;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
/**
|
||||
* This class is used to map unique colors to given GFS ensemble perturbation
|
||||
* members, which are identified by their hard-coded perturbation memeber names
|
||||
* (ctl1, ctl2, n1, n2 ... p4, p5). It has been created in support of
|
||||
* simplifying the process of allowing the user to color an entire ensemble set
|
||||
* of members using a color gradient.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ChosenGEFSColors {
|
||||
|
||||
static public ChosenGEFSColors getInstance() {
|
||||
if (SINGLETON == null) {
|
||||
SINGLETON = new ChosenGEFSColors();
|
||||
}
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
static private ChosenGEFSColors SINGLETON = null;
|
||||
|
||||
private ChosenGEFSColors() {
|
||||
|
||||
}
|
||||
|
||||
private Color color = SWTResourceManager.NEON_PURPLE;
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color c) {
|
||||
color = c;
|
||||
}
|
||||
|
||||
public Color getGradientByEnsembleId(String name) {
|
||||
|
||||
Color c = null;
|
||||
final int totalSteps = 12;
|
||||
|
||||
int pertNumber = getPerturbationIndex(name);
|
||||
c = getGradientColor(color, totalSteps, pertNumber);
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
private Color getGradientColor(Color c, int totalSteps, int currStep) {
|
||||
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = (float) currStep / (float) totalSteps;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
return SWTResourceManager.getColor(nrgb);
|
||||
}
|
||||
|
||||
public String getSrefPerturbationPrefix(String member) {
|
||||
return member.replaceAll("[0-9]", "");
|
||||
}
|
||||
|
||||
// TODO: this is a poor man's solution wokring against hard-coded names:
|
||||
// .... such as ctl1, ctl2, n1, n2 ... p4, p5
|
||||
public int getPerturbationIndex(String member) {
|
||||
|
||||
int pert = 0;
|
||||
if (member.startsWith("ctl1")) {
|
||||
pert = 12;
|
||||
} else if (member.startsWith("ctl2")) {
|
||||
pert = 11;
|
||||
} else if (member.startsWith("n1")) {
|
||||
pert = 10;
|
||||
} else if (member.startsWith("n2")) {
|
||||
pert = 9;
|
||||
} else if (member.startsWith("n3")) {
|
||||
pert = 8;
|
||||
} else if (member.startsWith("n4")) {
|
||||
pert = 7;
|
||||
} else if (member.startsWith("n5")) {
|
||||
pert = 6;
|
||||
} else if (member.startsWith("p1")) {
|
||||
pert = 5;
|
||||
} else if (member.startsWith("p2")) {
|
||||
pert = 4;
|
||||
} else if (member.startsWith("p3")) {
|
||||
pert = 3;
|
||||
} else if (member.startsWith("p4")) {
|
||||
pert = 2;
|
||||
} else if (member.startsWith("p5")) {
|
||||
pert = 1;
|
||||
}
|
||||
|
||||
return pert;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
/**
|
||||
* This class is used to map unique colors to given SREF ensemble perturbation
|
||||
* members, which are identified by their hard-coded perturbation memeber names.
|
||||
* It has been created in support of simplifying the process of allowing the
|
||||
* user to color the different groups of perturbation members (NMM, NMB, EM)
|
||||
* with their own color gradient using a base color for each group (e.g. NMM =
|
||||
* RED, NMB = BLUE, EM = GREEN).
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ChosenSREFColors {
|
||||
|
||||
static public ChosenSREFColors getInstance() {
|
||||
if (SINGLETON == null) {
|
||||
SINGLETON = new ChosenSREFColors();
|
||||
}
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
static private ChosenSREFColors SINGLETON = null;
|
||||
|
||||
private ChosenSREFColors() {
|
||||
|
||||
}
|
||||
|
||||
private Color nmm_color = SWTResourceManager.CHERRY_RED;
|
||||
|
||||
private Color nmb_color = SWTResourceManager.SPRING_GREEN;
|
||||
|
||||
private Color em_color = SWTResourceManager.DEEP_BLUE;
|
||||
|
||||
public Color get_EM_color() {
|
||||
return em_color;
|
||||
}
|
||||
|
||||
public void set_EM_color(Color em_color) {
|
||||
this.em_color = em_color;
|
||||
}
|
||||
|
||||
public Color get_NMM_color() {
|
||||
return nmm_color;
|
||||
}
|
||||
|
||||
public void set_NMM_color(Color nmm_color) {
|
||||
this.nmm_color = nmm_color;
|
||||
}
|
||||
|
||||
public Color get_NMB_color() {
|
||||
return nmb_color;
|
||||
}
|
||||
|
||||
public void set_NMB_color(Color nmb_color) {
|
||||
this.nmb_color = nmb_color;
|
||||
}
|
||||
|
||||
// TODO: this is a poor man's solution wokring against hard-coded names:
|
||||
// .... such as ctll1, ctll8, ctll15, n1, n2, n3, n4, p5, p6, p7 etc.
|
||||
public Color getGradientByEnsembleId(String name) {
|
||||
|
||||
Color c = null;
|
||||
|
||||
float[] saturationSchedule = { 1.0f, 0.70f, 0.60f, 0.50f, 0.40f, 0.25f,
|
||||
0.15f };
|
||||
int pertNumber = getPerturbationIndex(name);
|
||||
int shiftedPertNum = 0;
|
||||
|
||||
Color startColor = null;
|
||||
// int totalSteps = 7;
|
||||
|
||||
// first model is NMM ...
|
||||
if ((pertNumber >= 1) && (pertNumber <= 7)) {
|
||||
startColor = nmm_color;
|
||||
c = getGradientColor(startColor, saturationSchedule[pertNumber - 1]);
|
||||
}
|
||||
|
||||
// second model is NMB ...
|
||||
if ((pertNumber >= 8) && (pertNumber <= 14)) {
|
||||
startColor = nmb_color;
|
||||
shiftedPertNum = pertNumber - 7;
|
||||
c = getGradientColor(startColor,
|
||||
saturationSchedule[(shiftedPertNum - 1)]);
|
||||
}
|
||||
|
||||
// third model is EM ...
|
||||
if ((pertNumber >= 15) && (pertNumber <= 21)) {
|
||||
startColor = em_color;
|
||||
shiftedPertNum = pertNumber - 14;
|
||||
c = getGradientColor(startColor,
|
||||
saturationSchedule[(shiftedPertNum - 1)]);
|
||||
}
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Color getGradientColor(Color c, int totalSteps, int currStep) {
|
||||
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = (float) currStep / (float) totalSteps;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
return SWTResourceManager.getColor(nrgb);
|
||||
}
|
||||
|
||||
private Color getGradientColor(Color c, float ratio) {
|
||||
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = ratio;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
return SWTResourceManager.getColor(nrgb);
|
||||
}
|
||||
|
||||
public String getPerturbationPrefix(String member) {
|
||||
return member.replaceAll("[0-9]", "");
|
||||
}
|
||||
|
||||
public int getPerturbationIndex(String member) {
|
||||
|
||||
String pertNumStr = member.replaceAll("[^0-9]", "");
|
||||
int pert = Integer.parseInt(pertNumStr);
|
||||
return pert;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.ColorDialog;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import com.raytheon.viz.ui.dialogs.CaveJFACEDialog;
|
||||
|
||||
/**
|
||||
* This class is a Dialog which allows users to change the colors of the GFS
|
||||
* ensemble perturbation members. It is used as a convenience feature to make it
|
||||
* easy to create a gradient of colors given a base color.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleGEFSColorChooser extends CaveJFACEDialog {
|
||||
|
||||
/**
|
||||
* Create the dialog.
|
||||
*
|
||||
* @param parentShell
|
||||
*/
|
||||
public EnsembleGEFSColorChooser(Shell parentShell) {
|
||||
super(parentShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contents of the dialog.
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
|
||||
Composite container = (Composite) super.createDialogArea(parent);
|
||||
GridLayout gridLayout = (GridLayout) container.getLayout();
|
||||
gridLayout.numColumns = 5;
|
||||
gridLayout.makeColumnsEqualWidth = false;
|
||||
|
||||
Label label_modelName_GEFS = new Label(container, SWT.BORDER
|
||||
| SWT.CENTER);
|
||||
label_modelName_GEFS.setAlignment(SWT.CENTER);
|
||||
GridData gd_label_modelName_GEFS = new GridData(SWT.CENTER, SWT.CENTER,
|
||||
false, false, 1, 1);
|
||||
gd_label_modelName_GEFS.heightHint = 20;
|
||||
gd_label_modelName_GEFS.widthHint = 40;
|
||||
label_modelName_GEFS.setLayoutData(gd_label_modelName_GEFS);
|
||||
label_modelName_GEFS.setText("GEFS");
|
||||
|
||||
Label label_colon_GEFS = new Label(container, SWT.NONE);
|
||||
label_colon_GEFS.setText(":");
|
||||
|
||||
final Composite label_color_GEFS = new Composite(container, SWT.BORDER);
|
||||
label_color_GEFS.setForeground(ChosenGEFSColors.getInstance()
|
||||
.getColor());
|
||||
label_color_GEFS.setBackground(SWTResourceManager.WHITE);
|
||||
GridData gd_label_color_GEFS = new GridData(SWT.LEFT, SWT.CENTER,
|
||||
false, false, 3, 1);
|
||||
gd_label_color_GEFS.heightHint = 24;
|
||||
gd_label_color_GEFS.widthHint = 116;
|
||||
gd_label_color_GEFS.minimumWidth = 116;
|
||||
gd_label_color_GEFS.minimumHeight = 24;
|
||||
label_color_GEFS.setLayoutData(gd_label_color_GEFS);
|
||||
label_color_GEFS.setSize(116, 24);
|
||||
applyGradientBG(label_color_GEFS);
|
||||
label_color_GEFS.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
|
||||
ColorDialog cd = new ColorDialog(getShell());
|
||||
cd.setRGB(ChosenGEFSColors.getInstance().getColor().getRGB());
|
||||
cd.setText("Choose GEFS lower color");
|
||||
RGB result = cd.open();
|
||||
if (result != null) {
|
||||
Color c = SWTResourceManager.getColor(result);
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = 1.0f;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
Color nc = SWTResourceManager.getColor(nrgb);
|
||||
ChosenGEFSColors.getInstance().setColor(nc);
|
||||
label_color_GEFS.setForeground(nc);
|
||||
applyGradientBG(label_color_GEFS);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
container.pack();
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
private static Image oldImage = null;
|
||||
|
||||
public static void applyGradientBG(Composite c) {
|
||||
|
||||
Rectangle rect = c.getClientArea();
|
||||
Image newImage = new Image(c.getDisplay(), rect.width, rect.height);
|
||||
GC gc = new GC(newImage);
|
||||
gc.setBackground(SWTResourceManager.WHITE);
|
||||
gc.fillRectangle(0, 0, rect.width, rect.height);
|
||||
gc.setForeground(c.getForeground());
|
||||
gc.setBackground(c.getBackground());
|
||||
gc.fillGradientRectangle(0, 0, rect.width, rect.height, false);
|
||||
c.setBackgroundImage(newImage);
|
||||
gc.dispose();
|
||||
|
||||
if (oldImage != null) {
|
||||
oldImage.dispose();
|
||||
oldImage = newImage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contents of the button bar.
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
protected void createButtonsForButtonBar(Composite parent) {
|
||||
|
||||
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
|
||||
true);
|
||||
createButton(parent, IDialogConstants.CANCEL_ID,
|
||||
IDialogConstants.CANCEL_LABEL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureShell(Shell newShell) {
|
||||
super.configureShell(newShell);
|
||||
newShell.setText("Choose Color Range");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.ColorDialog;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import com.raytheon.viz.ui.dialogs.CaveJFACEDialog;
|
||||
|
||||
/**
|
||||
* This class is a Dialog which allows users to change the colors of the SREF
|
||||
* ensemble perturbation members. It is used as a convenience feature to make it
|
||||
* easy to create a gradient of colors given a base color.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EnsembleSREFColorChooser extends CaveJFACEDialog {
|
||||
|
||||
/**
|
||||
* Create the dialog.
|
||||
*
|
||||
* @param parentShell
|
||||
*/
|
||||
public EnsembleSREFColorChooser(Shell parentShell) {
|
||||
super(parentShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contents of the dialog.
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
|
||||
Composite container = (Composite) super.createDialogArea(parent);
|
||||
GridLayout gridLayout = (GridLayout) container.getLayout();
|
||||
gridLayout.numColumns = 5;
|
||||
gridLayout.makeColumnsEqualWidth = false;
|
||||
|
||||
Label label_modelName_NMM = new Label(container, SWT.BORDER
|
||||
| SWT.CENTER);
|
||||
label_modelName_NMM.setAlignment(SWT.CENTER);
|
||||
GridData gd_label_modelName_NMM = new GridData(SWT.CENTER, SWT.CENTER,
|
||||
false, false, 1, 1);
|
||||
gd_label_modelName_NMM.heightHint = 20;
|
||||
gd_label_modelName_NMM.widthHint = 40;
|
||||
label_modelName_NMM.setLayoutData(gd_label_modelName_NMM);
|
||||
label_modelName_NMM.setText("NMM");
|
||||
|
||||
Label label_colon_NMM = new Label(container, SWT.NONE);
|
||||
label_colon_NMM.setText(":");
|
||||
|
||||
final Composite label_color_NMM = new Composite(container, SWT.BORDER);
|
||||
label_color_NMM.setForeground(ChosenSREFColors.getInstance()
|
||||
.get_NMM_color());
|
||||
label_color_NMM.setBackground(SWTResourceManager.WHITE);
|
||||
GridData gd_label_color_NMM = new GridData(SWT.LEFT, SWT.CENTER, false,
|
||||
false, 3, 1);
|
||||
gd_label_color_NMM.heightHint = 24;
|
||||
gd_label_color_NMM.widthHint = 116;
|
||||
gd_label_color_NMM.minimumWidth = 116;
|
||||
gd_label_color_NMM.minimumHeight = 24;
|
||||
label_color_NMM.setLayoutData(gd_label_color_NMM);
|
||||
label_color_NMM.setSize(116, 24);
|
||||
applyGradientBG(label_color_NMM);
|
||||
label_color_NMM.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
|
||||
ColorDialog cd = new ColorDialog(getShell());
|
||||
cd.setRGB(ChosenSREFColors.getInstance().get_NMM_color()
|
||||
.getRGB());
|
||||
cd.setText("Choose SREF-NMM color");
|
||||
RGB result = cd.open();
|
||||
if (result != null) {
|
||||
Color c = SWTResourceManager.getColor(result);
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = 1.0f;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
Color nc = SWTResourceManager.getColor(nrgb);
|
||||
ChosenSREFColors.getInstance().set_NMM_color(nc);
|
||||
label_color_NMM.setForeground(nc);
|
||||
applyGradientBG(label_color_NMM);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Label label_modelName_NMB = new Label(container, SWT.BORDER
|
||||
| SWT.CENTER);
|
||||
label_modelName_NMB.setAlignment(SWT.CENTER);
|
||||
GridData gd_label_modelName_NMB = new GridData(SWT.CENTER, SWT.CENTER,
|
||||
false, false, 1, 1);
|
||||
gd_label_modelName_NMB.heightHint = 20;
|
||||
gd_label_modelName_NMB.widthHint = 40;
|
||||
label_modelName_NMB.setLayoutData(gd_label_modelName_NMB);
|
||||
label_modelName_NMB.setText("NMB");
|
||||
|
||||
Label label_colon_NMB = new Label(container, SWT.NONE);
|
||||
label_colon_NMB.setText(":");
|
||||
|
||||
final Composite label_color_NMB = new Composite(container, SWT.BORDER);
|
||||
label_color_NMB.setForeground(ChosenSREFColors.getInstance()
|
||||
.get_NMB_color());
|
||||
label_color_NMB.setBackground(SWTResourceManager.WHITE);
|
||||
GridData gd_label_color_NMB = new GridData(SWT.LEFT, SWT.CENTER, false,
|
||||
false, 3, 1);
|
||||
gd_label_color_NMB.heightHint = 24;
|
||||
gd_label_color_NMB.widthHint = 116;
|
||||
gd_label_color_NMB.minimumWidth = 116;
|
||||
gd_label_color_NMB.minimumHeight = 24;
|
||||
label_color_NMB.setLayoutData(gd_label_color_NMB);
|
||||
label_color_NMB.setSize(116, 24);
|
||||
applyGradientBG(label_color_NMB);
|
||||
label_color_NMB.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
|
||||
ColorDialog cd = new ColorDialog(getShell());
|
||||
cd.setRGB(ChosenSREFColors.getInstance().get_NMB_color()
|
||||
.getRGB());
|
||||
cd.setText("Choose SREF-NMB color");
|
||||
RGB result = cd.open();
|
||||
if (result != null) {
|
||||
Color c = SWTResourceManager.getColor(result);
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = 1.0f;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
Color nc = SWTResourceManager.getColor(nrgb);
|
||||
ChosenSREFColors.getInstance().set_NMB_color(nc);
|
||||
label_color_NMB.setForeground(nc);
|
||||
applyGradientBG(label_color_NMB);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Label label_modelName_EM = new Label(container, SWT.BORDER | SWT.CENTER);
|
||||
label_modelName_EM.setAlignment(SWT.CENTER);
|
||||
GridData gd_label_modelName_EM = new GridData(SWT.CENTER, SWT.CENTER,
|
||||
false, false, 1, 1);
|
||||
gd_label_modelName_EM.heightHint = 20;
|
||||
gd_label_modelName_EM.widthHint = 40;
|
||||
label_modelName_EM.setLayoutData(gd_label_modelName_EM);
|
||||
label_modelName_EM.setText("EM");
|
||||
|
||||
Label label_colon_EM = new Label(container, SWT.NONE);
|
||||
label_colon_EM.setText(":");
|
||||
|
||||
final Composite label_color_EM = new Composite(container, SWT.BORDER);
|
||||
label_color_EM.setForeground(ChosenSREFColors.getInstance()
|
||||
.get_EM_color());
|
||||
label_color_EM.setBackground(SWTResourceManager.WHITE);
|
||||
GridData gd_label_color_EM = new GridData(SWT.LEFT, SWT.CENTER, false,
|
||||
false, 3, 1);
|
||||
gd_label_color_EM.heightHint = 24;
|
||||
gd_label_color_EM.widthHint = 116;
|
||||
gd_label_color_EM.minimumWidth = 116;
|
||||
gd_label_color_EM.minimumHeight = 24;
|
||||
label_color_EM.setLayoutData(gd_label_color_EM);
|
||||
label_color_EM.setSize(116, 24);
|
||||
applyGradientBG(label_color_EM);
|
||||
|
||||
label_color_EM.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
|
||||
ColorDialog cd = new ColorDialog(getShell());
|
||||
cd.setRGB(ChosenSREFColors.getInstance().get_EM_color()
|
||||
.getRGB());
|
||||
cd.setText("Choose SREF-EM color");
|
||||
RGB result = cd.open();
|
||||
if (result != null) {
|
||||
Color c = SWTResourceManager.getColor(result);
|
||||
RGB rgb = c.getRGB();
|
||||
float[] hsb = rgb.getHSB();
|
||||
hsb[1] = 1.0f;
|
||||
RGB nrgb = new RGB(hsb[0], hsb[1], hsb[2]);
|
||||
Color nc = SWTResourceManager.getColor(nrgb);
|
||||
ChosenSREFColors.getInstance().set_EM_color(nc);
|
||||
label_color_EM.setForeground(nc);
|
||||
applyGradientBG(label_color_EM);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
container.pack();
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
private static Image oldImage = null;
|
||||
|
||||
public static void applyGradientBG(Composite c) {
|
||||
|
||||
Rectangle rect = c.getClientArea();
|
||||
Image newImage = new Image(c.getDisplay(), rect.width, rect.height);
|
||||
GC gc = new GC(newImage);
|
||||
gc.setBackground(SWTResourceManager.WHITE);
|
||||
gc.fillRectangle(0, 0, rect.width, rect.height);
|
||||
gc.setForeground(c.getForeground());
|
||||
gc.setBackground(c.getBackground());
|
||||
gc.fillGradientRectangle(0, 0, rect.width, rect.height, false);
|
||||
c.setBackgroundImage(newImage);
|
||||
gc.dispose();
|
||||
|
||||
if (oldImage != null) {
|
||||
oldImage.dispose();
|
||||
oldImage = newImage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contents of the button bar.
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
protected void createButtonsForButtonBar(Composite parent) {
|
||||
|
||||
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
|
||||
true);
|
||||
createButton(parent, IDialogConstants.CANCEL_ID,
|
||||
IDialogConstants.CANCEL_LABEL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureShell(Shell newShell) {
|
||||
super.configureShell(newShell);
|
||||
newShell.setText("Choose Color Range");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,497 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Google, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Google, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is automatically generated by Google's Windows Builder Pro.
|
||||
* It is made of of convenience utilites to make it easier for the developer
|
||||
* to create, manipulate, and dispose of images.
|
||||
*
|
||||
<pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov-23-2011 5056 epolster Initial Creation.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author epolster
|
||||
* @version 1
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.jface.resource.CompositeImageDescriptor;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* Utility class for managing OS resources associated with SWT/JFace controls
|
||||
* such as colors, fonts, images, etc.
|
||||
*
|
||||
* !!! IMPORTANT !!! Application code must explicitly invoke the
|
||||
* <code>dispose()</code> method to release the operating system resources
|
||||
* managed by cached objects when those objects and OS resources are no longer
|
||||
* needed (e.g. on application shutdown)
|
||||
*
|
||||
* This class may be freely distributed as part of any application or plugin.
|
||||
* <p>
|
||||
*
|
||||
* @author scheglov_ke
|
||||
* @author Dan Rubel
|
||||
*/
|
||||
public class ImageResourceManager extends SWTResourceManager {
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Image
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
private static Map<ImageDescriptor, Image> m_descriptorImageMap = new HashMap<ImageDescriptor, Image>();
|
||||
|
||||
/**
|
||||
* Returns an {@link ImageDescriptor} stored in the file at the specified
|
||||
* path relative to the specified class.
|
||||
*
|
||||
* @param clazz
|
||||
* the {@link Class} relative to which to find the image
|
||||
* descriptor.
|
||||
* @param path
|
||||
* the path to the image file.
|
||||
* @return the {@link ImageDescriptor} stored in the file at the specified
|
||||
* path.
|
||||
*/
|
||||
public static ImageDescriptor getImageDescriptor(Class<?> clazz, String path) {
|
||||
return ImageDescriptor.createFromFile(clazz, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ImageDescriptor} stored in the file at the specified
|
||||
* path.
|
||||
*
|
||||
* @param path
|
||||
* the path to the image file.
|
||||
* @return the {@link ImageDescriptor} stored in the file at the specified
|
||||
* path.
|
||||
*/
|
||||
public static ImageDescriptor getImageDescriptor(String path) {
|
||||
try {
|
||||
return ImageDescriptor
|
||||
.createFromURL(new File(path).toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} based on the specified {@link ImageDescriptor}.
|
||||
*
|
||||
* @param descriptor
|
||||
* the {@link ImageDescriptor} for the {@link Image}.
|
||||
* @return the {@link Image} based on the specified {@link ImageDescriptor}.
|
||||
*/
|
||||
public static Image getImage(ImageDescriptor descriptor) {
|
||||
if (descriptor == null) {
|
||||
return null;
|
||||
}
|
||||
Image image = m_descriptorImageMap.get(descriptor);
|
||||
if (image == null) {
|
||||
image = descriptor.createImage();
|
||||
m_descriptorImageMap.put(descriptor, image);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps images to decorated images.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} composed of a base image decorated by another
|
||||
* image.
|
||||
*
|
||||
* @param baseImage
|
||||
* the base {@link Image} that should be decorated.
|
||||
* @param decorator
|
||||
* the {@link Image} to decorate the base image.
|
||||
* @return {@link Image} The resulting decorated image.
|
||||
*/
|
||||
public static Image decorateImage(Image baseImage, Image decorator) {
|
||||
return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} composed of a base image decorated by another
|
||||
* image.
|
||||
*
|
||||
* @param baseImage
|
||||
* the base {@link Image} that should be decorated.
|
||||
* @param decorator
|
||||
* the {@link Image} to decorate the base image.
|
||||
* @param corner
|
||||
* the corner to place decorator image.
|
||||
* @return the resulting decorated {@link Image}.
|
||||
*/
|
||||
public static Image decorateImage(final Image baseImage,
|
||||
final Image decorator, final int corner) {
|
||||
if (corner <= 0 || corner >= LAST_CORNER_KEY) {
|
||||
throw new IllegalArgumentException("Wrong decorate corner");
|
||||
}
|
||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
|
||||
if (cornerDecoratedImageMap == null) {
|
||||
cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
|
||||
m_decoratedImageMap[corner] = cornerDecoratedImageMap;
|
||||
}
|
||||
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
|
||||
if (decoratedMap == null) {
|
||||
decoratedMap = new HashMap<Image, Image>();
|
||||
cornerDecoratedImageMap.put(baseImage, decoratedMap);
|
||||
}
|
||||
//
|
||||
Image result = decoratedMap.get(decorator);
|
||||
if (result == null) {
|
||||
final Rectangle bib = baseImage.getBounds();
|
||||
final Rectangle dib = decorator.getBounds();
|
||||
final Point baseImageSize = new Point(bib.width, bib.height);
|
||||
CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() {
|
||||
@Override
|
||||
protected void drawCompositeImage(int width, int height) {
|
||||
drawImage(baseImage.getImageData(), 0, 0);
|
||||
if (corner == TOP_LEFT) {
|
||||
drawImage(decorator.getImageData(), 0, 0);
|
||||
} else if (corner == TOP_RIGHT) {
|
||||
drawImage(decorator.getImageData(), bib.width
|
||||
- dib.width, 0);
|
||||
} else if (corner == BOTTOM_LEFT) {
|
||||
drawImage(decorator.getImageData(), 0, bib.height
|
||||
- dib.height);
|
||||
} else if (corner == BOTTOM_RIGHT) {
|
||||
drawImage(decorator.getImageData(), bib.width
|
||||
- dib.width, bib.height - dib.height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point getSize() {
|
||||
return baseImageSize;
|
||||
}
|
||||
};
|
||||
//
|
||||
result = compositImageDesc.createImage();
|
||||
decoratedMap.put(decorator, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose all of the cached images.
|
||||
*/
|
||||
public static void disposeImages() {
|
||||
SWTResourceManager.disposeImages();
|
||||
// dispose ImageDescriptor images
|
||||
{
|
||||
for (Iterator<Image> I = m_descriptorImageMap.values().iterator(); I
|
||||
.hasNext();) {
|
||||
I.next().dispose();
|
||||
}
|
||||
m_descriptorImageMap.clear();
|
||||
}
|
||||
// dispose decorated images
|
||||
for (int i = 0; i < m_decoratedImageMap.length; i++) {
|
||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
|
||||
if (cornerDecoratedImageMap != null) {
|
||||
for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap
|
||||
.values()) {
|
||||
for (Image image : decoratedMap.values()) {
|
||||
image.dispose();
|
||||
}
|
||||
decoratedMap.clear();
|
||||
}
|
||||
cornerDecoratedImageMap.clear();
|
||||
}
|
||||
}
|
||||
// dispose plugin images
|
||||
{
|
||||
for (Iterator<Image> I = m_URLImageMap.values().iterator(); I
|
||||
.hasNext();) {
|
||||
I.next().dispose();
|
||||
}
|
||||
m_URLImageMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Plugin images support
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Maps URL to images.
|
||||
*/
|
||||
private static Map<String, Image> m_URLImageMap = new HashMap<String, Image>();
|
||||
|
||||
/**
|
||||
* Provider for plugin resources, used by WindowBuilder at design time.
|
||||
*/
|
||||
public interface PluginResourceProvider {
|
||||
URL getEntry(String symbolicName, String path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instance of {@link PluginResourceProvider}, used by WindowBuilder at
|
||||
* design time.
|
||||
*/
|
||||
private static PluginResourceProvider m_designTimePluginResourceProvider = null;
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} based on a plugin and file path.
|
||||
*
|
||||
* @param plugin
|
||||
* the plugin {@link Object} containing the image
|
||||
* @param name
|
||||
* the path to the image within the plugin
|
||||
* @return the {@link Image} stored in the file at the specified path
|
||||
*
|
||||
* @deprecated Use {@link #getPluginImage(String, String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Image getPluginImage(Object plugin, String name) {
|
||||
try {
|
||||
URL url = getPluginImageURL(plugin, name);
|
||||
if (url != null) {
|
||||
return getPluginImageFromUrl(url);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} based on a {@link Bundle} and resource entry
|
||||
* path.
|
||||
*
|
||||
* @param symbolicName
|
||||
* the symbolic name of the {@link Bundle}.
|
||||
* @param path
|
||||
* the path of the resource entry.
|
||||
* @return the {@link Image} stored in the file at the specified path.
|
||||
*/
|
||||
public static Image getPluginImage(String symbolicName, String path) {
|
||||
try {
|
||||
URL url = getPluginImageURL(symbolicName, path);
|
||||
if (url != null) {
|
||||
return getPluginImageFromUrl(url);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} based on given {@link URL}.
|
||||
*/
|
||||
private static Image getPluginImageFromUrl(URL url) {
|
||||
try {
|
||||
try {
|
||||
String key = url.toExternalForm();
|
||||
Image image = m_URLImageMap.get(key);
|
||||
if (image == null) {
|
||||
InputStream stream = url.openStream();
|
||||
try {
|
||||
image = getImage(stream);
|
||||
m_URLImageMap.put(key, image);
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
return image;
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ImageDescriptor} based on a plugin and file path.
|
||||
*
|
||||
* @param plugin
|
||||
* the plugin {@link Object} containing the image.
|
||||
* @param name
|
||||
* the path to th eimage within the plugin.
|
||||
* @return the {@link ImageDescriptor} stored in the file at the specified
|
||||
* path.
|
||||
*
|
||||
* @deprecated Use {@link #getPluginImageDescriptor(String, String)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static ImageDescriptor getPluginImageDescriptor(Object plugin,
|
||||
String name) {
|
||||
try {
|
||||
try {
|
||||
URL url = getPluginImageURL(plugin, name);
|
||||
return ImageDescriptor.createFromURL(url);
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource
|
||||
* entry path.
|
||||
*
|
||||
* @param symbolicName
|
||||
* the symbolic name of the {@link Bundle}.
|
||||
* @param path
|
||||
* the path of the resource entry.
|
||||
* @return the {@link ImageDescriptor} based on a {@link Bundle} and
|
||||
* resource entry path.
|
||||
*/
|
||||
public static ImageDescriptor getPluginImageDescriptor(String symbolicName,
|
||||
String path) {
|
||||
try {
|
||||
URL url = getPluginImageURL(symbolicName, path);
|
||||
if (url != null) {
|
||||
return ImageDescriptor.createFromURL(url);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link URL} based on a {@link Bundle} and resource entry path.
|
||||
*/
|
||||
private static URL getPluginImageURL(String symbolicName, String path) {
|
||||
// try runtime plugins
|
||||
{
|
||||
Bundle bundle = Platform.getBundle(symbolicName);
|
||||
if (bundle != null) {
|
||||
return bundle.getEntry(path);
|
||||
}
|
||||
}
|
||||
// try design time provider
|
||||
if (m_designTimePluginResourceProvider != null) {
|
||||
return m_designTimePluginResourceProvider.getEntry(symbolicName,
|
||||
path);
|
||||
}
|
||||
// no such resource
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link URL} based on a plugin and file path.
|
||||
*
|
||||
* @param plugin
|
||||
* the plugin {@link Object} containing the file path.
|
||||
* @param name
|
||||
* the file path.
|
||||
* @return the {@link URL} representing the file at the specified path.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static URL getPluginImageURL(Object plugin, String name)
|
||||
throws Exception {
|
||||
// try to work with 'plugin' as with OSGI BundleContext
|
||||
try {
|
||||
Class<?> BundleClass = Class.forName("org.osgi.framework.Bundle"); //$NON-NLS-1$
|
||||
Class<?> BundleContextClass = Class
|
||||
.forName("org.osgi.framework.BundleContext"); //$NON-NLS-1$
|
||||
if (BundleContextClass.isAssignableFrom(plugin.getClass())) {
|
||||
Method getBundleMethod = BundleContextClass.getMethod(
|
||||
"getBundle", new Class[0]); //$NON-NLS-1$
|
||||
Object bundle = getBundleMethod.invoke(plugin, new Object[0]);
|
||||
//
|
||||
Class<?> PathClass = Class
|
||||
.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
|
||||
Constructor<?> pathConstructor = PathClass
|
||||
.getConstructor(new Class[] { String.class });
|
||||
Object path = pathConstructor
|
||||
.newInstance(new Object[] { name });
|
||||
//
|
||||
Class<?> IPathClass = Class
|
||||
.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
|
||||
Class<?> PlatformClass = Class
|
||||
.forName("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$
|
||||
Method findMethod = PlatformClass.getMethod(
|
||||
"find", new Class[] { BundleClass, IPathClass }); //$NON-NLS-1$
|
||||
return (URL) findMethod.invoke(null, new Object[] { bundle,
|
||||
path });
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore any exceptions
|
||||
}
|
||||
// else work with 'plugin' as with usual Eclipse plugin
|
||||
{
|
||||
Class<?> PluginClass = Class
|
||||
.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$
|
||||
if (PluginClass.isAssignableFrom(plugin.getClass())) {
|
||||
//
|
||||
Class<?> PathClass = Class
|
||||
.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
|
||||
Constructor<?> pathConstructor = PathClass
|
||||
.getConstructor(new Class[] { String.class });
|
||||
Object path = pathConstructor
|
||||
.newInstance(new Object[] { name });
|
||||
//
|
||||
Class<?> IPathClass = Class
|
||||
.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
|
||||
Method findMethod = PluginClass.getMethod(
|
||||
"find", new Class[] { IPathClass }); //$NON-NLS-1$
|
||||
return (URL) findMethod.invoke(plugin, new Object[] { path });
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// General
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Dispose of cached objects and their underlying OS resources. This should
|
||||
* only be called when the cached objects are no longer needed (e.g. on
|
||||
* application shutdown).
|
||||
*/
|
||||
public static void dispose() {
|
||||
disposeColors();
|
||||
disposeFonts();
|
||||
disposeImages();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,657 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Google, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Google, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is automatically generated by Google's Windows Builder Pro.
|
||||
* It is made of of convenience utilites to make it easier for the developer
|
||||
* to create, manipulate, and dispose of colors and fonts.
|
||||
|
||||
*
|
||||
<pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec-9-2011 5056 epolster Initial Creation.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author epolster
|
||||
* @version 1
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Cursor;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.FontData;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.ImageData;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
|
||||
/**
|
||||
* Utility class for managing OS resources associated with SWT controls such as
|
||||
* colors, fonts, images, etc.
|
||||
* <p>
|
||||
* !!! IMPORTANT !!! Application code must explicitly invoke the
|
||||
* <code>dispose()</code> method to release the operating system resources
|
||||
* managed by cached objects when those objects and OS resources are no longer
|
||||
* needed (e.g. on application shutdown)
|
||||
* <p>
|
||||
* This class may be freely distributed as part of any application or plugin.
|
||||
* <p>
|
||||
*
|
||||
* @author scheglov_ke
|
||||
* @author Dan Rubel
|
||||
*/
|
||||
public class SWTResourceManager {
|
||||
|
||||
private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>();
|
||||
|
||||
public static final Color NEAR_WHITE = SWTResourceManager.getColor(new RGB(
|
||||
240, 240, 240));
|
||||
|
||||
public static final Color LIGHTER_GRAY = SWTResourceManager
|
||||
.getColor(new RGB(216, 216, 216));
|
||||
|
||||
public static final Color LIGHT_GRAY = SWTResourceManager.getColor(new RGB(
|
||||
210, 210, 210));
|
||||
|
||||
public static final Color MEDIUM_GRAY = SWTResourceManager
|
||||
.getColor(new RGB(160, 160, 160));
|
||||
|
||||
public static final Color DARKER_GRAY = SWTResourceManager
|
||||
.getColor(new RGB(130, 130, 130));
|
||||
|
||||
public static final Color BRIGHT_YELLOW = SWTResourceManager
|
||||
.getColor(new RGB(255, 255, 0));
|
||||
|
||||
public static final Color LIGHTER_YELLOW = SWTResourceManager
|
||||
.getColor(new RGB(255, 255, 102));
|
||||
|
||||
public static final Color PALE_DULL_YELLOW = SWTResourceManager
|
||||
.getColor(new RGB(255, 255, 150));
|
||||
|
||||
public static final Color LIGHT_YELLOW = SWTResourceManager
|
||||
.getColor(new RGB(255, 255, 220));
|
||||
|
||||
public static final Color PALE_DULL_ORANGE = SWTResourceManager
|
||||
.getColor(new RGB(255, 204, 153));
|
||||
|
||||
public static final Color PALE_LIGHT_AZURE = SWTResourceManager
|
||||
.getColor(new RGB(215, 239, 255));
|
||||
|
||||
public static final Color PALE_DULL_AZURE = SWTResourceManager
|
||||
.getColor(new RGB(168, 215, 255));
|
||||
|
||||
public static final Color PALE_WEAK_MAGENTA = SWTResourceManager
|
||||
.getColor(new RGB(255, 204, 255));
|
||||
|
||||
public static final Color PALE_WEAK_GREEN = SWTResourceManager
|
||||
.getColor(new RGB(204, 255, 204));
|
||||
|
||||
public static final Color PALE_WEAK_BLUE = SWTResourceManager
|
||||
.getColor(new RGB(203, 229, 255));
|
||||
|
||||
public static final Color PASTEL_LIGHT_BLUE = SWTResourceManager
|
||||
.getColor(new RGB(134, 181, 245));
|
||||
|
||||
public static final Color PALE_DULL_VIOLET = SWTResourceManager
|
||||
.getColor(new RGB(204, 204, 255));
|
||||
|
||||
public static final Color WHITE = SWTResourceManager.getColor(new RGB(255,
|
||||
255, 255));
|
||||
|
||||
public static final Color BLACK = SWTResourceManager.getColor(new RGB(0, 0,
|
||||
0));
|
||||
|
||||
// Crayola Colors ...
|
||||
public static final Color BLUE = SWTResourceManager.getColor(new RGB(31,
|
||||
117, 254));
|
||||
|
||||
public static final Color SLATE_BLUE = SWTResourceManager.getColor(new RGB(
|
||||
0, 153, 255));
|
||||
|
||||
public static final Color CERULEAN = SWTResourceManager.getColor(new RGB(
|
||||
29, 172, 214));
|
||||
|
||||
public static final Color GREEN = SWTResourceManager.getColor(new RGB(0,
|
||||
204, 0));
|
||||
|
||||
public static final Color CARIBBEAN_GREEN = SWTResourceManager
|
||||
.getColor(new RGB(0, 204, 153));
|
||||
|
||||
public static final Color SLATE_GREEN = SWTResourceManager
|
||||
.getColor(new RGB(51, 153, 102));
|
||||
|
||||
public static final Color SEA_GREEN = SWTResourceManager.getColor(new RGB(
|
||||
51, 204, 204));
|
||||
|
||||
public static final Color LIGHT_OLIVE = SWTResourceManager
|
||||
.getColor(new RGB(153, 204, 0));
|
||||
|
||||
public static final Color YELLOW = SWTResourceManager.getColor(new RGB(255,
|
||||
255, 102));
|
||||
|
||||
public static final Color ATOMIC_TANGERINE = SWTResourceManager
|
||||
.getColor(new RGB(255, 164, 116));
|
||||
|
||||
public static final Color BURNT_ORANGE = SWTResourceManager
|
||||
.getColor(new RGB(255, 127, 73));
|
||||
|
||||
public static final Color NEON_CARROT = SWTResourceManager
|
||||
.getColor(new RGB(255, 163, 67));
|
||||
|
||||
public static final Color PEACH = SWTResourceManager.getColor(new RGB(255,
|
||||
204, 153));
|
||||
|
||||
public static final Color RED = SWTResourceManager.getColor(new RGB(255,
|
||||
51, 0));
|
||||
|
||||
public static final Color SLATE_RED = SWTResourceManager.getColor(new RGB(
|
||||
255, 153, 153));
|
||||
|
||||
public static final Color WILD_WATERMELON = SWTResourceManager
|
||||
.getColor(new RGB(252, 108, 133));
|
||||
|
||||
public static final Color PINK_FLAMINGO = SWTResourceManager
|
||||
.getColor(new RGB(252, 116, 253));
|
||||
|
||||
public static final Color HOT_MAGENTA = SWTResourceManager
|
||||
.getColor(new RGB(252, 29, 206));
|
||||
|
||||
public static final Color PURPLE = SWTResourceManager.getColor(new RGB(153,
|
||||
51, 255));
|
||||
|
||||
public static final Color SEPIA = SWTResourceManager.getColor(new RGB(165,
|
||||
105, 79));
|
||||
|
||||
public static final Color NEON_PURPLE = SWTResourceManager
|
||||
.getColor(new RGB(217, 0, 255));
|
||||
|
||||
public static final Color CHERRY_RED = SWTResourceManager.getColor(new RGB(
|
||||
255, 0, 31));
|
||||
|
||||
public static final Color SPRING_GREEN = SWTResourceManager
|
||||
.getColor(new RGB(0, 204, 68));
|
||||
|
||||
public static final Color DEEP_BLUE = SWTResourceManager.getColor(new RGB(
|
||||
3, 2, 255));
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Color
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Returns the system {@link Color} matching the specific ID. The color is a
|
||||
* system color so should never be disposed of by the caller.
|
||||
*
|
||||
* @param systemColorID
|
||||
* the ID value for the color
|
||||
* @return the system {@link Color} matching the specific ID
|
||||
*/
|
||||
public static Color getSystemColor(int systemColorID) {
|
||||
Display display = Display.getCurrent();
|
||||
return display.getSystemColor(systemColorID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Color} given its red, green and blue component values.
|
||||
*
|
||||
* @param r
|
||||
* the red component of the color
|
||||
* @param g
|
||||
* the green component of the color
|
||||
* @param b
|
||||
* the blue component of the color
|
||||
* @return the {@link Color} matching the given red, green and blue
|
||||
* component values
|
||||
*/
|
||||
public static Color getColor(int r, int g, int b) {
|
||||
return getColor(new RGB(r, g, b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Color} given its RGB value.
|
||||
*
|
||||
* @param rgb
|
||||
* the {@link RGB} value of the color
|
||||
* @return the {@link Color} matching the RGB value
|
||||
*/
|
||||
public static Color getColor(RGB rgb) {
|
||||
Color color = m_colorMap.get(rgb);
|
||||
if (color == null) {
|
||||
Display display = Display.getCurrent();
|
||||
color = new Color(display, rgb);
|
||||
m_colorMap.put(rgb, color);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose of all the cached {@link Color}'s.
|
||||
*/
|
||||
public static void disposeColors() {
|
||||
for (Color color : m_colorMap.values()) {
|
||||
color.dispose();
|
||||
}
|
||||
m_colorMap.clear();
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Image
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Maps image paths to images.
|
||||
*/
|
||||
private static Map<String, Image> m_imageMap = new HashMap<String, Image>();
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} encoded by the specified {@link InputStream}.
|
||||
*
|
||||
* @param stream
|
||||
* the {@link InputStream} encoding the image data
|
||||
* @return the {@link Image} encoded by the specified input stream
|
||||
*/
|
||||
protected static Image getImage(InputStream stream) throws IOException {
|
||||
try {
|
||||
Display display = Display.getCurrent();
|
||||
ImageData data = new ImageData(stream);
|
||||
if (data.transparentPixel > 0) {
|
||||
return new Image(display, data, data.getTransparencyMask());
|
||||
}
|
||||
return new Image(display, data);
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} stored in the file at the specified path.
|
||||
*
|
||||
* @param path
|
||||
* the path to the image file
|
||||
* @return the {@link Image} stored in the file at the specified path
|
||||
*/
|
||||
public static Image getImage(String path) {
|
||||
Image image = m_imageMap.get(path);
|
||||
if (image == null) {
|
||||
try {
|
||||
image = getImage(new FileInputStream(path));
|
||||
m_imageMap.put(path, image);
|
||||
} catch (Exception e) {
|
||||
image = getMissingImage();
|
||||
m_imageMap.put(path, image);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} stored in the file at the specified path
|
||||
* relative to the specified class.
|
||||
*
|
||||
* @param clazz
|
||||
* the {@link Class} relative to which to find the image
|
||||
* @param path
|
||||
* the path to the image file, if starts with <code>'/'</code>
|
||||
* @return the {@link Image} stored in the file at the specified path
|
||||
*/
|
||||
public static Image getImage(Class<?> clazz, String path) {
|
||||
String key = clazz.getName() + '|' + path;
|
||||
Image image = m_imageMap.get(key);
|
||||
if (image == null) {
|
||||
try {
|
||||
image = getImage(clazz.getResourceAsStream(path));
|
||||
m_imageMap.put(key, image);
|
||||
} catch (Exception e) {
|
||||
image = getMissingImage();
|
||||
m_imageMap.put(key, image);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private static final int MISSING_IMAGE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* @return the small {@link Image} that can be used as placeholder for
|
||||
* missing image.
|
||||
*/
|
||||
private static Image getMissingImage() {
|
||||
Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE,
|
||||
MISSING_IMAGE_SIZE);
|
||||
//
|
||||
GC gc = new GC(image);
|
||||
gc.setBackground(getSystemColor(SWT.COLOR_RED));
|
||||
gc.fillRectangle(0, 0, MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE);
|
||||
gc.dispose();
|
||||
//
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style constant for placing decorator image in top left corner of base
|
||||
* image.
|
||||
*/
|
||||
public static final int TOP_LEFT = 1;
|
||||
|
||||
/**
|
||||
* Style constant for placing decorator image in top right corner of base
|
||||
* image.
|
||||
*/
|
||||
public static final int TOP_RIGHT = 2;
|
||||
|
||||
/**
|
||||
* Style constant for placing decorator image in bottom left corner of base
|
||||
* image.
|
||||
*/
|
||||
public static final int BOTTOM_LEFT = 3;
|
||||
|
||||
/**
|
||||
* Style constant for placing decorator image in bottom right corner of base
|
||||
* image.
|
||||
*/
|
||||
public static final int BOTTOM_RIGHT = 4;
|
||||
|
||||
/**
|
||||
* Internal value.
|
||||
*/
|
||||
protected static final int LAST_CORNER_KEY = 5;
|
||||
|
||||
/**
|
||||
* Maps images to decorated images.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} composed of a base image decorated by another
|
||||
* image.
|
||||
*
|
||||
* @param baseImage
|
||||
* the base {@link Image} that should be decorated
|
||||
* @param decorator
|
||||
* the {@link Image} to decorate the base image
|
||||
* @return {@link Image} The resulting decorated image
|
||||
*/
|
||||
public static Image decorateImage(Image baseImage, Image decorator) {
|
||||
return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Image} composed of a base image decorated by another
|
||||
* image.
|
||||
*
|
||||
* @param baseImage
|
||||
* the base {@link Image} that should be decorated
|
||||
* @param decorator
|
||||
* the {@link Image} to decorate the base image
|
||||
* @param corner
|
||||
* the corner to place decorator image
|
||||
* @return the resulting decorated {@link Image}
|
||||
*/
|
||||
public static Image decorateImage(final Image baseImage,
|
||||
final Image decorator, final int corner) {
|
||||
if (corner <= 0 || corner >= LAST_CORNER_KEY) {
|
||||
throw new IllegalArgumentException("Wrong decorate corner");
|
||||
}
|
||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
|
||||
if (cornerDecoratedImageMap == null) {
|
||||
cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
|
||||
m_decoratedImageMap[corner] = cornerDecoratedImageMap;
|
||||
}
|
||||
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
|
||||
if (decoratedMap == null) {
|
||||
decoratedMap = new HashMap<Image, Image>();
|
||||
cornerDecoratedImageMap.put(baseImage, decoratedMap);
|
||||
}
|
||||
//
|
||||
Image result = decoratedMap.get(decorator);
|
||||
if (result == null) {
|
||||
Rectangle bib = baseImage.getBounds();
|
||||
Rectangle dib = decorator.getBounds();
|
||||
//
|
||||
result = new Image(Display.getCurrent(), bib.width, bib.height);
|
||||
//
|
||||
GC gc = new GC(result);
|
||||
gc.drawImage(baseImage, 0, 0);
|
||||
if (corner == TOP_LEFT) {
|
||||
gc.drawImage(decorator, 0, 0);
|
||||
} else if (corner == TOP_RIGHT) {
|
||||
gc.drawImage(decorator, bib.width - dib.width, 0);
|
||||
} else if (corner == BOTTOM_LEFT) {
|
||||
gc.drawImage(decorator, 0, bib.height - dib.height);
|
||||
} else if (corner == BOTTOM_RIGHT) {
|
||||
gc.drawImage(decorator, bib.width - dib.width, bib.height
|
||||
- dib.height);
|
||||
}
|
||||
gc.dispose();
|
||||
//
|
||||
decoratedMap.put(decorator, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose all of the cached {@link Image}'s.
|
||||
*/
|
||||
public static void disposeImages() {
|
||||
// dispose loaded images
|
||||
{
|
||||
for (Image image : m_imageMap.values()) {
|
||||
image.dispose();
|
||||
}
|
||||
m_imageMap.clear();
|
||||
}
|
||||
// dispose decorated images
|
||||
for (int i = 0; i < m_decoratedImageMap.length; i++) {
|
||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
|
||||
if (cornerDecoratedImageMap != null) {
|
||||
for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap
|
||||
.values()) {
|
||||
for (Image image : decoratedMap.values()) {
|
||||
image.dispose();
|
||||
}
|
||||
decoratedMap.clear();
|
||||
}
|
||||
cornerDecoratedImageMap.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Font
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Maps font names to fonts.
|
||||
*/
|
||||
private static Map<String, Font> m_fontMap = new HashMap<String, Font>();
|
||||
|
||||
/**
|
||||
* Maps fonts to their bold versions.
|
||||
*/
|
||||
private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>();
|
||||
|
||||
/**
|
||||
* Returns a {@link Font} based on its name, height and style.
|
||||
*
|
||||
* @param name
|
||||
* the name of the font
|
||||
* @param height
|
||||
* the height of the font
|
||||
* @param style
|
||||
* the style of the font
|
||||
* @return {@link Font} The font matching the name, height and style
|
||||
*/
|
||||
public static Font getFont(String name, int height, int style) {
|
||||
return getFont(name, height, style, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Font} based on its name, height and style.
|
||||
* Windows-specific strikeout and underline flags are also supported.
|
||||
*
|
||||
* @param name
|
||||
* the name of the font
|
||||
* @param size
|
||||
* the size of the font
|
||||
* @param style
|
||||
* the style of the font
|
||||
* @param strikeout
|
||||
* the strikeout flag (warning: Windows only)
|
||||
* @param underline
|
||||
* the underline flag (warning: Windows only)
|
||||
* @return {@link Font} The font matching the name, height, style, strikeout
|
||||
* and underline
|
||||
*/
|
||||
public static Font getFont(String name, int size, int style,
|
||||
boolean strikeout, boolean underline) {
|
||||
String fontName = name + '|' + size + '|' + style + '|' + strikeout
|
||||
+ '|' + underline;
|
||||
Font font = m_fontMap.get(fontName);
|
||||
if (font == null) {
|
||||
FontData fontData = new FontData(name, size, style);
|
||||
if (strikeout || underline) {
|
||||
try {
|
||||
Class<?> logFontClass = Class
|
||||
.forName("org.eclipse.swt.internal.win32.LOGFONT"); //$NON-NLS-1$
|
||||
Object logFont = FontData.class
|
||||
.getField("data").get(fontData); //$NON-NLS-1$
|
||||
if (logFont != null && logFontClass != null) {
|
||||
if (strikeout) {
|
||||
logFontClass
|
||||
.getField("lfStrikeOut").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
|
||||
}
|
||||
if (underline) {
|
||||
logFontClass
|
||||
.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.err
|
||||
.println("Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
font = new Font(Display.getCurrent(), fontData);
|
||||
m_fontMap.put(fontName, font);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bold version of the given {@link Font}.
|
||||
*
|
||||
* @param baseFont
|
||||
* the {@link Font} for which a bold version is desired
|
||||
* @return the bold version of the given {@link Font}
|
||||
*/
|
||||
public static Font getBoldFont(Font baseFont) {
|
||||
Font font = m_fontToBoldFontMap.get(baseFont);
|
||||
if (font == null) {
|
||||
FontData fontDatas[] = baseFont.getFontData();
|
||||
FontData data = fontDatas[0];
|
||||
font = new Font(Display.getCurrent(), data.getName(),
|
||||
data.getHeight(), SWT.BOLD);
|
||||
m_fontToBoldFontMap.put(baseFont, font);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose all of the cached {@link Font}'s.
|
||||
*/
|
||||
public static void disposeFonts() {
|
||||
// clear fonts
|
||||
for (Font font : m_fontMap.values()) {
|
||||
font.dispose();
|
||||
}
|
||||
m_fontMap.clear();
|
||||
// clear bold fonts
|
||||
for (Font font : m_fontToBoldFontMap.values()) {
|
||||
font.dispose();
|
||||
}
|
||||
m_fontToBoldFontMap.clear();
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Cursor
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Maps IDs to cursors.
|
||||
*/
|
||||
private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>();
|
||||
|
||||
/**
|
||||
* Returns the system cursor matching the specific ID.
|
||||
*
|
||||
* @param id
|
||||
* int The ID value for the cursor
|
||||
* @return Cursor The system cursor matching the specific ID
|
||||
*/
|
||||
public static Cursor getCursor(int id) {
|
||||
Integer key = Integer.valueOf(id);
|
||||
Cursor cursor = m_idToCursorMap.get(key);
|
||||
if (cursor == null) {
|
||||
cursor = new Cursor(Display.getDefault(), id);
|
||||
m_idToCursorMap.put(key, cursor);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose all of the cached cursors.
|
||||
*/
|
||||
public static void disposeCursors() {
|
||||
for (Cursor cursor : m_idToCursorMap.values()) {
|
||||
cursor.dispose();
|
||||
}
|
||||
m_idToCursorMap.clear();
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// General
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Dispose of cached objects and their underlying OS resources. This should
|
||||
* only be called when the cached objects are no longer needed (e.g. on
|
||||
* application shutdown).
|
||||
*/
|
||||
public static void dispose() {
|
||||
disposeColors();
|
||||
disposeImages();
|
||||
disposeFonts();
|
||||
disposeCursors();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package gov.noaa.gsd.viz.ensemble.util;
|
||||
|
||||
/**
|
||||
<pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Nov-20-2011 epolster Initial Creation.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author epolster
|
||||
* @version 1
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
/**
|
||||
* Generic Utilities class to contain a hodge-podge of utility capabilties.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 8, 2014 5056 polster Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author polster
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Utilities {
|
||||
|
||||
private Utilities() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static String padRight(String s, int n) {
|
||||
return String.format("%1$-" + n + "s", s);
|
||||
}
|
||||
|
||||
public static String padLeft(String s, int n) {
|
||||
return String.format("%1$" + n + "s", s);
|
||||
}
|
||||
|
||||
public static String removeExtraSpaces(String source) {
|
||||
String result = source.replaceAll("\\s+", " ");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String trimQuotes(String pqs) {
|
||||
if (pqs.startsWith("\"")) {
|
||||
pqs = pqs.substring(1);
|
||||
}
|
||||
if (pqs.endsWith("\"")) {
|
||||
pqs = pqs.substring(0, pqs.length() - 1);
|
||||
}
|
||||
return pqs;
|
||||
}
|
||||
|
||||
public static RGB getRandomColor() {
|
||||
|
||||
Random rand = new Random();
|
||||
final int lowerFilter = 80;
|
||||
final int upperFilter = 200;
|
||||
final int skewToBrightness = 256 - upperFilter;
|
||||
|
||||
int r = rand.nextInt(upperFilter);
|
||||
if (r < lowerFilter)
|
||||
r = lowerFilter;
|
||||
|
||||
int g = rand.nextInt(upperFilter);
|
||||
if (g < lowerFilter)
|
||||
g = lowerFilter;
|
||||
|
||||
int b = rand.nextInt(upperFilter);
|
||||
if (b < lowerFilter)
|
||||
b = lowerFilter;
|
||||
|
||||
r += skewToBrightness;
|
||||
g += skewToBrightness;
|
||||
b += skewToBrightness;
|
||||
|
||||
return new RGB(r, g, b);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gradient between a color and White.
|
||||
*
|
||||
* @param color1
|
||||
* The color to gradiate.
|
||||
*
|
||||
* @param ratio
|
||||
* Blend ratio. 0.5 will give even blend, 1.0 will return color1,
|
||||
* 0.0 will return color2 and so on.
|
||||
* @return Blended color.
|
||||
*/
|
||||
public static Color gradient(Color color1, double ratio) {
|
||||
|
||||
float r = (float) ratio;
|
||||
float ir = (float) 1.0 - r;
|
||||
|
||||
RGB rgb1 = color1.getRGB();
|
||||
RGB rgb2 = SWTResourceManager.WHITE.getRGB();
|
||||
|
||||
int r1 = rgb1.red;
|
||||
int b1 = rgb1.blue;
|
||||
int g1 = rgb1.green;
|
||||
int red = 255;
|
||||
int blue = 255;
|
||||
int green = 255;
|
||||
|
||||
if ((b1 > r1) && (b1 > g1)) {
|
||||
red = (int) (rgb1.red * ir + rgb2.red * r);
|
||||
green = (int) (rgb1.green * ir + rgb2.green * r);
|
||||
blue = b1;
|
||||
} else if ((r1 > b1) && (r1 > g1)) {
|
||||
red = r1;
|
||||
blue = (int) (rgb1.blue * ir + rgb2.blue * r);
|
||||
green = (int) (rgb1.green * ir + rgb2.green * r);
|
||||
} else if ((g1 > b1) && (g1 > r1)) {
|
||||
red = (int) (rgb1.red * ir + rgb2.red * r);
|
||||
blue = (int) (rgb1.blue * ir + rgb2.blue * r);
|
||||
green = g1;
|
||||
} else {
|
||||
red = (int) (rgb1.red * ir + rgb2.red * r);
|
||||
blue = (int) (rgb1.blue * ir + rgb2.blue * r);
|
||||
green = (int) (rgb1.green * ir + rgb2.green * r);
|
||||
}
|
||||
|
||||
RGB blend = new RGB(red, blue, green);
|
||||
|
||||
Color color = SWTResourceManager.getColor(blend);
|
||||
return color;
|
||||
|
||||
}
|
||||
|
||||
}
|