Merge branch 'master_16.1.2p3_for_merges' into master_16.2.1-p1

Conflicts:
	cave/com.raytheon.uf.viz.spellchecker/src/com/raytheon/uf/viz/spellchecker/dialogs/SpellCheckDlg.java
	cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java

Change-Id: I944b2f48026df080e494ab9104bfd63e30c0c9ef

Former-commit-id: f8ebc36d5e1edc7f625bfafc3f8e9d8a7d13303d
This commit is contained in:
Shawn.Hooper 2016-05-31 13:13:50 -04:00
commit 0960d09481
5 changed files with 542 additions and 125 deletions

View file

@ -88,7 +88,9 @@ import com.raytheon.uf.viz.spellchecker.jobs.SpellCheckJob;
* 08/31/2015 #4781 dgilling Improve handling of proper nouns in all
* caps mode, move override dictionary to
* SITE level.
*
* 05/25/2016 DR16930 MPorricelli Added suggestionsBlackList to spellCheckJob
* for flagging of words that are in
* inappropriateWords.txt blacklist
* </pre>
*
* @author lvenable
@ -257,6 +259,7 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
spellCheckJob.setCollector(this);
suggestionsBlacklist = getSuggestionsBlacklist();
spellCheckJob.setBlacklist(suggestionsBlacklist);
}
private Collection<String> getSuggestionsBlacklist() {

View file

@ -23,7 +23,15 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@ -56,6 +64,8 @@ import com.raytheon.uf.viz.spellchecker.Activator;
* 01Mar2010 4765 MW Fegan Moved from GFE plug-in.
* 18Oct2010 11237 rferrel Created readLine in order to compute
* offsets for start of line correctly.
* 25May2016 DR16930 MPorricelli Added flagging of words that are in
* inappropriateWords.txt blacklist
* </pre>
*
* @author wldougher
@ -92,6 +102,8 @@ public class SpellCheckJob extends Job implements ISpellingProblemCollector {
private String line;
private Collection<String> blackList;
private String vtecRegex = new String(
"/[OTEX]\\.([A-Z]{3})\\.([A-Z]{4})\\.([A-Z]{2})\\."
+ "([WAYSOFN])\\.([0-9]{4})\\.([0-9]{6})T([0-9]{4})Z-"
@ -220,8 +232,55 @@ public class SpellCheckJob extends Job implements ISpellingProblemCollector {
synchronized (this) {
service.check(document, regions, context, this, monitor);
}
// Look in this line for words that are in
// inappropriateWords.txt
// If one is found and it has not already been flagged by the
// Eclipse spell check above, add it to problems
Pattern pattern = Pattern.compile("\\w+");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
String currentWord = matcher.group();
if (blackList != null
&& blackList.contains(currentWord.toUpperCase())) {
int length = currentWord.length();
int offset = matcher.start();
SpellingProblem blacklistProblem = new AnotherSpellingProblem(
offset, length, currentWord);
if (problems.isEmpty())
problems.add(blacklistProblem);
else {
Boolean problemAlreadyFlagged = false;
Iterator<SpellingProblem> probIter = problems
.iterator();
while (probIter.hasNext()) {
if (probIter.next().getOffset() == blacklistProblem
.getOffset()) {
problemAlreadyFlagged = true;
break;
}
}
if (!problemAlreadyFlagged)
problems.add(blacklistProblem);
}
}
}
}
}
// Sort the problems by position (offset) in this line of text
List<SpellingProblem> problemsList;
problemsList = new ArrayList<SpellingProblem>();
if (!problems.isEmpty()) {
problemsList.addAll(problems);
Collections.sort(problemsList, new Comparator<SpellingProblem>() {
@Override
public int compare(SpellingProblem sp1, SpellingProblem sp2) {
return Integer.valueOf(sp1.getOffset()).compareTo(
Integer.valueOf(sp2.getOffset()));
}
});
problems.clear();
problems.addAll(problemsList);
}
if (problems.size() > 0) {
SpellingProblem lineProblem = problems.pollFirst();
@ -327,6 +386,12 @@ public class SpellCheckJob extends Job implements ISpellingProblemCollector {
this.collector = collector;
}
}
public void setBlacklist(Collection<String> suggestionsBlacklist) {
synchronized (this) {
this.blackList = suggestionsBlacklist;
}
}
}
/**
@ -388,3 +453,49 @@ class RevisedProblem extends SpellingProblem {
return lineProblem.getProposals();
}
}
class AnotherSpellingProblem extends SpellingProblem {
int offset;
int length;
String message;
AnotherSpellingProblem(int offSet, int wordLength, String word) {
super();
this.offset = offSet;
this.length = wordLength;
this.message = "The word '" + word + "' is not correctly spelled";
}
@Override
public int getOffset() {
return this.offset;
}
public void setOffset(int offSet) {
this.offset = offSet;
}
@Override
public int getLength() {
return this.length;
}
public void setLength(int wordLength) {
this.length = wordLength;
}
@Override
public String getMessage() {
return this.message;
}
public void setMessage(String word) {
this.message = "The word '" + word + "' is not correctly spelled";
}
@Override
public ICompletionProposal[] getProposals() {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -20,12 +20,22 @@
package com.raytheon.viz.warngen.gis;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.Validate;
@ -35,6 +45,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.GeospatialConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
import com.raytheon.uf.common.dataplugin.warning.portions.PortionsUtil;
import com.raytheon.uf.common.dataplugin.warning.util.CountyUserData;
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
@ -50,11 +61,17 @@ import com.raytheon.uf.common.status.PerformanceStatus;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.exception.VizException;
//import com.raytheon.viz.warngen.gis.GisUtil.Direction;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
import com.raytheon.uf.viz.core.localization.LocalizationManager;
import com.raytheon.viz.warngen.gui.WarngenLayer;
import com.raytheon.viz.warngen.util.Abbreviation;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.Polygonal;
import com.vividsolutions.jts.geom.TopologyException;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
/**
@ -91,6 +108,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometry;
* Mar 9, 2014 ASM #17190 D. Friedman Use fipsField and areaField for unique area ID.
* May 7, 2015 ASM #17438 D. Friedman Clean up debug and performance logging.
* Dec 15, 2015 ASM #17933 mgamazaychikov Update calculation of partOfParentRegion.
* May 12, 2016 ASM #18789 D. Friedman Improve findInsectingAreas performance.
* </pre>
*
* @author chammack
@ -113,6 +131,16 @@ public class Area {
.asList(new String[] { "PA", "MI", "PD", "UP", "BB", "ER", "EU",
"SR", "NR", "WU", "DS" });
private static final int DEFAULT_SUBDIVISION_TRESHOLD = 100;
private static final int SIMPLE_FEATURE_GEOM_COUNT_THRESHOLD = 2;
private static final int MAX_SUBDIVISION_DEPTH = 24;
private static final String SUBDIVISION_CONFIG_FILE = "subdiv.txt";
private static ExecutorService intersectionExecutor;
private PortionsUtil portionsUtil;
public Area(PortionsUtil portionsUtil) {
@ -327,7 +355,6 @@ public class Area {
Geometry warnPolygon, Geometry warnArea, String localizedSite,
WarngenLayer warngenLayer) throws VizException {
Map<String, Object> areasMap = new HashMap<String, Object>();
try {
Geometry precisionReducedArea = PolygonUtil
.reducePrecision(warnArea);
@ -340,25 +367,74 @@ public class Area {
String hatchedAreaSource = config.getHatchedAreaSource()
.getAreaSource();
boolean subdivide = true;
try {
String propertiesText = WarnFileUtil.convertFileContentsToString(
SUBDIVISION_CONFIG_FILE, LocalizationManager.getInstance()
.getCurrentSite(), warngenLayer.getLocalizedSite());
if (propertiesText != null) {
Properties props = new Properties();
props.load(new StringReader(propertiesText));
subdivide = Boolean.parseBoolean(props.getProperty("enabled", "true"));
}
} catch (FileNotFoundException e) {
// ignore
} catch (IOException e) {
statusHandler.handle(Priority.WARN, "Could not load subdivision configuration file", e);
}
if (!subdivide) {
statusHandler.debug("findIntersectingAreas: subdivision is disabled");
}
long t0 = System.currentTimeMillis();
for (AreaSourceConfiguration asc : config.getAreaSources()) {
boolean ignoreUserData = asc.getAreaSource().equals(
hatchedAreaSource) == false;
if (asc.getType() == AreaType.INTERSECT) {
List<Geometry> geoms = new ArrayList<Geometry>();
boolean filtered = false;
for (GeospatialData f : warngenLayer.getGeodataFeatures(
asc.getAreaSource(), localizedSite)) {
boolean ignoreUserData = asc.getAreaSource().equals(
hatchedAreaSource) == false;
Geometry intersect = GeometryUtil.intersection(warnArea,
f.prepGeom, ignoreUserData);
filtered = false;
if (!intersect.isEmpty()) {
filtered = warngenLayer.filterArea(f, intersect, asc);
if (subdivide && ignoreUserData) {
synchronized (Area.class) {
if (intersectionExecutor == null) {
int nThreads = Math.max(2,
Runtime.getRuntime().availableProcessors() / 2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
nThreads, nThreads, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
executor.allowCoreThreadTimeOut(true);
intersectionExecutor = executor;
}
}
if (intersect.isEmpty() == false && filtered == true) {
geoms.add(intersect);
Geometry waPoly = toPolygonal(warnArea);
GeospatialData[] features = warngenLayer.getGeodataFeatures(
asc.getAreaSource(), localizedSite);
List<Callable<Geometry>> callables = new ArrayList<>(features.length);
for (GeospatialData f : features) {
callables.add(new FeatureIntersection(waPoly, f));
}
try {
List<Future<Geometry>> futures = intersectionExecutor.invokeAll(callables);
int fi = 0;
for (Future<Geometry> future: futures) {
Geometry intersect = future.get();
if (intersect != null && !intersect.isEmpty()
&& warngenLayer.filterArea(features[fi], intersect, asc)) {
geoms.add(intersect);
}
fi++;
}
} catch (ExecutionException | InterruptedException e) {
throw new VizException("Error finding intersecting areas", e);
}
} else {
for (GeospatialData f : warngenLayer.getGeodataFeatures(
asc.getAreaSource(), localizedSite)) {
Geometry intersect = GeometryUtil.intersection(
warnArea, f.prepGeom, ignoreUserData);
if (!intersect.isEmpty()
&& warngenLayer.filterArea(f, intersect, asc)) {
geoms.add(intersect);
}
}
}
@ -369,9 +445,198 @@ public class Area {
areasMap.put(asc.getVariable(), affectedAreas);
}
}
perfLog.logDuration("findIntersectingAreas", System.currentTimeMillis() - t0);
return areasMap;
}
/*
* Convert input to Polygon or Multipolygon. This will discard any
* non-polygon elements.
*/
private static Geometry toPolygonal(Geometry input) {
Geometry result;
if (input instanceof Polygonal) {
result = input;
} else {
List<Polygon> pa = new ArrayList<>(input.getNumGeometries() + 63);
toPolygonalInner(input, pa);
result = input.getFactory().createMultiPolygon(pa.toArray(new Polygon[pa.size()]));
}
return result;
}
private static void toPolygonalInner(Geometry input, List<Polygon> pa) {
int n = input.getNumGeometries();
for (int i = 0; i < n; ++i) {
Geometry g = input.getGeometryN(i);
if (g instanceof Polygon) {
pa.add((Polygon) g);
} else if (g instanceof GeometryCollection) {
toPolygonalInner(g, pa);
}
}
}
private static class FeatureIntersection implements Callable<Geometry> {
private Geometry waPoly;
private GeospatialData f;
public FeatureIntersection(Geometry waPoly, GeospatialData f) {
this.waPoly = waPoly;
this.f = f;
}
@Override
public Geometry call() throws Exception {
Geometry intersect = null;
if (f.prepGeom.intersects(waPoly)) {
try {
Geometry fgPoly = toPolygonal(f.geometry);
List<Geometry> out = new ArrayList<Geometry>(64);
subdivIntersect(waPoly, fgPoly, true, out);
intersect = waPoly.getFactory().createGeometryCollection(
out.toArray(new Geometry[out.size()]));
// subdivIntersect loses user data to set it again.
intersect.setUserData(f.geometry.getUserData());
} catch (TopologyException e) {
intersect = GeometryUtil.intersection(waPoly,
f.prepGeom, true);
}
}
return intersect;
}
}
private static void subdivIntersect(Geometry warnArea, Geometry featureGeom,
boolean orient, List<Geometry> out) {
Envelope env = warnArea.getEnvelopeInternal().intersection(
featureGeom.getEnvelopeInternal());
if (env.isNull()) {
return;
}
Coordinate[] c = new Coordinate[5];
c[0] = new Coordinate(env.getMinX(), env.getMinY());
c[1] = new Coordinate(env.getMaxX(), env.getMinY());
c[2] = new Coordinate(env.getMaxX(), env.getMaxY());
c[3] = new Coordinate(env.getMinX(), env.getMaxY());
c[4] = c[0];
subdivIntersectInner(c, warnArea, featureGeom, orient, 1, out);
}
private static void subdivIntersectInner(Coordinate[] env, Geometry warnArea,
Geometry featureGeom, boolean orientation, int depth,
List<Geometry> out) {
if (warnArea.getNumGeometries() * featureGeom.getNumGeometries() <= DEFAULT_SUBDIVISION_TRESHOLD
|| depth >= MAX_SUBDIVISION_DEPTH) {
out.add(batchIntersect(warnArea, featureGeom));
} else if (featureGeom.getNumGeometries() <= SIMPLE_FEATURE_GEOM_COUNT_THRESHOLD) {
try {
Polygon clipPoly = warnArea.getFactory().createPolygon(env);
Geometry clippedWarnArea = clip(clipPoly, warnArea);
/*
* Not clipping feature geometry because it is already known to
* have a small geometry count.
*/
out.add(batchIntersect(clippedWarnArea, featureGeom));
} catch (TopologyException e) {
// Additional fallback without clipping.
statusHandler.handle(Priority.DEBUG,
"Clipped intersection failed. Will attempt fallback.", e);
out.add(GeometryUtil.intersection(warnArea, featureGeom, true));
}
} else {
GeometryFactory gf = warnArea.getFactory();
Coordinate[] c = new Coordinate[5];
List<Geometry> subOut = new ArrayList<>();
for (int side = 0; side < 2; ++side) {
if (side == 0) {
if (orientation) {
// horizontal split
c[0] = env[0];
c[1] = new Coordinate((env[0].x + env[1].x) / 2, env[0].y);
c[2] = new Coordinate(c[1].x, env[2].y);
c[3] = env[3];
c[4] = c[0];
} else {
// vertical split
c[0] = env[0];
c[1] = env[1];
c[2] = new Coordinate(c[1].x, (env[0].y + env[3].y) / 2);
c[3] = new Coordinate(c[0].x, c[2].y);
c[4] = c[0];
}
} else {
if (orientation) {
c[0] = c[1];
c[3] = c[2];
c[1] = env[1];
c[2] = env[2];
c[4] = c[0];
} else {
c[0] = c[3];
c[1] = c[2];
c[2] = env[2];
c[3] = env[3];
c[4] = c[0];
}
}
Polygon clipPoly = gf.createPolygon(c);
try {
Geometry subWarnArea = clip(clipPoly, warnArea);
Geometry subFeatureGeom = clip(clipPoly, featureGeom);
subdivIntersectInner(c, subWarnArea, subFeatureGeom,
!orientation, depth + 1, subOut);
} catch (TopologyException e) {
// Additional fallback without clipping.
statusHandler.handle(Priority.DEBUG,
"Subdivided intersection failed. Will attempt fallback.", e);
out.add(GeometryUtil.intersection(warnArea, featureGeom, true));
return;
}
}
out.addAll(subOut);
}
}
/**
* Calculate the intersection of p and g by operating on each element of g.
* This is necessary to prevent "side location conflict" errors. By using
* envelopes to either filter out elements or bypass
* Geometry.intersection(), it also is much faster than p.intersection(g)
* would be.
*
* @param p
* @param g must be Polygonal
* @return
*/
private static Geometry clip(Polygon p, Geometry g) {
Envelope pe = p.getEnvelopeInternal();
List<Polygon> out = new ArrayList<>(g.getNumGeometries() * 11 / 10);
int n = g.getNumGeometries();
for (int i = 0; i < n; ++i) {
Geometry gi = g.getGeometryN(i);
Envelope ge = gi.getEnvelopeInternal();
if (pe.contains(ge)) {
out.add((Polygon) gi);
} else if (pe.intersects(ge)) {
Geometry clipped = p.intersection(gi);
int m = clipped.getNumGeometries();
for (int j = 0; j < m; ++j) {
Geometry gj = clipped.getGeometryN(j);
if (!gj.isEmpty() && gj instanceof Polygon) {
out.add((Polygon) gj);
}
}
}
// else, discard gi
}
return g.getFactory().createMultiPolygon(out.toArray(new Polygon[out.size()]));
}
private static Geometry batchIntersect(Geometry warnArea, Geometry featureGeom) {
return GeometryUtil.intersection(warnArea, featureGeom, true);
}
public static List<String> converFeAreaToPartList(String feArea) {

View file

@ -153,6 +153,7 @@ import com.vividsolutions.jts.io.WKTReader;
* Jul 15, 2015 DR17716 mgamazaychikov Change to Geometry class in total intersection calculations.
* Oct 21, 2105 5021 randerso Fix issue with CORs for mixed case
* Feb 9, 2016 DR18421 D. Friedman Don't call ToolsDataManager.setStormTrackData if there is no storm motion.
* May 25, 2016 DR18789 D. Friedman Extract timezone calculation to method and add short circuit logic.
* </pre>
*
* @author njensen
@ -214,6 +215,127 @@ public class TemplateRunner {
return officeCityTimezone;
}
private static Set<String> determineTimezones(WarngenLayer warngenLayer,
AffectedAreas[] areas, Geometry warningArea) throws VizException {
Map<String, Double> intersectSize = new HashMap<String, Double>();
double minSize = 1.0E-3d;
Set<String> timeZones = new HashSet<String>();
for (AffectedAreas affectedAreas : areas) {
if (affectedAreas.getTimezone() != null) {
// Handles counties that span two time zones
String oneLetterTimeZones = affectedAreas.getTimezone()
.trim();
if (oneLetterTimeZones.length() == 1) {
timeZones.add(String.valueOf(oneLetterTimeZones
.charAt(0)));
}
}
}
if (timeZones.size() > 1) {
return timeZones;
}
for (AffectedAreas affectedAreas : areas) {
if (affectedAreas.getTimezone() != null) {
// Handles counties that span two time zones
String oneLetterTimeZones = affectedAreas.getTimezone()
.trim();
if (oneLetterTimeZones.length() > 1) {
// Determine if one letter timezone is going to be
// put into timeZones.
Geometry[] poly1, poly2;
int n1, n2;
double size, totalSize;
String[] oneLetterTZ = new String[oneLetterTimeZones.length()];
for (int i = 0; i < oneLetterTimeZones.length(); i++) {
oneLetterTZ[i] = String
.valueOf(oneLetterTimeZones.charAt(i));
Geometry timezoneGeom = warngenLayer
.getTimezoneGeom(oneLetterTZ[i]);
long t0 = System.currentTimeMillis();
poly1 = null;
poly2 = null;
n1 = 0;
n2 = 0;
size = 0.0d;
totalSize = 0.0d;
if ((timezoneGeom != null)
&& (warningArea != null)) {
if (intersectSize.get(oneLetterTZ[i]) != null) {
continue;
}
poly1 = new Geometry[warningArea
.getNumGeometries()];
n1 = warningArea.getNumGeometries();
for (int j = 0; j < n1; j++) {
poly1[j] = warningArea.getGeometryN(j);
}
poly2 = new Geometry[timezoneGeom
.getNumGeometries()];
n2 = timezoneGeom.getNumGeometries();
for (int j = 0; j < n2; j++) {
poly2[j] = timezoneGeom.getGeometryN(j);
}
// Calculate the total size of intersection
for (Geometry p1 : poly1) {
for (Geometry p2 : poly2) {
try {
size = p1.intersection(p2)
.getArea();
} catch (TopologyException e) {
statusHandler
.handle(Priority.VERBOSE,
"Geometry error calculating the total size of intersection.",
e);
}
if (size > 0.0) {
totalSize += size;
}
}
if (totalSize > minSize) {
break; // save time when the size of
// poly1 or poly2 is large
}
}
intersectSize
.put(oneLetterTZ[i], totalSize);
} else {
throw new VizException(
"Either timezoneGeom or/and warningArea is null. "
+ "Timezone cannot be determined.");
}
perfLog.logDuration(
"runTemplate size computation",
System.currentTimeMillis() - t0);
if (totalSize > minSize) {
timeZones.add(oneLetterTZ[i]);
}
}
// If timeZones has nothing in it when the hatched
// area is very small,
// use the timezone of larger intersection size.
if (timeZones.size() == 0) {
if (intersectSize.size() > 1) {
if (intersectSize.get(oneLetterTZ[0]) > intersectSize
.get(oneLetterTZ[1])) {
timeZones.add(oneLetterTZ[0]);
} else {
timeZones.add(oneLetterTZ[1]);
}
} else {
throw new VizException(
"The size of intersectSize is less than 1, "
+ "timezone cannot be determined.");
}
}
}
} else {
throw new VizException(
"Calling to area.getTimezone() returns null.");
}
}
return timeZones;
}
/**
* Executes a warngen template given the polygon from the Warngen Layer and
* the Storm tracking information from StormTrackDisplay
@ -317,113 +439,8 @@ public class TemplateRunner {
context.put(ia, intersectAreas.get(ia));
}
Map<String, Double> intersectSize = new HashMap<String, Double>();
String[] oneLetterTZ;
double minSize = 1.0E-3d;
if ((areas != null) && (areas.length > 0)) {
Set<String> timeZones = new HashSet<String>();
for (AffectedAreas affectedAreas : areas) {
if (affectedAreas.getTimezone() != null) {
// Handles counties that span two time zones
String oneLetterTimeZones = affectedAreas.getTimezone()
.trim();
oneLetterTZ = new String[oneLetterTimeZones.length()];
if (oneLetterTimeZones.length() == 1) {
timeZones.add(String.valueOf(oneLetterTimeZones
.charAt(0)));
} else {
// Determine if one letter timezone is going to be
// put into timeZones.
Geometry[] poly1, poly2;
int n1, n2;
double size, totalSize;
for (int i = 0; i < oneLetterTimeZones.length(); i++) {
oneLetterTZ[i] = String
.valueOf(oneLetterTimeZones.charAt(i));
Geometry timezoneGeom = warngenLayer
.getTimezoneGeom(oneLetterTZ[i]);
t0 = System.currentTimeMillis();
poly1 = null;
poly2 = null;
n1 = 0;
n2 = 0;
size = 0.0d;
totalSize = 0.0d;
if ((timezoneGeom != null)
&& (warningArea != null)) {
if (intersectSize.get(oneLetterTZ[i]) != null) {
continue;
}
poly1 = new Geometry[warningArea
.getNumGeometries()];
n1 = warningArea.getNumGeometries();
for (int j = 0; j < n1; j++) {
poly1[j] = warningArea.getGeometryN(j);
}
poly2 = new Geometry[timezoneGeom
.getNumGeometries()];
n2 = timezoneGeom.getNumGeometries();
for (int j = 0; j < n2; j++) {
poly2[j] = timezoneGeom.getGeometryN(j);
}
// Calculate the total size of intersection
for (Geometry p1 : poly1) {
for (Geometry p2 : poly2) {
try {
size = p1.intersection(p2)
.getArea();
} catch (TopologyException e) {
statusHandler
.handle(Priority.VERBOSE,
"Geometry error calculating the total size of intersection.",
e);
}
if (size > 0.0) {
totalSize += size;
}
}
if (totalSize > minSize) {
break; // save time when the size of
// poly1 or poly2 is large
}
}
intersectSize
.put(oneLetterTZ[i], totalSize);
} else {
throw new VizException(
"Either timezoneGeom or/and warningArea is null. "
+ "Timezone cannot be determined.");
}
perfLog.logDuration(
"runTemplate size computation",
System.currentTimeMillis() - t0);
if (totalSize > minSize) {
timeZones.add(oneLetterTZ[i]);
}
}
// If timeZones has nothing in it when the hatched
// area is very small,
// use the timezone of larger intersection size.
if (timeZones.size() == 0) {
if (intersectSize.size() > 1) {
if (intersectSize.get(oneLetterTZ[0]) > intersectSize
.get(oneLetterTZ[1])) {
timeZones.add(oneLetterTZ[0]);
} else {
timeZones.add(oneLetterTZ[1]);
}
} else {
throw new VizException(
"The size of intersectSize is less than 1, "
+ "timezone cannot be determined.");
}
}
}
} else {
throw new VizException(
"Calling to area.getTimezone() returns null.");
}
}
Set<String> timeZones = determineTimezones(warngenLayer, areas, warningArea);
Map<String, String> officeCityTimezone = createOfficeTimezoneMap();
String cityTimezone = null;

View file

@ -28,6 +28,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometry;
* Apr 28, 2013 1955 jsanchez Added an ignoreUserData flag to intersection method.
* Oct 21, 2013 DR 16632 D. Friedman Handle zero-length input in union.
* Dec 13, 2013 DR 16567 Qinglu Lin Added contains().
* May 12, 2016 DR 18789 D. Friedman Added intersection(g1, g2, ignoreUserData).
*
* </pre>
*
@ -103,6 +104,26 @@ public class GeometryUtil {
return rval;
}
/**
* Intersection between g1 and g2. Resulting intersection will contain user
* data from g2
*
* @param g1
* @param g2
*
* @return the intersection between g1 and g2
*/
public static Geometry intersection(Geometry g1, Geometry g2, boolean ignoreUserData) {
GeometryFactory gf = new GeometryFactory();
List<Geometry> intersection = new ArrayList<Geometry>(
g1.getNumGeometries() + g2.getNumGeometries());
intersection(g1, g2, intersection, ignoreUserData);
Geometry rval = gf.createGeometryCollection(intersection
.toArray(new Geometry[intersection.size()]));
rval.setUserData(g2.getUserData());
return rval;
}
private static void intersection(Geometry g1, Geometry g2,
List<Geometry> intersections, boolean ignoreUserData) {
if (g1 instanceof GeometryCollection) {