Merge tag 'OB_16.1.2-7' into omaha_16.1.2

16.1.2-7


Former-commit-id: 8c26046f62847ee6af14bad3953ab71ecc152621
This commit is contained in:
Steve Harris 2016-01-04 16:04:52 -06:00
commit 13906ed6ed
56 changed files with 3173 additions and 705 deletions

View file

@ -20,6 +20,7 @@
package com.raytheon.rcm.server.dataarchive;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -682,14 +683,14 @@ public class DataArchiveEndpoint extends RadarEventAdapter {
if (pdb.isBzip2Compressed()) {
int uncompressedSize = pdb.getUncompressedSize();
byte[] uncompressed;
try {
InputStream ins = new ByteArrayInputStream(msg, 120,
msg.length - 120);
ins = new BZip2InputStream(ins, false);
try (DataInputStream di = new DataInputStream(
new BZip2InputStream(
new ByteArrayInputStream(msg,
120, msg.length - 120), false))) {
// ByteArrayOutputStream outs = new
// ByteArrayOutputStream(uncompressedSize);
uncompressed = new byte[uncompressedSize];
ins.read(uncompressed);
di.readFully(uncompressed);
} catch (IOException e) {
Log.errorf("Error decompressing product: %s", e);
return msg;

View file

@ -93,7 +93,7 @@ if [ $? -ne 0 ]; then
fi
export apps_dir=${HYDRO_APPS_DIR}
SWITCHES=()
SWITCHES=($SWITCHES)
TESTCHECK="$TMCP_HOME/bin/getTestMode"
if [ -x ${TESTCHECK} ]; then
echo "Calling getTestMode()"

View file

@ -89,6 +89,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* 10/15/2012 1229 rferrel Changes for non-blocking HelpUsageDlg.
* 16 Aug 2013 #2256 lvenable Fixed image and cursor memory leaks.
* 19Mar2014 #2925 lvenable Added dispose checks for runAsync.
* 12/22/2015 18342 zhao Modified code for 'jnt' in objReceived()
*
* </pre>
*
@ -886,7 +887,7 @@ public class CigVisDistributionDlg extends CaveSWTDialog implements
int flightCat = (Integer) list.get(3);
float cig = (Float) list.get(4);
float vis = (Float) list.get(5);
float jnt = Math.min(cig, vis);
float jnt = (Float) list.get(6);
data.set(month, hour, windDir, flightCat, vis, cig, jnt);
} else {

View file

@ -34,6 +34,7 @@
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# Jul 07, 2015 16907 zhao Modified to work with new ids- files
# Dec 22, 2015 18341 zhao Modified __writeHDFData to avoid 'bad' input
import sys
sys.argv = [__name__]
@ -465,6 +466,8 @@ required NCDC data.
shape = f_col.descr._v_colObjects[col].shape[0] - 1
#datum = datum + [self.__get_msng(f_col.type)]*(f_col.shape[0]-len(datum))
datum = datum + [self.__get_msng(f_col.type)] * (f_col.descr._v_colObjects[col].shape[0] - len(datum))
if len(numpy.array(datum)) != len(row[col]):
continue
row[col] = numpy.array(datum).astype(f_col.type)
except Exception, e:
self.__updateMonitor(str(e) + '\n')

View file

@ -43,6 +43,10 @@
# Generates ceiling/visibility distribution by month, hour and wind direction
# George Trojan, SAIC/MDL, December 2005
# last update: 03/14/06
# Date Ticket# Engineer Description
# ------------ ---------- ----------- -----------------------------------
# Dec 22, 2015 18342 zhao Modified _process() to also pass 'jnt_count'
import logging, os, time, cPickle
import Avn, ClimLib
@ -174,7 +178,7 @@ def get_data(table, queue):
for windDir in range(num_wind_dir):
for flightCat in range(num_cat+1):
sendObj = [month, hour, windDir, flightCat, float(cig_count[month][hour][windDir][flightCat]),
float(vis_count[month][hour][windDir][flightCat])]#, float(jnt_count[month][hour][windDir][flightCat])]
float(vis_count[month][hour][windDir][flightCat]), float(jnt_count[month][hour][windDir][flightCat])]
#print "sendObj", sendObj
queue.put(sendObj)
queue.put("done")

View file

@ -66,6 +66,7 @@ Import-Package: com.raytheon.uf.common.dissemination,
com.raytheon.uf.viz.python.swt,
com.raytheon.uf.viz.python.swt.widgets,
com.raytheon.uf.viz.ui.menus.widgets.tearoff,
com.raytheon.viz.core.gl,
com.raytheon.viz.texteditor.util,
com.raytheon.viz.ui.tools.map,
org.apache.commons.logging,

View file

@ -5,7 +5,8 @@
#
# CopyNHCProposed
#
# Author:
# Author: T LeFebvre/P. Santos
# Last Modified: Dec 10, 2015 for 16.1.2
# ----------------------------------------------------------------------------
# The MenuItems list defines the GFE menu item(s) under which the
@ -25,37 +26,62 @@ ToolList = []
## cover all the variables necessary for the tools.
import SmartScript
from numpy import *
import TimeRange
import AbsTime
import time, re
try:
from Numeric import *
except:
from numpy import *
import GridManipulation
## For documentation on the available commands,
## see the SmartScript Utility, which can be viewed from
## the Edit Actions Dialog Utilities window
VariableList = [("Choose Hazards:" , "", "check",
# ["ProposedSS", "ProposedWW1", "ProposedWW2"]),
["ProposedSS"]),
Supported_elements=["ProposedSS"]
VariableList = [("Choose Hazards:" , ["ProposedSS"], "check", Supported_elements),
# ["ProposedSS"]),
]
class Procedure (GridManipulation.GridManipulation, SmartScript.SmartScript):
class Procedure (SmartScript.SmartScript):
def __init__(self, dbss):
GridManipulation.GridManipulation.__init__(self)
SmartScript.SmartScript.__init__(self, dbss)
# Makes a timeRange based on the specified start and end times.
# If no times are specified, returns the largest timeRange possible.
# This method will work in either an AWIPS I or AWIPS II environment.
def makeTimeRange(self, start=0, end=0):
if start == 0 and end == 0:
return TimeRange.allTimes()
startTime = AbsTime.AbsTime(start)
endTime = AbsTime.AbsTime(end)
tr = TimeRange.TimeRange(startTime, endTime)
return tr
def makeNewTimeRange(self, hours):
startTime = int(time.time() / 3600) * 3600
endTime = startTime + hours * 3600
timeRange = self.GM_makeTimeRange(startTime, endTime)
timeRange = self.makeTimeRange(startTime, endTime)
return timeRange
def getWEInventory(self, modelName, WEName, timeRange=None):
if timeRange is None:
timeRange = self.makeTimeRange()
gridInfo = self.getGridInfo(modelName, WEName, "SFC", timeRange)
trList = []
for g in gridInfo:
start = g.gridTime().startTime().unixTime()
end = g.gridTime().endTime().unixTime()
tr = self.makeTimeRange(start, end)
trList.append(tr)
return trList
def execute(self, varDict):
# Assign a timeRange from now to 48 hours from now
@ -69,7 +95,6 @@ class Procedure (GridManipulation.GridManipulation, SmartScript.SmartScript):
self.statusBarMsg("You must choose at least one hazard.", "U")
return
#weNames = ["ProposedSS", "ProposedWW1", "ProposedWW2"]
weNames = ["ProposedSS"]
# Remove any pre-existing grids first
@ -78,7 +103,7 @@ class Procedure (GridManipulation.GridManipulation, SmartScript.SmartScript):
if weName not in hazardsToCopy:
continue
trList = self.GM_getWEInventory(weName)
trList = self.getWEInventory("Fcst", weName)
for delTR in trList:
self.deleteGrid("Fcst", weName, "SFC", delTR)
@ -89,16 +114,21 @@ class Procedure (GridManipulation.GridManipulation, SmartScript.SmartScript):
continue
iscWeName = weName + "nc"
trList = self.GM_getWEInventory(iscWeName, "ISC", timeRange)
trList = self.getWEInventory("ISC", iscWeName, timeRange)
if len(trList) == 0:
continue
gridTR = trList[-1] # only interested in the latest grid
iscGrid, iscKeys = self.getGrids("ISC", iscWeName, "SFC", gridTR)
start = gridTR.endTime().unixTime() - (48 * 3600)
end = gridTR.endTime().unixTime()
createTR = self.makeTimeRange(start, end)
self.createGrid("Fcst", weName, "DISCRETE", (iscGrid, iscKeys),
timeRange, discreteKeys=iscKeys, discreteOverlap=0,
createTR, discreteKeys=iscKeys, discreteOverlap=0,
#trList, discreteKeys=iscKeys, discreteOverlap=0,
discreteAuxDataLength=0, defaultColorTable="StormSurgeHazards")

View file

@ -13,7 +13,10 @@
# in getQPFGrid method. Also in AWIPS 2 FFG is gridded and called just FFG.
# This is fixed in getRFCFFGModels method.
#
# LeFevbre/Santos: This is the version being turned in for baseline as of 10/20/2014
# LeFevbre/Santos: This is the version being turned in for baseline in 16.1.2 as of 12/7/2015. It includes fixes
#for new ERP data changes that took place in Summer of 2015 and better handling of grid points where there
#is no FFG guidance available.
#
#Search for COMMENTS to see any local config step you might need to take.
# ----------------------------------------------------------------------------
@ -88,10 +91,12 @@ class Procedure (SmartScript.SmartScript):
# get the current time, truncates to the last six hour value.
# returns a timeRange with this startTime until 72 hrs from this time
def make72hrTimeRange(self):
cTime = int(self._gmtime().unixTime()/ (3600 * 6)) * (3600 * 6)
startTime = AbsTime.AbsTime(cTime)
end = cTime + (3600 * 24 * 3)
def make72hrTimeRange(self, startTime):
# Make the end time 3 days from the startTime
end = startTime + (72 * 3600)
# Convert them to AbsTimes
startTime = AbsTime.AbsTime(startTime)
endTime = AbsTime.AbsTime(end)
timeRange = TimeRange.TimeRange(startTime, endTime)
@ -118,11 +123,11 @@ class Procedure (SmartScript.SmartScript):
availParms = self.availableParms()
for pName, level, dbID in availParms:
if dbID.modelName().find(modelName) > -1:
if pName.find(weName) > -1:
if level.find(weLevel) > -1:
if modelName in dbID.modelName():
if weName in pName:
if weLevel in level:
if dbID.modelIdentifier() not in modelList:
modelList.append(dbID.modelIdentifier())
modelList.append(dbID)
return modelList
# A small algorithm to determine the day number
@ -137,23 +142,33 @@ class Procedure (SmartScript.SmartScript):
return 3
return 0
def getModelTime(self, modelName):
timeStr = modelName[-13:]
year = int(timeStr[0:4])
month = int(timeStr[4:6])
day = int(timeStr[6:8])
hour = int(timeStr[9:11])
absTime = AbsTime.absTimeYMD(year, month, day, hour, 0, 0)
return absTime.unixTime()
def baseModelTime(self, modelTime):
oneDay = 3600 * 24
halfDay = 3600 * 12
baseTime = (int((modelTime + halfDay) / oneDay) * oneDay) - halfDay
return baseTime
def getLatestERPAnchorTime(self):
ERPModelName = "HPCERP"
ERPVarName = "ppffg" # This variable commented out
ERPLevel = "SFC"
# get the list of all available models. They come sorted latest to oldest.
modelList = self.getModelList(ERPModelName, ERPVarName, ERPLevel)
if len(modelList) > 0:
anchorTime = self.baseModelTime(modelList[0].modelTime().unixTime())
return anchorTime
self.statusBarMsg("No ERP Guidance found.", "S")
return None
def getERPGrids(self):
ERPModelName = "HPCERP"
ERPVarName = "ppffg"
ERPVarName = "ppffg"
ERPLevel = "SFC"
# make a dict and fill with grids with the default value.
@ -162,28 +177,57 @@ class Procedure (SmartScript.SmartScript):
for i in range(1, 4):
gridDict[i] = None
# get the list of all available models
# get the list of all available models. They come sorted latest to oldest.
modelList = self.getModelList(ERPModelName, ERPVarName, ERPLevel)
modelList.sort() # sort oldest to latest
# for each available model, fetch all the grids
# Debug output. Remove after testing
# print "ERP models available:"
# for m in modelList:
# print m, "baseTime:", time.asctime(time.gmtime(self.baseModelTime(m.modelTime().unixTime())))
# Calculate the nominal time we're searching for based on the latest model
anchorTime = self.baseModelTime(modelList[0].modelTime().unixTime())
# Debug output. Remove after testing
#print "anchorTime:", time.asctime(time.gmtime(anchorTime))
# keep only the most recent grids
for model in modelList:
# Only process models with a base time matching the latest base time. Ignore all others.
# This will cause the tool to abort if all the current grids are not yet in.
if self.baseModelTime(model.modelTime().unixTime()) != anchorTime:
# Debug output. remove after testing
print "Ignoring model at:", time.asctime(time.gmtime(model.modelTime().unixTime()))
continue
trList = self.getWEInventory(model, ERPVarName)
modelTime = self.getModelTime(model)
modelTime = model.modelTime()
for tr in trList:
dayNum = self.determineDay(modelTime,
tr.startTime().unixTime())
grid = self.getGrids(model, ERPVarName, ERPLevel, tr,
mode="First")
gridDict[dayNum] = grid
dayNum = self.determineDay(anchorTime, tr.startTime().unixTime())
grid = self.getGrids(model, ERPVarName, ERPLevel, tr, mode="First")
if gridDict[dayNum] is None:
gridDict[dayNum] = grid
print "modelTime and dayNum are: ", modelTime, dayNum
# Check to see if we found all the grids we need
allGridsFound = True
for dayNum in range(1, 4):
if gridDict[dayNum] is None:
allGridsFound = False
# We found all the grids, return them
if allGridsFound:
return gridDict
# After processing all the models, make sure we found all the grids we need.
for i in range(1, 4):
if gridDict[i] == None:
errorStr = "Day" + str(i) + " grid not found in AWIPS database."
self.statusBarMsg(errorStr, "S")
return None
return gridDict
# Use this method for testing if you have no luck getting products
@ -242,7 +286,7 @@ class Procedure (SmartScript.SmartScript):
for model in modelList:
# WARNING!!! This check should be more specific to the DBID string.
if model.find(rfcName) > -1:
if model.modelIdentifier().find(rfcName) > -1:
return model
return None
@ -456,10 +500,12 @@ class Procedure (SmartScript.SmartScript):
] # low ------ QPF/FFG ratio -------->high
# COMMENTS: The list of FFG products that contain FFG data for your WFO
# The following is set up for testing only. Please change these
# entries for your particular office.
# productList = ["FFGSHV", "FFGALR"]
productList = ["ATLFFGMFL", "ATLFFGTBW", "ATLFFGMLB"]
# The following is an example for Miami. Default list is emply. You must
# populate it with your CWA FFG guidance.
#productList = ["ATLFFGMFL", "ATLFFGTBW", "ATLFFGMLB","ATLFFGKEY"]
productList = []
if len(productList) == 0:
self.statusBarMsg("You have not configured Text FFG in Procedure. Create a site level copy, and configure your text FFG Guidance. Search for COMMENTS in the procedure.", "S")
### END CONFIGURATION SECTION #################################
@ -479,8 +525,13 @@ class Procedure (SmartScript.SmartScript):
threatMatrix[i][j] = "Elevated"
# make a 72 hour timeRange and a list of 6 hour timeRanges
timeRange = self.make72hrTimeRange()
# Find the nominal start time when we will be making grids
anchorTime = self.getLatestERPAnchorTime()
# make a 72 hour timeRange and a list of 6 hour timeRanges based on the anchorTime
timeRange = self.make72hrTimeRange(anchorTime)
print "Anchor TimeRange:", timeRange
trList = self.makeTimeRangeList(timeRange, 6)
@ -491,11 +542,17 @@ class Procedure (SmartScript.SmartScript):
#print "Getting FFG Grid Now: "
ffgGrid = self.getRFCFlashFloodGrid(productList,varDict)
#print "GOT FFG Grid"
ffgGrid = where(less(ffgGrid, 0.0), 0.0, ffgGrid)
# calculate the areas where the FFG is missing. We will fill these values with None eventually
missingFFGMask = less_equal(ffgGrid, 0.0)
# get the ERP grids and stuff them in six hour time blocks to match
# the cummulative QPF grids will create later
erpGridDict = self.getERPGrids()
if erpGridDict is None: # We're in that window where we should wait.
self.statusBarMsg("The current ERP guidance is not yet completely available. Please re-run this tool at a later time.", "S")
return
for i in range(len(trList)):
@ -518,6 +575,10 @@ class Procedure (SmartScript.SmartScript):
tempffgGrid = where(equal(ffgGrid, 0.0), 1000.0, ffgGrid)
ratioGrid = qpfGrid / tempffgGrid
ratioGrid = where(equal(ffgGrid, 0.0), 0.0, ratioGrid)
# Clip the ratioGrid to 8.0 to prevent problems when displaying
ratioGrid.clip(0.0, 8.0, ratioGrid)
self.createGrid("Fcst", "ERP", "SCALAR", erpGrid, tr,
minAllowedValue = -1, maxAllowedValue=100,
precision=2)
@ -543,7 +604,12 @@ class Procedure (SmartScript.SmartScript):
mask = logical_and(ratioMask, erpMask)
keyIndex = self.getIndex(threatMatrix[r][e], threatKeys)
floodThreat = where(mask, keyIndex, floodThreat)
# Now set the values we found missing to the None key
noneIndex = self.getIndex("None", threatKeys)
floodThreat[missingFFGMask] = noneIndex
# Create the grid
self.createGrid("Fcst", "FloodThreat", "DISCRETE",
(floodThreat, threatKeys), tr,
discreteKeys=threatKeys,

View file

@ -0,0 +1,986 @@
# ----------------------------------------------------------------------------
# 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.
#
# GridManipulation - Version 2.1
#
# Author: Matthew H. Belk Created: 10/02/2010
# WFO Taunton MA Last Modified: 12/03/2015
# ----------------------------------------------------------------------------
import SmartScript
import types, re
import LogStream
import numpy as np
import TimeRange, AbsTime
class GridManipulation(SmartScript.SmartScript):
def __init__(self, dbss):
SmartScript.SmartScript.__init__(self, dbss)
############################################################################
# (originally from CheckTandTd by Tom LeFebvre).
##
# Get the list of time ranges at the grid whose element name is WEName
# contains grids. The model and level of the weather element are assumed
# to be "Fcst" and "SFC" respectively, but can be identified differently.
#
# @param WEName: Name of a weather element
# @type WEName: string
# @param model: Name of model to inventory (default = "Fcst")
# @type model: string
# @param level: Level of a weather element to inventory (default = "SFC")
# @type level: string
# @return: time ranges at which WEName has data.
# @rtype: Python list of Python TimeRange objects
def GM_getWEInventory(self, WEName, dbase="Fcst", level="SFC",
timeRange=TimeRange.allTimes()):
"""Return a list of time ranges with available data for a field from
a specific database and level.
Args:
string WEName: name of field to inventory
string dbase: name of database to search (default = 'Fcst')
string level: level of data to inventory (default = 'SFC')
Returns:
Python list of Python time range objects
"""
# print "Getting inventory of -> '%s' from '%s' at '%s'" % \
# (WEName, dbase, level)
trList = []
# getGridInfo will just die if the modelName or weName is not valid
# so wrap it in a try block and return [] if it fails
try:
gridInfo = self.getGridInfo(dbase, WEName, level, timeRange)
except:
return trList
trList = [g.gridTime() for g in gridInfo
if timeRange.overlaps(g.gridTime())]
return trList
##
# Get time ranges locked by other workstations for the weather element named
# weName. The model for weName is taken from this object's mutableID() method;
# the level defaults to "SFC", but can be identified for a different level.
# @param weName: Name of a weather element.
# @type weName: string
# @param level: Level of a weather element to inventory (default = "SFC")
# @type level: string
# @return: time ranges locked by others
# @rtype: Python list of TimeRanges; if asJava is True, these are Java
# TimeRanges, otherwise they are Python TimeRanges.
def GM_getParmLocksByOthers(self, weName, level="SFC"):
"""Return a list of time ranges of locked data within the current
mutable database (typically 'Fcst').
Args:
string WEName: name of field to inventory
string level: level of data to inventory (default = 'SFC')
Returns:
Python list of Python time range objects
"""
# returns list of time ranges locked by others for this weather element
parm = self.getParm(self.mutableID(), weName, level)
if parm is None:
return []
lockTable = parm.getLockTable()
locksByOthers = lockTable.lockedByOther()
trList = []
for lock in locksByOthers.toArray():
print lock
start = lock.getStart().getTime() / 1000
end = lock.getEnd().getTime() / 1000
tr = self.GM_makeTimeRange(start, end)
trList.append(tr)
return trList
##
# Filter trList, returning only the time ranges that overlap timeRange.
# @param timeRange: the time range to test against
# @type timeRange: a Python TimeRange
# @param trList: the list of time ranges to filter
# @type trList: Python list of Python TimeRanges
# @param closest: toggle to find time ranges closest to selected time range (False = overlap only)
# @type closest: integer
# @return: The time ranges in trList that overlap timeRange.
# @rtype: a Python list of Python time ranges
def GM_overlappingTRs(self, timeRange, trList, closest=False):
"""Return a list of time ranges of locked data within the current
mutable database (typically 'Fcst').
Args:
TimeRange timeRange: a Python time range object
list trList: list of Python time range objects
boolean closest: if True, force new time range list to start and
end with the times closest to the start and end of
initial selected time range. If False (default),
only include times which overlap the initial
selected time range.
Returns:
Python list of Python time range objects
"""
# Get ready to return updated list of times
newTRList = []
# Get ready to track certain times
beforeTime = None # start time closest to selected time range start
afterTime = None # time range closest to selected time range start
beforeTR = None # start time closest to selected time range end
afterTR = None # time range closest to selected time range end
# Get start and end time of selected time range
selectStartTime = timeRange.startTime()
selectEndTime = timeRange.endTime()
#=======================================================================
# Examine each time range in the list
for tr in trList:
# If this time range overlaps the selected range
if timeRange.overlaps(tr):
# Add it to the list
newTRList.append(tr)
# Otherwise, if we should find the closest time ranges
elif closest:
# Get the start time of this time range
startTime = tr.startTime()
# Compute the difference between the start of this grid and
# the start and end times of our selected time range
diffStartTime = (startTime - selectStartTime)
diffEndTime = (startTime - selectEndTime)
# print "\t", diffStartTime, diffEndTime
# If start time of this grid is the closest to start time of
# selected time range, or it's the first one
if beforeTime is None or \
((diffStartTime < 0 and diffStartTime >= beforeTime) or
(diffStartTime >= 0 and diffStartTime < beforeTime)):
# Mark this grid as the closest to the selected start time
beforeTime = diffStartTime
beforeTR = tr
# print "beforeTime =", beforeTime, beforeTR
# If start time of this grid is the closest to end time of
# selected time range, or it's the first one
if afterTime is None or \
(diffEndTime >= 0 and diffEndTime <= abs(afterTime)):
# Mark this grid as the closest to the selected end time
afterTime = diffEndTime
afterTR = tr
# print "afterTime =", afterTime, afterTR
# print "newTRList = ", newTRList, beforeTR, afterTR
# If we don't have any grids in the list and we should determine the
# closest grid time ranges to the selected time range
if len(newTRList) == 0 and closest:
# Add closest start and end time ranges to selected time range
newTRList = [beforeTR, afterTR]
# Ensure time ranges are sorted when we return them
newTRList.sort(self.GM_trSortMethod)
# Finally, return our completed list
return newTRList
##
# method so that timeRanges will be sorted earliest to latest
# @param first: The first time range to compare
# @type first: Python TimeRange
# @param last: The second time range to compare
# @type last: Python TimeRange
# @return: -1 if first starts before last, 1 if first starts after last,
# and 0 if first and last start at the same time.
# @rtype: integer
def GM_trSortMethod(self, first, last):
"""Sorts Python time ranges into ascending order.
Args:
TimeRange first: a Python time range object
TimeRange last: a Python time range object
Returns:
An integer indicating the ascending order of the compared time
range objects.
"""
if first.startTime() < last.startTime():
return -1
elif first.startTime() == last.startTime():
return 0
else:
return 1
##
# Concatenate TRList1 and TRList2 and sort by starting times.
# @param TRList1: time ranges of the minT grid
# @type TRList1: Python list of Python TimeRange objects.
# @param TRList2: time ranges of the maxT grid
# @type TRList2: Python list of Python TimeRange objects.
# @return: The combined and sorted collection.
# @rtype: Python list of Python TimeRange objects
def GM_mergeTRLists(self, TRList1, TRList2):
"""Merges and sorts Python time range lists into ascending order.
Args:
TimeRange TRList1: a Python time range object
TimeRange TRList2: a Python time range object
Returns:
A merged and sorted list of Python time range objects.
"""
# Merge the lists
combined = set(TRList1) | set(TRList2)
# Sort the resulting time range list in ascending order
newList = sorted(combined, self.GM_trSortMethod)
# Return the merged and sorted list
return newList
#
############################################################################
############################################################################
# Other utility methods originally provided by Tom LeFebvre (GSD)
##
# Gets the maximum possible time range.
# @return: The maximum possible Python time range.
def GM_makeMaxTimeRange(self):
return TimeRange.allTimes()
##
# Insert a message into the log files.
# @param string: message to insert into log file
# @type string: string
# @return: nothing
# @rtype: nothing
def GM_logToolUse(self, string):
"""Inserts an entry into the log files.
Args:
string string: message to be inserted into the log files
Returns:
Nothing
"""
gtime = self._gmtime().timetuple()
ts="%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d"%(gtime[0], gtime[1], gtime[2],
gtime[3], gtime[4], gtime[5])
# Insert this message into the logs
LogStream.logEvent("%s| %s" % (ts, string))
##
# Creates a time range
# @param start: start of time range in seconds since the epoch began
# @type start: double
# @param end: end of time range in seconds since the epoch began
# @type end: double
# @return: time range
# @rtype: time range object appropriate for AWIPS version
def GM_makeTimeRange(self, start, end):
"""Creates a time range.
Args:
double start - start of time range in seconds since the epoch began
double end - end of time range in seconds since the epoch began
Returns:
Time range appropriate for AWIPS version
"""
startTime = AbsTime.AbsTime(start)
endTime = AbsTime.AbsTime(end)
return TimeRange.TimeRange(startTime, endTime)
##
# Creates a list time range objects to process
# @param executeTR: time range to use in creating list of time steps
# @type executeTR: time range object appropriate to AWIPS version
# @param interpHours: time step to use in hours (default = 1)
# @type end: integer
# @return: time range objects
# @rtype: Python list of time range objects
def GM_makeTimeRangeList(self, executeTR, interpHours=1):
"""Creates a list of time range objects from specified time range.
Args:
executeTR - time range object appropriate to AWIPS version
integer interpHours - number of hours between each time step
(default = 1)
Returns:
Python list of time range appropriate for AWIPS version
"""
start = executeTR.startTime().unixTime()
end = executeTR.endTime().unixTime()
trList = []
for t in range(start, end, 3600*interpHours):
tr = self.GM_makeTimeRange(t, t + 3600)
trList.append(tr)
return trList
##
# Searches a grid inventory for the first available time ranges before and
# after the target time range and returns those objects
# @param modelInventory: list of available data times for a particular model
# @type modelInventory: Python list
# @param targetTR: time range to use as basis for search
# @type targetTR: time range object
# @return: time ranges of available data before and after target time range
# @rtype: time range objects appropriate for AWIPS version or None for missing data
def GM_getPrevNextModelTimes(self, modelInventory, targetTR):
"""Creates a time range.
Args:
list modelInventory - list of available data times for a model
time range targetTR - time range to use as basis for search
Returns:
Previous and next time range objects appropriate for AWIPS version,
or None for missing data
"""
# If we have a model inventory
if len(modelInventory) == 0:
print "Model Inventory is empty"
return None, None
# Convert target time range object into number of seconds since epoch
targetTRsecs = targetTR.startTime().unixTime()
#-----------------------------------------------------------------------
# Make sure we're in range
# Target time range is before all available model data
if targetTRsecs < modelInventory[0].startTime().unixTime():
return None, None
# Target time range is after all available model data
if targetTRsecs > modelInventory[-1].startTime().unixTime():
return None, None
#-----------------------------------------------------------------------
# Search the model inventory
for i in range(len(modelInventory)):
# If we found the first availble model time ranges on both sides
# of the target time range
if modelInventory[i].startTime().unixTime() < targetTRsecs and \
modelInventory[i + 1].startTime().unixTime() > targetTRsecs:
# Return these time range objects
return modelInventory[i], modelInventory[i+1]
# If we made it this far, indicate we could not find appropriate
# time range objects
return None, None
##
# Interpolates a sounding at the specified time range, if needed.
# Otherwise, will use a cached sounding if appropriate.
# within the target time range and returns those objects
# @param model: model to use to grab cube
# @type model: string
# @param weName: weather element name to get cube data for
# @type weName: string
# @param levels: list of levels to use in constructing cube
# @type levels: Python list
# @param timeRange: time range to use as basis for search
# @type timeRange: time range object
# @param modelInventory: list of available data times for a particular model
# @type modelInventory: Python list
# @return: cube of geopotential height and cube of specified field
# @rtype: Python tuple of numpy cube data
def GM_interpolateSounding(self, model, weName, levels, timeRange,
modelInventory):
prevTR, nextTR = self.GM_getPrevNextModelTimes(modelInventory,
timeRange)
if prevTR is None or nextTR is None:
return None
prevGHCube, prevCube = self.makeNumericSounding(model, weName, levels,
prevTR, noDataError=0)
nextGHCube, nextCube = self.makeNumericSounding(model, weName, levels,
nextTR, noDataError=0)
# calculate weights for a time-weighted average
t1 = timeRange.startTime().unixTime() - prevTR.startTime().unixTime()
t2 = nextTR.startTime().unixTime() - timeRange.startTime().unixTime()
prevWt = float(t2) / float(t1 + t2)
nextWt = float(t1) / float(t1 + t2)
interpGHCube = (prevGHCube * prevWt) + (nextGHCube * nextWt)
# If this is a cube of scalars
if re.search("(?i)wind", weName) is None:
interpCube = (prevCube * prevWt) + (nextCube * nextWt)
else:
# Break up the wind into u and v components
(prevU, prevV) = self.MagDirToUV(prevCube[0], prevCube[1])
(nextU, nextV) = self.MagDirToUV(nextCube[0], nextCube[1])
# Interpolate the wind components
interpU = (prevU * prevWt) + (nextU * nextWt)
interpV = (prevV * prevWt) + (nextV * nextWt)
# Now compute the final wind magnitude and direction
interpCube = self.UVToMagDir(interpU, interpV)
return interpGHCube, interpCube
##
# Interpolates a grid field at the specified time range, if needed.
# Otherwise, will use a cached sounding if appropriate.
# within the target time range and returns those objects
# @param model: model to use to grab field
# @type model: string
# @param weName: weather element name to get cube data for
# @type weName: string
# @param level: level of data to interpolate
# @type level: string
# @param timeRange: time range to use as basis for search
# @type timeRange: time range object
# @param modelInventory: list of available data times for a particular model
# @type modelInventory: Python list
# @return: grid of specified field
# @rtype: numpy grid data
def GM_interpolateGrid(self, model, weName, level, timeRange,
modelInventory):
prevTR, nextTR = self.GM_getPrevNextModelTimes(modelInventory,
timeRange)
if prevTR is None or nextTR is None:
return None
prevGrid = self.getGrids(model, weName, level, prevTR, noDataError=0)
nextGrid = self.getGrids(model, weName, level, nextTR, noDataError=0)
# calculate weights for a time-weighted average
t1 = timeRange.startTime().unixTime() - prevTR.startTime().unixTime()
t2 = nextTR.startTime().unixTime() - timeRange.startTime().unixTime()
prevWt = t2 / float(t1 + t2)
nextWt = t1 / float(t1 + t2)
# If this is a grid of scalars
if re.search("(?i)wind", weName) is None:
finalGrid = (prevGrid * prevWt) + (nextGrid * nextWt)
else:
# Break up the wind into u and v components
(prevU, prevV) = self.MagDirToUV(prevGrid[0], prevGrid[1])
(nextU, nextV) = self.MagDirToUV(nextGrid[0], nextGrid[1])
# Interpolate the wind components
interpU = (prevU * prevWt) + (nextU * nextWt)
interpV = (prevV * prevWt) + (nextV * nextWt)
# Now compute the final wind magnitude and direction
finalGrid = self.UVToMagDir(interpU, interpV)
return finalGrid
#
############################################################################
############################################################################
# Define a method to manipulate grid times
############################################################################
##
# Produces a list of Python time ranges
# @param dataDict: time ranges of available data
# @type dataDict: Python dictionary keyed by database
# @param dataLocks: time ranges which are locked by others
# @type dataLocks: Python list of time ranges which are locked by others
# @param interpHours: requested time step in hours
# @type interpHours: integer
# @return: list of Python time range objects
# @rtype: Python list
def GM_makeNewTRlist(self, dataDict, dataLocks, interpHours=3):
"""Produces a list of Python time ranges.
Args:
dataDict: Python dictionary of time ranges of available data keyed by database
dataLocks: Python list of time ranges which are locked by others
interpHours: requested time step in hours
Returns:
Python list of Python time range objects
"""
#=======================================================================
# Make a new list of time ranges to iterate over
newTRlist = []
#-----------------------------------------------------------------------
# Look at all the models we have data for
for model in dataDict.keys():
#-------------------------------------------------------------------
# Start with all time steps from this model
for tr in dataDict[model].keys():
#print "TR:", dir(tr)
pyStart = self._gmtime(tr.startTime().unixTime())
startHour = pyStart.tm_hour
# print "HOUR:", startHour
#---------------------------------------------------------------
# If this time range is not already locked by someone else, and
# it is one we would want to have but do not have yet, and it
# is one we have data for from this model
# print "newTRlist:", newTRlist, "type:", type(newTRlist)
# print "dataLocks:", dataLocks, "type:", type(dataLocks)
if tr not in newTRlist and tr not in dataLocks and \
(startHour % interpHours) == 0 and \
dataDict[model][tr] is not None:
# Add this time range to the new time range list
newTRlist.append(tr)
#-----------------------------------------------------------------------
# Sort new model time range list by time
newTRlist.sort(self.GM_trSortMethod)
#-----------------------------------------------------------------------
# Return completed consolidated time range list
return newTRlist
############################################################################
# Define a method to adjust time range which will be deleted - this is so
# only grids for which we have data from selected model will be deleted
############################################################################
##
# Produces a new time range which can be used to delete data
# @param timeRange: initial selected time range
# @type timeRange: Python time range object
# @param TRList: time ranges with available data
# @type TRlist: Python list of time ranges
# @param adjustTR: number of hours to delete before and after available data to make for easier interpolation
# @type adjustTR: integer
# @return: list of Python time range objects
# @rtype: Python list
def GM_adjustDeleteTimeRange(self, timeRange, TRlist, adjustTR=0):
"""Adjusts a time range for purposes of deleting grids. The intent is
to make it easier to interpolate between old and new data.
Args:
timeRange: Python time range object representing selected time
ranage
TRlist: Python list of Python time range objects where data is
available
integer adjustTR: number of hours to delete on either side of
available data to make for easier interpolation
Returns:
a TimeRange object spanning adjusted time range
"""
#-----------------------------------------------------------------------
# Get ready to set new limits of the time range
newStart = None
newEnd = None
#-----------------------------------------------------------------------
# Look through the time ranges we have for model data
for tr in TRlist:
# If this grid is in the selected time range
if timeRange.overlaps(tr):
# If we have not yet determined a start time
if newStart is None:
# Define the new start time
newStart = tr.startTime().unixTime() - adjustTR*3600.0
# If we have not yet determined an end time
if tr.endTime().unixTime() > newEnd:
# Define the new end time
newEnd = tr.endTime().unixTime() + adjustTR*3600.0
## print '+'*90
## print newStart, newEnd
## print TimeRange.TimeRange(AbsTime.AbsTime(newStart), AbsTime.AbsTime(newEnd))
#-----------------------------------------------------------------------
# Return adjusted time range - if we did adjust it
if newStart is not None and newEnd is not None:
return TimeRange.TimeRange(AbsTime.AbsTime(newStart),
AbsTime.AbsTime(newEnd))
# Otherwise, return the original time range
else:
return timeRange
############################################################################
# Define a method to linearly interpolate data
############################################################################
##
# Produces an updated Python dictionary with interpolated data where needed
# @param dataDict: data for a specific time, can be mixed (e.g. gh, t, p)
# @type dataDict: Python dictionary keyed by Python TimeRange object
# @param TRList: list of times for
# @type TRlist: Python list of time ranges
# @param adjustTR: number of hours to delete before and after available data to make for easier interpolation
# @type adjustTR: integer
# @return: list of Python time range objects
# @rtype: Python list
def GM_interpolateData(self, dataDict, TRlist, interpHours=3,
vector=[], singleLevel=[]):
#-----------------------------------------------------------------------
# Determine the structure (i.e. how many fields are present) of the
# data dictionary
try:
numFields = len(dataDict[TRlist[0]])
except:
print "No data to interpolate!"
return dataDict
#-----------------------------------------------------------------------
# Cycle through each time period we already have
for index in range(len(TRlist) - 1):
# print "\tindex = ", index
#-------------------------------------------------------------------
# Define a list to hold the times we need to create soundings for
makeList = []
#-------------------------------------------------------------------
# Get the time range of the current and next soundings we have
current = TRlist[index]
next = TRlist[index + 1]
# print '*'*80
# print current, next
#-------------------------------------------------------------------
# Get the starting times of each sounding time range
currentStart = current.startTime().unixTime()
nextStart = next.startTime().unixTime()
#-------------------------------------------------------------------
# See how far apart these soundings are in time (hours)
diffTime = nextStart - currentStart
# print diffTime, interpHours*3600
#-------------------------------------------------------------------
# If gap between data time steps are more than what we need
if int(diffTime) > interpHours*3600:
#--------------------------------------------------------------
# Keep track of seconds we are between data time steps
curTime = float(interpHours*3600)
#---------------------------------------------------------------
# Make a new time range every three hours
# print '\t', int(currentStart + curTime), int(nextStart)
while int(currentStart + curTime) < int(nextStart):
#-----------------------------------------------------------
# Compute linear interpolation weight
weight = curTime / diffTime
# print "weight = ", weight
#-----------------------------------------------------------
# Make a new TimeRange object for this new time step
newTR = TimeRange.TimeRange(
AbsTime.AbsTime(currentStart + curTime),
AbsTime.AbsTime(currentStart + curTime + 3600)
)
#-----------------------------------------------------------
# Define an empty string to hold all interpolated data
# which should be placed within the final data structure
# for this time
finalData = ""
#===========================================================
# Interpolate data for each field at this time step
for field in range(numFields):
# Create a final data structure for interpolated data
exec "data%d = []" % (field)
# If this field is a vector, make component data
# structures
if field in vector:
exec "data%dU = []" % (field)
exec "data%dV = []" % (field)
#-------------------------------------------------------
# Get data from the current and next time steps we have
try:
curData = dataDict[current][field]
except:
# No point in continuing with this time step
msg = "Could not get 'current' data -> %s" % \
(repr(current))
self.statusBarMsg(msg, "R")
continue # move on
try:
nextData = dataDict[next][field]
except:
# No point in continuing with this time step
msg = "Could not get 'next' data -> %s" % \
(repr(next))
self.statusBarMsg(msg, "R")
continue # move on
#-------------------------------------------------------
# If this field is a vector, separate it into its'
# u and v components
if field in vector:
(curU, curV) = self.MagDirToUV(curData[0],
curData[1])
(nextU, nextV) = self.MagDirToUV(nextData[0],
nextData[1])
#=======================================================
# If this field is a single level
if field in singleLevel:
if not vector:
data = (curData + (nextData - curData) * weight)
else:
u = (curU + (nextU - curU) * weight)
v = (curV + (nextV - curV) * weight)
#---------------------------------------------------
# Get the newly interpolated grids
if not vector:
if type(data) == types.ListType:
dataGrid = data[0]
else:
dataGrid = data
else:
if type(u) == types.ListType:
uGrid = u[0]
else:
uGrid = u
if type(v) == types.ListType:
vGrid = v[0]
else:
vGrid = v
#---------------------------------------------------
# Add current level into the new data structure
if not vector:
exec "data%d = array(dataGrid)" % (field)
else:
exec "data%dU = array(uGrid)" % (field)
exec "data%dV = array(vGrid)" % (field)
#=======================================================
# Otherwise, cycle through each level in the sounding
else:
for level in xrange(curData.shape[0]):
#-----------------------------------------------
# Construct sounding values for this level
if not vector:
data = (curData[level] +
(nextData[level] - curData[level]) *
weight)
else:
u = (curU[level] +
(nextU[level] - curU[level]) * weight)
v = (curV[level] +
(nextV[level] - curV[level]) * weight)
#-----------------------------------------------
# Get the newly interpolated grids
if not vector:
if type(data) == types.ListType:
dataGrid = data[0]
else:
dataGrid = data
else:
if type(u) == types.ListType:
uGrid = u[0]
else:
uGrid = u
if type(v) == types.ListType:
vGrid = v[0]
else:
vGrid = v
#-----------------------------------------------
# Add current level into the new sounding
if not vector:
exec "data%d = data%d + [dataGrid]" % \
(field, field)
else:
exec "data%dU = data%dU + [uGrid]" % \
(field, field)
exec "data%dV = data%dV + [vGrid]" % \
(field, field)
#---------------------------------------------------
# Finish off the new cube for this time
if not vector:
exec "data%d = array(data%d)" % (field, field)
else:
exec "data%dU = array(data%dU)" % (field, field)
exec "data%dV = array(data%dV)" % (field, field)
#=======================================================
# If this is a vector field, reconstruct vector from
# the components
if vector:
exec "data%d = self.UVToMagDir(data%dU, data%dV)" %\
(field, field, field)
#=======================================================
# Add current interpolated data for this time step to
# the final data structure
exec "finalData += 'data%d'" % (field)
if field < (numFields - 1):
finalData += ", "
#-----------------------------------------------------------
# Add this interpolated data to data structure
exec "dataDict[newTR] = (%s)" % (finalData)
msg = "Created data for -> %s" % (repr(newTR))
self.statusBarMsg(msg, "R")
#-----------------------------------------------------------
# Move on to next desired time step
curTime += float(interpHours)*3600.0
#-----------------------------------------------------------------------
# Return the completed data dictionary
return dataDict
############################################################################
# Define a method to smooth data
############################################################################
##
# Produces a smoother version of a numpy grid.
# @param grid: numpy grid to be smoothed
# @type grid: numpy array
# @param factor: factor to control level of smoothing
# @type factor: Python integer
# @return: smoother grid object
# @rtype: numpy array
def GM_smoothGrid(self, grid, factor=3):
# This code is essentially the NumericSmooth example
# smart tool customized for our purposes.
# factors of less than 3 are useless or dangerous
if factor < 3:
return grid
half = int(factor)/ 2
sg = np.zeros(grid.shape, np.float64)
count = np.zeros(grid.shape, np.float64)
for y in range(-half, half + 1):
for x in range(-half, half + 1):
if y < 0:
yTargetSlice = slice(-y, None, None)
ySrcSlice = slice(0, y, None)
if y == 0:
yTargetSlice = slice(0, None, None)
ySrcSlice = slice(0, None, None)
if y > 0:
yTargetSlice = slice(0, -y, None)
ySrcSlice = slice(y, None, None)
if x < 0:
xTargetSlice = slice(-x, None, None)
xSrcSlice = slice(0, x, None)
if x == 0:
xTargetSlice = slice(0, None, None)
xSrcSlice = slice(0, None, None)
if x > 0:
xTargetSlice = slice(0, -x, None)
xSrcSlice = slice(x, None, None)
target = [yTargetSlice, xTargetSlice]
src = [ySrcSlice, xSrcSlice]
sg[target] = sg[target] + grid[src]
count[target] += 1
return sg / count

View file

@ -24,6 +24,7 @@
# ------------ ---------- ----------- --------------------------
# Sep 01, 2014 3572 randerso Fix getTopo
# Apr 23, 2015 4259 njensen Updated for new JEP API
# Dec 2, 2015 18356 yteng Fix typo in __getitem__
#
########################################################################
import DatabaseID, AbsTime, JUtil
@ -64,7 +65,7 @@ class DBSSWE:
if type(result) is numpy.ndarray and result.dtype == numpy.int8:
# discrete or weather
dkeys = JUtil.javaObjToPyVal(slice.getKeyList())
result = [result, keys]
result = [result, dkeys]
return result
return None

View file

@ -174,6 +174,9 @@ import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
* 08/10/2015 4721 randerso Changed getNNNid() to use the productID field (not textdbPil)
* 09/15/2015 4858 dgilling Disable store/transmit in DRT mode.
* 10/26/2015 18244 lshi fixed NullPointerException (pds, updateIssueExpireTimes)
* 12/14/2015 18367 ryu Disable finalization of ETN when product is stored to text database.
* 12/16/2015 18410 lshi For corrected products, both WMO time and MND time should
* match the current time
* </pre>
*
* @author lvenable
@ -1147,7 +1150,8 @@ public class ProductEditorComp extends Composite implements
// prevent the launching of another dialog until the modal dialog is
// closed.
StoreTransmitDlg storeDlg = new StoreTransmitDlg(parent.getShell(),
showStore, this, transmissionCB, pid, !textComp.isCorMode());
showStore, this, transmissionCB, pid,
!textComp.isCorMode() && (action == Action.TRANSMIT));
storeDlg.open();
}
}
@ -1973,18 +1977,18 @@ public class ProductEditorComp extends Composite implements
// else it will continue on.
if (textComp != null) {
// Update Issue time
try {
textComp.startUpdate();
ProductDataStruct pds = textComp.getProductDataStruct();
if (pds != null) {
if (!textComp.isCorMode()) {
TextIndexPoints pit = pds.getPIT();
if (pit != null) {
String time = purgeTimeFmt.format(now);
textComp.replaceText(pit, time);
}
// update WMO time
//if (!textComp.isCorMode()) { ## uncomment this if want to keep WMO time original
TextIndexPoints pit = pds.getPIT();
if (pit != null) {
String time = purgeTimeFmt.format(now);
textComp.replaceText(pit, time);
}
// }
// Update MND time
TextIndexPoints tip = pds.getMndMap().get("nwstime");

View file

@ -91,6 +91,13 @@ import com.raytheon.viz.gfe.textformatter.TextFmtParserUtil;
* editing of framing codes.
* 07/02/2015 13753 lshi Update times for products in Product Editor
* 08/06/2015 13753 lshi use isSystemTextChange instead of isUpdateTime
* 12/04/2015 13753 lshi revert 13753
*
*
* 11/19/2015 5141 randerso Changed upper() to also replace commas with ellipses
* 12/22/2015 18428 lshi Issuing a Correction of a corrected product via an existing
* Product Editor in GFE throws and error and unlocks text,
* wordWrap
*
* </pre>
*
@ -1291,7 +1298,7 @@ public class StyledTextComp extends Composite {
* <ol>
* <li value=0>The index in the old content of the first character</li>
* <li>The index in the old content of the last character</li>
* <li>The length of the replacement text</li>
* <li>The length of the replacemetruent text</li>
* </ol>
*/
public int[] wordWrap(StyledText st, int cursorIndex, int width) {
@ -1466,7 +1473,9 @@ public class StyledTextComp extends Composite {
post = post.replaceAll("^\\s*", "");
String text = pre + rchar + post;
st.replaceTextRange(startIndex, (1 + endIndex) - startIndex, text);
if (startIndex > 0) {
st.replaceTextRange(startIndex, (1 + endIndex) - startIndex, text);
}
int newCaretOffset = startIndex + pre.length();
st.setCaretOffset(newCaretOffset);

View file

@ -136,6 +136,7 @@ import com.vividsolutions.jts.index.strtree.STRtree;
* Jun 26, 2015 17386 xwei Fixed : HydroView crashes in when Refresh Data after loading saved display files
* Jul 06, 2015 4215 mpduff Correct the fact that user's cannot click and view time series.
* Oct 05, 2015 17978 lbousaidi Enable TimeStep GUI to display multiple values and Parameter Codes for a given lid
* Dec 05, 2015 18357 xwei Fixed error in opening Timeseries for Timesteps
*
* </pre>
*
@ -225,8 +226,6 @@ public class MultiPointResource extends
private STRtree strTree = new STRtree();
private STRtree strTreeTimeStep = new STRtree();
private IFont font;
private int fontSize;
@ -1498,13 +1497,14 @@ public class MultiPointResource extends
if (pcOptions.getQueryMode() == 1){
dataMapTimeStep.clear();
strTreeTimeStep = new STRtree();
}else{
dataMap.clear();
strTree = new STRtree();
}
strTree = new STRtree();
}
private class TimeSeriesLaunchAction extends AbstractRightClickAction {

View file

@ -28,6 +28,8 @@ package com.raytheon.viz.hydrocommon.data;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 14, 2015 17978 lbousaidi Initial Creation
*
* Dec 05, 2015 18357 xwei Fixed error in opening Timeseries for Timesteps
* </pre>
*
* @author lbousaidi
@ -74,6 +76,10 @@ public class GageDataTimeStep extends GageData {
setValue( gage.getValue() );
setThreatIndex( gage.getThreatIndex() );
setPe( gage.getPe() );
setTs( gage.getTs() );
setExtremum( gage.getExtremum() );
setP( gage );
setV( gage );
return;

View file

@ -31,9 +31,13 @@ import java.util.List;
import java.util.TimeZone;
import com.raytheon.uf.common.dataplugin.shef.tables.Hourlypc;
import com.raytheon.uf.common.dataplugin.shef.tables.HourlypcId;
import com.raytheon.uf.common.dataplugin.shef.tables.Hourlypp;
import com.raytheon.uf.common.dataplugin.shef.tables.HourlyppId;
import com.raytheon.uf.common.dataplugin.shef.tables.IHourlyTS;
import com.raytheon.uf.common.dataplugin.shef.tables.Ingestfilter;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.core.catalog.DirectDbQuery;
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
import com.raytheon.uf.viz.core.exception.VizException;
@ -53,6 +57,8 @@ import com.raytheon.viz.hydrocommon.HydroConstants;
* 09/26/2012 15385 lbousaidi fixed duplicate entries in gage table.
* 11/04/2015 5100 bkowal Fixes to handle records that spanned
* hour 24 to hour 1.
* 11/16/2015 5100 bkowal Generated a better query to handle the case when
* the requested data spans two days.
* </pre>
*
* @author grichard
@ -114,6 +120,9 @@ public final class PrecipUtil {
}
}
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(PrecipUtil.class);
public static enum PrecipPEmode {
PrecipPEbest, PrecipPEPP, PrecipPEPC
}
@ -237,7 +246,7 @@ public final class PrecipUtil {
String dur = "";
if ((typeSource != null) && !typeSource.isEmpty()) {
ts_clause = build_ts_clause(typeSource);
ts_clause = build_ts_clause(typeSource, "id.ts");
if (ts_clause == null) {
return null;
}
@ -352,14 +361,12 @@ public final class PrecipUtil {
}
query.append(where.toString());
// Echo the query string to the console.
System.out.println("Query = " + query.toString());
try {
retVal = (ArrayList<Object[]>) DirectDbQuery.executeQuery(
query.toString(), HydroConstants.IHFS, QueryLanguage.SQL);
} catch (VizException e) {
e.printStackTrace();
statusHandler.error("Failed to retrieve the PE raw data.", e);
}
return retVal;
@ -866,11 +873,11 @@ public final class PrecipUtil {
* @param ts
* @return
*/
public String build_ts_clause(List<String> ts) {
public String build_ts_clause(List<String> ts, String tsField) {
if ((ts == null) || ts.isEmpty()) {
return "";
}
StringBuilder tsClause = new StringBuilder("id.ts ");
StringBuilder tsClause = new StringBuilder(tsField.trim() + " ");
if (ts.get(0).startsWith("!")) {
tsClause.append("not in ('");
@ -1123,7 +1130,7 @@ public final class PrecipUtil {
return MISSING_PRECIP;
}
if (pc_timet.after(start_date)) {
if (pc_timet.after(start_date) && end_hour != 1) {
/*
* An exact match for the start date could not be found. Set the
* starting hour to 1.
@ -1183,17 +1190,6 @@ public final class PrecipUtil {
*/
value_found = false;
start_value = (short) MISSING_PRECIP;
/*
* Adjust for records returned that span more than one day. Simplest fix
* without doing a significant rewrite of the algorithm. Not completely
* optimal; however, this ensures that start->end is processed every
* time.
*/
if (start_hour == end_hour && start_hour == 1) {
start_hour = 24;
++pStartPCIdx;
pEndPCIdx += 2;
}
while ((pStartPCIdx < hourlyPCList.size())
&& ((pStartPCIdx != pEndPCIdx) || (start_hour < end_hour) || (start_hour == 24 && end_hour == 1))) {
@ -1231,7 +1227,7 @@ public final class PrecipUtil {
end_value = (short) MISSING_PRECIP;
while ((pEndPCIdx > pStartPCIdx)
|| ((pEndPCIdx == pStartPCIdx) && (end_hour > start_hour))) {
|| ((pEndPCIdx == pStartPCIdx) && (end_hour > start_hour) || (start_hour == 24 && end_hour == 1))) {
Hourlypc pEndPC = hourlyPCList.get(pEndPCIdx);
hour_index = end_hour - 1;
end_value = get_hour_slot_value(pEndPC, end_hour);
@ -1547,22 +1543,21 @@ public final class PrecipUtil {
return ts_group_count;
}
/**
* buildWhereClause
*
* @param query_begin_time
* @param query_end_time
* @param lid
* @param ts
* @return
*/
private String buildWhereClause(Date query_begin_time, Date query_end_time,
String lid, List<String> ts) {
/*
* Need special logic to account for accumulation intervals which start
* at 00Z. This is because the 00Z PC value is actually placed in the 24
* hour slot of the previous day.
*/
private String buildHourlyHQL(Date query_begin_time, Date query_end_time,
String lid, List<String> ts, final String entityName,
String selectAdditional) {
final String orderBy = " ORDER BY b.id.lid ASC, b.id.ts ASC, b.id.obsdate ASC";
StringBuilder fromList = new StringBuilder(
" b.id.lid, b.id.ts, b.id.obsdate, %s, %s, b.hour1, ");
fromList.append("b.hour2, b.hour3, b.hour4, b.hour5, b.hour6, b.hour7, b.hour8, b.hour9, b.hour10, ");
fromList.append("b.hour11, b.hour12, b.hour13, b.hour14, b.hour15, b.hour16, b.hour17, b.hour18, ");
fromList.append("b.hour19, b.hour20, b.hour21, b.hour22, b.hour23, ");
if (selectAdditional != null
&& selectAdditional.trim().startsWith(", ") == false) {
selectAdditional = ", " + selectAdditional;
}
Calendar pTm = null;
pTm = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
@ -1581,26 +1576,47 @@ public final class PrecipUtil {
String endstr = sdf.format(pTm.getTime());
/* consider according to whether type-source specified. */
/* load data which is not missing value (-9999.0) */
StringBuilder where = new StringBuilder("WHERE ");
String where = null;
String minuteOffsetStr = null;
String hourlyQCStr = null;
if (endstr.equals(beginstr)) {
fromList.append("b.hour24 ");
if (selectAdditional != null) {
fromList.append(selectAdditional);
}
fromList.append(" FROM ").append(entityName).append(" b ");
where = " b.id.obsdate = '" + beginstr + "'";
minuteOffsetStr = "b.minuteOffset";
hourlyQCStr = "b.hourlyQc";
} else {
fromList.append("a.hour24 ");
if (selectAdditional != null) {
fromList.append(selectAdditional);
}
fromList.append(" FROM ").append(entityName).append(" a, ")
.append(entityName).append(" b ");
where = " a.id.lid = b.id.lid AND a.id.ts = b.id.ts AND a.id.obsdate = '"
+ beginstr + "' AND b.id.obsdate = '" + endstr + "'";
minuteOffsetStr = "substring(b.minuteOffset, 1, 23) || substring(a.minuteOffset, 24, 24)";
hourlyQCStr = "substring(b.hourlyQc, 1, 23) || substring(a.hourlyQc, 24, 24)";
}
StringBuilder whereStr = new StringBuilder(where);
if (lid != null) {
where.append("id.lid = '");
where.append(lid);
where.append("' AND ");
whereStr.append(" AND ");
whereStr.append("id.lid = '");
whereStr.append(lid);
}
if ((ts != null) && (ts.size() > 0)) {
where.append(build_ts_clause(ts));
where.append(" AND ");
whereStr.append(" AND ");
whereStr.append(build_ts_clause(ts, "b.id.ts"));
}
where.append("id.obsdate between '");
where.append(beginstr);
where.append("' AND '");
where.append(endstr);
where.append("' ORDER BY id.lid ASC, id.ts ASC, id.obsdate ASC");
return where.toString();
return new StringBuilder("SELECT")
.append(String.format(fromList.toString(), minuteOffsetStr,
hourlyQCStr)).append("WHERE")
.append(whereStr.toString()).append(orderBy).toString();
}
/**
@ -1778,17 +1794,49 @@ public final class PrecipUtil {
public ArrayList<Hourlypc> load_PC_hourly(Date query_begin_time,
Date query_end_time, String lid, List<String> ts) {
ArrayList<Hourlypc> pHourlyPC = null;
final String fullQuery = this.buildHourlyHQL(query_begin_time,
query_end_time, lid, ts, Hourlypc.class.getName(), null);
List<Object[]> results = null;
try {
results = DirectDbQuery.executeQuery(fullQuery, "ihfs",
QueryLanguage.HQL);
} catch (VizException e) {
statusHandler.error("Failed to retrieve the Hourly PC data.", e);
// will return an empty list by the next if statement due to the
// null results.
}
String where = buildWhereClause(query_begin_time, query_end_time, lid,
ts);
if (results == null || results.isEmpty()) {
return new ArrayList<>(1);
}
/* get the data */
pHourlyPC = IHFSDbGenerated.GetHourlyPC(where);
System.out.println("SELECT * FROM HourlyPC " + where);
System.out.println(pHourlyPC.size()
+ " records retrieved from HourlyPC. ");
return pHourlyPC;
ArrayList<Hourlypc> hourlyPcRecords = new ArrayList<>(results.size());
for (Object object : results) {
Object[] dataValues = (Object[]) object;
/*
* First few fields are needed to build an {@link HourlypcId}.
*/
HourlypcId id = new HourlypcId((String) dataValues[0],
(String) dataValues[1], (Date) dataValues[2]);
Hourlypc record = new Hourlypc(id, (String) dataValues[3],
(String) dataValues[4], (Short) dataValues[5],
(Short) dataValues[6], (Short) dataValues[7],
(Short) dataValues[8], (Short) dataValues[9],
(Short) dataValues[10], (Short) dataValues[11],
(Short) dataValues[12], (Short) dataValues[13],
(Short) dataValues[14], (Short) dataValues[15],
(Short) dataValues[16], (Short) dataValues[17],
(Short) dataValues[18], (Short) dataValues[19],
(Short) dataValues[20], (Short) dataValues[21],
(Short) dataValues[22], (Short) dataValues[23],
(Short) dataValues[24], (Short) dataValues[25],
(Short) dataValues[26], (Short) dataValues[27],
(Short) dataValues[28]);
hourlyPcRecords.add(record);
}
return hourlyPcRecords;
}
/**
@ -1803,14 +1851,53 @@ public final class PrecipUtil {
public ArrayList<Hourlypp> load_PP_hourly(Date query_begin_time,
Date query_end_time, String lid, List<String> ts) {
ArrayList<Hourlypp> pHourlyPP = null;
final String selectAdditional = ", b.sixhr06, b.sixhr12, b.sixhr18, b.sixhr24, b.sixhrqc, b.sixhroffset ";
final String fullQuery = this.buildHourlyHQL(query_begin_time,
query_end_time, lid, ts, Hourlypp.class.getName(),
selectAdditional);
List<Object[]> results = null;
try {
results = DirectDbQuery.executeQuery(fullQuery, "ihfs",
QueryLanguage.HQL);
} catch (VizException e) {
statusHandler.error("Failed to retrieve the Hourly PP data.", e);
// will return an empty list by the next if statement due to the
// null results.
}
String where = buildWhereClause(query_begin_time, query_end_time, lid,
ts);
if (results == null || results.isEmpty()) {
return new ArrayList<>(1);
}
/* get the data */
pHourlyPP = IHFSDbGenerated.GetHourlyPP(where);
ArrayList<Hourlypp> hourlyPpRecords = new ArrayList<>(results.size());
for (Object object : results) {
Object[] dataValues = (Object[]) object;
return pHourlyPP;
/*
* First few fields are needed to build an {@link HourlypcId}.
*/
HourlyppId id = new HourlyppId((String) dataValues[0],
(String) dataValues[1], (Date) dataValues[2]);
Hourlypp record = new Hourlypp(id, (String) dataValues[3],
(String) dataValues[4], (Short) dataValues[5],
(Short) dataValues[6], (Short) dataValues[7],
(Short) dataValues[8], (Short) dataValues[9],
(Short) dataValues[10], (Short) dataValues[11],
(Short) dataValues[12], (Short) dataValues[13],
(Short) dataValues[14], (Short) dataValues[15],
(Short) dataValues[16], (Short) dataValues[17],
(Short) dataValues[18], (Short) dataValues[19],
(Short) dataValues[20], (Short) dataValues[21],
(Short) dataValues[22], (Short) dataValues[23],
(Short) dataValues[24], (Short) dataValues[25],
(Short) dataValues[26], (Short) dataValues[27],
(Short) dataValues[28], (Short) dataValues[29],
(Short) dataValues[30], (Short) dataValues[31],
(Short) dataValues[32], (String) dataValues[33],
(String) dataValues[34]);
hourlyPpRecords.add(record);
}
return hourlyPpRecords;
}
}

View file

@ -35,12 +35,10 @@ import javax.measure.converter.UnitConverter;
import javax.measure.unit.Unit;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.State;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
@ -48,7 +46,6 @@ import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.handlers.RadioState;
import org.eclipse.ui.handlers.RegistryToggleState;
import org.eclipse.ui.operations.RedoActionHandler;
import com.raytheon.uf.common.colormap.ColorMap;
import com.raytheon.uf.common.colormap.prefs.ColorMapParameters;
@ -63,6 +60,7 @@ import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.util.FileUtil;
import com.raytheon.uf.viz.core.IDisplayPane;
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.RGBColors;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.datastructure.LoopProperties;
@ -84,7 +82,6 @@ import com.raytheon.viz.mpe.MPECommandConstants;
import com.raytheon.viz.mpe.MPEDateFormatter;
import com.raytheon.viz.mpe.core.MPEDataManager;
import com.raytheon.viz.mpe.core.MPEDataManager.MPERadarLoc;
import com.raytheon.viz.mpe.ui.actions.ClearMPEData;
import com.raytheon.viz.mpe.ui.dialogs.hourlyradar.RadarDataManager;
import com.raytheon.viz.mpe.ui.displays.MPEMapRenderableDisplay;
import com.raytheon.viz.mpe.ui.rsc.MPEFieldResource;
@ -116,6 +113,7 @@ import com.raytheon.viz.ui.editor.IMultiPaneEditor;
* Jul 8, 2015 16790 snaples Updated setCurrentEditDate to refresh resources when dateMap is stale.
* Jul 29, 2015 17471 snaples Updated editTime to ensure that it always references "GMT" timezone.
* Sep 29, 2015 16790 snaples Fixed issue with date not following the CAVE time when changed, and fixed time matching issue.
* Dec 02, 2015 18104 snaples Fixed issue of not unzooming when using Pan/Zoom tools.
*
* </pre>
*
@ -314,6 +312,8 @@ public class MPEDisplayManager {
private static GageColor gageColor;
private static GageMissingOptions gageMissing;
private static IExtent defaultExtent;
static {
gageMissing = getCommandStateEnum(
@ -480,6 +480,15 @@ public class MPEDisplayManager {
@Override
public void run() {
MPEDisplayManager.this.toggleDisplayMode(DisplayMode.Image);
if (defaultExtent == null) {
IDisplayPaneContainer container = EditorUtil.getActiveVizContainer();
if (container != null) {
IDisplayPane pane = container.getActiveDisplayPane();
if (pane != null) {
setDefaultExtent(pane.getRenderableDisplay().getExtent());
}
}
}
}
});
@ -1295,4 +1304,12 @@ public class MPEDisplayManager {
return displayedAccumHrs;
}
public static IExtent getDefaultExtent() {
return defaultExtent;
}
public static void setDefaultExtent(IExtent defaultExtent) {
MPEDisplayManager.defaultExtent = defaultExtent;
}
}

View file

@ -30,6 +30,7 @@ import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.drawables.IRenderableDisplay;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.mpe.ui.MPEDisplayManager;
import com.raytheon.viz.ui.EditorUtil;
import com.raytheon.viz.ui.perspectives.AbstractVizPerspectiveManager;
import com.raytheon.viz.ui.perspectives.VizPerspectiveListener;
@ -48,6 +49,7 @@ import com.raytheon.viz.ui.tools.ModalToolManager;
* 11Apr2011 8738 jpiatt Initial Creation.
* Jun 30, 2015 14317 snaples Fixed issue when toggling back from Areal Zoom,
* not going to Pan mode.
* Dec 02, 2015 18104 snaples Fixed issue of not unzooming when using Pan/Zoom tools.
*
* </pre>
*
@ -97,20 +99,28 @@ public class MPEZoomAction extends AbstractHandler {
if (container != null) {
pane = container.getActiveDisplayPane();
if (pane != null) {
unZoomedExtent = pane.getRenderableDisplay().getExtent();
unZoomedExtent = pane.getRenderableDisplay().getExtent();
}
}
}
mgr.activateToolSet(ZOOM_ID);
break;
} else {
pane.getRenderableDisplay().setExtent(unZoomedExtent);
pane.getDescriptor().getRenderableDisplay().refresh();
if (display == null) {
container = EditorUtil.getActiveVizContainer();
if (container != null) {
pane = container.getActiveDisplayPane();
if (pane != null) {
if (unZoomedExtent == null){
unZoomedExtent = MPEDisplayManager.getDefaultExtent();
}
}
}
}
pane.getDescriptor().getRenderableDisplay().setExtent(unZoomedExtent);
pane.getDescriptor().getRenderableDisplay().refresh();
mgr.activateToolSet(PAN_ID);
break;
}

View file

@ -90,6 +90,8 @@ import com.vividsolutions.jts.geom.Coordinate;
* Dec 07, 2015 5171 bkowal Allow the user to change point quality to verified when the
* 24-hour value is partial.
*
* Dec 10, 2015 18391 snaples Updated changeCustomFile to not remove grid when EditStations Apply is clicked.
*
* </pre>
*
* @author snaples
@ -1353,11 +1355,7 @@ public class EditPrecipStationsDialog extends AbstractMPEDialog implements
bv.restore_bad_values(pcpn_day, precipStationList, max_stations);
if (k == 1 || k == 3)
grids_flag = 1;
OtherPrecipOptions op = new OtherPrecipOptions();
op.send_expose();
if (k == 1 || k == 3) grids_flag = 1;
return;
}

View file

@ -107,9 +107,11 @@ import com.raytheon.viz.mpe.ui.dialogs.gagetable.xml.GageTableSortType;
* Feb 02, 2014 16201 snaples Added saved data flag support
* Apr 16, 2014 3025 mpduff Fix sort method.
* Nov 18, 2015 18093 snaples Fixed GridComboListener to trigger table update when changing compare column.
*
* Dec 02, 2015 18094 lbousaidi added the sorting method for multi column sorting.
* Dec 07, 2015 18137 lbousaidi fixed sorting after editing gages.
*
* </pre>
*
*
* @author mpduff
* @version 1.0
*/
@ -1276,9 +1278,6 @@ public class GageTableDlg extends JFrame implements IEditTimeChangedListener {
rowData);
dataChanged = true;
}
// Update the grid combobox
gridCombo.removeAllItems();
populateGridCombo();
} else {
Enumeration<TableColumn> colEnum = table.getColumnModel()
@ -1341,10 +1340,26 @@ public class GageTableDlg extends JFrame implements IEditTimeChangedListener {
*/
private GageTableSortSettings setSortColumns(
GageTableSortSettings settings, int index, boolean ascending) {
settings.setSortCol4Index(settings.getSortCol3Index());
settings.setSortCol3Index(settings.getSortCol2Index());
settings.setSortCol2Index(settings.getSortCol1Index());
settings.setSortCol1Index(index);
int aPos = getSortClickPosition( settings, index );
if ( 4 == aPos || 0 == aPos ){
settings.setSortCol4Index(settings.getSortCol3Index());
settings.setSortCol3Index(settings.getSortCol2Index());
settings.setSortCol2Index(settings.getSortCol1Index());
settings.setSortCol1Index(index);
}else if ( 3 == aPos ){
settings.setSortCol3Index(settings.getSortCol2Index());
settings.setSortCol2Index(settings.getSortCol1Index());
settings.setSortCol1Index(index);
}else if ( 2 == aPos ){
settings.setSortCol2Index(settings.getSortCol1Index());
settings.setSortCol1Index(index);
}
settings.setAscending4(settings.getAscending3());
settings.setAscending3(settings.getAscending2());
@ -1388,6 +1403,38 @@ public class GageTableDlg extends JFrame implements IEditTimeChangedListener {
GageTableProductManager.getInstance().fireUpdateEvent(event);
}
/**
* Get click position for sorting
*
* @param settings
* The GageTableColumnSettings
* @param index
* The selected column index
* @return
*
*
**/
private int getSortClickPosition( GageTableSortSettings settings, int index ){
if ( index == settings.getSortCol1Index() ){
return 1;
}
if ( index == settings.getSortCol2Index() ){
return 2;
}
if ( index == settings.getSortCol3Index() ){
return 3;
}
if ( index == settings.getSortCol4Index() ){
return 4;
}
return 0;
}
/*
* (non-Javadoc)
*

View file

@ -84,7 +84,8 @@ import com.raytheon.viz.mpe.ui.rsc.MPEFieldResourceData.MPEFieldFrame;
* Mar 10, 2014 17059 snaples Added case for Prism data for unit conversion correction.
* Mar 19, 2014 17109 snaples Removed code that added an hour to SATPRE, the base file reference time has been adjusted.
* Nov 05, 2015 18095 lbousaidi Fixed hour substitued for satellite field precip when drawing polygon.
*
* Dec 04, 2015 5165/14513 mduff Set this resource on the display manager if not set in the display manager.
*
* </pre>
*
* @author mschenke
@ -96,8 +97,10 @@ public class MPEFieldResource extends
implements IPolygonEditsChangedListener {
private static final short MISSING_VALUE = -899;
private static final int BIG_VALUE = 1000 ;
private static final int RATIO_CONVERSION_FACTOR = 100;
private static final int BIG_VALUE = 1000;
private static final int RATIO_CONVERSION_FACTOR = 100;
private ContourPreferences contourPreferences;
@ -125,6 +128,12 @@ public class MPEFieldResource extends
contourPreferences = createContourPreferences(getCapability(
ColorMapCapability.class).getColorMapParameters());
PolygonEditManager.registerListener(this);
MPEDisplayManager displayManager = MPEDisplayManager
.getInstance(descriptor.getRenderableDisplay());
MPEFieldResource rsc = displayManager.getDisplayedFieldResource();
if (rsc == null) {
displayManager.setDisplayedResource(this);
}
}
/*
@ -183,17 +192,18 @@ public class MPEFieldResource extends
subData = dataMap.get(edit.getSubDrawSource());
if (subData == null) {
try {
Date date=frame.getDate();
//SATPRE MPE file time stamp is the start time of the hour
//i.e. a 12z -13z product has a time stamp of 12z.
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if (edit.getSubDrawSource().name().contains("satPre")) {
cal.add(Calendar.HOUR, - 1);
}
Date date = frame.getDate();
// SATPRE MPE file time stamp is the start time of the
// hour
// i.e. a 12z -13z product has a time stamp of 12z.
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if (edit.getSubDrawSource().name().contains("satPre")) {
cal.add(Calendar.HOUR, -1);
}
XmrgFile subFile = MPEDisplayManager.getXmrgFile(
edit.getSubDrawSource(), cal.getTime());
XmrgFile subFile = MPEDisplayManager.getXmrgFile(
edit.getSubDrawSource(), cal.getTime());
subFile.load();
subData = subFile.getData();
@ -341,241 +351,208 @@ public class MPEFieldResource extends
timeToLoad.setTime(currTime.getRefTime());
timeToLoad.add(Calendar.HOUR, -i);
if (displayField==DisplayFieldData.satPre) {
//SATPRE MPE file time stamp is the start time of the hour
//i.e. a 12z -13z product has a time stamp of 12z.
timeToLoad.add(Calendar.HOUR, -1);
if (displayField == DisplayFieldData.satPre) {
// SATPRE MPE file time stamp is the start time of the hour
// i.e. a 12z -13z product has a time stamp of 12z.
timeToLoad.add(Calendar.HOUR, -1);
}
if (displayField.isAComparisonField()) {
ComparisonFields comparisonFields = displayField
.getComparisonFields();
DisplayFieldData field1 = comparisonFields.getField1();
DisplayFieldData field2 = comparisonFields.getField2();
XmrgFile file1 = MPEDisplayManager.getXmrgFile(field1,
timeToLoad.getTime());
if (displayField.isAComparisonField() )
{
ComparisonFields comparisonFields = displayField.getComparisonFields();
DisplayFieldData field1 = comparisonFields.getField1();
DisplayFieldData field2 = comparisonFields.getField2();
XmrgFile file1 = MPEDisplayManager.getXmrgFile(field1,
timeToLoad.getTime());
XmrgFile file2 = MPEDisplayManager.getXmrgFile(field2,
timeToLoad.getTime());
boolean isDifference = false;
boolean isRatio = false;
if (displayField.equals(DisplayFieldData.precipDifferenceField))
{
isDifference = true;
XmrgFile file2 = MPEDisplayManager.getXmrgFile(field2,
timeToLoad.getTime());
}
else if (displayField.equals(DisplayFieldData.precipRatioField))
{
isRatio = true;
}
try {
file1.load();
file2.load();
} catch (IOException e) {
Activator.statusHandler.handle(
Priority.INFO,
"Error loading XMRG file for "
+ field1 + " or " + field2
+ " at time "
+ MPEDateFormatter
.format_MMM_dd_yyyy_HH(timeToLoad
.getTime()), e);
continue;
}
Rectangle fileExtent = file1.getHrapExtent();
short[] file1Data = file1.getData();
short[] file2Data = file2.getData();
for (int y = 0; y < displayExtent.height; ++y) {
for (int x = 0; x < displayExtent.width; ++x) {
int px = x + displayExtent.x;
int py = y + displayExtent.y;
if (px >= fileExtent.x
&& px < (fileExtent.x + fileExtent.width)
&& py >= fileExtent.y
&& py < (fileExtent.y + fileExtent.height))
{
int frameIdx = y * displayExtent.width + x;
int fx = px - fileExtent.x;
int fy = py - fileExtent.y;
int fileIdx = fy * fileExtent.width + fx;
short value1 = file1Data[fileIdx];
short value2 = file2Data[fileIdx];
short fi = 0;
if (isDifference)
{
short diffValue = calculateDifference(value1, value2);
fi = diffValue;
}
else if (isRatio)
{
double ratio = calculateRatio(value1, value2);
if (ratio != MISSING_VALUE)
{
fi = (short) ( ratio * RATIO_CONVERSION_FACTOR );
}
else
{
fi = MISSING_VALUE;
}
}
//short fc = frameData[frameIdx];
//fc is initial value of frameData[frameIdx],
//it is used to help accumulate precip in a multi-hour accum situation
frameData[frameIdx] = fi;
boolean isDifference = false;
boolean isRatio = false;
} //end if (px >=)
} //end for x
} //end for y
}
else //is a non-comparison field
if (displayField.equals(DisplayFieldData.precipDifferenceField)) {
isDifference = true;
} else if (displayField
.equals(DisplayFieldData.precipRatioField)) {
isRatio = true;
}
try {
file1.load();
file2.load();
} catch (IOException e) {
Activator.statusHandler.handle(
Priority.INFO,
"Error loading XMRG file for "
+ field1
+ " or "
+ field2
+ " at time "
+ MPEDateFormatter
.format_MMM_dd_yyyy_HH(timeToLoad
.getTime()), e);
continue;
}
Rectangle fileExtent = file1.getHrapExtent();
short[] file1Data = file1.getData();
short[] file2Data = file2.getData();
for (int y = 0; y < displayExtent.height; ++y) {
for (int x = 0; x < displayExtent.width; ++x) {
int px = x + displayExtent.x;
int py = y + displayExtent.y;
if (px >= fileExtent.x
&& px < (fileExtent.x + fileExtent.width)
&& py >= fileExtent.y
&& py < (fileExtent.y + fileExtent.height)) {
int frameIdx = y * displayExtent.width + x;
int fx = px - fileExtent.x;
int fy = py - fileExtent.y;
int fileIdx = fy * fileExtent.width + fx;
short value1 = file1Data[fileIdx];
short value2 = file2Data[fileIdx];
short fi = 0;
if (isDifference) {
short diffValue = calculateDifference(value1,
value2);
fi = diffValue;
} else if (isRatio) {
double ratio = calculateRatio(value1, value2);
if (ratio != MISSING_VALUE) {
fi = (short) (ratio * RATIO_CONVERSION_FACTOR);
} else {
fi = MISSING_VALUE;
}
}
// short fc = frameData[frameIdx];
// fc is initial value of frameData[frameIdx],
// it is used to help accumulate precip in a
// multi-hour accum situation
frameData[frameIdx] = fi;
} // end if (px >=)
} // end for x
} // end for y
} else // is a non-comparison field
{
XmrgFile file = MPEDisplayManager.getXmrgFile(displayField,
timeToLoad.getTime());
try {
long fileLength = file.getFile().length();
//System.out.printf("FileName = %s, length = %d\n", file.getFile().getPath(), fileLength);
if (fileLength > 0)
{
file.load();
}
else //can't read the file since it is empty
{
continue;
}
} catch (IOException e) {
Activator.statusHandler.handle(
Priority.INFO,
"Error loading XMRG file for "
+ displayField
+ " at time "
+ MPEDateFormatter
.format_MMM_dd_yyyy_HH(timeToLoad
.getTime()), e);
continue;
}
XmrgFile file = MPEDisplayManager.getXmrgFile(displayField,
timeToLoad.getTime());
try {
long fileLength = file.getFile().length();
// System.out.printf("FileName = %s, length = %d\n",
// file.getFile().getPath(), fileLength);
if (fileLength > 0) {
file.load();
} else // can't read the file since it is empty
{
continue;
}
} catch (IOException e) {
Activator.statusHandler.handle(
Priority.INFO,
"Error loading XMRG file for "
+ displayField
+ " at time "
+ MPEDateFormatter
.format_MMM_dd_yyyy_HH(timeToLoad
.getTime()), e);
continue;
}
Rectangle fileExtent = file.getHrapExtent();
short[] fileData = file.getData();
for (int y = 0; y < displayExtent.height; ++y) {
for (int x = 0; x < displayExtent.width; ++x) {
int px = x + displayExtent.x;
int py = y + displayExtent.y;
if (px >= fileExtent.x
&& px < (fileExtent.x + fileExtent.width)
&& py >= fileExtent.y
&& py < (fileExtent.y + fileExtent.height)) {
int frameIdx = y * displayExtent.width + x;
int fx = px - fileExtent.x;
int fy = py - fileExtent.y;
int fileIdx = fy * fileExtent.width + fx;
short fi = fileData[fileIdx];
short fc = frameData[frameIdx];
Rectangle fileExtent = file.getHrapExtent();
short[] fileData = file.getData();
for (int y = 0; y < displayExtent.height; ++y) {
for (int x = 0; x < displayExtent.width; ++x) {
int px = x + displayExtent.x;
int py = y + displayExtent.y;
if (px >= fileExtent.x
&& px < (fileExtent.x + fileExtent.width)
&& py >= fileExtent.y
&& py < (fileExtent.y + fileExtent.height)) {
int frameIdx = y * displayExtent.width + x;
int fx = px - fileExtent.x;
int fy = py - fileExtent.y;
int fileIdx = fy * fileExtent.width + fx;
short fi = fileData[fileIdx];
short fc = frameData[frameIdx];
if (fc < 0 && fi >= 0)
{
//orig precip is missing, and this hour's value is valid (> = 0)
// so set the value to the current hour's value
frameData[frameIdx] = fi;
}
else if (fc >= 0 && fi > 0)
{
//some previous hour's precip has been recorded and this hour's value is valid (> = 0)
//so accumulate
frameData[frameIdx] += fi;
}
} //end if (px >=)
} //end for x
} //end for y
} //end else is a non-comparison field
} //end for i
if (fc < 0 && fi >= 0) {
// orig precip is missing, and this hour's value
// is valid (> = 0)
// so set the value to the current hour's value
frameData[frameIdx] = fi;
} else if (fc >= 0 && fi > 0) {
// some previous hour's precip has been recorded
// and this hour's value is valid (> = 0)
// so accumulate
frameData[frameIdx] += fi;
}
} // end if (px >=)
} // end for x
} // end for y
} // end else is a non-comparison field
} // end for i
return new MPEFieldFrame(currTime.getRefTime(), frameData,
PolygonEditManager.getPolygonEdits(resourceData.getFieldData(),
currTime.getRefTime()));
}
private short calculateDifference(short value1, short value2)
{
private short calculateDifference(short value1, short value2) {
short result = 0;
if (( value1 >= 0) && (value2 >= 0) )
{
result = (short) (value1 - value2 );
}
else
{
if ((value1 >= 0) && (value2 >= 0)) {
result = (short) (value1 - value2);
} else {
result = MISSING_VALUE;
}
return result;
}
private double calculateRatio(short numerator, short denominator)
{
double result = 0;
if (denominator > 0)
{
if (numerator >= 0)
{
result = numerator / denominator;
}
else
{
result = MISSING_VALUE;
}
}
else if (denominator == 0)
{
if (numerator == 0)
{
result = 1.0; //if no rain, they are in agreeement, so show this
}
else if (numerator > 0)
{
result = BIG_VALUE;
}
else // numerator is missing
{
result = MISSING_VALUE;
}
}
else
{
result = MISSING_VALUE;
}
return result;
private double calculateRatio(short numerator, short denominator) {
double result = 0;
if (denominator > 0) {
if (numerator >= 0) {
result = numerator / denominator;
} else {
result = MISSING_VALUE;
}
}
else if (denominator == 0) {
if (numerator == 0) {
result = 1.0; // if no rain, they are in agreeement, so show
// this
} else if (numerator > 0) {
result = BIG_VALUE;
} else // numerator is missing
{
result = MISSING_VALUE;
}
} else {
result = MISSING_VALUE;
}
return result;
}
/*
* (non-Javadoc)
@ -620,66 +597,63 @@ public class MPEFieldResource extends
int length = data.length;
short[] imageData = new short[length];
switch (cvuse) {
case Locbias:
case LocbiasDP:
case Height:
case Index:
case Locspan:
case LocspanDP:
case mintempPrism:
case maxtempPrism:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
case Prism:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value < 0) {
imageData[i] = 0;
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
case precipDifferenceField:
case precipRatioField:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
}
else
{
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
default :
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
} else if(value <= 0){
imageData[i] = 1;
} else if(value > 0 && value < 25){
value = 10;
imageData[i] = (short) dataToImage.convert(value);
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
case Locbias:
case LocbiasDP:
case Height:
case Index:
case Locspan:
case LocspanDP:
case mintempPrism:
case maxtempPrism:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
case Prism:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value < 0) {
imageData[i] = 0;
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
case precipDifferenceField:
case precipRatioField:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
default:
for (int i = 0; i < length; ++i) {
short value = data[i];
if (value == MISSING_VALUE) {
imageData[i] = 0;
} else if (value <= 0) {
imageData[i] = 1;
} else if (value > 0 && value < 25) {
value = 10;
imageData[i] = (short) dataToImage.convert(value);
} else {
imageData[i] = (short) dataToImage.convert(value);
}
}
break;
}
return new GriddedImageDisplay2(ShortBuffer.wrap(imageData),
gridGeometry, this);
}

View file

@ -66,6 +66,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Mar 10, 2015 14575 snaples Added additional status flags.
* Oct 14, 2015 17977 snaples Fixed loadData to read station
* lists when new area, which means it needs to read some tokens also.
* Nov 25, 2015 17986 snaples Updated array func to adjust QC codes for update to dialogs.
*
* </pre>
*
@ -437,7 +438,7 @@ public class DailyQcUtils {
public static int new_area_flag = 0;
public int func[] = { 8, 0, 3, 1, 2 };
public int func[] = { 8, 3, 0, 1, 2 };
public static int hrgt12z = -1;

View file

@ -24,6 +24,9 @@ import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.geotools.coverage.grid.GeneralGridEnvelope;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.DirectPosition2D;
@ -33,6 +36,7 @@ import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.osgi.framework.Bundle;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.pointdata.PointDataContainer;
@ -41,9 +45,7 @@ import com.raytheon.uf.common.pointdata.PointDataView;
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.status.StatusConstants;
import com.raytheon.viz.redbook.Activator;
import com.raytheon.viz.redbookua.rsc.RedbookUpperAirResource;
/**
* Decoder for redbook upper air products.
@ -54,6 +56,7 @@ import com.raytheon.viz.redbookua.rsc.RedbookUpperAirResource;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 24, 2010 1029 dfriedma Initial creation
* Nov 17, 2015 5134 njensen Fixed loading pointDataDescription
*
* </pre>
*
@ -289,20 +292,17 @@ public class RedbookUpperAirDecoder {
private static synchronized PointDataDescription getPointDataDescription() {
if (pointDataDescription == null) {
InputStream is = RedbookUpperAirResource.class
.getResourceAsStream("/res/pointdata/redbookua.xml");
if (is != null) {
try {
try {
pointDataDescription = PointDataDescription
.fromStream(is);
} finally {
is.close();
}
} catch (Exception e) {
statusHandler.handle(Priority.PROBLEM,
"Could load point data description", e);
Bundle bundle = Activator.getDefault().getBundle();
IPath path = new Path("/res/pointdata/redbookua.xml");
try (InputStream is = FileLocator.openStream(bundle, path, false)) {
if (is != null) {
pointDataDescription = PointDataDescription.fromStream(is);
}
} catch (Exception e) {
statusHandler
.handle(Priority.PROBLEM,
"Couldn't load point data description for redbookua",
e);
}
}
return pointDataDescription;

View file

@ -354,6 +354,9 @@ import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
* Sep 29 2015 4899 rferrel Do not send product while in operational mode and
* simulated time.
* 07Oct2015 RM 18132 D. Friedman Exlucde certain phensigs from automatic ETN incrementing.
* 19Nov2015 5141 randerso Replace commas with ellipses if product not enabled for
* mixed case transmission
* 10Dec2015 5206 randerso Replace commas with ellipses only in WarnGen products
*
* </pre>
*
@ -385,6 +388,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
private static List<String> gfePils = Arrays.asList("WSW", "NPW", "HLS",
"CFW", "WCN", "FFA", "MWW", "RFW");
private static final List<String> warngenPils = Arrays.asList("AWW", "EWW",
"FFS", "FFW", "FLS", "FLW", "FRW", "MWS", "NOW", "SMW", "SPS",
"SVR", "SVS", "TOR");
/**
* Default list of VTEC phenomena significance codes for which the ETN
* should not be changed when sending a NEW-action product.
@ -392,6 +399,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
private static final List<String> defaultNoETNIncrementPhenSigs = Arrays
.asList("HU.A", "HU.S", "HU.W", "TR.A", "TR.W", "SS.A", "SS.W",
"TY.A", "TY.W");
/**
* Path of ETN rules localization file
*/
@ -4008,11 +4016,12 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
.getCaretOffset()));
int caretOffsetOnLine = textEditor.getCaretOffset()
- lineStartOffset;
int numberOfSpaces = (textEditor.getTabs() - caretOffsetOnLine
% textEditor.getTabs());
int numberOfSpaces = (textEditor.getTabs() - (caretOffsetOnLine % textEditor
.getTabs()));
String spaces = "";
for (int x = 0; x < numberOfSpaces; x++)
for (int x = 0; x < numberOfSpaces; x++) {
spaces += ' ';
}
textEditor.insert(spaces);
textEditor.setCaretOffset(textEditor.getCaretOffset()
+ numberOfSpaces);
@ -4231,6 +4240,14 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
// section
setCurrentHeaderAndBody();
// if product a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
if (warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
// Mark the uneditable warning text
if (markUneditableText(textEditor)) {
// Add listener to monitor attempt to edit locked text
@ -4370,6 +4387,17 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
if (originalText != null) {
textEditor.setText(originalText);
}
// if product is not enabled for mixed case transmission,
// replace all commas with ellipses
StdTextProduct product = TextDisplayModel.getInstance()
.getStdTextProduct(token);
if ((product != null)
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
// Mark the uneditable warning text
if (markUneditableText(textEditor)) {
// Add listener to monitor attempt to edit locked text
@ -4973,8 +5001,8 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
int startIndex = "Attachment:".length() + 1;
sb.append(statusBarLabel.getText().substring(startIndex));
sb.append(") will be transmitted with this message.");
int response = TextWSMessageBox.open(shell, "Notice", sb.toString(),
SWT.OK | SWT.CANCEL);
int response = TextWSMessageBox.open(shell, "Notice",
sb.toString(), SWT.OK | SWT.CANCEL);
if (SWT.OK != response) {
return;
}
@ -5100,11 +5128,13 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
* saveEditedProduct, does not actually save anything.
*/
if (shouldSetETNtoNextValue(prod)) {
statusHandler.handle(Priority.INFO, "Will increment ETN for this product.");
statusHandler.handle(Priority.INFO,
"Will increment ETN for this product.");
prod.setProduct(VtecUtil.getVtec(
removeSoftReturns(prod.getProduct()), true));
} else {
statusHandler.handle(Priority.INFO, "Will NOT increment ETN for this product.");
statusHandler.handle(Priority.INFO,
"Will NOT increment ETN for this product.");
}
/*
* This silly bit of code updates the ETN of a VTEC in the
@ -5137,13 +5167,15 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
try {
if (!resend) {
if (shouldSetETNtoNextValue(prod)) {
statusHandler.handle(Priority.INFO, "Will increment ETN for this product.");
statusHandler.handle(Priority.INFO,
"Will increment ETN for this product.");
body = VtecUtil
.getVtec(removeSoftReturns(MixedCaseProductSupport
.conditionalToUpper(prod.getNnnid(),
textEditor.getText())));
} else {
statusHandler.handle(Priority.INFO, "Will NOT increment ETN for this product.");
statusHandler.handle(Priority.INFO,
"Will NOT increment ETN for this product.");
}
}
updateTextEditor(body);
@ -5191,7 +5223,8 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
LocalizationFile lf = PathManagerFactory.getPathManager()
.getStaticLocalizationFile(ETN_RULES_FILE);
if (lf == null) {
throw new Exception("ETN rules file (" + ETN_RULES_FILE + ") not found.");
throw new Exception("ETN rules file (" + ETN_RULES_FILE
+ ") not found.");
}
return JAXB.unmarshal(lf.getFile(), EtnRules.class);
}
@ -5201,14 +5234,15 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
try {
excludedPhenSigs = getETNRules().getExcludePhenSigs();
} catch (Exception e) {
statusHandler.handle(Priority.WARN,
"Error loading ETN assignment rules. Will use default rules.",
e);
statusHandler
.handle(Priority.WARN,
"Error loading ETN assignment rules. Will use default rules.",
e);
excludedPhenSigs = defaultNoETNIncrementPhenSigs;
}
boolean result = true;
VtecObject vo = VtecUtil.parseMessage(prod.getProduct());
if (vo != null && excludedPhenSigs != null
if ((vo != null) && (excludedPhenSigs != null)
&& excludedPhenSigs.contains(vo.getPhensig())) {
result = false;
}
@ -6450,17 +6484,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
return;
}
// textEditor.setWordWrap(false);
// Set the text editor's contents to the warning message.
textEditor.removeVerifyListener(TextEditorDialog.this);
textEditor.setText(w);
//
// // Mark the uneditable warning text
// if (markUneditableText(textEditor)) {
// // Add listener to monitor attempt to edit locked text
// textEditor.addVerifyListener(TextEditorDialog.this);
// }
showDialog();
long t1 = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat(
@ -6471,7 +6498,8 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
+ "ms to show dialog");
enterEditor();
if (autoWrapMenuItem != null && !autoWrapMenuItem.isDisposed()) {
if ((autoWrapMenuItem != null)
&& !autoWrapMenuItem.isDisposed()) {
Menu menu = autoWrapMenuItem.getMenu();
for (MenuItem item : menu.getItems()) {
if (item.getSelection()) {
@ -7089,6 +7117,15 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
}
textEditor.append(textProduct);
// if product a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
if (warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
markUneditableText(textEditor);
// Update text display model with the product that was
@ -8130,8 +8167,8 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
&& (allText.charAt(eol + 1) == '\n')) {
deleteLen = 2;
} else if (allText.charAt(eol) == '\n') {
if (allText.charAt(eol - 1) == '.'
&& allText.charAt(eol - 2) != '.') {
if ((allText.charAt(eol - 1) == '.')
&& (allText.charAt(eol - 2) != '.')) {
// do not extend this line.
return;
} else {

View file

@ -26,7 +26,9 @@ Require-Bundle: org.eclipse.ui,
com.raytheon.viz.alerts,
com.raytheon.uf.common.site,
com.raytheon.viz.core.contours,
com.raytheon.uf.viz.core.rsc
com.raytheon.uf.viz.core.rsc,
org.eclipse.core.databinding;bundle-version="1.4.1",
com.raytheon.uf.common.auth;bundle-version="1.14.0"
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.viz.warngen,
com.raytheon.viz.warngen.gis,

View file

@ -99,4 +99,12 @@
recursive="true">
</path>
</extension>
<extension
point="com.raytheon.viz.ui.contextualMenu">
<contextualMenu
actionClass="com.raytheon.viz.warngen.gui.ShowExtensionAreaToggleAction"
name="com.raytheon.viz.warngen.ShowExtensionAreaToggle"
sortID="600">
</contextualMenu>
</extension>
</plugin>

View file

@ -95,6 +95,8 @@ import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer;
* 05/07/2015 DR 17438 D. Friedman Clean up debug and performance logging.
* 05/08/2015 DR 17310 D. Friedman Prevent reducePoints from generating invalid polygons.
* 09/22/2015 DR 18033 Qinglu Lin Updated removeOverlaidLinesegments(), removed one computeSlope().
* 12/09/2015 DR 18209 D. Friedman Support cwaStretch.
* 12/21/2015 DCS 17942 D. Friedman Support extension area. Work around glitch in contour adjustment.
* </pre>
*
* @author mschenke
@ -135,9 +137,12 @@ public class PolygonUtil {
}
public Polygon hatchWarningArea(Polygon origPolygon,
Geometry origWarningArea, Polygon oldWarningPolygon)
Geometry origWarningArea, Geometry extensionArea,
Polygon oldWarningPolygon, boolean cwaStretch)
throws VizException {
float[][] contourAreaData = toFloatData(origWarningArea);
if (extensionArea != null)
toFloatData(extensionArea, contourAreaData);
/*
* If we have an oldWarningPolygon, we can take a shortcut and see if
@ -167,7 +172,7 @@ public class PolygonUtil {
* that are used to generate origWarningArea.
*/
Geometry comparableIntersection = layer
.buildIdealArea(origPolygon);
.buildIdealArea(origPolygon, cwaStretch);
float[][] interAreaData = toFloatData(comparableIntersection);
if (areasEqual(interAreaData, contourAreaData)) {
return polygonIntersection;
@ -224,7 +229,7 @@ public class PolygonUtil {
boolean showContour = false;
if (contour != null && !showContour) {
rval = awips1PointReduction(contour, origPolygon, origWarningArea,
config, oldWarningPolygon);
extensionArea, config, oldWarningPolygon, contourAreaData);
if (rval == null) {
return (Polygon) origPolygon.clone();
}
@ -245,14 +250,38 @@ public class PolygonUtil {
* @return null if the original warningPolygon should be used
*/
private Polygon awips1PointReduction(Coordinate[] longest,
Polygon warningPolygon, Geometry warningArea, FortConConfig config,
Polygon oldWarningPolygon) throws VizException {
Polygon warningPolygon, Geometry warningArea,
Geometry extensionArea, FortConConfig config,
Polygon oldWarningPolygon, float[][] warningAreaData)
throws VizException {
if (extensionArea != null) {
/*
* Attempt to avoid a glitch in the code below in which it chooses
* an inappropriate side of the polygon on which to project an
* unmatched contour point. The glitch is likely to occur when a
* polygon point is outside the contour space, so clip the polygon
* to it.
*/
Polygon wpc = WarngenLayer.convertGeom(warningPolygon, latLonToContour);
GeometryFactory gf = new GeometryFactory();
Coordinate[] coords = new Coordinate[5];
coords[0] = new Coordinate(0, 0);
coords[1] = new Coordinate(nx, 0);
coords[2] = new Coordinate(nx, ny);
coords[3] = new Coordinate(0, ny);
coords[4] = new Coordinate(0, 0);
Polygon clip = gf.createPolygon(gf.createLinearRing(coords), null);
Geometry g = clip.intersection(wpc);
if (g instanceof Polygon) {
warningPolygon = WarngenLayer.convertGeom((Polygon) g, contourToLatLon);
}
}
Coordinate[] vertices = warningPolygon.getCoordinates();
vertices = Arrays.copyOf(vertices, vertices.length - 1);
// Extract data
float[][] contourPolyData = toFloatData(warningPolygon);
float[][] currentPolyData = toFloatData(warningArea);
float[][] currentPolyData = warningAreaData;
// If same area is hatched, just use the current polygon.
if (areasEqual(contourPolyData, currentPolyData)) {
@ -1174,7 +1203,13 @@ public class PolygonUtil {
}
}
private float[][] toFloatData(Geometry warningArea) throws VizException {
public float[][] toFloatData(Geometry warningArea) throws VizException {
float[][] contourAreaData = new float[nx][ny];
toFloatData(warningArea, contourAreaData);
return contourAreaData;
}
public void toFloatData(Geometry warningArea, float[][] contourAreaData) throws VizException {
Geometry contoured = layer.convertGeom(warningArea, latLonToContour);
List<Geometry> geomList = new ArrayList<Geometry>(
contoured.getNumGeometries());
@ -1188,7 +1223,6 @@ public class PolygonUtil {
GeometryFactory gf = warningArea.getFactory();
Point point = gf.createPoint(new Coordinate(0, 0));
CoordinateSequence pointCS = point.getCoordinateSequence();
float[][] contourAreaData = new float[nx][ny];
for (PreparedGeometry geom : prepped) {
Envelope env = geom.getGeometry().getEnvelopeInternal();
@ -1196,13 +1230,14 @@ public class PolygonUtil {
int startY = (int) env.getMinY();
int width = (int) env.getMaxX();
int height = (int) env.getMaxY();
if (startX < 0 || width > nx || startY < 0 || height > ny) {
continue;
}
startX = Math.max(0, startX - 1);
startY = Math.max(0, startY - 1);
width = Math.min(nx, width + 1);
height = Math.min(ny, height + 1);
if (width < 0 || startX >= nx || height < 0 || startY >= ny) {
continue;
}
for (int x = startX; x < width; ++x) {
for (int y = startY; y < height; ++y) {
@ -1215,7 +1250,6 @@ public class PolygonUtil {
}
}
}
return contourAreaData;
}
/**

View file

@ -0,0 +1,223 @@
package com.raytheon.viz.warngen.gui;
import javax.measure.converter.UnitConverter;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
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.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import com.raytheon.viz.warngen.gui.WarngenLayer.ExtensionAreaOptions;
/**
* GUI for advanced WarnGen options.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
public class PolygonOptionsComposite extends Composite {
private WarngenLayer warngenLayer;
private Button allowExtendedPolygonButton;
private Text extensionDistanceText;
private Text extensionSimplificationToleranceText;
private Button visualizeExtensionButton;
private WritableValue observableOptions;
private boolean ignoreControls;
private boolean ignoreOptions;
public PolygonOptionsComposite(Composite parent, WarngenLayer warngenLayer) {
super(parent, SWT.NONE);
this.warngenLayer = warngenLayer;
observableOptions = warngenLayer.getObservableExtensionAreaOptions();
createControls();
}
private void createControls() {
GridLayout gl = new GridLayout();
gl.numColumns = 2;
setLayout(gl);
Label label;
GridData textGD = new GridData();
textGD.horizontalAlignment = GridData.FILL;
textGD.grabExcessHorizontalSpace = true;
GridData fillGD = new GridData();
fillGD.horizontalAlignment = GridData.FILL;
fillGD.grabExcessHorizontalSpace = true;
fillGD.horizontalSpan = 2;
label = new Label(this, SWT.CENTER);
label.setText("Extension Area Options");
label.setLayoutData(fillGD);
allowExtendedPolygonButton = new Button(this, SWT.CHECK);
allowExtendedPolygonButton.setText("Allow polygon to extend past valid hatching area");
allowExtendedPolygonButton.setLayoutData(fillGD);
allowExtendedPolygonButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setEnabled(allowExtendedPolygonButton.getSelection());
setOptions(options);
}
});
visualizeExtensionButton = new Button(this, SWT.CHECK);
visualizeExtensionButton.setText("Show extension area");
visualizeExtensionButton.setLayoutData(fillGD);
visualizeExtensionButton.setSelection(warngenLayer.isExtensionAreaVisible());
visualizeExtensionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ignoreControls) {
return;
}
warngenLayer.setExtensionAreaVisualized(visualizeExtensionButton.getSelection());
}
});
warngenLayer.getObservableExtensionAreaVisible().addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
visualizeExtensionButton.setSelection(warngenLayer.isExtensionAreaVisible());
}
});
label = new Label(this, SWT.LEFT);
label.setText("Extension distance (mi)");
extensionDistanceText = new Text(this, SWT.LEFT | SWT.SINGLE | SWT.BORDER);
extensionDistanceText.setLayoutData(textGD);
new DistanceController() {
@Override
void setValue(double value) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setDistance(value);
setOptions(options);
}
}.setControl(extensionDistanceText);
label = new Label(this, SWT.LEFT);
label.setText("Simplification tolerance (mi)");
extensionSimplificationToleranceText = new Text(this, SWT.LEFT | SWT.SINGLE | SWT.BORDER);
extensionSimplificationToleranceText.setLayoutData(textGD);
new DistanceController() {
@Override
void setValue(double value) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setSimplificationTolerance(value);
setOptions(options);
}
@Override
public boolean validate(double value) {
return value >= WarngenLayer.ExtensionAreaOptions.MINIMUM_SIMPLIFICATION_TOLERANCE;
}
}.setControl(extensionSimplificationToleranceText);
realizeExtensionAreaOptions();
observableOptions.addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
if (! ignoreOptions) {
realizeExtensionAreaOptions();
}
}
});
}
private void setOptions(ExtensionAreaOptions options) {
ignoreOptions = true;
try {
observableOptions.setValue(options);
} finally {
ignoreOptions = false;
}
}
private void realizeExtensionAreaOptions() {
UnitConverter metersToMile = WarngenLayer.MILES_TO_METER.inverse();
ExtensionAreaOptions options = getExtensionAreaOptions();
ignoreControls = true;
try {
allowExtendedPolygonButton.setSelection(options.isEnabled());
extensionDistanceText.setText(Double.toString(
metersToMile.convert(options.getDistance())));
extensionSimplificationToleranceText.setText(Double.toString(
metersToMile.convert(options.getSimplificationTolerance())));
} finally {
ignoreControls = false;
}
}
private ExtensionAreaOptions getExtensionAreaOptions() {
return (ExtensionAreaOptions) observableOptions.getValue();
}
private static abstract class DistanceController implements ModifyListener {
Text text;
public DistanceController() {
}
void setControl(Text text) {
text.setTextLimit(10);
this.text = text;
text.addModifyListener(this);
}
@Override
public void modifyText(ModifyEvent event) {
boolean ok = false;
double newValue = Double.NaN;
String s = text.getText();
s = s.trim();
if (s.length() > 0) {
try {
newValue = WarngenLayer.MILES_TO_METER.convert(
Double.parseDouble(s));
} catch (RuntimeException e) {
// ignore
}
ok = validate(newValue);
text.setBackground(text.getDisplay().getSystemColor(
ok ? SWT.COLOR_LIST_BACKGROUND : SWT.COLOR_RED));
if (ok) {
setValue(newValue);
}
}
}
abstract void setValue(double value);
public boolean validate(double value) { return ! Double.isNaN(value); }
}
}

View file

@ -0,0 +1,56 @@
package com.raytheon.viz.warngen.gui;
import org.eclipse.jface.action.IAction;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
/**
* Action to toggle the display of the extension are in WarngenLayer
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
public class ShowExtensionAreaToggleAction extends AbstractRightClickAction {
WarngenLayer warngenLayer;
public void setSelectedRsc(ResourcePair selectedRsc) {
super.setSelectedRsc(selectedRsc);
AbstractVizResource<?, ?> rsc = selectedRsc != null ? selectedRsc.getResource() : null;
if (rsc instanceof WarngenLayer) {
warngenLayer = (WarngenLayer) rsc;
setChecked(warngenLayer.isExtensionAreaVisible());
} else {
warngenLayer = null;
}
}
@Override
public void run() {
if (warngenLayer != null) {
boolean checked = ! warngenLayer.isExtensionAreaVisible();
warngenLayer.setExtensionAreaVisualized(checked);
setChecked(checked);
}
}
@Override
public int getStyle() {
return IAction.AS_CHECK_BOX;
}
@Override
public String getText() {
return "Show Extension Area";
}
}

View file

@ -41,6 +41,8 @@ import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
@ -62,6 +64,7 @@ import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.common.auth.req.CheckAuthorizationRequest;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
import com.raytheon.uf.common.dataplugin.warning.config.BulletActionGroup;
@ -81,8 +84,10 @@ import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.localization.LocalizationManager;
import com.raytheon.uf.viz.core.maps.MapManager;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState.DisplayType;
import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState.Mode;
import com.raytheon.viz.core.mode.CAVEMode;
import com.raytheon.viz.texteditor.msgs.IWarngenObserver;
import com.raytheon.viz.texteditor.util.VtecUtil;
import com.raytheon.viz.ui.EditorUtil;
@ -170,6 +175,8 @@ import com.vividsolutions.jts.geom.Polygon;
* May 7, 2015 ASM #17438 D. Friedman Clean up debug and performance logging.
* Jun 05, 2015 DR 17428 D. Friedman Fixed duration-related user interface issues. Added duration logging.
* Sep 22, 2015 4859 dgilling Prevent product generation in DRT mode.
* Dec 9, 2015 DR 18209 D. Friedman Support cwaStretch dam break polygons.
* Dec 21, 2015 DCS 17942 D. Friedman Add advanced options tab
* </pre>
*
* @author chammack
@ -371,7 +378,21 @@ public class WarngenDialog extends CaveSWTDialog implements
}
});
Composite mainComposite = new Composite(shell, SWT.NONE);
Composite parent = shell;
boolean advanced = isAdvancedOptionsEnabled();
CTabFolder tabs = null;
CTabItem tabItem = null;
if (advanced) {
tabs = new CTabFolder(shell, SWT.FLAT|SWT.TOP);
parent = tabs;
}
Composite mainComposite = new Composite(parent, SWT.NONE);
if (advanced) {
tabItem = new CTabItem(tabs, SWT.NONE);
tabItem.setText("Product");
tabItem.setControl(mainComposite);
}
GridLayout gl = new GridLayout(1, false);
gl.verticalSpacing = 2;
gl.marginHeight = 1;
@ -385,6 +406,12 @@ public class WarngenDialog extends CaveSWTDialog implements
createBulletListAndLabel(mainComposite);
createBottomButtons(mainComposite);
setInstructions();
if (advanced) {
tabItem = new CTabItem(tabs, SWT.NONE);
tabItem.setText("Polygon Options");
tabItem.setControl(new PolygonOptionsComposite(tabs, warngenLayer));
}
}
@Override
@ -1569,9 +1596,9 @@ public class WarngenDialog extends CaveSWTDialog implements
} else {
coordinates.add(coordinates.get(0));
PolygonUtil.truncate(coordinates, 2);
setPolygonLocked(lockPolygon);
warngenLayer.createDamThreatArea(coordinates
.toArray(new Coordinate[coordinates.size()]));
setPolygonLocked(lockPolygon);
warngenLayer.issueRefresh();
damBreakInstruct = null;
}
@ -1892,9 +1919,16 @@ public class WarngenDialog extends CaveSWTDialog implements
} else {
bulletListManager.recreateBulletsFromFollowup(
warngenLayer.getConfiguration(), action, oldWarning);
if (bulletListManager.isDamNameSeletcted()
&& (action != WarningAction.NEW)) {
if (bulletListManager.isDamNameSeletcted()) {
setPolygonLocked(true);
/* Need to set the warning area again now that the dam bullets
* are set up so that cwaStretch=true dam polygons will work.
*/
try {
warngenLayer.resetWarningPolygonAndAreaFromRecord(oldWarning);
} catch (VizException e) {
statusHandler.error("Error updating the warning area for selected dam", e);
}
}
}
refreshBulletList();
@ -2716,4 +2750,25 @@ public class WarngenDialog extends CaveSWTDialog implements
}
});
}
public boolean isCwaStretchDamBulletSelected() {
DamInfoBullet bullet = bulletListManager.getSelectedDamInfoBullet();
return bullet != null && bullet.isCwaStretch();
}
private static boolean isAdvancedOptionsEnabled() {
boolean hasPermission = false;
try {
String userId = LocalizationManager.getInstance().getCurrentUser();
CheckAuthorizationRequest request = new CheckAuthorizationRequest(
userId, "advancedOptions", "WarnGen");
hasPermission = (Boolean) ThriftClient.sendRequest(request);
} catch (Exception e) {
statusHandler.error("error checking permissions", e);
}
return ((hasPermission && CAVEMode.getMode() == CAVEMode.PRACTICE)
|| WarngenLayer.isWarngenDeveloperMode());
}
}

View file

@ -32,6 +32,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -39,6 +42,9 @@ import javax.measure.converter.UnitConverter;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@ -65,6 +71,7 @@ import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.BulletActionGroup;
import com.raytheon.uf.common.dataplugin.warning.config.DialogConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.ExtensionArea;
import com.raytheon.uf.common.dataplugin.warning.config.GridSpacing;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GenerateGeospatialDataResult;
@ -141,6 +148,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
/**
* Warngen drawing layer. Need to do EVERYTHING in stereographic over centoid of
@ -240,6 +248,9 @@ import com.vividsolutions.jts.io.WKTReader;
* 04/24/2015 ASM #17394 D. Friedman Fix geometries that become invalid in local coordinate space.
* 05/07/2015 ASM #17438 D. Friedman Clean up debug and performance logging.
* 05/08/2015 ASM #17310 D. Friedman Log input polygon when output of AreaHatcher is invalid.
* 12/09/2015 ASM #18209 D. Friedman Support cwaStretch dam break polygons.
* 12/21/2015 DCS 17942 D. Friedman Support "extension area": polygon can extend past normal features into WFO's marine/land areas.
* Show preview of redrawn polygon when developer mode property is set.
* </pre>
*
* @author mschenke
@ -253,6 +264,9 @@ public class WarngenLayer extends AbstractStormTrackResource {
private static final IPerformanceStatusHandler perfLog = PerformanceStatus
.getHandler("WG:");
/*package*/ static final UnitConverter MILES_TO_METER = NonSI.MILE
.getConverterTo(SI.METER);
String uniqueFip = null;
String backupOfficeShort = null;
@ -280,6 +294,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
GeospatialData[] features;
GeospatialData[] cwaStretchFeatures; // contains all from 'features'
MathTransform latLonToLocal;
MathTransform localToLatLon;
@ -289,6 +305,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
int nx, ny;
GeneralGridGeometry localGridGeometry;
GeospatialData[] getFeatures(boolean cwaStretch) {
return cwaStretch && cwaStretchFeatures != null ?
cwaStretchFeatures : features;
}
}
private static class GeospatialDataAccessor {
@ -318,11 +339,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
* polygon to intersect with in lat/lon space
* @return the warning area in screen projection
*/
private Geometry buildArea(Polygon polygon) {
private Geometry buildArea(Geometry polygon, boolean cwaStretch) {
polygon = latLonToLocal(polygon);
Geometry area = null;
if (polygon != null) {
for (GeospatialData r : geoData.features) {
for (GeospatialData r : geoData.getFeatures(cwaStretch)) {
PreparedGeometry prepGeom = (PreparedGeometry) r.attributes
.get(GeospatialDataList.LOCAL_PREP_GEOM);
try {
@ -473,6 +494,12 @@ public class WarngenLayer extends AbstractStormTrackResource {
private Polygon oldWarningPolygon;
private boolean cwaStretch;
private Future<Geometry> extensionAreaFuture;
private GeospatialDataAccessor extensionAreaGDA;
public AreaHatcher(PolygonUtil polygonUtil) {
super("Hatching Warning Area");
setSystem(true);
@ -489,11 +516,15 @@ public class WarngenLayer extends AbstractStormTrackResource {
protected IStatus run(IProgressMonitor monitor) {
Geometry warningArea;
Polygon warningPolygon;
GeospatialDataAccessor extensionAreaGDA;
Future<Geometry> extensionAreaFuture;
synchronized (polygonUtil) {
warningArea = this.warningArea;
warningPolygon = this.warningPolygon;
this.warningArea = this.warningPolygon = null;
extensionAreaGDA = this.extensionAreaGDA;
extensionAreaFuture = this.extensionAreaFuture;
}
if ((warningArea != null) && (warningPolygon != null)) {
@ -502,14 +533,23 @@ public class WarngenLayer extends AbstractStormTrackResource {
Polygon outputHatchedArea = null;
Geometry outputHatchedWarningArea = null;
String adjustmentMessage = null;
Geometry extensionArea = null;
try {
if (extensionAreaGDA != null && extensionAreaFuture != null) {
Geometry staticExtensionArea = extensionAreaFuture.get();
extensionArea = extensionAreaGDA.buildArea(warningPolygon, false); // never uses cwaStretch
if (extensionArea != null && staticExtensionArea != null)
extensionArea = GeometryUtil.intersection(extensionArea, staticExtensionArea);
}
warningPolygon = PolygonUtil
.removeDuplicateCoordinate(warningPolygon);
Polygon hatched = polygonUtil.hatchWarningArea(
warningPolygon,
removeCounties(warningArea,
state.getFipsOutsidePolygon()),
oldWarningPolygon);
extensionArea, oldWarningPolygon,
cwaStretch);
if (hatched != null) {
// DR 15559
Coordinate[] coords = hatched.getCoordinates();
@ -583,7 +623,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
outputHatchedWarningArea = createWarnedArea(
latLonToLocal(outputHatchedArea),
latLonToLocal(warningArea));
latLonToLocal(warningArea),
cwaStretch);
if (! outputHatchedArea.isValid()) {
statusHandler.debug(String.format("Input %s redrawn to invalid %s",
inputWarningPolygon, outputHatchedArea));
@ -591,6 +632,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
this.hatchedArea = outputHatchedArea;
this.hatchedWarningArea = outputHatchedWarningArea;
setOutputPolygon(outputHatchedArea);
} catch (Exception e) {
this.hatchException = e;
/*
@ -602,6 +644,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
statusHandler.handle(Priority.DEBUG, String.format(
"Error redrawing polygon: %s\n Input: %s\nAdjustments: %s\n",
e.getLocalizedMessage(), inputWarningPolygon, adjustmentMessage), e);
setOutputPolygon(null);
}
perfLog.logDuration("AreaHatcher total", System.currentTimeMillis() - t0);
}
@ -615,6 +658,15 @@ public class WarngenLayer extends AbstractStormTrackResource {
this.warningPolygon = warningPolygon;
this.warningArea = warningArea;
this.oldWarningPolygon = oldWarningPolygon;
this.cwaStretch = isCwaStretch();
if (extensionAreaManager.isExtensionAreaActive()) {
this.extensionAreaFuture = extensionAreaManager.getGeometryFuture();
this.extensionAreaGDA = extensionAreaManager.getGDA();
} else {
this.extensionAreaFuture = null;
this.extensionAreaGDA = null;
}
this.hatchedArea = null;
this.hatchedWarningArea = null;
@ -654,6 +706,269 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
}
private void setOutputPolygon(final Polygon polygon) {
VizApp.runAsync(new Runnable() {
public void run() {
outputPolygon = polygon;
issueRefresh();
}
});
}
}
public class ExtensionAreaOptions implements Cloneable {
public static final double DEFAULT_SIMPLIFICATION_TOLERANCE = 1609.344; // 1 mile
public static final double MINIMUM_SIMPLIFICATION_TOLERANCE = 80.4672; // 0.05 miles
private boolean enabled;
private double distance = 0.0;
private double simplificationTolerance = DEFAULT_SIMPLIFICATION_TOLERANCE;
public ExtensionAreaOptions() {
}
public ExtensionAreaOptions(ExtensionArea ea) {
if (ea != null) {
// Relying on converters to return NaN for NaN input
this.distance = MILES_TO_METER.convert(ea.getDistance());
if (! (this.distance > 0)) {
this.distance = 0.0;
}
double v = MILES_TO_METER.convert(ea.getSimplificationTolerance());
if (Double.isNaN(v)) {
v = DEFAULT_SIMPLIFICATION_TOLERANCE;
} else if (! (v >= MINIMUM_SIMPLIFICATION_TOLERANCE)) {
v = MINIMUM_SIMPLIFICATION_TOLERANCE;
}
this.simplificationTolerance = v;
this.enabled = this.distance > 0.0;
} else {
this.distance = 0.0;
this.simplificationTolerance = DEFAULT_SIMPLIFICATION_TOLERANCE;
}
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
public double getSimplificationTolerance() {
return simplificationTolerance;
}
public void setSimplificationTolerance(double simplificationTolerance) {
this.simplificationTolerance = simplificationTolerance;
}
public ExtensionAreaOptions clone() {
try {
return (ExtensionAreaOptions) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
private class ExtensionAreaManager extends Job implements IChangeListener {
private ExtensionAreaOptions options = new ExtensionAreaOptions();
private WritableValue observableOptions = new WritableValue(options, null);
private GeospatialDataAccessor primaryGDA;
private GeospatialDataAccessor gda;
private Geometry geometry;
private FutureTask<Geometry> geometryFuture;
public ExtensionAreaManager() {
super("Generate extension area");
observableOptions.addChangeListener(this);
}
public GeospatialDataAccessor getGDA() {
return gda;
}
public Future<Geometry> getGeometryFuture() {
return geometryFuture;
}
public boolean isExtensionAreaActive() {
return options.isEnabled() && options.getDistance() > 0.0;
}
public void setExtensionAreaConfig(ExtensionArea extensionAreaConfig) {
observableOptions.setValue(new ExtensionAreaOptions(extensionAreaConfig));
}
private void realizeOptions(ExtensionAreaOptions options) {
if (options == null) {
throw new NullPointerException("options must not be null");
}
boolean recreateArea = true;
ExtensionAreaOptions oldOptions = this.options;
if (oldOptions != null) {
if (primaryGDA == geoAccessor
&& oldOptions.getDistance() == options.getDistance()
&& oldOptions.getSimplificationTolerance() ==
options.getSimplificationTolerance()) {
recreateArea = false;
}
}
this.options = options.clone();
if (recreateArea) {
geometry = null;
if (geometryFuture != null) {
geometryFuture.cancel(true);
geometryFuture = null;
}
extensionAreaVis = null;
if (extensionAreaShadedShape != null) {
extensionAreaShadedShape.reset();
issueRefresh();
}
gda = null;
if (isExtensionAreaDefined()) {
Exception error = null;
primaryGDA = geoAccessor;
try {
gda = getPolygonExtensionGDA();
} catch (Exception e) {
error = e;
}
if (gda != null) {
geometryFuture = new FutureTask<Geometry>(
new ExtensionAreaGeometryTask(options,
primaryGDA, gda));
schedule();
} else {
statusHandler.handle(Priority.WARN,
"Could not determine geospatial data type for polygon extension area",
error);
}
}
}
Polygon polygon = getWarngenState().getWarningPolygon();
if (polygon != null) {
try {
updateWarnedAreas(true);
} catch (VizException e) {
statusHandler.error("Error re-hatching", e);
}
issueRefresh();
}
}
@Override
protected IStatus run(IProgressMonitor monitor) {
FutureTask<Geometry> future = geometryFuture;
if (future != null) {
future.run();
}
return Status.OK_STATUS;
}
public boolean isExtensionAreaDefined() {
return options.getDistance() > 0;
}
protected GeospatialDataAccessor getPolygonExtensionGDA() throws Exception {
GeoFeatureType geoFeatureType = getDefaultExtensionAreaGeoType();
return geoFeatureType != null ? getGeospatialDataAcessor(geoFeatureType)
: null;
}
protected GeoFeatureType getDefaultExtensionAreaGeoType() {
GeoFeatureType otherType = null;
AreaSourceConfiguration asc = getConfiguration().getHatchedAreaSource();
if (asc != null) {
String areaSource = asc.getAreaSource().toLowerCase();
if (areaSource.contains("marinezones"))
otherType = GeoFeatureType.COUNTY;
else if (areaSource.contains("county") || areaSource.contains("zone")) {
otherType = GeoFeatureType.MARINE;
} else {
otherType = GeoFeatureType.COUNTY;
}
}
return otherType;
}
@Override
public void handleChange(ChangeEvent event) {
ExtensionAreaOptions options = (ExtensionAreaOptions) ((WritableValue) event
.getObservable()).getValue();
realizeOptions(options != null ? options : new ExtensionAreaOptions());
}
}
public WritableValue getObservableExtensionAreaOptions() {
return extensionAreaManager.observableOptions;
}
private class ExtensionAreaGeometryTask implements Callable<Geometry> {
ExtensionAreaOptions options;
GeospatialDataAccessor primaryGDA;
GeospatialDataAccessor extensionGDA;
public ExtensionAreaGeometryTask(ExtensionAreaOptions options,
GeospatialDataAccessor primaryGDA, GeospatialDataAccessor extensionGDA) {
if (! (options.getDistance() > 0)) {
throw new IllegalArgumentException("Extension distance must be greater than zero.");
}
this.options = options;
this.primaryGDA = primaryGDA;
this.extensionGDA = extensionGDA;
}
@Override
public Geometry call() throws Exception {
return createExtensionArea();
}
private Geometry createExtensionArea() throws Exception {
GeospatialData[] features = primaryGDA.geoData.getFeatures(false); // Never uses cwaStretch feactures.
Geometry[] g = new Geometry[features.length];
for (int i = 0; i < g.length; ++i) {
/*
* Pre-simplify as an optmization. Makes it possible to
* change the static extension distance in real time.
*/
g[i] = extensionSimplify(
convertGeom(features[i].geometry, primaryGDA.geoData.latLonToLocal),
options.getSimplificationTolerance()).
buffer(options.getDistance());
}
Geometry r = GeometryUtil.union(g);
r = createExtensionAreaFromLocal(r);
extensionAreaVis = extensionGDA.buildArea(r, false);
issueRefresh();
return r;
}
private Geometry createExtensionAreaFromLocal(Geometry geom) {
// geom should be simlified so that the following ops are not painful.
Geometry r = geom;
r = r.buffer(0);
r = extensionSimplify(r, options.getSimplificationTolerance());
r = convertGeom(r, primaryGDA.geoData.localToLatLon);
return r;
}
private Geometry extensionSimplify(Geometry geom, double tolerance) {
if (tolerance >= 0) {
geom = TopologyPreservingSimplifier.simplify(geom, tolerance);
}
return geom;
}
}
private static class GeomMetaDataUpdateNotificationObserver implements
@ -785,6 +1100,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
private GeomMetaDataUpdateNotificationObserver geomUpdateObserver;
private ExtensionAreaManager extensionAreaManager = new ExtensionAreaManager();
static {
for (int i = 0; i < 128; i++) {
if ((i % 32) == 0) {
@ -827,6 +1144,13 @@ public class WarngenLayer extends AbstractStormTrackResource {
setSpeedAndAngle();
setDuration();
observableExtensionAreaVisible.addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
issueRefresh();
}
});
}
@Override
@ -992,6 +1316,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
coveredAreaFrame = target.createWireframeShape(true, this.descriptor);
shadedCoveredArea = target.createShadedShape(true,
this.descriptor.getGridGeometry(), true);
extensionAreaShadedShape = target.createShadedShape(true,
this.descriptor.getGridGeometry());
}
/**
@ -1069,6 +1395,20 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
}
if ((Boolean) observableExtensionAreaVisible.getValue()) {
if (extensionAreaVis != null) {
extensionAreaShadedShape.reset();
JTSCompiler comp = new JTSCompiler(extensionAreaShadedShape, null, descriptor);
Geometry g = extensionAreaVis;
extensionAreaVis = null;
if (g != null) {
comp.handle(g, extensionAreaVisualizationColor);
}
}
target.drawShadedShape(extensionAreaShadedShape,
extensionAreaVisualizationAlpha);
}
lastMode = displayState.mode;
}
@ -1077,17 +1417,51 @@ public class WarngenLayer extends AbstractStormTrackResource {
displayState.intialFrame = trackUtil.getCurrentFrame(info);
}
/**
* @param target
* @param paintProps
* @param thePrimitivePolygon2
*/
private static class PolygonStyle {
public boolean show;
public RGB color;
public int lineWidth;
public boolean showVertices;
public PolygonStyle(boolean show, RGB color, int lineWidth, boolean showVertices) {
this.show = show;
this.color = color;
this.lineWidth = lineWidth;
this.showVertices = showVertices;
}
}
private static final String OUTPUT_POLYGON = "Result";
private static final String EDIT_POLYGON = "Edit";
private Polygon outputPolygon = null;
private Map<String, PolygonStyle> polygonStyles = new HashMap<String, PolygonStyle>();
{
polygonStyles.put(OUTPUT_POLYGON, new PolygonStyle(isWarngenDeveloperMode(),
new RGB(0, 128, 128), 5, true));
polygonStyles.put(EDIT_POLYGON, new PolygonStyle(true,
new RGB(255, 255, 255), 3, true));
}
private void paintPolygon(IGraphicsTarget target,
PaintProperties paintProps, Polygon thePrimitivePolygon)
throws VizException {
RGB color = getCapability(ColorableCapability.class).getColor();
float LINE_WIDTH = getCapability(OutlineCapability.class)
.getOutlineWidth();
if (outputPolygon != null) {
paintPolygon(target, paintProps, outputPolygon,
polygonStyles.get(OUTPUT_POLYGON));
}
PolygonStyle editStyle = polygonStyles.get(EDIT_POLYGON);
editStyle.color = getCapability(ColorableCapability.class).getColor();
editStyle.lineWidth = getCapability(OutlineCapability.class).getOutlineWidth();
paintPolygon(target, paintProps, thePrimitivePolygon, editStyle);
}
private void paintPolygon(IGraphicsTarget target,
PaintProperties paintProps, Polygon thePrimitivePolygon, PolygonStyle style)
throws VizException {
if (!style.show)
return;
RGB color = style.color;
float LINE_WIDTH = style.lineWidth;
float zoomLevel = paintProps.getZoomLevel();
if (LINE_WIDTH < 1.5f) {
LINE_WIDTH = 1.5f;
@ -1117,29 +1491,31 @@ public class WarngenLayer extends AbstractStormTrackResource {
line.width = LINE_WIDTH;
lines.add(line);
double delta;
if (style.showVertices) {
double delta;
if (!boxEditable) {
delta = 25 * zoomLevel;
} else {
delta = 80 * zoomLevel;
if (!boxEditable) {
delta = 25 * zoomLevel;
} else {
delta = 80 * zoomLevel;
}
// Build triangle control points
double[] triTop = new double[] { out1[0], out1[1] - delta };
double[] triLeft = new double[] { out1[0] - delta,
out1[1] + delta };
double[] triRight = new double[] { out1[0] + delta,
out1[1] + delta };
DrawableLine line2 = new DrawableLine();
line2.setCoordinates(triLeft[0], triLeft[1]);
line2.addPoint(triTop[0], triTop[1]);
line2.addPoint(triRight[0], triRight[1]);
line2.addPoint(triLeft[0], triLeft[1]);
line2.basics.color = color;
line2.width = LINE_WIDTH;
lines.add(line2);
}
// Build triangle control points
double[] triTop = new double[] { out1[0], out1[1] - delta };
double[] triLeft = new double[] { out1[0] - delta,
out1[1] + delta };
double[] triRight = new double[] { out1[0] + delta,
out1[1] + delta };
DrawableLine line2 = new DrawableLine();
line2.setCoordinates(triLeft[0], triLeft[1]);
line2.addPoint(triTop[0], triTop[1]);
line2.addPoint(triRight[0], triRight[1]);
line2.addPoint(triLeft[0], triLeft[1]);
line2.basics.color = color;
line2.width = LINE_WIDTH;
lines.add(line2);
}
target.drawLine(lines.toArray(new DrawableLine[0]));
}
@ -1210,6 +1586,51 @@ public class WarngenLayer extends AbstractStormTrackResource {
target.drawStrings(strings);
}
private Geometry extensionAreaVis;
private WritableValue observableExtensionAreaVisible = new WritableValue(false, null);
private RGB extensionAreaVisualizationColor = new RGB(240, 128, 128);
private float extensionAreaVisualizationAlpha = 0.4f;
private IShadedShape extensionAreaShadedShape = null;
public WritableValue getObservableExtensionAreaVisible() {
return observableExtensionAreaVisible;
}
public boolean isExtensionAreaVisible() {
return (Boolean) observableExtensionAreaVisible.getValue();
}
public void setExtensionAreaVisualized(boolean visible) {
observableExtensionAreaVisible.setValue(visible);
}
public RGB getExtensionAreaVisualizationColor() {
return extensionAreaVisualizationColor;
}
public void setExtensionAreaVisualizationColor(
RGB extensionAreaVisualizationColor) {
if (extensionAreaVisualizationColor == null) {
throw new NullPointerException("extensionAreaVisualizationColor must be non-null");
}
this.extensionAreaVisualizationColor = extensionAreaVisualizationColor;
issueRefresh();
}
public float getExtensionAreaVisualizationAlpha() {
return extensionAreaVisualizationAlpha;
}
public void setExtensionAreaVisualizationAlpha(
float extensionAreaVisualizationAlpha) {
this.extensionAreaVisualizationAlpha = extensionAreaVisualizationAlpha;
issueRefresh();
}
/**
* @param templateName
* the templateName to set
@ -1276,6 +1697,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
createAreaAndCentroidMaps();
this.configuration = config;
extensionAreaManager.setExtensionAreaConfig(config.getExtensionArea());
}// end synchronize
perfLog.logDuration("Init warngen config",
@ -1362,11 +1784,21 @@ public class WarngenLayer extends AbstractStormTrackResource {
GeospatialDataSet dataSet, GeospatialMetadata gmd, String currKey,
long tq0) throws FactoryException, MismatchedDimensionException,
TransformException {
gData.features = GeospatialFactory.getGeoSpatialList(dataSet, gmd);
GeospatialData[][] gdSets = GeospatialFactory.getGeoSpatialList(dataSet, gmd);
GeospatialData[] allFeatures;
gData.features = gdSets[0];
allFeatures = gData.features;
GeospatialData[] stretchFeatures = gdSets[1];
if (stretchFeatures != null) {
allFeatures = Arrays.copyOf(gData.features, gData.features.length + stretchFeatures.length);
System.arraycopy(stretchFeatures, 0, allFeatures, gData.features.length, stretchFeatures.length);
gData.cwaStretchFeatures = allFeatures;
}
// set the CountyUserData
List<Geometry> geoms = new ArrayList<Geometry>(gData.features.length);
for (GeospatialData gd : gData.features) {
List<Geometry> geoms = new ArrayList<Geometry>(allFeatures.length);
for (GeospatialData gd : allFeatures) {
geoms.add(gd.geometry);
CountyUserData cud = new CountyUserData(gd,
String.valueOf(gd.attributes.get(WarngenLayer.GID)));
@ -1381,7 +1813,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
.constructStereographic(MapUtil.AWIPS_EARTH_RADIUS,
MapUtil.AWIPS_EARTH_RADIUS, c.y, c.x));
gData.localToLatLon = gData.latLonToLocal.inverse();
for (GeospatialData gd : gData.features) {
for (GeospatialData gd : allFeatures) {
Geometry local = JTS.transform(gd.geometry, gData.latLonToLocal);
if (! local.isValid()) {
TopologyException topologyException = null;
@ -1502,8 +1934,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
GeospatialDataList geoDataList = getGeodataList(areaSource,
localizedSite);
if (geoDataList != null) {
return Arrays.copyOf(geoDataList.features,
geoDataList.features.length);
GeospatialData[] features = geoDataList.getFeatures(isCwaStretch());
return Arrays.copyOf(features, features.length);
}
return new GeospatialData[0];
}
@ -1725,7 +2157,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
throws Exception {
Set<String> ugcs = new HashSet<String>();
GeospatialDataAccessor gda = getGeospatialDataAcessor(type);
for (String fips : gda.getAllFipsInArea(gda.buildArea(polygon))) {
for (String fips : gda.getAllFipsInArea(gda.buildArea(polygon, isCwaStretch()))) {
ugcs.add(FipsUtil.getUgcFromFips(fips));
}
return ugcs;
@ -1735,7 +2167,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
// TODO: zig
GeospatialDataAccessor gda = getGeospatialDataAcessor(type);
Set<String> ugcs = new HashSet<String>();
for (GeospatialData r : gda.geoData.features) {
for (GeospatialData r : gda.geoData.getFeatures(isCwaStretch())) {
ugcs.add(FipsUtil.getUgcFromFips(gda.getFips(r)));
}
return ugcs;
@ -1875,7 +2307,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
if (includeAllEntries && !idsOutsidePolygon.isEmpty()) {
if (geoData != null) {
fipsOutsidePolygon = new HashSet<String>();
for (GeospatialData f : geoData.features) {
for (GeospatialData f : getActiveFeatures()) {
CountyUserData data = (CountyUserData) f.geometry
.getUserData();
String fips = String.valueOf(data.entry.attributes
@ -1916,7 +2348,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
* @return
*/
private Geometry getArea(Polygon polygon, Map<String, String[]> countyMap) {
return getArea(geoAccessor.buildArea(polygon), countyMap, true);
return getArea(geoAccessor.buildArea(polygon, isCwaStretch()), countyMap, true);
}
/**
@ -1973,7 +2405,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
latLonToLocal((snapHatchedAreaToPolygon || (warningArea == null)) ? warningPolygon
: warningArea), preservedSelection
&& (warningArea != null) ? latLonToLocal(warningArea)
: null);
: null,
isCwaStretch());
updateWarnedAreaState(newWarningArea, snapHatchedAreaToPolygon);
perfLog.logDuration("Determining hatchedArea",
@ -1991,7 +2424,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
* @return
*/
private Geometry createWarnedArea(Geometry hatchedArea,
Geometry preservedSelection) {
Geometry preservedSelection, boolean cwaStretch) {
Geometry oldWarningPolygon = latLonToLocal(state.getOldWarningPolygon());
Geometry oldWarningArea = latLonToLocal(state.getOldWarningArea());
Geometry newHatchedArea = null;
@ -2034,7 +2467,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
// Loop through each of our counties returned from the query
for (GeospatialData f : geoData.features) {
for (GeospatialData f : geoData.getFeatures(cwaStretch)) {
// get the geometry of the county and make sure it intersects
// with our hatched area
PreparedGeometry prepGeom = (PreparedGeometry) f.attributes
@ -2871,6 +3304,15 @@ public class WarngenLayer extends AbstractStormTrackResource {
updateWarnedAreas(true, true);
}
public void resetWarningPolygonAndAreaFromRecord(
AbstractWarningRecord record) throws VizException {
setOldWarningPolygon(record);
state.setWarningPolygon(getPolygon());
state.setWarningArea(getWarningAreaFromPolygon(
state.getWarningPolygon(), record));
updateWarnedAreas(true, true);
}
private DataTime recordFrameTime(AbstractWarningRecord warnRecord) {
Calendar frameTime;
String rawMessage = warnRecord.getRawmessage();
@ -3243,7 +3685,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
GeometryFactory gf = new GeometryFactory();
Point point = gf.createPoint(coord);
// potentially adding or removing a county, figure out county
for (GeospatialData f : geoData.features) {
for (GeospatialData f : getActiveFeatures()) {
Geometry geom = f.geometry;
if (f.prepGeom.contains(point)) {
Geometry newWarningArea;
@ -3326,7 +3768,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
boolean useFallback = getConfiguration().getHatchedAreaSource()
.isInclusionFallback();
for (GeospatialData f : geoData.features) {
for (GeospatialData f : getActiveFeatures()) {
String gid = GeometryUtil.getPrefix(f.geometry.getUserData());
Geometry warningAreaForFeature = getWarningAreaForGids(
Arrays.asList(gid), warningArea);
@ -3365,7 +3807,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
private Collection<GeospatialData> getDataWithFips(String fips) {
List<GeospatialData> data = new ArrayList<GeospatialData>();
for (GeospatialData d : geoData.features) {
for (GeospatialData d : getActiveFeatures()) {
if (fips.equals(getFips(d))) {
data.add(d);
}
@ -3405,7 +3847,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
String gid;
geomArea.clear();
geomCentroid.clear();
for (GeospatialData f : geoData.features) {
for (GeospatialData f : geoData.getFeatures(true)) {
Geometry geom = f.getGeometry();
gid = ((CountyUserData) geom.getUserData()).gid;
geomArea.put(gid, geom.getArea());
@ -3480,7 +3922,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
populatePt = new Coordinate(centroid.getX(), centroid.getY());
populatePtGeom = PolygonUtil.createPolygonByPoints(gf,
populatePt, shift);
for (GeospatialData gd : geoData.features) {
for (GeospatialData gd : getActiveFeatures()) {
geomN = gd.getGeometry();
CountyUserData cud = (CountyUserData) geomN.getUserData();
prefixN = cud.gid;
@ -3709,7 +4151,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
while (iter.hasNext()) {
prefix = iter.next();
double size = 0.0d;
for (GeospatialData f : geoData.features) {
for (GeospatialData f : getActiveFeatures()) {
fips = getFips(f);
Geometry geom = f.geometry;
if (prefix.equals(GeometryUtil.getPrefix(geom.getUserData()))) {
@ -3749,12 +4191,12 @@ public class WarngenLayer extends AbstractStormTrackResource {
* @param inputArea
* @return
*/
public Geometry buildIdealArea(Geometry inputArea) {
public Geometry buildIdealArea(Geometry inputArea, boolean stretch) {
Geometry localHatchedArea = latLonToLocal(inputArea);
Geometry oldWarningArea = latLonToLocal(state.getOldWarningArea());
Geometry newHatchedArea = null;
for (GeospatialData f : geoData.features) {
for (GeospatialData f : geoData.getFeatures(stretch)) {
// get the geometry of the county and make sure it intersects
// with our hatched area
PreparedGeometry prepGeom = (PreparedGeometry) f.attributes
@ -3844,4 +4286,20 @@ public class WarngenLayer extends AbstractStormTrackResource {
return backupOfficeLoc;
}
private GeospatialData[] getActiveFeatures() {
return geoData.getFeatures(isCwaStretch());
}
private boolean isCwaStretch() {
return dialog != null && dialog.isCwaStretchDamBulletSelected() &&
! isBoxEditable();
}
private static boolean warngenDeveloperMode =
Boolean.getBoolean("com.raytheon.viz.warngen.developerMode");
public static boolean isWarngenDeveloperMode() {
return warngenDeveloperMode;
}
}

View file

@ -740,10 +740,15 @@ public class TemplateRunner {
if (atIndex > 0) {
int hhmmStart = atIndex + 3;
hhmmEnd = message.indexOf(", ", hhmmStart);
if (hhmmEnd > 0) {
context.put("corToNewMarker", "cortonewmarker");
context.put("corEventtime",
message.substring(hhmmStart, hhmmEnd));
if (hhmmEnd < 0) {
// check for ellipsis
hhmmEnd = message.indexOf("...", hhmmStart);
} else {
if (hhmmEnd > 0) {
context.put("corToNewMarker", "cortonewmarker");
context.put("corEventtime",
message.substring(hhmmStart, hhmmEnd));
}
}
}
}

View file

@ -57,6 +57,7 @@ import com.raytheon.viz.hydrocommon.HydroConstants;
* 12 Aug 2014 3049 bkowal Close the BufferedReader when finished.
* 21 May 2015 4501 skorolev Changed a way of database connection. Got rid of Vector.
* 17 Sep 2015 4886 skorolev Corrected updateRejecteddata.
* 17 Dec 2015 18407 xwei Fixed: XDAT in Hydro Perspective allows user only to view 4 days instead of 30 days
*
* </pre>
*
@ -171,7 +172,7 @@ public class XdatDB {
for (Object[] obj : rs) {
hours.add((Integer) obj[0]);
}
if (hours != null && hours.size() > 1) {
if (hours != null && hours.size() >= 1) {
numHours = hours.get(0);
}
if (numHours > maxNumHours) {

View file

@ -756,21 +756,18 @@ public class Level3BaseRadar {
byte[] msg = new byte[120];
InputStream byt;
if (uncompressedSize + msg.length != theRawRadarByteArray.length) {
InputStream ins = null;
try {
theRadarData.reset();
theRadarData.readFully(msg);
ins = new BZip2InputStream(theRadarData, false);
uncompressed = new byte[uncompressedSize];
ins.read(uncompressed);
try (DataInputStream di = new DataInputStream(
new BZip2InputStream(theRadarData, false))) {
uncompressed = new byte[uncompressedSize];
di.readFully(uncompressed);
}
} catch (IOException e) {
theHandler.handle(Priority.ERROR,
"Error decompressing product: ", e);
return;
} finally {
if (ins != null) {
ins.close();
}
}
theRawRadarByteArray = new byte[120 + uncompressed.length];
System.arraycopy(msg, 0, theRawRadarByteArray, 0, 120);

View file

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.Timer;
@ -41,6 +42,9 @@ import java.util.concurrent.Future;
import javax.xml.bind.JAXBException;
import org.geotools.geometry.jts.JTS;
import org.opengis.referencing.operation.MathTransform;
import com.raytheon.edex.site.SiteUtil;
import com.raytheon.uf.common.dataplugin.warning.WarningConstants;
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration;
@ -58,6 +62,7 @@ import com.raytheon.uf.common.dataplugin.warning.util.StringUtil;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
import com.raytheon.uf.common.geospatial.ISpatialQuery.SearchMode;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.SpatialException;
import com.raytheon.uf.common.geospatial.SpatialQueryFactory;
import com.raytheon.uf.common.geospatial.SpatialQueryResult;
@ -82,8 +87,8 @@ import com.raytheon.uf.edex.database.cluster.ClusterLockUtils.LockState;
import com.raytheon.uf.edex.database.cluster.ClusterTask;
import com.raytheon.uf.edex.database.dao.CoreDao;
import com.raytheon.uf.edex.database.dao.DaoConfig;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
@ -114,6 +119,7 @@ import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
* Jun 26, 2015 17212 Qinglu Lin Removed features whose geometry is empty in queryGeospatialData(),
* caught exception in updateFeatures() & topologySimplifyQueryResults(),
* and added composeMessage().
* Dec 9, 2015 ASM# 18209 D. Friedman Support cwaStretch features outside CWA.
* </pre>
*
* @author rjpeter
@ -417,16 +423,28 @@ public class GeospatialDataGenerator {
if (generate) {
dataSet = new GeospatialDataSet();
GeospatialData[] areas = null;
GeospatialData[] primaryAreas = null;
GeospatialData[] stretchAreas = null;
// generate data
try {
areas = queryGeospatialData(site, metaData);
GeospatialData[][] areaArrays =
queryGeospatialData(site, metaData);
primaryAreas = areaArrays[0];
stretchAreas = areaArrays[1];
} catch (Exception e) {
throw new SpatialException(
"Unable to generate area geometries. Error occurred looking up geometries.",
e);
}
areas = new GeospatialData[primaryAreas.length
+ (stretchAreas != null ? stretchAreas.length : 0)];
System.arraycopy(primaryAreas, 0, areas, 0, primaryAreas.length);
if (stretchAreas != null) {
System.arraycopy(stretchAreas, 0, areas, primaryAreas.length, stretchAreas.length);
}
GeometryFactory gf = new GeometryFactory();
int size = areas.length;
Geometry[] geoms = new Geometry[size];
@ -446,7 +464,8 @@ public class GeospatialDataGenerator {
e);
}
dataSet.setAreas(areas);
dataSet.setAreas(primaryAreas);
dataSet.setCwaStretchAreas(stretchAreas);
// Get parent areas that intersect with cwa
try {
@ -525,6 +544,7 @@ public class GeospatialDataGenerator {
rval.setParentAreaSource(geoConfig.getParentAreaSource());
rval.setAreaNotationField(areaConfig.getAreaNotationField());
rval.setParentAreaField(areaConfig.getParentAreaField());
rval.setCwaStretch(areaConfig.getCwaStretch());
return rval;
}
@ -572,23 +592,16 @@ public class GeospatialDataGenerator {
return rval;
}
private GeospatialData[] queryGeospatialData(String site,
private GeospatialData[][] queryGeospatialData(String site,
GeospatialMetadata metaData) throws SpatialException,
InterruptedException, ExecutionException {
GeospatialData[] cwaStretchData = null;
String areaSource = metaData.getAreaSource();
HashMap<String, RequestConstraint> map = new HashMap<String, RequestConstraint>(
2);
String name = "cwa";
if (areaSource.equalsIgnoreCase(WarningConstants.MARINE)) {
name = "wfo";
}
map.put(name, new RequestConstraint(site, ConstraintType.LIKE));
List<String> areaFields = metaData.getAreaFields();
SpatialQueryResult[] features = SpatialQueryFactory.create().query(
areaSource, areaFields.toArray(new String[areaFields.size()]),
null, map, SearchMode.WITHIN);
String[] areaFieldsArray = areaFields.toArray(new String[areaFields.size()]);
SpatialQueryResult[] features = queryAreaFeatures(areaSource, site, ConstraintType.LIKE,
areaFieldsArray, null, SearchMode.WITHIN);
// clip against County Warning Area
if (!areaSource.equalsIgnoreCase(WarningConstants.MARINE)) {
@ -603,6 +616,12 @@ public class GeospatialDataGenerator {
cwaAreaFields.toArray(new String[cwaAreaFields
.size()]), null, cwaMap, SearchMode.WITHIN);
updateFeatures(features, cwaFeatures, areaSource);
if (metaData.getCwaStretch() != null
&& metaData.getCwaStretch() > 0) {
cwaStretchData = queryCwaStretchGeospatialData(site,
areaFieldsArray, cwaFeatures, metaData);
}
}
boolean emptyFeatureFound = false;
@ -627,8 +646,119 @@ public class GeospatialDataGenerator {
topologySimplifyQueryResults(features, areaSource);
// convert to GeospatialData
GeospatialData[] rval = new GeospatialData[features.length];
GeospatialData[] rval = convertToGeospatialData(features);
return new GeospatialData[][] { rval, cwaStretchData };
}
private SpatialQueryResult[] queryAreaFeatures(String areaSource, String site,
ConstraintType siteConstraint, String[] areaFields,
Geometry searchArea, SearchMode searchMode) throws SpatialException {
HashMap<String, RequestConstraint> map = new HashMap<String, RequestConstraint>(
2);
if (site != null) {
String name = "cwa";
if (areaSource.equalsIgnoreCase(WarningConstants.MARINE)) {
name = "wfo";
}
map.put(name, new RequestConstraint(site, ConstraintType.LIKE));
}
return SpatialQueryFactory.create().query(areaSource, areaFields,
searchArea, map, searchMode);
}
private GeospatialData[] queryCwaStretchGeospatialData(String site,
String[] areaFields, SpatialQueryResult[] cwaFeatures,
GeospatialMetadata metaData) throws SpatialException,
InterruptedException, ExecutionException {
/*
* Get bounding box (in local projection) of CWA and add a margin
* specified in kilometers by the cwaStretch value.
*/
String areaSource = metaData.getAreaSource();
ArrayList<Geometry> cwaFeatureGeoms = new ArrayList<Geometry>(
cwaFeatures.length);
for (SpatialQueryResult sqr : cwaFeatures) {
cwaFeatureGeoms.add(sqr.geometry);
}
Geometry cwaFeaturesGeometry = new GeometryFactory()
.buildGeometry(cwaFeatureGeoms);
Coordinate c = cwaFeaturesGeometry.getCentroid()
.getCoordinate();
Geometry stretchEnvelope = null;
try {
MathTransform latLonToLocal = MapUtil.getTransformFromLatLon(MapUtil
.constructStereographic(MapUtil.AWIPS_EARTH_RADIUS,
MapUtil.AWIPS_EARTH_RADIUS, c.y, c.x));
MathTransform localToLatLon = latLonToLocal.inverse();
Geometry g = JTS.transform(cwaFeaturesGeometry.getEnvelope(), latLonToLocal);
g = g.buffer(metaData.getCwaStretch() * 1000);
g = JTS.transform(g, localToLatLon);
stretchEnvelope = g;
} catch (Exception e) {
statusHandler
.handle(Priority.ERROR,
String.format(
"Error determining bound of CWA stretch area for site=%s, areaSource=%s",
site, areaSource), e);
return null;
}
/* Get all CWA geometries in the margin, excluding the primary CWA. */
String cwaSource = "cwa";
List<String> cwaAreaFields = new ArrayList<String>(Arrays.asList("wfo", "gid"));
HashMap<String, RequestConstraint> cwaMap = new HashMap<String, RequestConstraint>(2);
cwaMap.put("wfo", new RequestConstraint(site, ConstraintType.NOT_EQUALS));
SpatialQueryResult[] stretchCwaFeatures = SpatialQueryFactory
.create()
.query(cwaSource,
cwaAreaFields.toArray(new String[cwaAreaFields.size()]),
stretchEnvelope, cwaMap, SearchMode.INTERSECTS);
/* Group the geometries for each CWA together. */
HashMap<String, ArrayList<SpatialQueryResult>> stretchCwaFeaturesBySite = new HashMap<String, ArrayList<SpatialQueryResult>>();
for (SpatialQueryResult sqr : stretchCwaFeatures) {
String wfo = (String) sqr.attributes.get("wfo");
ArrayList<SpatialQueryResult> features = stretchCwaFeaturesBySite.get(wfo);
if (features == null) {
features = new ArrayList<SpatialQueryResult>();
stretchCwaFeaturesBySite.put(wfo, features);
}
features.add(sqr);
}
/*
* For each non-primary CWA, query the area features that are inside the
* margin.
*/
ArrayList<SpatialQueryResult> allFeatures = new ArrayList<SpatialQueryResult>();
for (Entry<String, ArrayList<SpatialQueryResult>> entry : stretchCwaFeaturesBySite.entrySet()) {
SpatialQueryResult[] features = queryAreaFeatures(areaSource,
entry.getKey(), ConstraintType.LIKE, areaFields,
stretchEnvelope, SearchMode.INTERSECTS);
updateFeatures(
features,
entry.getValue().toArray(
new SpatialQueryResult[entry.getValue().size()]),
areaSource);
for (SpatialQueryResult sqr : features) {
if (! sqr.geometry.isEmpty()) {
allFeatures.add(sqr);
}
}
}
SpatialQueryResult[] features = allFeatures
.toArray(new SpatialQueryResult[allFeatures.size()]);
topologySimplifyQueryResults(features, areaSource);
return convertToGeospatialData(features);
}
private GeospatialData[] convertToGeospatialData(SpatialQueryResult[] features) {
GeospatialData[] rval = new GeospatialData[features.length];
for (int i = 0; i < features.length; i++) {
SpatialQueryResult r = features[i];
GeospatialData data = new GeospatialData();
@ -636,7 +766,6 @@ public class GeospatialDataGenerator {
data.geometry = r.geometry;
rval[i] = data;
}
return rval;
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nwsRoleData xmlns:ns2="group">
<!-- AWIPS 2 WarnGen permissions file -->
<application>WarnGen</application>
<permission id="advancedOptions">
<description>
This permission allows the user to view advanced options in practice mode.
</description>
</permission>
</nwsRoleData>

View file

@ -24,6 +24,7 @@ import com.raytheon.uf.common.dataquery.requests.RequestableMetadataMarshaller;
* Mar 29, 2012 #14691 Qinglu Lin Added feAreaField and its getter and setter, etc.
* Apr 24, 2014 1943 jsanchez Removed unused areaType.
* Oct 23, 2013 DR 16632 D. Friedman Added inclusionFallback field.
* Dec 9, 2015 ASM #18209 D. Friedman Support cwaStretch.
*
* </pre>
*
@ -93,6 +94,9 @@ public class AreaSourceConfiguration {
@XmlElement
private boolean inclusionFallback = true;
@XmlElement
private Double cwaStretch;
public AreaSourceConfiguration() {
}
@ -283,4 +287,12 @@ public class AreaSourceConfiguration {
this.inclusionFallback = inclusionFallback;
}
public Double getCwaStretch() {
return cwaStretch;
}
public void setCwaStretch(Double cwaStretch) {
this.cwaStretch = cwaStretch;
}
}

View file

@ -31,6 +31,7 @@ import javax.xml.bind.annotation.XmlAttribute;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 24, 2011 jsanchez Initial creation
* Dec 9, 2015 ASM #18209 D. Friedman Support cwaStretch.
*
* </pre>
*
@ -43,6 +44,9 @@ public class DamInfoBullet extends Bullet {
@XmlAttribute
private String coords;
@XmlAttribute
private boolean cwaStretch;
public String getCoords() {
return coords;
}
@ -50,4 +54,12 @@ public class DamInfoBullet extends Bullet {
public void setCoords(String coords) {
this.coords = coords;
}
public boolean isCwaStretch() {
return cwaStretch;
}
public void setCwaStretch(boolean cwaStretch) {
this.cwaStretch = cwaStretch;
}
}

View file

@ -0,0 +1,51 @@
package com.raytheon.uf.common.dataplugin.warning.config;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
/**
* Describes how polygon is allowed to extend into a site's marine areas
* (for land-based warnings) or onto land (for marine-based warnings.)
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
@XmlAccessorType(XmlAccessType.NONE)
public class ExtensionArea implements Cloneable {
private double distance = Double.NaN;
private double simplificationTolerance = Double.NaN;
@XmlAttribute
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
@XmlAttribute(name="simplification")
public double getSimplificationTolerance() {
return simplificationTolerance;
}
public void setSimplificationTolerance(double simplificationTolerance) {
this.simplificationTolerance = simplificationTolerance;
}
public ExtensionArea clone() {
try {
return (ExtensionArea) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -62,6 +62,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* Oct 22, 2013 2361 njensen Removed ISerializableObject
* Apr 28, 2014 3033 jsanchez Properly handled back up configuration (*.xml) files.
* Aug 28, 2014 ASM #15658 D. Friedman Add marine zone watch wording option.
* Dec 21, 2015 DCS 17942 D. Friedman Add extension area specification.
* </pre>
*
* @author chammack
@ -154,6 +155,9 @@ public class WarngenConfiguration {
@XmlElement(name = "lockedGroupsOnFollowup")
private String lockedGroupsOnFollowup;
@XmlElement
private ExtensionArea extensionArea;
/**
* Method used to load a configuration file for a newly selected Warngen
* template.
@ -522,4 +526,12 @@ public class WarngenConfiguration {
this.hatchedAreaSource = hatchedAreaSource;
}
public ExtensionArea getExtensionArea() {
return extensionArea;
}
public void setExtensionArea(ExtensionArea extensionArea) {
this.extensionArea = extensionArea;
}
}

View file

@ -32,6 +32,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 15, 2011 rjpeter Initial creation
* Dec 9, 2015 ASM #18209 D. Friedman Support cwaStretch.
*
* </pre>
*
@ -49,6 +50,9 @@ public class GeospatialDataSet {
@DynamicSerializeElement
private GeospatialData[] timezones;
@DynamicSerializeElement
private GeospatialData[] cwaStretchAreas;
public GeospatialData[] getAreas() {
return areas;
}
@ -72,5 +76,13 @@ public class GeospatialDataSet {
public void setTimezones(GeospatialData[] timezones) {
this.timezones = timezones;
}
public GeospatialData[] getCwaStretchAreas() {
return cwaStretchAreas;
}
public void setCwaStretchAreas(GeospatialData[] cwaStretchAreas) {
this.cwaStretchAreas = cwaStretchAreas;
}
}

View file

@ -22,6 +22,7 @@ package com.raytheon.uf.common.dataplugin.warning.gis;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -68,6 +69,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
* Jun 17, 2014 DR 17390 Qinglu Lin Updated getMetaDataMap() for lonField and latField.
* Aug 21, 2014 3353 rferrel Generating Geo Spatial data set no longer on the UI thread.
* Feb 24, 2015 3978 njensen Use openInputStream() for reading file contents
* Dec 9, 2015 ASM #18209 D. Friedman Support cwaStretch.
*
* </pre>
*
@ -149,16 +151,27 @@ public class GeospatialFactory {
}
/**
* Convert the geospatial data set into array of geospatial data.
* Convert the geospatial data set into arrays of geospatial data.
* <p>The first array contains the primary features (i.e., those inside
* the CWA.) The second array, if not null, contains the extra
* (outside the CWA) features.
*
* @param dataSet
* @param metaData
* @return areas
*/
public static GeospatialData[] getGeoSpatialList(GeospatialDataSet dataSet,
public static GeospatialData[][] getGeoSpatialList(GeospatialDataSet dataSet,
GeospatialMetadata metaData) {
GeospatialData[] areas = dataSet.getAreas();
GeospatialData[] primaryAreas = dataSet.getAreas();
GeospatialData[] stretchAreas = dataSet.getCwaStretchAreas();
GeospatialData[] areas;
if (stretchAreas == null) {
areas = primaryAreas;
} else {
areas = Arrays.copyOf(primaryAreas, primaryAreas.length + stretchAreas.length);
System.arraycopy(stretchAreas, 0, areas, primaryAreas.length, stretchAreas.length);
}
GeospatialData[] parentAreas = dataSet.getParentAreas();
GeospatialData[] myTimeZones = dataSet.getTimezones();
if (myTimeZones != null && myTimeZones.length > 0) {
@ -193,7 +206,7 @@ public class GeospatialFactory {
data.prepGeom = PreparedGeometryFactory.prepare(data.geometry);
}
return areas;
return new GeospatialData[][] { primaryAreas, stretchAreas };
}
public static GeospatialData[] getTimezones() {
@ -274,6 +287,7 @@ public class GeospatialFactory {
gmd.setParentAreaSource(geoConfig.getParentAreaSource());
gmd.setAreaNotationField(asc.getAreaNotationField());
gmd.setParentAreaField(asc.getParentAreaField());
gmd.setCwaStretch(asc.getCwaStretch());
rval.put(asc.getAreaSource(), gmd);
}

View file

@ -39,6 +39,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 15, 2011 rjpeter Initial creation
* Dec 9, 2015 ASM #18209 D. Friedman Support cwaStretch.
*
* </pre>
*
@ -80,6 +81,10 @@ public class GeospatialMetadata {
@DynamicSerializeElement
private String timeZoneField;
@XmlAttribute
@DynamicSerializeElement
private Double cwaStretch;
public String getAreaSource() {
return areaSource;
}
@ -144,6 +149,14 @@ public class GeospatialMetadata {
this.fipsField = fipsField;
}
public Double getCwaStretch() {
return cwaStretch;
}
public void setCwaStretch(Double cwaStretch) {
this.cwaStretch = cwaStretch;
}
@Override
public int hashCode() {
final int prime = 31;
@ -165,6 +178,8 @@ public class GeospatialMetadata {
+ ((timeZoneField == null) ? 0 : timeZoneField.hashCode());
result = prime * result
+ ((timeZoneSource == null) ? 0 : timeZoneSource.hashCode());
result = prime * result
+ ((cwaStretch == null) ? 0 : cwaStretch.hashCode());
return result;
}
@ -212,6 +227,11 @@ public class GeospatialMetadata {
return false;
} else if (!timeZoneSource.equals(other.timeZoneSource))
return false;
if (cwaStretch == null) {
if (other.cwaStretch != null)
return false;
} else if (!cwaStretch.equals(other.cwaStretch))
return false;
return true;
}
}

View file

@ -37,6 +37,7 @@
##### use the 'fe_area' shapefile field for portions of state. This fixes
##### several DRs related to unique part-of-state codes, watch boxes, etc..
##### Bookbinder 10-30-2015 Added several additional fe_area codes and cleaned up watch logic.
##### Evan Bookbinder 12-01-2015 Fixed single column output
##############################################################################################################
#*
Mile Marker Test Code
@ -1702,11 +1703,11 @@ ${bulletLead}
##STRAIGHT LIST
#if($columns == 0)
#if($numMajorPoints == 1)
#capitalize(${strOutput}, 'FIRST')##
#capitalize(${strOutput}, 'FIRST')
#else
#if($count != $numMajorPoints)
#if(${count} == 1)
#capitalize(${strOutput}, 'FIRST')##
#capitalize(${strOutput}, 'FIRST')
#else
${strOutput}##
#end
@ -1718,12 +1719,14 @@ and ${strOutput}##
##ONE PER LINE
#elseif($columns == 1)
#if($count != $numMajorPoints && $numMajorPoints != 1)
#capitalize(${strOutput}, 'FIRST')...
#capitalize(${strOutput}, 'FIRST')
#elseif ($numMajorPoints == 1)
#capitalize(${strOutput}, 'FIRST').
#capitalize(${strOutput}, 'FIRST')
#else
and ${strOutput}.
and ${strOutput}
#end
##MULTIPLE COLUMNS
@ -1787,4 +1790,4 @@ ${time1}##
#if($time2 && $time1 != $time2)
/${time2}/##
#end
#end
#end

View file

@ -17,6 +17,7 @@
to determine what warning they are following up!)
Fixed Gauge reports source selection
Mike Dangelo 10-20-2015 Standard CTAs
Evan Bookbinder 12-7-2015 Fixed ambiguity with arroyo CTA and product type parse strings, and added satellite source
-->
@ -120,7 +121,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="general" bulletText="General (minor flooding)" bulletGroup="advType" bulletDefault="true" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="Urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="Hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="*********** PRIMARY CAUSE *********** " bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain (default)" bulletDefault="true" bulletGroup="ic" parseString=".ER."/>
@ -165,7 +166,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="ruralCTA" bulletText="Rural areas" parseString="COUNTRY ROADS, FARMLAND, AND OTHER LOW LYING SPOTS"/>
<bullet bulletName="stayAwayCTA" bulletText="Stay away" parseString="STAY AWAY OR BE SWEPT AWAY"/>
<bullet bulletName="lowSpotsCTA" bulletText="Low spots in hilly terrain" parseString="IN HILLY TERRAIN THERE ARE HUNDREDS OF LOW WATER CROSSINGS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS, STREAMS"/>
<bullet bulletName="burnAreasCTA" bulletText="Burn Areas" parseString="RECENTLY BURNED AREAS"/>
<bullet bulletName="camperSafetyCTA" bulletText="Camper/Hiker Safety" parseString="CAMPERS AND HIKERS"/>
<bullet bulletName="reportFloodingCTA" bulletText="Report flooding to law enforcement" parseString="REPORT FLOODING TO YOUR LOCAL LAW ENFORCEMENT"/>
@ -178,7 +179,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="general" bulletText="general (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE (locked) *****" bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -197,6 +198,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="public" bulletText="Public reported" bulletGroup="advSource" parseString="THE PUBLIC REPORTED"/>
<bullet bulletName="lawEnforcement" bulletText="Local law enforcement reported" bulletGroup="advSource" parseString="LOCAL LAW ENFORCEMENT REPORTED"/>
<bullet bulletName="emergencyManagement" bulletText="Emergency management reported" bulletGroup="advSource" parseString="EMERGENCY MANAGEMENT REPORTED"/>
<bullet bulletName="satelliteEstimates" bulletText="Satellite Estimates" bulletGroup="advSource" parseString="SATELLITE ESTIMATES"/>
<bullet bulletName="onlyGauge" bulletText="Gauge reports" bulletGroup="advSource" parseString="GAUGE REPORTS"/>
<bullet bulletText="*********** EVENT (choose one) *********** " bulletType="title"/>
<bullet bulletName="thunder" bulletText="Thunderstorm(s)" bulletGroup="advEvent" bulletDefault="true" parseString="&quot;THUNDERSTORM&quot;,&quot;-CAUSING&quot;,&quot;-RAPID RIVER RISES&quot;,&quot;-MINOR FLOODING OF POOR DRAINAGE&quot;"/>
@ -223,7 +225,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="ruralCTA" bulletText="Rural areas" parseString="COUNTRY ROADS, FARMLAND, AND OTHER LOW LYING SPOTS"/>
<bullet bulletName="stayAwayCTA" bulletText="Stay away" parseString="STAY AWAY OR BE SWEPT AWAY"/>
<bullet bulletName="lowSpotsCTA" bulletText="Low spots in hilly terrain" parseString="IN HILLY TERRAIN THERE ARE HUNDREDS OF LOW WATER CROSSINGS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS, STREAMS"/>
<bullet bulletName="burnAreasCTA" bulletText="Burn Areas" parseString="RECENTLY BURNED AREAS"/>
<bullet bulletName="camperSafetyCTA" bulletText="Camper/Hiker Safety" parseString="CAMPERS AND HIKERS"/>
<bullet bulletName="reportFloodingCTA" bulletText="Report flooding to law enforcement" parseString="REPORT FLOODING TO YOUR LOCAL LAW ENFORCEMENT"/>
@ -236,7 +238,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="general" bulletText="general (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE (locked) *****" bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -255,6 +257,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="public" bulletText="Public reported" bulletGroup="advSource" parseString="THE PUBLIC REPORTED"/>
<bullet bulletName="lawEnforcement" bulletText="Local law enforcement reported" bulletGroup="advSource" parseString="LOCAL LAW ENFORCEMENT REPORTED"/>
<bullet bulletName="emergencyManagement" bulletText="Emergency management reported" bulletGroup="advSource" parseString="EMERGENCY MANAGEMENT REPORTED"/>
<bullet bulletName="satelliteEstimates" bulletText="Satellite Estimates" bulletGroup="advSource" parseString="SATELLITE ESTIMATES"/>
<bullet bulletName="onlyGauge" bulletText="Gauge reports" bulletGroup="advSource" parseString="GAUGE REPORTS"/>
<bullet bulletText="*********** EVENT (choose one) *********** " bulletType="title"/>
<bullet bulletName="thunder" bulletText="Thunderstorm(s)" bulletGroup="advEvent" bulletDefault="true" parseString="&quot;THUNDERSTORM&quot;,&quot;-CAUSING&quot;,&quot;-RAPID RIVER RISES&quot;,&quot;-MINOR FLOODING OF POOR DRAINAGE&quot;"/>
@ -281,7 +284,7 @@ Must be paired with proper vm code (which are commented out in arealFloodAdvisor
<bullet bulletName="ruralCTA" bulletText="Rural areas" parseString="COUNTRY ROADS, FARMLAND, AND OTHER LOW LYING SPOTS"/>
<bullet bulletName="stayAwayCTA" bulletText="Stay away" parseString="STAY AWAY OR BE SWEPT AWAY"/>
<bullet bulletName="lowSpotsCTA" bulletText="Low spots in hilly terrain" parseString="IN HILLY TERRAIN THERE ARE HUNDREDS OF LOW WATER CROSSINGS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS, STREAMS"/>
<bullet bulletName="burnAreasCTA" bulletText="Burn Areas" parseString="RECENTLY BURNED AREAS"/>
<bullet bulletName="camperSafetyCTA" bulletText="Camper/Hiker Safety" parseString="CAMPERS AND HIKERS"/>
<bullet bulletName="reportFloodingCTA" bulletText="Report flooding to law enforcement" parseString="REPORT FLOODING TO YOUR LOCAL LAW ENFORCEMENT"/>

View file

@ -14,7 +14,8 @@
## Evan Bookbinder 9-4-2015 Fixed line of storms grammar ##
## Mike Dangelo 10-20-2015 Standard CTAs ##
## Phil Kurimski 10-21-2015 Back to the future day! Insert default end stmt ##
## Phil/Dave 10-20-2015 Added Canned statement for CAN
## Phil/Dave 10-20-2015 Added Canned statement for CAN ##
## Evan Bookbinder 12-7-2015 Added missing satellite source ##
#########################################################################################
#parse("config.vm")
#if(${action} == "EXT")
@ -151,6 +152,12 @@
#if(${list.contains(${bullets}, "public")} && ${list.contains(${bullets}, "plainRain")})
#set ($report = "the public reported ${cause} in !** LOCATION **! that will cause ${advTypeShort}${report2}")
#end
#if(${list.contains(${bullets}, "satelliteEstimates")})
#set($report = "satellite estimates indicate ${cause} in !** LOCATION **! that will cause ${advTypeShort}${report2}.")
#end
#if(${list.contains(${bullets}, "satelliteEstimates")} && ${list.contains(${bullets}, "thunder")})
#set($report = "satellite estimates indicate ${cause} from thunderstorms over !** LOCATION **! that will cause ${advTypeShort}${report2}.")
#end
#### added by GP
#if(${list.contains(${bullets}, "onlyGauge")})
#set ($report = "gauge reports indicated !**EVENT TYPE**!." )

View file

@ -17,6 +17,7 @@
to determine what warning they are following up!)
Mike Dangelo 10-20-2015 Standard CTAs
Phil/Dave 10-20-2015 Added Canned statement for CAN
Evan Bookbinder 12-7-2015 Fixed ambiguity with arroyo CTA and product type parse strings, and added satellite source
-->
<warngenConfig>
@ -105,7 +106,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="general" bulletText="General (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-HYDROLOGIC&quot;,&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="Urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO AND SMALL STREAM" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="Hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE ***** (locked) " bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -128,7 +129,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="general" bulletText="General (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-HYDROLOGIC&quot;,&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="Urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO AND SMALL STREAM" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="Hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE ***** (locked) " bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -151,7 +152,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="general" bulletText="General (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-HYDROLOGIC&quot;,&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="Urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO AND SMALL STREAM" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="Hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE ***** (locked) " bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -170,6 +171,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="public" bulletText="Public reported" bulletGroup="advSource" parseString="THE PUBLIC REPORTED"/>
<bullet bulletName="lawEnforcement" bulletText="Local law enforcement reported" bulletGroup="advSource" parseString="LOCAL LAW ENFORCEMENT REPORTED"/>
<bullet bulletName="emergencyManagement" bulletText="Emergency management reported" bulletGroup="advSource" parseString="EMERGENCY MANAGEMENT REPORTED"/>
<bullet bulletName="satelliteEstimates" bulletText="Satellite Estimates" bulletGroup="advSource" parseString="SATELLITE ESTIMATES"/>
<bullet bulletName="onlyGauge" bulletText="Gauge reports" bulletGroup="advSource" parseString="GAUGE REPORTS"/>
<bullet bulletText="*********** EVENT (choose one) *********** " bulletType="title"/>
<bullet bulletName="thunder" bulletText="Thunderstorm(s)" bulletGroup="advEvent" parseString="&quot;THUNDERSTORM&quot;,&quot;-CAUSING&quot;,&quot;-RAPID RIVER RISES&quot;,&quot;-MINOR FLOODING OF POOR DRAINAGE&quot;"/>
@ -196,7 +198,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="ruralCTA" bulletText="Rural areas" parseString="COUNTRY ROADS, FARMLAND, AND OTHER LOW LYING SPOTS"/>
<bullet bulletName="stayAwayCTA" bulletText="Stay away" parseString="STAY AWAY OR BE SWEPT AWAY"/>
<bullet bulletName="lowSpotsCTA" bulletText="Low spots in hilly terrain" parseString="IN HILLY TERRAIN THERE ARE HUNDREDS OF LOW WATER CROSSINGS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS, STREAMS"/>
<bullet bulletName="burnAreasCTA" bulletText="Burn Areas" parseString="RECENTLY BURNED AREAS"/>
<bullet bulletName="camperSafetyCTA" bulletText="Camper/Hiker Safety" parseString="CAMPERS AND HIKERS"/>
<bullet bulletName="reportFloodingCTA" bulletText="Report flooding to law enforcement" parseString="REPORT FLOODING TO YOUR LOCAL LAW ENFORCEMENT"/>
@ -209,7 +211,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="general" bulletText="General (minor flooding)" bulletGroup="advType" parseString="&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;" showString="&quot;-HYDROLOGIC&quot;,&quot;-ARROYO&quot;,&quot;-SMALL STREAM FLOOD ADVISORY&quot;,&quot;FLOOD ADVISORY&quot;"/>
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;" showString="&quot;-URBAN AND&quot;,&quot;-ARROYO&quot;,&quot;SMALL STREAM FLOOD ADVISORY&quot;"/>
<bullet bulletName="uss" bulletText="Urban and small stream" bulletGroup="advType" parseString="URBAN AND SMALL STREAM FLOOD ADVISORY" showString="URBAN AND SMALL STREAM FLOOD ADVISORY"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO" showString="ARROYO"/>
<bullet bulletName="arroyo" bulletText="Arroyo and small stream" bulletGroup="advType" parseString="ARROYO AND SMALL STREAM" showString="ARROYO AND SMALL STREAM"/>
<bullet bulletName="hydrologic" bulletText="Hydrologic" bulletGroup="advType" parseString="HYDROLOGIC ADVISORY" showString="HYDROLOGIC ADVISORY"/>
<bullet bulletText="***** PRIMARY CAUSE ***** (locked) " bulletType="title"/>
<bullet bulletName="ER" bulletText="Excessive rain" bulletGroup="ic" parseString=".ER." showString=".ER."/>
@ -225,6 +227,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="public" bulletText="Public reported" bulletGroup="advSource" parseString="THE PUBLIC REPORTED"/>
<bullet bulletName="lawEnforcement" bulletText="Local law enforcement reported" bulletGroup="advSource" parseString="LOCAL LAW ENFORCEMENT REPORTED"/>
<bullet bulletName="emergencyManagement" bulletText="Emergency management reported" bulletGroup="advSource" parseString="EMERGENCY MANAGEMENT REPORTED"/>
<bullet bulletName="satelliteEstimates" bulletText="Satellite Estimates" bulletGroup="advSource" parseString="SATELLITE ESTIMATES"/>
<bullet bulletName="onlyGauge" bulletText="Gauge reports" bulletGroup="advSource" parseString="GAUGE REPORTS"/>
<bullet bulletText="*********** EVENT (choose one) *********** " bulletType="title"/>
<bullet bulletName="thunder" bulletText="Thunderstorm(s)" bulletGroup="advEvent" parseString="&quot;THUNDERSTORM&quot;,&quot;-CAUSING&quot;,&quot;-RAPID RIVER RISES&quot;,&quot;-MINOR FLOODING OF POOR DRAINAGE&quot;"/>
@ -253,7 +256,7 @@ Must be paired with proper vm code (also commented out in arealFloodAdvisoryFoll
<bullet bulletName="ruralCTA" bulletText="Rural areas" parseString="COUNTRY ROADS, FARMLAND, AND OTHER LOW LYING SPOTS"/>
<bullet bulletName="stayAwayCTA" bulletText="Stay away" parseString="STAY AWAY OR BE SWEPT AWAY"/>
<bullet bulletName="lowSpotsCTA" bulletText="Low spots in hilly terrain" parseString="IN HILLY TERRAIN THERE ARE HUNDREDS OF LOW WATER CROSSINGS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS"/>
<bullet bulletName="arroyosCTA" bulletText="Arroyos" parseString="ARROYOS, STREAMS"/>
<bullet bulletName="burnAreasCTA" bulletText="Burn Areas" parseString="RECENTLY BURNED AREAS"/>
<bullet bulletName="camperSafetyCTA" bulletText="Camper/Hiker Safety" parseString="CAMPERS AND HIKERS"/>
<bullet bulletName="reportFloodingCTA" bulletText="Report flooding to law enforcement" parseString="REPORT FLOODING TO YOUR LOCAL LAW ENFORCEMENT"/>

View file

@ -6,6 +6,7 @@
Phil Kurimski 09-19-2013 added geospatialConfig.xml
Phil Kurimski 06-26-2014 added DSS Events
Phil Kurimski 02-18-2015 Updated CTA section
Evan Bookbinder 12/07/15 Updated CTA to remove ellipses in parseString to match product.
-->
<!-- INCLUDE ALL GEOSPTATIAL INFORMATION FOR THIS PRODUCT
@ -187,7 +188,7 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletText=" ****** CALLS TO ACTION (CHOOSE 1 OR MORE) ****** " bulletType="title"/>
<bullet bulletName="genericCTA" bulletText="Generic CTA" parseString="MOVE TO SAFE HARBOR UNTIL HAZARDOUS WEATHER PASSES"/>
<bullet bulletName="gustyWindsCTA" bulletText="Gusty Winds CTA" parseString="MOVE TO SAFE HARBOR IMMEDIATELY AS GUSTY WINDS AND HIGH WAVES ARE EXPECTED"/>
<bullet bulletName="hailWindsCTA" bulletText="Wind/Hail cta with hail/wind speeds" parseString="DANGEROUS LIGHTNING...AND HEAVY RAIN ARE POSSIBLE"/>
<bullet bulletName="hailWindsCTA" bulletText="Wind/Hail cta with hail/wind speeds" parseString="DANGEROUS LIGHTNING, AND HEAVY RAIN ARE POSSIBLE"/>
<bullet bulletName="nonThunderstormCTA" bulletText="Non thunderstorm winds - mariners can expect gusty winds.." parseString="MARINERS CAN EXPECT GUSTY WINDS AND INCREASING WAVES"/>
<bullet bulletName="waterspoutCTA" bulletText="Waterspout CTA" parseString="CREATE LOCALLY HAZARDOUS SEAS. SEEK SAFE HARBOR IMMEDIATELY"/>
<bullet bulletName="lightningCTA" bulletText="Frequent lightning CTA" parseString="FREQUENT LIGHTNING IS OCCURRING WITH"/>
@ -246,7 +247,7 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletText=" ****** CALLS TO ACTION (CHOOSE 1 OR MORE) ****** " bulletType="title"/>
<bullet bulletName="genericCTA" bulletText="Generic CTA" parseString="MOVE TO SAFE HARBOR UNTIL HAZARDOUS WEATHER PASSES"/>
<bullet bulletName="gustyWindsCTA" bulletText="Gusty Winds CTA" parseString="MOVE TO SAFE HARBOR IMMEDIATELY AS GUSTY WINDS AND HIGH WAVES ARE EXPECTED"/>
<bullet bulletName="hailWindsCTA" bulletText="Wind/Hail cta with hail/wind speeds" parseString="DANGEROUS LIGHTNING...AND HEAVY RAIN ARE POSSIBLE"/>
<bullet bulletName="hailWindsCTA" bulletText="Wind/Hail cta with hail/wind speeds" parseString="DANGEROUS LIGHTNING, AND HEAVY RAIN ARE POSSIBLE"/>
<bullet bulletName="nonThunderstormCTA" bulletText="Non thunderstorm winds - mariners can expect gusty winds.." parseString="MARINERS CAN EXPECT GUSTY WINDS AND INCREASING WAVES"/>
<bullet bulletName="waterspoutCTA" bulletText="Waterspout CTA" parseString="CREATE LOCALLY HAZARDOUS SEAS. SEEK SAFE HARBOR IMMEDIATELY"/>
<bullet bulletName="lightningCTA" bulletText="Frequent lightning CTA" parseString="FREQUENT LIGHTNING IS OCCURRING WITH"/>

View file

@ -1,9 +1,9 @@
#############################################################################
## IMPACT-BASED TORNADO WARNING TEMPLATE ##
## CREATED BY PHIL KURIMSKI - WFO GRB ##
## UPDATED -- 2-04-2012 OB13.2.1-5 impact stmts ##
## UPDATED -- Bookbinder 2/22/13 2013 IBW Changes ##
## UPDATED -- Kurimski 5/20/13 Addl IBW Changes ##
## CREATED BY PHIL KURIMSKI - WFO GRB ##
## UPDATED -- 2-04-2012 OB13.2.1-5 impact stmts ##
## UPDATED -- Bookbinder 2/22/13 2013 IBW Changes ##
## UPDATED -- Kurimski 5/20/13 Addl IBW Changes ##
## UPDATED -- Kurimski 9/17/13 Tor Emer Headline ##
## UPDATED -- Bookbinder 9/18/2013 implement config.vm ##
## UPDATED -- Dangelo 1/24/2014 added logic to keep defaultCTAs from being ##
@ -15,6 +15,7 @@
## UPDATED -- Bookbinder 6/15/15 Fixed softball and grapefruit hail sizes ##
## UPDATED -- Phil Kurimski 10-20-2015 Added waterspout option to basis ##
## Bookbinder 10-20-2015 Fixed extraSource var for tornado info ##
## Bookbinder 12-07-15 fixed lowercase preAmble on lne 283 ##
#############################################################################
## NOTE: Impact Statements for IBW templates are contained in impactStatements.vm
################################################################
@ -280,7 +281,7 @@ This is a test message. ##
#set($pathcastLead = "The tornado")
#set($moveLead = " Doppler radar showed this tornado moving")
#end
#set($preAmble = "to repeat, a large, extremely dangerous and potentially deadly tornado is on the ground. to protect your life, ")
#set($preAmble = "To repeat, a large, extremely dangerous and potentially deadly tornado is on the ground. to protect your life, ")
#end
*#
#if(${list.contains(${bullets}, "spotter")})

View file

@ -11,13 +11,13 @@
Phil Kurimski 05-20-2013 Added selection for very weak tornadoes and landspouts
Phil Kurimski 09-19-2013 added geospatialConfig.xml
Mike Dangelo 1/23/2014 changed parseString for defaultCTAs to match iTW.vm statements,
removed cta1 bulletGroup from COR to ensure it is selected when doing a COR for a torEMER
Evan Bookbinder 2-18-2014 added dssEvents hook, 2014 IBW impacts
Evan Bookbinder 10-24-2014 Fixed parse strings for Base TOR option for COR
Fixed parseString for SqLn embedded TOR for COR
Tomalak 3-24-2015 Converted Upper to Mixed Case for Impacts
Evan Bookbinder 6-15-2015 Fixed incorrect softball and grapefruit hail sizes
Phil Kurimski 10-20-2015 Added waterspout option to basis
Evan Bookbinder 12-7-2015 Added TOR EMER CTA back into cta1 bullet group (undid 1/23/2014 change)
-->
<warngenConfig>
@ -210,7 +210,7 @@ do not have mobile homes. If you wish to switch defaults or provide a single opt
<bullet bulletName="specialEvent" bulletText="Special heads-up for large event/venue" parseString="THOSE ATTENDING"/>
<bullet bulletText="" bulletType="title"/>
<bullet bulletText="*********** CALLS TO ACTION (CHOOSE 1 OR MORE) **********" bulletType="title"/>
<bullet bulletName="torEmergencyCTA" bulletText="**TOR EMERGENCY CTA** (CATASTROPHIC Tag use only)" parseString="TORNADO EMERGENCY"/>
<bullet bulletName="torEmergencyCTA" bulletText="**TOR EMERGENCY CTA** (CATASTROPHIC Tag use only)" parseString="TORNADO EMERGENCY" bulletGroup="cta1"/>
<bullet bulletName="replacesSVRCTA" bulletText="TOR Replaces Severe Thunderstorm Warning" parseString="TORNADO WARNING REPLACES THE SEVERE"/>
<!-- There are two "default" safety rules. The first...which will probably be used by most offices...includes safety rules for mobile homes. The second...which is commented out...is for large urban areas that
do not have mobile homes. If you wish to switch defaults or provide a single option, add comment tags as necessary and adjust the bulletDefault="true" as appropriate if both options are allowed -->

View file

@ -1,20 +1,21 @@
#####################################################
## DAM BREAK FFW FOLLOW-UP ##
## CREATED BY PHIL KURIMSKI - WFO DTX ##
## VERSION AWIPS II 1.0 -- APR 14 2011 OB11.4 ##
## -- JUL 14 2011 OB11.7 ##
## -- AUG 18 2011 OB11.0.8-4 ##
## Evan Bookbinder -- SEP 16 2011 OB11.0.8-8 ##
## Phil Kurimski -- SEP 23 2011 OB11.0.8-8 ##
## Mike Rega -- MAY 03 2012 DR 14885 MND ##
## Phil Kurimski -- FEB 08 2013 CTA stmnts ##
## Phil Kurimski -- SEP 17 2013 FFW Emerg ##
## Mike Rega -- JAN 18 2014 14.2.1 ##
## added Alaska GP changes ##
## Evan Bookbinder -- Oct 24 2014 Fixed floodSeverity code
## Phil Kurimski -- Mar 25 2015 Mixed Case ##
## Mike Dangelo -- 10-21-2015 added SM-only option
#####################################################
##################################################################
## DAM BREAK FFW FOLLOW-UP ##
## CREATED BY PHIL KURIMSKI - WFO GRB ##
## VERSION AWIPS II 1.0 -- APR 14 2011 OB11.4 ##
## -- JUL 14 2011 OB11.7 ##
## -- AUG 18 2011 OB11.0.8-4 ##
## Evan Bookbinder -- SEP 16 2011 OB11.0.8-8 ##
## Phil Kurimski -- SEP 23 2011 OB11.0.8-8 ##
## Mike Rega -- MAY 03 2012 DR 14885 MND ##
## Phil Kurimski -- FEB 08 2013 CTA stmnts ##
## Phil Kurimski -- SEP 17 2013 FFW Emerg ##
## Mike Rega -- JAN 18 2014 14.2.1 ##
## added Alaska GP changes ##
## Evan Bookbinder -- Oct 24 2014 Fixed floodSeverity code ##
## Phil Kurimski -- Mar 25 2015 Mixed Case ##
## Mike Dangelo -- 10-21-2015 added SM-only option ##
## Evan Bookbinder -- 12-7-2015 Baselined CTAs ##
##################################################################
##
#parse("config.vm")
#set($headline = "")
@ -366,29 +367,37 @@ Move to higher ground now! This is an extremely dangerous and life-threatening s
!** YOU SELECTED THE FLASH FLOOD EMERGENCY CTA WITHOUT SELECTING THE FLASH FLOOD EMERGENCY HEADER. PLEASE CLOSE THIS WINDOW AND RE-GENERATE THIS WARNING **!
#end
#end
#if(${list.contains(${bullets}, "TADD_CTA")})
Turn around, don't drown when encountering flooded roads. Most flood deaths occur in vehicles.
#end
#if(${list.contains(${bullets}, "actQuicklyCTA")})
Move to higher ground now! Act quickly to protect your life.
Move to higher ground now. Act quickly to protect your life.
#end
#if(${list.contains(${bullets}, "childSafetyCTA")})
Keep children away from storm drains, culverts, creeks, and streams. Water levels can rise rapidly and sweep children away.
Keep children away from storm drains, culverts, creeks and streams. Water levels can rise rapidly and sweep children away.
#end
#if(${list.contains(${bullets}, "nighttimeCTA")})
Be especially cautious at night when it is harder to recognize the dangers of flooding.
#end
#if(${list.contains(${bullets}, "safetyCTA")})
Do not enter or cross flowing water or water of unknown depth.
#if(${list.contains(${bullets}, "urbanCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, urban areas, highways, streets and underpasses as well as other drainage areas and low lying spots.
#end
#if(${list.contains(${bullets}, "ruralCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, country roads, farmland, and other low lying spots.
#end
#if(${list.contains(${bullets}, "stayAwayCTA")})
Stay away or be swept away. River banks and culverts can become unstable and unsafe.
#end
#if(${list.contains(${bullets}, "turnAroundCTA")})
If you encounter flooded roads, Turn Around, Don't Drown! Most flood deaths occur in vehicles.
#if(${list.contains(${bullets}, "lowSpotsCTA")})
In hilly terrain there are hundreds of low water crossings which are potentially dangerous in heavy rain. Do not attempt to cross flooded roads. Find an alternate route.
#end
#if(${list.contains(${bullets}, "arroyosCTA")})
@ -396,15 +405,24 @@ Remain alert for flooding even in locations not receiving rain. Arroyos, streams
#end
#if(${list.contains(${bullets}, "burnAreasCTA")})
Move away from recently burned areas. Life-threatening flooding of creeks, roads, and normally dry arroyos is likely. The heavy rains will likely trigger rockslides...mudslides and debris flows in steep terrain...especially in and around these areas.
Move away from recently burned areas. Life-threatening flooding of creeks, roads and normally dry arroyos is likely. The heavy rains will likely trigger rockslides, mudslides and debris flows in steep terrain, especially in and around these areas.
#end
#if(${list.contains(${bullets}, "camperSafetyCTA")})
Flooding is occurring or is imminent. It is important to know where you are relative to streams, rivers, or creeks which can become killers in heavy rains. Campers and hikers should avoid streams or creeks.
#end
#if(${list.contains(${bullets}, "reportFloodingCTA")})
Please report to your local law enforcement agency when you can do so safely.
Please report flooding to your local law enforcement agency when you can do so safely.
#end
#if(${ctaSelected} == "YES")
#if(${list.contains(${bullets}, "ffwMeansCTA")})
A Flash Flood Warning means that flooding is imminent or occurring. If you are in the warned area move to higher ground immediately. Residents living along streams and creeks should take immediate precautions to protect life and property.
#end
#if(${ctaSelected} == "YES")
&&
#end
#end
@ -626,29 +644,37 @@ Move to higher ground now! This is an extremely dangerous and life-threatening s
!** YOU SELECTED THE FLASH FLOOD EMERGENCY CTA WITHOUT SELECTING THE FLASH FLOOD EMERGENCY HEADER. PLEASE CLOSE THIS WINDOW AND RE-GENERATE THIS WARNING **!
#end
#end
#if(${list.contains(${bullets}, "TADD_CTA")})
Turn around, don't drown when encountering flooded roads. Most flood deaths occur in vehicles.
#end
#if(${list.contains(${bullets}, "actQuicklyCTA")})
Move to higher ground now! Act quickly to protect your life.
Move to higher ground now. Act quickly to protect your life.
#end
#if(${list.contains(${bullets}, "childSafetyCTA")})
Keep children away from storm drains, culverts, creeks, and streams. Water levels can rise rapidly and sweep children away.
Keep children away from storm drains, culverts, creeks and streams. Water levels can rise rapidly and sweep children away.
#end
#if(${list.contains(${bullets}, "nighttimeCTA")})
Be especially cautious at night when it is harder to recognize the dangers of flooding.
#end
#if(${list.contains(${bullets}, "safetyCTA")})
Do not enter or cross flowing water or water of unknown depth.
#if(${list.contains(${bullets}, "urbanCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, urban areas, highways, streets and underpasses as well as other drainage areas and low lying spots.
#end
#if(${list.contains(${bullets}, "ruralCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, country roads, farmland, and other low lying spots.
#end
#if(${list.contains(${bullets}, "stayAwayCTA")})
Stay away or be swept away. River banks and culverts can become unstable and unsafe.
#end
#if(${list.contains(${bullets}, "turnAroundCTA")})
If you encounter flooded roads, Turn Around, Don't Drown! Most flood deaths occur in vehicles.
#if(${list.contains(${bullets}, "lowSpotsCTA")})
In hilly terrain there are hundreds of low water crossings which are potentially dangerous in heavy rain. Do not attempt to cross flooded roads. Find an alternate route.
#end
#if(${list.contains(${bullets}, "arroyosCTA")})
@ -656,15 +682,24 @@ Remain alert for flooding even in locations not receiving rain. Arroyos, streams
#end
#if(${list.contains(${bullets}, "burnAreasCTA")})
Move away from recently burned areas. Life-threatening flooding of creeks, roads, and normally dry arroyos is likely. The heavy rains will likely trigger rockslides...mudslides and debris flows in steep terrain...especially in and around these areas.
Move away from recently burned areas. Life-threatening flooding of creeks, roads and normally dry arroyos is likely. The heavy rains will likely trigger rockslides, mudslides and debris flows in steep terrain, especially in and around these areas.
#end
#if(${list.contains(${bullets}, "camperSafetyCTA")})
Flooding is occurring or is imminent. It is important to know where you are relative to streams, rivers, or creeks which can become killers in heavy rains. Campers and hikers should avoid streams or creeks.
#end
#if(${list.contains(${bullets}, "reportFloodingCTA")})
Please report to your local law enforcement agency when you can do so safely.
Please report flooding to your local law enforcement agency when you can do so safely.
#end
#if(${ctaSelected} == "YES")
#if(${list.contains(${bullets}, "ffwMeansCTA")})
A Flash Flood Warning means that flooding is imminent or occurring. If you are in the warned area move to higher ground immediately. Residents living along streams and creeks should take immediate precautions to protect life and property.
#end
#if(${ctaSelected} == "YES")
&&
#end
#elseif(${CORCAN}=="true")
@ -866,29 +901,37 @@ Move to higher ground now! This is an extremely dangerous and life-threatening s
!** YOU SELECTED THE FLASH FLOOD EMERGENCY CTA WITHOUT SELECTING THE FLASH FLOOD EMERGENCY HEADER. PLEASE CLOSE THIS WINDOW AND RE-GENERATE THIS WARNING **!
#end
#end
#if(${list.contains(${bullets}, "TADD_CTA")})
Turn around, don't drown when encountering flooded roads. Most flood deaths occur in vehicles.
#end
#if(${list.contains(${bullets}, "actQuicklyCTA")})
Move to higher ground now! Act quickly to protect your life.
Move to higher ground now. Act quickly to protect your life.
#end
#if(${list.contains(${bullets}, "childSafetyCTA")})
Keep children away from storm drains, culverts, creeks, and streams. Water levels can rise rapidly and sweep children away.
Keep children away from storm drains, culverts, creeks and streams. Water levels can rise rapidly and sweep children away.
#end
#if(${list.contains(${bullets}, "nighttimeCTA")})
Be especially cautious at night when it is harder to recognize the dangers of flooding.
#end
#if(${list.contains(${bullets}, "safetyCTA")})
Do not enter or cross flowing water or water of unknown depth.
#if(${list.contains(${bullets}, "urbanCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, urban areas, highways, streets and underpasses as well as other drainage areas and low lying spots.
#end
#if(${list.contains(${bullets}, "ruralCTA")})
Excessive runoff from heavy rainfall will cause flooding of small creeks and streams, country roads, farmland, and other low lying spots.
#end
#if(${list.contains(${bullets}, "stayAwayCTA")})
Stay away or be swept away. River banks and culverts can become unstable and unsafe.
#end
#if(${list.contains(${bullets}, "turnAroundCTA")})
If you encounter flooded roads, Turn Around, Don't Drown! Most flood deaths occur in vehicles.
#if(${list.contains(${bullets}, "lowSpotsCTA")})
In hilly terrain there are hundreds of low water crossings which are potentially dangerous in heavy rain. Do not attempt to cross flooded roads. Find an alternate route.
#end
#if(${list.contains(${bullets}, "arroyosCTA")})
@ -896,15 +939,24 @@ Remain alert for flooding even in locations not receiving rain. Arroyos, streams
#end
#if(${list.contains(${bullets}, "burnAreasCTA")})
Move away from recently burned areas. Life-threatening flooding of creeks, roads, and normally dry arroyos is likely. The heavy rains will likely trigger rockslides...mudslides and debris flows in steep terrain...especially in and around these areas.
Move away from recently burned areas. Life-threatening flooding of creeks, roads and normally dry arroyos is likely. The heavy rains will likely trigger rockslides, mudslides and debris flows in steep terrain, especially in and around these areas.
#end
#if(${list.contains(${bullets}, "camperSafetyCTA")})
Flooding is occurring or is imminent. It is important to know where you are relative to streams, rivers, or creeks which can become killers in heavy rains. Campers and hikers should avoid streams or creeks.
#end
#if(${list.contains(${bullets}, "reportFloodingCTA")})
Please report to your local law enforcement agency when you can do so safely.
Please report flooding to your local law enforcement agency when you can do so safely.
#end
#if(${ctaSelected} == "YES")
#if(${list.contains(${bullets}, "ffwMeansCTA")})
A Flash Flood Warning means that flooding is imminent or occurring. If you are in the warned area move to higher ground immediately. Residents living along streams and creeks should take immediate precautions to protect life and property.
#end
#if(${ctaSelected} == "YES")
&&
#end
#end

View file

@ -18,6 +18,7 @@
## Mike Dangelo 26 Mar 2015 Mixed Case edits ##
## Evan Bookbinder 9/4/2015 fixed line of storms grammar as well as ##
## softball/grapefruit hail sizes (& MMD 10/20/15) ##
## Evan Bookbinder 12/7/2015 fixed typo in 'law enforcement' ##
################################################################################
##
###################################################################
@ -778,7 +779,7 @@ A large and extremely dangerous tornado is on the ground. Take immediate tornado
#end
#if(${list.contains(${bullets}, "lawEnforcementTORCTA")})
If a tornado or other severe weather is spotted report it to the National Weather Service or your nearest law enforecement agency who will relay your report. This act may save the lives of others in the path of dangerous weather.
If a tornado or other severe weather is spotted report it to the National Weather Service or your nearest law enforcement agency who will relay your report. This act may save the lives of others in the path of dangerous weather.
#end
#if(${list.contains(${bullets}, "squallCTA")} && ${stormType} == "line")

View file

@ -1,6 +1,6 @@
################################################################################
## TORNADO WARNING TEMPLATE ##
## VERSION AWIPS II ##
## VERSION AWIPS II ##
## RECENT CHANGES ##
## Mike Dangelo 9-13-2012 minor tweaks to ${variables} ##
## Mike Dangelo 2-4-2013 NWS Mets detected a svr ##
@ -14,11 +14,12 @@
## SVS parseString, prevented largeTORCTA ##
## if confirmedLarge not selected as type. ##
## Phil Kurimski 6-26-2014 fixed large tornado cta ##
## Evan Bookbinder 9-5-2014 fixed law enf cta ##
## MMD/DT/EB 3/26/2015 mixedCase Changes ##
## Evan Bookbinder 9-5-2014 fixed law enf cta ##
## MMD/DT/EB 3/26/2015 mixedCase Changes ##
## Evan Bookbinder 6-15-2015 fixed incorrect softball/grapefruit hail ##
## Evan Bookbinder 9-4-2015 cleaned up line-of-storm grammar ##
###############################################################################
## Evan Bookbinder 12-07-15 fixed default preAmble var (extra space) ##
################################################################################
## ESTABLISH SOME INITIAL VARIABLES
#parse("config.vm")
#set($hailSize = 0)
@ -26,7 +27,7 @@
#set($reportType = "A Tornado was reported")
#set($pathcastLead = "This tornadic storm")
#set($moveLead = " Doppler radar showed this tornado moving")
#set($preAmble = " TAKE COVER NOW! ")
#set($preAmble = "TAKE COVER NOW! ")
#if(${stormType} == "line")
#set($reportType = "Tornado producing storms were reported")
#set($pathcastLead = "These tornadic storms")

View file

@ -13,6 +13,7 @@
Richard Barnhill 10-28-2013 Changed/added torEMER bulletGroup to keep it locked on followups
Mike Dangelo 1-23-2014 Changed parseStrings for default safety rules CTAs and law enf CTA
Evan Bookbinder 9-5-2014 Fixed law enf CTA parse strings to match
Evan Bookbinder 12-7-2015 Added TOR EMER CTA back into cta1 bullet group (undid 1/23/2014 change)
-->
<warngenConfig>
@ -189,7 +190,7 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletName="specialEvent" bulletText="Special heads-up for large event/venue" parseString="THOSE ATTENDING"/>
<bullet bulletText="" bulletType="title"/>
<bullet bulletText="*********** CALLS TO ACTION (CHOOSE 1 OR MORE) **********" bulletType="title"/>
<bullet bulletName="torEmergencyCTA" bulletText="**TOR EMERGENCY CTA**" parseString="TORNADO EMERGENCY"/>
<bullet bulletName="torEmergencyCTA" bulletText="**TOR EMERGENCY CTA**" parseString="TORNADO EMERGENCY" bulletGroup="cta1"/>
<bullet bulletName="replacesSVRCTA" bulletText="TOR Replaces Severe Thunderstorm Warning" parseString="TORNADO WARNING REPLACES THE SEVERE"/>
<!-- There are two "default" safety rules. The first...which will probably be used by most offices...includes safety rules for mobile homes. The second...which is commented out...is for large urban areas that do not have mobile homes. If you wish to switch defaults or provide both options, remove comment tags as necessary and adjust the bulletDefault="true" as appropriate if both options are allowed -->
<bullet bulletName="defaultMobileCTA" bulletText="Default safety rules -- includes mobile homes" parseString="IF YOU ARE IN A MOBILE HOME OR OUTDOORS" bulletDefault="true" bulletGroup="cta1"/>

View file

@ -48,8 +48,10 @@ import com.vividsolutions.jts.geom.Coordinate;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 16, 2008 randerso Initial creation
* Mar 31, 2014 2689 mpduff Log input values on conversion failure.
* Sep 16, 2008 randerso Initial creation
* Mar 31, 2014 2689 mpduff Log input values on conversion failure.
* Dec 09, 2015 18391 snaples Updated gridmapper to use CELL CENTER instead of corner.
*
* </pre>
*
* @author randerso
@ -208,7 +210,7 @@ public class HRAP {
false);
gridMapper = new GridToEnvelopeMapper(gridRange, userRange);
gridMapper.setPixelAnchor(PixelInCell.CELL_CORNER);
gridMapper.setPixelAnchor(PixelInCell.CELL_CENTER);
gridMapper.setReverseAxis(new boolean[] { false, false });
} catch (Exception e) {

View file

@ -135,12 +135,4 @@
<unit>K</unit>
<resolution>750.0</resolution>
</channelInfo>
<!-- DNB replace id when known -->
<channelInfo id="10">
<channelType>Moderate</channelType>
<wavelength>0.7</wavelength>
<channel>10</channel>
<resolution>750.0</resolution>
</channelInfo>
</viirsHeaderMapping>
</viirsHeaderMapping>

View file

@ -206,11 +206,18 @@ HDS ^(Y[IJL]XA[0-9][0-9]) KKCI (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^
HDS ^(YAW[BCDGJM][0-9][0-9]) KKCI (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})/(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\5/(\2:yyyy)(\2:mm)\2/\3/\6/GRID\7/\9Z_\(10)_\(11)-\1_KKCI_\2\3\4_(seq).\5.%Y%m%d%H
# AWIPS1: GRID ^YVW[ABCDGJM][0-9][0-9].*KKCI /Grid/SBN/Raw
# YVWA41 KKCI 012200 /mRUC2 !grib/ncep/RUC2/#255/201102012200F000/CAT/7010 m above MSL/
# Aviation Clear Air Turbulence (CAT)
# YVWA41 KKCI 012200 /mRUC2 !grib/ncep/RUC2/#255/201102012200F000/CAT/7010 m HGHT
ANY ^(YVW[ABCDGJMPS][0-9][0-9]) KKCI (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\5/(\2:yyyy)(\2:mm)\2/\3/\6/GRID\7/\9Z_\(10)_\(11)-\1_KKCI_\2\3\4_(seq).\5.%Y%m%d%H
NGRID ^([YZ]VW[ABCDGJMPS][0-9][0-9]) (KKCI) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\6/(\3:yyyy)(\3:mm)\3/\4/\7/GRID\8/\(10)Z_\(11)_\(12)-\1_\2_\3\4\5_(seq).\6.%Y%m%d%H
# Aviation composite clear air turbulence (TPFI)
# ZVWS50 KKCI 160300 !grib2/ncep/RUC2/#130/FHRS//LVL
# 16.1.1: DR 18194 - This entry may need modification when LDM upgrade allows this product to match gempak grib2 tables
NGRID ^(ZV)(W)([ABCDGJMPS]..) (KKCI) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)
FILE -overwrite -log -close -edex /data_store/\8/(\5:yyyy)(\5:mm)\5/\6/\9/GRID\(10)/\1\2\3_\4_\5\6\7_(seq).\8.%Y%m%d%H
# AWIPS1: GRID ^[LM].[ABDHMNRSTU].*KWB.* /Grid/SBN/rawGrib2
# AWIPS1 OCONUS: GRID ^[LM].[ABCDGHMNORSTUVX].*KWB.* /Grid/SBN/rawGrib2
@ -397,9 +404,6 @@ ANY ^(ZDIA98) (....) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9
HRS ^(YA)([WX])(A..) (KKCI) (..)(..)(..).*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})/(F[0-9]{3})
FILE -overwrite -log -close -edex /data_store/\8/(\5:yyyy)(\5:mm)\5/\6/\9/GRID\(10)/\(12)Z_\(13)-\1\2\3_\4_\5\6\7_(seq).\8.%Y%m%d%H
ANY ^(ZV)(W)([ABCDGJMPS]..) (KKCI) (..)(..)(..).*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})/(F[0-9]{3})
FILE -overwrite -log -close -edex /data_store/\8/(\5:yyyy)(\5:mm)\5/\6/\9/GRID\(10)/\(12)Z_\(13)-\1\2\3_\4_\5\6\7_(seq).\8.%Y%m%d%H
#
# Addition for 3KM Alaska RTMA
#
NGRID ^(L[HKNPRTUV]KA98) (KWBR) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
@ -851,3 +855,6 @@ EXP (.*wcl_decrypted.*)
# DR 4958: NationalBlend model
NGRID ^(L[ABCDEFGHRTW]AZ9[0-9]) (KWEA) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\6/(\3:yyyy)(\3:mm)\3/\4/\7/GRID\8/\(10)Z_\(11)_\(12)-\1_\2_\3\4\5_(seq).\6.%Y%m%d%H
NGRID ^(L[ABCDEFGHRTW]AZ9[0-9]) (KWEA) (..)(..)(..)
FILE -overwrite -log -close -edex /data_store/grib2/(\3:yyyy)(\3:mm)\3/\4/NationalBlend/\1_\2_\3\4\5_(seq).\6.%Y%m%d%H