From 02511db2b9245c6b560b7123cb9fc3bd8a26b5ea Mon Sep 17 00:00:00 2001 From: Connor Taylor-Brown Date: Fri, 28 Apr 2017 01:58:55 +1200 Subject: [PATCH 1/2] Implemented marker visualisation from XML in ResizableRaceCanvas - Replaced and deprecated Constants - Added getMarkers to RaceDataSource interface - Added boundary testing for source data #story[782] --- .../src/main/java/seng302/Constants.java | 1 + .../seng302/Controllers/RaceController.java | 1 - .../java/seng302/Mock/StreamedCourse.java | 3 ++ .../seng302/Mock/StreamedCourseXMLReader.java | 23 ++++++---- .../src/main/java/seng302/Model/Marker.java | 8 ++++ .../seng302/Model/ResizableRaceCanvas.java | 42 ++++++++++--------- .../src/main/java/seng302/RaceDataSource.java | 2 + .../src/main/java/seng302/RaceXMLReader.java | 6 +++ .../java/seng302/Mock/StreamedRaceTest.java | 20 +++++++++ 9 files changed, 78 insertions(+), 28 deletions(-) diff --git a/visualiser/src/main/java/seng302/Constants.java b/visualiser/src/main/java/seng302/Constants.java index b2d96fcb..096e5a2b 100644 --- a/visualiser/src/main/java/seng302/Constants.java +++ b/visualiser/src/main/java/seng302/Constants.java @@ -6,6 +6,7 @@ import seng302.Model.BoatInRace; /** * Constants that are used throughout the program * Created by Erika on 19-Mar-17. + * @deprecated please use XML for constant data */ public class Constants { diff --git a/visualiser/src/main/java/seng302/Controllers/RaceController.java b/visualiser/src/main/java/seng302/Controllers/RaceController.java index 9c64bbfa..69bbf74b 100644 --- a/visualiser/src/main/java/seng302/Controllers/RaceController.java +++ b/visualiser/src/main/java/seng302/Controllers/RaceController.java @@ -125,7 +125,6 @@ public class RaceController extends Controller { raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty()); //raceMap.setBoats(newRace.getStartingBoats()); - raceMap.setRaceBoundaries(raceData.getBoundary()); raceMap.drawRaceMap(); raceMap.setVisible(true); diff --git a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java index ebde5a4c..d379566e 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java @@ -3,6 +3,7 @@ package seng302.Mock; import seng302.GPSCoordinate; import seng302.Model.BoatInRace; import seng302.Model.Leg; +import seng302.Model.Marker; import seng302.Model.RaceClock; import seng302.RaceDataSource; @@ -58,6 +59,8 @@ public class StreamedCourse implements RaceDataSource { return streamedCourseXMLReader.getLegs(); } + public List getMarkers() { return streamedCourseXMLReader.getMarkers(); } + public List getBoundary() { return streamedCourseXMLReader.getBoundary(); } diff --git a/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java b/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java index 8fe86835..70651437 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java @@ -21,12 +21,13 @@ import java.util.*; * Created by jjg64 on 21/04/17. */ public class StreamedCourseXMLReader extends XMLReader { - private static double COORDINATEPADDING = 0.0005; + private static double COORDINATEPADDING = 0.000; private GPSCoordinate mapTopLeft, mapBottomRight; private List boundary = new ArrayList<>(); - private Map marks = new HashMap<>(); + private Map compoundMarks = new HashMap<>(); private Map participants = new HashMap<>(); private List legs = new ArrayList<>(); + private List markers = new ArrayList<>(); Date creationTimeDate; Date raceStartTime; int raceID; @@ -98,14 +99,17 @@ public class StreamedCourseXMLReader extends XMLReader { } /** - * Indexes CompoundMark elements by their ID for use in generating the course. + * Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers. + * @see seng302.Model.Marker */ - private void readCompoundMarks() { + private void readCompoundMarks() throws StreamedCourseXMLException { Element nCourse = (Element) doc.getElementsByTagName("Course").item(0); for(int i = 0; i < nCourse.getChildNodes().getLength(); i++) { Node compoundMark = nCourse.getChildNodes().item(i); if(compoundMark.getNodeName().equals("CompoundMark")) { - marks.put(getCompoundMarkID((Element)compoundMark),(Element)compoundMark); + int compoundMarkID = getCompoundMarkID((Element) compoundMark); + compoundMarks.put(compoundMarkID, (Element)compoundMark); + markers.add(getMarker(compoundMarkID)); } } } @@ -114,11 +118,11 @@ public class StreamedCourseXMLReader extends XMLReader { * Generates a Marker from the CompoundMark element with given ID. * @param compoundMarkID index of required CompoundMark element * @return generated Marker - * @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of marks + * @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of compoundMarks * @see seng302.Model.Marker */ private Marker getMarker(int compoundMarkID) throws StreamedCourseXMLException { - Element compoundMark = marks.get(compoundMarkID); + Element compoundMark = compoundMarks.get(compoundMarkID); NodeList nMarks = compoundMark.getElementsByTagName("Mark"); Marker marker; @@ -152,7 +156,7 @@ public class StreamedCourseXMLReader extends XMLReader { * @return value of "name" attribute */ private String getCompoundMarkName(int compoundMarkID) { - return marks.get(compoundMarkID).getAttribute("Name"); + return compoundMarks.get(compoundMarkID).getAttribute("Name"); } /** @@ -184,6 +188,7 @@ public class StreamedCourseXMLReader extends XMLReader { } } + double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING; double maxLongitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING; double minLatitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING; @@ -209,6 +214,8 @@ public class StreamedCourseXMLReader extends XMLReader { return legs; } + public List getMarkers() { return markers; } + public Double getPadding() { return COORDINATEPADDING; } diff --git a/visualiser/src/main/java/seng302/Model/Marker.java b/visualiser/src/main/java/seng302/Model/Marker.java index 118219f1..ec46edb2 100644 --- a/visualiser/src/main/java/seng302/Model/Marker.java +++ b/visualiser/src/main/java/seng302/Model/Marker.java @@ -37,6 +37,14 @@ public class Marker { return mark2; } + /** + * Returns true if mark consists of two points, e.g. it is a gate. + * @return boolean + */ + public boolean isCompoundMark() { + return mark1 != mark2; + } + public GPSCoordinate getAverageGPSCoordinate() { return averageGPSCoordinate; } diff --git a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java index dd8287dc..66ccb518 100644 --- a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java +++ b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java @@ -27,7 +27,8 @@ public class ResizableRaceCanvas extends Canvas { private boolean annoAbbrev = true; private boolean annoSpeed = true; private boolean annoPath = true; - private ArrayList raceBoundaries; + private List raceBoundaries; + private List markers; double[] xpoints = {}, ypoints = {}; public ResizableRaceCanvas(RaceDataSource raceData) { @@ -40,7 +41,11 @@ public class ResizableRaceCanvas extends Canvas { double long1 = raceData.getMapTopLeft().getLongitude(); double lat2 = raceData.getMapBottomRight().getLatitude(); double long2 = raceData.getMapBottomRight().getLongitude(); + setMap(new RaceMap(lat1, long1, lat2, long2, (int) getWidth(), (int) getHeight())); + + this.raceBoundaries = raceData.getBoundary(); + this.markers = raceData.getMarkers(); } /** @@ -206,6 +211,22 @@ public class ResizableRaceCanvas extends Canvas { gc.fillPolygon(xpoints, ypoints, xpoints.length); } + /** + * Draw race markers + */ + public void drawMarkers() { + for(Marker marker: markers) { + GraphCoordinate mark1 = this.map.convertGPS(marker.getMark1()); + if(marker.isCompoundMark()) { + GraphCoordinate mark2 = this.map.convertGPS(marker.getMark2()); + // TODO - improve colour coding of markers + displayLine(mark1, mark2, Color.GREEN); + } else { + displayPoint(mark1, Color.GREEN); + } + } + } + /** * Draws the Race Map */ @@ -222,26 +243,9 @@ public class ResizableRaceCanvas extends Canvas { this.map.setHeight((int) height); this.map.setWidth((int) width); - //finish line gc.setLineWidth(2); drawBoundaries(); - GraphCoordinate finishLineCoord1 = this.map.convertGPS(Constants.finishLineMarker1); - GraphCoordinate finishLineCoord2 = this.map.convertGPS(Constants.finishLineMarker2); - displayLine(finishLineCoord1, finishLineCoord2, Color.DARKRED); - //marks - GraphCoordinate markCoord = this.map.convertGPS(Constants.mark1); - GraphCoordinate windwardGate1 = this.map.convertGPS(Constants.windwardGate1); - GraphCoordinate windwardGate2 = this.map.convertGPS(Constants.windwardGate2); - GraphCoordinate leewardGate1 = this.map.convertGPS(Constants.leewardGate1); - GraphCoordinate leewardGate2 = this.map.convertGPS(Constants.leewardGate2); - displayMark(markCoord, Color.GOLD); - displayLine(windwardGate1, windwardGate2, Color.DARKCYAN); - displayLine(leewardGate1, leewardGate2, Color.DARKVIOLET); - //start line - GraphCoordinate startline1 = this.map.convertGPS(Constants.startLineMarker1); - GraphCoordinate startline2 = this.map.convertGPS(Constants.startLineMarker2); - - displayLine(startline1, startline2, Color.GREEN); + drawMarkers(); updateBoats(); diff --git a/visualiser/src/main/java/seng302/RaceDataSource.java b/visualiser/src/main/java/seng302/RaceDataSource.java index 82d30b73..c309661b 100644 --- a/visualiser/src/main/java/seng302/RaceDataSource.java +++ b/visualiser/src/main/java/seng302/RaceDataSource.java @@ -2,6 +2,7 @@ package seng302; import seng302.Model.BoatInRace; import seng302.Model.Leg; +import seng302.Model.Marker; import java.time.ZonedDateTime; import java.util.List; @@ -12,6 +13,7 @@ import java.util.List; public interface RaceDataSource { List getBoats(); List getLegs(); + List getMarkers(); List getBoundary(); ZonedDateTime getZonedDateTime(); diff --git a/visualiser/src/main/java/seng302/RaceXMLReader.java b/visualiser/src/main/java/seng302/RaceXMLReader.java index 14244417..a3b0dfeb 100644 --- a/visualiser/src/main/java/seng302/RaceXMLReader.java +++ b/visualiser/src/main/java/seng302/RaceXMLReader.java @@ -14,6 +14,7 @@ import java.util.List; /** * Created by fwy13 on 26/03/2017. + * @deprecated use {@link seng302.Mock.StreamedCourseXMLReader} */ public class RaceXMLReader extends XMLReader implements RaceDataSource { private List boats = new ArrayList<>(); @@ -263,6 +264,11 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { return new GPSCoordinate(startLat, startLong); } + @Override + public List getMarkers() { + return null; + } + public List getBoats() { return boats; } diff --git a/visualiser/src/test/java/seng302/Mock/StreamedRaceTest.java b/visualiser/src/test/java/seng302/Mock/StreamedRaceTest.java index c7ddb3d3..d842c9c0 100644 --- a/visualiser/src/test/java/seng302/Mock/StreamedRaceTest.java +++ b/visualiser/src/test/java/seng302/Mock/StreamedRaceTest.java @@ -1,13 +1,16 @@ package seng302.Mock; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import seng302.GPSCoordinate; import seng302.Model.Leg; +import seng302.Model.Marker; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** @@ -75,4 +78,21 @@ public class StreamedRaceTest { }; for(int i = 0; i < legs.size(); i++) assertEquals(expectedNames[i], legs.get(i).getName()); } + + /** + * raceTest.xml is not compliant with this test. Markers are positioned far out of bounds. + */ + @Test + public void markersWithinRaceBoundaries() { + GPSCoordinate topLeft = streamedCourseXMLReader.getMapTopLeft(); + GPSCoordinate bottomRight = streamedCourseXMLReader.getMapBottomRight(); + + for(Marker marker: streamedCourseXMLReader.getMarkers()) { + GPSCoordinate centre = marker.getAverageGPSCoordinate(); + assertTrue(centre.getLatitude() < bottomRight.getLatitude()); + assertTrue(centre.getLatitude() > topLeft.getLatitude()); + assertTrue(centre.getLongitude() > bottomRight.getLongitude()); + assertTrue(centre.getLongitude() < topLeft.getLongitude()); + } + } } From 7f273f8ba063f5b3240cd42c90d28f81e749223f Mon Sep 17 00:00:00 2001 From: Connor Taylor-Brown Date: Fri, 28 Apr 2017 02:37:50 +1200 Subject: [PATCH 2/2] Fixed time source for visualiser, replacing local time - StreamedCourse now provides start time for clock from XML #story[782] --- .../main/java/seng302/Mock/StreamedCourse.java | 2 +- .../seng302/Mock/StreamedCourseXMLReader.java | 17 ++++++++++------- .../src/main/java/seng302/Model/RaceClock.java | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java index d379566e..f2bcfed0 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java @@ -66,7 +66,7 @@ public class StreamedCourse implements RaceDataSource { } public ZonedDateTime getZonedDateTime() { - return RaceClock.getCurrentZonedDateTime(regattaXMLReader.getRegatta().getGPSCoordinate()); + return streamedCourseXMLReader.getRaceStartTime(); } public GPSCoordinate getMapTopLeft() { diff --git a/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java b/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java index 70651437..43cd9f44 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedCourseXMLReader.java @@ -1,5 +1,6 @@ package seng302.Mock; +import org.joda.time.DateTime; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -15,6 +16,8 @@ import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; /** @@ -28,8 +31,8 @@ public class StreamedCourseXMLReader extends XMLReader { private Map participants = new HashMap<>(); private List legs = new ArrayList<>(); private List markers = new ArrayList<>(); - Date creationTimeDate; - Date raceStartTime; + ZonedDateTime creationTimeDate; + ZonedDateTime raceStartTime; int raceID; String raceType; boolean postpone; @@ -67,14 +70,14 @@ public class StreamedCourseXMLReader extends XMLReader { } private void readRace() throws ParseException { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"); Element settings = (Element) doc.getElementsByTagName("Race").item(0); raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID")); raceType = getTextValueOfNode(settings, "RaceType"); - creationTimeDate = dateFormat.parse(getTextValueOfNode(settings, "CreationTimeDate")); + creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat); NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes(); - raceStartTime = dateFormat.parse(raceTimeTag.getNamedItem("Time").getTextContent()); + raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat); postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent()); } @@ -220,11 +223,11 @@ public class StreamedCourseXMLReader extends XMLReader { return COORDINATEPADDING; } - public Date getCreationTimeDate() { + public ZonedDateTime getCreationTimeDate() { return creationTimeDate; } - public Date getRaceStartTime() { + public ZonedDateTime getRaceStartTime() { return raceStartTime; } diff --git a/visualiser/src/main/java/seng302/Model/RaceClock.java b/visualiser/src/main/java/seng302/Model/RaceClock.java index 3dfb5af5..c4ce751d 100644 --- a/visualiser/src/main/java/seng302/Model/RaceClock.java +++ b/visualiser/src/main/java/seng302/Model/RaceClock.java @@ -43,7 +43,7 @@ public class RaceClock { */ public void setTime(ZonedDateTime time) { this.time = time; - this.timeString.set(DateTimeFormatter.ofPattern("dd-MM HH:mm:ss z").format(time)); + this.timeString.set(DateTimeFormatter.ofPattern("HH:mm:ss dd/MM/YYYY Z").format(time)); this.lastTime = System.currentTimeMillis(); }