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:
commit
13906ed6ed
56 changed files with 3173 additions and 705 deletions
|
@ -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;
|
||||
|
|
|
@ -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()"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
150
cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCFloodingRainThreat.py
Executable file → Normal file
150
cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCFloodingRainThreat.py
Executable file → Normal 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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""THUNDERSTORM","-CAUSING","-RAPID RIVER RISES","-MINOR FLOODING OF POOR DRAINAGE""/>
|
||||
|
@ -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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""THUNDERSTORM","-CAUSING","-RAPID RIVER RISES","-MINOR FLOODING OF POOR DRAINAGE""/>
|
||||
|
@ -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"/>
|
||||
|
|
|
@ -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**!." )
|
||||
|
|
|
@ -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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-HYDROLOGIC","-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-HYDROLOGIC","-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-HYDROLOGIC","-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""THUNDERSTORM","-CAUSING","-RAPID RIVER RISES","-MINOR FLOODING OF POOR DRAINAGE""/>
|
||||
|
@ -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=""-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY"" showString=""-HYDROLOGIC","-ARROYO","-SMALL STREAM FLOOD ADVISORY","FLOOD ADVISORY""/>
|
||||
<bullet bulletName="small" bulletText="Small stream" bulletGroup="advType" parseString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY"" showString=""-URBAN AND","-ARROYO","SMALL STREAM FLOOD ADVISORY""/>
|
||||
<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=""THUNDERSTORM","-CAUSING","-RAPID RIVER RISES","-MINOR FLOODING OF POOR DRAINAGE""/>
|
||||
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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")})
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue