12.10.1-3 baseline

Former-commit-id: de1639aea2 [formerly 21f430062b] [formerly de1639aea2 [formerly 21f430062b] [formerly 969e7e6dfd [formerly 1a94c1ca3674c8e4dbb8847de5190efe33da371c]]]
Former-commit-id: 969e7e6dfd
Former-commit-id: f376a4b4db [formerly 438d139fdd]
Former-commit-id: faadb51529
This commit is contained in:
Steve Harris 2012-09-11 16:00:38 -05:00
parent 5684a84a46
commit 5030894212
184 changed files with 13677 additions and 3204 deletions

View file

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

View file

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

View file

@ -0,0 +1,307 @@
# ----------------------------------------------------------------------------
# This software is in the public domain, furnished "as is", without technical
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#
# MakeHazard.py
#
# SOFTWARE HISTORY
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# Apr 03,2012 436 randerso Converted to Python procedure to allow some
# level of site customization
# Apr 09,2012 436 randerso Merged RNK's MakeHazards_Elevation procedure
#
# Author: randerso
# ----------------------------------------------------------------------------
# The MenuItems list defines the GFE menu item(s) under which the
# Procedure is to appear.
# Possible items are: Populate, Edit, Consistency, Verify, Hazards
MenuItems = ["Hazards"]
import SmartScript
import time, string, sys
import HazardUtils
import re
import numpy
import LogStream
import JUtil
class Procedure (SmartScript.SmartScript):
def __init__(self, dbss):
SmartScript.SmartScript.__init__(self, dbss)
self._dataManager = dbss
self._afterInit = 0 #flag indicating init is done.
self._tropicalHaz = ['HU.W','HU.A','HU.S','TR.W','TR.A']
self._natlBaseETN = 1001
def setUpUI(self):
if sys.modules.has_key("MakeHazardConfig"):
sys.modules.__delitem__("MakeHazardConfig")
import MakeHazardConfig
args = {}
args['dataManager'] = self._dataManager
args['selectedTimeRange'] = self.selectedTimeRange
args['mapColor'] = MakeHazardConfig.mapColor
args['defaultMapWidth'] = MakeHazardConfig.defaultMapWidth
args['timeScaleEndTime'] = MakeHazardConfig.timeScaleEndTime
args['areaThreshold'] = MakeHazardConfig.areaThreshold
args['defaultHazardType'] = MakeHazardConfig.defaultHazardType
args['mapNames'] = MakeHazardConfig.mapNames
args['hazardDict'] = MakeHazardConfig.hazardDict
args['tcmList'] = MakeHazardConfig.tcmList
args['tropicalHaz'] = self._tropicalHaz
args['natlBaseETN'] = self._natlBaseETN
if not hasattr(MakeHazardConfig, 'localEffectAreas') or \
MakeHazardConfig.localEffectAreas is None:
args['localEffectAreas'] = {}
else:
args['localEffectAreas'] = MakeHazardConfig.localEffectAreas
if not hasattr(MakeHazardConfig, 'localAreaData') or \
MakeHazardConfig.localAreaData is None:
args['localAreaData'] = {}
else:
args['localAreaData'] = MakeHazardConfig.localAreaData
# create the Java/SWT dialog and open it
from com.raytheon.viz.gfe.makehazard import MakeHazardDialog
self.__dlg = MakeHazardDialog.createFromPython(
JUtil.pyValToJavaObj(args)
)
self.__dlg.openFromPython()
# run the Java/SWT event loop
try:
dismiss = False
while not dismiss:
args = JUtil.javaObjToPyVal(self.__dlg.runFromPython(), converter)
dismiss = True;
# if args is None, then Cancel was pressed
if args is not None:
# dismiss is True if the Run/Dismiss button is pressed,
# false if Run is pressed
dismiss = args["dismiss"]
del args["dismiss"]
if self.makeHazardGrid(**args) != 1:
dismiss = False
finally:
# close the Java/SWT dialog when Cancelled, Dismissed or exception occurs
self.__dlg.closeFromPython()
# RJM modified this routine from the HazardUtility file
# returns a Numeric mask where each zone in zoneList is set to 1
def _makeMask(self, zoneList, hazLocalEffect):
# RJM had to modify this next line to point to the hazUtils
# for the getGridSize routine.
gridSize = self._hazUtils._getGridSize()
mask = numpy.zeros(gridSize)
eaList = self.editAreaList()
# Get the elevation from the GUI input. We'll do this by clipping
# of any numerical digits from the local effect.
# elevation_string = re.findall("\d+", hazLocalEffect)
# print "re elevation=", elevation_string, "xxx"
# try:
# elevation = elevation_string[0]
# except:
# elevation = "None"
# print "re elevation=", elevation, "xxx"
for z in zoneList:
print "in _makeMask processing zone ", z
if z in eaList:
zoneArea = self.getEditArea(z)
zoneMask = self.encodeEditArea(zoneArea)
# Code added by RJM. This checks to see if the local effect
# area was specified and is a valid edit area. If so,
# make a mask from it, and then do an intersection with
# the zone mask.
if hazLocalEffect in eaList:
print "Masking",z,"with",hazLocalEffect
localEffectArea = self.getEditArea(hazLocalEffect)
localEffectMask = self.encodeEditArea(localEffectArea)
zoneMask = numpy.logical_and(zoneMask, localEffectMask)
mask = numpy.logical_or(mask, zoneMask)
# else:
# if z in eaList:
# zoneArea = self.getEditArea(z)
# zoneMask = self.encodeEditArea(zoneArea)
# mask = numpy.logical_or(mask, zoneMask)
return mask
# Creates the hazard grid based on the dialog input
def makeHazardGrid(self, selectedHazard, timeRange, areaList, segmentNumber,
selectedTimeRange, defaultAreaList, defaultHazard, defaultSegment,
hazLocalEffect):
siteID = self.getSiteID()
usingHazLocalEffect = (hazLocalEffect != 'None')
if len(areaList) == 0:
editArea = self.getActiveEditArea()
mask = self.encodeEditArea(editArea)
else:
# make the mask based on the list selections
if not usingHazLocalEffect:
mask = self._hazUtils._makeMask(areaList)
else:
mask = self._makeMask(areaList, hazLocalEffect)
if usingHazLocalEffect:
# get the segment number and filter for valid characters
segNum = segmentNumber
# get the hazards currently defined as temporary grids
hazParms = self.getHazardParmNames()
# look through the list of grids and create a list of
# segment numbers (if any) that are already in use
# for the current hazard
# if len(hazParms) == 0:
# self.statusBarMsg("No temporary grids to merge.", "S")
# return 0
segList = []
print "selectedHazard=", selectedHazard
selectedPhen = selectedHazard[0:2]
selectedSig = selectedHazard[3]
print "selectedPhen,selectedSig=", selectedPhen, ".", selectedSig
for hazParm in hazParms:
print "hazParm=", hazParm
trList = self._hazUtils._getWEInventory(hazParm)
for tr in trList:
print " tr=", tr, timeRange
intersect_hours = tr.intersection(timeRange).duration()
print " intersect=", intersect_hours
intersect_percent = intersect_hours / timeRange.duration() * 100.0
print " intersect %=", intersect_percent
phen = hazParm[3:5]
sig = hazParm[5:6]
print "phen,sig=", phen, ".", sig
if len(hazParm) > 6:
if hazParm[6:].isdigit():
seg = int(hazParm[6:])
print " seg=", seg
if phen == selectedPhen and sig == selectedSig:
segList.append(seg)
print "appending ", seg
else:
seg = 0
segList.sort()
# print "looping through segList"
# for seg in segList:
# print " seg=", seg," elev=", elevation
# if str(elevation) == str(seg):
# print "adding 1 to elevation"
# elevation += 1
#
# if elevation > 400:
# print "using elevation for segNum"
# segNum = elevation
# # replace the segmentNumber field with the elevation +/- the Above/Below indicator.
# self.__dlg.setSegmentNumber(elevation)
# segmentNumber = str(elevation)
# print "*** segmentNumber=", segmentNumber
index = string.find(selectedHazard, " ")
if index != -1:
selectedHazard = selectedHazard[0:index]
if len(segmentNumber) > 0:
hazardKey = selectedHazard + ":" + segmentNumber
else:
hazardKey = selectedHazard
defaultHazKey = ""
if len(defaultSegment) > 0 and defaultHazard is not None:
defaultHazKey = defaultHazard + ":" + defaultSegment
weName = self._hazUtils._makeTempWEName(hazardKey)
# if we're modifying, remove the old grid first
if defaultAreaList != [] and hazardKey == defaultHazKey:
self.deleteCmd([weName], self.selectedTimeRange)
# if we have no selection prevent user from making an empty hazard
if 1 not in mask:
self.statusBarMsg("NO EDIT AREA SELECTED: \n Select area from map or load edit area in GFE!", "S")
return 0
self._hazUtils._addHazard(weName, timeRange, hazardKey, mask)
LogStream.logUse("Set: ", weName,
self._hazUtils._printTime(timeRange.startTime().unixTime()),
self._hazUtils._printTime(timeRange.endTime().unixTime()), hazardKey,
self._hazUtils._printAreas(areaList))
return 1
def getHazardParmNames(self):
# get the list of loaded temporary hazard parms
parms = self.loadedParms()
hazParms = []
for weName, level, dbID in parms:
if "haz" in weName:
key = self._hazUtils._tempWENameToKey(weName)
index = string.find(key, ":")
if index != -1:
mkey = key[0:index]
segNum = key[index+1:]
else:
mkey = key
segNum = ""
# append the hazard and a description
parmName = "haz" + key
parmName = string.replace(parmName, ".", "")
parmName = string.replace(parmName, ":", "")
hazParms.append(parmName)
return hazParms
def execute(self, timeRange):
#self._hazUtils = HazardUtils.HazardUtils(self._dataManager, self.eaMgr())
self._hazUtils = HazardUtils.HazardUtils(self._dataManager, None)
# save the selected timeRange
self.selectedTimeRange = timeRange
self.setToolType("numeric")
# see if the Hazards WE is loaded in the GFE, if not abort the tool
if not self._hazUtils._hazardsLoaded():
self.statusBarMsg("Hazards Weather Element must be loaded in " + \
"the GFE before running MakeHazard", "S")
self.cancel()
# always separate the Hazards grid first
self._hazUtils._separateHazardGrids()
self.setUpUI()
self._afterInit = 1 #initialization done
return
def converter(obj):
import AbsTime
import TimeRange
retVal = None
objtype = obj.jclassname
if objtype == "java.util.Date":
retVal = AbsTime.AbsTime(obj)
elif objtype == "com.raytheon.uf.common.time.TimeRange":
retVal = TimeRange.TimeRange(obj)
return retVal

View file

@ -1,157 +0,0 @@
##
# 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.
##
# AWIPS1 imports SmartScript to retrieve the site ID below, but
# since all we need is just that site ID, it makes more sense to
# import DataManager directly to get that rather than all of the
# SmartScript module
# import SmartScript
from com.raytheon.viz.gfe.core import DataManager
def sortHazardList(dict):
#sorts the entries in the menus in alphabetical order, returns sorted
#dictionary
import VTECTable
for ent in dict.keys():
values = dict[ent]
# get the descriptive word for this phen/sig
items = []
for v in values:
desc = VTECTable.VTECTable.get(v,'')
items.append((desc, v))
items.sort() #sorts by description
#extract out the sorted phen/sig
phensig = []
for desc, v in items:
phensig.append(v)
dict[ent] = phensig
return dict
###########################################################
############## ###############
############## CONFIGURATION SECTION ###############
############## ###############
# Lists of hazards organized by type in a dictionary
# Set these to value you use for your site. To minimize scrolling,
# change the order so that the most common values your site uses are
# near the front of each list. The key is the menu entry on the
# Make Hazard dialog, the values are the key values for Hazards.
siteID = DataManager.getCurrentInstance().getSiteID()
if siteID == "GUM":
hazardDict = {
'Hydrology' : ["FF.A", "FA.A"],
'Fire Weather' : ["FW.A", "FW.W"],
'Coastal Flood' : ["CF.S", "LS.S", "CF.Y", "CF.W", "CF.A",
"SU.Y", "SU.W", "LS.Y", "LS.W", "LS.A", "RP.S"],
'Non-Precipitation' : ["AF.W", "AF.Y", "AQ.Y", "AS.O", "AS.Y", "DU.Y",
"DS.W", "EH.W", "EH.A", "EC.W", "EC.A", "FG.Y", "FZ.W", "FZ.A",
"HZ.W", "HZ.A", "ZF.Y", "FR.Y", "HT.Y", "HW.W", "HW.A",
"LW.Y", "SM.Y", "WI.Y"],
'Marine' : ["MA.S", "MH.W", "MH.Y", "BW.Y", "UP.Y", "MF.Y",
"GL.A", "GL.W", "SE.A", "SE.W", "UP.A", "UP.W", "HF.A", "HF.W", "LO.Y", "SC.Y", "SW.Y",
"RB.Y", "SI.Y", "MS.Y", "SR.A", "SR.W"],
'Typhoon' : ["TY.A", "TY.W", "TR.A", "TR.W", "HU.S"],
'Tsunami' : ["TS.A", "TS.W"],
#'Local' : ["TEST"], #example of adding local hazards
# you can define your own groups of hazards by adding new categories
}
else:
hazardDict = {
'Winter Weather' : ["BZ.W", "BZ.A", "ZR.Y",
"IS.W", "LE.Y", "LE.W", "LE.A",
"WC.Y", "WC.W", "WC.A", "WS.W", "WS.A", "WW.Y"],
'Hydrology' : ["FF.A", "FA.A"],
'Fire Weather' : ["FW.A", "FW.W"],
'Convective Watches' : ["SV.A", "TO.A"],
'Coastal Flood' : ["CF.S", "LS.S", "CF.Y", "CF.W", "CF.A",
"SU.Y", "SU.W", "LS.Y", "LS.W", "LS.A", "RP.S"],
'Non-Precipitation' : ["AF.W", "AF.Y", "AQ.Y", "AS.O", "AS.Y", "DU.Y",
"DS.W", "EH.W", "EH.A", "EC.W", "EC.A", "FG.Y", "FZ.W", "FZ.A",
"HZ.W", "HZ.A", "ZF.Y", "FR.Y", "HT.Y", "HW.W", "HW.A",
"LW.Y", "SM.Y", "WI.Y"],
'Marine' : ["MA.S", "MH.W", "MH.Y", "BW.Y", "UP.Y", "MF.Y",
"GL.A", "GL.W", "SE.A", "SE.W", "UP.A", "UP.W", "HF.A", "HF.W", "LO.Y", "SC.Y", "SW.Y",
"RB.Y", "SI.Y", "MS.Y", "SR.A", "SR.W"],
'Tropical Cyclone' : ["HU.W", "HU.A", "HU.S", "TR.W", "TR.A"],
'Tsunami' : ["TS.A", "TS.W"],
#'Local' : ["TEST"], #example of adding local hazards
# you can define your own groups of hazards by adding new categories
}
# This function sorts the hazards in the hazardDict by description.
# Comment it out if this is not desired.
hazardDict = sortHazardList(hazardDict)
# Dictionary of map categories and the map names. The "<site>" is
# substituted with your site name. The names of the map must match
# those defined in the ifpServer. The keys in mapNames must match
# the keys in hazardDict.
mapNames = {
'Fire Weather' : ["FireWxZones_<site>"],
'Hydrology' : ["Zones_<site>"],
'Coastal Flood': ["Zones_<site>"],
'Convective Watches' : ["Marine_Zones_<site>","FIPS_<site>"],
'Non-Precipitation' : ["Zones_<site>"],
'Tropical Cyclone' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Typhoon' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Tsunami' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Winter Weather' : ["Zones_<site>"],
'Marine' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>"],
#'Local' : ["Zones_<site>"], #example of adding local class
}
# The hazard type chosen when MakeHazard opens
defaultHazardType = "Non-Precipitation"
# this is the color for the selected areas in the map
mapColor = "red"
# initial map width
defaultMapWidth = 400;
# the percentage that an area must be covered to default to selected
areaThreshold = 0.10
# End time in hours of the time scales
timeScaleEndTime = 96
# Define the tropical product used to identify the particular storm
tcmList = [] # Comment out for HLS sites
# Uncomment line below for Atlantic basin sites
#tcmList = ["TCMAT1", "TCMAT2", "TCMAT3", "TCMAT4", "TCMAT5"]
# Uncomment line below for EPac basin sites
#tcmList = ["TCMEP1", "TCMEP2", "TCMEP3", "TCMEP4", "TCMEP5"]
# Uncomment line below for CPac basin sites
#self.tcmList = ["TCMCP1", "TCMCP2", "TCMCP3", "TCMCP4", "TCMCP5"]
#################### END CONFIGURATION SECTION #################

View file

@ -1061,10 +1061,7 @@ class HazardUtils(SmartScript.SmartScript):
#print areas, from dictionary
def _printAreas(self, areas):
ara = []
for a in areas.keys():
if areas[a] == 1:
ara.append(a)
ara = list(areas)
ara.sort()
return ara

View file

@ -0,0 +1,182 @@
# ----------------------------------------------------------------------------
# This software is in the public domain, furnished "as is", without technical
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#
# MakeHazard.py
#
# SOFTWARE HISTORY
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# Jul 10,2012 436 randerso Separated configuration data from the
# MakeHazard procedure
#
# Author: randerso
# ----------------------------------------------------------------------------
def sortHazardList(dict):
#sorts the entries in the menus in alphabetical order, returns sorted
#dictionary
import VTECTable
for ent in dict.keys():
values = dict[ent]
# get the descriptive word for this phen/sig
items = []
for v in values:
desc = VTECTable.VTECTable.get(v,'')
items.append((desc, v))
items.sort() #sorts by description
#extract out the sorted phen/sig
phensig = []
for desc, v in items:
phensig.append(v)
dict[ent] = phensig
return dict
# Lists of hazards organized by type in a dictionary
# Set these to value you use for your site. To minimize scrolling,
# change the order so that the most common values your site uses are
# near the front of each list. The key is the menu entry on the
# Make Hazard dialog, the values are the key values for Hazards.
# Using OrderedDict allows you to control the order in which the
# Hazard Types are displayed in the dialog
#
from collections import OrderedDict
hazardDict = OrderedDict([
('Winter Weather', ["BZ.W", "BZ.A", "ZR.Y",
"IS.W", "LE.Y", "LE.W", "LE.A",
"WC.Y", "WC.W", "WC.A", "WS.W", "WS.A", "WW.Y"]),
('Hydrology', ["FF.A", "FA.A"]),
('Fire Weather', ["FW.A", "FW.W"]),
('Convective Watches', ["SV.A", "TO.A"]),
('Coastal Flood', ["CF.S", "LS.S", "CF.Y", "CF.W", "CF.A",
"SU.Y", "SU.W", "LS.Y", "LS.W", "LS.A", "RP.S"]),
('Non-Precipitation', ["AF.W", "AF.Y", "AQ.Y", "AS.O", "AS.Y", "DU.Y",
"DS.W", "EH.W", "EH.A", "EC.W", "EC.A", "FG.Y", "FZ.W", "FZ.A",
"HZ.W", "HZ.A", "ZF.Y", "FR.Y", "HT.Y", "HW.W", "HW.A",
"LW.Y", "SM.Y", "WI.Y"]),
('Marine', ["MA.S", "MH.W", "MH.Y", "BW.Y", "UP.Y", "MF.Y",
"GL.A", "GL.W", "SE.A", "SE.W", "UP.A", "UP.W", "HF.A", "HF.W", "LO.Y", "SC.Y", "SW.Y",
"RB.Y", "SI.Y", "MS.Y", "SR.A", "SR.W"]),
('Tropical Cyclone', ["HU.W", "HU.A", "HU.S", "TR.W", "TR.A"]),
('Tsunami', ["TS.A", "TS.W"]),
# ('Local', ["TEST"]), #example of adding local hazards
# you can define your own groups of hazards by adding new categories
])
# for GUM use comment out the above definition and uncomment the one below
#hazardDict = OrderedDict([
# ('Hydrology', ["FF.A", "FA.A"]),
# ('Fire Weather', ["FW.A", "FW.W"]),
# ('Coastal Flood', ["CF.S", "LS.S", "CF.Y", "CF.W", "CF.A",
# "SU.Y", "SU.W", "LS.Y", "LS.W", "LS.A", "RP.S"]),
# ('Non-Precipitation', ["AF.W", "AF.Y", "AQ.Y", "AS.O", "AS.Y", "DU.Y",
# "DS.W", "EH.W", "EH.A", "EC.W", "EC.A", "FG.Y", "FZ.W", "FZ.A",
# "HZ.W", "HZ.A", "ZF.Y", "FR.Y", "HT.Y", "HW.W", "HW.A",
# "LW.Y", "SM.Y", "WI.Y"]),
# ('Marine', ["MA.S", "MH.W", "MH.Y", "BW.Y", "UP.Y", "MF.Y",
# "GL.A", "GL.W", "SE.A", "SE.W", "UP.A", "UP.W", "HF.A", "HF.W", "LO.Y", "SC.Y", "SW.Y",
# "RB.Y", "SI.Y", "MS.Y", "SR.A", "SR.W"]),
# ('Typhoon', ["TY.A", "TY.W", "TR.A", "TR.W", "HU.S"]),
# ('Tsunami', ["TS.A", "TS.W"]),
#
# # ('Local', ["TEST"]), #example of adding local hazards
# # you can define your own groups of hazards by adding new categories
# ])
# This function sorts the hazards in the hazardDict by description.
# Comment it out if this is not desired.
hazardDict = sortHazardList(hazardDict)
# Dictionary of map categories and the map names. The "<site>" is
# substituted with your site name. The names of the map must match
# those defined in the ifpServer. The keys in mapNames must match
# the keys in hazardDict.
mapNames = {
'Fire Weather' : ["FireWxZones_<site>"],
'Hydrology' : ["Zones_<site>"],
'Coastal Flood': ["Zones_<site>"],
'Convective Watches' : ["Marine_Zones_<site>","FIPS_<site>"],
'Non-Precipitation' : ["Zones_<site>"],
'Tropical Cyclone' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Typhoon' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Tsunami' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>","Zones_<site>"],
'Winter Weather' : ["Zones_<site>"],
'Marine' : ["Offshore_Marine_Zones_<site>",
"Marine_Zones_<site>"],
#'Local' : ["Zones_<site>"], #example of adding local class
}
# The defaultHazardType - selected when the tool is first run. This
# must be one of the categories (keys) in the mapNames and hazardDict.
defaultHazardType = "Non-Precipitation"
# this is the color for the selected areas in the map
mapColor = "red" # color of selected areas
# initial map width
defaultMapWidth = 400;
# the percentage that an area must be covered to default to selected
areaThreshold = 0.10
# End time in hours of the time scales
timeScaleEndTime = 96
# Define the tropical product used to identify the particular storm
tcmList = [] # Comment out for HLS sites
# Uncomment line below for Atlantic basin sites
#tcmList = ["TCMAT1", "TCMAT2", "TCMAT3", "TCMAT4", "TCMAT5"]
# Uncomment line below for EPac basin sites
#tcmList = ["TCMEP1", "TCMEP2", "TCMEP3", "TCMEP4", "TCMEP5"]
# Uncomment line below for CPac basin sites
#tcmList = ["TCMCP1", "TCMCP2", "TCMCP3", "TCMCP4", "TCMCP5"]
# Dictionary mapping Hazard Types to applicable local effect areas
# that can be intersected with the zone edit areas.
# You should not define localEffectAreas entries for Tropical Cyclone
# or Convective Watches.
localEffectAreas = {}
#localEffectAreas = {
# 'Winter Weather' : ["Below_1000","Below_1500","Below_2000","Below_2500","Below_3000","Below_3500","Below_4000",
# "Above_1000","Above_1500","Above_2000","Above_2500","Above_3000","Above_3500"],
# }
# Dictionary associating local Effect Area names with a corresponding
# segment number, display name, and list of zones to be auto-selected
# If you do not wish to auto-select zones you should supply an empty list
#
# The display name allows you to display a "pretty" string in the UI rather
# than the edit area name. If the display name is empty ("") the edit area
# name will be used.
localAreaData = {}
#localAreaData = {
# "Below_1000" : ( 999, "", []),
# "Below_1500" : (1499, "", []),
# "Below_2000" : (1999, "", []),
# "Below_2500" : (2499, "", []),
# "Below_3000" : (2999, "", []),
# "Below_3500" : (3499, "", []),
# "Below_4000" : (3999, "", []),
# "Above_1000" : (1000, "", []),
# "Above_1500" : (1500, "", []),
# "Above_2000" : (2000, "", []),
# "Above_2500" : (2500, "", []),
# "Above_3000" : (3000, "", []),
# "Above_3500" : (3500, "", []),
# }

View file

@ -1,126 +0,0 @@
##
# 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.
##
# ----------------------------------------------------------------------------
# This software is in the public domain, furnished "as is", without technical
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#
# MakeHazard.py
#
# Author: wdougherty
# ----------------------------------------------------------------------------
import numpy
import JUtil
import LogStream
import TimeRange
from HazardUtils import HazardUtils
from HazardUtils import ELEMENT
from HazardUtils import MODEL
from HazardUtils import LEVEL
from HazardUtils import SUCCESS
from HazardUtils import FAIL_REDUNDANT
def makeHazard(hazard, dbss, timeRange, zones, segment, selectedTimeRange, defaultAreaList, defaultHazard, defaultSegment):
hazardUtils = HazardUtils(dbss, None)
# hazard has already been validated
# timeRange has already been validated
# convert zones to a Python list
if zones is None:
zones = []
if defaultAreaList is None:
defaultAreaList = []
if not isinstance(zones, list):
zones = JUtil.javaStringListToPylist(zones)
if not isinstance(defaultAreaList, list):
defaultAreaList = JUtil.javaStringListToPylist(defaultAreaList)
# Find the mask that describes the area covered by the hazard
if [] == zones:
ea = hazardUtils.getActiveEditArea()
if ea is None:
mask = None
else:
mask = hazardUtils.encodeEditArea(ea)
else:
mask = hazardUtils._makeMask(zones)
# Hazards need to be separated for makeHazard's temp hazard grid.
# If the user hasn't already separated them, it's up to us.
if hazardUtils._tempWELoaded():
pass # Hazards are already separated
else:
hazParm = hazardUtils.getParm(MODEL,ELEMENT,LEVEL)
# If the inventory span is invalid, the hazards grid is empty.
if hazParm.getInventorySpan().isValid():
if SUCCESS != hazardUtils._separateHazardGrids():
return False
# Build the hazard key
hazardKey = hazard
defaultHazardKey = defaultHazard
if segment is None:
segment = ""
if defaultSegment is None:
defaultSegment = ""
segment = segment.strip()
defaultSegment = defaultSegment.strip()
if "" != segment:
hazardKey = hazardKey + ":" + segment
if "" != defaultSegment and defaultHazardKey is not None:
defaultHazardKey = defaultHazardKey + ":" + defaultSegment
# Create the name of the temp weather element from hazardKey
weName = hazardUtils._makeTempWEName(hazardKey)
# if we're modifying, remove the old grid first
if defaultAreaList != [] and hazardKey == defaultHazardKey:
hazardUtils.deleteCmd([weName], selectedTimeRange)
# Don't allow the user to create an empty hazard grid
if not numpy.any(mask):
hazardUtils.statusBarMsg(
"NO EDIT AREA SELECTED: \n Select area from map or load edit area in GFE!",
"S", "GHG Status")
return False
# Create the temporary hazard grid
hazardUtils._addHazard(weName, timeRange, hazardKey, mask)
# convert timeRange to Python for logging
timeRange = TimeRange.TimeRange(timeRange)
# log the creation of the temp hazard
LogStream.logEvent("Set: " + weName + " " +
hazardUtils._printTime(timeRange.startTime().unixTime()) + " " +
hazardUtils._printTime(timeRange.endTime().unixTime()) + " " +
hazardKey + " " + str(zones))
return True
##
#
def ensureSeparated(dbss):
hazardUtils = HazardUtils(dbss, None)
rtnCode = hazardUtils._separateHazardGrids()
separated = rtnCode in [SUCCESS, FAIL_REDUNDANT]
return separated

View file

