mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Basic implementation for mapping windspeed to draw a polar on a gate complete
Created functionality to grab the closest windspeed value to map to VMG values based off the current wind speed in the Polar Table Created new RaceXML mark object which contains ALL marks for purposes of sequencing Displaying correct (?) polars for one point only on a gate Created functionality to receive leg data for each boat and then map that to the next gate. This may only work for the current race due to a slight fudge factor Created functionality to receive wind speed tags: #story[956] #pair[wmu16, mra106]
This commit is contained in:
@@ -25,12 +25,6 @@
|
|||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>1.3.2</version>
|
<version>1.3.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/com.opencsv/opencsv -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.opencsv</groupId>
|
|
||||||
<artifactId>opencsv</artifactId>
|
|
||||||
<version>3.9</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.googlecode.json-simple</groupId>
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
<artifactId>json-simple</artifactId>
|
<artifactId>json-simple</artifactId>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class App extends Application {
|
|||||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||||
break;
|
break;
|
||||||
case "staffserver":
|
case "staffserver":
|
||||||
sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
|
sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4942, "RaceStream");
|
||||||
break;
|
break;
|
||||||
case "official":
|
case "official":
|
||||||
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||||
@@ -67,7 +67,7 @@ public class App extends Application {
|
|||||||
else {
|
else {
|
||||||
// sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
// sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||||
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||||
// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
|
// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4942, "RaceStream");
|
||||||
}
|
}
|
||||||
|
|
||||||
sr.start();
|
sr.start();
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeMarks() {
|
private void initializeMarks() {
|
||||||
ArrayList<Mark> allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks();
|
List<Mark> allMarks = StreamParser.getXmlObject().getRaceXML().getNonDupCompoundMarks();
|
||||||
for (Mark mark : allMarks) {
|
for (Mark mark : allMarks) {
|
||||||
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
||||||
SingleMark sMark = (SingleMark) mark;
|
SingleMark sMark = (SingleMark) mark;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
@@ -29,7 +30,9 @@ import seng302.models.*;
|
|||||||
import seng302.models.mark.GateMark;
|
import seng302.models.mark.GateMark;
|
||||||
import seng302.models.mark.Mark;
|
import seng302.models.mark.Mark;
|
||||||
import seng302.models.mark.MarkGroup;
|
import seng302.models.mark.MarkGroup;
|
||||||
|
import seng302.models.mark.SingleMark;
|
||||||
import seng302.models.stream.StreamParser;
|
import seng302.models.stream.StreamParser;
|
||||||
|
import seng302.models.stream.XMLParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -185,37 +188,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
updateWindDirection();
|
updateWindDirection();
|
||||||
updateOrder();
|
updateOrder();
|
||||||
updateBoatSelectionComboBox();
|
updateBoatSelectionComboBox();
|
||||||
|
updateLaylines();
|
||||||
for (Yacht yacht : StreamParser.getBoatsPos().values()) {
|
|
||||||
|
|
||||||
if (yacht.getNextMark() != null){
|
|
||||||
System.out.println("next Mark: " + yacht.getNextMark().getName());
|
|
||||||
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
|
||||||
|
|
||||||
Boolean isUpwindLeg = null;
|
|
||||||
// Can only calc leg direction if there is a next mark and it is a gate mark
|
|
||||||
Mark nextMark = bg.getBoat().getNextMark();
|
|
||||||
if (!(nextMark == null || !(nextMark instanceof GateMark))) {
|
|
||||||
isUpwindLeg = bg.isUpwindLeg(includedCanvasController);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (MarkGroup mg : includedCanvasController.getMarkGroups()) {
|
|
||||||
if (mg.getMainMark().equals(nextMark)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isUpwindLeg != null) {
|
|
||||||
if (isUpwindLeg) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -224,6 +197,43 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over all corners until ones SeqID matches with the boats current leg number.
|
||||||
|
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
|
||||||
|
* Returns null if no next mark found.
|
||||||
|
* @param bg The BoatGroup to find the next mark of
|
||||||
|
* @return The next Mark or null if none found
|
||||||
|
*/
|
||||||
|
private Mark getNextMark(BoatGroup bg) {
|
||||||
|
Integer legNumber = bg.getBoat().getLegNumber();
|
||||||
|
|
||||||
|
System.out.println("Leg Number: " + legNumber);
|
||||||
|
List<XMLParser.RaceXMLObject.Corner> markSequence = StreamParser.getXmlObject().getRaceXML().getCompoundMarkSequence();
|
||||||
|
|
||||||
|
if (legNumber == 0) {
|
||||||
|
System.out.println("PreStart");
|
||||||
|
return null;
|
||||||
|
} else if (legNumber == markSequence.size() - 2) {
|
||||||
|
System.out.println("Finishing");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (XMLParser.RaceXMLObject.Corner corner : markSequence) {
|
||||||
|
if (legNumber + 2 == corner.getSeqID()) {
|
||||||
|
Integer thisCompoundMarkID = corner.getCompoundMarkID();
|
||||||
|
|
||||||
|
for (Mark mark : StreamParser.getXmlObject().getRaceXML().getAllCompoundMarks()) {
|
||||||
|
if (mark.getCompoundMarkID() == thisCompoundMarkID) {
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the wind direction arrow and text as from info from the StreamParser
|
* Updates the wind direction arrow and text as from info from the StreamParser
|
||||||
*/
|
*/
|
||||||
@@ -285,6 +295,53 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateLaylines() {
|
||||||
|
|
||||||
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
||||||
|
System.out.println("========" + bg.getBoat().getBoatName() + "=========");
|
||||||
|
Mark nextMark = getNextMark(bg);
|
||||||
|
Boolean isUpwind = null;
|
||||||
|
// Can only calc leg direction if there is a next mark and it is a gate mark
|
||||||
|
if (nextMark != null) {
|
||||||
|
System.out.println("Next Mark: " + nextMark.getName());
|
||||||
|
if (nextMark instanceof GateMark) {
|
||||||
|
if (bg.isUpwindLeg(includedCanvasController, nextMark)) {
|
||||||
|
isUpwind = true;
|
||||||
|
System.out.println(bg.getBoat().getBoatName() + " is on an upwind leg");
|
||||||
|
} else {
|
||||||
|
isUpwind = false;
|
||||||
|
System.out.println(bg.getBoat().getBoatName() + " is on a downwind leg");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(MarkGroup mg : includedCanvasController.getMarkGroups()) {
|
||||||
|
if (mg.getMainMark().getId() == nextMark.getId()) {
|
||||||
|
|
||||||
|
SingleMark singleMark1 = ((GateMark) nextMark).getSingleMark1();
|
||||||
|
SingleMark singleMark2 = ((GateMark) nextMark).getSingleMark2();
|
||||||
|
Point2D markPoint1 = includedCanvasController.findScaledXY(singleMark1.getLatitude(), singleMark1.getLongitude());
|
||||||
|
Point2D markPoint2 = includedCanvasController.findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
|
||||||
|
HashMap<Double, Double> angleAndSpeed;
|
||||||
|
if (isUpwind) {
|
||||||
|
angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
|
||||||
|
} else {
|
||||||
|
angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
Double resultingAngle = angleAndSpeed.keySet().iterator().next();
|
||||||
|
|
||||||
|
mg.addLayLine(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
||||||
|
mg.addLayLine(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialised the combo box with any boats currently in the race and adds the required listener
|
* Initialised the combo box with any boats currently in the race and adds the required listener
|
||||||
* for the combobox to take action upon selection
|
* for the combobox to take action upon selection
|
||||||
|
|||||||
@@ -375,8 +375,7 @@ public class BoatGroup extends Group {
|
|||||||
* going up wind, if they are on different sides of the gate, then the boat is going downwind
|
* going up wind, if they are on different sides of the gate, then the boat is going downwind
|
||||||
* @param canvasController
|
* @param canvasController
|
||||||
*/
|
*/
|
||||||
public Boolean isUpwindLeg(CanvasController canvasController) {
|
public Boolean isUpwindLeg(CanvasController canvasController, Mark nextMark) {
|
||||||
Mark nextMark = boat.getNextMark();
|
|
||||||
|
|
||||||
Double windAngle = StreamParser.getWindDirection();
|
Double windAngle = StreamParser.getWindDirection();
|
||||||
GateMark thisGateMark = (GateMark) nextMark;
|
GateMark thisGateMark = (GateMark) nextMark;
|
||||||
@@ -398,8 +397,6 @@ public class BoatGroup extends Group {
|
|||||||
boat is travelling into the wind. thus upwind. Otherwise if they are on different sides, then the boat is going
|
boat is travelling into the wind. thus upwind. Otherwise if they are on different sides, then the boat is going
|
||||||
with the wind.
|
with the wind.
|
||||||
*/
|
*/
|
||||||
System.out.println("Boat Line func result: " + boatLineFuncResult);
|
|
||||||
System.out.println("Wind Line func result: " + windLineFuncResult);
|
|
||||||
if (boatLineFuncResult == windLineFuncResult) {
|
if (boatLineFuncResult == windLineFuncResult) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,4 +114,50 @@ public final class PolarTable {
|
|||||||
return downwindOptimal;
|
return downwindOptimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will raise an exception if a polar table has just one row of data
|
||||||
|
* @param thisWindSpeed The current wind speed
|
||||||
|
* @return HashMap containing just the optimal upwind angle and resulting boat speed
|
||||||
|
*/
|
||||||
|
public static HashMap<Double, Double> getOptimalUpwindVMG(Double thisWindSpeed) {
|
||||||
|
|
||||||
|
Double polarWindSpeed = getClosestMatch(thisWindSpeed);
|
||||||
|
return upwindOptimal.get(polarWindSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will raise an exception if a polar table has just one row of data
|
||||||
|
* @param thisWindSpeed The current wind speed
|
||||||
|
* @return HashMap containing just the optimal downwind angle and resulting boat speed
|
||||||
|
*/
|
||||||
|
public static HashMap<Double, Double> getOptimalDownwindVMG(Double thisWindSpeed) {
|
||||||
|
|
||||||
|
Double polarWindSpeed = getClosestMatch(thisWindSpeed);
|
||||||
|
return downwindOptimal.get(polarWindSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Double getClosestMatch(Double thisWindSpeed) {
|
||||||
|
|
||||||
|
ArrayList<Double> windValues = new ArrayList<>(polarTable.keySet());
|
||||||
|
|
||||||
|
Double lowerVal = windValues.get(0);
|
||||||
|
Double upperVal = windValues.get(1);
|
||||||
|
|
||||||
|
for(int i = 0; i < windValues.size() - 1; i++) {
|
||||||
|
lowerVal = windValues.get(i);
|
||||||
|
upperVal = windValues.get(i+1);
|
||||||
|
if (thisWindSpeed <= upperVal) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Double lowerDiff = Math.abs(lowerVal - thisWindSpeed);
|
||||||
|
Double upperDiff = Math.abs(upperVal - thisWindSpeed);
|
||||||
|
|
||||||
|
return (lowerDiff <= upperDiff) ? lowerVal : upperVal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ public class MarkGroup extends Group {
|
|||||||
* @param layLineAngle The angle the laylines point
|
* @param layLineAngle The angle the laylines point
|
||||||
* @param baseAngle The reference angle
|
* @param baseAngle The reference angle
|
||||||
*/
|
*/
|
||||||
private void addLayLine(Point2D startPoint, Double layLineAngle, Double baseAngle){
|
public void addLayLine(Point2D startPoint, Double layLineAngle, Double baseAngle){
|
||||||
|
|
||||||
Point2D ep1 = getPointRotation(startPoint, 50.0, baseAngle + -layLineAngle);
|
Point2D ep1 = getPointRotation(startPoint, 50.0, baseAngle + -layLineAngle);
|
||||||
Point2D ep2 = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
|
Point2D ep2 = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
|
||||||
@@ -117,8 +117,8 @@ public class MarkGroup extends Group {
|
|||||||
//Laylines
|
//Laylines
|
||||||
// if (mark.)
|
// if (mark.)
|
||||||
|
|
||||||
addLayLine(points1, 12.0, 90.0);
|
// addLayLine(points1, 12.0, 90.0);
|
||||||
addLayLine(points2, 12.0, 90.0);
|
// addLayLine(points2, 12.0, 90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveMarkTo (double x, double y, long raceId)
|
public void moveMarkTo (double x, double y, long raceId)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -24,7 +23,6 @@ import org.xml.sax.InputSource;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.mark.Mark;
|
import seng302.models.mark.Mark;
|
||||||
import seng302.models.stream.XMLParser.RaceXMLObject.Corner;
|
|
||||||
import seng302.models.stream.packets.BoatPositionPacket;
|
import seng302.models.stream.packets.BoatPositionPacket;
|
||||||
import seng302.models.stream.packets.StreamPacket;
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
@@ -49,10 +47,15 @@ public class StreamParser extends Thread{
|
|||||||
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
|
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
|
||||||
private static Map<Long, Yacht> boatsPos = new ConcurrentSkipListMap<>();
|
private static Map<Long, Yacht> boatsPos = new ConcurrentSkipListMap<>();
|
||||||
private static double windDirection = 0;
|
private static double windDirection = 0;
|
||||||
|
private static Double windSpeed = 0d;
|
||||||
private static Long currentTimeLong;
|
private static Long currentTimeLong;
|
||||||
private static String currentTimeString;
|
private static String currentTimeString;
|
||||||
private static boolean appRunning;
|
private static boolean appRunning;
|
||||||
|
|
||||||
|
|
||||||
|
//CONVERSION CONSTANTS
|
||||||
|
private static final Double MS_TO_KNOTS = 1.94384;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to initialise the thread name and stream parser object so a thread can be executed
|
* Used to initialise the thread name and stream parser object so a thread can be executed
|
||||||
*
|
*
|
||||||
@@ -196,7 +199,7 @@ public class StreamParser extends Thread{
|
|||||||
int raceStatus = payload[11];
|
int raceStatus = payload[11];
|
||||||
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
|
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
|
||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
||||||
long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
|
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
|
||||||
|
|
||||||
currentTimeLong = currentTime;
|
currentTimeLong = currentTime;
|
||||||
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
||||||
@@ -224,6 +227,7 @@ public class StreamParser extends Thread{
|
|||||||
|
|
||||||
double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc...
|
double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc...
|
||||||
windDirection = windDir / windDirFactor;
|
windDirection = windDir / windDirFactor;
|
||||||
|
windSpeed = rawWindSpeed / 1000 * MS_TO_KNOTS;
|
||||||
|
|
||||||
int noBoats = payload[22];
|
int noBoats = payload[22];
|
||||||
int raceType = payload[23];
|
int raceType = payload[23];
|
||||||
@@ -445,25 +449,10 @@ public class StreamParser extends Thread{
|
|||||||
// assign mark rounding time to boat
|
// assign mark rounding time to boat
|
||||||
boats.get((int)subjectId).setMarkRoundingTime(timeStamp);
|
boats.get((int)subjectId).setMarkRoundingTime(timeStamp);
|
||||||
|
|
||||||
for (Mark mark : xmlObject.getRaceXML().getCompoundMarks()) {
|
for (Mark mark : xmlObject.getRaceXML().getAllCompoundMarks()) {
|
||||||
if (mark.getCompoundMarkID() == markId) {
|
if (mark.getCompoundMarkID() == markId) {
|
||||||
boats.get((int)subjectId).setLastMarkRounded(mark);
|
boats.get((int)subjectId).setLastMarkRounded(mark);
|
||||||
|
}
|
||||||
List<Corner> markSequence = xmlObject.getRaceXML().getCompoundMarkSequence();
|
|
||||||
|
|
||||||
for (int i = 0; i < markSequence.size() - 1; i++){
|
|
||||||
Corner corner = markSequence.get(i);
|
|
||||||
|
|
||||||
if (corner.getCompoundMarkID().equals(mark.getCompoundMarkID()) && (i + 1) < markSequence.size()){
|
|
||||||
Corner nextCorner = markSequence.get(i+1);
|
|
||||||
for (Mark m : xmlObject.getRaceXML().getCompoundMarks()){
|
|
||||||
if (m.getCompoundMarkID() == nextCorner.getCompoundMarkID()){
|
|
||||||
boats.get((int)subjectId).setNextMark(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,6 +582,15 @@ public class StreamParser extends Thread{
|
|||||||
return windDirection;
|
return windDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the wind speed in knots
|
||||||
|
* @return A double indicating the wind speed in knots
|
||||||
|
*/
|
||||||
|
public static Double getWindSpeed() {
|
||||||
|
return windSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns stream time in formatted string format
|
* returns stream time in formatted string format
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -235,7 +235,8 @@ public class XMLParser {
|
|||||||
|
|
||||||
//Non atomic race attributes
|
//Non atomic race attributes
|
||||||
private ArrayList<Participant> participants;
|
private ArrayList<Participant> participants;
|
||||||
private ArrayList<Mark> course;
|
private ArrayList<Mark> allMarks;
|
||||||
|
private ArrayList<Mark> nonDuplicateMarks;
|
||||||
private ArrayList<Corner> compoundMarkSequence;
|
private ArrayList<Corner> compoundMarkSequence;
|
||||||
private ArrayList<Limit> courseLimit;
|
private ArrayList<Limit> courseLimit;
|
||||||
|
|
||||||
@@ -283,7 +284,9 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Course
|
//Course
|
||||||
course = createCompoundMarks(docEle);
|
allMarks = new ArrayList<>();
|
||||||
|
nonDuplicateMarks = new ArrayList<>();
|
||||||
|
createCompoundMarks(docEle);
|
||||||
|
|
||||||
//Course Mark Sequence
|
//Course Mark Sequence
|
||||||
compoundMarkSequence = new ArrayList<>();
|
compoundMarkSequence = new ArrayList<>();
|
||||||
@@ -312,26 +315,21 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ArrayList<Mark> createCompoundMarks(Element docEle) {
|
private void createCompoundMarks(Element docEle) {
|
||||||
ArrayList<Mark> cMarks = new ArrayList<>();
|
|
||||||
|
|
||||||
NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
||||||
for (int i = 0; i < cMarkList.getLength(); i++) {
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
Node cMarkNode = cMarkList.item(i);
|
Node cMarkNode = cMarkList.item(i);
|
||||||
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
Mark mark = createMark(cMarkNode);
|
createAndAddMark(cMarkNode);
|
||||||
if (mark != null) {
|
|
||||||
cMarks.add(mark);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cMarks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Mark createMark(Node compoundMark) {
|
private void createAndAddMark(Node compoundMark) {
|
||||||
|
|
||||||
|
Boolean markSeen = false;
|
||||||
List<SingleMark> marksList = new ArrayList<>();
|
List<SingleMark> marksList = new ArrayList<>();
|
||||||
Integer compoundMarkID = getNodeAttributeInt(compoundMark, "CompoundMarkID");
|
Integer compoundMarkID = getNodeAttributeInt(compoundMark, "CompoundMarkID");
|
||||||
String cMarkName = getNodeAttributeString(compoundMark, "Name");
|
String cMarkName = getNodeAttributeString(compoundMark, "Name");
|
||||||
@@ -354,20 +352,26 @@ public class XMLParser {
|
|||||||
|
|
||||||
for (SingleMark mark : marksList) {
|
for (SingleMark mark : marksList) {
|
||||||
if (seenSourceIDs.contains(mark.getId())) {
|
if (seenSourceIDs.contains(mark.getId())) {
|
||||||
return null;
|
markSeen = true;
|
||||||
} else {
|
} else {
|
||||||
seenSourceIDs.add(mark.getId());
|
seenSourceIDs.add(mark.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (marksList.size() == 1) {
|
if (marksList.size() == 1) {
|
||||||
return marksList.get(0);
|
if (!markSeen) {
|
||||||
|
nonDuplicateMarks.add(marksList.get(0));
|
||||||
|
}
|
||||||
|
allMarks.add(marksList.get(0));
|
||||||
} else if (marksList.size() == 2) {
|
} else if (marksList.size() == 2) {
|
||||||
return new GateMark(cMarkName, MarkType.OPEN_GATE, marksList.get(0),
|
GateMark thisGateMark = new GateMark(cMarkName, MarkType.OPEN_GATE, marksList.get(0),
|
||||||
marksList.get(1), marksList.get(0).getLatitude(),
|
marksList.get(1), marksList.get(0).getLatitude(),
|
||||||
marksList.get(0).getLongitude(), compoundMarkID);
|
marksList.get(0).getLongitude(), compoundMarkID);
|
||||||
} else {
|
if(!markSeen) {
|
||||||
return null;
|
nonDuplicateMarks.add(thisGateMark);
|
||||||
|
}
|
||||||
|
allMarks.add(thisGateMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -396,8 +400,18 @@ public class XMLParser {
|
|||||||
return participants;
|
return participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Mark> getCompoundMarks() {
|
/**
|
||||||
return course;
|
* @return Returns ALL compound marks as stated in the RaceXML (INCLUDING DUPLICATE MARKS)
|
||||||
|
*/
|
||||||
|
public List<Mark> getAllCompoundMarks() {
|
||||||
|
return allMarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns Marks from the race XML without any duplicates
|
||||||
|
*/
|
||||||
|
public List<Mark> getNonDupCompoundMarks() {
|
||||||
|
return nonDuplicateMarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Corner> getCompoundMarkSequence() {
|
public ArrayList<Corner> getCompoundMarkSequence() {
|
||||||
|
|||||||
Reference in New Issue
Block a user