From 344058c0cd1413d35ce0e38990b8a96eaedffc3b Mon Sep 17 00:00:00 2001 From: mjames-upc Date: Sun, 1 Oct 2017 10:51:30 -0600 Subject: [PATCH] gov.noaa.nws.mdl.viz.boundaryTool moved from its own repo --- .../.project | 17 + .../build.properties | 1 + .../feature.xml | 49 + .../.classpath | 7 + .../.project | 17 + .../META-INF/MANIFEST.MF | 36 + .../build.properties | 6 + .../plugin.xml | 31 + .../boundaries/state/xml/Boundaries.java | 977 ++++++++++++ .../state/xml/BoundariesStateSchema.xml | 28 + .../state/xml/BoundariesStateSchema.xsd | 112 ++ .../state/xml/BoundaryObjectFactory.java | 82 + .../state/xml/ReadBoundariesXmlFile.java | 197 +++ .../state/xml/WriteBoundariesXmlFile.java | 272 ++++ .../boundary/AbstractBoundaryResource.java | 271 ++++ .../common/boundary/BoundaryDisplay.java | 1416 +++++++++++++++++ .../common/boundary/BoundaryProperties.java | 33 + .../common/boundary/BoundaryState.java | 258 +++ .../common/boundary/BoundaryUIManager.java | 682 ++++++++ .../common/boundary/BoundaryUtil.java | 122 ++ .../boundary/ImpossibleTrackException.java | 45 + .../ui/action/BoundaryEditorAction.java | 73 + .../ui/dialog/BoundaryEditorDialog.java | 1178 ++++++++++++++ .../ui/dialog/UserInputBndType.java | 87 + .../ui/layer/BoundaryEditorLayer.java | 319 ++++ 25 files changed, 6316 insertions(+) create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/.project create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/build.properties create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/feature.xml create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/.classpath create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/.project create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/META-INF/MANIFEST.MF create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/build.properties create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/plugin.xml create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/Boundaries.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xml create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xsd create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundaryObjectFactory.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/ReadBoundariesXmlFile.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/WriteBoundariesXmlFile.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/AbstractBoundaryResource.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryDisplay.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryProperties.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryState.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUIManager.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUtil.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/ImpossibleTrackException.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/action/BoundaryEditorAction.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/BoundaryEditorDialog.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/UserInputBndType.java create mode 100644 cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/layer/BoundaryEditorLayer.java diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/.project b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/.project new file mode 100644 index 0000000000..c3c37f787c --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/.project @@ -0,0 +1,17 @@ + + + gov.noaa.nws.mdl.viz.boundaryTool.common.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/build.properties b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/build.properties new file mode 100644 index 0000000000..64f93a9f0b --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/feature.xml b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/feature.xml new file mode 100644 index 0000000000..2f1a6c3d69 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool.common.feature/feature.xml @@ -0,0 +1,49 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/.classpath b/cave/gov.noaa.nws.mdl.viz.boundaryTool/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/.project b/cave/gov.noaa.nws.mdl.viz.boundaryTool/.project new file mode 100644 index 0000000000..34e7eb1c18 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/.project @@ -0,0 +1,17 @@ + + + gov.noaa.nws.mdl.viz.boundaryTool + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/META-INF/MANIFEST.MF b/cave/gov.noaa.nws.mdl.viz.boundaryTool/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..f03007c731 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/META-INF/MANIFEST.MF @@ -0,0 +1,36 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Boundarytools Plug-in +Bundle-SymbolicName: gov.noaa.nws.mdl.viz.boundaryTool;singleton:=true +Bundle-Version: 1.15.0.qualifier +Bundle-Vendor: MDL +Eclipse-RegisterBuddy: com.raytheon.uf.viz.core.rsc +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.ui, + com.raytheon.viz.core, + org.apache.commons.lang, + org.geotools, + com.raytheon.viz.ui.tools.map, + com.raytheon.viz.ui, + javax.measure, + com.raytheon.uf.common.pointdata, + javax.vecmath;bundle-version="1.3.1", + com.raytheon.uf.common.awipstools;bundle-version="1.12.1112", + com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1112", + com.raytheon.uf.viz.d2d.core, + com.raytheon.uf.common.dataplugin.radar;bundle-version="1.0.0", + com.raytheon.uf.viz.core.maps;bundle-version="1.12.1174", + com.raytheon.uf.viz.d2d.ui, + com.raytheon.viz.awipstools, + com.raytheon.uf.viz.points;bundle-version="1.0.0", + com.raytheon.uf.viz.core.rsc;bundle-version="1.0.0" +Bundle-ActivationPolicy: lazy +Export-Package: gov.noaa.nws.mdl.viz.boundaryTool, + gov.noaa.nws.mdl.viz.boundaryTool.common.boundary, + gov.noaa.nws.mdl.viz.boundaryTool.ui.action, + gov.noaa.nws.mdl.viz.boundaryTool.ui.dialog, + gov.noaa.nws.mdl.viz.boundaryTool.ui.layer +Import-Package: com.raytheon.uf.common.topo, + com.raytheon.uf.viz.d2d.core, + com.raytheon.uf.viz.d2d.ui.dialogs.procedures +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/build.properties b/cave/gov.noaa.nws.mdl.viz.boundaryTool/build.properties new file mode 100644 index 0000000000..6e2f847b66 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + localization/ diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/plugin.xml b/cave/gov.noaa.nws.mdl.viz.boundaryTool/plugin.xml new file mode 100644 index 0000000000..6e37987ff2 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/plugin.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/Boundaries.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/Boundaries.java new file mode 100644 index 0000000000..8000bc0f69 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/Boundaries.java @@ -0,0 +1,977 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.07.12 at 04:10:24 PM EDT +// + +package gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.datatype.XMLGregorianCalendar; + +/** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained within + * this class. + * + *

+ * <complexType>
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="UserName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="TimeInfo">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="FileCreationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ *                   <element name="FileCreationUtime" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="Boundary" maxOccurs="unbounded" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="BoundaryId" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *                   <element name="BoundaryType" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                   <element name="BoundaryMode" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                   <element name="BoundaryLifeSpan" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *                   <element name="BoundaryCreationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *                   <element name="BoundaryCreationUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *                   <element name="BoundaryEditedTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *                   <element name="BoundaryEditedUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *                   <element name="BoundaryExpirationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *                   <element name="BoundaryExpirationUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *                   <element name="NumberOfVertices" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *                   <element name="Vertex" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="Latitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                             <element name="Longitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                             <element name="Azimuth" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                             <element name="Speed" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                             <element name="U" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                             <element name="V" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="ForbiddenBoundaryIds" maxOccurs="unbounded" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="ForbiddenId" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="Log" maxOccurs="unbounded" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="Comment" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { "userName", "timeInfo", "boundary", + "forbiddenBoundaryIds", "log" }) +@XmlRootElement(name = "Boundaries") +public class Boundaries { + + @XmlElement(name = "UserName", required = true) + protected String userName; + @XmlElement(name = "TimeInfo", required = true) + protected Boundaries.TimeInfo timeInfo; + @XmlElement(name = "Boundary") + protected List boundary; + @XmlElement(name = "ForbiddenBoundaryIds") + protected List forbiddenBoundaryIds; + @XmlElement(name = "Log") + protected List log; + + /** + * Gets the value of the userName property. + * + * @return possible object is {@link String } + * + */ + public String getUserName() { + return userName; + } + + /** + * Sets the value of the userName property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setUserName(String value) { + this.userName = value; + } + + /** + * Gets the value of the timeInfo property. + * + * @return possible object is {@link Boundaries.TimeInfo } + * + */ + public Boundaries.TimeInfo getTimeInfo() { + return timeInfo; + } + + /** + * Sets the value of the timeInfo property. + * + * @param value + * allowed object is {@link Boundaries.TimeInfo } + * + */ + public void setTimeInfo(Boundaries.TimeInfo value) { + this.timeInfo = value; + } + + /** + * Gets the value of the boundary property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list will + * be present inside the JAXB object. This is why there is not a + * set method for the boundary property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+     * getBoundary().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Boundaries.Boundary } + * + * + */ + public List getBoundary() { + if (boundary == null) { + boundary = new ArrayList(); + } + return this.boundary; + } + + /** + * Gets the value of the forbiddenBoundaryIds property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list will + * be present inside the JAXB object. This is why there is not a + * set method for the forbiddenBoundaryIds property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+     * getForbiddenBoundaryIds().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Boundaries.ForbiddenBoundaryIds } + * + * + */ + public List getForbiddenBoundaryIds() { + if (forbiddenBoundaryIds == null) { + forbiddenBoundaryIds = new ArrayList(); + } + return this.forbiddenBoundaryIds; + } + + /** + * Gets the value of the log property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list will + * be present inside the JAXB object. This is why there is not a + * set method for the log property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+     * getLog().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Boundaries.Log } + * + * + */ + public List getLog() { + if (log == null) { + log = new ArrayList(); + } + return this.log; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained + * within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="BoundaryId" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+     *         <element name="BoundaryType" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *         <element name="BoundaryMode" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *         <element name="BoundaryLifeSpan" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+     *         <element name="BoundaryCreationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+     *         <element name="BoundaryCreationUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+     *         <element name="BoundaryEditedTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+     *         <element name="BoundaryEditedUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+     *         <element name="BoundaryExpirationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+     *         <element name="BoundaryExpirationUtime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+     *         <element name="NumberOfVertices" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+     *         <element name="Vertex" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="Latitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                   <element name="Longitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                   <element name="Azimuth" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                   <element name="Speed" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                   <element name="U" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                   <element name="V" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "boundaryId", "boundaryType", + "boundaryMode", "boundaryLifeSpan", "boundaryCreationTime", + "boundaryCreationUtime", "boundaryEditedTime", + "boundaryEditedUtime", "boundaryExpirationTime", + "boundaryExpirationUtime", "numberOfVertices", "vertex" }) + public static class Boundary { + + @XmlElement(name = "BoundaryId") + protected Integer boundaryId; + @XmlElement(name = "BoundaryType") + protected String boundaryType; + @XmlElement(name = "BoundaryMode") + protected String boundaryMode; + @XmlElement(name = "BoundaryLifeSpan") + protected Integer boundaryLifeSpan; + @XmlElement(name = "BoundaryCreationTime") + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar boundaryCreationTime; + @XmlElement(name = "BoundaryCreationUtime") + protected Long boundaryCreationUtime; + @XmlElement(name = "BoundaryEditedTime") + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar boundaryEditedTime; + @XmlElement(name = "BoundaryEditedUtime") + protected Long boundaryEditedUtime; + @XmlElement(name = "BoundaryExpirationTime") + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar boundaryExpirationTime; + @XmlElement(name = "BoundaryExpirationUtime") + protected Long boundaryExpirationUtime; + @XmlElement(name = "NumberOfVertices") + protected Integer numberOfVertices; + @XmlElement(name = "Vertex") + protected List vertex; + + /** + * Gets the value of the boundaryId property. + * + * @return possible object is {@link Integer } + * + */ + public Integer getBoundaryId() { + return boundaryId; + } + + /** + * Sets the value of the boundaryId property. + * + * @param value + * allowed object is {@link Integer } + * + */ + public void setBoundaryId(Integer value) { + this.boundaryId = value; + } + + /** + * Gets the value of the boundaryType property. + * + * @return possible object is {@link String } + * + */ + public String getBoundaryType() { + return boundaryType; + } + + /** + * Sets the value of the boundaryType property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setBoundaryType(String value) { + this.boundaryType = value; + } + + /** + * Gets the value of the boundaryMode property. + * + * @return possible object is {@link String } + * + */ + public String getBoundaryMode() { + return boundaryMode; + } + + /** + * Sets the value of the boundaryMode property. + * + * @param value + * allowed object is {@link String } + * + */ + public void setBoundaryMode(String value) { + this.boundaryMode = value; + } + + /** + * Gets the value of the boundaryLifeSpan property. + * + * @return possible object is {@link Integer } + * + */ + public Integer getBoundaryLifeSpan() { + return boundaryLifeSpan; + } + + /** + * Sets the value of the boundaryLifeSpan property. + * + * @param value + * allowed object is {@link Integer } + * + */ + public void setBoundaryLifeSpan(Integer value) { + this.boundaryLifeSpan = value; + } + + /** + * Gets the value of the boundaryCreationTime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getBoundaryCreationTime() { + return boundaryCreationTime; + } + + /** + * Sets the value of the boundaryCreationTime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setBoundaryCreationTime(XMLGregorianCalendar value) { + this.boundaryCreationTime = value; + } + + /** + * Gets the value of the boundaryCreationUtime property. + * + * @return possible object is {@link Long } + * + */ + public Long getBoundaryCreationUtime() { + return boundaryCreationUtime; + } + + /** + * Sets the value of the boundaryCreationUtime property. + * + * @param value + * allowed object is {@link Long } + * + */ + public void setBoundaryCreationUtime(Long value) { + this.boundaryCreationUtime = value; + } + + /** + * Gets the value of the boundaryEditedTime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getBoundaryEditedTime() { + return boundaryEditedTime; + } + + /** + * Sets the value of the boundaryEditedTime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setBoundaryEditedTime(XMLGregorianCalendar value) { + this.boundaryEditedTime = value; + } + + /** + * Gets the value of the boundaryEditedUtime property. + * + * @return possible object is {@link Long } + * + */ + public Long getBoundaryEditedUtime() { + return boundaryEditedUtime; + } + + /** + * Sets the value of the boundaryEditedUtime property. + * + * @param value + * allowed object is {@link Long } + * + */ + public void setBoundaryEditedUtime(Long value) { + this.boundaryEditedUtime = value; + } + + /** + * Gets the value of the boundaryExpirationTime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getBoundaryExpirationTime() { + return boundaryExpirationTime; + } + + /** + * Sets the value of the boundaryExpirationTime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setBoundaryExpirationTime(XMLGregorianCalendar value) { + this.boundaryExpirationTime = value; + } + + /** + * Gets the value of the boundaryExpirationUtime property. + * + * @return possible object is {@link Long } + * + */ + public Long getBoundaryExpirationUtime() { + return boundaryExpirationUtime; + } + + /** + * Sets the value of the boundaryExpirationUtime property. + * + * @param value + * allowed object is {@link Long } + * + */ + public void setBoundaryExpirationUtime(Long value) { + this.boundaryExpirationUtime = value; + } + + /** + * Gets the value of the numberOfVertices property. + * + * @return possible object is {@link Integer } + * + */ + public Integer getNumberOfVertices() { + return numberOfVertices; + } + + /** + * Sets the value of the numberOfVertices property. + * + * @param value + * allowed object is {@link Integer } + * + */ + public void setNumberOfVertices(Integer value) { + this.numberOfVertices = value; + } + + /** + * Gets the value of the vertex property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list + * will be present inside the JAXB object. This is why there is not a + * set method for the vertex property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+         * getVertex().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Boundaries.Boundary.Vertex } + * + * + */ + public List getVertex() { + if (vertex == null) { + vertex = new ArrayList(); + } + return this.vertex; + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content + * contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="Latitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *         <element name="Longitude" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *         <element name="Azimuth" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *         <element name="Speed" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *         <element name="U" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *         <element name="V" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "latitude", "longitude", "azimuth", + "speed", "u", "v" }) + public static class Vertex { + + @XmlElement(name = "Latitude") + protected Float latitude; + @XmlElement(name = "Longitude") + protected Float longitude; + @XmlElement(name = "Azimuth") + protected Float azimuth; + @XmlElement(name = "Speed") + protected Float speed; + @XmlElement(name = "U") + protected Float u; + @XmlElement(name = "V") + protected Float v; + + /** + * Gets the value of the latitude property. + * + * @return possible object is {@link Float } + * + */ + public Float getLatitude() { + return latitude; + } + + /** + * Sets the value of the latitude property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setLatitude(Float value) { + this.latitude = value; + } + + /** + * Gets the value of the longitude property. + * + * @return possible object is {@link Float } + * + */ + public Float getLongitude() { + return longitude; + } + + /** + * Sets the value of the longitude property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setLongitude(Float value) { + this.longitude = value; + } + + /** + * Gets the value of the azimuth property. + * + * @return possible object is {@link Float } + * + */ + public Float getAzimuth() { + return azimuth; + } + + /** + * Sets the value of the azimuth property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setAzimuth(Float value) { + this.azimuth = value; + } + + /** + * Gets the value of the speed property. + * + * @return possible object is {@link Float } + * + */ + public Float getSpeed() { + return speed; + } + + /** + * Sets the value of the speed property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setSpeed(Float value) { + this.speed = value; + } + + /** + * Gets the value of the u property. + * + * @return possible object is {@link Float } + * + */ + public Float getU() { + return u; + } + + /** + * Sets the value of the u property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setU(Float value) { + this.u = value; + } + + /** + * Gets the value of the v property. + * + * @return possible object is {@link Float } + * + */ + public Float getV() { + return v; + } + + /** + * Sets the value of the v property. + * + * @param value + * allowed object is {@link Float } + * + */ + public void setV(Float value) { + this.v = value; + } + + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained + * within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="ForbiddenId" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "forbiddenId" }) + public static class ForbiddenBoundaryIds { + + @XmlElement(name = "ForbiddenId") + protected List forbiddenId; + + /** + * Gets the value of the forbiddenId property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list + * will be present inside the JAXB object. This is why there is not a + * set method for the forbiddenId property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+         * getForbiddenId().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link String } + * + * + */ + public List getForbiddenId() { + if (forbiddenId == null) { + forbiddenId = new ArrayList(); + } + return this.forbiddenId; + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained + * within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="Comment" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "comment" }) + public static class Log { + + @XmlElement(name = "Comment") + protected List comment; + + /** + * Gets the value of the comment property. + * + *

+ * This accessor method returns a reference to the live list, not a + * snapshot. Therefore any modification you make to the returned list + * will be present inside the JAXB object. This is why there is not a + * set method for the comment property. + * + *

+ * For example, to add a new item, do as follows: + * + *

+         * getComment().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link String } + * + * + */ + public List getComment() { + if (comment == null) { + comment = new ArrayList(); + } + return this.comment; + } + + } + + /** + *

+ * Java class for anonymous complex type. + * + *

+ * The following schema fragment specifies the expected content contained + * within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="FileCreationTime" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+     *         <element name="FileCreationUtime" type="{http://www.w3.org/2001/XMLSchema}long"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { "fileCreationTime", "fileCreationUtime" }) + public static class TimeInfo { + + @XmlElement(name = "FileCreationTime", required = true) + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar fileCreationTime; + @XmlElement(name = "FileCreationUtime") + protected long fileCreationUtime; + + /** + * Gets the value of the fileCreationTime property. + * + * @return possible object is {@link XMLGregorianCalendar } + * + */ + public XMLGregorianCalendar getFileCreationTime() { + return fileCreationTime; + } + + /** + * Sets the value of the fileCreationTime property. + * + * @param value + * allowed object is {@link XMLGregorianCalendar } + * + */ + public void setFileCreationTime(XMLGregorianCalendar value) { + this.fileCreationTime = value; + } + + /** + * Gets the value of the fileCreationUtime property. + * + */ + public long getFileCreationUtime() { + return fileCreationUtime; + } + + /** + * Sets the value of the fileCreationUtime property. + * + */ + public void setFileCreationUtime(long value) { + this.fileCreationUtime = value; + } + + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xml b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xml new file mode 100644 index 0000000000..efce827fb8 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xml @@ -0,0 +1,28 @@ + + + UserName + + 2001-12-31T12:00:00 + 0 + + + 0 + BoundaryType + BoundaryMode + 0 + 2001-12-31T12:00:00 + 0 + 2001-12-31T12:00:00 + 0 + 2001-12-31T12:00:00 + 0 + 0 + + + + ForbiddenId + + + Comment + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xsd b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xsd new file mode 100644 index 0000000000..9fb94c9853 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundariesStateSchema.xsd @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundaryObjectFactory.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundaryObjectFactory.java new file mode 100644 index 0000000000..de160f0530 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/BoundaryObjectFactory.java @@ -0,0 +1,82 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.07.12 at 04:10:24 PM EDT +// + +package gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml; + +import javax.xml.bind.annotation.XmlRegistry; + +/** + * This object contains factory methods for each Java content interface and Java + * element interface generated in the generated package. + *