@ -1,250 +0,0 @@
##
# 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.
##
# ----------------------------------------------------------------------------
import string, time
from com.raytheon.uf.common.status import UFStatus
from com.raytheon.uf.common.status import UFStatus_Priority as Priority
### New class for fetching ETN from TCM header for tropical hazards
class TCMDecoder:
def __init__(self):
self.pos = 0
# key words in TCM products from NCEP
self.keyWordDict = {"NATIONAL HURRICANE CENTER" : self.decodeAltFilename,
}
self.fcstList = [] # a place to store all of the forecasts
self.text = [] # the text product
self.currentFcst = {} # the current forecast we are docoding
self.baseProductTime = 0
self.altFilename = ""
self._handler = UFStatus.getHandler("GFE", 'GFE')
def stripText(self):
endStr = chr(13) + chr(13) + chr(10)
for i in range(len(self.text)):
self.text[i] = string.replace(self.text[i], endStr, "")
return
def getFcstList(self):
return self.fcstList
def getBaseProductTime(self):
return self.baseProductTime
def getAltInfoFilename(self):
return self.altFilename
def currentLine(self):
return self.text[self.pos]
def nextLine(self):
self.pos = self.pos + 1
if self.pos < len(self.text):
return self.text[self.pos]
else:
return ""
def monthNum(self, monthStr):
monthList = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
try:
return monthList.index(monthStr) + 1
except ValueError:
return 0
def convertBaseTime(self, timeStr):
# timeStr format: "HHMM UTC DAY MON DD YYYY"
try:
baseTime = time.strptime(timeStr, "%H%M UTC %a %b %d %Y")
print "baseTime is", baseTime
return baseTime
except ValueError:
return
# extract time parts from the str
# strList = string.split(timeStr)
# if len(strList) != 6:
# print "Invalid time string:", timeStr
# print "Format should be of the form HHMM UTC DAY MON DD YYYY"
# return
#
# hour = int(timeStr[0:2])
# minute = int(timeStr[2:4])
# monthStr = strList[3]
# month = self.monthNum(monthStr)
# day = int(strList[4])
# year = int(strList[5])
#
# # time.mktime returns time in seconds but in local time
# baseTime = time.mktime((year, month, day, hour, minute, 0, 0, 0, 0))
# print "month is", month
# print "baseTime is", baseTime
## # Adjust to UTC
## diffTime = time.mktime(time.gmtime()) - time.mktime(time.localtime())
## print "diffTime is", diffTime
## # subtract timeZone and round to the nearest hour
## roundedTime = int((baseTime - diffTime) / 3600) * 3600
##
# return baseTime
def convert_ddhhmm(self, ddhhmmStr, baseTime):
# remove the slash if present
ddhhmmStr = string.replace(ddhhmmStr, "/", "")
if baseTime == 0:
baseTime = time.time()
# extract the time parts
dayStr = ddhhmmStr[0:2]
hourStr = ddhhmmStr[2:4]
minStr = ddhhmmStr[4:6]
day = int(dayStr)
hour = int(hourStr)
minute = int(minStr)
tupleTime = time.gmtime(baseTime)
year = tupleTime[0]
month = tupleTime[1]
# see if we crossed over to a new month
if tupleTime[2] > day:
month = month + 1
if month > 12:
month = 1
year = year + 1
newTuple = (year, month, day, hour, minute, tupleTime[5],
tupleTime[6], tupleTime[7], tupleTime[8])
secondsTime = time.mktime(newTuple)
# Adjustment to UTC
diffTime = time.mktime(time.gmtime()) - time.mktime(time.localtime())
return secondsTime - diffTime # subtract timeZone
def decodeProductTime(self):
# Time of the product found on the next line
timeStr = self.nextLine()
print "the time string is:", timeStr
# sanity check for the time string
hhmm = timeStr[0:4]
for c in hhmm:
if not c in string.digits:
return
baseTime = self.convertBaseTime(timeStr)
self.baseProductTime = baseTime
return
def decodeAltFilename(self):
nameStr = self.currentLine()
parts = string.split(nameStr)
self.altFilename = parts[-1] # grab the last string token
return
def decodeTCMProduct(self, TCMProduct):
self.text = TCMProduct
self.pos = 0
self.fcstList = []
## self.defaultEyeDiameter = eyeDiameter
self.stripText()
while self.pos < len(TCMProduct):
line = self.currentLine()
for k in self.keyWordDict.keys():
if string.find(line, k) > -1:
self.keyWordDict[k]()
break
self.pos = self.pos + 1
# store the last forecast in the list of forecasts
if self.currentFcst != {}:
self.fcstList.append(self.currentFcst)
self.currentFcst = {} # reset
return
## End TCM decoder class
### New methods to pull ETN from TCM if grid is not initialized with ETN
def tcmETNforTrop(tcmProduct):
tcmProd = tcmProduct
# print "chosen TCM is", tcmProd
tcmDecoder = TCMDecoder()
TCMProduct = getTextProductFromDB(tcmProd)
if len(TCMProduct) < 3:
msg = tcmProd + " could not be retrieved from the text database."
statusBarMsg(msg, "S")
return None # Just return if no TCM is found. Something's really wrong
else:
tcmDecoder.decodeTCMProduct(TCMProduct)
altFileName = tcmDecoder.getAltInfoFilename()
stormNum = altFileName[2:4]
## print "storm number is", stormNum
nationalBase = "10"
tropicalETN = nationalBase + stormNum
## print "Tropical ETN is: ", tropicalETN
## print "lenth of tropical ETN is:", len(tropicalETN)
return tropicalETN
def getTextProductFromDB(productID):
from com.raytheon.viz.gfe import Activator
from com.raytheon.viz.gfe.core import DataManager
from com.raytheon.viz.gfe.product import TextDBUtil
prefStore = Activator.getDefault().getPreferenceStore()
if prefStore.contains("TestVTECDecode"):
testVtec = prefStore.getBoolean("TestVTECDecode")
else:
testVtec = False
gfeMode = (DataManager.getCurrentInstance().getOpMode().name() == "OPERATIONAL")
opMode = testVtec or gfeMode
fullText = TextDBUtil.retrieveProduct(productID, opMode)
textList = fullText.splitlines(True)
return textList
def statusBarMsg(message, status, category="GFE"):
from com.raytheon.uf.common.status import UFStatus
from com.raytheon.uf.common.status import UFStatus_Priority as Priority
from com.raytheon.viz.gfe import Activator
from com.raytheon.viz.gfe.constants import StatusConstants
if "A" == status:
importance = Priority.PROBLEM
elif "R" == status:
importance = Priority.EVENTA
elif "U" == status:
importance = Priority.CRITICAL
else:
importance = Priority.SIGNIFICANT
self._handler.handle(importance,message)

View file

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -63,6 +64,7 @@ import com.vividsolutions.jts.geom.Point;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 22, 2009 3072 bsteffen Initial creation
* Aug 23, 2012 1096 njensen Fixed memory leaks
*
* </pre>
*
@ -161,8 +163,10 @@ public class CcfpResource extends
}
private void disposeFrames() {
for (DisplayFrame frame : frames.values()) {
frame.dispose();
synchronized (frames) {
for (DisplayFrame frame : frames.values()) {
frame.dispose();
}
}
}
@ -180,11 +184,15 @@ public class CcfpResource extends
@Override
public String inspect(ReferencedCoordinate coord) throws VizException {
if (frames.get(this.displayedDataTime) == null) {
DisplayFrame frame = null;
synchronized (frames) {
frame = frames.get(this.displayedDataTime);
}
if (frame == null) {
return "";
}
StringBuilder res = new StringBuilder();
for (CcfpRecord record : frames.get(this.displayedDataTime).records) {
for (CcfpRecord record : frame.records) {
// Check if we have an area we are rendering
if (isPaintingArea(record)) {
try {
@ -216,15 +224,20 @@ public class CcfpResource extends
*/
private void updateRecords(IGraphicsTarget target,
PaintProperties paintProps) throws VizException {
DisplayFrame frame = frames.get(this.displayedDataTime);
if (frame == null) {
frame = new DisplayFrame();
frames.put(this.displayedDataTime, frame);
DisplayFrame frame = null;
synchronized (frames) {
frame = frames.get(this.displayedDataTime);
if (frame == null) {
frame = new DisplayFrame();
frames.put(this.displayedDataTime, frame);
}
}
// Add all the new Records
Collection<CcfpRecord> newRecords = unprocessedRecords
.get(this.displayedDataTime);
Collection<CcfpRecord> newRecords = null;
synchronized (unprocessedRecords) {
newRecords = unprocessedRecords.get(this.displayedDataTime);
}
for (CcfpRecord record : newRecords) {
// If we need to draw anything for this record then keep it
if (isPaintingArea(record) || isPaintingMovement(record)
@ -259,14 +272,19 @@ public class CcfpResource extends
this.displayedDataTime = paintProps.getDataTime();
// First check to see if we need to process new data
Collection<CcfpRecord> unprocessed = unprocessedRecords
.get(this.displayedDataTime);
Collection<CcfpRecord> unprocessed = null;
synchronized (unprocessedRecords) {
unprocessed = unprocessedRecords.get(this.displayedDataTime);
}
if (unprocessed != null && unprocessed.size() > 0) {
updateRecords(target, paintProps);
}
// Hopefully we now have some data to display, if not bail
DisplayFrame frame = frames.get(this.displayedDataTime);
DisplayFrame frame = null;
synchronized (frames) {
frame = frames.get(this.displayedDataTime);
}
if (frame == null) {
this.displayedDataTime = null;
return;
@ -509,14 +527,24 @@ public class CcfpResource extends
*/
protected void addRecord(CcfpRecord obj) {
DataTime dataTime = obj.getDataTime();
Collection<CcfpRecord> records = unprocessedRecords.get(dataTime);
if (records == null) {
records = new ArrayList<CcfpRecord>();
unprocessedRecords.put(dataTime, records);
this.dataTimes.add(dataTime);
Collections.sort(this.dataTimes);
if (resourceData.durationMatches(dataTime)) {
Collection<CcfpRecord> records = null;
boolean brandNew = false;
synchronized (unprocessedRecords) {
records = unprocessedRecords.get(dataTime);
if (records == null) {
records = new HashSet<CcfpRecord>();
unprocessedRecords.put(dataTime, records);
brandNew = true;
}
}
if (brandNew) {
this.dataTimes.add(dataTime);
Collections.sort(this.dataTimes);
}
records.add(obj);
}
records.add(obj);
}
@Override
@ -677,16 +705,40 @@ public class CcfpResource extends
@Override
public void project(CoordinateReferenceSystem crs) throws VizException {
disposeFrames();
// add as unprocessed to make sure frames created
for (DataTime time : frames.keySet()) {
DisplayFrame frame = frames.get(time);
if (frame != null) {
List<CcfpRecord> copyList = new ArrayList<CcfpRecord>(
frame.records);
unprocessedRecords.put(time, copyList);
synchronized (frames) {
disposeFrames();
// add as unprocessed to make sure frames created
for (DataTime time : frames.keySet()) {
DisplayFrame frame = frames.get(time);
if (frame != null) {
List<CcfpRecord> copyList = new ArrayList<CcfpRecord>(
frame.records);
synchronized (unprocessedRecords) {
unprocessedRecords.put(time, copyList);
}
}
}
}
}
@Override
public void remove(DataTime time) {
super.remove(time);
Collection<CcfpRecord> notNeeded = null;
synchronized (unprocessedRecords) {
notNeeded = unprocessedRecords.remove(time);
}
if (notNeeded != null) {
notNeeded.clear();
}
DisplayFrame frame = null;
synchronized (frames) {
frame = frames.remove(time);
}
if (frame != null) {
frame.dispose();
}
}
}

View file

@ -31,12 +31,10 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.ccfp.Activator;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.status.StatusConstants;
/**
*
@ -56,8 +54,9 @@ import com.raytheon.uf.viz.core.status.StatusConstants;
*/
@XmlAccessorType(XmlAccessType.NONE)
public class CcfpResourceData extends AbstractRequestableResourceData {
private static final transient IUFStatusHandler statusHandler = UFStatus.getHandler(CcfpResourceData.class);
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CcfpResourceData.class);
// This flag determnies if we draw lines and polygons
@XmlAttribute
private boolean displayArea = true;
@ -69,35 +68,34 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
// This flag determines if we display text boxes
@XmlAttribute
private boolean displayText = true;
// Filter by coverage
@XmlAttribute
private int coverageFilter = 0;
@XmlAttribute
private int validDuration = 0;
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
if (obj instanceof CcfpResourceData == false) {
return false;
}
CcfpResourceData other = (CcfpResourceData) obj;
if (other.coverageFilter != this.coverageFilter) {
return false;
}
if (other.validDuration != this.validDuration) {
return false;
}
if (other.displayText != this.displayText) {
return false;
}
@ -109,7 +107,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
if (other.displayMovement != this.displayMovement) {
return false;
}
return true;
}
@ -122,7 +120,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
DataTime[] originalTimes = super.getAvailableTimes();
ArrayList<DataTime> newTimes = new ArrayList<DataTime>();
for (DataTime time : originalTimes) {
if (time.getValidPeriod().getDuration() == validDuration * 1000) {
if (durationMatches(time)) {
newTimes.add(time);
}
}
@ -147,6 +145,18 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
return nr;
}
/**
* Checks if a DataTime's valid period matches the duration of the resource
* data
*
* @param time
* the time to check
* @return true if the durations are equal, otherwise false
*/
protected boolean durationMatches(DataTime time) {
return time.getValidPeriod().getDuration() == validDuration * 1000;
}
public boolean isDisplayArea() {
return displayArea;
}
@ -185,6 +195,6 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
public void setValidDuration(int validDuration) {
this.validDuration = validDuration;
}
}
}

View file

@ -17,7 +17,6 @@ com.raytheon.uf.viz.core.rsc.capabilities.LabelableCapability
com.raytheon.uf.viz.core.rsc.capabilities.DensityCapability
com.raytheon.uf.viz.core.rsc.capabilities.DisplayTypeCapability
com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability
com.raytheon.uf.viz.core.rsc.capabilities.MultiChannelCapability
com.raytheon.uf.viz.core.rsc.capabilities.PointCapability
com.raytheon.uf.viz.core.rsc.capabilities.TimeMatchBasisCapability
com.raytheon.uf.viz.core.rsc.GenericResourceData

View file

@ -187,6 +187,8 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
private boolean mirror;
private double noDataValue = Double.NaN;
@XmlElement
private PersistedParameters persisted = new PersistedParameters();
@ -1009,4 +1011,20 @@ public class ColorMapParameters implements Cloneable, ISerializableObject {
this.colorMapMax = params.colorMapMax;
}
}
/**
* @return the noDataValue
*/
public double getNoDataValue() {
return noDataValue;
}
/**
* @param noDataValue
* the noDataValue to set
*/
public void setNoDataValue(double noDataValue) {
this.noDataValue = noDataValue;
}
}

View file

@ -124,7 +124,7 @@ public class ImagingSupport {
bulk.toArray(new DrawableImage[bulk.size()]));
}
return rval & skipped;
return rval & !skipped;
}
/**

View file

@ -1,104 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.core.drawables.ext.colormap;
import java.util.Map;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* {@link IImagingExtension} used to create and draw multi-channel R,G,B images
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 5, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public interface IMultiChannelImageExtension extends IImagingExtension {
public static enum Channel {
RED, GREEN, BLUE;
}
public static class ChannelData {
public String name;
public ColorMapParameters parameters;
public boolean invert;
public ChannelData(String name, ColorMapParameters params,
boolean invert) {
this.name = name;
this.parameters = params;
}
}
public static interface IMultiChannelImage extends IImage {
public Map<Channel, IImageChannel> getImageMapping();
public void setImageMapping(Map<Channel, IImageChannel> mapping);
}
public static interface IImageChannel extends IColormappedImage {
public void setInverted(boolean inverted);
}
/**
* Construct a true color image, this
*
* @param channelMap
* @return
* @throws VizException
*/
public IMultiChannelImage constructImage(
Map<Channel, IImageChannel> imageMapping) throws VizException;
/**
* Construct a IImageChannel for a IMultiChannelImage
*
* @param callback
* @param inverted
* @return
* @throws VizException
*/
public IImageChannel constructImage(
IColorMapDataRetrievalCallback callback, ChannelData channelData)
throws VizException;
}

View file

@ -158,6 +158,18 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
return add(rp);
}
/**
* Function for determining if the {@link ResourcePair} can be added to the
* list. Default checks if the pair is already in the list and returns false
* if so
*
* @param e
* @return
*/
protected boolean canAdd(ResourcePair e) {
return contains(e) == false;
}
/*
* (non-Javadoc)
*
@ -165,7 +177,7 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
*/
@Override
public boolean add(ResourcePair e) {
if (e == null || contains(e)) {
if (e == null || canAdd(e) == false) {
return false;
}
@ -263,7 +275,7 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
}
synchronized (this) {
if (contains(e)) {
if (canAdd(e) == false) {
return false;
}
@ -276,9 +288,7 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
super.add(i >= 0 ? (i + 1) : 0, e);
synchronized (resourcesToInstantiate) {
if (resourcesToInstantiate.contains(e) == false) {
resourcesToInstantiate.add(e);
}
resourcesToInstantiate.add(e);
}
}
@ -300,7 +310,7 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
if (rp.getResource() == null) {
Validate.notNull(rp.getResourceData());
}
if (contains(rp) == false) {
if (canAdd(rp)) {
toAdd.add(rp);
}
}
@ -400,7 +410,13 @@ public class ResourceList extends CopyOnWriteArrayList<ResourcePair> implements
super.remove(index);
synchronized (resourcesToInstantiate) {
resourcesToInstantiate.remove(rp);
// Ensure rp is removed from list entirely
Iterator<ResourcePair> iter = resourcesToInstantiate.iterator();
while (iter.hasNext()) {
if (iter.next() == rp) {
iter.remove();
}
}
}
try {

View file

@ -1,313 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.core.rsc.capabilities;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.Channel;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.ChannelData;
/**
* Capability for multi channel imagery
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 20, 2011 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class MultiChannelCapability extends AbstractCapability {
@XmlAccessorType(XmlAccessType.NONE)
public static class ChannelSerializable {
@XmlAttribute
private String name;
@XmlAttribute
private Channel channel;
@XmlAttribute
private boolean invert;
@XmlElement
private float dataMin;
@XmlElement
private float dataMax;
@XmlElement
private float cmapMin;
@XmlElement
private float cmapMax;
public ChannelSerializable() {
}
public ChannelSerializable(Channel channel, ChannelData channelData) {
this.channel = channel;
this.name = channelData.name;
this.invert = channelData.invert;
ColorMapParameters params = channelData.parameters;
this.dataMin = params.getDataMin();
this.dataMax = params.getDataMax();
this.cmapMin = params.getColorMapMin();
this.cmapMax = params.getColorMapMax();
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the channel
*/
public Channel getChannel() {
return channel;
}
/**
* @param channel
* the channel to set
*/
public void setChannel(Channel channel) {
this.channel = channel;
}
/**
* @return the dataMin
*/
public float getDataMin() {
return dataMin;
}
/**
* @param dataMin
* the dataMin to set
*/
public void setDataMin(float dataMin) {
this.dataMin = dataMin;
}
/**
* @return the dataMax
*/
public float getDataMax() {
return dataMax;
}
/**
* @param dataMax
* the dataMax to set
*/
public void setDataMax(float dataMax) {
this.dataMax = dataMax;
}
/**
* @return the cmapMin
*/
public float getCmapMin() {
return cmapMin;
}
/**
* @param cmapMin
* the cmapMin to set
*/
public void setCmapMin(float cmapMin) {
this.cmapMin = cmapMin;
}
/**
* @return the cmapMax
*/
public float getCmapMax() {
return cmapMax;
}
/**
* @param cmapMax
* the cmapMax to set
*/
public void setCmapMax(float cmapMax) {
this.cmapMax = cmapMax;
}
/**
* @return the invert
*/
public boolean isInvert() {
return invert;
}
/**
* @param invert
* the invert to set
*/
public void setInvert(boolean invert) {
this.invert = invert;
}
}
public static class Marshaller extends
XmlAdapter<ChannelSerializable[], HashMap<Channel, ChannelData>> {
/*
* (non-Javadoc)
*
* @see
* javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang
* .Object)
*/
@Override
public HashMap<Channel, ChannelData> unmarshal(ChannelSerializable[] v)
throws Exception {
HashMap<Channel, ChannelData> channelMap = new HashMap<Channel, ChannelData>();
for (ChannelSerializable cs : v) {
ColorMapParameters params = new ColorMapParameters();
params.setDataMin(cs.dataMin);
params.setDataMax(cs.dataMax);
params.setColorMapMin(cs.cmapMin);
params.setColorMapMax(cs.cmapMax);
channelMap.put(cs.channel, new ChannelData(cs.name, params,
cs.invert));
}
return channelMap;
}
/*
* (non-Javadoc)
*
* @see
* javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object
* )
*/
@Override
public ChannelSerializable[] marshal(HashMap<Channel, ChannelData> v)
throws Exception {
ChannelSerializable[] serializable = new ChannelSerializable[v
.size()];
int i = 0;
for (Entry<Channel, ChannelData> entry : v.entrySet()) {
ChannelSerializable cs = new ChannelSerializable(
entry.getKey(), entry.getValue());
serializable[i++] = cs;
}
return serializable;
}
}
@XmlJavaTypeAdapter(value = Marshaller.class)
private HashMap<Channel, ChannelData> channelMap = new HashMap<Channel, ChannelData>();
private String[] names;
/**
* @return the names
*/
public String[] getNames() {
return names;
}
/**
* @param names
* the names to set
*/
public void setNames(String[] names) {
this.names = names;
}
/**
* @return the channelMap
*/
public Map<Channel, ChannelData> getChannelMap() {
return channelMap;
}
/**
* @param channelMap
* the channelMap to set
*/
public void setChannelMap(HashMap<Channel, ChannelData> channelMap) {
if (channelMap == null) {
channelMap = new HashMap<Channel, ChannelData>();
}
this.channelMap = channelMap;
capabilityChanged();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability#
* capabilityChanged()
*/
@Override
public void capabilityChanged() {
super.capabilityChanged();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.capabilities.AbstractCapability#clone()
*/
@Override
public AbstractCapability clone() {
MultiChannelCapability cap = new MultiChannelCapability();
cap.channelMap = new HashMap<Channel, ChannelData>(channelMap);
return cap;
}
}

View file

@ -0,0 +1,195 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.core.tile;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.geometry.Envelope;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
/**
* Object that represents a single Tile. Contains a level and GridGeometry as
* well as a border which is used in {@link #intersects(Geometry)}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 8, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class Tile {
public final int tileLevel;
public final GridGeometry2D tileGeometry;
public final List<PreparedGeometry> tileBorder;
/**
* Create a Tile specifying a border for intersection checks
*
* @param tileLevel
* @param tileGeometry
* @param tileBorder
*/
public Tile(int tileLevel, GridGeometry2D tileGeometry, Geometry tileBorder) {
this.tileLevel = tileLevel;
this.tileGeometry = tileGeometry;
if (tileBorder != null) {
int num = tileBorder.getNumGeometries();
this.tileBorder = new ArrayList<PreparedGeometry>(num);
for (int n = 0; n < num; ++n) {
this.tileBorder.add(PreparedGeometryFactory.prepare(tileBorder
.getGeometryN(n)));
}
} else {
this.tileBorder = null;
}
}
/**
* Creates a Tile with no border. intersects calls will always return true
*
* @param tileLevel
* @param tileGeometry
*/
public Tile(int tileLevel, GridGeometry2D tileGeometry) {
this(tileLevel, tileGeometry, null);
}
public Rectangle getRectangle() {
GridEnvelope env = tileGeometry.getGridRange();
return new Rectangle(env.getLow(0), env.getLow(1), env.getSpan(0),
env.getSpan(1));
}
/**
* Checks if the geometry intersects the Tile. Tiles without a
* {@link #tileBorder} will always return true
*
* @param geometry
* @return
*/
public boolean intersects(Geometry geometry) {
if (tileBorder == null) {
return true;
}
for (PreparedGeometry border : tileBorder) {
if (border.intersects(geometry)) {
return true;
}
}
return false;
}
/**
* Checks to see if the x/y coordinate is contained by the Tile's CRS
* Envelope
*
* @param x
* @param y
* @return
*/
public boolean crsContains(double x, double y) {
Envelope env = tileGeometry.getEnvelope();
return env.getMinimum(0) <= x && env.getMaximum(0) >= x
&& env.getMinimum(1) <= y && env.getMaximum(1) >= y;
}
/**
* Checks to see if the Coordinate is contained by the Tile's CRS Envelope
*
* @param c
* @return
*/
public boolean crsContains(Coordinate c) {
return crsContains(c.x, c.y);
}
/**
* Checks to see if the x/y coordinate is contained by the Tile's grid
* envelope
*
* @param gridX
* @param gridY
* @return
*/
public boolean gridContains(int gridX, int gridY) {
GridEnvelope ge = tileGeometry.getGridRange();
return ge.getLow(0) <= gridX && ge.getHigh(0) >= gridX
&& ge.getLow(1) <= gridY && ge.getHigh(1) >= gridY;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((tileGeometry == null) ? 0 : tileGeometry.hashCode());
result = prime * result + tileLevel;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tile other = (Tile) obj;
if (tileGeometry == null) {
if (other.tileGeometry != null)
return false;
} else if (!tileGeometry.equals(other.tileGeometry))
return false;
if (tileLevel != other.tileLevel)
return false;
return true;
}
}

View file

@ -0,0 +1,418 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.core.tile;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GeneralGridEnvelope;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.CRSCache;
import com.raytheon.uf.common.geospatial.util.WorldWrapCorrector;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
/**
* This object represents a single tile level. It does this by containing a 2
* dimensional array of {@link Tile} objects.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 8, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class TileLevel {
/** Tile level's GridGeometry */
private GridGeometry2D levelGeometry;
/** GridGeometry tile level was created for */
private GeneralGridGeometry targetGeometry;
// Cached MathTransforms
private MathTransform crsToGrid;
private MathTransform gridToCRS;
private MathTransform tileCRSToTargetGrid;
/** Target grid to lat/lon for world wrap correcting */
private MathTransform targetGridToLatLon;
/** World wrap corrector, corrects Tile borders */
private WorldWrapCorrector corrector;
/** Level of this TileLevel */
private int tileLevel;
/** size for tiles in this level */
private int tileSize;
/** Pixel density of the tile level */
private double pixelDensity;
/** Tile array */
private Tile[][] tiles;
TileLevel(GridGeometry2D levelGeometry, GeneralGridGeometry targetGeometry,
int tileLevel, int tileSize) {
this.levelGeometry = levelGeometry;
this.targetGeometry = targetGeometry;
this.tileLevel = tileLevel;
this.tileSize = tileSize;
intialize(levelGeometry.getGridRange(), levelGeometry.getEnvelope());
}
private void intialize(GridEnvelope range, Envelope envelope) {
int width = range.getSpan(0);
int height = range.getSpan(1);
int fullTileDimX = width / tileSize;
int tileRemainderX = width % tileSize;
int fullTileDimY = height / tileSize;
int tileRemainderY = height % tileSize;
int totalTilesX = fullTileDimX;
if (tileRemainderX > 0) {
totalTilesX++;
}
int totalTilesY = fullTileDimY;
if (tileRemainderY > 0) {
totalTilesY++;
}
tiles = new Tile[totalTilesY][totalTilesX];
try {
gridToCRS = levelGeometry.getGridToCRS(PixelInCell.CELL_CORNER);
crsToGrid = gridToCRS.inverse();
DefaultMathTransformFactory factory = new DefaultMathTransformFactory();
tileCRSToTargetGrid = factory.createConcatenatedTransform(
CRSCache.getInstance().findMathTransform(
levelGeometry.getCoordinateReferenceSystem(),
targetGeometry.getCoordinateReferenceSystem()),
targetGeometry.getGridToCRS(PixelInCell.CELL_CORNER)
.inverse());
targetGridToLatLon = factory.createConcatenatedTransform(
targetGeometry.getGridToCRS(PixelInCell.CELL_CORNER),
CRSCache.getInstance().findMathTransform(
targetGeometry.getCoordinateReferenceSystem(),
DefaultGeographicCRS.WGS84));
corrector = new WorldWrapCorrector(targetGeometry);
// Calculate pixel density
// Grab the center x, 3/4 y of the map
double mapXCenter = targetGeometry.getGridRange().getSpan(0) * 0.5;
double mapYCenter = targetGeometry.getGridRange().getSpan(1) * 0.75;
double[] input = new double[] { mapXCenter, mapYCenter,
mapXCenter + 1, mapYCenter + 1 };
double[] output = new double[input.length];
tileCRSToTargetGrid.inverse().transform(input, 0, output, 0, 2);
levelGeometry.getGridToCRS(PixelInCell.CELL_CORNER).inverse()
.transform(output, 0, input, 0, 2);
pixelDensity = 1.0 / Math.abs(new Coordinate(input[0], input[1],
0.0).distance(new Coordinate(input[2], input[3], 0.0)));
} catch (Exception e) {
throw new RuntimeException(
"Cannot tranform tile CRS into target CRS", e);
}
}
/**
* Returns the pixel density for the tile level. This is the approximate
* number of target grid pixels a single tile grid pixel takes up
*
* @return
*/
public double getPixelDensity() {
return pixelDensity;
}
/**
* The number of tiles in the x direction (number of columns)
*
* @return
*/
public int getNumXTiles() {
return tiles[0].length;
}
/**
* The number of tiles in the y direction (number of rows)
*
* @return
*/
public int getNumYTiles() {
return tiles.length;
}
/**
* Level of this TileLevel
*
* @return
*/
public int getLevel() {
return tileLevel;
}
/**
* Get the Tile at the specified x/y index in the tile set
*
* @param x
* @param y
* @return
*/
public Tile getTile(int x, int y) {
Tile tile = tiles[y][x];
if (tile == null) {
synchronized (tiles) {
// Double check tile to see if another thread created it
tile = tiles[y][x];
if (tile == null) {
tiles[y][x] = tile = createTile(x, y);
}
}
}
return tile;
}
/**
* Gets the Tile for the specified tile grid location
*
* @param x
* @param y
* @return
*/
public Tile getTile(double x, double y) {
double xIdx = x / tileSize;
double yIdx = y / tileSize;
if (xIdx >= 0 && yIdx >= 0 && xIdx < getNumXTiles()
&& yIdx < getNumYTiles()) {
Tile tile = getTile((int) xIdx, (int) yIdx);
if (tile.gridContains((int) x, (int) y)) {
return tile;
}
}
return null;
}
/**
* Transforms TileLevel crs x,y into tile level grid space x,y
*
* @param x
* @param y
* @return
*/
public double[] crsToGrid(double x, double y) throws TransformException {
double[] out = new double[2];
crsToGrid.transform(new double[] { x, y }, 0, out, 0, 1);
return out;
}
/**
* Creates a Tile for the specified x/y {@link #tiles} index
*
* @param x
* @param y
* @return
*/
private Tile createTile(int x, int y) {
GridEnvelope range = levelGeometry.getGridRange();
// Get grid range ranges and calculate grid range for the tile
int startX = range.getLow(0);
int startY = range.getLow(1);
int endX = range.getHigh(0) + 1;
int endY = range.getHigh(1) + 1;
int tileY = startY + y * tileSize;
int tileX = startX + x * tileSize;
int tileEndX = Math.min(endX, tileX + tileSize);
int tileEndY = Math.min(endY, tileY + tileSize);
// Convert grid range into crs envelope range
double[] in = new double[] { tileX, tileY, tileEndX, tileEndY };
double[] out = new double[in.length];
try {
gridToCRS.transform(in, 0, out, 0, 2);
} catch (TransformException e) {
throw new RuntimeException("Error getting tile envelope from grid",
e);
}
double envTileX = out[0];
double envTileY = out[1];
double envTileEndX = out[2];
double envTileEndY = out[3];
// Create tile GridGeometry
range = new GeneralGridEnvelope(new int[] { tileX, tileY }, new int[] {
tileEndX, tileEndY }, false);
GridGeometry2D tileGridGeom = new GridGeometry2D(range, new Envelope2D(
levelGeometry.getCoordinateReferenceSystem(), out[0], envTileY,
envTileEndX - envTileX, envTileEndY - envTileY));
// Calculate the border in target grid space for the Tile
Geometry border = null;
try {
double[] UL = new double[] { envTileX, envTileY };
double[] UR = new double[] { envTileEndX, envTileY };
double[] LR = new double[] { envTileEndX, envTileEndY };
double[] LL = new double[] { envTileX, envTileEndY };
// Create tile border based on pixel density tile level 0 should
// always have threshold of 1.0
border = createTileBorder(UL, UR, LR, LL,
Math.max(range.getSpan(0) / 4, 1),
Math.max(range.getSpan(1) / 4, 1),
tileLevel > 0 ? Math.max(pixelDensity, 1.0) : 1.0);
} catch (TransformException e) {
// Invalid geometry, don't add a border
}
// Create the Tile object
return new Tile(tileLevel, tileGridGeom, border);
}
/**
* Ensures all Tile objects are created for the level. This method can takes
* lots of time depending on grid resolution of level and {@link #tileSize}.
* Tiles are created dynamically as requested otherwise
*/
public void populateTiles() {
int totalTilesY = getNumYTiles();
int totalTilesX = getNumXTiles();
for (int y = 0; y < totalTilesY; ++y) {
for (int x = 0; x < totalTilesX; ++x) {
if (tiles[y][x] == null) {
tiles[y][x] = createTile(x, y);
}
}
}
}
private Geometry createTileBorder(double[] UL, double[] UR, double[] LR,
double[] LL, int maxHorDivisions, int maxVertDivisions,
double threshold) throws TransformException {
List<Coordinate> borderPoints = new ArrayList<Coordinate>(
maxVertDivisions * 2 + maxHorDivisions * 2);
double[] out = new double[2];
// UL to UR
tileCRSToTargetGrid.transform(UL, 0, out, 0, 1);
borderPoints.add(new Coordinate(out[0], out[1]));
calculateBorder(borderPoints, UL, null, UR, null, maxHorDivisions,
threshold);
// UR to LR
tileCRSToTargetGrid.transform(UR, 0, out, 0, 1);
borderPoints.add(new Coordinate(out[0], out[1]));
calculateBorder(borderPoints, UR, null, LR, null, maxVertDivisions, 1.0);
// LR to LL
tileCRSToTargetGrid.transform(LR, 0, out, 0, 1);
borderPoints.add(new Coordinate(out[0], out[1]));
calculateBorder(borderPoints, LR, null, LL, null, maxHorDivisions, 1.0);
// LL to UL
tileCRSToTargetGrid.transform(LL, 0, out, 0, 1);
borderPoints.add(new Coordinate(out[0], out[1]));
calculateBorder(borderPoints, LL, null, UL, null, maxVertDivisions, 1.0);
// Add start point to complete linear ring
tileCRSToTargetGrid.transform(UL, 0, out, 0, 1);
borderPoints.add(new Coordinate(out[0], out[1]));
// Create Geometry and world wrap correct (need to be in lat/lon)
return JTS.transform(corrector.correct(JTS.transform(TileSet.gf
.createPolygon(TileSet.gf.createLinearRing(borderPoints
.toArray(new Coordinate[borderPoints.size()])), null),
targetGridToLatLon)), targetGridToLatLon.inverse());
}
private int calculateBorder(List<Coordinate> borderList, double[] point1,
double[] transformedPoint1, double[] point3,
double[] transformedPoint3, double maxNumDivs, double threshold)
throws TransformException {
if (transformedPoint1 == null) {
transformedPoint1 = new double[point1.length];
tileCRSToTargetGrid.transform(point1, 0, transformedPoint1, 0, 1);
}
if (transformedPoint3 == null) {
transformedPoint3 = new double[point3.length];
tileCRSToTargetGrid.transform(point3, 0, transformedPoint3, 0, 1);
}
if (transformedPoint1 == null || transformedPoint3 == null) {
// if the image has some points outside the valid range of the
// screen then give up optimizing and assume the max number of
// points.
return (int) Math.ceil(maxNumDivs);
}
double[] point2 = { (point1[0] + point3[0]) / 2,
(point1[1] + point3[1]) / 2 };
double[] transformedPoint2 = new double[point2.length];
tileCRSToTargetGrid.transform(point2, 0, transformedPoint2, 0, 1);
double[] interp2 = { (transformedPoint1[0] + transformedPoint3[0]) / 2,
(transformedPoint1[1] + transformedPoint3[1]) / 2 };
double dX = transformedPoint2[0] - interp2[0];
double dY = transformedPoint2[1] - interp2[1];
double d = Math.hypot(dX, dY);
if (d < threshold || maxNumDivs < 1) {
return 1;
} else {
int nd1 = calculateBorder(borderList, point1, transformedPoint1,
point2, transformedPoint2, maxNumDivs / 2, threshold);
borderList.add(new Coordinate(transformedPoint2[0],
transformedPoint2[1]));
if (nd1 * 2 >= maxNumDivs) {
nd1 = (int) Math.ceil(maxNumDivs);
}
int nd2 = calculateBorder(borderList, point2, transformedPoint2,
point3, transformedPoint3, maxNumDivs / 2, threshold);
if (nd2 * 2 >= maxNumDivs) {
nd2 = (int) Math.ceil(maxNumDivs);
}
return (Math.max(nd1, nd2) * 2);
}
}
}

View file

@ -0,0 +1,462 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.core.tile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.CRSCache;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.IImage.Status;
import com.raytheon.uf.viz.core.drawables.IRenderable;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.jobs.JobPool;
import com.raytheon.uf.viz.core.rsc.capabilities.ImagingCapability;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Renderable tile set class that creates a {@link TileSet} and renders images
* for tiles displayed using the {@link TileImageCreator} passed in at
* construction
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 8, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class TileSetRenderable implements IRenderable {
public static interface TileImageCreator {
/**
* Create a complete DrawableImage for the given tile on the
* targetGeometry
*/
public DrawableImage createTileImage(IGraphicsTarget target, Tile tile,
GeneralGridGeometry targetGeometry) throws VizException;
}
private class TileImageCreatorTask implements Runnable {
private IGraphicsTarget target;
private Tile tile;
private TileImageCreatorTask(IGraphicsTarget target, Tile tile) {
this.target = target;
this.tile = tile;
}
@Override
public void run() {
try {
DrawableImage di = tileCreator.createTileImage(target, tile,
tileSet.getTargetGeometry());
if (di != null) {
di.getImage().stage();
}
addTileImage(tile, di);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
protected static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(TileSetRenderable.class);
/** Screen pixel to image pixel threshold at which we change levels */
protected static final double LEVEL_CHANGE_THRESHOLD = 2.0;
/** Job pool for tile creation */
protected static final JobPool tileCreationPool = new JobPool(
"Creating Image Tiles", 10, false);
/** Job map, should only have one job running per tile at a time */
protected Map<Tile, Runnable> jobMap = new ConcurrentHashMap<Tile, Runnable>();
/** Image map for tiles */
protected Map<Tile, DrawableImage> imageMap = new HashMap<Tile, DrawableImage>();
/** Full resolution tile set GridGeometry2D */
protected final GridGeometry2D tileSetGeometry;
protected final TileImageCreator tileCreator;
/** Desired size for each tile */
protected final int tileSize;
/** Number of tile levels to create */
protected final int tileLevels;
/** {@link TileSet} object, manages tiles */
protected TileSet tileSet;
/** Transform for tileset CRS to lat/lon */
protected final MathTransform localProjToLL;
/** Transform for lat/lon to tileset CRS */
protected final MathTransform llToLocalProj;
/** Stored imaging capability */
protected final ImagingCapability imaging;
/** Last painted tile level, used for interrogating proper level */
protected int lastPaintedLevel;
/** The ratio of target grid pixels / image pixel for each tile level */
protected double[] pixelWidth;
/**
* Constructs a tile set renderable, creators needs to call
* {@link #project(GeneralGridGeometry)} before the renderable can be used
*
* @param resource
* @param tileSetGeometry
* @param tileCreator
* @param tileLevels
* @param tileSize
*/
public TileSetRenderable(ImagingCapability imaging,
GridGeometry2D tileSetGeometry, TileImageCreator tileCreator,
int tileLevels, int tileSize) {
this.tileSetGeometry = tileSetGeometry;
this.tileCreator = tileCreator;
this.tileLevels = tileLevels;
this.tileSize = tileSize;
this.pixelWidth = new double[tileLevels];
this.imaging = imaging;
try {
// Set lat/lon math transforms for tile set
llToLocalProj = CRSCache.getInstance().findMathTransform(
DefaultGeographicCRS.WGS84,
tileSetGeometry.getCoordinateReferenceSystem());
localProjToLL = llToLocalProj.inverse();
} catch (Exception e) {
throw new IllegalArgumentException(
"Could not get tranform from tile crs to lat/lon", e);
}
}
/**
* Projects the tile set for use with the target geometry
*
* @param targetGeometry
*/
public synchronized void project(GeneralGridGeometry targetGeometry) {
// dispose the old TileSet
if (tileSet != null) {
tileSet.dispose();
}
// Create TileSet for new target geometry
tileSet = TileSet.getTileSet(tileSetGeometry, targetGeometry,
tileLevels, tileSize);
// Clear out meshes and create new ones cloning old ones
for (DrawableImage di : imageMap.values()) {
if (di != null) {
IMesh currentMesh = di.getCoverage().getMesh();
if (currentMesh != null) {
try {
di.getCoverage().setMesh(
currentMesh.clone(targetGeometry));
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
currentMesh.dispose();
}
}
}
// Get the pixel densities for each tile level. This is approximately
// how many target grid pixels per image pixel there are for the level
for (int level = 0; level < tileLevels; ++level) {
TileLevel tileLevel = tileSet.getTileLevel(level);
pixelWidth[level] = tileLevel.getPixelDensity();
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.IRenderable#paint(com.raytheon.uf.
* viz.core.IGraphicsTarget,
* com.raytheon.uf.viz.core.drawables.PaintProperties)
*/
@Override
public void paint(IGraphicsTarget target, PaintProperties paintProps)
throws VizException {
Collection<DrawableImage> images = getImagesToRender(target, paintProps);
target.drawRasters(paintProps,
images.toArray(new DrawableImage[images.size()]));
}
/**
* Disposes the tile set and any data associated with it
*/
public synchronized void dispose() {
// Make sure any lingering jobs are canceled and joined on
for (Runnable job : jobMap.values()) {
tileCreationPool.cancel(job);
}
tileCreationPool.join();
// Dispose the tile set
if (tileSet != null) {
tileSet.dispose();
tileSet = null;
}
// Dispose of all the images for the tile set
for (DrawableImage image : imageMap.values()) {
if (image != null) {
image.dispose();
}
}
imageMap.clear();
}
/**
* Get the {@link DrawableImage} list to display for the given target and
* paint properties
*
* @param target
* @param paintProps
* @return
* @throws VizException
*/
public synchronized Collection<DrawableImage> getImagesToRender(
IGraphicsTarget target, PaintProperties paintProps)
throws VizException {
double screenToWorldRatio = paintProps.getCanvasBounds().width
/ paintProps.getView().getExtent().getWidth();
int usedTileLevel = tileLevels - 1;
/*
* pixelRatios[usedTileLevel] * screenToWorldRatio gives us
* canvasPixels/image pixel at the level, We should use the level if
* there are less than LEVEL_CHANGE_THRESHOLD canvas pixels per image
* pixel
*/
while ((pixelWidth[usedTileLevel] * screenToWorldRatio > LEVEL_CHANGE_THRESHOLD)
&& usedTileLevel > 0) {
usedTileLevel--;
}
lastPaintedLevel = usedTileLevel;
return getImagesWithinExtent(target, paintProps.getView().getExtent(),
usedTileLevel, 0);
}
/**
*
* @param target
* @param paintProps
* @param level
* @param depth
* @return
* @throws VizException
*/
protected List<DrawableImage> getImagesWithinExtent(IGraphicsTarget target,
IExtent extent, int level, int depth) throws VizException {
if (tileSet == null) {
// Early exit condition, disposed or haven't projected yet
return Collections.emptyList();
}
// Flag to determine if we should draw lower tile levels. This will be
// the case if we don't have all the images for all intersecting tiles
// at this level
boolean needDrawLower = false;
// Get the intersecting tiles for the level
Collection<Tile> intersecting = tileSet.getIntersectingTiles(level,
extent);
// These Tiles still need images created for them
List<Tile> tilesNeedingImage = new ArrayList<Tile>(intersecting.size());
List<DrawableImage> drawableImages = new ArrayList<DrawableImage>(
intersecting.size());
for (Tile tile : intersecting) {
// Flag to indicate if a tile needs an image created for it
boolean needsImage = false;
DrawableImage di = imageMap.get(tile);
if (di != null) {
IImage image = di.getImage();
if (image.getStatus() == Status.FAILED
|| image.getStatus() == Status.INVALID) {
// Image is invalid, re-request creation
needsImage = true;
} else {
image.setBrightness(imaging.getBrightness());
image.setContrast(imaging.getContrast());
image.setInterpolated(imaging.isInterpolationState());
if (image.getStatus() != Status.LOADED) {
needDrawLower = true;
}
drawableImages.add(di);
}
} else {
needsImage = true;
}
if (needsImage) {
tilesNeedingImage.add(tile);
needDrawLower = true;
}
}
if (depth == 0) {
// Only request images to be created if we are at the desired level
// i.e. the recursion depth is 0
if (tilesNeedingImage.isEmpty()) {
// All intersecting tiles are loaded for this level, cancel any
// jobs running for tiles we don't need anymore (may be case if
// zooming or panning)
for (Runnable job : jobMap.values()) {
tileCreationPool.cancel(job);
}
jobMap.clear();
} else {
target.setNeedsRefresh(true);
// Create tiles needing images
createTileImages(target, tilesNeedingImage);
}
}
// Draw lower resolution data first
if (needDrawLower && (level + 1) < tileLevels) {
// put lower levels first in the list so they are drawn first.
List<DrawableImage> lowerImages = getImagesWithinExtent(target,
extent, level + 1, depth + 1);
lowerImages.addAll(drawableImages);
drawableImages = lowerImages;
}
return drawableImages;
}
/**
* Create tile images for the specified tiles
*
* @param target
* @param tilesToCreate
*/
protected void createTileImages(IGraphicsTarget target,
Collection<Tile> tilesToCreate) {
for (Tile tile : tilesToCreate) {
if (jobMap.get(tile) == null) {
// No job already running for tile, create and schedule one
TileImageCreatorTask job = new TileImageCreatorTask(target,
tile);
jobMap.put(tile, job);
tileCreationPool.schedule(job);
}
}
}
/**
* Adds a DrawableImage for the specified Tile. Disposes of any old image
*
* @param tile
* @param image
*/
public void addTileImage(Tile tile, DrawableImage image) {
DrawableImage oldImage = imageMap.put(tile, image);
if (oldImage != null) {
oldImage.dispose();
}
Runnable task = jobMap.remove(tile);
if (task != null) {
tileCreationPool.cancel(task);
}
}
/**
* Returns the raw image value from tile image that contains the lat/lon
* coordinate
*
* @param coordinate
* in lat/lon space
* @return
* @throws VizException
*/
public double interrogate(Coordinate coordinate) throws VizException {
try {
double[] local = new double[2];
llToLocalProj
.transform(new double[] { coordinate.x, coordinate.y }, 0,
local, 0, 1);
double localX = local[0];
double localY = local[1];
TileLevel level = tileSet.getTileLevel(lastPaintedLevel);
double[] grid = level.crsToGrid(localX, localY);
Tile tile = level.getTile(grid[0], grid[1]);
DrawableImage di = imageMap.get(tile);
if (di != null) {
IImage image = di.getImage();
if (image instanceof IColormappedImage) {
return ((IColormappedImage) image).getValue((int) grid[0]
% tileSize, (int) grid[1] % tileSize);
}
}
} catch (TransformException e) {
throw new VizException("Error interrogating ", e);
}
return Double.NaN;
}
}

View file

@ -32,10 +32,12 @@ import com.raytheon.uf.viz.core.IDisplayPane;
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.globals.VizGlobalsManager;
import com.raytheon.uf.viz.core.maps.display.VizMapEditor;
import com.raytheon.uf.viz.core.status.StatusConstants;
import com.raytheon.uf.viz.d2d.ui.Activator;
import com.raytheon.viz.ui.EditorUtil;
import com.raytheon.viz.ui.HistoryList;
import com.raytheon.viz.ui.editor.AbstractEditor;
import com.raytheon.viz.ui.editor.IMultiPaneEditor;
/**
@ -60,7 +62,8 @@ import com.raytheon.viz.ui.editor.IMultiPaneEditor;
* @version 1
*/
public class ClearAction extends AbstractHandler {
private static final transient IUFStatusHandler statusHandler = UFStatus.getHandler(ClearAction.class);
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(ClearAction.class);
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
@ -69,15 +72,14 @@ public class ClearAction extends AbstractHandler {
new NewMapEditor().execute(null);
return null;
}
if (!(part instanceof IDisplayPaneContainer)) {
return null;
}
try {
HistoryList.getInstance().refreshLatestBundle();
clear((IDisplayPaneContainer) part);
HistoryList.getInstance().addBundle();
if (part instanceof IDisplayPaneContainer) {
HistoryList.getInstance().refreshLatestBundle();
clear(part);
HistoryList.getInstance().addBundle();
} else {
clear(part);
}
} catch (VizException e) {
throw new ExecutionException("Error during clear", e);
}
@ -85,26 +87,19 @@ public class ClearAction extends AbstractHandler {
return null;
}
/**
* Clears the map
*
* The map is cleared with either the provided default-procedure.xml or a
* default world map, if no default-bundle.xml is available.
*
* @param target
* the graphics target
* @return the map descriptor prepared
* @throws VizException
*/
public static void clear(IDisplayPaneContainer container)
throws VizException {
if (container instanceof IMultiPaneEditor) {
((IMultiPaneEditor) container).clear();
public static void clear(IEditorPart part) throws VizException {
if (part instanceof VizMapEditor) {
((VizMapEditor) part).clear();
} else if (part instanceof AbstractEditor) {
// AbstractEditor asks the user if they are sure if we pass in
// save=true, if the user clicked clear than they must be sure so
// pass in save=false.
part.getSite().getPage().closeEditor(part, false);
} else {
for (IDisplayPane displayPane : container.getDisplayPanes()) {
displayPane.clear();
}
// Give other editors a chance to save.
part.getSite().getPage().closeEditor(part, true);
}
if (EditorUtil.getActiveEditor() == null) {
try {
new NewMapEditor().execute(null);

View file

@ -385,11 +385,12 @@ public class MasterDerivScript extends PythonInterpreter {
private void setDataRecordArg(String argName, IDataRecord argValue)
throws JepException {
boolean reshape = true;
long[] sizes = argValue.getSizes();
if (argValue instanceof FloatDataRecord) {
FloatDataRecord record = (FloatDataRecord) argValue;
if (record.getDimension() == 2) {
jep.setNumeric(argName, record.getFloatData(),
(int) record.getSizes()[0], (int) record.getSizes()[1]);
if (sizes.length == 2) {
jep.setNumeric(argName, record.getFloatData(), (int) sizes[0],
(int) sizes[1]);
reshape = false;
} else {
evaluateArgument(argName, record.getFloatData());
@ -401,18 +402,18 @@ public class MasterDerivScript extends PythonInterpreter {
jep.eval("del globals()['numpy']");
} else if (argValue instanceof IntegerDataRecord) {
IntegerDataRecord record = (IntegerDataRecord) argValue;
if (record.getDimension() == 2) {
jep.setNumeric(argName, record.getIntData(),
(int) record.getSizes()[0], (int) record.getSizes()[1]);
if (sizes.length == 2) {
jep.setNumeric(argName, record.getIntData(), (int) sizes[0],
(int) sizes[1]);
reshape = false;
} else {
evaluateArgument(argName, record.getIntData());
}
} else if (argValue instanceof ByteDataRecord) {
ByteDataRecord record = (ByteDataRecord) argValue;
if (record.getDimension() == 2) {
jep.setNumeric(argName, record.getByteData(),
(int) record.getSizes()[0], (int) record.getSizes()[1]);
if (sizes.length == 2) {
jep.setNumeric(argName, record.getByteData(), (int) sizes[0],
(int) sizes[1]);
reshape = false;
} else {
evaluateArgument(argName, record.getByteData());

View file

@ -171,11 +171,11 @@ public abstract class AbstractInventory implements DerivParamUpdateListener {
protected Map<String, List<String>> sourceAliases = new HashMap<String, List<String>>();
private List<String> allSources;
protected List<String> allSources;
private List<String> allParameters;
protected List<String> allParameters;
private List<Level> allLevels;
protected List<Level> allLevels;
/**
* A call to this method assigns the passed grid tree to the original grid

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,8 @@
#Wed May 30 15:50:31 CDT 2012
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,27 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: KML Export
Bundle-SymbolicName: com.raytheon.uf.viz.kml.export;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.raytheon.uf.viz.kml.export.Activator
Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization
Bundle-Vendor: RAYTHEON
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
com.raytheon.uf.common.serialization;bundle-version="1.12.1174",
org.geotools;bundle-version="2.6.4",
com.raytheon.uf.viz.core;bundle-version="1.12.1174",
com.raytheon.uf.viz.core.rsc;bundle-version="1.0.0",
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174",
com.raytheon.uf.common.colormap;bundle-version="1.12.1174",
com.raytheon.uf.common.time;bundle-version="1.12.1174",
com.raytheon.viz.ui;bundle-version="1.12.1174",
com.raytheon.uf.viz.core.maps;bundle-version="1.12.1174",
de.micromata.opengis.kml;bundle-version="1.0.0",
com.raytheon.viz.pointdata;bundle-version="1.12.1174",
com.raytheon.viz.radar;bundle-version="1.12.1174",
com.raytheon.uf.common.dataplugin.radar;bundle-version="1.0.0",
javax.measure;bundle-version="1.0.0",
javax.vecmath;bundle-version="1.3.1"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy

View file

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

View file

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

View file

@ -0,0 +1,50 @@
package com.raytheon.uf.viz.kml.export;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.raytheon.uf.viz.kml.export"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View file

@ -0,0 +1,606 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.kml.export.KmlExportOptions.KmlExportTimeMode;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
/**
* Allow user to select options for export and starts the KmlExportJob.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 5, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlExportDialog extends CaveSWTDialog {
private final KmlExportOptions options;
private Text locationText;
private Tree productTree;
private Button exportHiddenButton;
private Button exportMapsButton;
private Button shadeEarthButton;
private Button setTimesButton;
private Button timeSpanButton;
private Button timeStampButton;
private Button fillPlotsButton;
private Button selectedFramesButton;
private Button currentFramesButton;
private Button allFramesButton;
private Text framesFromText;
private Text framesToText;
public KmlExportDialog(Shell shell, KmlExportOptions options) {
super(shell, SWT.RESIZE | SWT.DIALOG_TRIM);
this.setText("Export KML");
this.options = options;
}
@Override
protected void initializeComponents(Shell shell) {
Composite leftComposite = new Composite(shell, SWT.NONE);
leftComposite.setLayoutData(new GridData(SWT.NONE, SWT.FILL, false,
true));
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.fill = true;
leftComposite.setLayout(layout);
Group locationGroup = new Group(leftComposite, SWT.NONE);
initializeLocationGroup(locationGroup);
Group framesGroup = new Group(leftComposite, SWT.NONE);
initializeFramesGroup(framesGroup);
Group optionsGroup = new Group(leftComposite, SWT.NONE);
initializeOptionsGroup(optionsGroup);
// Group timeOptionsGroup = new Group(leftComposite, SWT.NONE);
// initializeTimeOptionsGroup(timeOptionsGroup);
Group productsGroup = new Group(shell, SWT.NONE);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.widthHint = 250;
productsGroup.setLayoutData(gridData);
initializeProductsGroup(productsGroup);
Composite buttonComposite = new Composite(shell, SWT.NONE);
gridData = new GridData(SWT.FILL, SWT.NONE, true, false, 2, 1);
gridData.horizontalAlignment = SWT.CENTER;
buttonComposite.setLayoutData(gridData);
initializeButtons(buttonComposite);
populateProductTree();
if (productTree.getItemCount() == 0) {
// for the intial load change this option so there is something to
// export.
exportMapsButton.setSelection(true);
populateProductTree();
}
shell.pack();
shell.setMinimumSize(shell.getSize());
}
@Override
protected Layout constructShellLayout() {
GridLayout mainLayout = new GridLayout(2, false);
mainLayout.marginHeight = 3;
mainLayout.marginWidth = 3;
return mainLayout;
}
protected void initializeLocationGroup(Group group) {
group.setLayout(new GridLayout(2, false));
group.setText("Export Location");
locationText = new Text(group, SWT.BORDER);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.widthHint = 250;
locationText.setLayoutData(gridData);
locationText.setText(options.getKmzFileLocation().getAbsolutePath());
Button button = new Button(group, SWT.PUSH);
button.setText("Browse ...");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
selectDestinationFile();
}
});
}
protected void initializeFramesGroup(Group group) {
group.setLayout(new GridLayout(5, false));
group.setText("Export Location");
allFramesButton = new Button(group, SWT.RADIO);
allFramesButton.setText("All Frames");
GridData gridData = new GridData();
gridData.horizontalSpan = 5;
allFramesButton.setLayoutData(gridData);
allFramesButton.setSelection(true);
currentFramesButton = new Button(group, SWT.RADIO);
currentFramesButton.setText("Current Frame");
gridData = new GridData();
gridData.horizontalSpan = 5;
currentFramesButton.setLayoutData(gridData);
selectedFramesButton = new Button(group, SWT.RADIO);
selectedFramesButton.setText("Frames");
new Label(group, SWT.NONE).setText("from:");
framesFromText = new Text(group, SWT.BORDER);
gridData = new GridData();
gridData.widthHint = 24;
framesFromText.setLayoutData(gridData);
framesFromText.setEnabled(false);
framesFromText.setText("1");
new Label(group, SWT.NONE).setText("to:");
framesToText = new Text(group, SWT.BORDER);
gridData = new GridData();
gridData.widthHint = 24;
framesToText.setLayoutData(gridData);
framesToText.setEnabled(false);
int numFrames = 1;
for (KmlPane pane : options.getPanes()) {
int frames = pane.getDisplay().getDescriptor().getFramesInfo()
.getFrameCount();
numFrames = Math.max(frames, numFrames);
}
framesToText.setText(Integer.toString(numFrames));
selectedFramesButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
framesToText.setEnabled(selectedFramesButton.getSelection());
framesFromText.setEnabled(selectedFramesButton.getSelection());
}
});
}
protected void initializeOptionsGroup(Group group) {
group.setText("Other Options");
group.setLayout(new RowLayout(SWT.VERTICAL));
exportHiddenButton = new Button(group, SWT.CHECK);
exportHiddenButton.setText("Export Hidden");
exportHiddenButton.setSelection(true);
exportHiddenButton
.setToolTipText("Include hidden products in the selection of products to export.");
exportHiddenButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
populateProductTree();
}
});
exportMapsButton = new Button(group, SWT.CHECK);
exportMapsButton.setText("Export Maps");
exportMapsButton.setSelection(false);
exportMapsButton
.setToolTipText("Include maps in the selection of products to export.");
exportMapsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
populateProductTree();
}
});
shadeEarthButton = new Button(group, SWT.CHECK);
shadeEarthButton.setText("Shade Earth");
shadeEarthButton.setSelection(options.isShadeEarth());
shadeEarthButton
.setToolTipText("Hides the Google Earth surface imagery.");
fillPlotsButton = new Button(group, SWT.CHECK);
fillPlotsButton.setText("Show Background Tiles");
fillPlotsButton.setSelection(options.isFillPlotBackground());
fillPlotsButton
.setToolTipText("Displays an opaque background tile behind point observations");
}
protected void initializeTimeOptionsGroup(Group group) {
group.setText("Time Options");
group.setLayout(new RowLayout(SWT.VERTICAL));
setTimesButton = new Button(group, SWT.CHECK);
setTimesButton.setText("Set KML Time");
setTimesButton
.setSelection(options.getTimeMode() != KmlExportTimeMode.NONE);
setTimesButton
.setToolTipText("Causes Google Earth to display a time slider.");
Composite timeComposite = new Composite(group, SWT.NONE);
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.marginLeft = 20;
timeComposite.setLayout(layout);
timeSpanButton = new Button(timeComposite, SWT.RADIO);
timeSpanButton.setText("Time Span");
timeSpanButton
.setSelection(options.getTimeMode() != KmlExportTimeMode.TIME_STAMP);
timeSpanButton.setEnabled(setTimesButton.getSelection());
timeSpanButton
.setToolTipText("Allow products to be visible over a time range.");
timeStampButton = new Button(timeComposite, SWT.RADIO);
timeStampButton.setText("Time Stamp");
timeStampButton
.setSelection(options.getTimeMode() == KmlExportTimeMode.TIME_STAMP);
timeStampButton.setEnabled(setTimesButton.getSelection());
timeStampButton
.setToolTipText("Makes each product visible only at its exact valid time.");
setTimesButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
timeSpanButton.setEnabled(setTimesButton.getSelection());
timeStampButton.setEnabled(setTimesButton.getSelection());
}
});
}
protected void initializeProductsGroup(Group group) {
group.setText("Products");
group.setLayout(new FillLayout());
productTree = new Tree(group, SWT.CHECK);
productTree.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (e.detail == SWT.CHECK) {
treeItemChecked((TreeItem) e.item);
}
super.widgetSelected(e);
}
});
}
protected void initializeButtons(Composite comp) {
comp.setLayout(new RowLayout(SWT.HORIZONTAL));
Button okButton = new Button(comp, SWT.PUSH);
okButton.setText("OK");
okButton.setLayoutData(new RowData(100, SWT.DEFAULT));
okButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
okPressed();
}
});
Button cancelButton = new Button(comp, SWT.PUSH);
cancelButton.setText("Cancel");
cancelButton.setLayoutData(new RowData(100, SWT.DEFAULT));
cancelButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
protected void populateProductTree() {
boolean exportMaps = exportMapsButton.getSelection();
boolean exportHidden = exportHiddenButton.getSelection();
if (options.isSinglePane()) {
List<ResourcePair> rscList = options.getSinglPane().getResources(
exportMaps, exportHidden);
populateProductSubTree(rscList, null);
} else {
int index = 0;
for (KmlPane pane : options.getPanes()) {
List<ResourcePair> rscList = pane.getResources(exportMaps,
exportHidden);
TreeItem item = null;
if (index < productTree.getItemCount()) {
item = productTree.getItem(index);
}
if (!rscList.isEmpty()) {
if (item == null || item.getData() != pane) {
item = new TreeItem(productTree, SWT.NONE, index);
item.setText("Pane " + (index + 1));
item.setData(pane);
populateProductSubTree(rscList, item);
item.setExpanded(true);
} else {
populateProductSubTree(rscList, item);
}
index += 1;
} else {
if (item != null && item.getData() == pane) {
item.dispose();
}
}
}
}
}
private void populateProductSubTree(List<ResourcePair> rscList,
final TreeItem parent) {
TreeItem[] items = parent != null ? parent.getItems() : productTree
.getItems();
int itemIndex = 0;
int rscIndex = 0;
while (itemIndex < items.length || rscIndex < rscList.size()) {
TreeItem item = null;
if (itemIndex < items.length) {
item = items[itemIndex];
}
ResourcePair pair = null;
if (rscIndex < rscList.size()) {
pair = rscList.get(rscIndex);
}
if (item != null && item.getData() == pair) {
itemIndex += 1;
rscIndex += 1;
} else if (item != null && !rscList.contains(item.getData())) {
item.dispose();
itemIndex += 1;
} else {
if (parent != null) {
item = new TreeItem(parent, SWT.NONE, rscIndex);
} else {
item = new TreeItem(productTree, SWT.NONE, rscIndex);
}
String name = pair.getResource().getName();
if (name == null) {
name = pair.getResource().getClass().getSimpleName();
}
item.setText(name);
item.setData(pair);
item.setChecked(true);
treeItemChecked(item);
rscIndex += 1;
}
}
}
private void treeItemChecked(TreeItem item) {
for (TreeItem ti : item.getItems()) {
ti.setChecked(item.getChecked());
}
TreeItem parent = item.getParentItem();
while (parent != null) {
parent.setChecked(true);
for (TreeItem ti : parent.getItems()) {
if (!ti.getChecked()) {
parent.setChecked(false);
break;
}
}
parent = parent.getParentItem();
}
}
protected void selectDestinationFile() {
FileDialog fileDialog = new FileDialog(this.shell, SWT.SAVE);
File file = new File(locationText.getText());
fileDialog.setFileName(file.getName());
if (file.getParentFile() != null && file.getParentFile().isDirectory()) {
fileDialog.setFilterPath(file.getParent());
}
fileDialog.setFilterExtensions(new String[] { ".kmz" });
fileDialog.open();
String filterPath = fileDialog.getFilterPath();
String selectedFile = fileDialog.getFileName();
/*
* Ensure that the user has entered a name for the file.
*/
if (selectedFile.equalsIgnoreCase("")) {
return;
}
if (!filterPath.endsWith("/")) {
filterPath += "/";
}
String destinationFile = filterPath + selectedFile;
this.locationText.setText(destinationFile);
this.locationText.setToolTipText(destinationFile);
}
protected void okPressed() {
if (allFramesButton.getSelection()) {
options.setFirstFrameIndex(Integer.MIN_VALUE);
options.setLastFrameIndex(Integer.MAX_VALUE);
} else if (currentFramesButton.getSelection()) {
for (KmlPane pane : options.getPanes()) {
int frame = pane.getDisplay().getDescriptor().getFramesInfo()
.getFrameIndex();
frame = Math.max(0, frame);
options.setFirstFrameIndex(frame);
options.setLastFrameIndex(frame + 1);
}
} else {
try {
int from = Integer.parseInt(framesFromText.getText()) - 1;
options.setFirstFrameIndex(from);
} catch (NumberFormatException e) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR
| SWT.OK);
mb.setText("Invalid Number");
mb.setMessage(framesFromText.getText()
+ " is not a valid number, please enter a valid number for the starting frame.");
mb.open();
return;
}
try {
int to = Integer.parseInt(framesToText.getText());
options.setLastFrameIndex(to);
} catch (NumberFormatException e) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR
| SWT.OK);
mb.setText("Invalid Number");
mb.setMessage(framesFromText.getText()
+ " is not a valid number, please enter a valid number for the ending frame.");
mb.open();
return;
}
}
options.setKmzFileLocation(new File(locationText.getText()));
options.setShadeEarth(shadeEarthButton.getSelection());
// if (!setTimesButton.getSelection()) {
// options.setTimeMode(KmlExportTimeMode.NONE);
// } else if (timeSpanButton.getSelection()) {
// options.setTimeMode(KmlExportTimeMode.TIME_SPAN);
// } else if (timeStampButton.getSelection()) {
// options.setTimeMode(KmlExportTimeMode.TIME_STAMP);
//
// }
options.setFillPlotBackground(fillPlotsButton.getSelection());
if (options.isSinglePane()) {
List<ResourcePair> resourcesToExport = new ArrayList<ResourcePair>();
for (TreeItem ti : productTree.getItems()) {
if (ti.getChecked()) {
resourcesToExport.add((ResourcePair) ti.getData());
}
}
options.getSinglPane().setResourcesToExport(resourcesToExport);
} else {
for (TreeItem paneitem : productTree.getItems()) {
KmlPane pane = (KmlPane) paneitem.getData();
List<ResourcePair> resourcesToExport = new ArrayList<ResourcePair>();
for (TreeItem ti : paneitem.getItems()) {
if (ti.getChecked()) {
resourcesToExport.add((ResourcePair) ti.getData());
}
}
pane.setResourcesToExport(resourcesToExport);
}
}
if (!validate()) {
// clear the current selection
for (KmlPane pane : options.getPanes()) {
pane.setResourcesToExport(null);
}
return;
}
new KmlExportJob(options).schedule();
close();
}
protected boolean validate() {
boolean products = false;
for (KmlPane pane : options.getPanes()) {
if (pane.getResourcesToExport() != null
&& !pane.getResourcesToExport().isEmpty()) {
products = true;
break;
}
}
if (!products) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK);
mb.setText("No Products");
mb.setMessage("No products are selected.");
mb.open();
return false;
}
if (options.getFirstFrameIndex() > options.getLastFrameIndex()
|| options.getLastFrameIndex() < 0) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK);
mb.setText("Invalid Range");
mb.setMessage("The frame range you entered is invalid, please enter a valid range");
mb.open();
return false;
}
File file = options.getKmzFileLocation();
if (!file.getParentFile().exists()) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_QUESTION
| SWT.YES | SWT.NO);
mb.setText("Create Directory");
mb.setMessage("The directory " + file.getParent()
+ " does not exist, would you like to create it.");
int result = mb.open();
if (result == SWT.YES) {
if (!file.getParentFile().mkdirs()) {
mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK);
mb.setText("Error Creating Directory");
mb.setMessage("An unspecified error has occured creating the directory, please select a new file location.");
mb.open();
return false;
}
} else {
return false;
}
}
if (file.exists()) {
MessageBox mb = new MessageBox(getShell(), SWT.ICON_WARNING
| SWT.YES | SWT.NO);
mb.setText("Overwrite file");
mb.setMessage("The specified file already exist. Would you like to overwrite it?");
int result = mb.open();
if (result == SWT.NO) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,103 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.handlers.HandlerUtil;
import com.raytheon.uf.viz.core.IDisplayPane;
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay;
import com.raytheon.uf.viz.core.maps.display.MapRenderableDisplay;
import com.raytheon.uf.viz.kml.export.KmlExportOptions.KmlExportTimeMode;
import com.raytheon.viz.ui.EditorUtil;
/**
*
* Handler for events from the KML Export menu item.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlExportHandler extends AbstractHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
new KmlExportDialog(HandlerUtil.getActiveShell(event),
getDefaultOptions()).open();
return null;
}
protected static KmlExportOptions getDefaultOptions() {
KmlExportOptions options = new KmlExportOptions();
options.setFirstFrameIndex(Integer.MIN_VALUE);
options.setLastFrameIndex(Integer.MAX_VALUE);
options.setPreserveVisibility(true);
options.setShadeEarth(false);
options.setTimeMode(KmlExportTimeMode.TIME_SPAN);
options.setKmzFileLocation(new File(System.getProperty("user.home"),
"caveExport.kmz"));
options.setPlotIconScale(3.5);
options.setFillPlotBackground(false);
options.setPaintSleepMillis(10);
options.setMaxRefreshSeconds(60);
IDisplayPaneContainer container = EditorUtil.getActiveVizContainer();
List<KmlPane> panes = new ArrayList<KmlPane>();
for (IDisplayPane pane : container.getDisplayPanes()) {
AbstractRenderableDisplay display = (AbstractRenderableDisplay) pane
.getRenderableDisplay();
panes.add(new KmlPane(display, pane.getBounds()));
}
options.setPanes(panes);
return options;
}
@Override
public void setEnabled(Object evaluationContext) {
IDisplayPaneContainer container = EditorUtil.getActiveVizContainer();
if (container == null) {
super.setBaseEnabled(false);
return;
}
IDisplayPane pane = container.getActiveDisplayPane();
if (pane == null) {
super.setBaseEnabled(false);
return;
}
super.setBaseEnabled(pane.getRenderableDisplay() instanceof MapRenderableDisplay);
}
}

View file

@ -0,0 +1,676 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.graphics.RGB;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.GeodeticCalculator;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.colormap.Color;
import com.raytheon.uf.common.colormap.IColorMap;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.TransformFactory;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters.LabelEntry;
import com.raytheon.uf.viz.core.drawables.IDescriptor;
import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.PaintStatus;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.jobs.JobPool;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.IResourceGroup;
import com.raytheon.uf.viz.core.rsc.ResourceList;
import com.raytheon.uf.viz.core.rsc.capabilities.BlendableCapability;
import com.raytheon.uf.viz.core.rsc.capabilities.BlendedCapability;
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsFactoryAdapter;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.raytheon.uf.viz.kml.export.io.KmlRootOutputManager;
import de.micromata.opengis.kml.v_2_2_0.AbstractObject;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.LookAt;
import de.micromata.opengis.kml.v_2_2_0.MultiGeometry;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.PolyStyle;
import de.micromata.opengis.kml.v_2_2_0.ScreenOverlay;
import de.micromata.opengis.kml.v_2_2_0.Style;
import de.micromata.opengis.kml.v_2_2_0.TimePrimitive;
import de.micromata.opengis.kml.v_2_2_0.TimeSpan;
import de.micromata.opengis.kml.v_2_2_0.TimeStamp;
import de.micromata.opengis.kml.v_2_2_0.Units;
import de.micromata.opengis.kml.v_2_2_0.Vec2;
/**
* The main Job for exporting KML in a background thread
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 6, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlExportJob extends Job {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlExportJob.class);
private static final SimpleDateFormat KML_TIME_FORMAT = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
private final KmlExportOptions options;
private final JobPool backgroundPool = new JobPool("Exporting KML", 4,
true, Job.INTERACTIVE);
public KmlExportJob(KmlExportOptions options) {
super("Generating Kml");
setUser(true);
this.options = options;
KML_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
}
@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor smonitor = SubMonitor
.convert(monitor, "Generating KML", 800);
try {
copyPanes(smonitor.newChild(20, SubMonitor.SUPPRESS_NONE));
initPanes(smonitor.newChild(80, SubMonitor.SUPPRESS_NONE));
KmlRootOutputManager out = new KmlRootOutputManager(
options.getKmzFileLocation());
exportPanes(smonitor.newChild(500, SubMonitor.SUPPRESS_NONE), out);
joinBackground(smonitor.newChild(150, SubMonitor.SUPPRESS_NONE));
// Do not dispose until all background processes are done
for (KmlPane pane : options.getPanes()) {
pane.getDisplay().dispose();
}
recursiveInvisibility(out.getContainer(), true);
out.close();
smonitor.worked(50);
} catch (IOException e) {
statusHandler.handle(Priority.PROBLEM, "Error writing KML", e);
}
smonitor.done();
return Status.OK_STATUS;
}
/**
* Copy each pane and remove any panes that aren't being exported.
*
* @param monitor
*/
private void copyPanes(IProgressMonitor monitor) {
// Keep this code as fast as possible, if the user runs kml export in
// the background and modifies the main display it will affect kml if
// copy is not done.
List<KmlPane> panes = options.getPanes();
monitor.beginTask("Copying Displays", panes.size());
Iterator<KmlPane> paneIt = panes.iterator();
while (paneIt.hasNext()) {
KmlPane pane = paneIt.next();
List<ResourcePair> exports = pane.getResourcesToExport();
if (exports == null || exports.isEmpty()) {
paneIt.remove();
} else {
try {
AbstractRenderableDisplay display = pane.getDisplay();
// copy the current time before clone
FramesInfo fi = display.getDescriptor().getFramesInfo();
if (fi.getFrameTimes() != null) {
int index = fi.getFrameIndex();
if (index > options.getFirstFrameIndex()
&& index < options.getLastFrameIndex()) {
pane.setDisplayedTime(fi.getFrameTimes()[fi
.getFrameIndex()]);
}
}
display = display.cloneDisplay();
pane.setDisplay(display);
KmlGraphicsFactoryAdapter graphicsAdapter = new KmlGraphicsFactoryAdapter(
display.getView().getExtent(), pane.getBounds());
display.setGraphicsAdapter(graphicsAdapter);
KmlGraphicsTarget target = graphicsAdapter.constructTarget(
null, 0.0f, 0.0f);
target.setBackgroundColor(display.getBackgroundColor());
display.setup(target);
pane.setTarget(target);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
paneIt.remove();
}
}
monitor.worked(1);
}
monitor.done();
}
private void initPanes(IProgressMonitor monitor) {
List<KmlPane> panes = options.getPanes();
monitor.beginTask("Initializing Displays", panes.size());
Iterator<KmlPane> paneIt = panes.iterator();
while (paneIt.hasNext()) {
KmlPane pane = paneIt.next();
try {
AbstractRenderableDisplay display = pane.getDisplay();
IDescriptor descriptor = display.getDescriptor();
descriptor.setRenderableDisplay(display);
descriptor.getResourceList().instantiateResources(descriptor,
true);
for (ResourcePair rp : descriptor.getResourceList()) {
rp.getResource().init(pane.getTarget());
monitor.worked(1);
}
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
paneIt.remove();
}
monitor.worked(1);
}
monitor.done();
}
private void exportPanes(IProgressMonitor monitor, KmlOutputManager out)
throws IOException {
List<KmlPane> panes = options.getPanes();
SubMonitor smonitor = SubMonitor.convert(monitor, "Exporting Displays",
panes.size() * 100);
int paneNumber = 1;
for (KmlPane pane : options.getPanes()) {
KmlOutputManager displayOut = out;
if (!options.isSinglePane()) {
displayOut = out.createFolder("Pane " + (paneNumber++));
}
AbstractRenderableDisplay display = pane.getDisplay();
setView(pane, displayOut);
if (options.isShadeEarth()) {
shadeEarth(displayOut, display.getBackgroundColor());
}
IDescriptor descriptor = display.getDescriptor();
List<ResourcePair> exports = new ArrayList<ResourcePair>();
for (ResourcePair rp : descriptor.getResourceList()) {
if (pane.getResourcesToExport().contains(rp)) {
exports.add(rp);
} else {
rp.getProperties().setVisible(false);
}
}
exportResources(smonitor.newChild(100, SubMonitor.SUPPRESS_NONE),
displayOut, exports, pane);
if (smonitor.isCanceled()) {
break;
}
}
smonitor.done();
}
private void exportResources(IProgressMonitor monitor,
KmlOutputManager out, List<ResourcePair> exports, KmlPane pane)
throws IOException {
SubMonitor smonitor = SubMonitor.convert(monitor, "Exporting Products",
exports.size() * 100);
KmlGraphicsTarget target = pane.getTarget();
AbstractRenderableDisplay display = pane.getDisplay();
IDescriptor descriptor = display.getDescriptor();
List<Boolean> visibility = new ArrayList<Boolean>();
for (ResourcePair rp : exports) {
visibility.add(rp.getProperties().isVisible());
rp.getProperties().setVisible(false);
}
for (int c = 0; c < exports.size(); c++) {
ResourcePair rp = exports.get(c);
AbstractVizResource<?, ?> rsc = rp.getResource();
rp.getProperties().setVisible(true);
String name = rp.getResource().getName();
if (name == null) {
name = rp.getResource().getClass().getSimpleName();
}
KmlOutputManager resourceOut = out.createFolder(name.trim());
SubMonitor rscmonitor = smonitor.newChild(100,
SubMonitor.SUPPRESS_NONE);
if (rsc.hasCapability(BlendableCapability.class)) {
ResourceList list = rsc
.getCapability(BlendableCapability.class)
.getResourceList();
exportResources(rscmonitor, resourceOut, list, pane);
} else {
int startIndex = options.getFirstFrameIndex();
startIndex = Math.max(startIndex, 0);
int lastIndex = options.getLastFrameIndex();
lastIndex = Math.min(lastIndex, descriptor.getNumberOfFrames());
rscmonitor.beginTask("Saving " + rsc.getName(), lastIndex
- startIndex);
addColorMap(resourceOut, display.getBackgroundColor(), rsc);
DataTime[] times = descriptor.getFramesInfo().getTimeMap()
.get(rsc);
if ((times == null || times.length == 0)
&& rsc instanceof IResourceGroup) {
ResourceList list = ((IResourceGroup) rsc)
.getResourceList();
for (ResourcePair pair : list) {
times = descriptor.getFramesInfo().getTimeMap()
.get(pair.getResource());
if (times != null && times.length > 0) {
break;
}
}
}
List<DataTime> pastFrames = new ArrayList<DataTime>();
for (int i = startIndex; i < lastIndex; i += 1) {
descriptor.setFramesInfo(new FramesInfo(i));
KmlOutputManager timeOut = resourceOut;
if (rsc.isTimeAgnostic()
&& (times == null || times.length == 0)) {
i = lastIndex - 1;
} else {
if (i < 0 || times == null || i >= times.length) {
rscmonitor.worked(1);
continue;
}
DataTime time = times[i];
if (time == null || pastFrames.contains(time)) {
rscmonitor.worked(1);
continue;
}
timeOut = resourceOut.createFolder(time
.getLegendString());
timeOut.getContainer().setTimePrimitive(
getTimePrimitive(times, i));
pastFrames.add(time);
}
PaintProperties paintProps = new PaintProperties(1.0f,
(float) display.getZoom(), display.getView(),
pane.getBounds(), false, descriptor.getFramesInfo());
paintResource(rscmonitor, timeOut, display, target, rsc,
paintProps);
rscmonitor.worked(1);
if (rscmonitor.isCanceled()) {
return;
}
}
}
rp.getProperties().setVisible(false);
if (options.isPreserveVisibility() && !visibility.get(c)) {
resourceOut.getContainer().setVisibility(false);
}
rscmonitor.done();
}
}
private void setView(KmlPane pane, KmlOutputManager out) {
IExtent extent = pane.getDisplay().getView().getExtent();
try {
DirectPosition2D center = new DirectPosition2D(
extent.getCenter()[0], extent.getCenter()[1]);
DirectPosition2D corner = new DirectPosition2D(extent.getMaxX(),
extent.getMinX());
MathTransform gridToLatLon = TransformFactory.gridToLatLon(pane
.getDisplay().getDescriptor().getGridGeometry(),
PixelInCell.CELL_CENTER);
gridToLatLon.transform(center, center);
gridToLatLon.transform(corner, corner);
GeodeticCalculator gc = new GeodeticCalculator();
gc.setStartingGeographicPoint(MapUtil.correctLon(center.x),
center.y);
gc.setDestinationGeographicPoint(MapUtil.correctLon(corner.x),
corner.y);
LookAt lookAt = out.getContainer().createAndSetLookAt();
lookAt.setLongitude(center.x);
lookAt.setLatitude(center.y);
lookAt.setRange(gc.getOrthodromicDistance());
if (pane.getDisplayedTime() != null) {
DataTime time = pane.getDisplayedTime();
TimeStamp ts = new TimeStamp();
ts.setWhen(KML_TIME_FORMAT.format(new Date(time.getMatchValid())));
// At the time of this writing the current api doesn't allow
// setting time primitive for AbstractView
lookAt.setAbstractViewObjectExtension(Arrays
.asList((AbstractObject) ts));
}
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
/**
* Given a list of times for a resource and the index of the current time,
* generate a KML TimePrimitive for a resource. When the time mode is SPAN
* the times in the array are used to calculate a span such that the spans
* for every time create a continuos time line.
*
* @param times
* @param index
* @return
*/
private TimePrimitive getTimePrimitive(DataTime[] times, int index) {
long validTime = times[index].getMatchValid();
switch (options.getTimeMode()) {
case TIME_STAMP: {
TimeStamp ts = new TimeStamp();
ts.setWhen(KML_TIME_FORMAT.format(new Date(validTime)));
return ts;
}
case TIME_SPAN: {
long prevValid = 0;
long nextValid = 0;
for (DataTime t : times) {
if (t == null) {
continue;
}
long valid = t.getMatchValid();
if (valid < validTime) {
if (prevValid == 0 || prevValid < valid) {
prevValid = valid;
}
} else if (valid > validTime) {
if (nextValid == 0 || nextValid > valid) {
nextValid = valid;
}
}
}
long prevDist = 0;
long nextDist = 0;
if (prevValid != 0) {
nextDist = prevDist = (validTime - prevValid) / 2;
}
if (nextValid != 0) {
nextDist = (nextValid - validTime) / 2;
if (prevDist == 0) {
prevDist = nextDist;
}
}
TimeSpan span = new TimeSpan();
span.setBegin(KML_TIME_FORMAT
.format(new Date(validTime - prevDist)));
span.setEnd(KML_TIME_FORMAT.format(new Date(validTime + nextDist)));
return span;
}
default:
return null;
}
}
/**
* KML reference documentation from google clearly states that a feature is
* visible only if all of it's ancestors are also visible. Google
* Earth(tested on version 6.2) ignores this and displays everything as
* visible unless that item is specifically set to invisible even when
* ancestors are invisible. This function makes google earth work properly
* by finding invisible features and making all their children invisible.
*
* @param feature
* @param parentVisibility
*/
private void recursiveInvisibility(Feature feature, boolean parentVisibility) {
if (!parentVisibility) {
feature.setVisibility(false);
}
List<Feature> features = null;
if (feature instanceof Folder) {
features = ((Folder) feature).getFeature();
} else if (feature instanceof Document) {
features = ((Document) feature).getFeature();
}
if (features == null) {
return;
}
for (Feature f : features) {
if (f == null) {
continue;
}
recursiveInvisibility(f,
!Boolean.FALSE.equals(feature.isVisibility()));
}
}
private void paintResource(IProgressMonitor monitor, KmlOutputManager out,
AbstractRenderableDisplay display, KmlGraphicsTarget target,
AbstractVizResource<?, ?> resource, PaintProperties paintProps) {
target.setNeedsRefresh(true);
long startTime = System.currentTimeMillis();
while (target.isNeedsRefresh()
|| resource.getPaintStatus() != PaintStatus.PAINTED) {
if (target.isNeedsRefresh()) {
target.beginFrame(paintProps.getView(), false);
try {
display.paint(target, paintProps);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
return;
}
target.endFrame();
}
if (System.currentTimeMillis() - startTime > options
.getMaxRefreshSeconds() * 1000) {
statusHandler.handle(Priority.PROBLEM, resource.getName()
+ " took more than " + options.getMaxRefreshSeconds()
+ " seconds to paint, KML may be incomplete.");
break;
}
try {
Thread.sleep(options.getPaintSleepMillis());
} catch (InterruptedException e) {
}
if (monitor.isCanceled()) {
break;
}
}
List<KmlFeatureGenerator> generators = new ArrayList<KmlFeatureGenerator>(
target.getGenerators());
for (KmlFeatureGenerator generator : generators) {
generator
.setGridGeometry(display.getDescriptor().getGridGeometry());
generator.setBackgroundColor(display.getBackgroundColor());
generator.setOptions(options);
}
backgroundPool.schedule(new GenerateRunnable(generators, out));
}
private void addColorMap(KmlOutputManager out, RGB backcolor,
AbstractVizResource<?, ?> rsc) throws IOException {
ColorMapParameters parameters = null;
if (rsc.hasCapability(ColorMapCapability.class)) {
ColorMapCapability cap = rsc
.getCapability(ColorMapCapability.class);
parameters = cap.getColorMapParameters();
} else {
return;
}
double xAnchor = 0;
if (rsc.hasCapability(BlendedCapability.class)) {
BlendedCapability cap = rsc.getCapability(BlendedCapability.class);
xAnchor = Math.min(1, cap.getResourceIndex());
}
IColorMap colorMap = parameters.getColorMap();
BufferedImage bi = new BufferedImage(colorMap.getSize() * 2, 25,
BufferedImage.TYPE_INT_RGB);
Graphics graphics = bi.getGraphics();
graphics.setColor(new java.awt.Color(backcolor.red, backcolor.green,
backcolor.blue));
graphics.fillRect(0, 0, bi.getWidth(), 25);
int x = 0;
for (Color color : colorMap.getColors()) {
graphics.setColor(new java.awt.Color(color.getRed(), color
.getGreen(), color.getBlue(), color.getAlpha()));
graphics.drawLine(x, 0, x, 25);
x += 1;
graphics.drawLine(x, 0, x, 25);
x += 1;
}
for (LabelEntry label : parameters.getLabels()) {
if (label.getText().isEmpty()) {
continue;
}
Rectangle2D bounds = graphics.getFontMetrics().getStringBounds(
label.getText(), graphics);
int centerX = (int) (bi.getWidth() * label.getLocation());
int leftX = (int) (centerX - bounds.getWidth() / 2);
if (leftX < 0) {
leftX = 0;
} else if (leftX + bounds.getWidth() > bi.getWidth()) {
leftX = (int) (bi.getWidth() - bounds.getWidth());
}
graphics.setColor(java.awt.Color.BLACK);
graphics.fillRect(leftX - 1, 2, (int) bounds.getWidth() + 2,
(int) bounds.getHeight() + 2);
graphics.setColor(java.awt.Color.WHITE);
graphics.drawString(label.getText(), leftX,
(int) bounds.getHeight() + 1);
}
graphics.dispose();
ScreenOverlay overlay = new ScreenOverlay();
overlay.setName("ColorMap");
Vec2 overlayxy = overlay.createAndSetOverlayXY();
overlayxy.withX(xAnchor).withXunits(Units.FRACTION);
overlayxy.withY(1).withYunits(Units.FRACTION);
Vec2 screenxy = overlay.createAndSetScreenXY();
screenxy.withX(xAnchor).withXunits(Units.FRACTION);
screenxy.withY(1).withYunits(Units.FRACTION);
overlay.createAndSetIcon().setHref(
out.addImage(bi, "colormap" + xAnchor + ".png"));
out.addFeature(overlay);
}
private void shadeEarth(KmlOutputManager out, RGB color) {
Placemark placemark = new Placemark();
placemark.setName("Background Color");
Style style = new Style();
style.createAndSetIconStyle().setScale(0.0);
PolyStyle polyStyle = style.createAndSetPolyStyle();
polyStyle.setFill(true);
polyStyle.setOutline(false);
polyStyle.setColor(KmlFeatureGenerator.toColorStr(1.0, color));
placemark.setStyleUrl(out.getStyleUrl(style));
// Google earth seems to do a weird things with one big polygon when you
// zoom way out, specifically there is lots of flickering and it misses
// big pieces towards the back of the sphere, lots of smaller polygons
// helps avoid the missing hunks but I still see a lot of flickering.
MultiGeometry multi = placemark.createAndSetMultiGeometry();
for (int i = -180; i < 180; i += 10) {
for (int j = -90; j < 90; j += 10) {
LinearRing ring = multi.createAndAddPolygon()
.createAndSetOuterBoundaryIs().createAndSetLinearRing();
ring.addToCoordinates(i, j);
ring.addToCoordinates(i, j + 10);
ring.addToCoordinates(i + 10, j + 10);
ring.addToCoordinates(i + 10, j);
ring.addToCoordinates(i, j);
}
}
out.addFeature(placemark);
}
private void joinBackground(IProgressMonitor monitor) {
// some tasks(like radar mosaic) can take a very long time to finish the
// background task, so this waits for those to finish and makes an
// attempt to let the user know how it is going.
int remaining = backgroundPool.getWorkRemaining();
monitor.beginTask("Finalizing KML", remaining);
while (remaining > 0) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
int r = backgroundPool.getWorkRemaining();
monitor.worked(remaining - r);
remaining = r;
if (monitor.isCanceled()) {
monitor.subTask("Canceling");
backgroundPool.cancel();
break;
}
}
backgroundPool.join();
}
private static class GenerateRunnable implements Runnable {
private final List<KmlFeatureGenerator> generators;
private final KmlOutputManager outputManager;
public GenerateRunnable(List<KmlFeatureGenerator> generators,
KmlOutputManager outputManager) {
this.generators = generators;
this.outputManager = outputManager;
}
@Override
public void run() {
for (KmlFeatureGenerator generator : generators) {
generator.addFeature(outputManager);
}
}
}
}

View file

@ -0,0 +1,172 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.io.File;
import java.util.List;
/**
* Contains any options which can be configured for KML export.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 4, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlExportOptions {
public enum KmlExportTimeMode {
NONE, TIME_STAMP, TIME_SPAN;
}
private File kmzFileLocation;
private int firstFrameIndex;
private int lastFrameIndex;
private boolean shadeEarth;
// Google Earth requires a fairly large plot scale to make plots look nice
// but World Wind prefers a smaller scale.
private double plotIconScale;
private boolean fillPlotBackground;
private boolean preserveVisibility;
private KmlExportTimeMode timeMode;
private List<KmlPane> panes;
private int paintSleepMillis;
private int maxRefreshSeconds;
public File getKmzFileLocation() {
return kmzFileLocation;
}
public void setKmzFileLocation(File kmzFileLocation) {
this.kmzFileLocation = kmzFileLocation;
}
public int getFirstFrameIndex() {
return firstFrameIndex;
}
public void setFirstFrameIndex(int firstFrameIndex) {
this.firstFrameIndex = firstFrameIndex;
}
public int getLastFrameIndex() {
return lastFrameIndex;
}
public void setLastFrameIndex(int lastFrameIndex) {
this.lastFrameIndex = lastFrameIndex;
}
public boolean isShadeEarth() {
return shadeEarth;
}
public void setShadeEarth(boolean shadeEarth) {
this.shadeEarth = shadeEarth;
}
public boolean isFillPlotBackground() {
return fillPlotBackground;
}
public void setFillPlotBackground(boolean fillPlotBackground) {
this.fillPlotBackground = fillPlotBackground;
}
public boolean isPreserveVisibility() {
return preserveVisibility;
}
public void setPreserveVisibility(boolean preserveVisibility) {
this.preserveVisibility = preserveVisibility;
}
public KmlExportTimeMode getTimeMode() {
return timeMode;
}
public void setTimeMode(KmlExportTimeMode timeMode) {
this.timeMode = timeMode;
}
public List<KmlPane> getPanes() {
return panes;
}
public void setPanes(List<KmlPane> panes) {
this.panes = panes;
}
public boolean isSinglePane() {
return panes != null && panes.size() == 1;
}
public KmlPane getSinglPane() {
if (isSinglePane()) {
return panes.get(0);
} else {
return null;
}
}
public int getPaintSleepMillis() {
return paintSleepMillis;
}
public void setPaintSleepMillis(int paintSleepMillis) {
this.paintSleepMillis = paintSleepMillis;
}
public int getMaxRefreshSeconds() {
return maxRefreshSeconds;
}
public void setMaxRefreshSeconds(int maxRefreshSeconds) {
this.maxRefreshSeconds = maxRefreshSeconds;
}
public double getPlotIconScale() {
return plotIconScale;
}
public void setPlotIconScale(double plotIconScale) {
this.plotIconScale = plotIconScale;
}
}

View file

@ -0,0 +1,111 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.TransformFactory;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
/**
* Anything that can be drawn on the screen can also be used to create a KML
* feature, this class provides some basic utility functions as well as an
* interface for classes that generate KML.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class KmlFeatureGenerator {
protected GridGeometry2D gridGeometry;
protected MathTransform gridToLatLon;
protected RGB backgroundColor;
protected KmlExportOptions options;
public void setGridGeometry(GeneralGridGeometry gridGeometry) {
this.gridGeometry = GridGeometry2D.wrap(gridGeometry);
}
public void setBackgroundColor(RGB backgroundColor) {
this.backgroundColor = backgroundColor;
}
public void setOptions(KmlExportOptions options) {
this.options = options;
}
public Coordinate transformToLatLon(double gridX, double gridY)
throws TransformException, FactoryException {
return transformToLatLon(new double[] { gridX, gridY });
}
public Coordinate transformToLatLon(double[] gridPixel)
throws TransformException, FactoryException {
if (gridToLatLon == null) {
gridToLatLon = TransformFactory.gridToLatLon(gridGeometry,
PixelInCell.CELL_CENTER);
}
double[] out = new double[2];
gridToLatLon.transform(gridPixel, 0, out, 0, 1);
return new Coordinate(out[0], out[1]);
}
public List<Coordinate> transformToLatLon(List<double[]> gridPixels)
throws TransformException, FactoryException {
List<Coordinate> result = new ArrayList<Coordinate>();
for (double[] gridPixel : gridPixels) {
result.add(transformToLatLon(gridPixel));
}
return result;
}
public abstract void addFeature(KmlOutputManager outputManager);
public static String toColorStr(double alpha, RGB rgb) {
return String.format("%02x%02x%02x%02x", (int) (alpha * 255), rgb.blue,
rgb.green, rgb.red);
}
}

View file

@ -0,0 +1,123 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.graphics.Rectangle;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
/**
* VizDisplayPane but for KML!
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 5, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPane {
private List<ResourcePair> resourcesToExport;
private AbstractRenderableDisplay display;
private Rectangle bounds;
private KmlGraphicsTarget target;
private DataTime displayedTime;
public KmlPane(AbstractRenderableDisplay display, Rectangle bounds) {
this.display = display;
this.bounds = bounds;
}
public List<ResourcePair> getResources(boolean includeMaps,
boolean includeHidden) {
List<ResourcePair> rscList = new ArrayList<ResourcePair>();
for (ResourcePair rp : display.getDescriptor().getResourceList()) {
if (!rp.getResourceData().equals(rp.getResourceData())) {
// A special check for those special resources which will never
// work with KML because they don't properly implement equals.
// ... like GFE
continue;
} else if (rp.getProperties().isSystemResource()) {
continue;
} else if (!includeMaps && rp.getProperties().isMapLayer()) {
continue;
} else if (!includeHidden && !rp.getProperties().isVisible()) {
continue;
}
rscList.add(rp);
}
return rscList;
}
public void setDisplay(AbstractRenderableDisplay display) {
this.display = display;
}
public void setTarget(KmlGraphicsTarget target) {
this.target = target;
}
public List<ResourcePair> getResourcesToExport() {
return resourcesToExport;
}
public void setResourcesToExport(List<ResourcePair> resourcesToExport) {
this.resourcesToExport = resourcesToExport;
}
public AbstractRenderableDisplay getDisplay() {
return display;
}
public Rectangle getBounds() {
return bounds;
}
public KmlGraphicsTarget getTarget() {
return target;
}
public DataTime getDisplayedTime() {
return displayedTime;
}
public void setDisplayedTime(DataTime displayedTime) {
this.displayedTime = displayedTime;
}
}

View file

@ -0,0 +1,185 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics;
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.raytheon.uf.viz.core.drawables.IFont;
/**
*
* KML has really bad font support so only support the minimum operations
* required to avoid errors.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlFont implements IFont {
private Font font;
private float magnification;
private boolean scaleFont;
private boolean smoothing;
public KmlFont(Font font) {
this.font = font;
this.magnification = 1.0f;
}
public KmlFont() {
this(new Font(java.awt.Font.MONOSPACED, Font.BOLD, 14));
}
public KmlFont(String fontName) {
this(new Font(fontName, Font.PLAIN, 10));
}
public KmlFont(String fontName, float fontSize) {
this(new Font(fontName, Font.PLAIN, (int) fontSize));
}
public KmlFont(String fontName, float fontSize, Style[] styles) {
this(new Font(fontName, toAwtStyle(styles), (int) fontSize));
}
public KmlFont(File fontFile, float fontSize, Style[] styles)
throws FontFormatException, IOException {
this(Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(fontSize)
.deriveFont(toAwtStyle(styles)));
}
@Override
public String getFontName() {
return this.font.getFontName();
}
@Override
public float getFontSize() {
return this.font.getSize2D();
}
@Override
public Style[] getStyle() {
return toVizStyles(font.getStyle());
}
@Override
public void dispose() {
}
@Override
public IFont deriveWithSize(float size) {
return new KmlFont(font.deriveFont(size));
}
@Override
public void setMagnification(float magnification) {
setMagnification(magnification, true);
}
@Override
public void setMagnification(float magnification, boolean scaleFont) {
if (scaleFont) {
this.font = font.deriveFont(font.getSize2D() * magnification);
} else {
this.magnification = magnification;
}
}
@Override
public float getMagnification() {
return magnification;
}
@Override
public void setSmoothing(boolean smooth) {
this.smoothing = smooth;
}
@Override
public boolean getSmoothing() {
return smoothing;
}
@Override
public boolean isScaleFont() {
return scaleFont;
}
@Override
public void setScaleFont(boolean scaleFont) {
this.scaleFont = scaleFont;
}
public Font getFont() {
return font;
}
public void setFont(Font font) {
this.font = font;
}
private static int toAwtStyle(Style[] styles) {
int styleInt = Font.PLAIN;
if (styles == null || styles.length == 0) {
return styleInt;
}
for (Style style : styles) {
if (style == Style.BOLD) {
styleInt |= Font.BOLD;
} else if (style == Style.ITALIC) {
styleInt |= Font.ITALIC;
}
}
return styleInt;
}
private static Style[] toVizStyles(int style) {
List<Style> styles = new ArrayList<Style>();
if ((style & Font.BOLD) != 0) {
styles.add(Style.BOLD);
}
if ((style & Font.ITALIC) != 0) {
styles.add(Style.ITALIC);
}
return styles.toArray(new Style[0]);
}
}

View file

@ -0,0 +1,101 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.opengis.coverage.grid.GridEnvelope;
import com.raytheon.uf.viz.core.AbstractGraphicsFactoryAdapter;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.PixelExtent;
import com.raytheon.uf.viz.core.exception.VizException;
import com.vividsolutions.jts.geom.Coordinate;
/**
*
* Not very interesting, just constructs KML things
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlGraphicsFactoryAdapter extends AbstractGraphicsFactoryAdapter {
// The view needs to know the extent and canvas bounds from the source pane.
private final IExtent extent;
private final Rectangle canvasBounds;
public KmlGraphicsFactoryAdapter(IExtent extent, Rectangle canvasBounds) {
this.extent = extent;
this.canvasBounds = canvasBounds;
}
@Override
public KmlView constructView() {
return new KmlView(extent, canvasBounds);
}
@Override
public KmlGraphicsTarget constructTarget(Canvas canvas, float width,
float height) throws VizException {
return new KmlGraphicsTarget();
}
@Override
public IExtent constructExtent(Coordinate[] coords) throws VizException {
return new PixelExtent(coords);
}
@Override
public IExtent constructExtent(double aMinX, double aMaxX, double aMinY,
double aMaxY) throws VizException {
return new PixelExtent(aMinX, aMaxX, aMinY, aMaxY);
}
@Override
public IExtent constructExtent(Rectangle rect) throws VizException {
return new PixelExtent(rect);
}
@Override
public IExtent constructExtent(GridEnvelope range) throws VizException {
return new PixelExtent(range);
}
@Override
public Canvas constrcutCanvas(Composite canvasComp) throws VizException {
// Its possible we should just return null and not worry so much
throw new UnsupportedOperationException(
"KmlGraphicsFactoryAdapter does not support creating a canvas");
}
}

View file

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

View file

@ -0,0 +1,208 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.TransformFactory;
import com.raytheon.uf.viz.core.drawables.IShadedShape;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Geometry;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Polygon;
/**
* Implementation of shaded shape that can create a generator for making KML
* filled polygons. KML has no concept of a fill pattern so it is completly
* ignored and all polygons are filled with color.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlShadedShape implements IShadedShape {
private Map<RGB, List<Polygon>> polygons = new HashMap<RGB, List<Polygon>>();
private final GeneralGridGeometry gridGeometry;
public KmlShadedShape(GeneralGridGeometry gridGeometry) {
this.gridGeometry = gridGeometry;
}
@Override
public void compile() {
}
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean isDrawable() {
return true;
}
@Override
public void dispose() {
polygons.clear();
}
@Override
public void reset() {
polygons.clear();
}
@Override
public void addPolygon(LineString[] lineString, RGB color) {
Polygon p = new Polygon();
LinearRing outer = p.createAndSetOuterBoundaryIs()
.createAndSetLinearRing();
for (Coordinate c : lineString[0].getCoordinates()) {
outer.addToCoordinates(c.x, c.y);
}
for (int i = 1; i < lineString.length; i += 1) {
LinearRing inner = p.createAndAddInnerBoundaryIs()
.createAndSetLinearRing();
for (Coordinate c : lineString[i].getCoordinates()) {
inner.addToCoordinates(c.x, c.y);
}
}
List<Polygon> polygons = this.polygons.get(color);
if (polygons == null) {
polygons = new ArrayList<Polygon>();
this.polygons.put(color, polygons);
}
polygons.add(p);
}
@Override
public void addPolygonPixelSpace(LineString[] contours, RGB color) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
double[] loc = new double[2];
LineString[] newContours = new LineString[contours.length];
for (int i = 0; i < contours.length; i += 1) {
List<Coordinate> newCoordinates = new ArrayList<Coordinate>();
for (Coordinate c : contours[i].getCoordinates()) {
loc = new double[] { c.x, c.y };
transform.transform(loc, 0, loc, 0, 1);
newCoordinates.add(new Coordinate(loc[0], loc[1]));
}
newContours[i] = contours[i].getFactory().createLineString(
newCoordinates.toArray(new Coordinate[0]));
}
addPolygon(newContours, color);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
@Override
public void setFillPattern(byte[] pattern) {
}
public static class Generator extends KmlFeatureGenerator {
private final double alpha;
private final Map<RGB, List<Polygon>> polygons;
public Generator(double alpha, KmlShadedShape shape) {
this.alpha = alpha;
this.polygons = new HashMap<RGB, List<Polygon>>(shape.polygons);
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (polygons.size() == 1) {
Entry<RGB, List<Polygon>> entry = polygons.entrySet()
.iterator().next();
outputManager.addFeature(getPlacemark(outputManager,
entry.getKey(), entry.getValue()));
} else if (!polygons.isEmpty()) {
Folder folder = new Folder();
folder.setName("Shaded Shapes");
for (Entry<RGB, List<Polygon>> entry : polygons.entrySet()) {
folder.addToFeature(getPlacemark(outputManager,
entry.getKey(), entry.getValue()));
}
outputManager.addFeature(folder);
}
}
private Placemark getPlacemark(KmlOutputManager out, RGB color,
List<Polygon> polygons) {
Placemark placemark = new Placemark();
placemark.setName("Shaded Shape");
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetPolyStyle().withFill(true)
.withColor(toColorStr(alpha, color));
kmlStyle.createAndSetLineStyle()
.withColor(toColorStr(alpha, color));
placemark.setStyleUrl(out.getStyleUrl(kmlStyle));
if (polygons.size() == 1) {
placemark.setGeometry(polygons.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(
new ArrayList<Geometry>(polygons));
}
return placemark;
}
}
}

View file

@ -0,0 +1,108 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics;
import org.eclipse.swt.graphics.Rectangle;
import com.raytheon.uf.viz.core.AbstractView;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget;
/**
*
* Minimalistic implementation of a view for KML. Can not be shifted or
* modified, so KML does not supprt Pan/Zoom.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlView extends AbstractView {
private final Rectangle canvasBounds;
public KmlView(IExtent extent, Rectangle canvasBounds) {
super(extent);
this.canvasBounds = canvasBounds;
}
@Override
public void setupView(IGraphicsTarget target) {
if (target instanceof KmlGraphicsTarget) {
((KmlGraphicsTarget) target).setView(this);
return;
}
throw new IllegalArgumentException(
"KmlView was expecting a KmlGraphicsTarget but recieved "
+ target.getClass().getSimpleName());
}
@Override
public double recalcZoomLevel(int[] dimensions) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void zoom(double zoomLevel) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void scaleAndBias(double factor, double screenX, double screenY,
IGraphicsTarget target) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void setExtent(IExtent pe) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void shiftExtent(double[] startScreen, double[] endScreen,
IGraphicsTarget target) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public void scaleToClientArea(Rectangle clientArea, int[] dimensions) {
throw new UnsupportedOperationException("KmlView is read only!");
}
@Override
public KmlView clone() {
return new KmlView(extent.clone(), canvasBounds);
}
@Override
public Rectangle getCanvasBounds(IGraphicsTarget target) {
return canvasBounds;
}
}

View file

@ -0,0 +1,284 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.TransformFactory;
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.vividsolutions.jts.geom.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Geometry;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
import de.micromata.opengis.kml.v_2_2_0.LineString;
import de.micromata.opengis.kml.v_2_2_0.LineStyle;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
*
* Converts a wireframe shape into KML LineStrings and Labels.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlWireframeShape implements IWireframeShape {
private List<Geometry> segments = new ArrayList<Geometry>();
private Map<String, List<Geometry>> labels = new HashMap<String, List<Geometry>>();
private final GeneralGridGeometry gridGeometry;
public KmlWireframeShape(GeneralGridGeometry gridGeometry) {
this.gridGeometry = gridGeometry;
}
@Override
public void compile() {
}
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean isDrawable() {
return true;
}
@Override
public void dispose() {
segments.clear();
labels.clear();
}
@Override
public void reset() {
segments.clear();
labels.clear();
}
@Override
public void addLineSegment(Coordinate[] latLong) {
LineString line = new LineString();
for (Coordinate c : latLong) {
line.addToCoordinates(round(c.x), round(c.y));
}
segments.add(line);
}
@Override
public void addLineSegment(double[][] screenCoordinates) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
LineString line = new LineString();
double[] out = new double[2];
for (int i = 0; i < screenCoordinates.length; i += 1) {
transform.transform(screenCoordinates[i], 0, out, 0, 1);
line.addToCoordinates(round(out[0]), round(out[1]));
}
segments.add(line);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
/**
* round a latitude or longitude, rounding can cut the size of the generated
* kml and only moves the actual line by less than a meter.
*
* @param value
* @return
*/
private double round(double value) {
return ((long) (value * 100000)) / 100000.0;
}
@Override
public void addLabel(String label, double[] screenCoordinate) {
try {
MathTransform transform = TransformFactory.gridToLatLon(
gridGeometry, PixelInCell.CELL_CENTER);
double[] out = new double[2];
transform.transform(screenCoordinate, 0, out, 0, 1);
Point point = new Point();
point.addToCoordinates(round(out[0]), round(out[1]));
List<Geometry> points = labels.get(label);
if (points == null) {
points = new ArrayList<Geometry>();
labels.put(label, points);
}
points.add(point);
} catch (TransformException e) {
throw new IllegalStateException(e);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
}
@Override
public void clearLabels() {
labels.clear();
}
@Override
public void allocate(int points) {
}
public static class Generator extends KmlFeatureGenerator {
private final List<Geometry> segments;
private final Map<String, List<Geometry>> labels;
private final float alpha;
private final RGB color;
private final float lineWidth;
public Generator(KmlWireframeShape shape, float alpha, RGB color,
float lineWidth) {
this.segments = new ArrayList<Geometry>(shape.segments);
this.labels = new HashMap<String, List<Geometry>>(shape.labels);
this.alpha = alpha;
this.color = color;
this.lineWidth = lineWidth;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (segments.isEmpty() && labels.isEmpty()) {
return;
}
String styleUrl = outputManager.getStyleUrl(getStyle());
Feature lineFeature = getLineFeature(styleUrl);
Feature labelFeature = getLabelFeature(styleUrl);
if (lineFeature == null) {
outputManager.addFeature(labelFeature);
} else if (labelFeature == null) {
outputManager.addFeature(lineFeature);
} else {
Folder folder = new Folder();
folder.setName("LinesAndLabels");
folder.addToFeature(lineFeature);
folder.addToFeature(labelFeature);
outputManager.addFeature(folder);
}
}
private Style getStyle() {
Style style = new de.micromata.opengis.kml.v_2_2_0.Style();
LineStyle lineStyle = style.createAndSetLineStyle();
LabelStyle labelStyle = style.createAndSetLabelStyle();
style.createAndSetIconStyle().setScale(0);
String colorStr = toColorStr(alpha, color);
lineStyle.setColor(colorStr);
lineStyle.setWidth(lineWidth);
labelStyle.setColor(colorStr);
labelStyle.setScale(1.0);
return style;
}
private Feature getLineFeature(String styleUrl) {
if (segments.isEmpty()) {
return null;
}
Placemark placemark = new Placemark();
placemark.setName("Lines");
placemark.setStyleUrl(styleUrl);
if (segments.size() == 1) {
placemark.setGeometry(segments.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(
new ArrayList<Geometry>(segments));
}
return placemark;
}
private Feature getLabelFeature(String styleUrl) {
if (labels.size() == 1) {
for (Entry<String, List<Geometry>> entry : labels.entrySet()) {
return createLabelPlacemark(entry.getKey(),
entry.getValue(), styleUrl);
}
} else if (!labels.isEmpty()) {
Folder folder = new Folder();
folder.setName("Labels");
for (Entry<String, List<Geometry>> entry : labels.entrySet()) {
Placemark placemark = createLabelPlacemark(entry.getKey(),
entry.getValue(), styleUrl);
folder.addToFeature(placemark);
}
return folder;
}
return null;
}
private Placemark createLabelPlacemark(String label,
List<Geometry> points, String styleUrl) {
Placemark placemark = new Placemark();
placemark.setName(label);
placemark.setStyleUrl(styleUrl);
if (points.size() == 1) {
placemark.setGeometry(points.get(0));
} else {
placemark.createAndSetMultiGeometry().setGeometry(points);
}
return placemark;
}
}
}

View file

@ -0,0 +1,119 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.basicgen;
import java.util.ArrayList;
import java.util.List;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.DrawableCircle;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
/**
* Generates KML polygons for DrawableCircles.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlCirclesGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlLinesGenerator.class);
private final DrawableCircle[] circles;
public KmlCirclesGenerator(DrawableCircle[] circles) {
this.circles = circles;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (circles.length > 1) {
outputManager = outputManager.createFolder("Circles");
}
for (DrawableCircle circle : circles) {
String colorStr = toColorStr(circle.basics.alpha,
circle.basics.color);
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetLabelStyle().setScale(0);
kmlStyle.createAndSetIconStyle().setScale(0);
if (circle.filled) {
kmlStyle.createAndSetPolyStyle().withFill(true)
.withColor(colorStr);
} else {
kmlStyle.createAndSetLineStyle().withWidth(circle.lineWidth)
.withColor(colorStr);
}
Placemark placemark = new Placemark();
placemark.setName("Circle");
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
List<double[]> pts = new ArrayList<double[]>();
double step = 360.0 / (circle.numberOfPoints);
double radius = circle.radius == null ? circle.screenRadius
: circle.radius;
try {
for (double i = 0; i <= circle.numberOfPoints; i++) {
double[] pt = new double[2];
pt[0] = circle.basics.x + radius
* Math.cos(Math.toRadians(i * step));
pt[1] = circle.basics.y + radius
* Math.sin(Math.toRadians(i * step));
pts.add(pt);
}
if (circle.filled) {
placemark.createAndSetPolygon()
.createAndSetOuterBoundaryIs()
.createAndSetLinearRing()
.withCoordinates(transformToLatLon(pts));
} else {
placemark.createAndSetLineString().withCoordinates(
transformToLatLon(pts));
}
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
outputManager.addFeature(placemark);
}
}
}

View file

@ -0,0 +1,92 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.basicgen;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.DrawableLine;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
/**
* Generates KML line strings for DrawableLine.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlLinesGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlLinesGenerator.class);
private final DrawableLine[] lines;
public KmlLinesGenerator(DrawableLine[] lines) {
super();
this.lines = lines;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (lines.length > 1) {
outputManager = outputManager.createFolder("Lines");
}
for (DrawableLine line : lines) {
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
kmlStyle.createAndSetLabelStyle().setScale(0);
kmlStyle.createAndSetIconStyle().setScale(0);
kmlStyle.createAndSetLineStyle()
.withWidth(line.width)
.withColor(toColorStr(line.basics.alpha, line.basics.color));
Placemark placemark = new Placemark();
placemark.setName("Line");
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
try {
placemark.createAndSetLineString().withCoordinates(
transformToLatLon(line.points));
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
}

View file

@ -0,0 +1,162 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.basicgen;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Collection;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.IGraphicsTarget.PointStyle;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
import de.micromata.opengis.kml.v_2_2_0.MultiGeometry;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
/**
* Generates KML point icons.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPointsGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlStringsGenerator.class);
private final Collection<double[]> locations;
private final RGB color;
private final PointStyle pointStyle;
private final float magnification;
public KmlPointsGenerator(Collection<double[]> locations, RGB color,
PointStyle pointStyle, float magnification) {
super();
this.locations = locations;
this.color = color;
this.pointStyle = pointStyle;
this.magnification = magnification;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
BufferedImage image = new BufferedImage(15, 15,
BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.getGraphics();
if (graphics instanceof Graphics2D) {
((Graphics2D) graphics).setStroke(new BasicStroke(3.0f));
}
graphics.setColor(new java.awt.Color(0, 0, 0, 0));
graphics.fillRect(0, 0, 24, 24);
graphics.setColor(new java.awt.Color(color.red, color.green, color.blue));
switch (pointStyle) {
case NONE:
graphics.dispose();
return;
case SQUARE:
graphics.fillRect(1, 1, 13, 13);
break;
case CIRCLE:
graphics.drawOval(1, 1, 13, 13);
break;
case CROSS:
graphics.drawLine(7, 0, 7, 14);
graphics.drawLine(0, 7, 14, 7);
break;
case DASH:
graphics.drawLine(0, 7, 14, 7);
break;
case POINT:
graphics.fillOval(5, 5, 5, 5);
break;
case BOX:
graphics.drawRect(1, 1, 13, 13);
break;
case STAR:
graphics.drawLine(7, 0, 7, 14);
case X:
graphics.drawLine(0, 0, 14, 14);
graphics.drawLine(0, 14, 14, 0);
break;
case DISC:
default:
graphics.fillOval(1, 1, 13, 13);
break;
}
graphics.dispose();
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
LabelStyle kmlLabelStyle = kmlStyle.createAndSetLabelStyle();
IconStyle kmlIconStyle = kmlStyle.createAndSetIconStyle();
kmlIconStyle.createAndSetIcon().setHref(outputManager.addImage(image));
kmlLabelStyle.setScale(0);
kmlIconStyle.setScale(magnification * 0.5);
Placemark placemark = new Placemark();
placemark.setName(pointStyle.toString());
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
try {
if (locations.size() == 1) {
Point p = placemark.createAndSetPoint();
Coordinate loc = transformToLatLon(locations.iterator().next());
p.addToCoordinates(loc.getLongitude(), loc.getLatitude());
} else {
MultiGeometry multi = placemark.createAndSetMultiGeometry();
for (double[] location : locations) {
Point p = multi.createAndAddPoint();
Coordinate loc = transformToLatLon(location);
p.addToCoordinates(loc.getLongitude(), loc.getLatitude());
}
}
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
}

View file

@ -0,0 +1,113 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.basicgen;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* Generates kml Polygon for both filled and not filled rectangles.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRectGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRectGenerator.class);
private final IExtent pe;
private final RGB color;
private final double alpha;
private final float lineWidth;
private final boolean filled;
public KmlRectGenerator(IExtent pe, RGB color, double alpha,
float lineWidth, boolean filled) {
this.pe = pe;
this.color = color;
this.alpha = alpha;
this.lineWidth = lineWidth;
this.filled = filled;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
Placemark placemark = new Placemark();
placemark.setName("Rectangle");
Style style = new de.micromata.opengis.kml.v_2_2_0.Style();
style.createAndSetLabelStyle().setScale(0);
style.createAndSetIconStyle().setScale(0);
style.createAndSetLineStyle().withWidth(lineWidth)
.withColor(toColorStr(alpha, color));
style.createAndSetPolyStyle().withFill(filled)
.withColor(toColorStr(alpha, color));
try {
LinearRing ring = placemark.createAndSetPolygon()
.createAndSetOuterBoundaryIs().createAndSetLinearRing();
Coordinate corner = transformToLatLon(pe.getMinX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMaxX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMaxX(), pe.getMaxY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMinX(), pe.getMaxY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
corner = transformToLatLon(pe.getMinX(), pe.getMinY());
ring.addToCoordinates(corner.getLongitude(), corner.getLatitude());
placemark.setStyleUrl(outputManager.getStyleUrl(style));
outputManager.addFeature(placemark);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
}
}
}

View file

@ -0,0 +1,189 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.basicgen;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.LabelStyle;
import de.micromata.opengis.kml.v_2_2_0.MultiGeometry;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
/**
* Generates KML Placemark Labels for DrawableStrings.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlStringsGenerator extends KmlFeatureGenerator {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlStringsGenerator.class);
private final Collection<DrawableString> parameters;
public KmlStringsGenerator(Collection<DrawableString> parameters) {
this.parameters = parameters;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
Collection<DrawableString> parameters = mergeDuplicatePoints();
if (parameters.size() > 1) {
outputManager = outputManager.createFolder("Labels");
}
Map<String, Placemark> redundantPlacemarks = new HashMap<String, Placemark>();
for (DrawableString dstring : parameters) {
RGB color = dstring.getColors()[0];
for (RGB dcolor : dstring.getColors()) {
if (!dcolor.equals(color)) {
statusHandler.handle(Priority.INFO,
"Multicolor labels will be one color in kml");
}
break;
}
String colorStr = toColorStr(dstring.basics.alpha, color);
StringBuilder text = new StringBuilder(dstring.getText()[0]);
for (int i = 1; i < dstring.getText().length; i++) {
text.append(" ");
text.append(dstring.getText()[i]);
}
Placemark placemark = redundantPlacemarks.get(text.toString()
+ colorStr + dstring.magnification);
if (placemark == null) {
// google earth handles multiple points in a single placemark
// faster than multiple placemarks with a single point, so
// combine wherever possible
de.micromata.opengis.kml.v_2_2_0.Style kmlStyle = new de.micromata.opengis.kml.v_2_2_0.Style();
LabelStyle kmlLabelStyle = kmlStyle.createAndSetLabelStyle();
IconStyle kmlIconStyle = kmlStyle.createAndSetIconStyle();
kmlLabelStyle.setColor(colorStr);
double magnifiaction = dstring.magnification;
if (dstring.font != null) {
magnifiaction *= dstring.font.getMagnification();
}
kmlLabelStyle.setScale(magnifiaction);
kmlIconStyle.setScale(0);
placemark = new Placemark();
placemark.setName(text.toString());
placemark.setStyleUrl(outputManager.getStyleUrl(kmlStyle));
outputManager.addFeature(placemark);
redundantPlacemarks.put(text.toString() + colorStr
+ dstring.magnification, placemark);
}
Point point = null;
if (placemark.getGeometry() == null) {
point = placemark.createAndSetPoint();
} else if (placemark.getGeometry() instanceof Point) {
point = (Point) placemark.getGeometry();
MultiGeometry multi = placemark.createAndSetMultiGeometry();
multi.addToGeometry(point);
point = multi.createAndAddPoint();
} else {
MultiGeometry multi = (MultiGeometry) placemark.getGeometry();
point = multi.createAndAddPoint();
}
try {
Coordinate loc = transformToLatLon(dstring.basics.x,
dstring.basics.y);
point.addToCoordinates(loc.getLongitude(), loc.getLatitude());
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
private Collection<DrawableString> mergeDuplicatePoints() {
Map<Coordinate, DrawableString> pointMap = new HashMap<Coordinate, DrawableString>();
for (DrawableString dstring : parameters) {
Coordinate c = new Coordinate(dstring.basics.x, dstring.basics.y);
if (pointMap.containsKey(c)) {
DrawableString inMap = pointMap.get(c);
DrawableString dstring2 = inMap;
// try determine which of the two dtrings would be considered
// "first"
if (dstring2.verticallAlignment != dstring.verticallAlignment) {
if (dstring2.verticallAlignment == VerticalAlignment.BOTTOM
|| dstring.verticallAlignment == VerticalAlignment.TOP) {
DrawableString tmp = dstring2;
dstring2 = dstring;
dstring = tmp;
}
} else if (dstring2.horizontalAlignment != dstring.horizontalAlignment) {
if (dstring2.horizontalAlignment == HorizontalAlignment.RIGHT
|| dstring.horizontalAlignment == HorizontalAlignment.LEFT) {
DrawableString tmp = dstring2;
dstring2 = dstring;
dstring = tmp;
}
}
String[] text1 = dstring.getText();
String[] text2 = dstring2.getText();
RGB[] colors1 = dstring.getColors();
RGB[] colors2 = dstring2.getColors();
String[] text = Arrays.copyOf(text1, text1.length
+ text2.length);
System.arraycopy(text2, 0, text, text1.length, text2.length);
RGB[] colors = Arrays.copyOf(colors1, colors1.length
+ colors2.length);
System.arraycopy(colors2, 0, colors, colors1.length,
colors2.length);
inMap.setText(text, colors);
} else {
pointMap.put(c, dstring);
}
}
return pointMap.values();
}
}

View file

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

View file

@ -0,0 +1,125 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.IntBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.ShortBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.UnsignedByteBufferWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.UnsignedShortBufferWrapper;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback.ColorMapData;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Implements the interface and converts all data callbacks into raw float
* arrays.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlColormappedImage extends KmlImage implements IColormappedImage {
private final IColorMapDataRetrievalCallback dataCallback;
private ColorMapParameters colorMapParameters;
public KmlColormappedImage(IColorMapDataRetrievalCallback dataCallback,
ColorMapParameters colorMapParameters) {
this.dataCallback = dataCallback;
this.colorMapParameters = colorMapParameters;
}
public DataSource getData(GridGeometry2D geometry) throws VizException {
ColorMapData data = dataCallback.getColorMapData();
switch (data.getDataType()) {
case FLOAT:
return new FloatBufferWrapper(((FloatBuffer) data.getBuffer()),
geometry);
case BYTE: {
return new UnsignedByteBufferWrapper(
((ByteBuffer) data.getBuffer()), geometry);
}
case SIGNED_BYTE: {
return new ByteBufferWrapper(((ByteBuffer) data.getBuffer()),
geometry);
}
case INT: {
return new IntBufferWrapper(((IntBuffer) data.getBuffer()),
geometry);
}
case SHORT: {
return new ShortBufferWrapper(((ShortBuffer) data.getBuffer()),
geometry);
}
case UNSIGNED_SHORT: {
return new UnsignedShortBufferWrapper(
((ShortBuffer) data.getBuffer()), geometry);
}
}
throw new UnsupportedOperationException(
"Kml Export does not supprt image type: " + data.getDataType());
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlColormappedImageExtension.class;
}
@Override
public ColorMapParameters getColorMapParameters() {
return colorMapParameters;
}
@Override
public void setColorMapParameters(ColorMapParameters params) {
this.colorMapParameters = params;
}
@Override
public double getValue(int x, int y) {
return 0;
}
}

View file

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

View file

@ -0,0 +1,143 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.awt.image.RenderedImage;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.keyvalue.MultiKey;
import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
import com.raytheon.uf.common.geospatial.interpolation.GridReprojection;
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback.ColorMapData;
import com.raytheon.uf.viz.core.data.prep.Colormapper;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import de.micromata.opengis.kml.v_2_2_0.GroundOverlay;
import de.micromata.opengis.kml.v_2_2_0.LatLonBox;
/**
* Base class for any feature generator that is creating a ground overlay,
* provides the reproject logic as well as logic for actually making the
* overlay.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class KmlGroundOverlayGenerator extends KmlFeatureGenerator {
private static Map<MultiKey, Reference<GridReprojection>> reprojCache = new HashMap<MultiKey, Reference<GridReprojection>>();
protected final double alpha;
public KmlGroundOverlayGenerator(double alpha) {
this.alpha = alpha;
}
protected void makeOverlay(KmlOutputManager out, GridGeometry2D geometry,
float[] fdata, ColorMapParameters parameters) {
GridEnvelope2D range = geometry.getGridRange2D();
int[] dimensions = { range.width, range.height };
ColorMapData data = new ColorMapData(FloatBuffer.wrap(fdata),
dimensions);
RenderedImage image = Colormapper.colorMap(data, parameters);
makeOverlay(out, image, geometry.getEnvelope2D());
}
protected void makeOverlay(KmlOutputManager out, RenderedImage image,
Envelope2D envelope) {
GroundOverlay overlay = new GroundOverlay();
overlay.setColor(toColorStr(alpha, new RGB(255, 255, 255)));
overlay.setName("Image");
overlay.createAndSetIcon().setHref(out.addImage(image));
LatLonBox box = overlay.createAndSetLatLonBox();
box.setNorth(envelope.getMaxY());
box.setEast(envelope.getMaxX());
box.setSouth(envelope.getMinY());
box.setWest(envelope.getMinX());
out.addFeature(overlay);
}
protected float[] reproject(GridGeometry2D src, GridGeometry2D dest,
DataSource data, Boolean interpolated) throws FactoryException,
TransformException {
GridReprojection reproj = getReprojection(src, dest);
Interpolation interp = null;
if (interpolated) {
interp = new BilinearInterpolation();
} else {
interp = new NearestNeighborInterpolation();
}
FloatArrayWrapper dst = new FloatArrayWrapper(dest);
return reproj.reprojectedGrid(interp, data, dst).getArray();
}
protected GridReprojection getReprojection(GridGeometry2D src,
GridGeometry2D dest) throws FactoryException, TransformException {
MultiKey key = new MultiKey(src, dest);
GridReprojection reproj = null;
boolean needsCompute = false;
synchronized (reprojCache) {
Reference<GridReprojection> reprojRef = reprojCache.get(key);
if (reprojRef != null) {
reproj = reprojRef.get();
}
if (reproj == null) {
reproj = new GridReprojection(src, dest);
needsCompute = true;
reprojCache.put(key,
new SoftReference<GridReprojection>(reproj));
}
}
synchronized (reproj) {
if (needsCompute) {
reproj.computeTransformTable();
}
}
return reproj;
}
}

View file

@ -0,0 +1,96 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* Base image class for KML that does almost nothing and ignores any of the
* methods that aren't important to KML.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class KmlImage implements IImage {
private boolean interpolated;
@Override
public void stage() throws VizException {
}
@Override
public Status getStatus() {
return Status.LOADED;
}
@Override
public void setInterpolated(boolean isInterpolated) {
this.interpolated = isInterpolated;
}
public boolean isInterpolated() {
return interpolated;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IImage#dispose()
*/
@Override
public void dispose() {
}
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
@Override
public void setBrightness(float brightness) {
}
@Override
public void setContrast(float contrast) {
}
}

View file

@ -0,0 +1,77 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D;
import org.opengis.coverage.grid.GridEnvelope;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.drawables.IDescriptor;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.map.IMapMeshExtension;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
/**
*
* Creates meshes.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMapMeshExtension extends GraphicsExtension<KmlGraphicsTarget>
implements IMapMeshExtension {
@Override
public IMesh constructMesh(GridGeometry2D imageGeometry,
GeneralGridGeometry targetGeometry) throws VizException {
GridEnvelope2D range = imageGeometry.getGridRange2D();
Envelope2D envelope = imageGeometry.getEnvelope2D();
range.x = 0;
range.y = 0;
imageGeometry = new GridGeometry2D((GridEnvelope) range, envelope);
return new KmlMesh(imageGeometry);
}
@Override
public IMesh constructMesh(GridGeometry2D imageGeometry,
IDescriptor targetDescriptor) throws VizException {
return constructMesh(imageGeometry, targetDescriptor.getGridGeometry());
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
}

View file

@ -0,0 +1,101 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Basically just a container for a grid geometry.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMesh implements IMesh {
private final GridGeometry2D imageGeometry;
private Envelope latLonEnvelope;
public KmlMesh(GridGeometry2D imageGeometry) {
this.imageGeometry = imageGeometry;
}
public GridGeometry2D getImageGeometry() {
return imageGeometry;
}
@Override
public void dispose() {
}
@Override
public boolean intersects(IExtent extent) {
return false;
}
@Override
public KmlMesh reproject(GeneralGridGeometry targetGeometry)
throws VizException {
return clone(targetGeometry);
}
@Override
public KmlMesh clone(GeneralGridGeometry targetGeometry)
throws VizException {
return this;
}
public Envelope getLatLonEnvelope() throws TransformException {
if (latLonEnvelope == null) {
ReferencedEnvelope env = new ReferencedEnvelope(
imageGeometry.getEnvelope());
try {
latLonEnvelope = env.transform(MapUtil.LATLON_PROJECTION, true,
500);
} catch (FactoryException e) {
throw new TransformException(e.getLocalizedMessage(), e);
}
}
return latLonEnvelope;
}
}

View file

@ -0,0 +1,149 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.util.Comparator;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicImageExtension.IMosaicImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Keeps track of the images that are to be mosaiced so that the extension can
* handle rendering them.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 20, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
class KmlMosaicImage implements IMosaicImage {
private ColorMapParameters colorMapParameters;
private int[] bounds;
private IExtent imageExtent;
private DrawableImage[] imagesToMosaic;
private Comparator<Double> mosaicComparator;
public KmlMosaicImage(int[] imageBounds, IExtent imageExtent,
ColorMapParameters params, Comparator<Double> mosaicComparator) {
this.colorMapParameters = params;
this.bounds = imageBounds;
this.imageExtent = imageExtent;
this.mosaicComparator = mosaicComparator;
}
@Override
public ColorMapParameters getColorMapParameters() {
return colorMapParameters;
}
@Override
public void setColorMapParameters(ColorMapParameters params) {
this.colorMapParameters = params;
}
@Override
public double getValue(int x, int y) {
// TODO do I need this?
return 0;
}
@Override
public void stage() throws VizException {
// TODO do I need this?
}
@Override
public Status getStatus() {
// TODO do I need this?
return Status.LOADED;
}
@Override
public void setInterpolated(boolean isInterpolated) {
// TODO do I need this?
}
@Override
public void dispose() {
// TODO do I need this?
}
@Override
public int getWidth() {
return bounds[0];
}
@Override
public int getHeight() {
return bounds[1];
}
@Override
public void setBrightness(float brightness) {
// TODO do I need this?
}
@Override
public void setContrast(float contrast) {
// TODO do I need this?
}
@Override
public Class<? extends IMosaicImageExtension> getExtensionClass() {
return IMosaicImageExtension.class;
}
public Comparator<Double> getMosaicComparator() {
return mosaicComparator;
}
@Override
public void setImagesToMosaic(DrawableImage... images) {
this.imagesToMosaic = images;
}
public DrawableImage[] getImagesToMosaic() {
return this.imagesToMosaic;
}
@Override
public void setImageExtent(IExtent imageExtent) {
this.imageExtent = imageExtent;
}
}

View file

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

View file

@ -17,46 +17,46 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.ghg;
package com.raytheon.uf.viz.kml.export.graphics.ext;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import java.util.Comparator;
import com.raytheon.viz.gfe.core.DataManager;
import com.raytheon.viz.ghg.makehazard.MakeHazardDialog;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicMaxValImageExtension;
/**
* TODO Add Description MakeHazardsAction.java Jun 5, 2008
* Extends mosaic extesnion to perform maxVal mosaicing.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 5, 2008 Eric Babin Initial Creation
* Jul 10, 2012 bsteffen Initial creation
*
* </pre>
*
* @author ebabin
* @author bsteffen
* @version 1.0
*/
public class MakeHazardsAction extends AbstractHandler {
public class KmlMosaicMaxValImageExtension extends KmlMosaicImageExtension
implements IMosaicMaxValImageExtension {
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
DataManager dm = DataManager.getCurrentInstance();
if (dm == null) {
return null;
}
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell();
MakeHazardDialog monitorDlg = new MakeHazardDialog(shell, dm);
monitorDlg.open();
protected Comparator<Double> getMosaicComparator() {
return new Comparator<Double>() {
@Override
public int compare(Double o1, Double o2) {
if (Double.isNaN(o2)) {
return 1;
} else if (Double.isNaN(o1)) {
return -1;
} else {
return Double.compare(o1, o2);
}
}
return null;
};
}
}

View file

@ -0,0 +1,59 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.util.Comparator;
import com.raytheon.uf.viz.core.drawables.ext.IMosaicOrderedImageExtension;
/**
* Extends mosaic extesnion to perform ordered mosaicing.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 10, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlMosaicOrderedImageExtension extends KmlMosaicImageExtension
implements IMosaicOrderedImageExtension {
@Override
protected Comparator<Double> getMosaicComparator() {
return new Comparator<Double>() {
@Override
public int compare(Double o1, Double o2) {
if (o2 != 0 && !Double.isNaN(o2)) {
return -1;
}
return 1;
}
};
}
}

View file

@ -0,0 +1,130 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* Basically a wrapper around a RenderedImageCallback but also has logic for
* filling in transparent parts of plots.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRasterImage extends KmlImage {
protected final IRenderedImageCallback callback;
/**
* @param imageCallback
*/
public KmlRasterImage(IRenderedImageCallback imageCallback) {
this.callback = imageCallback;
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlRasterImageExtension.class;
}
/**
* get the image for a ground overlay
*
* @return
* @throws VizException
*/
public RenderedImage getImage() throws VizException {
return callback.getImage();
}
/**
* get the image for a plot
*
* @param target
* @return
* @throws VizException
*/
public RenderedImage getImage(RGB backcolor) throws VizException {
RenderedImage ri = getImage();
BufferedImage bi = cloneRenderedImage(ri);
applyFill(bi, backcolor);
return bi;
}
protected BufferedImage cloneRenderedImage(RenderedImage ri)
throws VizException {
BufferedImage bi = new BufferedImage(ri.getWidth(), ri.getHeight(),
BufferedImage.TYPE_INT_ARGB);
if (ri instanceof Image) {
bi.getGraphics().drawImage((Image) ri, 0, 0, null);
} else {
throw new VizException("Cannot handle image of type "
+ ri.getClass().getSimpleName());
}
return bi;
}
protected void applyFill(BufferedImage bi, RGB backcolor) {
int backint = (0xFF << 24) | (backcolor.red << 16)
| (backcolor.green << 8) | backcolor.blue;
for (int i = 0; i < bi.getWidth(); i++) {
for (int j = 0; j < bi.getHeight(); j++) {
int argb = bi.getRGB(i, j);
int alphaint = ((argb >> 24) & 0xFF);
if (alphaint == 0) {
argb = backint;
} else if (alphaint != 255) {
// blend the colors.
double alpha = alphaint / 255.0;
int red = (argb >> 16) & 0xFF;
int green = (argb >> 8) & 0xFF;
int blue = (argb >> 0) & 0xFF;
red = (int) (red * alpha + backcolor.red * (1.0 - alpha));
green = (int) (green * alpha + backcolor.green
* (1.0 - alpha));
blue = (int) (blue * alpha + backcolor.blue * (1.0 - alpha));
argb = (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
bi.setRGB(i, j, argb);
}
}
}
}

View file

@ -0,0 +1,122 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.processing.Operations;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.PixelCoverage;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
/**
* Extension for creating KML Ground Overlay from raster images.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 11, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRasterImageExtension extends
GraphicsExtension<KmlGraphicsTarget> implements IImagingExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRasterImageExtension.class);
@Override
public boolean drawRasters(PaintProperties paintProps,
DrawableImage... images) throws VizException {
target.addGenerator(new Generator(paintProps.getAlpha(), images));
return true;
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlGroundOverlayGenerator {
private final DrawableImage[] images;
public Generator(float alpha, DrawableImage[] images) {
super(alpha);
this.images = images;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
GridCoverageFactory coverageFactory = new GridCoverageFactory();
for (DrawableImage image : images) {
KmlRasterImage kmlImage = (KmlRasterImage) image.getImage();
PixelCoverage coverage = image.getCoverage();
MathTransform transform = gridGeometry.getGridToCRS();
DirectPosition2D min = new DirectPosition2D(coverage.getMinX(),
coverage.getMinY());
DirectPosition2D max = new DirectPosition2D(coverage.getMaxX(),
coverage.getMaxY());
try {
transform.transform(min, min);
transform.transform(max, max);
ReferencedEnvelope env = new ReferencedEnvelope(
new Envelope2D(min, max),
gridGeometry.getCoordinateReferenceSystem());
GridCoverage2D source = coverageFactory.create("Test",
kmlImage.getImage(), env);
GridCoverage2D result = (GridCoverage2D) new Operations(
null).resample(source, MapUtil.LATLON_PROJECTION);
makeOverlay(outputManager, result.getRenderedImage(),
result.getEnvelope2D());
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
}
}
}

View file

@ -0,0 +1,90 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension.ISingleColorImage;
import com.raytheon.uf.viz.core.exception.VizException;
/**
*
* Adds logic to change colors to KmlRasterIamge.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlSingleColorImage extends KmlRasterImage implements
ISingleColorImage {
private RGB color;
public KmlSingleColorImage(IRenderedImageCallback callback, RGB color) {
super(callback);
this.color = color;
}
@Override
public Class<? extends IImagingExtension> getExtensionClass() {
return KmlSingleColorImageExtension.class;
}
@Override
public void setColor(RGB color) {
this.color = color;
}
@Override
public RenderedImage getImage() throws VizException {
RenderedImage ri = callback.getImage();
BufferedImage bi = cloneRenderedImage(ri);
makeSingleColor(bi);
return bi;
}
protected void makeSingleColor(BufferedImage bi) {
int colorint = (0xFF << 24) | (color.red << 16) | (color.green << 8)
| color.blue;
for (int i = 0; i < bi.getWidth(); i++) {
for (int j = 0; j < bi.getHeight(); j++) {
int argb = bi.getRGB(i, j);
// preserve alpha but color becomes color.
argb = (0xFF000000 & argb) | (0x00FFFFFF & colorint);
bi.setRGB(i, j, argb);
}
}
}
}

View file

@ -0,0 +1,53 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext;
import org.eclipse.swt.graphics.RGB;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension;
/**
* Extesnion for creating single color images.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 14, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlSingleColorImageExtension extends KmlRasterImageExtension
implements ISingleColorImageExtension {
@Override
public ISingleColorImage constructImage(IRenderedImageCallback callback,
RGB color) {
return new KmlSingleColorImage(callback, color);
}
}

View file

@ -0,0 +1,153 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext.point;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Collection;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.KmlFeatureGenerator;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImage;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlRasterImageExtension;
import com.raytheon.uf.viz.kml.export.io.KmlOutputManager;
import com.raytheon.viz.pointdata.drawables.IPointImageExtension;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Icon;
import de.micromata.opengis.kml.v_2_2_0.IconStyle;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
*
* Renders images at points as placemark icons in KML
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlPointImageExtension extends GraphicsExtension<KmlGraphicsTarget>
implements IPointImageExtension {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(KmlRasterImageExtension.class);
@Override
public void drawPointImages(PaintProperties paintProps,
PointImage... images) throws VizException {
drawPointImages(paintProps, Arrays.asList(images));
}
@Override
public void drawPointImages(PaintProperties paintProps,
Collection<PointImage> images) throws VizException {
target.addGenerator(new Generator(images));
}
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
private static class Generator extends KmlFeatureGenerator {
private final Collection<PointImage> images;
public Generator(Collection<PointImage> images) {
this.images = images;
}
@Override
public void addFeature(KmlOutputManager outputManager) {
if (images.size() > 1) {
outputManager = outputManager.createFolder("Points");
}
for (PointImage image : images) {
try {
Placemark placemark = new Placemark();
placemark.setName(image.getSiteId());
Coordinate loc = transformToLatLon(image.getX(),
image.getY());
Point point = placemark.createAndSetPoint();
point.addToCoordinates(loc.getLongitude(),
loc.getLatitude());
Style style = new Style();
style.createAndSetLabelStyle().setScale(0);
IconStyle iconStyle = style.createAndSetIconStyle();
iconStyle.setScale(options.getPlotIconScale());
double heading = 180 + MapUtil.rotation(
new com.vividsolutions.jts.geom.Coordinate(loc
.getLongitude(), loc.getLatitude()),
gridGeometry);
iconStyle.setHeading(heading);
Icon icon = iconStyle.createAndSetIcon();
RenderedImage rImage = null;
if (options.isFillPlotBackground()) {
rImage = ((KmlRasterImage) image.getImage())
.getImage(backgroundColor);
} else {
rImage = ((KmlRasterImage) image.getImage()).getImage();
}
String siteId = image.getSiteId();
if (siteId == null) {
icon.setHref(outputManager.addImage(rImage));
} else {
siteId = siteId.replaceAll("\\?", "QuestionMark");
icon.setHref(outputManager.addImage(rImage,
"pointIcons/" + siteId + ".png"));
}
placemark.setStyleUrl(outputManager.getStyleUrl(style));
outputManager.addFeature(placemark);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
} catch (FactoryException e) {
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
}
}
}

View file

@ -0,0 +1,78 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.graphics.ext.radar;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.referencing.FactoryException;
import com.raytheon.uf.common.dataplugin.radar.RadarRecord;
import com.raytheon.uf.common.dataplugin.radar.projection.RadarProjectionFactory;
import com.raytheon.uf.viz.core.IMesh;
import com.raytheon.uf.viz.core.drawables.ext.GraphicsExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.kml.export.graphics.KmlGraphicsTarget;
import com.raytheon.uf.viz.kml.export.graphics.ext.KmlMesh;
import com.raytheon.viz.radar.rsc.image.IRadialMeshExtension;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Creates a KMLMesh by constructing a RadialBinCRS based CrigGeometry object.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 6, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRadialMeshExtension extends
GraphicsExtension<KmlGraphicsTarget> implements IRadialMeshExtension {
@Override
public int getCompatibilityValue(KmlGraphicsTarget target) {
return Compatibilty.TARGET_COMPATIBLE;
}
@Override
public IMesh constructMesh(RadarRecord record,
GeneralGridGeometry targetGeometry) throws VizException {
GridGeometry2D imageGeometry;
try {
imageGeometry = RadarProjectionFactory
.constructGridGeometry(new Coordinate(
record.getLongitude(), record.getLatitude()),
record.getAngleData(), record.getGateResolution(),
record.getTrueElevationAngle(),
record.getNumBins(), true);
} catch (FactoryException e) {
throw new VizException(e);
}
return new KmlMesh(imageGeometry);
}
}

View file

@ -0,0 +1,96 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.io;
import java.awt.image.RenderedImage;
import de.micromata.opengis.kml.v_2_2_0.Container;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* The Folder output does not actually contain a KMZ stream but allows the
* parent to handle all file io.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlFolderOutputManager implements KmlOutputManager {
protected final KmlOutputManager parent;
protected final Folder folder;
private int imageCounter = 1;
public KmlFolderOutputManager(KmlOutputManager parent, Folder folder) {
this.parent = parent;
this.folder = folder;
}
@Override
public KmlOutputManager createFolder(String name) {
return new KmlFolderOutputManager(this, folder.createAndAddFolder()
.withName(name));
}
@Override
public String addImage(RenderedImage image) {
return addImage(image, "image" + (imageCounter++) + ".png");
}
@Override
public String addImage(RenderedImage image, String name) {
return parent.addImage(image, folder.getName() + "/" + name);
}
@Override
public String resolvePath(String name) {
return parent.resolvePath(folder.getName() + "/" + name);
}
@Override
public String getStyleUrl(Style style) {
return parent.getStyleUrl(style);
}
@Override
public void addFeature(Feature feature) {
folder.addToFeature(feature);
}
@Override
public Container getContainer() {
return folder;
}
}

View file

@ -0,0 +1,63 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.io;
import java.awt.image.RenderedImage;
import de.micromata.opengis.kml.v_2_2_0.Container;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* Wrapper around a KMZ file as well as a container java object, each folder an
* outputManager creates will be a folder in the KML view as well as a folder in
* the kmz file for any image resources that are stored.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public interface KmlOutputManager {
public KmlOutputManager createFolder(String name);
public String addImage(RenderedImage image);
public String addImage(RenderedImage image, String name);
public String resolvePath(String name);
public String getStyleUrl(Style style);
public void addFeature(Feature feature);
public Container getContainer();
}

View file

@ -0,0 +1,164 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.kml.export.io;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import javax.xml.bind.JAXB;
import de.micromata.opengis.kml.v_2_2_0.Container;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import de.micromata.opengis.kml.v_2_2_0.Style;
/**
* The root output manager holds a the base output stream as well as the root
* KML Document.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 1, 2012 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class KmlRootOutputManager implements KmlOutputManager {
private Set<String> names = new HashSet<String>();
private final Kml kml;
private final Document document;
private IOException exception;
private int imageCounter = 1;
private int styleCounter = 1;
private Map<Style, String> styleMap = new HashMap<Style, String>();
private final ZipOutputStream zos;
public KmlRootOutputManager(File kmzFile) throws FileNotFoundException {
this.zos = new ZipOutputStream(new FileOutputStream(kmzFile));
this.kml = new Kml();
this.document = this.kml.createAndSetDocument();
}
@Override
public KmlOutputManager createFolder(String name) {
return new KmlFolderOutputManager(this, document.createAndAddFolder()
.withName(name));
}
@Override
public String addImage(RenderedImage image) {
return addImage(image, "image" + (imageCounter++) + ".png");
}
@Override
public String addImage(RenderedImage image, String name) {
if (names.contains(name)) {
String newName = name;
for (int i = 1; names.contains(newName); i++) {
newName = name.replace(".png", "-" + i + ".png");
}
name = newName;
}
names.add(name);
synchronized (zos) {
try {
zos.putNextEntry(new ZipEntry(name));
ImageIO.write(image, "png", zos);
zos.closeEntry();
} catch (IOException e) {
exception = e;
}
}
return name;
}
@Override
public String resolvePath(String name) {
return name;
}
@Override
public synchronized String getStyleUrl(Style style) {
Style key = style.clone().withId(null);
String id = styleMap.get(key);
if (id == null) {
id = style.getId();
if (id == null) {
id = "style" + this.styleCounter++;
}
styleMap.put(key, id);
style.setId(id);
document.addToStyleSelector(style);
}
return "#" + id;
}
@Override
public void addFeature(Feature feature) {
document.addToFeature(feature);
}
@Override
public Container getContainer() {
return document;
}
/**
* Closes the kmz stream and serializes the kml document.
*
* @throws IOException
*/
public void close() throws IOException {
if (exception != null) {
throw exception;
}
zos.putNextEntry(new ZipEntry("doc.kml"));
JAXB.marshal(kml, zos);
zos.closeEntry();
zos.close();
}
}

View file

@ -0,0 +1,90 @@
#include <colorUtil>
#include <indexing>
// Multiplier used to store bit mask safely between 0-1
const float maskMultiplier = 8.0;
uniform sampler2D rawTex;
uniform float naturalMin;
uniform float naturalMax;
uniform float cmapMin;
uniform float cmapMax;
uniform int isFloat;
uniform int band;
uniform sampler2D trueColorTexture;
uniform int height;
uniform int width;
uniform float noDataValue;
uniform float alphaStep;
uniform int expectedMask;
int toBitMask(float alpha) {
return int((alpha * maskMultiplier) + 0.5);
}
float getIndex(sampler2D rawTex, float cmapMin, float cmapMax, float naturalMin, float naturalMax, int isFloat) {
vec4 textureValue = texture2D(rawTex, gl_TexCoord[0].st);
float naturalVal = textureValue.r;
if ( isFloat == 0 ) {
naturalVal = ((naturalVal * (naturalMax - naturalMin)) + naturalMin);
}
float index = -1.0;
if (naturalVal != noDataValue && naturalVal == naturalVal) {
index = findIndex(naturalVal, cmapMin, cmapMax);
}
return index;
}
void main(void)
{
if ( band == -1 ) {
vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st);
float r = imageVal.r;
float g = imageVal.g;
float b = imageVal.b;
float a = imageVal.a;
// Round because of 8-bit floating point precision
int bitMask = toBitMask(a);
if (expectedMask > 0 && bitMask == expectedMask ) {
a = 1.0;
} else {
a = 0.0;
}
gl_FragColor = vec4(r,g,b,a);
} else {
vec2 xy = gl_FragCoord.xy;
vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st);
vec4 curVal = texture2D(trueColorTexture, vec2((xy.x / float(width)), (xy.y / float(height))));
float r = curVal.r;
float g = curVal.g;
float b = curVal.b;
float a = curVal.a;
float index = getIndex(rawTex, cmapMin, cmapMax, naturalMin, naturalMax, isFloat);
if ( index != -1.0 ) {
int currentMask = toBitMask(a);
int bitValue = (1 << band);
if ( band == 0 && index > r ) {
r = index;
} else if ( band == 1 && index > g ) {
g = index;
} else if ( band == 2 && index > b ) {
b = index;
}
if ( (currentMask & bitValue) == 0 ) {
// alpha does not contain this bit yet!
a = (currentMask | bitValue) / maskMultiplier;
}
}
gl_FragColor = vec4(r,g,b,a);
}
}

View file

@ -0,0 +1,257 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.gl.extension;
import java.util.IdentityHashMap;
import java.util.Map;
import javax.media.opengl.GL;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.PixelCoverage;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.ImagingSupport;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension;
import com.raytheon.uf.viz.truecolor.gl.image.GLTrueColorImage;
import com.raytheon.viz.core.gl.ext.GLOffscreenRenderingExtension;
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
import com.raytheon.viz.core.gl.images.AbstractGLImage;
import com.raytheon.viz.core.gl.images.GLColormappedImage;
/**
* GL implementation of the {@link ITrueColorImagingExtension}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension
implements ITrueColorImagingExtension {
private AbstractGLImage writeToImage;
private Channel renderingChannel;
/** The current rendering bit mask, specifies what bands we rendered */
private int currentMask = 0;
private Map<ColorMapParameters, Object> parameters = new IdentityHashMap<ColorMapParameters, Object>();
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension#
* initializeRaster(int[], com.raytheon.uf.viz.core.IExtent)
*/
@Override
public ITrueColorImage initializeRaster(int[] imageBounds,
IExtent imageExtent) throws VizException {
return new GLTrueColorImage(GLTrueColorImagingExtension.class,
imageBounds, imageExtent);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#getShaderProgramName
* ()
*/
@Override
public String getShaderProgramName() {
return "truecolor";
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#preImageRender
* (com.raytheon.uf.viz.core.drawables.PaintProperties,
* com.raytheon.viz.core.gl.images.AbstractGLImage,
* com.raytheon.uf.viz.core.PixelCoverage)
*/
@Override
public Object preImageRender(PaintProperties paintProps,
AbstractGLImage image, PixelCoverage imageCoverage)
throws VizException {
if (image instanceof GLTrueColorImage) {
GLTrueColorImage trueColorImage = (GLTrueColorImage) image;
if (trueColorImage.isRepaint()) {
// Reset current bit mask
currentMask = 0;
parameters.clear();
writeToImage = trueColorImage;
GLOffscreenRenderingExtension extension = target
.getExtension(GLOffscreenRenderingExtension.class);
try {
extension.renderOffscreen(trueColorImage,
trueColorImage.getImageExtent());
boolean allPainted = true;
for (Channel channel : Channel.values()) {
renderingChannel = channel;
DrawableImage[] imagesToDraw = trueColorImage
.getImages(channel);
if (imagesToDraw != null && imagesToDraw.length > 0) {
// Mark the channel bit in the current bit mask
currentMask |= (1 << channel.ordinal());
// Make sure images are staged before we mosaic them
ImagingSupport.prepareImages(target, imagesToDraw);
// Each image needs to draw separately due to gl
// issues when zoomed in very far, rendered parts
// near the corners don't show all the pixels for
// each image. Pushing and popping GL_TEXTURE_BIT
// before/after each render fixes this issue
for (DrawableImage di : imagesToDraw) {
allPainted &= drawRasters(paintProps, di);
}
// Need to set repaint based on if drawing
// completed.
trueColorImage.setRepaint(allPainted == false);
}
}
} catch (VizException e) {
extension.renderOnscreen();
throw e;
}
renderingChannel = null;
writeToImage = null;
trueColorImage.setImageParameters(parameters.keySet());
trueColorImage.bind(target.getGl());
return imageCoverage;
} else {
target.drawRasters(paintProps,
new DrawableImage(trueColorImage.getWrappedImage(),
imageCoverage));
return null;
}
} else {
GL gl = target.getGl();
// bind on GL_TEXTURE1 as 0 is channel image
writeToImage.bind(gl, GL.GL_TEXTURE1);
return image;
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#postImageRender
* (com.raytheon.uf.viz.core.drawables.PaintProperties,
* com.raytheon.viz.core.gl.images.AbstractGLImage, java.lang.Object)
*/
@Override
public void postImageRender(PaintProperties paintProps,
AbstractGLImage image, Object data) throws VizException {
if (image instanceof GLTrueColorImage) {
target.getExtension(GLOffscreenRenderingExtension.class)
.renderOnscreen();
target.drawRasters(paintProps, new DrawableImage(
((GLTrueColorImage) image).getWrappedImage(),
(PixelCoverage) data));
} else if (writeToImage != null) {
GL gl = target.getGl();
// Unbind the writeToImage from GL_TEXTURE1
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glBindTexture(writeToImage.getTextureStorageType(), 0);
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#loadShaderData
* (com.raytheon.viz.core.gl.glsl.GLShaderProgram,
* com.raytheon.uf.viz.core.drawables.IImage,
* com.raytheon.uf.viz.core.drawables.PaintProperties)
*/
@Override
public void loadShaderData(GLShaderProgram program, IImage image,
PaintProperties paintProps) throws VizException {
if (image instanceof GLTrueColorImage) {
program.setUniform("band", -1);
program.setUniform("rawTex", 0);
program.setUniform("expectedMask", currentMask);
} else {
if (image instanceof GLColormappedImage == false) {
throw new VizException(
"Can only render colormapped images in true color");
}
GLColormappedImage cmapImage = (GLColormappedImage) image;
ColorMapParameters colorMapParameters = cmapImage
.getColorMapParameters();
parameters.put(colorMapParameters, null);
int textureType = cmapImage.getTextureType();
// Set the band image data
program.setUniform("rawTex", 0);
program.setUniform("naturalMin", colorMapParameters.getDataMin());
program.setUniform("naturalMax", colorMapParameters.getDataMax());
program.setUniform("cmapMin", colorMapParameters.getColorMapMin());
program.setUniform("cmapMax", colorMapParameters.getColorMapMax());
program.setUniform("isFloat", textureType == GL.GL_FLOAT
|| textureType == GL.GL_HALF_FLOAT_ARB ? 1 : 0);
program.setUniform("noDataValue",
colorMapParameters.getNoDataValue());
// Set the composite image data
program.setUniform("trueColorTexture", 1);
program.setUniform("width", writeToImage.getWidth());
program.setUniform("height", writeToImage.getHeight());
// Set the band we are rendering to
program.setUniform("band", renderingChannel.ordinal());
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#enableBlending
* (javax.media.opengl.GL)
*/
@Override
protected void enableBlending(GL gl) {
// Do not enable blending for this extension as it messes with alpha
// values between passes
}
}

View file

@ -0,0 +1,249 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.gl.image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.data.IRenderedImageCallback;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColorMapParametersListener;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.Channel;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.ITrueColorImage;
import com.raytheon.viz.core.gl.images.GLDelegateImage;
import com.raytheon.viz.core.gl.images.GLImage;
/**
* GL implementation of {@link ITrueColorImage}. Manages drawable images for
* {@link Channel} objects. Listens for changes on the ColorMapParameters for
* the underlying images so it knows when repaint
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class GLTrueColorImage extends GLDelegateImage<GLImage> implements
ITrueColorImage, IColorMapParametersListener {
private static class RGBCallback implements IRenderedImageCallback {
private int[] bounds;
private RGBCallback(int[] bounds) {
this.bounds = bounds;
}
@Override
public RenderedImage getImage() throws VizException {
return new BufferedImage(bounds[0], bounds[1],
BufferedImage.TYPE_INT_ARGB);
}
}
private boolean repaint = true;
private int[] bounds;
private IExtent imageExtent;
private Map<Channel, DrawableImage[]> channelMap = new HashMap<Channel, DrawableImage[]>();
/* Identity set used to track color map parameters currently listening on */
private Map<ColorMapParameters, Object> listening = new IdentityHashMap<ColorMapParameters, Object>();
/**
* @param extensionClass
*/
public GLTrueColorImage(Class<? extends IImagingExtension> extensionClass,
int[] bounds, IExtent imageExtent) {
super(new GLImage(new RGBCallback(bounds), IImagingExtension.class),
extensionClass);
this.bounds = bounds;
this.imageExtent = imageExtent;
}
/**
* @return the imageExtent
*/
public IExtent getImageExtent() {
return imageExtent;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.
* ITrueColorImage
* #setImages(com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension
* .Channel, com.raytheon.uf.viz.core.DrawableImage[])
*/
@Override
public void setImages(Channel channel, DrawableImage... images) {
DrawableImage[] prev = channelMap.put(channel, images);
if (prev != images) {
// Try to find equal array
if (prev != null && images != null && prev.length == images.length) {
for (int i = 0; i < images.length; ++i) {
if (images[i].getImage() != prev[i].getImage()) {
repaint = true;
break;
}
}
} else {
repaint = true;
}
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.
* ITrueColorImage
* #getImages(com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension
* .Channel)
*/
@Override
public DrawableImage[] getImages(Channel channel) {
return channelMap.get(channel);
}
/**
* @return the repaint
*/
public boolean isRepaint() {
return repaint;
}
/**
* @param repaint
* the repaint to set
*/
public void setRepaint(boolean repaint) {
this.repaint = repaint;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.
* ITrueColorImage#setSize(int[])
*/
@Override
public void setSize(int[] bounds) {
if (Arrays.equals(bounds, this.bounds) == false) {
this.bounds = bounds;
image.dispose();
image = new GLImage(new RGBCallback(bounds),
IImagingExtension.class);
repaint = true;
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.
* ITrueColorImage#setImageExtent(com.raytheon.uf.viz.core.IExtent)
*/
@Override
public void setImageExtent(IExtent extent) {
if (extent.equals(this.imageExtent) == false) {
this.imageExtent = extent;
repaint = true;
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColorMapParametersListener#
* colorMapChanged()
*/
@Override
public void colorMapChanged() {
// Repaint image on colormap change events
repaint = true;
}
/**
* Sets the ColorMapParameters it's images are using. We add ourselves as
* listeners so we can repaint on changes
*
* @param parameters
*/
public void setImageParameters(Collection<ColorMapParameters> parameters) {
boolean same = false;
if (parameters.size() == listening.size()) {
same = true;
for (ColorMapParameters params : parameters) {
same &= listening.containsKey(params);
if (!same) {
break;
}
}
}
if (!same) {
// Current image parameters list different from passed in, set up
// listeners on new set and remove from current set
for (ColorMapParameters params : listening.keySet()) {
params.removeListener(this);
}
listening.clear();
for (ColorMapParameters params : parameters) {
params.addListener(this);
listening.put(params, null);
}
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.GLDelegateImage#dispose()
*/
@Override
public void dispose() {
super.dispose();
for (ColorMapParameters params : listening.keySet()) {
params.removeListener(this);
}
listening.clear();
}
}

View file

@ -0,0 +1,18 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Truecolor
Bundle-SymbolicName: com.raytheon.uf.viz.truecolor;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.raytheon.uf.viz.truecolor.Activator
Bundle-Vendor: RAYTHEON
Eclipse-RegisterBuddy: com.raytheon.uf.viz.core, com.raytheon.viz.ui
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
com.raytheon.uf.viz.core;bundle-version="1.12.1174",
com.raytheon.viz.ui;bundle-version="1.12.1174",
com.raytheon.uf.common.time;bundle-version="1.12.1174",
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174",
javax.measure;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.uf.viz.truecolor.extension

View file

@ -0,0 +1,3 @@
com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroupData
com.raytheon.uf.viz.truecolor.rsc.ChannelInfo
com.raytheon.uf.viz.truecolor.rsc.ChannelResource

View file

@ -0,0 +1,39 @@
<?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.
-->
<?eclipse version="3.2"?>
<plugin>
<extension
point="com.raytheon.uf.viz.core.resource">
<resource
class="com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroup"
name="True Color Imagery"
renderingOrderId="IMAGE_COUNTRY"
resourceType="PLAN_VIEW"/>
</extension>
<extension
point="com.raytheon.viz.ui.contextualMenu">
<contextualMenu
actionClass="com.raytheon.uf.viz.truecolor.ui.TrueColorDialogAction"
capabilityClass="com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroup"
name="TrueColorImaging"
sortID="25"/>
</extension>
</plugin>

View file

@ -0,0 +1,77 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.extension;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension;
import com.raytheon.uf.viz.core.exception.VizException;
/**
* Imaging extension for "true color" images. Where a set of
* {@link IColormappedImage} images are assigned to each band of an RGB channel
* image
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public interface ITrueColorImagingExtension extends IImagingExtension {
public static enum Channel {
RED, GREEN, BLUE;
}
public static interface ITrueColorImage extends IImage {
public void setImages(Channel channel, DrawableImage... images);
public DrawableImage[] getImages(Channel channel);
public void setSize(int[] bounds);
public void setImageExtent(IExtent extent);
}
/**
* Creates a true color image with the given imageBounds and imageExtent
*
* @param imageBounds
* @param imageExtent
* @param params
* @return
* @throws VizException
*/
public ITrueColorImage initializeRaster(int[] imageBounds,
IExtent imageExtent) throws VizException;
}

View file

@ -0,0 +1,192 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.rsc;
import java.text.ParsePosition;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.Channel;
/**
* Channel information (range/unit) for a true color channel
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 20, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class ChannelInfo {
@XmlAttribute
private Channel channel;
@XmlElement
private double rangeMin = 0.0;
@XmlElement
private double rangeMax = 1.0;
private Unit<?> unit = Unit.ONE;
/**
* @return the channel
*/
public Channel getChannel() {
return channel;
}
/**
* @param channel
* the channel to set
*/
public void setChannel(Channel channel) {
this.channel = channel;
}
/**
* @return the rangeMin
*/
public double getRangeMin() {
return rangeMin;
}
/**
* @param rangeMin
* the rangeMin to set
*/
public void setRangeMin(double rangeMin) {
this.rangeMin = rangeMin;
}
/**
* @return the rangeMax
*/
public double getRangeMax() {
return rangeMax;
}
/**
* @param rangeMax
* the rangeMax to set
*/
public void setRangeMax(double rangeMax) {
this.rangeMax = rangeMax;
}
/**
* @return the unit
*/
public Unit<?> getUnit() {
return unit;
}
/**
* @param unit
* the unit to set
*/
public void setUnit(Unit<?> unit) {
this.unit = unit;
}
@XmlElement(name = "unit")
public void setUnitString(String unit) {
if (unit != null) {
this.unit = UnitFormat.getUCUMInstance().parseObject(unit,
new ParsePosition(0));
} else {
this.unit = null;
}
if (this.unit == null) {
this.unit = Unit.ONE;
}
}
public String getUnitString() {
// Let anything with Unit.ONE serialize back out as null since it was
// probably never set and will default to Unit.ONE
return unit != Unit.ONE ? UnitFormat.getUCUMInstance().format(unit)
: null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((channel == null) ? 0 : channel.hashCode());
long temp;
temp = Double.doubleToLongBits(rangeMax);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(rangeMin);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((unit == null) ? 0 : unit.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChannelInfo other = (ChannelInfo) obj;
if (channel != other.channel)
return false;
if (Double.doubleToLongBits(rangeMax) != Double
.doubleToLongBits(other.rangeMax))
return false;
if (Double.doubleToLongBits(rangeMin) != Double
.doubleToLongBits(other.rangeMin))
return false;
if (unit == null) {
if (other.unit != null)
return false;
} else if (!unit.equals(other.unit))
return false;
return true;
}
}

View file

@ -0,0 +1,146 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.rsc;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import com.raytheon.uf.viz.core.rsc.AbstractResourceData;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.Channel;
/**
* Object that represents a resource bound to a {@link Channel}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 16, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class ChannelResource {
@XmlElement
protected AbstractResourceData resourceData;
@XmlElement
protected Channel channel;
@XmlAttribute
protected String channelName;
/**
* @return the resourceData
*/
public AbstractResourceData getResourceData() {
return resourceData;
}
/**
* @param resourceData
* the resourceData to set
*/
public void setResourceData(AbstractResourceData resourceData) {
this.resourceData = resourceData;
}
/**
* @return the channel
*/
public Channel getChannel() {
return channel;
}
/**
* @param channel
* the channel to set
*/
public void setChannel(Channel channel) {
this.channel = channel;
}
/**
* @return the channelName
*/
public String getChannelName() {
return channelName;
}
/**
* @param channelName
* the channelName to set
*/
public void setChannelName(String channelName) {
this.channelName = channelName;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((channelName == null) ? 0 : channelName.hashCode());
result = prime * result
+ ((resourceData == null) ? 0 : resourceData.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChannelResource other = (ChannelResource) obj;
if (channelName == null) {
if (other.channelName != null)
return false;
} else if (!channelName.equals(other.channelName))
return false;
if (resourceData == null) {
if (other.resourceData != null)
return false;
} else if (!resourceData.equals(other.resourceData))
return false;
return true;
}
}

View file

@ -0,0 +1,441 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.rsc;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import org.eclipse.swt.graphics.Rectangle;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.DrawableImage;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget;
import com.raytheon.uf.viz.core.PixelCoverage;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IDescriptor;
import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension.ImageProvider;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.IResourceDataChanged;
import com.raytheon.uf.viz.core.rsc.IResourceGroup;
import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.rsc.ResourceList;
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
import com.raytheon.uf.viz.core.rsc.capabilities.GroupNamingCapability;
import com.raytheon.uf.viz.core.rsc.capabilities.ImagingCapability;
import com.raytheon.uf.viz.truecolor.Activator;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.Channel;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.ITrueColorImage;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Resource group that operates on 3 resources, one assigned to each band of an
* RGB image. This resource checks for the {@link ImageProvider} on the
* {@link ImagingCapability}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class TrueColorResourceGroup extends
AbstractVizResource<TrueColorResourceGroupData, IDescriptor> implements
IResourceGroup, IResourceDataChanged {
public static class DisplayedChannelResource {
private String displayName;
public AbstractVizResource<?, ?> resource;
public ChannelResource channel;
private DisplayedChannelResource(ChannelResource cr,
AbstractVizResource<?, ?> resource) {
this.channel = cr;
this.resource = resource;
this.displayName = cr.getChannelName();
if (displayName == null) {
displayName = resource.getName();
}
}
/**
* Returns the display name of the channel
*
* @return
*/
public String getDisplayName() {
return displayName;
}
/**
* Checks if the resource is bound to the specified {@link Channel}
*
* @param channel
* @return
*/
public boolean isChannel(Channel channel) {
return this.channel.getChannel() == channel;
}
/**
* @return
*/
public Channel getChannel() {
return channel.getChannel();
}
}
private static final String DEFAULT_NAME = "RGB Composite";
private Map<Channel, DisplayedChannelResource> displayedResources;
private ITrueColorImage image;
private boolean timeAgnostic = true;
private String baseName;
/**
* Mapping to keep colormap parameters in sync with ChannelInfo in
* resourceData
*/
private Map<ColorMapParameters, ChannelInfo> channelInfoMap = new IdentityHashMap<ColorMapParameters, ChannelInfo>();
/**
* @param resourceData
* @param loadProperties
*/
public TrueColorResourceGroup(TrueColorResourceGroupData resourceData,
LoadProperties loadProperties) {
super(resourceData, loadProperties);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.IResourceGroup#getResourceList()
*/
@Override
public ResourceList getResourceList() {
return resourceData.getResourceList();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.AbstractVizResource#disposeInternal()
*/
@Override
protected void disposeInternal() {
resourceData.removeChangeListener(this);
for (ResourcePair rp : getResourceList()) {
rp.getResource().dispose();
}
image.dispose();
}
/*
* (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 {
Rectangle rect = paintProps.getCanvasBounds();
IExtent extent = paintProps.getView().getExtent();
image.setSize(new int[] { rect.width, rect.height });
image.setImageExtent(extent);
FramesInfo fi = paintProps.getFramesInfo();
for (Channel c : Channel.values()) {
DrawableImage[] images = null;
DisplayedChannelResource dcr = displayedResources.get(c);
if (dcr != null) {
DataTime dcrTime = fi.getTimeForResource(dcr.resource);
if (dcrTime != null) {
paintProps.setDataTime(fi.getTimeForResource(dcr.resource));
Collection<DrawableImage> dcrImages = dcr.resource
.getCapability(ImagingCapability.class)
.getProvider().getImages(target, paintProps);
if (dcrImages != null) {
images = dcrImages.toArray(new DrawableImage[dcrImages
.size()]);
}
}
}
image.setImages(c, images);
}
Coordinate ul = new Coordinate(extent.getMinX(), extent.getMaxY());
Coordinate ur = new Coordinate(extent.getMaxX(), extent.getMaxY());
Coordinate lr = new Coordinate(extent.getMaxX(), extent.getMinY());
Coordinate ll = new Coordinate(extent.getMinX(), extent.getMinY());
target.drawRaster(image, new PixelCoverage(ul, ur, lr, ll), paintProps);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.AbstractVizResource#isTimeAgnostic()
*/
@Override
public boolean isTimeAgnostic() {
return timeAgnostic;
}
/*
* (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 {
// We will name the composite
getCapability(GroupNamingCapability.class);
displayedResources = new HashMap<Channel, DisplayedChannelResource>();
ResourceList resources = getResourceList();
for (ChannelResource cr : resourceData.getChannelResources()) {
for (ResourcePair rp : resources) {
if (cr.getResourceData() == rp.getResourceData()) {
DisplayedChannelResource displayedResource = new DisplayedChannelResource(
cr, rp.getResource());
AbstractVizResource<?, ?> resource = rp.getResource();
resource.init(target);
// Check resource for required capabilities
String error = null;
if (resource.hasCapability(ImagingCapability.class)) {
ImagingCapability imaging = resource
.getCapability(ImagingCapability.class);
if (imaging.getProvider() != null) {
if (resource
.hasCapability(ColorMapCapability.class) == false) {
error = "does not have ColorMapCapability";
} else if (resource.getCapability(
ColorMapCapability.class)
.getColorMapParameters() == null) {
error = "does not have ColorMapParameters set";
}
} else {
error = "does not have image provider set on the ImagingCapability";
}
} else {
error = "does not have the ImagingCapability";
}
if (cr.getChannel() == null) {
error = "is not tied to any channel";
} else if (displayedResources.containsKey(cr.getChannel())) {
error = "is tied to a channel already in use";
}
if (error == null) {
// No errors so far, check for ChannelInfo override
ColorMapParameters params = resource.getCapability(
ColorMapCapability.class)
.getColorMapParameters();
ChannelInfo ci = resourceData
.getChannelInfo(displayedResource.getChannel());
if (ci == null
|| ci.getUnit().isCompatible(
params.getDataUnit())) {
if (ci == null) {
ci = new ChannelInfo();
ci.setChannel(displayedResource.getChannel());
resourceData.setChannelInfo(ci);
} else {
params.setDisplayUnit(ci.getUnit());
params.setColorMapMin((float) params
.getDisplayToDataConverter().convert(
ci.getRangeMin()));
params.setColorMapMax((float) params
.getDisplayToDataConverter().convert(
ci.getRangeMax()));
}
channelInfoMap.put(params, ci);
resourceChanged(
ChangeType.CAPABILITY,
resource.getCapability(ColorMapCapability.class));
} else {
error = "is not compatible with custom ChannelInfo for Channel="
+ displayedResource.getChannel();
}
}
if (error != null) {
Activator.statusHandler.handle(Priority.PROBLEM,
displayedResource.getDisplayName()
+ " resource in true color composite "
+ error);
resources.remove(rp);
} else {
resource.getResourceData().addChangeListener(this);
displayedResources.put(displayedResource.getChannel(),
displayedResource);
}
break;
}
}
}
if (displayedResources.size() == 0) {
throw new VizException(
"No resources to draw in true color composite");
}
ITrueColorImagingExtension ext = target
.getExtension(ITrueColorImagingExtension.class);
image = ext.initializeRaster(new int[] { 0, 0 }, null);
resourceData.addChangeListener(this);
// Set initial ImagingCapability parameters
resourceChanged(ChangeType.CAPABILITY,
getCapability(ImagingCapability.class));
// Every resource has to be time agnostic for us to be as well
timeAgnostic = true;
for (DisplayedChannelResource dr : displayedResources.values()) {
timeAgnostic &= dr.resource.isTimeAgnostic();
}
String groupName = resourceData.getGroupName();
if (groupName == null) {
groupName = "True Color Composite";
}
String channels = " (";
for (Channel c : Channel.values()) {
if (displayedResources.containsKey(c)) {
channels += c.name().substring(0, 1);
}
}
channels += "): ";
baseName = groupName + channels;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.AbstractVizResource#getName()
*/
@Override
public String getName() {
String name = baseName;
boolean first = true;
for (Channel c : Channel.values()) {
DisplayedChannelResource dcr = displayedResources.get(c);
if (dcr != null) {
if (!first) {
name += "/";
}
first = false;
boolean has = true;
if (image != null && image.getImages(c) == null) {
has = false;
}
if (has) {
name += dcr.getDisplayName();
} else {
String channelName = c.name();
name += "No " + channelName.substring(0, 1)
+ channelName.substring(1).toLowerCase();
}
}
}
return name;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.rsc.AbstractVizResource#project(org.opengis.
* referencing.crs.CoordinateReferenceSystem)
*/
@Override
public void project(CoordinateReferenceSystem crs) throws VizException {
for (ResourcePair rp : getResourceList()) {
rp.getResource().project(crs);
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.rsc.IResourceDataChanged#resourceChanged(com
* .raytheon.uf.viz.core.rsc.IResourceDataChanged.ChangeType,
* java.lang.Object)
*/
@Override
public void resourceChanged(ChangeType type, Object object) {
if (type == ChangeType.CAPABILITY) {
if (object instanceof ImagingCapability) {
ImagingCapability imaging = (ImagingCapability) object;
image.setBrightness(imaging.getBrightness());
image.setContrast(imaging.getContrast());
image.setInterpolated(imaging.isInterpolationState());
} else if (object instanceof ColorMapCapability) {
ColorMapParameters params = ((ColorMapCapability) object)
.getColorMapParameters();
ChannelInfo ci = channelInfoMap.get(params);
if (ci != null) {
ci.setRangeMin(params.getDataToDisplayConverter().convert(
params.getColorMapMin()));
ci.setRangeMax(params.getDataToDisplayConverter().convert(
params.getColorMapMax()));
ci.setUnit(params.getDisplayUnit());
}
}
}
issueRefresh();
}
public Collection<DisplayedChannelResource> getChannelResources() {
return displayedResources.values();
}
}

View file

@ -0,0 +1,249 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.truecolor.rsc;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
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.AbstractResourceData;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.IResourceGroup;
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.truecolor.extension.ITrueColorImagingExtension.Channel;
/**
* {@link TrueColorResourceGroup} resource data. Contains a red/blue/green
* channel resource and a name.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 6, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class TrueColorResourceGroupData extends AbstractResourceData implements
IResourceGroup {
private ResourceList resourceList;
@XmlElement
private String groupName;
@XmlElement(name = "channelResource")
private List<ChannelResource> channelResources;
private Map<Channel, ChannelInfo> channelInfo = new HashMap<Channel, ChannelInfo>();
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.rsc.IResourceGroup#getResourceList()
*/
@Override
public ResourceList getResourceList() {
if (resourceList == null) {
resourceList = new ResourceList() {
private static final long serialVersionUID = 1L;
@Override
protected boolean canAdd(ResourcePair e) {
// Don't allow a ResourcePair that == another in the list
Iterator<ResourcePair> iter = iterator();
while (iter.hasNext()) {
if (iter.next() == e) {
return false;
}
}
return true;
}
};
for (ChannelResource resource : channelResources) {
addResource(resource.getResourceData());
}
}
return resourceList;
}
private void addResource(AbstractResourceData resourceData) {
ResourcePair rp = new ResourcePair();
rp.setResourceData(resourceData);
rp.setLoadProperties(new LoadProperties());
rp.setProperties(new ResourceProperties());
resourceList.add(rp);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.rsc.AbstractResourceData#construct(com.raytheon
* .uf.viz.core.rsc.LoadProperties,
* com.raytheon.uf.viz.core.drawables.IDescriptor)
*/
@Override
public AbstractVizResource<?, ?> construct(LoadProperties loadProperties,
IDescriptor descriptor) throws VizException {
return new TrueColorResourceGroup(this, loadProperties);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.rsc.AbstractResourceData#update(java.lang.Object
* )
*/
@Override
public void update(Object updateData) {
// Nothing to update, updates will be handled by sub resources
}
/**
* @return the groupName
*/
public String getGroupName() {
return groupName;
}
/**
* @param groupName
* the groupName to set
*/
public void setGroupName(String groupName) {
this.groupName = groupName;
}
/**
* @return the channelResources
*/
public List<ChannelResource> getChannelResources() {
return channelResources;
}
/**
* @param channelResources
* the channelResources to set
*/
public void setChannelResources(List<ChannelResource> channelResources) {
this.channelResources = channelResources;
}
/**
* @return the channelInfo
*/
public ChannelInfo getChannelInfo(Channel channel) {
return channelInfo.get(channel);
}
/**
* @param channelInfo
* the channelInfo to set
*/
public void setChannelInfo(ChannelInfo channelInfo) {
this.channelInfo.put(channelInfo.getChannel(), channelInfo);
}
public ChannelInfo[] getChannelInfoArray() {
return this.channelInfo.values().toArray(
new ChannelInfo[channelInfo.size()]);
}
@XmlElement(name = "channelInfo")
public void setChannelInfoArray(ChannelInfo[] channelInfo) {
if (channelInfo == null) {
channelInfo = new ChannelInfo[0];
}
this.channelInfo.clear();
for (ChannelInfo ci : channelInfo) {
setChannelInfo(ci);
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((channelInfo == null) ? 0 : channelInfo.hashCode());
result = prime
* result
+ ((channelResources == null) ? 0 : channelResources.hashCode());
result = prime * result
+ ((groupName == null) ? 0 : groupName.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TrueColorResourceGroupData other = (TrueColorResourceGroupData) obj;
if (channelInfo == null) {
if (other.channelInfo != null)
return false;
} else if (!channelInfo.equals(other.channelInfo))
return false;
if (channelResources == null) {
if (other.channelResources != null)
return false;
} else if (!channelResources.equals(other.channelResources))
return false;
if (groupName == null) {
if (other.groupName != null)
return false;
} else if (!groupName.equals(other.groupName))
return false;
return true;
}
}

View file

@ -17,11 +17,11 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.ui.dialogs;
package com.raytheon.uf.viz.truecolor.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
@ -30,20 +30,24 @@ import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.Channel;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.ChannelData;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.capabilities.MultiChannelCapability;
import com.raytheon.uf.viz.core.rsc.IDisposeListener;
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension.Channel;
import com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroup;
import com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroup.DisplayedChannelResource;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
import com.raytheon.viz.ui.dialogs.ColorMapSliderComp;
/**
* Dialog for manipulating multi channel capability
* Dialog for modifying true color attributes on a dialog
*
* TODO: Update sliders when combo changes
*
* <pre>
*
@ -51,7 +55,7 @@ import com.raytheon.uf.viz.core.rsc.capabilities.MultiChannelCapability;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 3, 2012 mschenke Initial creation
* Aug 16, 2012 mschenke Initial creation
*
* </pre>
*
@ -59,29 +63,26 @@ import com.raytheon.uf.viz.core.rsc.capabilities.MultiChannelCapability;
* @version 1.0
*/
public class MultiChannelDialog extends CaveSWTDialog {
public class TrueColorDialog extends CaveSWTDialog implements IDisposeListener {
private static final String DISABLED = "Disabled";
private AbstractVizResource<?, ?> resource;
private MultiChannelCapability capability;
private String[] items;
protected TrueColorResourceGroup resource;
private List<ColorMapSliderComp> sliderComps;
public MultiChannelDialog(Shell parent, AbstractVizResource<?, ?> resource,
MultiChannelCapability capability) {
super(parent);
this.capability = capability;
/**
* Creates the TrueColorDialog as a window of the parent Shell
*
* @param parent
* @param resource
*/
public TrueColorDialog(Shell parent, TrueColorResourceGroup resource) {
super(parent, SWT.DIALOG_TRIM);
this.resource = resource;
String[] names = capability.getNames();
this.items = new String[names.length + 1];
System.arraycopy(names, 0, items, 1, names.length);
items[0] = DISABLED;
this.sliderComps = new ArrayList<ColorMapSliderComp>();
setText("Channel Options");
setText("Composite Options");
resource.registerListener(this);
}
/*
@ -93,9 +94,15 @@ public class MultiChannelDialog extends CaveSWTDialog {
*/
@Override
protected void initializeComponents(Shell shell) {
Map<Channel, ChannelData> channelMap = capability.getChannelMap();
Collection<DisplayedChannelResource> resources = resource
.getChannelResources();
for (Channel c : Channel.values()) {
addGroup(shell, c, channelMap.get(c));
for (DisplayedChannelResource rsc : resources) {
if (rsc.isChannel(c)) {
addGroup(shell, c, rsc);
break;
}
}
}
Composite buttonComp = new Composite(shell, SWT.NONE);
@ -129,73 +136,39 @@ public class MultiChannelDialog extends CaveSWTDialog {
b.setLayoutData(gd);
}
private void addGroup(Composite parent, Channel channel,
final ChannelData data) {
/**
* @param shell
* @param c
* @param displayedChannelResource
*/
private void addGroup(Composite parent, final Channel channel,
DisplayedChannelResource displayedResource) {
ColorMapParameters params = null;
if (data != null) {
params = data.parameters;
if (displayedResource != null) {
params = displayedResource.resource.getCapability(
ColorMapCapability.class).getColorMapParameters();
} else {
params = new ColorMapParameters();
}
String groupName = channel.name();
if (displayedResource != null) {
groupName += " (" + displayedResource.getDisplayName() + ")";
}
Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
group.setLayout(new GridLayout(4, false));
group.setText(channel + ":");
group.setLayout(new GridLayout(1, false));
group.setText(groupName + ":");
group.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
final ColorMapSliderComp cmapSlider = new ColorMapSliderComp(group,
params);
cmapSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
((GridData) cmapSlider.getLayoutData()).widthHint = 450;
sliderComps.add(cmapSlider);
final Button invertBtn = new Button(group, SWT.CHECK);
invertBtn.addSelectionListener(new SelectionAdapter() {
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse
* .swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
data.invert = invertBtn.getSelection();
resource.issueRefresh();
}
});
if (data != null) {
invertBtn.setSelection(data.invert);
}
Label label = new Label(group, SWT.NONE);
label.setText("Invert");
final Combo options = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY);
options.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
options.setItems(items);
if (data == null) {
options.setText(DISABLED);
if (displayedResource == null) {
enable(group, false);
} else {
if (data.name == null) {
options.setText(DISABLED);
enable(cmapSlider, false);
} else {
options.setText(data.name);
}
options.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (DISABLED.equals(options.getText())) {
enable(cmapSlider, false);
data.name = null;
} else {
enable(cmapSlider, true);
data.name = options.getText();
}
capability.capabilityChanged();
}
});
}
}
@ -209,4 +182,28 @@ public class MultiChannelDialog extends CaveSWTDialog {
private void okPressed() {
close();
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.rsc.IDisposeListener#disposed(com.raytheon.uf
* .viz.core.rsc.AbstractVizResource)
*/
@Override
public void disposed(AbstractVizResource<?, ?> rsc) {
close();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.ui.dialogs.CaveSWTDialogBase#disposed()
*/
@Override
protected void disposed() {
super.disposed();
resource.unregisterListener(this);
}
}

View file

@ -17,7 +17,10 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.ui.cmenu;
package com.raytheon.uf.viz.truecolor.ui;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
@ -25,14 +28,11 @@ import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.IDisposeListener;
import com.raytheon.uf.viz.core.rsc.capabilities.MultiChannelCapability;
import com.raytheon.viz.ui.dialogs.MultiChannelDialog;
import com.raytheon.uf.viz.truecolor.rsc.TrueColorResourceGroup;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
/**
* Right click action that opens a dialog for modifying resources with
* MultiChannelCapability
* Action that opens the {@link TrueColorDialog}
*
* <pre>
*
@ -40,7 +40,7 @@ import com.raytheon.viz.ui.dialogs.MultiChannelDialog;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 3, 2012 mschenke Initial creation
* Aug 16, 2012 mschenke Initial creation
*
* </pre>
*
@ -48,7 +48,9 @@ import com.raytheon.viz.ui.dialogs.MultiChannelDialog;
* @version 1.0
*/
public class MultiChannelImagingAction extends AbstractRightClickAction {
public class TrueColorDialogAction extends AbstractRightClickAction {
private static Map<TrueColorResourceGroup, TrueColorDialog> dialogMap = new HashMap<TrueColorResourceGroup, TrueColorDialog>();
/*
* (non-Javadoc)
@ -57,7 +59,7 @@ public class MultiChannelImagingAction extends AbstractRightClickAction {
*/
@Override
public String getText() {
return "Channel Options...";
return "Composite Options...";
}
/*
@ -67,26 +69,22 @@ public class MultiChannelImagingAction extends AbstractRightClickAction {
*/
@Override
public void run() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell();
final AbstractVizResource<?, ?> rsc = getSelectedRsc();
MultiChannelCapability cap = rsc
.getCapability(MultiChannelCapability.class);
final MultiChannelDialog dialog = new MultiChannelDialog(shell, rsc,
cap);
final IDisposeListener listener = new IDisposeListener() {
@Override
public void disposed(AbstractVizResource<?, ?> rsc) {
dialog.close();
}
};
rsc.registerListener(listener);
dialog.addListener(SWT.Dispose, new Listener() {
@Override
public void handleEvent(Event event) {
rsc.unregisterListener(listener);
}
});
TrueColorResourceGroup resource = (TrueColorResourceGroup) getSelectedRsc();
TrueColorDialog dialog = dialogMap.get(resource);
if (dialog == null) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell();
dialog = new TrueColorDialog(shell, resource);
final TrueColorDialog toRemove = dialog;
dialogMap.put(resource, dialog);
dialog.addListener(SWT.Close, new Listener() {
@Override
public void handleEvent(Event event) {
dialogMap.remove(toRemove.resource);
}
});
}
dialog.open();
}
}

View file

@ -1,70 +0,0 @@
#include <colorUtil>
#include <indexing>
uniform float alpha;
uniform float brightness;
uniform float contrast;
uniform sampler2D rawTexR;
uniform float naturalMinR;
uniform float naturalMaxR;
uniform float cmapMinR;
uniform float cmapMaxR;
uniform int isFloatR;
uniform int invertR;
uniform int applyR;
uniform sampler2D rawTexG;
uniform float naturalMinG;
uniform float naturalMaxG;
uniform float cmapMinG;
uniform float cmapMaxG;
uniform int isFloatG;
uniform int invertG;
uniform int applyG;
uniform sampler2D rawTexB;
uniform float naturalMinB;
uniform float naturalMaxB;
uniform float cmapMinB;
uniform float cmapMaxB;
uniform int isFloatB;
uniform int invertB;
uniform int applyB;
float getIndex(sampler2D rawTex, float cmapMin, float cmapMax, float naturalMin, float naturalMax, int isFloat) {
vec4 textureValue = texture2D(rawTex, gl_TexCoord[0].st);
float naturalVal = textureValue.r;
if ( isFloat == 0 ) {
naturalVal = ((naturalVal * (naturalMax - naturalMin)) + naturalMin);
}
return findIndex(naturalVal, cmapMin, cmapMax);
}
void main(void) {
float r = 0.0;
float g = 0.0;
float b = 0.0;
if ( applyR != 0 ) {
r = getIndex(rawTexR, cmapMinR, cmapMaxR, naturalMinR, naturalMaxR, isFloatR);
if ( invertR != 0 ) {
r = 1.0 - r;
}
}
if ( applyG != 0 ) {
g = getIndex(rawTexG, cmapMinG, cmapMaxG, naturalMinG, naturalMaxG, isFloatG);
if ( invertG != 0 ) {
g = 1.0 - g;
}
}
if ( applyB != 0 ) {
b = getIndex(rawTexB, cmapMinB, cmapMaxB, naturalMinB, naturalMaxB, isFloatB);
if ( invertB != 0 ) {
b = 1.0 - b;
}
}
gl_FragColor = applyContrastAlphaBrightness(vec4(r,g,b,alpha), alpha, brightness, contrast);
}

View file

@ -53,9 +53,6 @@
<graphicsExtension
class="com.raytheon.viz.core.gl.internal.ext.GLDefaultImagingExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.viz.core.gl.internal.ext.GLMultiChannelImageExtension">
</graphicsExtension>
<graphicsExtension
class="com.raytheon.viz.core.gl.internal.ext.mosaic.GLMosaicImageExtension">
</graphicsExtension>

View file

@ -90,8 +90,7 @@ public abstract class AbstractGLImagingExtension extends
try {
gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);
rval = drawRastersInternal(paintProps, images);
gl.glPolygonMode(GL.GL_BACK, GL.GL_LINE);
gl.glDisable(GL.GL_BLEND);
disableBlending(gl);
} finally {
target.popGLState();
}
@ -159,14 +158,7 @@ public abstract class AbstractGLImagingExtension extends
program.startShader();
}
gl.glTexEnvi(GL.GL_TEXTURE_ENV,
GL.GL_TEXTURE_ENV_MODE, GL.GL_ADD);
gl.glEnable(GL.GL_BLEND);
gl.glTexEnvi(GL.GL_TEXTURE_ENV,
GL.GL_TEXTURE_ENV_MODE, GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA,
GL.GL_ONE_MINUS_SRC_ALPHA);
enableBlending(gl);
gl.glColor4f(0.0f, 0.0f, 0.0f,
paintProps.getAlpha());
}
@ -311,6 +303,27 @@ public abstract class AbstractGLImagingExtension extends
return PaintStatus.ERROR;
}
/**
* Function to enable blending for images
*
* @param gl
*/
protected void enableBlending(GL gl) {
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_ADD);
gl.glEnable(GL.GL_BLEND);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}
/**
* Function to disable blending for images
*
* @param gl
*/
protected void disableBlending(GL gl) {
gl.glDisable(GL.GL_BLEND);
}
/**
* Setup anything that is required pre image rendering. Object returned is a
* state object and will be passed in to postImageRender. If the image

View file

@ -209,7 +209,10 @@ public class GLShaderProgram {
* @param value
*/
private void setUniformInternal(String uniformName, Object value) {
if (value instanceof Float) {
if (value instanceof Double) {
gl.glUniform1f(getUniformLocation(uniformName),
((Double) value).floatValue());
} else if (value instanceof Float) {
gl.glUniform1f(getUniformLocation(uniformName), (Float) value);
} else if (value instanceof Integer) {
gl.glUniform1i(getUniformLocation(uniformName), (Integer) value);

View file

@ -74,6 +74,8 @@ public class GLProgramManager {
private final Map<String, File> programFiles = new HashMap<String, File>();
private final Map<String, Long> programFileModTimes = new HashMap<String, Long>();
private final IPathManager pm;
private GLProgramManager() {
@ -86,6 +88,7 @@ public class GLProgramManager {
File fileObj = file.getFile();
String name = fileObj.getName();
programFiles.put(name, fileObj);
programFileModTimes.put(name, fileObj.lastModified());
programsCode.put(name, readProgramContents(fileObj));
}
}
@ -107,9 +110,15 @@ public class GLProgramManager {
* @throws VizException
*/
public String getProgramCode(String aProgramName) throws VizException {
String fileName = aProgramName + GLSL_EXTENSION;
hasBeenModified(aProgramName);
return programsCode.get(fileName);
if (aProgramName.endsWith(GLSL_EXTENSION) == false) {
aProgramName += GLSL_EXTENSION;
}
if (hasBeenModified(aProgramName)) {
File programFile = programFiles.get(aProgramName);
programsCode.put(aProgramName, readProgramContents(programFile));
programFileModTimes.put(aProgramName, programFile.lastModified());
}
return programsCode.get(aProgramName);
}
/**
@ -119,9 +128,16 @@ public class GLProgramManager {
* @return
*/
public boolean hasBeenModified(String programName) {
// TODO: Check file modification time and reload contents. Should also
// check modification times of files depends on and reload if any
// changes
if (programName.endsWith(GLSL_EXTENSION) == false) {
programName += GLSL_EXTENSION;
}
File programFile = programFiles.get(programName);
if (programFile != null) {
long lastMod = programFileModTimes.get(programName);
if (lastMod != programFile.lastModified()) {
return true;
}
}
return false;
}

View file

@ -1,113 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.core.gl.images;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.ChannelData;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.IImageChannel;
import com.raytheon.viz.core.gl.internal.ext.GLMultiChannelImageExtension;
/**
* GL implementation of {@link IImageChannel}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 9, 2012 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class GLImageChannel extends GLDelegateImage<GLColormappedImage>
implements IImageChannel {
private ChannelData channelData;
/**
* @param target
* @param image
* @param extensionClass
*/
public GLImageChannel(GLColormappedImage image, ChannelData channelData) {
super(image, GLMultiChannelImageExtension.class);
this.channelData = channelData;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.IColormappedImage#getColorMapParameters
* ()
*/
@Override
public ColorMapParameters getColorMapParameters() {
return image.getColorMapParameters();
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.IColormappedImage#setColorMapParameters
* (com.raytheon.uf.viz.core.drawables.ColorMapParameters)
*/
@Override
public void setColorMapParameters(ColorMapParameters params) {
image.setColorMapParameters(params);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IColormappedImage#getValue(int,
* int)
*/
@Override
public double getValue(int x, int y) {
return image.getValue(x, y);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension
* .IChannelImage#setInvert(boolean)
*/
@Override
public void setInverted(boolean inverted) {
channelData.invert = inverted;
}
/**
* @return the invert
*/
public boolean isInverted() {
return channelData.invert;
}
}

View file

@ -1,262 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.core.gl.images;
import java.util.Map;
import javax.media.opengl.GL;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.Channel;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.IImageChannel;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension.IMultiChannelImage;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.core.gl.IGLTarget;
import com.raytheon.viz.core.gl.internal.ext.GLMultiChannelImageExtension;
import com.sun.opengl.util.texture.TextureCoords;
/**
* GL implementation of a multi channel image
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 19, 2011 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class GLMultiChannelImage extends AbstractGLImage implements
IMultiChannelImage {
private Map<Channel, IImageChannel> channelMap;
/**
* @param target
* @param extensionClass
*/
public GLMultiChannelImage(IGLTarget target,
Map<Channel, IImageChannel> channelMap) {
super(GLMultiChannelImageExtension.class);
this.channelMap = channelMap;
}
/**
* Get the first IColormappedImage in the map
*
* @return first image in the map or null if none
*/
private IColormappedImage getFirstImage() {
if (channelMap != null) {
for (IColormappedImage image : channelMap.values()) {
if (image != null) {
return image;
}
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.images.AbstractGLImage#setInterpolated(boolean)
*/
@Override
public void setInterpolated(boolean isInterpolated) {
super.setInterpolated(isInterpolated);
for (IColormappedImage image : channelMap.values()) {
((AbstractGLImage) image).setInterpolated(isInterpolated);
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IImage#getWidth()
*/
@Override
public int getWidth() {
IColormappedImage image = getFirstImage();
if (image != null) {
return image.getWidth();
}
return 0;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.core.drawables.IImage#getHeight()
*/
@Override
public int getHeight() {
IColormappedImage image = getFirstImage();
if (image != null) {
return image.getHeight();
}
return 0;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension
* .IMultiChannelImage#getImageMapping()
*/
@Override
public Map<Channel, IImageChannel> getImageMapping() {
return channelMap;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension
* .IMultiChannelImage#setImageMapping(java.util.Map)
*/
@Override
public void setImageMapping(Map<Channel, IImageChannel> mapping) {
this.channelMap = mapping;
// Set ourselves as unloaded since we are updating the mapping
setStatus(Status.UNLOADED);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#getTextureCoords()
*/
@Override
public TextureCoords getTextureCoords() {
return new TextureCoords(0, 1, 1, 0);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#getTextureid()
*/
@Override
public int getTextureid() {
// We do not have a single textureid specifically
return 0;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.images.AbstractGLImage#getTextureStorageType()
*/
@Override
public int getTextureStorageType() {
AbstractGLImage image = (AbstractGLImage) getFirstImage();
return image.getTextureStorageType();
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#stage()
*/
@Override
public boolean stageTexture() throws VizException {
boolean rval = false;
if (channelMap.size() > 0) {
rval = true;
for (IColormappedImage image : channelMap.values()) {
AbstractGLImage glImage = (AbstractGLImage) image;
glImage.stage();
if (glImage.getStatus() == Status.FAILED) {
rval = false;
}
}
}
return rval;
}
@Override
public void loadTexture(GL gl) throws VizException {
if (channelMap.size() > 0) {
Status status = Status.LOADED;
for (IColormappedImage image : channelMap.values()) {
AbstractGLImage glImage = (AbstractGLImage) image;
glImage.loadTexture(gl);
if (glImage.getStatus() == Status.FAILED) {
status = Status.FAILED;
}
}
setStatus(status);
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#dispose()
*/
@Override
public void dispose() {
for (IColormappedImage image : channelMap.values()) {
((AbstractGLImage) image).dispose();
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#bind()
*/
@Override
public boolean bind(GL gl) {
return true;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#bind(int)
*/
@Override
public boolean bind(GL gl, int texture) {
return true;
}
/*
* (non-Javadoc)
*
* @see com.raytheon.viz.core.gl.images.AbstractGLImage#usaAsFrameBuffer()
*/
@Override
public void usaAsFrameBuffer() throws VizException {
throw new VizException(
"Using a GLMultiChannelImage as a frame buffer is not supported");
}
}

View file

@ -1,184 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.core.gl.internal.ext;
import java.util.Map;
import javax.media.opengl.GL;
import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
import com.raytheon.uf.viz.core.drawables.IColormappedImage;
import com.raytheon.uf.viz.core.drawables.IImage;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension;
import com.raytheon.viz.core.gl.glsl.GLShaderProgram;
import com.raytheon.viz.core.gl.images.GLImageChannel;
import com.raytheon.viz.core.gl.images.GLMultiChannelImage;
/**
* GL implementation of {@link IMultiChannelImageExtension}
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 19, 2011 mschenke Initial creation
*
* </pre>
*
* @author mschenke
* @version 1.0
*/
public class GLMultiChannelImageExtension extends AbstractGLSLImagingExtension
implements IMultiChannelImageExtension {
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension
* #constructImage(java.util.Map)
*/
@Override
public IMultiChannelImage constructImage(
Map<Channel, IImageChannel> imageMapping) throws VizException {
return new GLMultiChannelImage(target, imageMapping);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.core.drawables.ext.colormap.IMultiChannelImageExtension
* #
* constructImage(com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback
* , com.raytheon.uf.viz.core.drawables.ColorMapParameters)
*/
@Override
public IImageChannel constructImage(
IColorMapDataRetrievalCallback callback, ChannelData channelData)
throws VizException {
return new GLImageChannel(target.getExtension(
GLColormappedImageExtension.class).initializeRaster(callback,
channelData.parameters), channelData);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#getShaderProgramName
* ()
*/
@Override
public String getShaderProgramName() {
return "multichannel";
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.viz.core.gl.ext.AbstractGLImagingExtension#loadShaderData
* (com.raytheon.viz.core.gl.glsl.GLShaderProgram,
* com.raytheon.uf.viz.core.drawables.IImage,
* com.raytheon.uf.viz.core.drawables.PaintProperties)
*/
@Override
public void loadShaderData(GLShaderProgram program, IImage image,
PaintProperties paintProps) throws VizException {
GLMultiChannelImage glImage = null;
if (image instanceof GLMultiChannelImage == false) {
throw new VizException(
"Cannot apply glsl multichannel shader to non gl multichannel image");
}
glImage = (GLMultiChannelImage) image;
Map<Channel, IImageChannel> channelMap = glImage.getImageMapping();
program.setUniform("brightness", glImage.getBrightness());
program.setUniform("contrast", glImage.getContrast());
program.setUniform("alpha", paintProps.getAlpha());
for (Channel c : Channel.values()) {
String suffix = "";
int texture = -1;
int texNum = -1;
switch (c) {
case RED:
suffix = "R";
texture = GL.GL_TEXTURE0;
texNum = 0;
break;
case GREEN:
suffix = "G";
texture = GL.GL_TEXTURE1;
texNum = 1;
break;
case BLUE:
suffix = "B";
texture = GL.GL_TEXTURE2;
texNum = 2;
break;
}
boolean applied = false;
IColormappedImage ci = channelMap.get(c);
if (ci != null) {
if (ci instanceof GLImageChannel == false) {
throw new VizException(
"Cannot apply glsl multichannel shader to non gl colormapped image");
}
GLImageChannel glCMImage = (GLImageChannel) ci;
if (glCMImage.bind(target.getGl(), texture)) {
int textureType = glCMImage.getWrappedImage()
.getTextureType();
ColorMapParameters colorMapParameters = ci
.getColorMapParameters();
program.setUniform("rawTex" + suffix, texNum);
program.setUniform("naturalMin" + suffix,
colorMapParameters.getDataMin());
program.setUniform("naturalMax" + suffix,
colorMapParameters.getDataMax());
program.setUniform("cmapMin" + suffix,
colorMapParameters.getColorMapMin());
program.setUniform("cmapMax" + suffix,
colorMapParameters.getColorMapMax());
program.setUniform("isFloat" + suffix,
textureType == GL.GL_FLOAT
|| textureType == GL.GL_HALF_FLOAT_ARB ? 1
: 0);
program.setUniform("invert" + suffix,
glCMImage.isInverted());
applied = true;
}
}
program.setUniform("apply" + suffix, applied ? 1 : 0);
}
}
}

View file

@ -27,12 +27,17 @@
</extension>
<extension point="org.eclipse.core.expressions.definitions">
<definition id="com.raytheon.viz.gfe.inGFEActionSet">
<with variable="activeContexts">
<iterate operator="or">
<equals value="com.raytheon.viz.gfe.GFEActionSet">
</equals>
</iterate>
</with>
<and>
<with variable="activeContexts">
<iterate operator="or">
<equals value="com.raytheon.viz.gfe.GFEActionSet">
</equals>
</iterate>
</with>
<with variable="activeEditor">
<instanceof value="com.raytheon.uf.viz.core.IDisplayPaneContainer"/>
</with>
</and>
</definition>
</extension>
<extension point="org.eclipse.ui.commands">

View file

@ -407,9 +407,11 @@ public class ReferenceSetManager implements IReferenceSetManager,
areas.add(areaName);
}
}
Collections.sort(areas);
return areas;
}
@Override
public void saveGroup(String groupName, List<String> areaNames) {
statusHandler.handle(Priority.VERBOSE, "Save Edit Area Group: "
+ groupName + " areas:" + areaNames);
@ -469,6 +471,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
}
}
@Override
public void deleteGroup(String groupName) {
IPathManager pm = PathManagerFactory.getPathManager();
@ -545,7 +548,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
refDataCache.remove(add.getName());
}
}
/**
* Constructor for ReferenceSet taking a pointer to the Data Manager
*
@ -655,6 +658,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* @see
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#getActiveRefSet()
*/
@Override
public ReferenceData getActiveRefSet() {
return new ReferenceData(activeRefSet);
}
@ -666,6 +670,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#setActiveRefSet
* (com.raytheon.edex.plugin.gfe.reference.ReferenceData)
*/
@Override
public void setActiveRefSet(final ReferenceData refData) {
refData.getGrid(); // force it to a grid
@ -706,6 +711,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#getAvailableSets
* ()
*/
@Override
public List<ReferenceID> getAvailableSets() {
return Collections.unmodifiableList(availableSets);
}
@ -716,6 +722,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* @see
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#emptyRefSet()
*/
@Override
public ReferenceData emptyRefSet() {
return EMPTY;
}
@ -725,6 +732,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
*
* @see com.raytheon.viz.gfe.core.internal.IReferenceSetManager#fullRefSet()
*/
@Override
public ReferenceData fullRefSet() {
return FULL;
}
@ -736,6 +744,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#loadRefSet(com
* .raytheon.edex.plugin.gfe.reference.ReferenceID)
*/
@Override
public ReferenceData loadRefSet(final ReferenceID refSetID) {
// UFStatus.handle(Priority.VERBOSE, Activator.PLUGIN_ID,
// StatusConstants.CATEGORY_GFE, null, "LoadRefSet: " + refSetID);
@ -789,6 +798,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* the referenceIDs
* @return a List of ReferenceData
*/
@Override
public List<ReferenceData> getReferenceData(List<ReferenceID> need) {
List<ReferenceData> refData = new ArrayList<ReferenceData>();
for (int i = 0; i < need.size(); i++) {
@ -804,6 +814,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#saveActiveRefSet
* (com.raytheon.edex.plugin.gfe.reference.ReferenceID)
*/
@Override
public boolean saveActiveRefSet(final ReferenceID refID) {
statusHandler.handle(Priority.VERBOSE, "saveActiveRefSet req=" + refID);
@ -832,6 +843,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#saveRefSet(com
* .raytheon.edex.plugin.gfe.reference.ReferenceData)
*/
@Override
public boolean saveRefSet(final ReferenceData orefData) {
statusHandler.handle(Priority.VERBOSE,
"SaveRefSet id=" + orefData.getId());
@ -867,9 +879,9 @@ public class ReferenceSetManager implements IReferenceSetManager,
"Unable to save reference set", e));
return false;
}
// cache it temporarily
refDataCache.put(refData.getId().getName(), refData);
refDataCache.put(refData.getId().getName(), refData);
return true;
}
@ -881,6 +893,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#deleteRefSet(
* com.raytheon.edex.plugin.gfe.reference.ReferenceID)
*/
@Override
public boolean deleteRefSet(final ReferenceID refID,
boolean withVerification) {
IPathManager pm = PathManagerFactory.getPathManager();
@ -911,6 +924,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
*
* @see com.raytheon.viz.gfe.core.internal.IReferenceSetManager#undoRefSet()
*/
@Override
public void undoRefSet() {
ReferenceData newRefSet = prevRefSet;
setActiveRefSet(newRefSet);
@ -1020,6 +1034,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#taperGrid(com
* .raytheon.edex.plugin.gfe.reference.ReferenceData, int)
*/
@Override
public Grid2DFloat taperGrid(final ReferenceData refData, int taperFactor) {
// Get some info and make a grid of zeros
@ -1106,6 +1121,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#directionTaperGrid
* (com.raytheon.edex.plugin.gfe.reference.ReferenceData, java.lang.String)
*/
@Override
public Grid2DFloat directionTaperGrid(final ReferenceData refData,
final String direction) {
@ -1230,6 +1246,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#mySiteGridpoints
* ()
*/
@Override
public Grid2DBit mySiteGridpoints() {
return siteGridpoints(Arrays.asList(dataManager.getSiteID()), true);
}
@ -1263,6 +1280,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
*
* @see com.raytheon.viz.gfe.core.internal.IReferenceSetManager#getMode()
*/
@Override
public RefSetMode getMode() {
return mode;
}
@ -1274,6 +1292,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* com.raytheon.viz.gfe.core.internal.IReferenceSetManager#setMode(com.raytheon
* .viz.gfe.core.internal.ReferenceSetManager.RefSetMode)
*/
@Override
public void setMode(RefSetMode mode) {
this.mode = mode;
}
@ -1514,6 +1533,7 @@ public class ReferenceSetManager implements IReferenceSetManager,
* @param slot
* @return the quickset area
*/
@Override
public ReferenceData getQuickSet(int slot) {
// Return the ReferenceData contents of the given quickSet button
ReferenceData result = emptyRefSet();

View file

@ -62,8 +62,8 @@ public class ProcedureFactory {
GfePyIncludeUtil.getCommonPythonIncludePath(),
GfePyIncludeUtil.getVtecIncludePath(),
GfePyIncludeUtil.getCommonGfeIncludePath(),
GfePyIncludeUtil.getUtilitiesIncludePath(),
GfePyIncludeUtil.getProceduresIncludePath());
GfePyIncludeUtil.getProceduresIncludePath(),
GfePyIncludeUtil.getUtilitiesIncludePath());
ProcedureController procCont = null;
if (ui) {

View file

@ -19,10 +19,6 @@
**/
package com.raytheon.viz.gfe.procedures.menu;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
/**
* Specific contribution item for contributing procedures to the Hazards menu
*
@ -62,18 +58,4 @@ public class HazardsItems extends AbstractProcedureMenuItems {
return "Hazards";
}
/*
* (non-Javadoc)
*
* @seecom.raytheon.viz.gfe.procedures.menu.AbstractProcedureMenuItems#
* getAdditionalItems()
*/
@Override
protected CommandContributionItemParameter[] getAdditionalItems() {
return new CommandContributionItemParameter[] { new CommandContributionItemParameter(
PlatformUI.getWorkbench(), getId(),
"com.raytheon.viz.ghg.openmakehazards", null, null, null, null,
"MakeHazard", null, null, CommandContributionItem.STYLE_PUSH,
null, true) };
}
}

View file

@ -63,8 +63,8 @@ public class SmartToolFactory {
GfePyIncludeUtil.getCommonPythonIncludePath(),
GfePyIncludeUtil.getVtecIncludePath(),
GfePyIncludeUtil.getCommonGfeIncludePath(),
GfePyIncludeUtil.getUtilitiesIncludePath(),
GfePyIncludeUtil.getSmartToolsIncludePath());
GfePyIncludeUtil.getSmartToolsIncludePath(),
GfePyIncludeUtil.getUtilitiesIncludePath());
SmartToolController smartCont = null;
if (ui) {

View file

@ -26,10 +26,6 @@
id="com.raytheon.viz.ghg.openGhgMonitor"
name="GHGHazardsMonnitor">
</command>
<command
id="com.raytheon.viz.ghg.openmakehazards"
name="MakeHazards">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
@ -37,9 +33,5 @@
class="com.raytheon.viz.ghg.GhgMonitorAction"
commandId="com.raytheon.viz.ghg.openGhgMonitor">
</handler>
<handler
class="com.raytheon.viz.ghg.MakeHazardsAction"
commandId="com.raytheon.viz.ghg.openmakehazards">
</handler>
</extension>
</plugin>

View file

@ -1,4 +0,0 @@
scriptName=ghg/userPython/MakeHazard.py
tcmScriptName=ghg/userPython/TCMETNDecoder.py
hazardDict=gfe/userPython/procedures/MakeHazardConfig.py
includePath=gfe/userPython/utilities/SmartScript.py:python/gfe/AbsTime.py:python/BaseTool.py:python/JUtil.py:gfe/userPython/textUtilities/regular:vtec/VTECTable.py

View file

@ -1,5 +1,4 @@
com.raytheon.viz.satellite.rsc.SatResourceData
com.raytheon.viz.satellite.rsc.SatBlendedResourceData
com.raytheon.viz.satellite.rsc.SatBestResResourceData
com.raytheon.viz.satellite.rsc.SatTrueColorResourceData
com.raytheon.viz.satellite.SatelliteProductBrowserDataDefinition

View file

@ -31,11 +31,6 @@
class="com.raytheon.viz.satellite.rsc.SatBlendedResource"
name="satBlendedResource"
renderingOrderId="IMAGE_COUNTRY"/>
<resource
class="com.raytheon.viz.satellite.rsc.SatTrueColorResource"
name="Satellite True Color"
renderingOrderId="IMAGE_COUNTRY"
resourceType="PLAN_VIEW"/>
</extension>
<extension
point="com.raytheon.uf.viz.core.scriptTemplate">

Some files were not shown because too many files have changed in this diff Show more