+ * An ObjectFactory allows you to programatically construct new instances of the + * Java representation for XML content. The Java representation of XML content + * can consist of schema derived interfaces and classes representing the binding + * of schema type definitions, element declarations and model groups. Factory + * methods for each of these are provided in this class. + * + */ +@XmlRegistry +public class BoundaryObjectFactory { + + /** + * Create a new ObjectFactory that can be used to create new instances of + * schema derived classes for package: generated + * + */ + public BoundaryObjectFactory() { + } + + /** + * Create an instance of {@link Boundaries.TimeInfo } + * + */ + public Boundaries.TimeInfo createBoundariesTimeInfo() { + return new Boundaries.TimeInfo(); + } + + /** + * Create an instance of {@link Boundaries.Boundary } + * + */ + public Boundaries.Boundary createBoundariesBoundary() { + return new Boundaries.Boundary(); + } + + /** + * Create an instance of {@link Boundaries.Boundary.Vertex } + * + */ + public Boundaries.Boundary.Vertex createBoundariesBoundaryVertex() { + return new Boundaries.Boundary.Vertex(); + } + + /** + * Create an instance of {@link Boundaries.Log } + * + */ + public Boundaries.Log createBoundariesLog() { + return new Boundaries.Log(); + } + + /** + * Create an instance of {@link Boundaries } + * + */ + public Boundaries createBoundaries() { + return new Boundaries(); + } + + /** + * Create an instance of {@link Boundaries.ForbiddenBoundaryIds } + * + */ + public Boundaries.ForbiddenBoundaryIds createBoundariesForbiddenBoundaryIds() { + return new Boundaries.ForbiddenBoundaryIds(); + } + +} \ No newline at end of file diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/ReadBoundariesXmlFile.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/ReadBoundariesXmlFile.java new file mode 100644 index 0000000000..8c47bebc0e --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/ReadBoundariesXmlFile.java @@ -0,0 +1,197 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml; + +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.Boundaries.ForbiddenBoundaryIds; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState; + +import java.io.FileNotFoundException; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.xml.bind.JAXBException; +import javax.xml.datatype.DatatypeConfigurationException; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; +import com.raytheon.uf.common.localization.LocalizationFile; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.localization.exception.LocalizationException; +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.SimulatedTime; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.viz.core.exception.VizException; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; + +/** + * Methods to be called to read boundary xml file via LocalizationFile and + * populate BoundaryState objects for the display active boundaries by + * BounadaryDisplay class + * + *

+ * @author Mamoudou Ba
+ * @version 1.0
+ * 
+ * + */ +public class ReadBoundariesXmlFile { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(ReadBoundariesXmlFile.class); + + public void readBoundariesXmlFile(BoundaryState currentState) + throws VizException, DatatypeConfigurationException, + FileNotFoundException { + Date d = null; + + long createTime = 0; + long currTime = 0; + float bndLifeSpan = 0; + long oneHour = TimeUtil.MILLIS_PER_HOUR; + String moving = "Moving"; + + // Use Localization context to read boundary data + IPathManager pm = PathManagerFactory.getPathManager(); + LocalizationContext context = pm.getContext( + LocalizationType.CAVE_STATIC, LocalizationLevel.SITE); + LocalizationFile boundaryFile = pm.getLocalizationFile(context, + "awipsTools" + IPathManager.SEPARATOR + "boundaryTool.xml"); + + if (boundaryFile.exists()) { + try { + // Read boundary data via localization + Boundaries boundariesObj = boundaryFile.jaxbUnmarshal( + Boundaries.class, new JAXBManager(Boundaries.class)); + + d = new Date(boundariesObj.getTimeInfo().getFileCreationUtime()); + + currentState.creationFileTime = new DataTime(d); + + for (int i = 0; i < boundariesObj.getBoundary().size(); i++) { + int boundaryId = boundariesObj.getBoundary().get(i) + .getBoundaryId(); + // Populate boundary active list for those active + // boundaries. + + d = new Date(boundariesObj.getBoundary().get(i) + .getBoundaryCreationUtime()); + + DataTime t = new DataTime(SimulatedTime.getSystemTime() + .getTime()); + currTime = t.getMatchRef(); + createTime = boundariesObj.getBoundary().get(i) + .getBoundaryCreationUtime(); + bndLifeSpan = (currTime - createTime) / oneHour; + + if (bndLifeSpan >= (float) boundariesObj.getBoundary() + .get(i).getBoundaryLifeSpan()) { + // Add expired boundaries to forbidden list + if (currentState.forbiddenBoundaryIdsMap + .get(boundaryId) != null) { + currentState.forbiddenBoundaryIdsMap + .remove(boundaryId); + currentState.forbiddenBoundaryIdsMap.put( + boundaryId, boundaryId); + } + continue; + } + + currentState.createTimeMap.put(boundaryId, new DataTime(d)); + currentState.boundaryDurationMap.put(boundaryId, + boundariesObj.getBoundary().get(i) + .getBoundaryLifeSpan()); + + d = new Date(boundariesObj.getBoundary().get(i) + .getBoundaryEditedUtime()); + currentState.editedTimeMap.put(boundaryId, new DataTime(d)); + + d = new Date(boundariesObj.getBoundary().get(i) + .getBoundaryExpirationUtime()); + currentState.expirationTimeMap.put(boundaryId, + new DataTime(d)); + + Coordinate[] coords = new Coordinate[boundariesObj + .getBoundary().get(i).getNumberOfVertices()]; + float[] speed = new float[boundariesObj.getBoundary() + .get(i).getNumberOfVertices()]; + float[] angle = new float[boundariesObj.getBoundary() + .get(i).getNumberOfVertices()]; + + for (int j = 0; j < boundariesObj.getBoundary().get(i) + .getVertex().size(); j++) { + coords[j] = new Coordinate(boundariesObj.getBoundary() + .get(i).getVertex().get(j).getLongitude(), + boundariesObj.getBoundary().get(i).getVertex() + .get(j).getLatitude()); + speed[j] = boundariesObj.getBoundary().get(i) + .getVertex().get(j).getSpeed(); + angle[j] = boundariesObj.getBoundary().get(i) + .getVertex().get(j).getAzimuth(); + + } + + currentState.boundariesMap.put(boundaryId, + new GeometryFactory().createLineString(coords)); + + if (boundariesObj.getBoundary().get(i).getBoundaryMode() + .equals(moving)) { + currentState.isMovingMap.put(boundaryId, true); + currentState.vertexAngleMap.put(boundaryId, angle); + currentState.vertexSpeedMap.put(boundaryId, speed); + } else { + currentState.isMovingMap.put(boundaryId, false); + } + currentState.boundaryTypeMap.put(boundaryId, boundariesObj + .getBoundary().get(i).getBoundaryType()); + currentState.boundaryId = boundaryId; + if (currentState.boundariesMap.size() != 0) { + if (currentState.existingBoundaryNotEmptyMap + .get(boundaryId) != null) { + currentState.existingBoundaryNotEmptyMap + .remove(boundaryId); + } + + currentState.existingBoundaryNotEmptyMap.put( + boundaryId, true); + } + } + + // Populate boundary forbidden id list + + List forbiden = boundariesObj + .getForbiddenBoundaryIds(); + + Iterator iterator = forbiden.iterator(); + + int id = 0; + Iterable s1 = null; + + while (iterator.hasNext()) { + s1 = iterator.next().getForbiddenId(); + for (String e : s1) { + try { + id = Integer.parseInt(e); + + } catch (NumberFormatException ex) { + statusHandler.handle(Priority.PROBLEM, + "Problem in parsing the integer", ex); + } + currentState.forbiddenBoundaryIdsMap.put(id, id); + } + } + + } catch (JAXBException e) { + statusHandler.handle(Priority.PROBLEM, + "problem in reading boundary data", e); + } catch (LocalizationException e1) { + statusHandler.handle(Priority.PROBLEM, + "Localization exception", e1); + } + } + } +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/WriteBoundariesXmlFile.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/WriteBoundariesXmlFile.java new file mode 100644 index 0000000000..c93dcf2c8a --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/boundaries/state/xml/WriteBoundariesXmlFile.java @@ -0,0 +1,272 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml; + +import static java.lang.Math.PI; +import static java.lang.Math.cos; +import static java.lang.Math.sin; +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.Boundaries.Boundary.Vertex; +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.Boundaries.ForbiddenBoundaryIds; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.BoundaryPolyLine; + +import java.io.IOException; +import java.sql.Date; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.List; + +import javax.xml.bind.JAXBException; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; +import com.raytheon.uf.common.localization.LocalizationFile; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.localization.SaveableOutputStream; +import com.raytheon.uf.common.localization.exception.LocalizationException; +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.viz.core.exception.VizException; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.LineString; + +/** + * Methods to be called to save boundary xml file via LocalizationFile + * + *
+ * @author Mamoudou Ba
+ * @version 1.0
+ * 
+ */ +public class WriteBoundariesXmlFile { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(WriteBoundariesXmlFile.class); + private static JAXBManager jaxbManager; + private static boolean initialized; + + /** + * Populate the Boundaries Object and save it via LocalizationFile. + */ + public void writeBoundariesXmlFile(BoundaryState currentState, + DataTime[] dataTimes, int currentTimeIndex) throws VizException, + DatatypeConfigurationException { + BoundaryObjectFactory ofObj = new BoundaryObjectFactory(); + Boundaries boundariesObj = ofObj.createBoundaries(); + + // Use Localization context to save boundary data + IPathManager pm = PathManagerFactory.getPathManager(); + + LocalizationContext context = pm.getContext( + LocalizationType.CAVE_STATIC, LocalizationLevel.SITE); + + LocalizationFile boundaryFile = pm.getLocalizationFile(context, + "awipsTools" + IPathManager.SEPARATOR + "boundaryTool.xml"); + + /* + * Use ProfileDescription methods to populate the ProfileDescription + * object with values. Fist the simple type variables. + */ + + // Populate the Boundaries Object + + // Current user name + boundariesObj.setUserName(System.getProperty("user.name")); + + // Time info (Time frame) + // currentTimeIndex = this.trackUtil.getCurrentFrame(info); + + long currentUTime = 0; + long oneHour = TimeUtil.MILLIS_PER_HOUR; + long expirationUTime = 0; + long boundaryCreationUtime = 0; + long boundaryEditedUtime = 0; + Date d; + Date expiration_date; + // dataTimes = trackUtil.getDataTimes(info); + + currentUTime = dataTimes[currentTimeIndex].getMatchRef(); + d = new Date(currentUTime); + + GregorianCalendar c = new GregorianCalendar(); + c.setTime(d); + + XMLGregorianCalendar d2 = DatatypeFactory.newInstance() + .newXMLGregorianCalendar(c); + + Boundaries.TimeInfo timeInfoObj = ofObj.createBoundariesTimeInfo(); + timeInfoObj.setFileCreationTime(d2); + timeInfoObj.setFileCreationUtime(currentUTime); + + boundariesObj.setTimeInfo(timeInfoObj); + + // Populate active boundaries: loop over all existing boundaries + + int moveIndex = currentTimeIndex; + + BoundaryPolyLine[] currentTimePoints; + LineString line; + Iterator iterator = currentState.boundariesMap.keySet() + .iterator(); + + while (iterator.hasNext()) { + String boundaryMode = null; + + Boundaries.Boundary boundary = ofObj.createBoundariesBoundary(); + + int boundaryId = iterator.next(); + boundary.setBoundaryId(boundaryId); + if (currentState.isMovingMap.get(boundaryId)) { + boundaryMode = "Moving"; + currentTimePoints = currentState.timePointsMap.get(boundaryId); + line = currentTimePoints[moveIndex].polyline; + + } else { + line = currentState.boundariesMap.get(boundaryId); + boundaryMode = "Stationary"; + } + boundary.setBoundaryMode(boundaryMode); + boundary.setBoundaryType(currentState.boundaryTypeMap + .get(boundaryId)); + boundary.setBoundaryLifeSpan(currentState.boundaryDurationMap + .get(boundaryId)); + + Coordinate[] coords = line.getCoordinates(); + boundary.setNumberOfVertices(coords.length); + // Populate boundary's time attributes + // Set boundary creation time attributes + boundaryCreationUtime = currentState.createTimeMap.get(boundaryId) + .getMatchRef(); + expirationUTime = boundaryCreationUtime + + (currentState.boundaryDurationMap.get(boundaryId) * oneHour); + d = new Date(boundaryCreationUtime); + expiration_date = new Date(expirationUTime); + DataTime expirationDataTime = new DataTime(expiration_date); + + // Set Boundary expiration Time + if (currentState.expirationTimeMap.get(boundaryId) != null) + currentState.expirationTimeMap.remove(boundaryId); + currentState.expirationTimeMap.put(boundaryId, expirationDataTime); + + c = new GregorianCalendar(); + c.setTime(d); + d2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); + boundary.setBoundaryCreationTime(d2); + boundary.setBoundaryCreationUtime(boundaryCreationUtime); + + // Set modification Time attributes + boundaryEditedUtime = currentState.editedTimeMap.get(boundaryId) + .getMatchRef(); + d = new Date(boundaryEditedUtime); + c = new GregorianCalendar(); + c.setTime(d); + d2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); + boundary.setBoundaryEditedTime(d2); + boundary.setBoundaryEditedUtime(boundaryEditedUtime); + + // Set boundary expiration time attributes + c = new GregorianCalendar(); + c.setTime(expiration_date); + d2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); + boundary.setBoundaryExpirationTime(d2); + boundary.setBoundaryExpirationUtime(expirationUTime); + + // populate vertices + // boundaryObj.setNumberOfVertices(coords.length); + + List vertexList = new ArrayList(); + // add vertex to the list + for (int i = 0; i < coords.length; i++) { + // coordinates + Boundaries.Boundary.Vertex vertex = ofObj + .createBoundariesBoundaryVertex(); + vertexList.add(vertex); + + Vertex vx = vertexList.get(i); + vx.setLongitude((float) coords[i].x); + vx.setLatitude((float) coords[i].y); + + // speed and angle + if (currentState.isMovingMap.get(boundaryId)) { + vx.setAzimuth(currentState.vertexAngleMap.get(boundaryId)[i]); + vx.setSpeed(currentState.vertexSpeedMap.get(boundaryId)[i]); + // Compute u,v components of speed + float u = (float) (currentState.vertexSpeedMap + .get(boundaryId)[i] * sin(currentState.vertexAngleMap + .get(boundaryId)[i] * PI / 180.)); + float v = (float) (currentState.vertexSpeedMap + .get(boundaryId)[i] * cos(currentState.vertexAngleMap + .get(boundaryId)[i] * PI / 180.)); + vx.setU(u); + vx.setV(v); + } else { + vx.setAzimuth((float) 0.0); + vx.setSpeed((float) 0.0); + vx.setU((float) 0.0); + vx.setV((float) 0.0); + + } + boundary.getVertex().add(vx); + + } + + boundariesObj.getBoundary().add(boundary); + } + + // Populate forbidden ids list + + Iterator logIndex = currentState.logMap.keySet().iterator(); + + while (logIndex.hasNext()) { + Boundaries.Log log = ofObj.createBoundariesLog(); + int id = logIndex.next(); + log.getComment().add(currentState.logMap.get(id)); + boundariesObj.getLog().add(log); + } + + Iterator forbidenIds = currentState.forbiddenBoundaryIdsMap + .keySet().iterator(); + + while (forbidenIds.hasNext()) { + ForbiddenBoundaryIds forbiden = ofObj + .createBoundariesForbiddenBoundaryIds(); + int id = forbidenIds.next(); + String s = "" + id; + forbiden.getForbiddenId().add(s); + boundariesObj.getForbiddenBoundaryIds().add(forbiden); + } + + try { + initialize(); + } catch (JAXBException e1) { + statusHandler.handle(Priority.PROBLEM, "Initialization fails", e1); + } + try (SaveableOutputStream sos = boundaryFile.openOutputStream()) { + jaxbManager.marshalToStream(boundariesObj, sos); + sos.save(); + } catch (IOException | LocalizationException | SerializationException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); + } + } + + /** + * initialize jaxb manager + * + * @throws JAXBException + */ + private static synchronized void initialize() throws JAXBException { + if (!initialized) { + jaxbManager = new JAXBManager(Boundaries.class); + initialized = true; + } + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/AbstractBoundaryResource.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/AbstractBoundaryResource.java new file mode 100644 index 0000000000..a45aa95e08 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/AbstractBoundaryResource.java @@ -0,0 +1,271 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.Mode; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.UserAction; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; + +import org.eclipse.jface.action.IMenuManager; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.SimulatedTime; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.viz.core.IGraphicsTarget; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; +import com.raytheon.uf.viz.core.drawables.PaintProperties; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.map.MapDescriptor; +import com.raytheon.uf.viz.core.rsc.AbstractResourceData; +import com.raytheon.uf.viz.core.rsc.AbstractVizResource; +import com.raytheon.uf.viz.core.rsc.IResourceDataChanged; +import com.raytheon.uf.viz.core.rsc.LoadProperties; +import com.raytheon.uf.viz.core.rsc.ResourceProperties; +import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; +import com.raytheon.uf.viz.core.rsc.capabilities.EditableCapability; +import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability; +import com.raytheon.uf.viz.core.rsc.capabilities.OutlineCapability; +import com.raytheon.uf.viz.core.rsc.tools.GenericToolsResourceData; +import com.raytheon.viz.ui.cmenu.IContextMenuContributor; +import com.raytheon.viz.ui.input.EditableManager; + +/** + * Abstract class for drawing boundary object + * + * @author Mamoudou ba + * @version 1.0 + * + * Modified from A2 "AbstractStormTrackResource" class by renaming the + * class name and methods + */ + +public abstract class AbstractBoundaryResource extends + AbstractVizResource implements + IResourceDataChanged, IContextMenuContributor { + + private BoundaryDisplay display; + + protected BoundaryState displayState; + + protected BoundaryUIManager manager; + + private boolean timeMatchBasis = false; + + private int maximumFrameCount = -1; + + protected BoundaryUtil trackUtil; + + private boolean keepTrackOfDuration = false; + + private int lastFrameCount = -1; + + public AbstractBoundaryResource( + GenericToolsResourceData resourceData, + LoadProperties loadProperties, MapDescriptor descriptor) { + super(resourceData, loadProperties); + setDescriptor(descriptor); + resourceData.addChangeListener(this); + dataTimes = new ArrayList(); + + displayState = new BoundaryState(); + trackUtil = new BoundaryUtil(); + initializeState(displayState); + + if (displayState.duration == -1) { + keepTrackOfDuration = true; + } + } + + @Override + public void setDescriptor(MapDescriptor descriptor) { + super.setDescriptor(descriptor); + if (display != null) { + display.setDescriptor(descriptor); + } + } + + @Override + public DataTime[] getDataTimes() { + if (timeMatchBasis) { + /* + * We only want to calculate more data times if the user hasselected + * more frames than there have been in the past. + */ + if (this.descriptor.getNumberOfFrames() > this.maximumFrameCount) { + int variance = this.descriptor.getNumberOfFrames() + - this.maximumFrameCount; + + this.maximumFrameCount = this.descriptor.getNumberOfFrames(); + + DataTime earliestTime = this.dataTimes.get(0); + this.fillDataTimeArray(earliestTime, variance); + } + } else { + FramesInfo info = descriptor.getFramesInfo(); + dataTimes.clear(); + this.maximumFrameCount = this.descriptor.getNumberOfFrames(); + // First time called + if (info.getFrameTimes() != null) { + for (DataTime dt : info.getFrameTimes()) { + dataTimes.add(dt); + } + } + + if (dataTimes.size() == 0) { + timeMatchBasis = true; + /* + * Case where this tool is time match basis or no data loaded + */ + DataTime currentTime = null; + if (dataTimes.size() > 0) { + currentTime = dataTimes.get(dataTimes.size() - 1); + } else { + currentTime = new DataTime(SimulatedTime.getSystemTime() + .getTime()); + } + + dataTimes.add(currentTime); + this.fillDataTimeArray(currentTime, + this.descriptor.getNumberOfFrames() - 1); + } + } + Collections.sort(dataTimes); + return dataTimes.toArray(new DataTime[dataTimes.size()]); + } + + private void fillDataTimeArray(DataTime startDataTime, int numberOfDataTimes) { + long fifteenMin = 15 * TimeUtil.MILLIS_PER_MINUTE; + long time = startDataTime.getRefTime().getTime(); + DataTime currentDataTime = null; + + for (int i = 0; i < numberOfDataTimes; i++) { + time -= fifteenMin; + currentDataTime = new DataTime(new Date(time)); + this.dataTimes.add(currentDataTime); + } + } + + public boolean isEditable() { + return getCapability(EditableCapability.class).isEditable(); + } + + @Override + protected void disposeInternal() { + if (manager != null) { + manager.dispose(); + } + } + + @Override + protected void initInternal(IGraphicsTarget target) throws VizException { + EditableManager.makeEditable(this, true); + manager = new BoundaryUIManager(this); + manager.setTrackUtil(trackUtil); + // Create the display + display = new BoundaryDisplay(descriptor, manager); + descriptor.getTimeMatcher().redoTimeMatching(this); + descriptor.getTimeMatcher().redoTimeMatching(descriptor); + } + + @Override + protected void paintInternal(IGraphicsTarget target, + PaintProperties paintProps) throws VizException { + FramesInfo info = paintProps.getFramesInfo(); + manager.setHandleInput(displayState.isEditable()); + if (keepTrackOfDuration && lastFrameCount != info.getFrameCount()) { + displayState.duration = -1; + lastFrameCount = info.getFrameCount(); + } + + displayState.color = getCapability(ColorableCapability.class) + .getColor(); + displayState.lineWidth = getCapability(OutlineCapability.class) + .getOutlineWidth(); + displayState.lineStyle = getCapability(OutlineCapability.class) + .getLineStyle(); + // set the magnification for the display state + displayState.magnification = getCapability( + MagnificationCapability.class).getMagnification().floatValue(); + + PaintProperties newProps = new BoundaryProperties(paintProps, + displayState); + + display.paint(target, newProps); + + manager.setHandleInput(displayState.isEditable()); + } + + @Override + public void resourceChanged(ChangeType type, Object object) { + if (type == ChangeType.CAPABILITY) { + displayState.geomChanged = true; + if (object instanceof EditableCapability) { + displayState.editable = ((EditableCapability) object) + .isEditable(); + } + issueRefresh(); + } + } + + public BoundaryState getBoundaryState() { + return displayState; + } + + @Override + public String getName() { + DataTime[] frameTimes = descriptor.getFramesInfo().getFrameTimes(); + if (frameTimes != null) { + descriptor.getTimeMatchingMap().put(this, frameTimes); + } + return getResourceName(); + } + + public void resetState() { + displayState = new BoundaryState(); + initializeState(displayState); + } + + public BoundaryUIManager getUIManager() { + return manager; + } + + protected String getAddVertexText() { + return "Add Vertex"; + } + + protected String getDeleteVertexText() { + return "Remove Vertex"; + } + + protected abstract void initializeState(BoundaryState state); + + protected abstract String getResourceName(); + + @Override + public void addContextMenuItems(IMenuManager menuManager, int x, int y) { + if (displayState.mode == Mode.DRAG_ME + || displayState.userAction != UserAction.INSERT_BOUNDARY) { + return; + } + + if (manager.closeToPoint()) { + menuManager.add(manager.getDeleteAction()); + } else if (manager.closeToLine()) { + menuManager.add(manager.getAddAction()); + } + } + + @Override + public void propertiesChanged(ResourceProperties props) { + manager.setHandleInput(props.isVisible()); + } + + @Override + public void project(CoordinateReferenceSystem crs) throws VizException { + displayState.geomChanged = true; + issueRefresh(); + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryDisplay.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryDisplay.java new file mode 100644 index 0000000000..74c139272b --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryDisplay.java @@ -0,0 +1,1416 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.BoundaryPolyLine; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.UserAction; + +import java.awt.geom.Point2D; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TimeZone; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.geotools.referencing.GeodeticCalculator; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.DrawableCircle; +import com.raytheon.uf.viz.core.DrawableLine; +import com.raytheon.uf.viz.core.DrawableString; +import com.raytheon.uf.viz.core.IGraphicsTarget; +import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment; +import com.raytheon.uf.viz.core.IGraphicsTarget.LineStyle; +import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment; +import com.raytheon.uf.viz.core.drawables.IRenderable; +import com.raytheon.uf.viz.core.drawables.PaintProperties; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.map.IMapDescriptor; +import com.raytheon.uf.viz.core.map.MapDescriptor; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Point; + +/** + * Working version of BoundaryDisplay, correctly draws and keeps track of + * coordinates, speed, and angle. + * + *
+ * 
+ * @author Mamoudou Ba
+ * @version 1.0
+ * 
+ * 
+ * + * April 2011: Substantially modified from A2 "StormTrackDisplay" class + */ + +public class BoundaryDisplay implements IRenderable { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(BoundaryDisplay.class); + + private final GeometryFactory gf = new GeometryFactory(); + + public final RGB LIGHT_GRAY = new RGB(200, 200, 200); + + /* + * Boundary type color: Red for warn/Stationary fronts; Blue for cold + * fronts; orange for dry line fronts, pink for sea/lake breeze fronts, and + * Gray for gust fronts + */ + + public static final RGB COLD_FRONT = new RGB(0, 0, 255); + + public static final RGB WARM_FRONT = new RGB(255, 0, 0); + + public static final RGB DRY_LINE = new RGB(249, 104, 12); + + public static final RGB SEA_BREEZE = new RGB(255, 0, 206); + + public static final RGB GUST_FRONTS = new RGB(200, 200, 200); + + private final int editableCircleSize = 45; + + private final int unEditableCircleSize = 25; + + private final String dragTextFormat = "Drag %s to %s"; + + private static final double MAX_DIST = 20000000; + + private final DateFormat timeFormat = new SimpleDateFormat("HH:mm"); + + private IMapDescriptor descriptor; + + private final BoundaryUIManager manager; + + private int lastFrame = -1; + + public static final double ang = 15.0; + + private DataTime[] currentDisplayedTimes; + + /** HashMap to store active boundaries */ + public Map theAnchorLineMap = new HashMap(); + + /** HashMap to store active boundaries */ + public Map theAnchorIndexMap = new HashMap(); + + private int theAnchorIndex = -1; + + private final BoundaryUtil trackUtil; + + boolean timeUpdated = false; + + public BoundaryDisplay(IMapDescriptor descriptor, BoundaryUIManager manager) { + this.descriptor = descriptor; + this.timeFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + this.manager = manager; + trackUtil = this.manager.getTrackUtil(); + } + + public void setDescriptor(MapDescriptor descriptor) { + this.descriptor = descriptor; + } + + @Override + public void paint(IGraphicsTarget target, PaintProperties paintProps) + throws VizException { + paint(target, (BoundaryProperties) paintProps); + } + + private void paint(IGraphicsTarget target, BoundaryProperties paintProps) + throws VizException { + BoundaryState currentState = paintProps.getState(); + + DataTime[] times = trackUtil.getDataTimes(paintProps.getFramesInfo()); + // short circuit if no data times to paint + if (times.length == 0) { + return; + } + int currentTimeIndex = this.trackUtil.getCurrentFrame(paintProps + .getFramesInfo()); + currentState.timeIndex = currentTimeIndex; + DataTime[] dataTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + currentState.currentDataTimes = dataTimes; + int currentFrame = trackUtil + .getCurrentFrame(paintProps.getFramesInfo()); + + currentState.timePoints = currentState.timePointsMap + .get(currentState.boundaryId); + // If the state's time points are set and the times don't quite match up + if (currentState.timePoints != null + && (currentState.timePoints.length != times.length || !times[currentFrame] + .equals(currentState.timePoints[currentFrame].time, + true))) { + int oldPivot = currentState.pivotIndex; + trackUtil.setPivotIndexes(paintProps.getFramesInfo(), currentState); + + if (currentState.otherPivotIndex == currentState.pivotIndex) { + if (currentState.displayedPivotIndex == oldPivot) { + currentState.pivotIndex = 0; + } else { + currentState.otherPivotIndex = 0; + } + } + if (currentState.displayedPivotIndex == oldPivot) { + currentState.displayedPivotIndex = currentState.pivotIndex; + } + + if (currentFrame == currentState.displayedPivotIndex) { + if (currentState.displayedPivotIndex == currentState.pivotIndex + && currentState.otherPivotIndex >= 0) { + currentState.displayedPivotIndex = currentState.otherPivotIndex; + } else if (currentState.pivotIndex >= 0) { + currentState.displayedPivotIndex = currentState.pivotIndex; + } + } + + if (currentState.displayedPivotIndex >= times.length) { + currentState.displayedPivotIndex = Math.max(0, + currentFrame != times.length - 1 ? times.length - 1 + : times.length - 2); + } + + currentState.geomChanged = true; + target.setNeedsRefresh(true); + } else if (lastFrame != -1 && lastFrame != currentFrame) { + // This is a newly painted frame, update the display if we need to + if (currentState.nextPivotIndex != -1) { + // we acquired a new pivot index while painting the last frame + currentState.pivotIndex = currentState.nextPivotIndex; + currentState.otherPivotIndex = currentState.displayedPivotIndex; + currentState.displayedPivotIndex = currentState.pivotIndex; + currentState.nextPivotIndex = -1; + } else if (currentFrame == currentState.displayedPivotIndex) { + if (currentState.displayedPivotIndex == currentState.pivotIndex + && currentState.otherPivotIndex >= 0) { + currentState.displayedPivotIndex = currentState.otherPivotIndex; + } else if (currentState.pivotIndex >= 0) { + currentState.displayedPivotIndex = currentState.pivotIndex; + } + } else if (currentFrame != currentState.displayedPivotIndex) { + if (currentState.displayedPivotIndex == currentState.otherPivotIndex) { + currentState.displayedPivotIndex = currentState.pivotIndex; + } + } + + if (currentState.timePoints != null) { + + Coordinate[] anchorCoords = currentState.dragMePointMap.get( + currentState.boundaryId).getCoordinates(); + currentState.dragMePoint = new Point[anchorCoords.length]; + for (int k = 0; k < anchorCoords.length; k++) { + currentState.dragMePoint[k] = gf + .createPoint(anchorCoords[k]); + } + } + currentState.dragMeLine = currentState.boundariesMap + .get(currentState.boundaryId); + if (currentState.dragMeLine != null + && currentState.isMovingMap.get(currentState.boundaryId)) { + currentState.dragMeLine = manager.figureLineFromPoint( + currentState.dragMeLine, currentState.dragMePoint); + currentState.boundariesMap.remove(currentState.boundaryId); + currentState.boundariesMap.put(currentState.boundaryId, + currentState.dragMeLine); + if (!currentState.isMovingMap.get(currentState.boundaryId)) { + currentState.prevBoundary = currentState.dragMeLine; + } + + } + currentState.geomChanged = true; + target.setNeedsRefresh(true); + } + + switch (currentState.userAction) { + case READ_ACTIVE_BOUNDARIES: { + currentState.mode = BoundaryState.Mode.TRACK; + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + } + break; + } + + case EDIT_BOUNDARY: { + if (currentState.motionIsResetToStationary) { + currentState.frameAtCreationTime = trackUtil + .getCurrentFrame(paintProps.getFramesInfo()); + currentState.createTimeMap.remove(currentState.boundaryId); + currentState.editedTimeMap.remove(currentState.boundaryId); + currentState.timePoints = null; + currentState.createTimeMap.put(currentState.boundaryId, + dataTimes[currentTimeIndex]); + currentState.editedTimeMap.put(currentState.boundaryId, + dataTimes[currentTimeIndex]); + theAnchorLineMap.remove(currentState.boundaryId); + currentState.existingBoundaryNotEmptyMap + .remove(currentState.boundaryId); + currentState.existingBoundaryNotEmptyMap.put( + currentState.boundaryId, false); + currentState.editedLineForMotionComputation = null; + currentState.timePointsMap.remove(currentState.boundaryId); + currentState.motionIsResetToStationary = false; + } + currentState.dragMeLine = currentState.boundariesMap + .get(currentState.boundaryId); + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + } + + if (!currentState.isMovingMap.get(currentState.boundaryId)) { + currentState.editedTimeMap.remove(currentState.boundaryId); + currentState.editedTimeMap.put(currentState.boundaryId, + times[currentTimeIndex]); + } + break; + } + + case SAVE: { + /* + * new thread "saveData" to write the data to the disc when SaveBtn + * is clicked re-paint polylines after boundary data being saved + */ + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + } + currentState.editedLineForMotionComputation = null; + currentState.dragingLineNotAllowed = true; + break; + } + + case INSERT_BOUNDARY: { + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + } + currentState.frameAtCreationTime = trackUtil + .getCurrentFrame(paintProps.getFramesInfo()); + + currentState.createTimeMap.remove(currentState.boundaryId); + currentState.editedTimeMap.remove(currentState.boundaryId); + + currentState.createTimeMap.put(currentState.boundaryId, + dataTimes[currentTimeIndex]); + currentState.editedTimeMap.put(currentState.boundaryId, + dataTimes[currentTimeIndex]); + + currentState.userAction = UserAction.EDIT_BOUNDARY; + currentState.editedLineForMotionComputation = null; + currentState.motionIndex = currentFrame; + currentState.lineIsMoving = false; + currentState.movingEdited = false; + currentState.dragingLineNotAllowed = false; + break; + } + + case CANCEL_MODIFICATION: { + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + currentState.dialogObject.setBtnFalseAfterCancelAction(); + currentState.editedLineForMotionComputation = null; + currentState.dragingLineNotAllowed = true; + } + break; + } + + case NONE: { + if (!currentState.boundariesMap.isEmpty()) { + paintPolyMode(target, paintProps); + currentState.dialogObject.setBtnFalseAfterCancelAction(); + currentState.editedLineForMotionComputation = null; + currentState.dragingLineNotAllowed = true; + } + break; + } + } + + lastFrame = currentFrame; + } + + /** + * Paints the boundary track display + * + * @param target + * @param paintProps + */ + private void paintPolyMode(IGraphicsTarget target, + BoundaryProperties paintProps) throws VizException { + BoundaryState currentState = paintProps.getState(); + + switch (currentState.mode) { + + case DRAG_ME: { + + currentState.dialogObject.enableMotionSelection(false); + paintDragMeLine(target, paintProps); + paintDragMeText(target, paintProps, currentState.dragMeLine); + currentState.dragingLineNotAllowed = false; + break; + } + + case TRACK: { + currentState.dialogObject.enableMotionSelection(true); + if (currentState.loopingWasOn) { + currentState.loopingWasOn = false; + break; + } + DataTime frameTime = paintProps.getDataTime(); + generateTrackInfo(currentState, paintProps, frameTime); + if (currentState.motionIsResetToStationary) { + currentState.userAction = UserAction.EDIT_BOUNDARY; + break; + } + paintDragMeLine(target, paintProps); + if (trackUtil.getDataTimes(paintProps.getFramesInfo()).length == 1) { + paintDragMeText(target, paintProps, currentState.dragMeLine); + } + + /* + * Ama: Jan 11, 2011: Enabling send button when user modifies a + * stationary boundary line + */ + if (!currentState.isMovingMap.get(currentState.boundaryId) + && currentState.prevBoundary != null) { + Coordinate[] prevCoords = currentState.prevBoundary + .getCoordinates(); + Coordinate[] currentCoords = currentState.dragMeLine + .getCoordinates(); + boolean vertexMoved = false; + boolean lengthChanged = false; + if (prevCoords.length == currentCoords.length) { + for (int i = 0; i < prevCoords.length; i++) { + if (prevCoords[i].x != currentCoords[i].x + || prevCoords[i].y != currentCoords[i].y) { + vertexMoved = true; + } + + } + } else { + lengthChanged = true; + } + + if (lengthChanged || vertexMoved) { + currentState.dialogObject.setBtnTrueAfterCancelAction(); + } + } + + break; + } + + // end of switch + } + currentState.dragMeGeom = currentState.dragMeLine; + } + + /** + * Like paintDragMePoint, this will paint the drag line which is a little + * different than drawing a line then drawing points. If editable, points + * will look like drpaintPolyModeag me points but it not, will be smaller + * filled in circle + * + * @param target + * @param paintProps + * @throws VizException + */ + private void paintDragMeLine(IGraphicsTarget target, + BoundaryProperties paintProps) throws VizException { + BoundaryState state = paintProps.getState(); + final double circleSize = state.isEditable() ? editableCircleSize + * paintProps.getZoomLevel() : unEditableCircleSize + * paintProps.getZoomLevel(); + + // get the magnification from the state + float magnification = state.magnification; + LineString line = state.boundariesMap.get(state.boundaryId); + + if (line == null) { + GeodeticCalculator gc = new GeodeticCalculator(descriptor.getCRS()); + int numPoints = state.numDragMePoints; + double[] worldPixel = descriptor.pixelToWorld(paintProps.getView() + .getExtent().getCenter()); + double lengthInMeters = state.distanceThreshold + * state.lineOfStormsLength; + gc.setStartingGeographicPoint(worldPixel[0], worldPixel[1]); + double startAngle = state.angle; + double firstAngle = startAngle - 90; + double secondAngle = startAngle + 90; + gc.setDirection(trackUtil.adjustAngle(firstAngle), lengthInMeters); + Coordinate c1 = new Coordinate(gc.getDestinationGeographicPoint() + .getX(), gc.getDestinationGeographicPoint().getY()); + + gc.setStartingGeographicPoint(worldPixel[0], worldPixel[1]); + gc.setDirection(trackUtil.adjustAngle(secondAngle), lengthInMeters); + Coordinate c3 = new Coordinate(gc.getDestinationGeographicPoint() + .getX(), gc.getDestinationGeographicPoint().getY()); + + Coordinate[] coords = null; + // unless explicitly set to 2, assume 3 points + if (numPoints == 2) { + coords = new Coordinate[] { c1, c3 }; + } else { + coords = new Coordinate[] { c1, + new Coordinate(worldPixel[0], worldPixel[1]), c3 }; + } + line = new GeometryFactory().createLineString(coords); + + if (state.dragMePoint != null) { + if (state.dragMePointMap.get(state.boundaryId) == null) + state.dragMePointMap.put(state.boundaryId, line); + Coordinate[] dragLineCoords = state.dragMePointMap.get( + state.boundaryId).getCoordinates(); + state.dragMePoint = new Point[dragLineCoords.length]; + for (int k = 0; k < dragLineCoords.length; k++) { + state.dragMePoint[k] = gf.createPoint(dragLineCoords[k]); + } + state.dragMeLine = manager.figureLineFromPoint(line, + state.dragMePoint); + line = state.dragMeLine; + state.boundariesMap.remove(state.boundaryId); + state.boundariesMap.put(state.boundaryId, line); + } else { + state.dragMeLine = line; + state.boundariesMap.remove(state.boundaryId); + state.boundariesMap.put(state.boundaryId, line); + } + } + + /* + * Time to paint the line. Again, need to handle if mouseDownGeom set or + * not + */ + RGB lineColor = state.mouseDownGeom != null ? LIGHT_GRAY : state.color; + + RGB textColor = state.color; + + // KS - Need to loop over all lines rather than just paint one + + int moveIndex = this.trackUtil.getCurrentFrame(paintProps + .getFramesInfo()); + BoundaryPolyLine[] currentTimePoints; + LineString boundary; + Iterator iterator = state.boundariesMap.keySet().iterator(); + while (iterator.hasNext()) { + + int boundaryId = iterator.next(); + if (state.isMovingMap.get(boundaryId)) { + currentTimePoints = state.timePointsMap.get(boundaryId); + boundary = currentTimePoints[moveIndex].polyline; + + } else { + boundary = state.boundariesMap.get(boundaryId); + } + + Coordinate[] coords = boundary.getCoordinates(); + if (boundaryId == state.boundaryId + && state.userAction != UserAction.SAVE + && state.userAction != UserAction.READ_ACTIVE_BOUNDARIES + && state.userAction != UserAction.DELETE_BOUNDARY + && state.userAction != UserAction.NONE + && state.userAction != UserAction.CANCEL_MODIFICATION) { + paintLine(target, boundary.getCoordinates(), lineColor, + state.lineWidth, state.isEditable(), circleSize, + state.lineStyle); + + } else { + + String frontType = state.boundaryTypeMap.get(boundaryId); + /* + * check if frontType is null; this will prevent null exception + * when the user load the tool while the looping was on and they + * insert new boundary. + */ + + if (frontType == null) { + lineColor = state.color; + } else { + switch (frontType) { + case "COLD FRONT": + lineColor = COLD_FRONT; + textColor = COLD_FRONT; + break; + case "STATIONARY/WARM FRONT": + lineColor = WARM_FRONT; + textColor = WARM_FRONT; + break; + case "DRY LINE": + lineColor = DRY_LINE; + textColor = DRY_LINE; + break; + case "SEA/LAKE BREEZE": + lineColor = SEA_BREEZE; + textColor = SEA_BREEZE; + break; + case "GUST FRONT": + lineColor = GUST_FRONTS; + textColor = GUST_FRONTS; + break; + + } + } + + paintLine(target, boundary.getCoordinates(), lineColor, + state.lineWidth, false, unEditableCircleSize, + state.lineStyle); + lineColor = state.color; + } + + // draw boundary Id text + + Coordinate last = coords[coords.length - 1]; + Coordinate toUseId = null; + toUseId = new Coordinate(last.x, last.y); + String text = "" + boundaryId; + paintTextAtPoint(target, text, toUseId, textColor, circleSize * 3, + ang, magnification); + textColor = state.color; + } + + if (state.mouseDownGeom != null) { + paintLine(target, state.mouseDownGeom.getCoordinates(), + state.color, state.lineWidth, state.isEditable(), + circleSize, LineStyle.DOTTED); + lineColor = LIGHT_GRAY; + } + } + + /** + * Paints a line with points at each vertex in the line on the screen + * + * @param target + * @param coords + * coordinates in the line + * @param color + * color of the line + * @param lineWidth + * @param editable + * if the line is editable + * @throws VizException + */ + private void paintLine(IGraphicsTarget target, Coordinate[] coords, + RGB color, float lineWidth, boolean editable, double circleSize, + LineStyle style) throws VizException { + DrawableCircle circle = new DrawableCircle(); + circle.basics.color = color; + circle.radius = circleSize; + circle.filled = true; + + DrawableLine line = new DrawableLine(); + line.basics.color = color; + line.width = lineWidth; + line.lineStyle = style; + double[] p1; + for (int i = 0; i < coords.length; ++i) { + Coordinate currCoord = coords[i]; + if (currCoord != null) { + // paint point + if (editable) { + paintPoint(target, currCoord, color, circleSize); + } else { + p1 = descriptor.worldToPixel(new double[] { currCoord.x, + currCoord.y }); + circle.setCoordinates(p1[0], p1[1]); + target.drawCircle(circle); + } + + p1 = descriptor.worldToPixel(new double[] { currCoord.x, + currCoord.y }); + line.addPoint(p1[0], p1[1]); + } + } + target.drawLine(line); + } + + /** + * + * @param target + * @param point + * @param color + * @param circleSize + * @throws VizException + */ + private void paintPoint(IGraphicsTarget target, Coordinate point, + RGB color, double circleSize) throws VizException { + if (point == null) { + return; + } + // Paint the point + double[] p1 = descriptor + .worldToPixel(new double[] { point.x, point.y }); + + if (p1 == null) { + return; + } + + DrawableCircle circle = new DrawableCircle(); + circle.basics.color = color; + circle.setCoordinates(p1[0], p1[1]); + circle.radius = 2 * circleSize; + target.drawCircle(circle); + + circle.filled = true; + circle.radius = circleSize; + target.drawCircle(circle); + } + + /** + * Paint the drag me text + * + * @param target + * @param paintProps + * @throws VizException + */ + private void paintDragMeText(IGraphicsTarget target, + BoundaryProperties paintProps, Geometry dragMeGeom) + throws VizException { + final double circleSize = editableCircleSize + * paintProps.getZoomLevel(); + + BoundaryState state = paintProps.getState(); + // get the magnification from the state + float magnification = state.magnification; + + String text = String.format(dragTextFormat, state.userAction.dragWhat, + state.thingToDragTo); + Geometry geom = dragMeGeom; + Geometry mouseDownGeom = state.mouseDownGeom; + RGB geomColor = mouseDownGeom != null ? LIGHT_GRAY : state.color; + + // draw text using this drag geom + Coordinate[] coords = geom.getCoordinates(); + Coordinate toUse = null; + Coordinate toUseId = null; + if (coords.length == 1) { + toUse = coords[0]; + } else if (coords.length > 1) { + // pick half way between last 2 + Coordinate last = coords[coords.length - 1]; + Coordinate secondLast = coords[coords.length - 2]; + + toUse = new Coordinate(last.x - (last.x - secondLast.x) / 2, last.y + - (last.y - secondLast.y) / 2); + toUseId = new Coordinate(last.x, last.y); + } + paintTextAtPoint(target, text, toUse, geomColor, circleSize * 3, ang, + magnification); + text = "" + state.boundaryId; + paintTextAtPoint(target, text, toUseId, state.color, circleSize * 3, + ang, magnification); + + if (mouseDownGeom != null) { + // draw text using mouse geom + coords = mouseDownGeom.getCoordinates(); + toUse = null; + if (coords.length == 1) { + toUse = coords[0]; + } else if (coords.length > 1) { + // pick half way between last 2 + Coordinate last = coords[coords.length - 1]; + Coordinate secondLast = coords[coords.length - 2]; + + toUse = new Coordinate(last.x - (last.x - secondLast.x) / 2, + last.y - (last.y - secondLast.y) / 2); + } + paintTextAtPoint(target, text, toUse, state.color, circleSize * 3, + ang, magnification); + } + + } + + /** + * Paints text at an offset from a point with left alignment + * + * @param target + * @param text + * @param point + * @param color + * @param radiusFromPoint + * @param angle + * @throws VizException + */ + private void paintTextAtPoint(IGraphicsTarget target, String text, + Coordinate point, RGB color, double radiusFromPoint, double angle, + float magnification) throws VizException { + paintTextAtPoint(target, text, point, color, radiusFromPoint, angle, + HorizontalAlignment.LEFT, VerticalAlignment.BOTTOM, + magnification); + } + + /** + * Paints text at an offset from a point + * + * @param target + * @param text + * @param point + * @param color + * @param radiusFromPoint + * @param angle + * @param hAlignment + * horizontal alignment + * @param vAlignment + * vertical alignment + * + * @throws VizException + */ + private void paintTextAtPoint(IGraphicsTarget target, String text, + Coordinate point, RGB color, double radiusFromPoint, double angle, + HorizontalAlignment hAlignment, VerticalAlignment vAlignment, + float magnification) throws VizException { + // get screen location of point + double[] p1 = descriptor + .worldToPixel(new double[] { point.x, point.y }); + + // get screen location of where to draw text using point + double[] labelLoc = target.getPointOnCircle(p1[0], p1[1], 0.0, + radiusFromPoint, angle); + DrawableString str = new DrawableString(text, color); + str.horizontalAlignment = hAlignment; + str.verticalAlignment = vAlignment; + // set the string magnification + str.magnification = magnification; + str.setCoordinates(labelLoc[0], labelLoc[1]); + + // draw the string + target.drawStrings(str); + } + + /** + * Generates the start track info from the state + * + * @param currentState + */ + private void generateTrackInfo(BoundaryState currentState, + PaintProperties paintProps, DataTime frameTime) throws VizException { + int frameCount = trackUtil.getFrameCount(paintProps.getFramesInfo()); + int currFrame = trackUtil.getCurrentFrame(paintProps.getFramesInfo()); + DataTime[] times = trackUtil.getDataTimes(paintProps.getFramesInfo()); + + /* + * Ama: October 4, 2011 when time updates, update position for all + * active moving boundaries at the current time Resetting to polyline to + * its original form before the user tries to move it without selecting + * another frame other the one at creation frame + */ + + int currentBoundaryId = currentState.boundaryId; + + boolean update = isUpdatedDataTimes(paintProps); + /* + * Create a map holding the active boundaries Since boundariesMap is + * being modified, cannot use "iterator" using "iterator" statement + * while the list is modified causes "ConcurrentModificationException" + */ + Map activeBoundariesMap = new HashMap(); + + for (int i : currentState.boundariesMap.keySet()) { + if (currentState.isMovingMap.get(i)) { + if (currentState.existingBoundaryNotEmptyMap.get(i) == null) { + currentState.existingBoundaryNotEmptyMap.put(i, false); + } + activeBoundariesMap.put(i, i); + } + + } + + /* + * Now looping moving boundaries to update their position if the time + * update + */ + for (int bndId : activeBoundariesMap.keySet()) { + if (update || currentState.existingBoundaryNotEmptyMap.get(bndId)) { + currentState.boundaryId = bndId; + + } else if (bndId != currentState.boundaryId) { + continue; + } + + try { + boolean moved = false; + currentState.timePoints = currentState.timePointsMap + .get(currentState.boundaryId); + + if (currentState.timePointsMap.get(currentState.boundaryId) == null + || currentState.timePoints.length != frameCount + || currentState.newDuration != -1 + || update + || currentState.existingBoundaryNotEmptyMap + .get(currentState.boundaryId)) { + + /* + * if "update = true" then we need to remove the current + * boundary from timePointMap and theAnchorLineMap + */ + if (currentState.timePoints != null + && currentState.timePoints.length != frameCount) { + /* + * need to set theAnchorPoint and theAnchorIndex here + * because timePoints get erased before we get to + * updateAnchorPoint + */ + + for (int j = 0; j < currentState.timePoints.length; j++) { + if (frameTime + .equals(currentState.timePoints[j].time)) { + theAnchorLineMap + .remove(currentState.boundaryId); + theAnchorLineMap.put(currentState.boundaryId, + currentState.timePoints[j].polyline); + theAnchorIndex = j; + } + } + currentState.timePoints = null; + + currentState.timePointsMap + .remove(currentState.boundaryId); + currentState.timePointsMap.put(currentState.boundaryId, + currentState.timePoints); + } + + if (currentState.newDuration != -1) { + currentState.duration = currentState.newDuration; + currentState.newDuration = -1; + } + + if (this.theAnchorLineMap.get(currentState.boundaryId) == null + && currentState.existingBoundaryNotEmptyMap + .get(currentState.boundaryId) == false) { + this.theAnchorLineMap.remove(currentState.boundaryId); + + this.theAnchorLineMap.put(currentState.boundaryId, + currentState.dragMePointMap + .get(currentState.boundaryId)); + currentState.dragMePointMap + .remove(currentState.boundaryId); + + currentState.dragMePointMap.put( + currentState.boundaryId, this.theAnchorLineMap + .get(currentState.boundaryId)); + currentState.timePoints = null; + currentState.timePointsMap + .remove(currentState.boundaryId); + currentState.timePointsMap.put(currentState.boundaryId, + currentState.timePoints); + currentState.lineMovedMap + .remove(currentState.boundaryId); + currentState.lineMovedMap.put(currentState.boundaryId, + false); + } else if (update && currentState.timePoints != null) { + this.theAnchorLineMap.remove(currentState.boundaryId); + this.theAnchorLineMap.put(currentState.boundaryId, + updateAnchorLineMap(currentState, paintProps)); + currentState.timePoints = null; + currentState.timePointsMap + .remove(currentState.boundaryId); + currentState.timePointsMap.put(currentState.boundaryId, + currentState.timePoints); + + } else if (currentState.existingBoundaryNotEmptyMap + .get(currentState.boundaryId) + && currentState.timePoints == null) { + + this.theAnchorLineMap.put(currentState.boundaryId, + updateAnchorLineMap(currentState, paintProps)); + currentState.timePoints = null; + currentState.timePointsMap + .remove(currentState.boundaryId); + currentState.timePointsMap.put(currentState.boundaryId, + currentState.timePoints); + currentState.lineMovedMap.put(currentState.boundaryId, + false); + } + + generateNewTrackInfo(currentState, currFrame, paintProps); + currentDisplayedTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + + currentState.displayedIndexAtStartMotionCompute = this.trackUtil + .getCurrentFrame(paintProps.getFramesInfo()); + + generateTrackInfo(currentState, paintProps, frameTime); + } else { + if (currentState.lineMovedMap.get(currentState.boundaryId)) { + if (currentState.userAction == UserAction.EDIT_BOUNDARY) { + currentState.editedTimeMap + .remove(currentState.boundaryId); + currentState.editedTimeMap.put( + currentState.boundaryId, times[currFrame]); + if (currentState.geomChanged == true) { + currentState.dialogObject + .setBtnTrueAfterCancelAction(); + } + } + this.theAnchorLineMap.remove(currentState.boundaryId); + this.theAnchorLineMap.put(currentState.boundaryId, + currentState.dragMePointMap + .get(currentState.boundaryId)); + generateExistingTrackInfo(currentState, paintProps); + if (currentState.motionIsResetToStationary) { + return; + } + currentState.lineMovedMap + .remove(currentState.boundaryId); + currentState.lineMovedMap.put(currentState.boundaryId, + false); + moved = true; + } + + currentDisplayedTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + if (moved) { + this.theAnchorIndex = currFrame; + currentState.timePoints = currentState.timePointsMap + .get(currentState.boundaryId); + this.theAnchorLineMap.remove(currentState.boundaryId); + this.theAnchorLineMap + .put(currentState.boundaryId, + currentState.timePoints[theAnchorIndex].polyline); + } + } + + } catch (ImpossibleTrackException e) { + statusHandler.handle(Priority.PROBLEM, + "Track produced an impossible scenario", e); + } + currentState.timePoints = currentState.timePointsMap + .get(currentState.boundaryId); + if (currentState.timePoints != null) { + LineString dragPointLine = currentState.timePoints[currFrame].polyline; + Coordinate[] dragLineCoords = dragPointLine.getCoordinates(); + currentState.dragMePoint = new Point[dragLineCoords.length]; + for (int k = 0; k < dragLineCoords.length; k++) { + currentState.dragMePoint[k] = gf + .createPoint(dragLineCoords[k]); + } + currentState.dragMePointMap.remove(currentState.boundaryId); + + currentState.dragMePointMap.put(currentState.boundaryId, + dragPointLine); + + if (currentState.boundariesMap.get(currentState.boundaryId) != null) { + + currentState.dragMeLine = manager.figureLineFromPoint( + currentState.boundariesMap + .get(currentState.boundaryId), + currentState.dragMePoint); + currentState.boundariesMap.remove(currentState.boundaryId); + currentState.boundariesMap.put(currentState.boundaryId, + currentState.dragMeLine); + } + } else { + currentState.mode = BoundaryState.Mode.DRAG_ME; + currentState.dragMePointMap.remove(currentState.boundaryId); + + currentState.dragMePointMap.put(currentState.boundaryId, + this.theAnchorLineMap.get(currentState.boundaryId)); + Coordinate[] dragLineCoords = this.theAnchorLineMap.get( + currentState.boundaryId).getCoordinates(); + currentState.dragMePoint = new Point[dragLineCoords.length]; + for (int k = 0; k < dragLineCoords.length; k++) { + currentState.dragMePoint[k] = gf + .createPoint(dragLineCoords[k]); + } + } + } + currentState.boundaryId = currentBoundaryId; + } + + private void generateExistingTrackInfo(BoundaryState state, + PaintProperties paintProps) { + int moveIndex = this.trackUtil.getCurrentFrame(paintProps + .getFramesInfo()); + moveIndex = Math.min(moveIndex, state.timePoints.length - 1); + int pivotIndex = state.displayedPivotIndex; + pivotIndex = Math.min(pivotIndex, state.timePoints.length - 1); + BoundaryPolyLine startCoordForMotion; + BoundaryPolyLine endCoordForMotion; + int startCoordIndex; + int endCoordIndex; + state.timePoints = state.timePointsMap.get(state.boundaryId); + + state.timePoints[moveIndex].polyline = state.dragMePointMap + .get(state.boundaryId); + + startCoordIndex = pivotIndex < moveIndex ? pivotIndex : moveIndex; + endCoordIndex = pivotIndex < moveIndex ? moveIndex : pivotIndex; + if (startCoordIndex < moveIndex) { + startCoordIndex = endCoordIndex = moveIndex; + } + + BoundaryPolyLine startCoord = state.timePoints[startCoordIndex]; + BoundaryPolyLine endCoord = state.timePoints[endCoordIndex]; + + Coordinate[] lineStartCoords = startCoord.polyline.getCoordinates(); + Coordinate[] lineEndCoords = endCoord.polyline.getCoordinates(); + Coordinate[] endVertices = new Coordinate[lineEndCoords.length]; + + double angle = 0.0; + double oppositeAngle = 0.0; + double speed = 0.0; + if (state.vertexSpeedMap.get(state.boundaryId) != null) { + state.vertexSpeed = state.vertexSpeedMap.get(state.boundaryId); + state.vertexAngle = state.vertexAngleMap.get(state.boundaryId); + } + BoundaryPolyLine[] timePoints = new BoundaryPolyLine[state.timePoints.length]; + + /* + * If the user does not select another frame different of the frame + * where the line is created, nothing will happens until she move to + * another frame (a message will pop up to remind the user to select a + * different frame). + */ + if (state.lineIsMoving && (moveIndex == state.frameAtCreationTime) + && state.editedLineForMotionComputation != null) { + state.timePoints[moveIndex].polyline = state.editedLineForMotionComputation; + MessageDialog.openWarning(Display.getCurrent().getActiveShell(), + "Invalid Action", + "Please change the frame to generate boundary motion"); + + } else { + /* + * Motion computation for moving boundary + * editedLineForMotionComputation: original boundary at creation + * time + */ + if (state.editedLineForMotionComputation != null) { + startCoordForMotion = state.timePoints[moveIndex]; + endCoordForMotion = state.timePoints[state.displayedIndexAtStartMotionCompute]; + + Coordinate[] lineStartCoordsForMotion; + + lineStartCoordsForMotion = startCoordForMotion.polyline + .getCoordinates(); + lineEndCoords = state.editedLineForMotionComputation + .getCoordinates(); + if (lineStartCoordsForMotion.length == lineEndCoords.length + && state.isEditable()) { + + GeodeticCalculator gc = new GeodeticCalculator(); + for (int j = 0; j < lineStartCoordsForMotion.length; j++) { + + if (state.displayedIndexAtStartMotionCompute > moveIndex) { + gc.setStartingGeographicPoint( + lineStartCoordsForMotion[j].x, + lineStartCoordsForMotion[j].y); + gc.setDestinationGeographicPoint( + lineEndCoords[j].x, lineEndCoords[j].y); + } else { + gc.setStartingGeographicPoint(lineEndCoords[j].x, + lineEndCoords[j].y); + gc.setDestinationGeographicPoint( + lineStartCoordsForMotion[j].x, + lineStartCoordsForMotion[j].y); + + } + angle = gc.getAzimuth(); + oppositeAngle = trackUtil.adjustAngle(angle + 180); + speed = gc.getOrthodromicDistance() + / trackUtil.timeBetweenDataTimes( + startCoordForMotion.time, + endCoordForMotion.time); + state.vertexAngle[j] = (float) angle; + state.vertexSpeed[j] = (float) speed; + } + } + state.editedLineForMotionComputation = null; + + } + + timePoints[startCoordIndex] = startCoord; + timePoints[endCoordIndex] = endCoord; + + for (int i = timePoints.length - 1; i >= 0; --i) { + if (i == startCoordIndex || i == endCoordIndex) { + continue; + } + + DataTime coordTime = state.timePoints[i].time; + + /* + * Preventing a paint error. When a distance is out of range the + * user will get an alert indicating that she must follow the + * correct steps for creating a moving boundary. This alert + * prevents the paint error to occur + */ + for (int j = 0; j < lineStartCoords.length; j++) { + if (state.vertexSpeed[j] + * trackUtil.timeBetweenDataTimes(startCoord.time, + coordTime) > MAX_DIST) { + invalidAction(); + state.editedLineForMotionComputation = state.boundariesMap + .get(state.boundaryId); + + state.dialogObject.outOfrangeError(); + return; + } + } + GeodeticCalculator gc = new GeodeticCalculator(); + for (int j = 0; j < lineStartCoords.length; j++) { + + oppositeAngle = trackUtil + .adjustAngle(state.vertexAngle[j] + 180); + gc.setStartingGeographicPoint(lineStartCoords[j].x, + lineStartCoords[j].y); + + double distance = state.vertexSpeed[j] + * trackUtil.timeBetweenDataTimes(startCoord.time, + coordTime); + if (distance > MAX_DIST) { + invalidAction(); + state.editedLineForMotionComputation = state.boundariesMap + .get(state.boundaryId); + + state.dialogObject.outOfrangeError(); + return; + } + if (i > startCoordIndex) { + gc.setDirection(state.vertexAngle[j], distance); + } else if (i < startCoordIndex) { + gc.setDirection(oppositeAngle, distance); + } + Point2D point = gc.getDestinationGeographicPoint(); + endVertices[j] = new Coordinate(point.getX(), point.getY()); + } + if (state.vertexSpeedMap.get(state.boundaryId) != null) { + state.vertexSpeedMap.remove(state.boundaryId); + state.vertexAngleMap.remove(state.boundaryId); + state.vertexAngleMap.put(state.boundaryId, + state.vertexAngle); + state.vertexSpeedMap.put(state.boundaryId, + state.vertexSpeed); + } else { + state.vertexAngleMap.put(state.boundaryId, + state.vertexAngle); + state.vertexSpeedMap.put(state.boundaryId, + state.vertexSpeed); + + } + + Coordinate[] newLineCoords = new Coordinate[lineEndCoords.length]; + for (int k = 0; k < lineEndCoords.length; k++) { + newLineCoords[k] = endVertices[k]; + + } + LineString line = new GeometryFactory() + .createLineString(newLineCoords); + timePoints[i] = new BoundaryPolyLine(line, coordTime); + } + state.timePointsMap.remove(state.boundaryId); + + state.timePointsMap.put(state.boundaryId, timePoints); + } + } + + private void generateNewTrackInfo(BoundaryState state, int anchorIndex, + PaintProperties paintProps) throws ImpossibleTrackException { + double oppositeAngle; + int frameCount = trackUtil.getFrameCount(paintProps.getFramesInfo()); + state.timePoints = state.timePointsMap.get(state.boundaryId); + + if (state.timePointsMap.get(state.boundaryId) != null) { + theAnchorIndex = frameCount + - (state.timePoints.length - theAnchorIndex); + if (theAnchorIndex >= 0 && theAnchorIndex < frameCount) { + anchorIndex = theAnchorIndex; + } else { + theAnchorIndex = 0; + } + LineString polyline = state.timePoints[state.timePoints.length + - (frameCount - anchorIndex)].polyline; + theAnchorLineMap.remove(state.boundaryId); + theAnchorLineMap.put(state.boundaryId, polyline); + } else { + theAnchorIndex = anchorIndex; + } + DataTime[] dataTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + BoundaryPolyLine[] timePoints = new BoundaryPolyLine[frameCount]; + BoundaryPolyLine anchor = new BoundaryPolyLine( + this.theAnchorLineMap.get(state.boundaryId), + dataTimes[anchorIndex]); + + timePoints[anchorIndex] = anchor; + if (state.timePointsMap.get(state.boundaryId) == null + || isUpdatedDataTimes(paintProps)) { + + /* + * Compute/retrieve vertex coordinate of the starting position of + * the line + */ + Coordinate[] lineCoords = anchor.polyline.getCoordinates(); + Coordinate[] vertices = new Coordinate[lineCoords.length]; + + float[] vertexSpeed = new float[lineCoords.length]; + for (int i = 0; i < lineCoords.length; i++) { + vertexSpeed[i] = (float) 0.0; + } + state.vertexSpeed = state.vertexSpeedMap.get(state.boundaryId); + state.vertexAngle = state.vertexAngleMap.get(state.boundaryId); + + if (state.vertexSpeed == null) { + state.vertexSpeed = new float[lineCoords.length]; + state.vertexAngle = new float[lineCoords.length]; + } + for (int i = timePoints.length - 1; i >= 0; --i) { + if (i == anchorIndex) { + continue; + } + + DataTime coordTime = dataTimes[i]; + + for (int j = 0; j < lineCoords.length; j++) { + + Coordinate[] coords = state.boundariesMap.get( + state.boundaryId).getCoordinates(); + if (state.vertexSpeed == null || state.vertexAngle == null) { + state.vertexSpeed[j] = vertexSpeed[j]; + + // calculate based on polyline + GeodeticCalculator gc = new GeodeticCalculator(); + gc.setStartingGeographicPoint(coords[j].x, coords[j].y); + gc.setDestinationGeographicPoint( + coords[coords.length - 1].x, + coords[coords.length - 1].y); + state.vertexAngle[j] = (float) trackUtil.adjustAngle(gc + .getAzimuth() - 90); + } + oppositeAngle = trackUtil + .adjustAngle(state.vertexAngle[j] + 180); + + GeodeticCalculator gc = new GeodeticCalculator(); + gc.setStartingGeographicPoint(lineCoords[j].x, + lineCoords[j].y); + + double distance = state.vertexSpeed[j] + * trackUtil.timeBetweenDataTimes(anchor.time, + coordTime); + if (distance > MAX_DIST) { + invalidAction(); + state.editedLineForMotionComputation = state.boundariesMap + .get(state.boundaryId); + + state.dialogObject.outOfrangeError(); + return; + } + + if (i > anchorIndex) { + gc.setDirection(state.vertexAngle[j], distance); + } else if (i < anchorIndex) { + gc.setDirection(oppositeAngle, distance); + } + Point2D point = gc.getDestinationGeographicPoint(); + + vertices[j] = new Coordinate(point.getX(), point.getY()); + } + if (state.vertexSpeedMap.get(state.boundaryId) != null) { + state.vertexSpeedMap.remove(state.boundaryId); + state.vertexAngleMap.remove(state.boundaryId); + state.vertexAngleMap.put(state.boundaryId, + state.vertexAngle); + state.vertexSpeedMap.put(state.boundaryId, + state.vertexSpeed); + } else { + state.vertexAngleMap.put(state.boundaryId, + state.vertexAngle); + state.vertexSpeedMap.put(state.boundaryId, + state.vertexSpeed); + } + Coordinate[] newLineCoords = new Coordinate[lineCoords.length]; + for (int j = 0; j < vertices.length; j++) { + newLineCoords[j] = vertices[j]; + + } + LineString line = new GeometryFactory() + .createLineString(newLineCoords); + timePoints[i] = new BoundaryPolyLine(line, coordTime); + } + } else { + timePoints = state.timePointsMap.get(state.boundaryId); + } + + if (state.duration == -1) { + state.duration = trackUtil.timeBetweenDataTimes(dataTimes[0], + dataTimes[dataTimes.length - 1]) / 60; + } + state.timePointsMap.remove(state.boundaryId); + state.timePointsMap.put(state.boundaryId, timePoints); + } + + private LineString updateAnchorLineMap(BoundaryState currentState, + PaintProperties paintProps) { + int currFrame = trackUtil.getCurrentFrame(paintProps.getFramesInfo()); + BoundaryPolyLine sc = null; + if (currentState.existingBoundaryNotEmptyMap + .get(currentState.boundaryId)) { + sc = new BoundaryPolyLine( + currentState.boundariesMap.get(currentState.boundaryId), + currentState.creationFileTime); + if (currentState.existingBoundaryNotEmptyMap != null) + currentState.existingBoundaryNotEmptyMap + .remove(currentState.boundaryId); + currentState.existingBoundaryNotEmptyMap.put( + currentState.boundaryId, false); + } else { + sc = currentState.timePoints[currFrame]; + } + DataTime[] dataTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + double distance; + + Coordinate[] coords = sc.polyline.getCoordinates(); + Coordinate[] vertices = new Coordinate[coords.length]; + float[] vertexSpeed = currentState.vertexSpeedMap + .get(currentState.boundaryId); + float[] vertexAngle = currentState.vertexAngleMap + .get(currentState.boundaryId); + for (int j = 0; j < coords.length; j++) { + GeodeticCalculator gc = new GeodeticCalculator(); + gc.setStartingGeographicPoint(coords[j].x, coords[j].y); + distance = vertexSpeed[j] + * trackUtil.timeBetweenDataTimes(sc.time, + dataTimes[currFrame]); + gc.setDirection(vertexAngle[j], distance); + Point2D point = gc.getDestinationGeographicPoint(); + vertices[j] = new Coordinate(point.getX(), point.getY()); + } + Coordinate[] newLineCoords = new Coordinate[vertices.length]; + for (int j = 0; j < vertices.length; j++) { + newLineCoords[j] = vertices[j]; + + } + return new GeometryFactory().createLineString(newLineCoords); + + } + + public boolean isUpdatedDataTimes(PaintProperties paintProps) { + DataTime[] uniqueTimes = trackUtil.getDataTimes(paintProps + .getFramesInfo()); + if (currentDisplayedTimes == null) { + return false; + } + int len = currentDisplayedTimes.length; + return uniqueTimes.length != len + || (!uniqueTimes[0].equals(currentDisplayedTimes[0]) && !uniqueTimes[len - 1] + .equals(currentDisplayedTimes[len - 1])); + } + + public void invalidAction() { + MessageDialog + .openWarning( + Display.getCurrent().getActiveShell(), + "Invalid Action for setting the motion", + "Please follow the proper steps in setting the boundary in motion " + + " The boundary is being reset to stationary \n" + + " Now retry to set it in motion following these two simple steps: \n" + + " 1) Select 'Moving' from 'Boundary Mode's dropdown menu \n" + + " 2) move to another frame " + + "before dragging the line to the desired position"); + + return; + } +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryProperties.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryProperties.java new file mode 100644 index 0000000000..f64ce55f0f --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryProperties.java @@ -0,0 +1,33 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import com.raytheon.uf.viz.core.drawables.PaintProperties; + +/** + * + * @author Mamoudou Ba + * @version 1.0 + * + * Entirely reused of A2 "StormTrackProperties" Class by renaming it + * and its methods + */ + +public class BoundaryProperties extends PaintProperties { + + private BoundaryState state; + + public BoundaryProperties(PaintProperties props, BoundaryState state) { + super(props); + this.state = state; + state.distanceThreshold = (props.getView().getExtent().getWidth() / props + .getCanvasBounds().width) * 10; + } + + public BoundaryState getState() { + return state; + } + + public void setState(BoundaryState state) { + this.state = state; + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryState.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryState.java new file mode 100644 index 0000000000..1b02463735 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryState.java @@ -0,0 +1,258 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import gov.noaa.nws.mdl.viz.boundaryTool.ui.dialog.BoundaryEditorDialog; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.graphics.RGB; + +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.IGraphicsTarget; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Point; + +/** + * + * @author Mamoudou ba + * @version 1.0 + * + * April 2011: Substantially modified from A2 "StormTrackState" class + */ + +public class BoundaryState { + + public enum Mode { + DRAG_ME, TRACK, NONE + }; + + public enum UserAction { + SAVE("save me"), INSERT_BOUNDARY("line"), EDIT_BOUNDARY(" edit me"), DELETE_BOUNDARY( + "delete me"), READ_ACTIVE_BOUNDARIES("read me"), CANCEL_MODIFICATION( + "cancel modif"), NONE("no action"); + + public String dragWhat; + + private UserAction(String text) { + this.dragWhat = text; + } + } + + public enum LabelMode { + TIME, SPEED; + } + + public static class BoundaryPolyLine { + public LineString polyline; + + public DataTime time; + + public BoundaryPolyLine(LineString polyline, DataTime time) { + this.polyline = polyline; + this.time = time; + } + } + + /** Drawing mode, TRACK or DRAG */ + public Mode mode; + + /** + * User's actions: Insert, Edit, Save, Delete a boundary, or Select a + * boundary type ------------- and Read from XML when the tool opens + */ + public UserAction userAction; + + /** + * How to draw the labels (SPEED or TIME) + */ + public LabelMode labelMode; + + public boolean editable = true; + + // public boolean isMoving = false; + + public Map isMovingMap = new HashMap(); + + public boolean isEditable() { + return editable; + } + + /** the array of time/loc coordinates for the frames */ + + public BoundaryPolyLine[] timePoints; + + public Map timePointsMap = new HashMap(); + + /** + * The future points, will include timePoints[timePoints.length-1] as + * element 0 + */ + public BoundaryPolyLine[] futurePoints; + + public Map futurePointsMap = new HashMap(); + + /** The Points for the drag me points */ + public Point[] dragMePoint; + + public Point newLineCenter; + + /** Drag me line */ + public LineString dragMeLine; + + public LineString editedLineForMotionComputation; + + public int displayedIndexAtStartMotionCompute; + + public int frameAtCreationTime = 0; + + public int motionIndex; + + public boolean dragingLineNotAllowed = false; + + public boolean lineIsMoving = false; + + public boolean movingEdited = false; + + public boolean loopingWasOn = false; + + public boolean motionIsResetToStationary = false; + + public LineString prevBoundary; + + /** Map to store active boundaries */ + public Map boundariesMap = new HashMap(); + + // public Map boundaryIdsMap = new HashMap(); + + /** Drag me Line for the points for the drag me points */ + public Map dragMePointMap = new HashMap(); + + /** Map to store the list of forbidden ids (deleted boundaries */ + public Map forbiddenBoundaryIdsMap = new HashMap(); + + /** Drag me line creation/modification time */ + // public DataTime createTime; + public Map createTimeMap = new HashMap(); + + public Map editedTimeMap = new HashMap(); + + /** Drag me line expiration time */ + // public DataTime createTime; + public Map expirationTimeMap = new HashMap(); + + public Map logMap = new HashMap(); + + /** Geometry object when mouse is down */ + public Geometry mouseDownGeom; + + /** current geometry object */ + public Geometry dragMeGeom; + + // parameters passed to method saving the data + public int timeIndex = 0; + + public DataTime[] currentDataTimes = null; + + public BoundaryEditorDialog dialogObject = null; + + /** Number of drag points for line to start with. when line is created */ + public int numDragMePoints; + + /** index into timePoints where pivot point should be */ + public int pivotIndex; + + /** The pivot index to use when current frame index is on pivotIndex */ + public int otherPivotIndex; + + /** The next pivot index to use */ + public int nextPivotIndex = -1; + + /** The currently displayed pivot index (pivotIndex or otherPivotIndex) */ + public int displayedPivotIndex; + + /** The angle of the line */ + public double angle = Double.NaN; + + public float[] vertexAngle = null; + + public Map vertexAngleMap = new HashMap(); + + /** The speed of the line */ + public double speed = Double.NaN; + + public float[] vertexSpeed = null; + + public Map vertexSpeedMap = new HashMap(); + + /** "Storm" or "feature" or whatever you want people to drag the point to */ + public String thingToDragTo; + + public int editedBoundaryId; + + public String boundaryType; + + public Map boundaryTypeMap = new HashMap(); + + public int boundaryId; + + public String fileName; + + /** + * size of line of storms, not sure about units. Used when poly line is + * first constructed + */ + public double lineOfStormsLength = 30000; + + /** + * Some value calculated in BoundaryProperties based on some things, used + * with lineOfStormsLength + */ + public double distanceThreshold; + + /** Set true if the geometry has changed and needs to be redrawn */ + public boolean geomChanged = true; + + /** set true if the number of vertex in the line increases/decreases */ + + public boolean numberPointChanged = false; + + // Resource capabilities + /** The width of the line to draw, resource should set before passed on */ + public float lineWidth; + + /** The style of the line to draw */ + public IGraphicsTarget.LineStyle lineStyle; + + /** The color of the lines to draw, resource should set */ + public RGB color = new RGB(255, 255, 255); + + /** Duration of the future time in minutes */ + public int duration = -1; + + /** Set if you want to change the duration */ + public int newDuration = -1; + + public boolean trackVisible = true; + + public boolean lineMoved = false; + + /** set magnification to default value */ + public float magnification = 1.0f; + + public Map existingBoundaryNotEmptyMap = new HashMap(); + + public DataTime creationFileTime = null; + + public Map lineMovedMap = new HashMap(); + + public int boundaryDuration = 8; + + public Map boundaryDurationMap = new HashMap(); + + /** Set if you the duration needs to be calculated from the end time */ + public Calendar endTime = null; + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUIManager.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUIManager.java new file mode 100644 index 0000000000..7e14febc28 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUIManager.java @@ -0,0 +1,682 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.Mode; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.UserAction; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPart; + +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.IDisplayPaneContainer; +import com.raytheon.uf.viz.core.VizApp; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; +import com.raytheon.viz.ui.VizWorkbenchManager; +import com.raytheon.viz.ui.cmenu.AbstractRightClickAction; +import com.raytheon.viz.ui.input.InputAdapter; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineSegment; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Point; + +/** + * + * @author Mamoudou ba + * @version 1.0 + * + * Substantially modified of A2 "StormTrackUIManager" class + */ + +public class BoundaryUIManager extends InputAdapter { + + private enum MoveType { + SINGLE_POINT, ALL_POINTS; + } + + private AbstractBoundaryResource controller; + + private Cursor movePolygon; + + private Cursor movePoint; + + private MoveType moveType = null; + + private int movePointIndex = -1; + + private int lastX, lastY; + + private boolean pointCreated = false; + + private boolean handle = true; + + private BoundaryUtil trackUtil; + + public static final double point_coord = 3.0; + + public BoundaryUIManager(AbstractBoundaryResource controller) { + this.controller = controller; + + IDisplayPaneContainer container = controller.getResourceContainer(); + if (container != null) { + container.registerMouseHandler(this); + } + + VizApp.runAsync(new Runnable() { + + @Override + public void run() { + Display display = getShell().getDisplay(); + movePolygon = display.getSystemCursor(SWT.CURSOR_SIZEALL); + movePoint = display.getSystemCursor(SWT.CURSOR_HAND); + display.getSystemCursor(SWT.CURSOR_ARROW); + } + }); + } + + public void dispose() { + IDisplayPaneContainer container = controller.getResourceContainer(); + if (container != null) { + container.unregisterMouseHandler(this); + } + } + + /** + * @param draw + */ + public void setHandleInput(boolean handle) { + this.handle = handle; + if (!handle) { + getShell().setCursor(null); + } + } + + public boolean isHandleInput() { + if (handle) { + if (controller.displayState.mode != Mode.NONE) { + return true; + } + } + return false; + } + + @Override + public boolean handleMouseMove(int x, int y) { + + IDisplayPaneContainer container = controller.getResourceContainer(); + lastX = x; + lastY = y; + if (!isHandleInput()) { + return super.handleMouseMove(x, y); + } + moveType = null; + movePointIndex = -1; + pointCreated = false; + Coordinate mouse = new Coordinate(x, y); + BoundaryState state = controller.getBoundaryState(); + if (state.isEditable() == false) { + return super.handleMouseMove(x, y); + } + Geometry dragme = state.dragMeGeom; + Cursor toUse = null; + if (dragme != null) { + Coordinate[] coords = dragme.getCoordinates(); + int idx = getCoordinateIndex(controller, coords, mouse); + if (idx > -1) { + toUse = movePoint; + moveType = MoveType.SINGLE_POINT; + /* + * In AWIPS I, When Looping Is Enabled Before A Track Has Been + * Created, Looping Will Automatically Be Disabled When TheMouse + * Cursor Comes Into The Proximity Of The Tool. + */ + if (state.mode == BoundaryState.Mode.DRAG_ME) { + if (container.getLoopProperties().isLooping()) { + container.getLoopProperties().setLooping(false); + state.loopingWasOn = true; + } + } + movePointIndex = idx; + } + + if (moveType == null) { + if (state.userAction == UserAction.INSERT_BOUNDARY + || state.userAction == UserAction.EDIT_BOUNDARY) { + if (closeToLine(controller, coords, mouse)) { + toUse = movePolygon; + moveType = MoveType.ALL_POINTS; + } + } + } + } + getShell().setCursor(toUse); + return super.handleMouseMove(x, y); + } + + @Override + public boolean handleMouseDown(int x, int y, int mouseButton) { + if (controller.getBoundaryState().dragingLineNotAllowed) { + return false; + } + if (!isHandleInput()) { + return super.handleMouseDown(x, y, mouseButton); + } + lastX = x; + lastY = y; + pointCreated = false; + BoundaryState state = controller.getBoundaryState(); + if (state.isEditable() == false) { + return super.handleMouseDown(x, y, mouseButton); + } + if (mouseButton == 1 && moveType != null) { + Geometry moveGeom = (Geometry) state.dragMeGeom.clone(); + state.mouseDownGeom = moveGeom; + return true; + } else if (mouseButton == 2 && moveType != null) { + return false; + } + + moveType = null; + movePointIndex = -1; + return false; + } + + @Override + public boolean handleMouseDownMove(int x, int y, int mouseButton) { + if (controller.getBoundaryState().dragingLineNotAllowed) { + return false; + } + if (controller.getBoundaryState().movingEdited) { + return false; + } + if (!isHandleInput()) { + return super.handleMouseDownMove(x, y, mouseButton); + } + boolean move = false; + BoundaryState state = controller.getBoundaryState(); + if (state.isEditable() == false) { + return super.handleMouseDownMove(x, y, mouseButton); + } + if (mouseButton == 1 && moveType != null) { + move = true; + } else if (mouseButton == 2 + && moveType != null + && controller.getBoundaryState().userAction == UserAction.INSERT_BOUNDARY + && controller.getBoundaryState().lineIsMoving == false) { + if (!pointCreated) { + state = controller.getBoundaryState(); + pointCreated = true; + movePointIndex = addVertex(lastX, lastY); + state.mouseDownGeom = (Geometry) state.dragMeGeom.clone(); + moveType = MoveType.SINGLE_POINT; + } + move = true; + } + + if (move) { + move(x, y); + return true; + } + + return super.handleMouseDownMove(x, y, mouseButton); + } + + @Override + public boolean handleMouseUp(int x, int y, int mouseButton) { + if (controller.getBoundaryState().dragingLineNotAllowed) { + controller.getBoundaryState().dragingLineNotAllowed = false; + return false; + } + if (!isHandleInput()) { + super.handleMouseUp(x, y, mouseButton); + } + BoundaryState state = controller.getBoundaryState(); + boolean rval = false; + if (((mouseButton == 1) || (mouseButton == 2 && pointCreated && controller + .getBoundaryState().lineIsMoving == false)) && moveType != null) { + state.dragMeGeom = state.mouseDownGeom; + state.mouseDownGeom = null; + if (state.mode == Mode.DRAG_ME) { + state.mode = Mode.TRACK; + } + state.lineMovedMap.put(state.boundaryId, true); + FramesInfo info = controller.getDescriptor().getFramesInfo(); + trackUtil.setPivotIndexes(info, state); + + // This code is duplicated from StormTrackDisplay.paint(). + if (state.displayedPivotIndex == trackUtil.getCurrentFrame(info)) { + if (state.displayedPivotIndex == state.pivotIndex + && state.otherPivotIndex >= 0) { + state.displayedPivotIndex = state.otherPivotIndex; + } else if (state.pivotIndex >= 0) { + state.displayedPivotIndex = state.pivotIndex; + } + } + rval = true; + } else if (mouseButton == 2 && !pointCreated) { + rval = true; + Coordinate[] coords = state.dragMeGeom.getCoordinates(); + Coordinate mouse = new Coordinate(x, y); + int idxToDelete = getCoordinateIndex(controller, coords, mouse); + if (idxToDelete >= 0) { + if (!controller.getBoundaryState().lineIsMoving) + deleteVertex(idxToDelete); + } else if (closeToLine(controller, coords, mouse)) { + if (!controller.getBoundaryState().lineIsMoving) { + addVertex(lastX, lastY); + } + } else { + rval = false; + } + } + + if (rval) { + state.geomChanged = true; + + state.dragMeLine = (LineString) state.dragMeGeom; + state.boundariesMap.put(state.boundaryId, state.dragMeLine); + + updateNumberOfPointsForLine(); + controller.issueRefresh(); + } + pointCreated = false; + return rval; + } + + public static int getCoordinateIndex(AbstractBoundaryResource resource, + Coordinate[] coords, Coordinate mouse) { + return getCoordinateIndex(resource.getResourceContainer(), coords, + mouse, 15.0); + } + + public static int getCoordinateIndex(IDisplayPaneContainer container, + Coordinate[] coords, Coordinate mouse, double threshold) { + int rval = -1; + int i = 0; + for (Coordinate c : coords) { + double[] screen = container.translateInverseClick(c); + if (screen != null) { + c = new Coordinate(screen[0], screen[1]); + if (c.distance(mouse) <= threshold) { + rval = i; + break; + } + } + ++i; + } + return rval; + } + + public static boolean closeToLine(AbstractBoundaryResource controller, + Coordinate[] coords, Coordinate mouse) { + IDisplayPaneContainer container = controller.getResourceContainer(); + if (coords.length < 2) { + return false; + } + + GeometryFactory gf = new GeometryFactory(); + List inverted = new ArrayList(coords.length); + + for (int i = 0; i < coords.length; ++i) { + double[] vals = container.translateInverseClick(coords[i]); + + // handle offscreen coords + // TODO: use nearest point on line that is on screen? + if (vals != null) { + inverted.add(new Coordinate(vals[0], vals[1])); + } + } + + if (inverted.size() > 1) { + return (gf.createLineString( + inverted.toArray(new Coordinate[inverted.size()])) + .distance(gf.createPoint(mouse)) <= point_coord); + } + + return false; + } + + private void move(int x, int y) { + BoundaryState state = controller.getBoundaryState(); + IDisplayPaneContainer container = controller.getResourceContainer(); + + int changeX = x - lastX; + int changeY = y - lastY; + switch (moveType) { + case ALL_POINTS: { + Coordinate[] coords = state.mouseDownGeom.getCoordinates(); + for (Coordinate c : coords) { + double[] vals = container.translateInverseClick(c); + vals[0] += changeX; + vals[1] += changeY; + + Coordinate tmp = container.translateClick(vals[0], vals[1]); + if (tmp != null) { + c.x = tmp.x; + c.y = tmp.y; + } + } + break; + } + case SINGLE_POINT: { + if (state.mouseDownGeom != null) { + Coordinate[] coords = state.mouseDownGeom.getCoordinates(); + Coordinate c = coords[movePointIndex]; + double[] vals = container.translateInverseClick(c); + vals[0] += changeX; + vals[1] += changeY; + + Coordinate tmp = container.translateClick(vals[0], vals[1]); + if (tmp != null) { + c.x = tmp.x; + c.y = tmp.y; + } + } + break; + } + } + lastX = x; + lastY = y; + controller.issueRefresh(); + } + + public int addVertex(int x, int y) { + BoundaryState state = controller.getBoundaryState(); + IDisplayPaneContainer container = controller.getResourceContainer(); + double bestDistance = Double.MAX_VALUE; + int insertionPoint = 0; + Coordinate[] coords = state.dragMeGeom.getCoordinates(); + Coordinate mouse = container.translateClick(x, y); + for (int i = 1; i < coords.length; i++) { + LineSegment segment = new LineSegment(coords[i - 1], coords[i]); + double distance = segment.distance(mouse); + if (distance < bestDistance) { + insertionPoint = i; + bestDistance = distance; + } + } + + Coordinate[] newLine = new Coordinate[coords.length + 1]; + for (int i = 0; i < newLine.length; i++) { + if (i < insertionPoint) { + newLine[i] = coords[i]; + } else if (i > insertionPoint) { + newLine[i] = coords[i - 1]; + } else { + newLine[i] = mouse; + } + } + + state.dragMeGeom = new GeometryFactory().createLineString(newLine); + state.geomChanged = true; + state.numberPointChanged = true; + return insertionPoint; + } + + public void deleteVertex(int index) { + BoundaryState state = controller.getBoundaryState(); + Coordinate[] coords = state.dragMeGeom.getCoordinates(); + if (coords.length > 2) { + Coordinate[] newCoords = new Coordinate[coords.length - 1]; + int j = 0; + for (int i = 0; i < coords.length; ++i) { + if (i != index) { + newCoords[j++] = coords[i]; + } + } + + state.dragMeGeom = new GeometryFactory() + .createLineString(newCoords); + state.geomChanged = true; + state.numberPointChanged = true; + } + + } + + public void updateNumberOfPointsForLine() { + BoundaryState state = controller.getBoundaryState(); + if (state.timePointsMap.get(state.boundaryId) != null) + state.dragMePointMap.remove(state.boundaryId); + state.dragMePointMap.put(state.boundaryId, + state.boundariesMap.get(state.boundaryId)); + Coordinate[] coords = state.dragMePointMap.get(state.boundaryId) + .getCoordinates(); + state.dragMePoint = new Point[coords.length]; + GeometryFactory gf = new GeometryFactory(); + for (int k = 0; k < coords.length; k++) { + state.dragMePoint[k] = gf.createPoint(coords[k]); + } + + // Check if a vertex is added or deleted in the boundary; + // if so, update the polyline accordingly along the track + state.timePoints = state.timePointsMap.get(state.boundaryId); + if (state.timePoints != null) { + + for (int i = 0; i < state.timePoints.length; i++) { + Point point = getPointFromLine(state.timePoints[i].polyline); + state.timePoints[i].polyline = figureLineFromPoint( + state.dragMePointMap.get(state.boundaryId), point); + state.numberPointChanged = false; + } + state.timePointsMap.put(state.boundaryId, state.timePoints); + } + + } + + public static Point getPointFromLine(LineString line) { + Coordinate[] coords = line.getCoordinates(); + if (coords.length % 2 == 1) { + return new GeometryFactory() + .createPoint(coords[(coords.length - 1) / 2]); + } else { + Coordinate middleLeft = coords[coords.length / 2]; + Coordinate middleRight = coords[(coords.length - 2) / 2]; + return new GeometryFactory().createPoint(new Coordinate( + middleLeft.x + ((middleRight.x - middleLeft.x) / 2), + middleLeft.y + ((middleRight.y - middleLeft.y) / 2))); + } + } + + public static Point getPointFromLine(LineString line, int indexVertex) { + Coordinate[] coords = line.getCoordinates(); + return new GeometryFactory().createPoint(coords[indexVertex]); + + } + + public LineString figureLineFromPoint(LineString line, Point pointGeom) { + IDisplayPaneContainer container = controller.getResourceContainer(); + Coordinate point = pointGeom.getCoordinate(); + Coordinate linePoint = getPointFromLine(line).getCoordinate(); + + double[] dest = container.translateInverseClick(point); + double[] start = container.translateInverseClick(linePoint); + + double changeX = dest[0] - start[0]; + double changeY = dest[1] - start[1]; + + Coordinate[] coords = line.getCoordinates(); + Coordinate[] newLineCoords = new Coordinate[coords.length]; + + for (int i = 0; i < coords.length; ++i) { + double[] vals = container.translateInverseClick(coords[i]); + newLineCoords[i] = container.translateClick(vals[0] + changeX, + vals[1] + changeY); + } + return new GeometryFactory().createLineString(newLineCoords); + } + + /** + * Will return null if the line or point are offscreen. + * + * @param line + * @param pointGeom + * @return + */ + public LineString figureLineFromPoint(LineString line, Point[] pointGeom) + throws ImpossibleTrackException { + IDisplayPaneContainer container = controller.getResourceContainer(); + + IDisplayPane pane = container.getActiveDisplayPane(); + + Coordinate[] coords = line.getCoordinates(); + Coordinate[] newLineCoords = new Coordinate[coords.length]; + + for (int i = 0; i < coords.length; ++i) { + Coordinate point = pointGeom[i].getCoordinate(); + Coordinate linePoint = getPointFromLine(line, i).getCoordinate(); + + double[] dest = container.translateInverseClick(point); + double[] start = container.translateInverseClick(linePoint); + if (dest != null && start != null) { + double changeX = dest[0] - start[0]; + double changeY = dest[1] - start[1]; + double[] vals = container.translateInverseClick(coords[i]); + double[] translated = pane.getDescriptor().pixelToWorld( + pane.screenToGrid(vals[0] + changeX, vals[1] + changeY, + + 0)); + newLineCoords[i] = new Coordinate(translated[0], translated[1]); + } else { + return null; + } + } + return new GeometryFactory().createLineString(newLineCoords); + } + + /** + * @return + */ + public boolean closeToPoint() { + LineString line = null; + for (Integer boundaryId : controller.getBoundaryState().boundariesMap + .keySet()) { + if (boundaryId == controller.getBoundaryState().boundaryId) { + line = controller.getBoundaryState().boundariesMap + .get(boundaryId); + break; + } + + } + return getCoordinateIndex(controller, line.getCoordinates(), + new Coordinate(lastX, lastY)) > -1; + } + + /** + * @return + */ + public boolean closeToLine() { + LineString line = null; + for (Integer boundaryId : controller.getBoundaryState().boundariesMap + .keySet()) { + if (boundaryId == controller.getBoundaryState().boundaryId) { + line = controller.getBoundaryState().boundariesMap + .get(boundaryId); + break; + } + } + return closeToLine(controller, line.getCoordinates(), new Coordinate( + lastX, lastY)); + } + + /** + * @return + */ + public IAction getDeleteAction() { + return new DeleteVertexAction(); + } + + /** + * @return + */ + public IAction getAddAction() { + return new AddVertexAction(); + } + + private class DeleteVertexAction extends AbstractRightClickAction { + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + BoundaryState state = controller.getBoundaryState(); + if (!controller.getBoundaryState().lineIsMoving) + deleteVertex(getCoordinateIndex(controller, state.boundariesMap + .get(state.boundaryId).getCoordinates(), + new Coordinate(lastX, lastY))); + state.dragMeLine = (LineString) state.dragMeGeom; + state.geomChanged = true; + updateNumberOfPointsForLine(); + controller.issueRefresh(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#getText() + */ + @Override + public String getText() { + return controller.getDeleteVertexText(); + } + + } + + private class AddVertexAction extends AbstractRightClickAction { + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + BoundaryState state = controller.getBoundaryState(); + if (!controller.getBoundaryState().lineIsMoving) + addVertex(lastX, lastY); + state.dragMeLine = (LineString) state.dragMeGeom; + state.geomChanged = true; + updateNumberOfPointsForLine(); + controller.issueRefresh(); + } + + /* + * (non-Javadoc)B + * + * @see org.eclipse.jface.action.Action#getText() + */ + @Override + public String getText() { + return controller.getAddVertexText(); + } + } + + /** + * @param trackUtil + */ + public void setTrackUtil(BoundaryUtil trackUtil) { + this.trackUtil = trackUtil; + } + + public BoundaryUtil getTrackUtil() { + return trackUtil; + } + + private Shell getShell() { + IDisplayPaneContainer container = controller.getResourceContainer(); + if (container instanceof IWorkbenchPart) { + return ((IWorkbenchPart) container).getSite().getShell(); + } else { + return VizWorkbenchManager.getInstance().getCurrentWindow() + .getShell(); + } + } +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUtil.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUtil.java new file mode 100644 index 0000000000..003dcfd1de --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/BoundaryUtil.java @@ -0,0 +1,122 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import java.util.ArrayList; +import java.util.List; + +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; + +/** + * + * @author bkowal + * @version 1.0 + * + * Slightly modified of "StormTrackUti" class + */ + +public class BoundaryUtil { + + public BoundaryUtil() { + } + + public int getFrameCount(FramesInfo info) { + int len = makeUniqueTimes(info.getFrameTimes()).length; + return len; + } + + public int getCurrentFrame(FramesInfo info) { + int returnIndex = 0; + if (info.getFrameTimes() == null || info.getFrameCount() < 1) { + return -1; + } + DataTime[] uniqueTimes = makeUniqueTimes(info.getFrameTimes()); + DataTime currTime = info.getFrameTimes()[info.getFrameIndex()]; + + if (uniqueTimes == null) { + return -1; + } + for (int i = 0; i < uniqueTimes.length; i++) { + if (currTime.equals(uniqueTimes[i], true)) { + returnIndex = i; + break; + } + } + return returnIndex; + } + + public DataTime[] getDataTimes(FramesInfo info) { + return makeUniqueTimes(info.getFrameTimes()); + } + + public void setPivotIndexes(FramesInfo info, BoundaryState boundaryState) { + int lastFrame = getFrameCount(info) - 1; + if (getCurrentFrame(info) == lastFrame) { + // We Are Presently On The Last Frame. + boundaryState.otherPivotIndex = 0; + boundaryState.nextPivotIndex = lastFrame; + boundaryState.pivotIndex = lastFrame; + } else { + boundaryState.otherPivotIndex = 0; + boundaryState.nextPivotIndex = -1; + boundaryState.pivotIndex = lastFrame; + } + } + + private DataTime[] makeUniqueTimes(DataTime[] times) { + List uniqueTimes = new ArrayList(); + if (times != null && times.length > 0) { + DataTime lastTime = times[0]; + uniqueTimes.add(times[0]); + for (int i = 1; i < times.length; ++i) { + if (!lastTime.equals(times[i], true)) { + uniqueTimes.add(times[i]); + lastTime = times[i]; + } + } + } + return uniqueTimes.toArray(new DataTime[uniqueTimes.size()]); + } + + /** + * Returns the time between times in seconds using valid time + * + * @param a + * @param b + * @return + */ + public int timeBetweenDataTimes(DataTime a, DataTime b) { + return (int) (Math.abs(a.getValidTime().getTimeInMillis() + - b.getValidTime().getTimeInMillis()) / 1000); + } + + /** + * Adjusts the angle from -360/360 to be between -180/180 + * + * @param angle + * @return + */ + protected double adjustAngle(double angle) { + double newVal = angle % 360; + if (newVal > 180) { + newVal -= 360; + } else if (newVal < -180) { + newVal += 360; + } + return newVal; + } + + /** + * Adjusts the angle from -180/180 to be between 0/360 + * + * @param angle + * @return + */ + protected double unadjustAngle(double angle) { + double newVal = angle; + if (newVal < 0) { + newVal = 360 - newVal; + } + return newVal; + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/ImpossibleTrackException.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/ImpossibleTrackException.java new file mode 100644 index 0000000000..b567e6a257 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/common/boundary/ImpossibleTrackException.java @@ -0,0 +1,45 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.common.boundary; + +import com.raytheon.uf.viz.core.exception.VizException; + +/** + * + * @author Mamoudou Ba + * @version 1.0 + * + * Entirely reused of A2 "ImpossibleTrackException" class + */ + +public class ImpossibleTrackException extends VizException { + + private static final long serialVersionUID = -7171916545937661879L; + + /** + * + */ + public ImpossibleTrackException() { + super(); + } + + /** + * @param message + * @param cause + */ + public ImpossibleTrackException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public ImpossibleTrackException(String message) { + super(message); + } + + /** + * @param cause + */ + public ImpossibleTrackException(Throwable cause) { + super(cause); + } +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/action/BoundaryEditorAction.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/action/BoundaryEditorAction.java new file mode 100644 index 0000000000..8f38f43b99 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/action/BoundaryEditorAction.java @@ -0,0 +1,73 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.ui.action; + +import gov.noaa.nws.mdl.viz.boundaryTool.ui.layer.BoundaryEditorLayer; + +import java.util.List; + +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.VizApp; +import com.raytheon.uf.viz.core.drawables.IDescriptor; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.rsc.LoadProperties; +import com.raytheon.uf.viz.core.rsc.tools.GenericToolsResourceData; +import com.raytheon.uf.viz.core.rsc.tools.action.AbstractGenericToolAction; + +/** + * @author Mamoudou Ba + * @version 1.0 + * + * April 2011: Substantially modified from A2 "TimeOfArrivalAction" + * class + */ + +public class BoundaryEditorAction extends + AbstractGenericToolAction { + + /* + * (non-Javadoc) + * + * @seecom.raytheon.viz.awipstools.ui.action.MapToolAction#getResourceData() + */ + @Override + protected GenericToolsResourceData getResourceData() { + return new GenericToolsResourceData( + BoundaryEditorLayer.NAME, BoundaryEditorLayer.class); + + } + + // November 25, 2013 + + @Override + protected BoundaryEditorLayer getResource(LoadProperties loadProperties, + IDescriptor descriptor) throws VizException { + BoundaryEditorLayer layer = getExistingResource(); + if (layer == null) + return super.getResource(loadProperties, descriptor); + + VizApp.runAsync(new Runnable() { + @Override + public void run() { + BoundaryEditorLayer layer = getExistingResource(); + if (layer != null) { + layer.makeEditableAndReopenDialog(); + } + } + }); + return layer; + + } + + private BoundaryEditorLayer getExistingResource() { + IDisplayPane[] panes = getSelectedPanes(); + if (panes != null && panes.length > 0) { + List layers = null; + layers = panes[0].getDescriptor().getResourceList() + .getResourcesByTypeAsType(BoundaryEditorLayer.class); + if (!layers.isEmpty()) { + return layers.get(0); + } + } + return null; + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/BoundaryEditorDialog.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/BoundaryEditorDialog.java new file mode 100644 index 0000000000..342dc0689c --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/BoundaryEditorDialog.java @@ -0,0 +1,1178 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.ui.dialog; + +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.ReadBoundariesXmlFile; +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.WriteBoundariesXmlFile; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.Mode; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.UserAction; +import gov.noaa.nws.mdl.viz.boundaryTool.ui.layer.BoundaryEditorLayer; + +import java.io.FileNotFoundException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.xml.datatype.DatatypeConfigurationException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.viz.ui.dialogs.CaveJFACEDialog; + +/** + * + * @author Mamoudou Ba + * @version 1.0 + * + * April 28, 2011 + * + * Based on A2 "TimeOfArrivalDialog" class + */ + +public class BoundaryEditorDialog extends CaveJFACEDialog { + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(BoundaryEditorDialog.class); + + protected int boundaryIdLabel; + + protected int durationLabel; + + private Composite top = null; + + private Composite boundaryFieldComposite; + + private Combo editCbo; + + // private Combo deleteCombo; + + private Combo regimeCbo; + + private Combo motionCbo; + + private Combo boundaryLifeSpanCbo; + + private LinkedHashMap boundaryIdsMap; + + private LinkedHashMap durationMap; + + private LinkedHashMap regimeMap; + + private LinkedHashMap boundaryModeMap; + + private final BoundaryEditorLayer boundarylayer; + + private Button insertBoundaryBtn, adjustMotionBtn, deleteBtn, saveDataBtn, + cancelBtn; + + private String[] idStrings = null; + + private String[] durationStrings = null; + + private String duration; + + private String[] regimeStrings = null; + + private String[] modeStrings = null; + + private final String Moving = "Moving"; + + private final String Stationary = "Stationary"; + + // Boundary Mode (Stationary or Moving + private final String boundaryMode[] = { "Stationary", "Moving" }; + + // Atmospheric regimes + private final String regime[] = { "COLD FRONT", "STATIONARY/WARM FRONT", + "SEA/LAKE BREEZE", "DRY LINE", "GUST FRONT", + "SELECT TO DEFINE TYPE" }; + + private final int userRegimeIndex = 5; + + private void setupEditMenu(UserAction type) { + + String displayName = null; + + boundaryIdsMap = new LinkedHashMap(); + + // Populate edit and delete boundary menu + + // 0 is reserved id for ANC software + // valid Id start with 1 + + for (int i : boundarylayer.getBoundaryState().boundariesMap.keySet()) { + + displayName = "" + i; + + boundaryIdsMap.put(displayName, displayName); + } + // displayName = "---"; + // populating edit and delete drop menu + + idStrings = new String[boundaryIdsMap.size()]; + Iterator bndIterator = null; + + bndIterator = boundaryIdsMap.keySet().iterator(); + + for (int i = 0; i < idStrings.length; i++) { + idStrings[i] = bndIterator.next(); + + } + } + + private void setupDurationMenu() { + + String displayName = null; + + durationMap = new LinkedHashMap(); + + // Populate duration menu + + for (int i = 1; i < 9; i++) { + + displayName = "" + i; + + durationMap.put(displayName, displayName); + } + // displayName = "---"; + // populating boundary duration drop menu + + duration = "" + durationMap.size(); + + durationStrings = new String[durationMap.size()]; + Iterator durationIterator = null; + + durationIterator = durationMap.keySet().iterator(); + + for (int i = 0; i < durationStrings.length; i++) { + durationStrings[i] = durationIterator.next(); + + } + } + + private void setupDataMenu() { + String displayName = null; + + regimeMap = new LinkedHashMap(); + boundaryModeMap = new LinkedHashMap(); + + // Populate regime menu; Populate boundary mode menu + + for (int i = 0; i < regime.length; i++) { + + displayName = regime[i]; + regimeMap.put(displayName, displayName); + + } + + for (int i = 0; i < boundaryMode.length; i++) { + + displayName = boundaryMode[i]; + boundaryModeMap.put(displayName, displayName); + + } + + regimeStrings = new String[regimeMap.size()]; + Iterator regimeIterator = null; + + regimeIterator = regimeMap.keySet().iterator(); + + for (int i = 0; i < regimeStrings.length; i++) { + regimeStrings[i] = regimeIterator.next(); + + } + + // The motion mode is proprely handled in the BoundaryDisplay class + // + modeStrings = new String[boundaryModeMap.size()]; + Iterator modeIterator = null; + + modeIterator = boundaryModeMap.keySet().iterator(); + + for (int i = 0; i < modeStrings.length; i++) { + modeStrings[i] = modeIterator.next(); + + } + + } + + public BoundaryEditorDialog(Shell parShell, + BoundaryEditorLayer boundarylayer) { + super(parShell); + this.setShellStyle(SWT.TITLE | SWT.MODELESS | SWT.CLOSE); + this.boundarylayer = boundarylayer; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets + * .Composite) + */ + @Override + public Control createDialogArea(Composite parent) { + top = (Composite) super.createDialogArea(parent); + GridLayout gridLayout = new GridLayout(1, false); + top.setLayout(gridLayout); + setupDataMenu(); + setupEditMenu(UserAction.EDIT_BOUNDARY); + setupDurationMenu(); + initializeComponents(); + return top; + + } + + private void initializeComponents() { + + boundaryFieldComposite = new Composite(top, SWT.NONE); + boundaryFieldComposite.setLayout(new GridLayout(2, false)); + GridData data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + insertBoundaryBtn = new Button(boundaryFieldComposite, SWT.PUSH); + insertBoundaryBtn.setText("Insert Boundary"); + insertBoundaryBtn.setLayoutData(data); + + insertBoundaryBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + // Check if regime is set for each inserted boundary + if (boundarylayer.getBoundaryState().boundariesMap.size() != 0) { + Iterator iterator = boundarylayer + .getBoundaryState().boundariesMap.keySet() + .iterator(); + int boundaryId; + String s = ""; + while (iterator.hasNext()) { + boundaryId = iterator.next(); + if (boundarylayer.getBoundaryState().boundaryTypeMap + .get(boundaryId) == null) { + s = s + boundaryId; + } + + } + if (!s.isEmpty()) { + MessageDialog.openWarning(Display.getCurrent() + .getActiveShell(), + "Previous Boundary Type Not Set", + "Please set the boundary type for ids: " + s + + " before inserting another boundary"); + return; + } + } + updateDisplayType(UserAction.INSERT_BOUNDARY); + Display display = Display.getCurrent(); + /* + * Highlight "Save Boundary Data" button is red: data not yet + * save after a new boundary is inserted or an existing boundary + * is modified. + */ + saveDataBtn.setBackground(display.getSystemColor(SWT.COLOR_RED)); + } + + }); + deleteBtn = new Button(boundaryFieldComposite, SWT.PUSH); + deleteBtn.setText("Delete Boundary..."); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + deleteBtn.setLayoutData(data); + deleteBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + + deleteAction(); + } + }); + + Label boundaryIdLabel = new Label(boundaryFieldComposite, SWT.NONE); + boundaryIdLabel.setText("Edit Boundary:"); + // boundaryIdLabel.setLayoutData(createFormLayoutLoc(true, 0)); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + boundaryIdLabel.setLayoutData(data); + editCbo = new Combo(boundaryFieldComposite, SWT.DROP_DOWN); + editCbo.setItems(idStrings); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + editCbo.setLayoutData(data); + + editCbo.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + editAction(); + } + }); + + Label durationLabel = new Label(boundaryFieldComposite, SWT.NONE); + durationLabel.setText("Boundary Duration (hrs):"); + // durationLabel.setLayoutData(createFormLayoutLoc(true, 0)); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + durationLabel.setLayoutData(data); + boundaryLifeSpanCbo = new Combo(boundaryFieldComposite, SWT.DROP_DOWN); + boundaryLifeSpanCbo.setItems(durationStrings); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + boundaryLifeSpanCbo.setLayoutData(data); + + boundaryLifeSpanCbo.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + lifeSpanAction(); + } + }); + + Label regimeLabel = new Label(boundaryFieldComposite, SWT.NONE); + regimeLabel.setText("Boundary Type:"); + // regimeLabel.setLayoutData(createFormLayoutLoc(true, 0)); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + regimeLabel.setLayoutData(data); + regimeCbo = new Combo(boundaryFieldComposite, SWT.DROP_DOWN); + regimeCbo.setItems(regimeStrings); + regimeCbo.setLayoutData(data); + + regimeCbo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + regimeAction(); + } + + }); + + // Boundary motion mode drop down menu + + Label modeLabel = new Label(boundaryFieldComposite, SWT.NONE); + modeLabel.setText("Boundary Mode:"); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + modeLabel.setLayoutData(data); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + motionCbo = new Combo(boundaryFieldComposite, SWT.DROP_DOWN); + motionCbo.setItems(modeStrings); + motionCbo.setLayoutData(data); + + motionCbo.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + modeAction(); + } + }); + + /* + * Boundary Motion Modification: This will allow the user to adjust the + * boundary position + */ + adjustMotionBtn = new Button(boundaryFieldComposite, SWT.PUSH); + adjustMotionBtn.setText("Modify the Motion"); + adjustMotionBtn + .setToolTipText("Clicking this button will allow you to adjust the boundary position to " + + " its current location and recompute its motion; the boundary will be reset to stationary" + + " so that you can readjust its position and compute its current motion accordingly"); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + adjustMotionBtn.setLayoutData(data); + adjustMotionBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + adjustMotionAction(); + } + }); + + cancelBtn = new Button(boundaryFieldComposite, SWT.PUSH); + cancelBtn.setText("Cancel Modification"); + cancelBtn + .setToolTipText("Clicking this button will cancel the modification you just made"); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + cancelBtn.setLayoutData(data); + cancelBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + cancelAction(); + } + + }); + + saveDataBtn = new Button(boundaryFieldComposite, SWT.PUSH); + saveDataBtn.setText("Save Boundary Data"); + data = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + saveDataBtn.setLayoutData(data); + saveDataBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + saveDataAction(); + } + }); + + // Boundary Id = 0 is always forbidden + + boundarylayer.getBoundaryState().forbiddenBoundaryIdsMap.put(0, 0); + + /* Set Display Text To First Element In Combo Box */ + + fillBoundaryMenus(); + + } + + /** + * + */ + @Override + protected void createButtonsForButtonBar(Composite parents) { + // Don't do anything since we don't want the OK and cancel buttons + } + + @Override + protected boolean canHandleShellCloseEvent() { + Composite closeDialogOption = new Composite(top, SWT.NONE); + closeDialogOption.setLayout(new FormLayout()); + boolean optionSelected = false; + + MessageBox messageBox = new MessageBox(getShell(), SWT.ICON_QUESTION + | SWT.YES | SWT.NO); + messageBox.setText("Closing?"); + messageBox.setMessage("Are you sure you want to close the dialog?"); + int buttonID = messageBox.open(); + switch (buttonID) { + case SWT.YES: + optionSelected = true; + boundaryFieldComposite.getShell().dispose(); + boundarylayer.getBoundaryState().dialogObject = null; + break; + } + return optionSelected; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.window.Window#configureShell( + * editCbo.setItems(idStrings);org.eclipse.swt.widgets .Shell) + */ + @Override + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText("Boundary Editor"); + } + + private void updateDisplayType(UserAction type) { + boundarylayer.getBoundaryState().userAction = type; + boundarylayer.getBoundaryState().geomChanged = true; + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + deleteBtn.setEnabled(true); + // KS - corrected coding error + int idMax = 0; + + for (int id : boundarylayer.getBoundaryState().boundariesMap.keySet()) { + + if (id > idMax) { + idMax = id; + } + } + ++idMax; + while (boundarylayer.getBoundaryState().forbiddenBoundaryIdsMap + .get(idMax) != null) { + idMax = idMax + 1; + } + + // 99 is the highest boundary Id allowed; If this number is reached, the + // second number from forbidden list is used + // zero is a reserved id number for ANC is the first element in + // forbiddenBoundaruIdsMap + + if (idMax > 99) { + Iterator iterator = boundarylayer.getBoundaryState().forbiddenBoundaryIdsMap + .keySet().iterator(); + int boundaryId = 0; + while (iterator.hasNext()) { + boundaryId = iterator.next(); + if (boundaryId > 0) { + boundarylayer.getBoundaryState().forbiddenBoundaryIdsMap + .remove(boundaryId); + break; + } + } + idMax = boundaryId; + } + boundarylayer.getBoundaryState().boundaryId = idMax; + String s = null; + s = "new" + " boundary(" + idMax + ")"; + boundarylayer.getBoundaryState().logMap.put(idMax, s); + + boundarylayer.getBoundaryState().dragMeLine = null; + boundarylayer.getBoundaryState().boundariesMap.put( + boundarylayer.getBoundaryState().boundaryId, + boundarylayer.getBoundaryState().dragMeLine); + setupEditMenu(UserAction.EDIT_BOUNDARY); + editCbo.setItems(idStrings); + + String boundaryId = "" + boundarylayer.getBoundaryState().boundaryId; + editCbo.setText(boundaryIdsMap.get(boundaryId)); + + motionCbo.setText(modeStrings[0]); + + boundarylayer.getBoundaryState().isMovingMap.put( + boundarylayer.getBoundaryState().boundaryId, false); + boundarylayer.getBoundaryState().mode = Mode.DRAG_ME; + regimeCbo.setText("Select Boundary Type"); + boundarylayer.issueRefresh(); + } + + private void saveBoundaryData(UserAction type) { + + boundarylayer.getBoundaryState().userAction = type; + boundarylayer.issueRefresh(); + saveData(boundarylayer.getBoundaryState(), + boundarylayer.getBoundaryState().currentDataTimes, + boundarylayer.getBoundaryState().timeIndex); + boundarylayer.getBoundaryState().userAction = UserAction.NONE; + } + + /** + * Save data to localization file (run new thread to save data). + */ + public void saveData(final BoundaryState currentState, + final DataTime[] dataTimes, final int timeIndex) { + Job job = new Job("Writing data to localization file") { + @Override + protected IStatus run(IProgressMonitor monitor) { + WriteBoundariesXmlFile writeXMLFile = new WriteBoundariesXmlFile(); + try { + writeXMLFile.writeBoundariesXmlFile(currentState, + dataTimes, timeIndex); + } catch (VizException | DatatypeConfigurationException e) { + statusHandler.handle(Priority.PROBLEM, + "Writing boundary data fails", e); + } + writeXMLFile = null; + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + + // + private void getEditedBoundaryId(UserAction type, String s) { + boundarylayer.getBoundaryState().userAction = type; + try { + // convert boundaryId string into integer + + int i = Integer.parseInt(s.trim()); + + boundarylayer.getBoundaryState().boundaryId = i; + } catch (NumberFormatException nfe) { + // ignore values that are not numbers + } + boundarylayer.issueRefresh(); + } + + private void getDuration(String s) { + // boundarylayer.getBoundaryState().userAction = type; + try { + // convert boundaryId string into integer + + int i = Integer.parseInt(s.trim()); + + boundarylayer.getBoundaryState().boundaryDuration = i; + } catch (NumberFormatException nfe) { + statusHandler.handle(Priority.PROBLEM, nfe.getMessage(), nfe); + } + boundarylayer.issueRefresh(); + } + + // user action methods + + public void saveDataAction() { + + if (boundarylayer.getBoundaryState().boundariesMap.get(boundarylayer + .getBoundaryState().boundaryId) != null) { + + if (boundarylayer.getBoundaryState().boundariesMap.size() != 0) { + Iterator iterator = boundarylayer.getBoundaryState().boundariesMap + .keySet().iterator(); + int boundaryId; + String s = ""; + while (iterator.hasNext()) { + boundaryId = iterator.next(); + if (boundarylayer.getBoundaryState().boundaryTypeMap + .get(boundaryId) == null) { + s = s + boundaryId; + } + + } + if (!s.isEmpty()) { + // Need to define the boundary type before saving + // the data + MessageBox messageBox = new MessageBox(getShell(), + SWT.ICON_WARNING | SWT.OK); + messageBox.setText("Warning !!!"); + messageBox.setMessage("Boundary type is not defined yet" + + " for ids: " + s + + " set boundary type before saving the data"); + int buttonID = messageBox.open(); + switch (buttonID) { + case SWT.OK: + break; + } + return; + } else { + saveBoundaryData(UserAction.SAVE); + } + } + setupEditMenu(UserAction.EDIT_BOUNDARY); + int id = boundarylayer.getBoundaryState().boundaryId; + String s = "" + id; + if (id == 0) { + s = ""; + } + editCbo.setItems(idStrings); + editCbo.setText(s); + s = boundarylayer.getBoundaryState().boundaryTypeMap.get(id); + regimeCbo.setItems(regimeStrings); + regimeCbo.setText(s); + if (boundarylayer.getBoundaryState().isMovingMap.get(id) == true) { + s = Moving; + } else { + s = Stationary; + } + motionCbo.setItems(modeStrings); + motionCbo.setText(s); + } + saveDataBtn.setEnabled(false); + cancelBtn.setEnabled(false); + deleteBtn.setEnabled(false); + adjustMotionBtn.setEnabled(false); + /* + * Set "Save Boundary Data" button gray: when data are saved + */ + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_GRAY)); + boundarylayer.issueRefresh(); + } + + public void cancelAction() { + MessageBox messageBox = new MessageBox(getShell(), SWT.ICON_QUESTION + | SWT.YES); + messageBox.setText("Canceling?"); + messageBox + .setMessage("Are you sure you want cancel your modification?"); + int buttonID = messageBox.open(); + switch (buttonID) { + case SWT.YES: + + boundarylayer.getBoundaryState().userAction = UserAction.CANCEL_MODIFICATION; + + setupEditMenu(UserAction.EDIT_BOUNDARY); + Map activeBoundariesMap = new HashMap(); + + for (int i : boundarylayer.getBoundaryState().boundariesMap + .keySet()) { + // active boundaries saved on memory + activeBoundariesMap.put(i, i); + } + + // remove all boundaries from memories; + for (int id : activeBoundariesMap.keySet()) { + boundarylayer.getBoundaryState().boundariesMap.remove(id); + boundarylayer.getBoundaryState().boundaryTypeMap.remove(id); + boundarylayer.getBoundaryState().boundariesMap.remove(id); + boundarylayer.getBoundaryState().timePointsMap.remove(id); + boundarylayer.getBoundaryState().dragMePointMap.remove(id); + boundarylayer.getBoundaryState().lineMovedMap.remove(id); + boundarylayer.getBoundaryState().isMovingMap.remove(id); + boundarylayer.getBoundaryState().boundaryDurationMap.remove(id); + boundarylayer.getBoundaryState().createTimeMap.remove(id); + boundarylayer.getBoundaryState().editedTimeMap.remove(id); + boundarylayer.getBoundaryState().expirationTimeMap.remove(id); + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap + .remove(id); + boundarylayer.getBoundaryState().vertexAngleMap.remove(id); + boundarylayer.getBoundaryState().vertexSpeedMap.remove(id); + } + + // Now Read boundary data from disc + ReadBoundariesXmlFile readXMLFile = new ReadBoundariesXmlFile(); + try { + readXMLFile.readBoundariesXmlFile(boundarylayer + .getBoundaryState()); + } catch (FileNotFoundException e) { + statusHandler.handle(Priority.PROBLEM, e.getMessage(), e); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, e.getMessage(), e); + } catch (DatatypeConfigurationException e) { + statusHandler.handle(Priority.PROBLEM, e.getMessage(), e); + } + + break; + default: + saveBoundaryData(UserAction.SAVE); + boundarylayer.getBoundaryState().userAction = UserAction.NONE; + break; + } + fillBoundaryMenus(); + cancelBtn.setEnabled(false); + // If "Save Boundary Data" button is gray: + // data are saved + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_GRAY)); + boundarylayer.issueRefresh(); + } + + public void modeAction() { + if (motionCbo.getSelectionIndex() != -1 + && boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + + if (boundaryModeMap.get(motionCbo.getText()) == Stationary) { + boundarylayer.getBoundaryState().isMovingMap.put( + boundarylayer.getBoundaryState().boundaryId, false); + + boundarylayer.getBoundaryState().vertexAngleMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().vertexSpeedMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().timePointsMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().dragingLineNotAllowed = false; + boundarylayer.getBoundaryState().lineIsMoving = false; + + } else { + if (boundarylayer.getBoundaryState().isMovingMap + .get(boundarylayer.getBoundaryState().boundaryId) == false) { + + if (boundarylayer.getBoundaryState().editedLineForMotionComputation == null) { + boundarylayer.getBoundaryState().editedLineForMotionComputation = boundarylayer + .getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId); + + } + + boundarylayer.getBoundaryState().dragMePointMap + .put(boundarylayer.getBoundaryState().boundaryId, + boundarylayer.getBoundaryState().boundariesMap.get(boundarylayer + .getBoundaryState().boundaryId)); + boundarylayer.getBoundaryState().isMovingMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().isMovingMap.put( + boundarylayer.getBoundaryState().boundaryId, true); + // Setting speed for newly created moving boundary + // Need to move to another frame + boundarylayer.getBoundaryState().dragingLineNotAllowed = true; + boundarylayer.getBoundaryState().lineIsMoving = true; + } + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap + .put(boundarylayer.getBoundaryState().boundaryId, false); + } + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + // Highlight "Save Boundary Data" button is red: data not + // yet saved after a new boundary + // is inserted or an existing boundary is modified. + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_RED)); + boundarylayer.issueRefresh(); + } + } + + public void adjustMotionAction() { + + MessageBox messageBox = new MessageBox(getShell(), SWT.ICON_QUESTION + | SWT.YES); + messageBox.setText("Modifying the motion?"); + messageBox + .setMessage("Are you sure you want to modify the motion of this boundary?"); + int buttonID = messageBox.open(); + switch (buttonID) { + case SWT.YES: + + resetToStationary(); + break; + default: + boundarylayer.getBoundaryState().userAction = UserAction.NONE; + break; + } + adjustMotionBtn.setEnabled(false); + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + /* + * Highlight "Save Boundary Data" button is red: data not yet saved + * after a new boundary is inserted or an existing boundary is modified. + */ + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_RED)); + boundarylayer.issueRefresh(); + } + + public void outOfrangeError() { + resetToStationary(); + adjustMotionBtn.setEnabled(false); + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + /* + * Highlight "Save Boundary Data" button is red: data not yet saved + * after a new boundary is inserted or an existing boundary is modified. + */ + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_RED)); + boundarylayer.issueRefresh(); + } + + public void resetToStationary() { + + if (boundaryModeMap.get(motionCbo.getText()) == Moving) { + boundarylayer.getBoundaryState().isMovingMap.remove(boundarylayer + .getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().isMovingMap.put( + boundarylayer.getBoundaryState().boundaryId, false); + + boundarylayer.getBoundaryState().vertexAngleMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().vertexSpeedMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().timePointsMap.remove(boundarylayer + .getBoundaryState().boundaryId); + motionCbo.setItems(modeStrings); + motionCbo.setText(Stationary); + boundarylayer.getBoundaryState().lineIsMoving = false; + boundarylayer.getBoundaryState().dragingLineNotAllowed = false; + boundarylayer.getBoundaryState().movingEdited = false; + boundarylayer.getBoundaryState().editedLineForMotionComputation = boundarylayer + .getBoundaryState().boundariesMap.get(boundarylayer + .getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().motionIsResetToStationary = true; + + } + + } + + public void regimeAction() { + if (regimeCbo.getSelectionIndex() != -1 + && boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + // User define boundary Type + if (regimeCbo.getText().equals(regime[userRegimeIndex])) { + UserInputBndType dlg = new UserInputBndType(Display + .getCurrent().getActiveShell()); + dlg.open(); + String input = dlg.userInput; + + if (UserInputBndType.isOK) { + if (!input.isEmpty()) { + for (String i : regimeMap.keySet()) { + if (regimeMap.get(i) + .equals(regime[userRegimeIndex])) { + regimeMap.remove(i); + regimeMap.put(input, input); + } + } + regimeCbo.setText(input); + if (regimeMap.get(regimeCbo.getText()) == null) { + regimeMap.put(input, input); + } + + } else { + MessageDialog.openWarning(Display.getCurrent() + .getActiveShell(), "Input is empty", + "Please define a boundary type \n" + + " 'SELECT TO DEFINE TYPE' again " + + "from Boundary Type dropmenu"); + regimeCbo.setText("Select Boundary Type"); + return; + } + } else { + return; + } + + } + boundarylayer.getBoundaryState().boundaryTypeMap.put( + boundarylayer.getBoundaryState().boundaryId, + regimeMap.get(regimeCbo.getText())); + + setupEditMenu(UserAction.EDIT_BOUNDARY); + editCbo.setItems(idStrings); + String s = "" + boundarylayer.getBoundaryState().boundaryId; + editCbo.setText(s); + s = "" + 8; + boundarylayer.getBoundaryState().boundaryDurationMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().boundaryDurationMap.put( + boundarylayer.getBoundaryState().boundaryId, 8); + boundaryLifeSpanCbo.setText(s); + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + boundarylayer.issueRefresh(); + } + } + + public void lifeSpanAction() { + int id = 0; + + if (boundaryLifeSpanCbo.getSelectionIndex() != -1 + && boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + String s = durationMap.get(boundaryLifeSpanCbo.getText()); + getDuration(s); + try { + id = Integer.parseInt(s); + } catch (NumberFormatException nfe) { + // ignore values that are not numbers + } + boundarylayer.getBoundaryState().boundaryDurationMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().boundaryDurationMap.put( + boundarylayer.getBoundaryState().boundaryId, id); + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + boundarylayer.issueRefresh(); + } + } + + public void editAction() { + deleteBtn.setEnabled(true); + int id = 0; + if (editCbo.getSelectionIndex() != -1 + && boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + String s = boundaryIdsMap.get(editCbo.getText()); + getEditedBoundaryId(UserAction.EDIT_BOUNDARY, s); + try { + id = Integer.parseInt(s); + + } catch (NumberFormatException nfe) { + // ignore values that are not numbers + } + + s = "boundary(" + id + ") is edited"; + boundarylayer.getBoundaryState().logMap.put(id, s); + + if (boundarylayer.getBoundaryState().boundaryTypeMap.get(id) != null) { + regimeCbo + .setText(boundarylayer.getBoundaryState().boundaryTypeMap + .get(id)); + } else { + // this will prevent a null exception + regimeCbo.setText("Boundary type not yet defined"); + } + if (boundarylayer.getBoundaryState().isMovingMap.get(id) == true) { + s = Moving; + boundarylayer.getBoundaryState().lineIsMoving = true; + boundarylayer.getBoundaryState().dragingLineNotAllowed = true; + boundarylayer.getBoundaryState().movingEdited = true; + + adjustMotionBtn.setEnabled(true); + } else { + s = Stationary; + boundarylayer.getBoundaryState().lineIsMoving = false; + boundarylayer.getBoundaryState().dragingLineNotAllowed = false; + boundarylayer.getBoundaryState().movingEdited = false; + adjustMotionBtn.setEnabled(false); + } + motionCbo.setText(s); + s = "" + + boundarylayer.getBoundaryState().boundaryDurationMap + .get(boundarylayer.getBoundaryState().boundaryId); + boundaryLifeSpanCbo.setText(s); + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap + .remove(boundarylayer.getBoundaryState().boundaryId); + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap.put( + boundarylayer.getBoundaryState().boundaryId, false); + + if (!boundarylayer.getBoundaryState().isMovingMap.get(boundarylayer + .getBoundaryState().boundaryId)) { + boundarylayer.getBoundaryState().prevBoundary = boundarylayer + .getBoundaryState().boundariesMap.get(boundarylayer + .getBoundaryState().boundaryId); + } + + boundarylayer.issueRefresh(); + + } + } + + public void deleteAction() { + MessageBox messageBox = new MessageBox(getShell(), SWT.ICON_QUESTION + | SWT.YES); + messageBox.setText("Deleting?"); + messageBox.setMessage("Are you sure you want to delete this boundary?"); + int buttonID = messageBox.open(); + switch (buttonID) { + case SWT.YES: + + if (boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + String s = "" + boundarylayer.getBoundaryState().boundaryId; + boundaryIdsMap.remove(s); + int id = boundarylayer.getBoundaryState().boundaryId; + boundarylayer.getBoundaryState().boundaryTypeMap.remove(id); + boundarylayer.getBoundaryState().boundariesMap.remove(id); + boundarylayer.getBoundaryState().timePointsMap.remove(id); + boundarylayer.getBoundaryState().dragMePointMap.remove(id); + boundarylayer.getBoundaryState().lineMovedMap.remove(id); + boundarylayer.getBoundaryState().isMovingMap.remove(id); + boundarylayer.getBoundaryState().boundaryDurationMap.remove(id); + boundarylayer.getBoundaryState().createTimeMap.remove(id); + boundarylayer.getBoundaryState().editedTimeMap.remove(id); + boundarylayer.getBoundaryState().expirationTimeMap.remove(id); + boundarylayer.getBoundaryState().existingBoundaryNotEmptyMap + .remove(id); + ; + boundarylayer.getBoundaryState().vertexAngleMap.remove(id); + boundarylayer.getBoundaryState().vertexSpeedMap.remove(id); + s = "" + "boundary(" + id + ") is deleted"; + boundarylayer.getBoundaryState().logMap.put(id, s); + // Map the delete boundaries Ids list + boundarylayer.getBoundaryState().forbiddenBoundaryIdsMap.put( + boundarylayer.getBoundaryState().boundaryId, + boundarylayer.getBoundaryState().boundaryId); + + // + setupEditMenu(UserAction.EDIT_BOUNDARY); + editCbo.setItems(idStrings); + + int idMax = 0; + + for (int id1 : boundarylayer.getBoundaryState().boundariesMap + .keySet()) { + + if (id1 > idMax) { + idMax = id1; + } + } + s = "" + idMax; + if (idMax == 0) { + s = " "; + } + + getEditedBoundaryId(UserAction.DELETE_BOUNDARY, s); + editCbo.setText(s); + if (boundarylayer.getBoundaryState().boundaryTypeMap.get(idMax) != null) { + regimeCbo + .setText(boundarylayer.getBoundaryState().boundaryTypeMap + .get(idMax)); + } else { + regimeCbo.setText(" "); + } + + if (boundarylayer.getBoundaryState().boundaryTypeMap.get(idMax) == null) { + + s = Stationary; + + } else { + if (boundarylayer.getBoundaryState().isMovingMap.get(idMax) == true) { + s = Moving; + } else { + s = Stationary; + } + + } + motionCbo.setText(s); + if (boundarylayer.getBoundaryState().boundariesMap + .get(boundarylayer.getBoundaryState().boundaryId) != null) { + s = "" + + boundarylayer.getBoundaryState().boundaryDurationMap + .get(idMax); + } else { + s = "8"; + regimeCbo.setText("Select boundary type"); + } + boundaryLifeSpanCbo.setText(s); + saveBoundaryData(UserAction.SAVE); + deleteBtn.setEnabled(false); + boundarylayer.issueRefresh(); + } + + break; + default: + boundarylayer.getBoundaryState().userAction = UserAction.NONE; + break; + } + } + + public void setBtnFalseAfterCancelAction() { + cancelBtn.setEnabled(false); + saveDataBtn.setEnabled(false); + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_GRAY)); + } + + public void enableMotionSelection(boolean enabled) { + motionCbo.setEnabled(enabled); + } + + public void setBtnTrueAfterCancelAction() { + cancelBtn.setEnabled(true); + saveDataBtn.setEnabled(true); + saveDataBtn.setBackground(Display.getCurrent().getSystemColor( + SWT.COLOR_RED)); + } + + private void fillBoundaryMenus() { + cancelBtn.setEnabled(false); + saveDataBtn.setEnabled(false); + deleteBtn.setEnabled(false); + adjustMotionBtn.setEnabled(false); + if (boundarylayer.getBoundaryState().boundariesMap.size() != 0) { + Iterator iterator = boundarylayer.getBoundaryState().boundariesMap + .keySet().iterator(); + int id = 0; + int boundaryId = 0; + String s = null; + setupEditMenu(UserAction.EDIT_BOUNDARY); + while (iterator.hasNext()) { + boundaryId = iterator.next(); + idStrings[id] = "" + boundaryId; + id++; + } + + setupEditMenu(UserAction.EDIT_BOUNDARY); + editCbo.setItems(idStrings); + s = "" + boundarylayer.getBoundaryState().boundaryId; + editCbo.setText(s); + s = "" + + boundarylayer.getBoundaryState().boundaryTypeMap + .get(boundaryId); + regimeCbo.setItems(regimeStrings); + regimeCbo.setText(s); + if (boundarylayer.getBoundaryState().isMovingMap.get(boundaryId) == true) { + s = Moving; + } else { + s = Stationary; + } + motionCbo.setItems(modeStrings); + motionCbo.setText(s); + s = "" + + boundarylayer.getBoundaryState().boundaryDurationMap + .get(boundaryId); + boundaryLifeSpanCbo.setItems(durationStrings); + boundaryLifeSpanCbo.setText(s); + } else { + regimeCbo.setText("Select boundary type"); + motionCbo.setText(modeStrings[0]); + boundaryLifeSpanCbo.setText(duration); + boundarylayer.getBoundaryState().isMovingMap.put( + boundarylayer.getBoundaryState().boundaryId, false); + } + } + +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/UserInputBndType.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/UserInputBndType.java new file mode 100644 index 0000000000..8534dd9b48 --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/dialog/UserInputBndType.java @@ -0,0 +1,87 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.ui.dialog; + +import org.eclipse.swt.SWT; +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.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.raytheon.viz.ui.dialogs.CaveSWTDialog; + +/** + * + * @author Mamoudou Ba + * @version 1.0 + * + * Dialog class which allows users to input a string defining a + * boundary type + * + * December 2015: Initial creation + * + * January 2016: extends to use CaveSWTDialog dialog, and remove + * unnecessary getters and setters + */ + +class UserInputBndType extends CaveSWTDialog { + protected static Boolean isOK = false; + protected String userInput; + + public UserInputBndType(Shell parent) { + this(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); + } + + public UserInputBndType(Shell parent, int style) { + super(parent, style); + setText("Input Dialog"); + } + + @Override + protected void initializeComponents(final Shell shell) { + + shell.setLayout(new GridLayout(2, true)); + + Label label = new Label(shell, SWT.NONE); + label.setText("Please enter a boundary type:"); + GridData data = new GridData(); + data.horizontalSpan = 2; + label.setLayoutData(data); + + final Text text = new Text(shell, SWT.BORDER); + data = new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan = 2; + text.setLayoutData(data); + + Button okButton = new Button(shell, SWT.PUSH); + okButton.setText("OK"); + data = new GridData(GridData.FILL_HORIZONTAL); + okButton.setLayoutData(data); + + okButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent arg0) { + userInput = text.getText(); + isOK = true; + close(); + } + }); + + Button cancelButton = new Button(shell, SWT.PUSH); + cancelButton.setText("Cancel"); + data = new GridData(GridData.FILL_HORIZONTAL); + cancelButton.setLayoutData(data); + cancelButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + isOK = false; + close(); + } + }); + + shell.setDefaultButton(okButton); + } +} diff --git a/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/layer/BoundaryEditorLayer.java b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/layer/BoundaryEditorLayer.java new file mode 100644 index 0000000000..1dadf4b2ea --- /dev/null +++ b/cave/gov.noaa.nws.mdl.viz.boundaryTool/src/gov/noaa/nws/mdl/viz/boundaryTool/ui/layer/BoundaryEditorLayer.java @@ -0,0 +1,319 @@ +package gov.noaa.nws.mdl.viz.boundaryTool.ui.layer; + +import gov.noaa.nws.mdl.viz.boundaryTool.boundaries.state.xml.ReadBoundariesXmlFile; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.AbstractBoundaryResource; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState.LabelMode; +import gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryUIManager; +import gov.noaa.nws.mdl.viz.boundaryTool.ui.dialog.BoundaryEditorDialog; + +import java.io.FileNotFoundException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +import javax.xml.datatype.DatatypeConfigurationException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.opengis.coverage.grid.GridEnvelope; + +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.IDisplayPaneContainer; +import com.raytheon.uf.viz.core.IExtent; +import com.raytheon.uf.viz.core.IGraphicsTarget; +import com.raytheon.uf.viz.core.PixelExtent; +import com.raytheon.uf.viz.core.VizApp; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; +import com.raytheon.uf.viz.core.drawables.IWireframeShape; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.map.MapDescriptor; +import com.raytheon.uf.viz.core.rsc.LoadProperties; +import com.raytheon.uf.viz.core.rsc.ProgressiveDisclosureProperties; +import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability; +import com.raytheon.uf.viz.core.rsc.tools.GenericToolsResourceData; +import com.raytheon.viz.ui.VizWorkbenchManager; +import com.raytheon.viz.ui.input.EditableManager; +import com.raytheon.viz.ui.input.InputAdapter; +import com.vividsolutions.jts.geom.Coordinate; + +/** + * + * @author Mamoudou ba + * @version 1.0 + * + * April 2011: Based on A2 "TimeOfArrivalLayer" class + */ + +public class BoundaryEditorLayer extends AbstractBoundaryResource { + + public static class BoundaryEditorState { + public Coordinate loc; + + public Coordinate mouseLoc; + + // public String text = "Drag me to Point of Arrival"; + + public double distance; + + public boolean changed; + } + + private final DateFormat timeFormat = new SimpleDateFormat("HH:mm"); + + public static final String NAME = "Boundary Editor"; + + private static final int PD_MAX_WIDTH = 1999000; + + private IWireframeShape jazzyExtras; + + private BoundaryEditorDialog dialog; + + private BoundaryEditorState boundaryEditState; + + private ProgressiveDisclosureProperties pdProps; + + private Shell shell; + + private Cursor movePoint; + + private boolean hovering = false; + + private InputAdapter adapter = new InputAdapter() { + @Override + public boolean handleMouseMove(int x, int y) { + Coordinate mouse = new Coordinate(x, y); + hovering = false; + Coordinate loc = boundaryEditState.loc; + + if (loc != null) { + if (BoundaryUIManager.getCoordinateIndex( + BoundaryEditorLayer.this, new Coordinate[] { loc }, + mouse) > -1) { + shell.setCursor(movePoint); + hovering = true; + } + } + + return super.handleMouseMove(x, y); + } + + @Override + public boolean handleMouseDown(int x, int y, int mouseButton) { + + if (mouseButton == 1 && hovering) { + boundaryEditState.mouseLoc = new Coordinate( + boundaryEditState.loc); + issueRefresh(); + return true; + } + + return false; + } + + // November 25 2013 - updated from TimeOfArrivalLayer + @Override + public boolean handleMouseDownMove(int arg_x, int arg_y, int mouseButton) { + double x = arg_x; + double y = arg_y; + if (mouseButton == 1 && hovering) { + + // check if point of arrival is off the drawn map, draw at + // closest border if it is + IDisplayPane pane = getResourceContainer() + .getActiveDisplayPane(); + double[] world = pane.screenToGrid(x, y, 0); + GridEnvelope ge = pane.getDescriptor().getGridGeometry() + .getGridRange(); + IExtent extent = new PixelExtent(ge); + if (world == null) { + return true; + } else if (extent.contains(world) == false) { + // snap x coord to closest edge if out of bounds + if (world[0] > extent.getMaxX()) { + world[0] = extent.getMaxX(); + } else if (world[0] < extent.getMinX()) { + world[0] = extent.getMinX(); + } + + // snap y coord to closest edge if out of bounds + if (world[1] > extent.getMaxY()) { + world[1] = extent.getMaxY(); + } else if (world[1] < extent.getMinY()) { + world[1] = extent.getMinY(); + } + + // translate back to screen coords + double[] screen = pane.gridToScreen(world); + x = screen[0]; + y = screen[1]; + } + + // translate from screen to lat/lon + Coordinate c = getResourceContainer().translateClick(x, y); + if (c != null) { + boundaryEditState.mouseLoc = c; + issueRefresh(); + } + return true; + } + + return false; + } + + @Override + public boolean handleMouseUp(int x, int y, int mouseButton) { + if (mouseButton == 1 && hovering) { + boundaryEditState.loc = boundaryEditState.mouseLoc; + boundaryEditState.mouseLoc = null; + boundaryEditState.changed = true; + + displayState.geomChanged = true; + + issueRefresh(); + return true; + } + + return false; + } + }; + + public BoundaryEditorLayer( + GenericToolsResourceData resourceData, + LoadProperties loadProperties, MapDescriptor descriptor) { + super(resourceData, loadProperties, descriptor); + // add magnification capability + getCapabilities().addCapability(new MagnificationCapability()); + this.pdProps = new ProgressiveDisclosureProperties(); + this.pdProps.setMaxDisplayWidth(BoundaryEditorLayer.PD_MAX_WIDTH); + + timeFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + // reopenDialog(); + boundaryEditState = new BoundaryEditorState(); + + shell = VizWorkbenchManager.getInstance().getCurrentWindow().getShell(); + + Display display = Display.getCurrent(); + + movePoint = display.getSystemCursor(SWT.CURSOR_HAND); + } + + @Override + protected void initInternal(IGraphicsTarget target) throws VizException { + super.initInternal(target); + IDisplayPaneContainer container = getResourceContainer(); + if (container != null) { + container.registerMouseHandler(adapter); + } + reopenDialog(); + } + + @Override + protected void disposeInternal() { + super.disposeInternal(); + dialog.close(); + displayState.dialogObject = null; + if (jazzyExtras != null) { + jazzyExtras.dispose(); + } + + IDisplayPaneContainer container = getResourceContainer(); + if (container != null) { + container.unregisterMouseHandler(adapter); + } + } + + /* + * (non-Javadoc) + * + * @see + * gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.AbstractBoundaryResource + * #getResourceName() + */ + @Override + protected String getResourceName() { + return NAME; + } + + /* + * (non-Javadoc) + * + * @see + * gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.AbstractBoundaryResource + * #initializeState + * (gov.noaa.nws.mdl.viz.boundaryTool.common.boundary.BoundaryState) + */ + @Override + protected void initializeState(BoundaryState state) { + IDisplayPaneContainer container = getResourceContainer(); + if (container.getLoopProperties().isLooping()) { + container.getLoopProperties().setLooping(false); + state.loopingWasOn = true; + } + FramesInfo info = descriptor.getFramesInfo(); + // Setup the initial state for the storm track + // Default angle for POINT + displayState.userAction = BoundaryState.UserAction.READ_ACTIVE_BOUNDARIES; + + displayState.labelMode = LabelMode.TIME; + state.angle = 90; + state.boundaryId = 0; + state.dragMePoint = null; + state.dragMeLine = null; + // default for POLY, calculated usually + state.lineOfStormsLength = 1000; + state.mode = BoundaryState.Mode.DRAG_ME; + state.numDragMePoints = 1; + state.pivotIndex = trackUtil.getCurrentFrame(info); + state.otherPivotIndex = displayState.pivotIndex > 0 ? 0 : trackUtil + .getFrameCount(info) - 1; + state.thingToDragTo = "boundary location"; + + ReadBoundariesXmlFile readXMLFile = new ReadBoundariesXmlFile(); + try { + readXMLFile.readBoundariesXmlFile(state); + readXMLFile = null; + } catch (FileNotFoundException e) { + statusHandler.handle(Priority.PROBLEM, "No such file exists", e); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, "VisException", e); + } catch (DatatypeConfigurationException e) { + statusHandler.handle(Priority.PROBLEM, + "Data type configuration problem", e); + } + + } + + /** + * Re-opens the dialog if closed + */ + public void reopenDialog() { + // Open the dialog + VizApp.runAsync(new Runnable() { + + @Override + public void run() { + if (dialog == null || dialog.getShell() == null + || dialog.getShell().isDisposed()) { + dialog = new BoundaryEditorDialog(VizWorkbenchManager + .getInstance().getCurrentWindow().getShell(), + BoundaryEditorLayer.this); + dialog.setBlockOnOpen(false); + dialog.open(); + displayState.dialogObject = dialog; + } + } + }); + } + + // November 25, 2013 + + public void makeEditableAndReopenDialog() { + EditableManager.makeEditable(this, true); + reopenDialog(); + } + +} \ No newline at end of file