mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Refactored the setup for MarkObjects (now renamed Markers) and made the CompoundMark + Mark + GeoPoint classes the standard across all classes instead of GateMark + SingleMark + Mark.
#refactor
This commit is contained in:
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
package seng302.utilities;
|
package seng302.model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class represent Geo location (latitude, longitude).
|
* A class represent Geo location (latitude, lnggitude).
|
||||||
* Created by Haoming on 15/5/2017
|
* Created by Haoming on 15/5/2017
|
||||||
*/
|
*/
|
||||||
public class GeoPoint {
|
public class GeoPoint {
|
||||||
|
|
||||||
double lat, lng;
|
private double lat, lng;
|
||||||
|
|
||||||
public GeoPoint(double lat, double lng) {
|
public GeoPoint(double lat, double lng) {
|
||||||
this.lat = lat;
|
this.lat = lat;
|
||||||
@@ -3,27 +3,16 @@ package seng302.model;
|
|||||||
/**
|
/**
|
||||||
* Stores data on the border of a race
|
* Stores data on the border of a race
|
||||||
*/
|
*/
|
||||||
public class Limit {
|
public class Limit extends GeoPoint {
|
||||||
|
|
||||||
private Integer seqID;
|
private Integer seqID;
|
||||||
private Double lat;
|
|
||||||
private Double lng;
|
|
||||||
|
|
||||||
public Limit(Integer seqID, Double lat, Double lng) {
|
public Limit(Integer seqID, Double lat, Double lng) {
|
||||||
|
super(lat, lng);
|
||||||
this.seqID = seqID;
|
this.seqID = seqID;
|
||||||
this.lat = lat;
|
|
||||||
this.lng = lng;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getSeqID() {
|
public Integer getSeqID() {
|
||||||
return seqID;
|
return seqID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getLat() {
|
|
||||||
return lat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getLng() {
|
|
||||||
return lng;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,6 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.utilities.GeoPoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat.
|
* Yacht class for the racing boat.
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package seng302.model.mark;
|
||||||
|
|
||||||
|
import com.sun.deploy.util.StringUtils;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CompoundMark {
|
||||||
|
|
||||||
|
private int compoundMarkId;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private List<Mark> marks = new ArrayList<>();
|
||||||
|
|
||||||
|
public CompoundMark(int markID, String name) {
|
||||||
|
this.compoundMarkId = markID;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSubMarks(Mark... marks) {
|
||||||
|
this.marks.addAll(Arrays.asList(marks));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSubMarks(List<Mark> marks) {
|
||||||
|
this.marks.addAll(marks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints out compoundMark's info and its marks, good for testing
|
||||||
|
* @return a string showing its details
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
String info = String.format("CompoundMark: %d (%s), [", compoundMarkId, name);
|
||||||
|
info += StringUtils.join(marks, ", ") + "]";
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return compoundMarkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId (int markID) {
|
||||||
|
this.compoundMarkId = markID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mark contained in the compound mark. Marks are numbered 1 to n;
|
||||||
|
* @param singleMarkId the id of the desired mark contained in this compound mark.
|
||||||
|
* @return the desired mark. Returns null if the ID is not in range (1, NUM_MARKS)
|
||||||
|
*/
|
||||||
|
public Mark getSubMark(int singleMarkId) {
|
||||||
|
try {
|
||||||
|
return marks.get(singleMarkId - 1);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not this CompoundMark is a Gate. It is generally cleaner to program to a
|
||||||
|
* specific singleMark or the list of marks.
|
||||||
|
*
|
||||||
|
* @return True if the compound mark is a gate, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isGate () {
|
||||||
|
return marks.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of marks in the compoundMark
|
||||||
|
*
|
||||||
|
* @return All marks contained in this mark.
|
||||||
|
*/
|
||||||
|
public List<Mark> getMarks () {
|
||||||
|
return marks;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package seng302.model;
|
package seng302.model.mark;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the data for the cornering of a mark.
|
* Stores the data for the cornering of a mark.
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package seng302.model.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To represent a gate mark which contains two single marks.
|
|
||||||
* Created by ptg19 on 16/03/17.
|
|
||||||
* Modified by Haoming Yin (hyi25) on 17/3/2017.
|
|
||||||
*/
|
|
||||||
public class GateMark extends Mark {
|
|
||||||
|
|
||||||
private SingleMark singleMark1;
|
|
||||||
private SingleMark singleMark2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of Gate Mark which contains two single mark
|
|
||||||
* @param name the name of the gate mark
|
|
||||||
* @param singleMark1 one single mark inside of the gate mark
|
|
||||||
* @param singleMark2 the second mark inside of the gate mark
|
|
||||||
*/
|
|
||||||
public GateMark(String name, MarkType type, SingleMark singleMark1, SingleMark singleMark2, double latitude, double longitude, int compoundMarkID) {
|
|
||||||
super(name, type, latitude, longitude, compoundMarkID);
|
|
||||||
this.singleMark1 = singleMark1;
|
|
||||||
this.singleMark2 = singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleMark getSingleMark1() {
|
|
||||||
return singleMark1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSingleMark1(SingleMark singleMark1) {
|
|
||||||
this.singleMark1 = singleMark1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleMark getSingleMark2() {
|
|
||||||
return singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSingleMark2(SingleMark singleMark2) {
|
|
||||||
this.singleMark2 = singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude(){
|
|
||||||
return (this.getSingleMark1().getLatitude());
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude(){
|
|
||||||
return (this.getSingleMark1().getLongitude());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +1,46 @@
|
|||||||
package seng302.model.mark;
|
package seng302.model.mark;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract class to represent general marks
|
* An abstract class to represent general marks
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
* Created by Haoming Yin (hyi25) on 17/3/17.
|
||||||
*/
|
*/
|
||||||
public abstract class Mark {
|
public class Mark extends GeoPoint {
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PositionListener {
|
||||||
|
void notifyPositionChange(Mark mark, double lat, double lon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int seqID;
|
||||||
private String name;
|
private String name;
|
||||||
private MarkType markType;
|
private int sourceID;
|
||||||
private double latitude;
|
private List<PositionListener> positionListeners = new ArrayList<>();
|
||||||
private double longitude;
|
|
||||||
private int id;
|
|
||||||
private int compoundMarkID;
|
|
||||||
|
|
||||||
/**
|
public Mark(String name, double lat, double lng, int sourceID) {
|
||||||
* Create a mark instance by passing its name and type
|
super(lat, lng);
|
||||||
* @param name the name of the mark
|
|
||||||
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
|
||||||
*/
|
|
||||||
public Mark (String name, MarkType markType, int sourceID, int compoundMarkID) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.markType = markType;
|
this.sourceID = sourceID;
|
||||||
this.id = sourceID;
|
|
||||||
this.compoundMarkID = compoundMarkID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark(String name, MarkType markType, double latitude, double longitude, int compoundMarkID) {
|
|
||||||
this.name = name;
|
|
||||||
this.markType = markType;
|
|
||||||
this.latitude = latitude;
|
|
||||||
this.longitude = longitude;
|
|
||||||
this.id = 0;
|
|
||||||
this.compoundMarkID = compoundMarkID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculated the heading in radians from first Mark to the second Mark.
|
* Prints out mark's info and its geo location, good for testing
|
||||||
*
|
* @return a string showing its details
|
||||||
* @param pointOne First Mark
|
|
||||||
* @param pointTwo Second Mark
|
|
||||||
* @return Heading in radians
|
|
||||||
*/
|
*/
|
||||||
public static Double calculateHeadingRad(Mark pointOne, Mark pointTwo) {
|
@Override
|
||||||
Double longitude1 = pointOne.getLongitude();
|
public String toString() {
|
||||||
Double longitude2 = pointTwo.getLongitude();
|
return String.format("Mark%d: %s, source: %d, lat: %f, lng: %f", seqID, name, sourceID, getLat(), getLng());
|
||||||
Double latitude1 = pointOne.getLatitude();
|
|
||||||
Double latitude2 = pointTwo.getLatitude();
|
|
||||||
return calculateHeadingRad(latitude1, longitude1, latitude2, longitude2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public int getSeqID() {
|
||||||
* Calculate the heading in radians from geographical location with latitude1, longitude 1 to
|
return seqID;
|
||||||
* geographical latitude2, longitude 2
|
|
||||||
*
|
|
||||||
* @param longitude1 Longitude of first point in degrees
|
|
||||||
* @param longitude2 Longitude of second point in degrees
|
|
||||||
* @param latitude1 Latitude of first point in degrees
|
|
||||||
* @param latitude2 Latitude of first point in degrees
|
|
||||||
* @return Heading in radians
|
|
||||||
*/
|
|
||||||
public static double calculateHeadingRad(Double latitude1, Double longitude1, Double latitude2,
|
|
||||||
Double longitude2) {
|
|
||||||
latitude1 = Math.toRadians(latitude1);
|
|
||||||
latitude2 = Math.toRadians(latitude2);
|
|
||||||
Double longDiff = Math.toRadians(longitude2 - longitude1);
|
|
||||||
Double y = Math.sin(longDiff) * Math.cos(latitude2);
|
|
||||||
Double x =
|
|
||||||
Math.cos(latitude1) * Math.sin(latitude2) - Math.sin(latitude1) * Math.cos(latitude2)
|
|
||||||
* Math.cos(longDiff);
|
|
||||||
return Math.atan2(y, x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setSeqID(int seqID) {
|
||||||
* Calculates the distance in meters from the first Mark to a second Mark
|
this.seqID = seqID;
|
||||||
*
|
|
||||||
* @param pointOne First Mark
|
|
||||||
* @param pointTwo Second Mark
|
|
||||||
* @return Distance in meters
|
|
||||||
*/
|
|
||||||
public static Double calculateDistance(Mark pointOne, Mark pointTwo) {
|
|
||||||
Double longitude1 = pointOne.getLongitude();
|
|
||||||
Double longitude2 = pointTwo.getLongitude();
|
|
||||||
Double latitude1 = pointOne.getLatitude();
|
|
||||||
Double latitude2 = pointTwo.getLatitude();
|
|
||||||
return calculateDistance(latitude1, longitude1, latitude2, longitude2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the distance in meters from geographical location with latitude1, longitude 1 to
|
|
||||||
* geographical latitude2, longitude 2
|
|
||||||
*
|
|
||||||
* @param longitude1 Longitude of first point in degrees
|
|
||||||
* @param longitude2 Longitude of second point in degrees
|
|
||||||
* @param latitude1 Latitude of first point in degrees
|
|
||||||
* @param latitude2 Latitude of first point in degrees
|
|
||||||
* @return Distance in meters
|
|
||||||
*/
|
|
||||||
public static Double calculateDistance(Double latitude1, Double longitude1, Double latitude2,
|
|
||||||
Double longitude2) {
|
|
||||||
Double theta = longitude1 - longitude2;
|
|
||||||
Double dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) +
|
|
||||||
Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) *
|
|
||||||
Math.cos(Math.toRadians(theta));
|
|
||||||
dist = Math.acos(dist);
|
|
||||||
dist = Math.toDegrees(dist);
|
|
||||||
dist = dist * 60
|
|
||||||
* 1.1508; //nautical mile (distance between two degrees) * (degrees in a minute)
|
|
||||||
dist = dist * 1609.344; //ratio of miles to metres
|
|
||||||
return dist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -118,31 +51,29 @@ public abstract class Mark {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MarkType getMarkType() {
|
public int getSourceID() {
|
||||||
return markType;
|
return sourceID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMarkType(MarkType markType) {
|
public void setSourceID(int sourceID) {
|
||||||
this.markType = markType;
|
this.sourceID = sourceID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLatitude() {
|
public void updatePosition (double lat, double lon) {
|
||||||
return latitude;
|
this.setLat(lat);
|
||||||
|
this.setLng(lon);
|
||||||
|
for (PositionListener listener : positionListeners) {
|
||||||
|
listener.notifyPositionChange(this, lat, lon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLongitude() {
|
public void addPositionListener (PositionListener listener) {
|
||||||
return longitude;
|
positionListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public void removePositionListener (PositionListener listener) {
|
||||||
return id;
|
positionListeners.remove(listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(int id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCompoundMarkID() {
|
|
||||||
return compoundMarkID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
package seng302.model.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To represent two types of mark
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
|
||||||
*/
|
|
||||||
public enum MarkType {
|
|
||||||
SINGLE_MARK, OPEN_GATE
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package seng302.model.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the marker as a single mark
|
|
||||||
*
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/2017
|
|
||||||
*/
|
|
||||||
public class SingleMark extends Mark {
|
|
||||||
private double lat;
|
|
||||||
private double lon;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a marker
|
|
||||||
*
|
|
||||||
* @param name, the name of the marker*
|
|
||||||
* @param lat, the latitude of the marker
|
|
||||||
* @param lon, the longitude of the marker
|
|
||||||
*/
|
|
||||||
public SingleMark(String name, double lat, double lon, int sourceID, int compoundMarkID) {
|
|
||||||
super(name, MarkType.SINGLE_MARK, sourceID, compoundMarkID);
|
|
||||||
this.lat = lat;
|
|
||||||
this.lon = lon;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public double getLatitude() {
|
|
||||||
return this.lat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude() {
|
|
||||||
return this.lon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@ package seng302.model.stream.xml.parser;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import seng302.model.Corner;
|
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a Document object containing race data in XML format and stores the data.
|
* Process a Document object containing race data in XML format and stores the data.
|
||||||
@@ -13,20 +13,18 @@ import seng302.model.mark.Mark;
|
|||||||
public class RaceXMLData {
|
public class RaceXMLData {
|
||||||
|
|
||||||
private List<Integer> participants;
|
private List<Integer> participants;
|
||||||
private Map<Integer, Mark> compoundMarks;
|
private Map<Integer, CompoundMark> compoundMarks;
|
||||||
private List<Corner> markSequence;
|
private List<Corner> markSequence;
|
||||||
private List<Limit> courseLimit;
|
private List<Limit> courseLimit;
|
||||||
private Map<Integer, Mark> individualMarks;
|
|
||||||
|
|
||||||
public RaceXMLData(List<Integer> participants, List<Mark> compoundMarks, List<Corner> markSequence,
|
public RaceXMLData(List<Integer> participants, List<CompoundMark> compoundMarks,
|
||||||
List<Limit> courseLimit) {
|
List<Corner> markSequence, List<Limit> courseLimit) {
|
||||||
this.participants = participants;
|
this.participants = participants;
|
||||||
this.markSequence = markSequence;
|
this.markSequence = markSequence;
|
||||||
this.courseLimit = courseLimit;
|
this.courseLimit = courseLimit;
|
||||||
this.compoundMarks = new HashMap<>();
|
this.compoundMarks = new HashMap<>();
|
||||||
for (Mark mark : compoundMarks)
|
for (CompoundMark cMark : compoundMarks) {
|
||||||
this.compoundMarks.put(mark.getId(), mark);
|
this.compoundMarks.put(cMark.getId(), cMark);
|
||||||
for (Mark mark : compoundMarks) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +32,7 @@ public class RaceXMLData {
|
|||||||
return participants;
|
return participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, Mark> getCompoundMarks() {
|
public Map<Integer, CompoundMark> getCompoundMarks() {
|
||||||
return compoundMarks;
|
return compoundMarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,4 +43,5 @@ public class RaceXMLData {
|
|||||||
public List<Limit> getCourseLimit() {
|
public List<Limit> getCourseLimit() {
|
||||||
return courseLimit;
|
return courseLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package seng302.server.simulator;
|
package seng302.server.simulator;
|
||||||
|
|
||||||
import seng302.server.simulator.mark.Corner;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.utilities.GeoPoint;
|
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
public class Boat {
|
public class Boat {
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
package seng302.server.simulator.mark;
|
package seng302.server.simulator;
|
||||||
|
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
|
||||||
public class Corner {
|
public class Corner {
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package seng302.server.simulator.mark;
|
package seng302.server.simulator;
|
||||||
|
|
||||||
public enum RoundingType {
|
public enum RoundingType {
|
||||||
|
|
||||||
@@ -3,10 +3,9 @@ package seng302.server.simulator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import seng302.server.simulator.mark.Corner;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.server.simulator.mark.Mark;
|
|
||||||
import seng302.server.simulator.parsers.RaceParser;
|
import seng302.server.simulator.parsers.RaceParser;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
public class Simulator extends Observable implements Runnable {
|
public class Simulator extends Observable implements Runnable {
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
package seng302.server.simulator.mark;
|
|
||||||
|
|
||||||
public class CompoundMark {
|
|
||||||
|
|
||||||
private int markID;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private Mark mark1;
|
|
||||||
private Mark mark2;
|
|
||||||
|
|
||||||
public CompoundMark(int markID, String name) {
|
|
||||||
this.markID = markID;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMark(int seqId, Mark mark) {
|
|
||||||
if (seqId == 1) {
|
|
||||||
setMark1(mark);
|
|
||||||
} else if (seqId == 2) {
|
|
||||||
setMark2(mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints out compoundMark's info and its marks, good for testing
|
|
||||||
* @return a string showing its details
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
if (mark2 == null)
|
|
||||||
return String.format("CompoundMark: %d (%s), [%s]",
|
|
||||||
markID, name, mark1.toString());
|
|
||||||
return String.format("CompoundMark: %d (%s), [%s; %s]",
|
|
||||||
markID, name, mark1.toString(), mark2.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMarkID() {
|
|
||||||
return markID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMarkID(int markID) {
|
|
||||||
this.markID = markID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark getMark1() {
|
|
||||||
return mark1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMark1(Mark mark1) {
|
|
||||||
this.mark1 = mark1;
|
|
||||||
mark1.setSeqID(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark getMark2() {
|
|
||||||
return mark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMark2(Mark mark2) {
|
|
||||||
this.mark2 = mark2;
|
|
||||||
mark2.setSeqID(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package seng302.server.simulator.mark;
|
|
||||||
|
|
||||||
import seng302.utilities.GeoPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An abstract class to represent general marks
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
|
||||||
*/
|
|
||||||
public class Mark extends GeoPoint {
|
|
||||||
|
|
||||||
private int seqID;
|
|
||||||
private String name;
|
|
||||||
private int sourceID;
|
|
||||||
|
|
||||||
public Mark(String name, double lat, double lng, int sourceID) {
|
|
||||||
super(lat, lng);
|
|
||||||
this.name = name;
|
|
||||||
this.sourceID = sourceID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints out mark's info and its geo location, good for testing
|
|
||||||
* @return a string showing its details
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Mark%d: %s, source: %d, lat: %f, lng: %f", seqID, name, sourceID, getLat(), getLng());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSeqID() {
|
|
||||||
return seqID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSeqID(int seqID) {
|
|
||||||
this.seqID = seqID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSourceID() {
|
|
||||||
return sourceID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSourceID(int sourceID) {
|
|
||||||
this.sourceID = sourceID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -8,10 +8,10 @@ import org.w3c.dom.Document;
|
|||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import seng302.server.simulator.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.server.simulator.mark.Corner;
|
import seng302.server.simulator.Corner;
|
||||||
import seng302.server.simulator.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.server.simulator.mark.RoundingType;
|
import seng302.server.simulator.RoundingType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the race xml file to get course details
|
* Parses the race xml file to get course details
|
||||||
@@ -66,7 +66,7 @@ public class CourseParser extends FileParser {
|
|||||||
for (int i = 0; i < cMarks.getLength(); i++) {
|
for (int i = 0; i < cMarks.getLength(); i++) {
|
||||||
CompoundMark cMark = getCompoundMark(cMarks.item(i));
|
CompoundMark cMark = getCompoundMark(cMarks.item(i));
|
||||||
if (cMark != null)
|
if (cMark != null)
|
||||||
compoundMarksMap.put(cMark.getMarkID(), cMark);
|
compoundMarksMap.put(cMark.getId(), cMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
return compoundMarksMap;
|
return compoundMarksMap;
|
||||||
@@ -87,7 +87,7 @@ public class CourseParser extends FileParser {
|
|||||||
for (int i = 0; i < marks.getLength(); i++) {
|
for (int i = 0; i < marks.getLength(); i++) {
|
||||||
Mark mark = getMark(marks.item(i));
|
Mark mark = getMark(marks.item(i));
|
||||||
if (mark != null)
|
if (mark != null)
|
||||||
cMark.addMark(mark.getSeqID(), mark);
|
cMark.addSubMarks(mark);
|
||||||
}
|
}
|
||||||
return cMark;
|
return cMark;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import org.w3c.dom.Element;
|
|||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import seng302.server.simulator.Boat;
|
import seng302.server.simulator.Boat;
|
||||||
import seng302.server.simulator.mark.Corner;
|
import seng302.server.simulator.Corner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the race xml file to get course details
|
* Parses the race xml file to get course details
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
public class GeoUtility {
|
public class GeoUtility {
|
||||||
|
|
||||||
@@ -43,16 +44,31 @@ public class GeoUtility {
|
|||||||
* and end up on a heading of 120°
|
* and end up on a heading of 120°
|
||||||
*/
|
*/
|
||||||
public static Double getBearing(GeoPoint p1, GeoPoint p2) {
|
public static Double getBearing(GeoPoint p1, GeoPoint p2) {
|
||||||
|
return (getBearingRad(p1, p2) + 360.0) % 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the angle between to angular co-ordinates on a sphere in radians.
|
||||||
|
*
|
||||||
|
* @param p1 the first geographical position, start point
|
||||||
|
* @param p2 the second geographical position, end point
|
||||||
|
* @return the initial bearing in degree from p1 to p2, value range (0 ~ 360 deg.).
|
||||||
|
* vertical up is 0 deg. horizontal right is 90 deg.
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
* The final bearing will differ from the initial bearing by varying degrees
|
||||||
|
* according to distance and latitude (if you were to go from say 35°N,45°E
|
||||||
|
* (≈ Baghdad) to 35°N,135°E (≈ Osaka), you would start on a heading of 60°
|
||||||
|
* and end up on a heading of 120°
|
||||||
|
*/
|
||||||
|
public static Double getBearingRad(GeoPoint p1, GeoPoint p2) {
|
||||||
double dLon = Math.toRadians(p2.getLng() - p1.getLng());
|
double dLon = Math.toRadians(p2.getLng() - p1.getLng());
|
||||||
|
|
||||||
double y = Math.sin(dLon) * Math.cos(Math.toRadians(p2.getLat()));
|
double y = Math.sin(dLon) * Math.cos(Math.toRadians(p2.getLat()));
|
||||||
double x = Math.cos(Math.toRadians(p1.getLat())) * Math.sin(Math.toRadians(p2.getLat()))
|
double x = Math.cos(Math.toRadians(p1.getLat())) * Math.sin(Math.toRadians(p2.getLat()))
|
||||||
- Math.sin(Math.toRadians(p1.getLat())) * Math.cos(Math.toRadians(p2.getLat())) * Math.cos(dLon);
|
- Math.sin(Math.toRadians(p1.getLat())) * Math.cos(Math.toRadians(p2.getLat())) * Math.cos(dLon);
|
||||||
|
|
||||||
double bearing = Math.toDegrees(Math.atan2(y, x));
|
return Math.toDegrees(Math.atan2(y, x));
|
||||||
|
|
||||||
return (bearing + 360.0) % 360.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import org.w3c.dom.Document;
|
|||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import seng302.model.Corner;
|
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.Yacht;
|
import seng302.model.Yacht;
|
||||||
import seng302.model.mark.GateMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkType;
|
|
||||||
import seng302.model.mark.SingleMark;
|
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
|
||||||
@@ -249,13 +247,19 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Extracts course mark data
|
* Extracts course mark data
|
||||||
*/
|
*/
|
||||||
private static List<Mark> extractCompoundMarks(Element docEle) {
|
private static List<CompoundMark> extractCompoundMarks(Element docEle) {
|
||||||
List<Mark> allMarks = new ArrayList<>();
|
List<CompoundMark> allMarks = new ArrayList<>();
|
||||||
NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
||||||
|
CompoundMark cMark;
|
||||||
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")) {
|
||||||
allMarks.add(createMark(cMarkNode));
|
cMark = new CompoundMark(
|
||||||
|
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
|
||||||
|
XMLParser.getNodeAttributeString(cMarkNode, "Name")
|
||||||
|
);
|
||||||
|
cMark.addSubMarks(createMarks(cMarkNode));
|
||||||
|
allMarks.add(cMark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allMarks;
|
return allMarks;
|
||||||
@@ -264,8 +268,8 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Creates marks objects from the given node
|
* Creates marks objects from the given node
|
||||||
*/
|
*/
|
||||||
private static Mark createMark(Node compoundMark) {
|
private static List<Mark> createMarks(Node compoundMark) {
|
||||||
List<SingleMark> subMarks = new ArrayList<>();
|
List<Mark> subMarks = new ArrayList<>();
|
||||||
Integer compoundMarkID = XMLParser.getNodeAttributeInt(compoundMark, "CompoundMarkID");
|
Integer compoundMarkID = XMLParser.getNodeAttributeInt(compoundMark, "CompoundMarkID");
|
||||||
String cMarkName = XMLParser.getNodeAttributeString(compoundMark, "Name");
|
String cMarkName = XMLParser.getNodeAttributeString(compoundMark, "Name");
|
||||||
|
|
||||||
@@ -277,17 +281,10 @@ public class XMLParser {
|
|||||||
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
||||||
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
||||||
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
||||||
SingleMark mark = new SingleMark(markName, targetLat, targetLng, sourceID,
|
Mark mark = new Mark(markName, targetLat, targetLng, sourceID);
|
||||||
compoundMarkID);
|
|
||||||
subMarks.add(mark);
|
subMarks.add(mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subMarks.size() == 1) {
|
return subMarks;
|
||||||
return subMarks.get(0);
|
|
||||||
} else {
|
|
||||||
return new GateMark( cMarkName, MarkType.OPEN_GATE, subMarks.get(0), subMarks.get(1),
|
|
||||||
subMarks.get(0).getLatitude(), subMarks.get(0).getLongitude(), compoundMarkID
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -11,38 +10,34 @@ import java.util.Map;
|
|||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import seng302.model.Colors;
|
import seng302.model.Colors;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.Yacht;
|
import seng302.model.Yacht;
|
||||||
import seng302.model.mark.GateMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkType;
|
|
||||||
import seng302.model.mark.SingleMark;
|
|
||||||
import seng302.utilities.GeoPoint;
|
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.visualiser.fxObjects.AnnotationBox;
|
import seng302.visualiser.fxObjects.AnnotationBox;
|
||||||
import seng302.visualiser.fxObjects.BoatObject;
|
import seng302.visualiser.fxObjects.BoatObject;
|
||||||
import seng302.visualiser.fxObjects.MarkObject;
|
import seng302.visualiser.fxObjects.Gate;
|
||||||
|
import seng302.visualiser.fxObjects.Marker;
|
||||||
|
import seng302.visualiser.map.Boundary;
|
||||||
|
import seng302.visualiser.map.CanvasMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by cir27 on 20/07/17.
|
* Created by cir27 on 20/07/17.
|
||||||
*/
|
*/
|
||||||
public class GameView extends Pane {
|
public class GameView extends Pane {
|
||||||
|
|
||||||
private ObservableList<Node> gameObjects;
|
|
||||||
private ImageView mapImage;
|
|
||||||
|
|
||||||
private double bufferSize = 50;
|
private double bufferSize = 50;
|
||||||
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
||||||
private double panelHeight = 960;
|
private double panelHeight = 960;
|
||||||
@@ -52,23 +47,25 @@ public class GameView extends Pane {
|
|||||||
|
|
||||||
private double distanceScaleFactor;
|
private double distanceScaleFactor;
|
||||||
private ScaleDirection scaleDirection;
|
private ScaleDirection scaleDirection;
|
||||||
private Mark minLatPoint;
|
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
|
||||||
private Mark minLonPoint;
|
private double referencePointX, referencePointY;
|
||||||
private Mark maxLatPoint;
|
private double metersPerPixelX, metersPerPixelY;
|
||||||
private Mark maxLonPoint;
|
|
||||||
private double referencePointX;
|
private Text fpsDisplay = new Text();
|
||||||
private double referencePointY;
|
private Polygon raceBorder = new Polygon();
|
||||||
private double metersPerPixelX;
|
|
||||||
private double metersPerPixelY;
|
/* Note that if either of these is null then values for it have not been added and the other
|
||||||
|
should be used as the limits of the map. */
|
||||||
|
private List<Limit> borderPoints;
|
||||||
|
private List<CompoundMark> course;
|
||||||
|
private Map<Mark, Marker> markerObjects;
|
||||||
|
|
||||||
private Map<Yacht, BoatObject> boatObjects = new HashMap<>();
|
private Map<Yacht, BoatObject> boatObjects = new HashMap<>();
|
||||||
private List<AnnotationBox> annotations = new ArrayList<>();
|
private List<AnnotationBox> annotations = new ArrayList<>();
|
||||||
|
private List<Integer> markSequence;
|
||||||
|
private ObservableList<Node> gameObjects;
|
||||||
|
|
||||||
private Text fpsDisplay = new Text();
|
private ImageView mapImage = new ImageView();
|
||||||
/* Note that if either of these is null then values for it have not been added and the other
|
|
||||||
should be used as the limits of the map. */
|
|
||||||
private Polygon raceBorder;
|
|
||||||
private Map<SingleMark, MarkObject> markObjects = new HashMap<>();
|
|
||||||
|
|
||||||
//FRAME RATE
|
//FRAME RATE
|
||||||
private Double frameRate = 60.0;
|
private Double frameRate = 60.0;
|
||||||
@@ -86,11 +83,24 @@ public class GameView extends Pane {
|
|||||||
public GameView () {
|
public GameView () {
|
||||||
gameObjects = this.getChildren();
|
gameObjects = this.getChildren();
|
||||||
// create image view for map, bind panel size to image
|
// create image view for map, bind panel size to image
|
||||||
mapImage = new ImageView();
|
|
||||||
gameObjects.add(mapImage);
|
|
||||||
mapImage.fitWidthProperty().bind(this.widthProperty());
|
mapImage.fitWidthProperty().bind(this.widthProperty());
|
||||||
mapImage.fitHeightProperty().bind(this.heightProperty());
|
mapImage.fitHeightProperty().bind(this.heightProperty());
|
||||||
|
gameObjects.add(mapImage);
|
||||||
|
fpsDisplay.setLayoutX(5);
|
||||||
|
fpsDisplay.setLayoutY(20);
|
||||||
|
fpsDisplay.setStrokeWidth(2);
|
||||||
|
gameObjects.add(fpsDisplay);
|
||||||
|
gameObjects.add(raceBorder);
|
||||||
initializeTimer();
|
initializeTimer();
|
||||||
|
this.widthProperty().addListener(resize -> {
|
||||||
|
canvasWidth = this.getWidth();
|
||||||
|
canvasHeight = this.getHeight();
|
||||||
|
if (borderPoints != null) {
|
||||||
|
updateBorder(borderPoints);
|
||||||
|
} else if (course != null) {
|
||||||
|
updateCourse(course, markSequence);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer () {
|
private void initializeTimer () {
|
||||||
@@ -120,7 +130,7 @@ public class GameView extends Pane {
|
|||||||
drawFps(frameRate.intValue());
|
drawFps(frameRate.intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateGroups();
|
boatObjects.forEach((boat, boatObject) -> {});
|
||||||
lastTime = now;
|
lastTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,45 +138,13 @@ public class GameView extends Pane {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeCanvas() {
|
|
||||||
drawGoogleMap();
|
|
||||||
fpsDisplay.setLayoutX(5);
|
|
||||||
fpsDisplay.setLayoutY(20);
|
|
||||||
fpsDisplay.setStrokeWidth(2);
|
|
||||||
gameObjects.add(fpsDisplay);
|
|
||||||
gameObjects.add(raceBorder);
|
|
||||||
|
|
||||||
this.widthProperty().addListener(resize -> {
|
|
||||||
canvasWidth = this.getWidth();
|
|
||||||
canvasHeight = this.getHeight();
|
|
||||||
fitMarksToCanvas();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void switchToFinishScreen() {
|
|
||||||
try {
|
|
||||||
// canvas view -> anchor pane -> grid pane -> main view
|
|
||||||
GridPane gridPane = (GridPane) this.getParent().getParent();
|
|
||||||
AnchorPane contentPane = (AnchorPane) gridPane.getParent();
|
|
||||||
contentPane.getChildren().removeAll();
|
|
||||||
contentPane.getChildren().clear();
|
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
contentPane.getChildren().addAll(
|
|
||||||
(Pane) FXMLLoader.load(getClass().getResource("/views/FinishScreenView.fxml")));
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
|
||||||
System.out.println("[Controller] FXML load exception");
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("[Controller] IO exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First find the top right and bottom left points' geo locations, then retrieve
|
* First find the top right and bottom left points' geo locations, then retrieve
|
||||||
* map from google to display on image view. - Haoming 22/5/2017
|
* map from google to display on image view. - Haoming 22/5/2017
|
||||||
*/
|
*/
|
||||||
private void drawGoogleMap() {
|
private void drawGoogleMap() {
|
||||||
findMetersPerPixel();
|
findMetersPerPixel();
|
||||||
Point2D topLeftPoint = findScaledXY(maxLatPoint.getLatitude(), minLonPoint.getLongitude());
|
Point2D topLeftPoint = findScaledXY(maxLatPoint.getLat(), minLonPoint.getLng());
|
||||||
// distance from top left extreme to panel origin (top left corner)
|
// distance from top left extreme to panel origin (top left corner)
|
||||||
double distanceFromTopLeftToOrigin = Math.sqrt(
|
double distanceFromTopLeftToOrigin = Math.sqrt(
|
||||||
Math.pow(topLeftPoint.getX() * metersPerPixelX, 2) + Math
|
Math.pow(topLeftPoint.getX() * metersPerPixelX, 2) + Math
|
||||||
@@ -175,7 +153,7 @@ public class GameView extends Pane {
|
|||||||
double bearingFromTopLeftToOrigin = Math
|
double bearingFromTopLeftToOrigin = Math
|
||||||
.toDegrees(Math.atan2(-topLeftPoint.getX(), topLeftPoint.getY()));
|
.toDegrees(Math.atan2(-topLeftPoint.getX(), topLeftPoint.getY()));
|
||||||
// the top left extreme
|
// the top left extreme
|
||||||
GeoPoint topLeftPos = new GeoPoint(maxLatPoint.getLatitude(), minLonPoint.getLongitude());
|
GeoPoint topLeftPos = new GeoPoint(maxLatPoint.getLat(), minLonPoint.getLng());
|
||||||
GeoPoint originPos = GeoUtility
|
GeoPoint originPos = GeoUtility
|
||||||
.getGeoCoordinate(topLeftPos, bearingFromTopLeftToOrigin, distanceFromTopLeftToOrigin);
|
.getGeoCoordinate(topLeftPos, bearingFromTopLeftToOrigin, distanceFromTopLeftToOrigin);
|
||||||
|
|
||||||
@@ -196,20 +174,103 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds border marks to the canvas, taken from the XML file
|
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
|
||||||
|
* case the course is added relative ot the border.
|
||||||
*
|
*
|
||||||
* NOTE: This is quite confusing as objects are grabbed from the XMLParser such as Mark and
|
* @param newCourse the mark objects that make up the course.
|
||||||
* CompoundMark which are named the same as those in the model package but are, however not the
|
*/
|
||||||
* same, so they do not have things such as a type and must be derived from the number of marks
|
public void updateCourse(List<CompoundMark> newCourse, List<Integer> sequence) {
|
||||||
* in a compound mark etc..
|
course = newCourse;
|
||||||
|
this.markSequence = sequence;
|
||||||
|
markerObjects = new HashMap<>();
|
||||||
|
Paint colour = Color.BLACK;
|
||||||
|
//Creates new markers
|
||||||
|
for (CompoundMark cMark : course) {
|
||||||
|
//Set start and end colour
|
||||||
|
if (cMark.getId() == sequence.get(0)) {
|
||||||
|
colour = Color.GREEN;
|
||||||
|
} else if (cMark.getId() == sequence.get(sequence.size() - 1)) {
|
||||||
|
colour = Color.RED;
|
||||||
|
}
|
||||||
|
//Create mark dots
|
||||||
|
for (Mark mark : cMark.getMarks()) {
|
||||||
|
makeAndBindMarker(mark, colour);
|
||||||
|
}
|
||||||
|
//Create gate line
|
||||||
|
if (cMark.isGate()) {
|
||||||
|
for (int i = 0; i < cMark.getMarks().size()-1; i++) {
|
||||||
|
makeAndBindGate(
|
||||||
|
markerObjects.get(cMark.getSubMark(i)),
|
||||||
|
markerObjects.get(cMark.getSubMark(i+1)),
|
||||||
|
colour
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colour = Color.BLACK;
|
||||||
|
}
|
||||||
|
//Set X,Y co-ordinates
|
||||||
|
if (borderPoints == null) {
|
||||||
|
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
||||||
|
} else {
|
||||||
|
rescaleRace(new ArrayList<>(borderPoints));
|
||||||
|
}
|
||||||
|
//Move the Markers to initial position.
|
||||||
|
markerObjects.forEach(((mark, marker) -> {
|
||||||
|
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
||||||
|
marker.setCenterX(p2d.getX());
|
||||||
|
marker.setCenterY(p2d.getY());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Marker and binds it's position to the given Mark.
|
||||||
|
*
|
||||||
|
* @param observableMark The mark to bind the marker to.
|
||||||
|
* @param colour The desired colour of the mark
|
||||||
|
*/
|
||||||
|
private void makeAndBindMarker(Mark observableMark, Paint colour) {
|
||||||
|
Marker marker = new Marker(colour);
|
||||||
|
markerObjects.put(observableMark, marker);
|
||||||
|
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||||
|
Point2D p2d = findScaledXY(lat, lon);
|
||||||
|
markerObjects.get(mark).setCenterX(p2d.getX());
|
||||||
|
markerObjects.get(mark).setCenterY(p2d.getY());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new gate connecting the given marks.
|
||||||
|
*
|
||||||
|
* @param m1 The first Mark of the gate.
|
||||||
|
* @param m2 The second Mark of the gate.
|
||||||
|
* @param colour The desired colour of the gate.
|
||||||
|
*/
|
||||||
|
private void makeAndBindGate(Marker m1, Marker m2, Paint colour) {
|
||||||
|
Gate gate = new Gate(colour);
|
||||||
|
gate.startXProperty().bind(
|
||||||
|
m1.centerXProperty()
|
||||||
|
);
|
||||||
|
gate.startYProperty().bind(
|
||||||
|
m1.centerYProperty()
|
||||||
|
);
|
||||||
|
gate.endXProperty().bind(
|
||||||
|
m2.centerXProperty()
|
||||||
|
);
|
||||||
|
gate.endYProperty().bind(
|
||||||
|
m2.centerYProperty()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
|
||||||
|
* border already exists. Assumes the border is larger than the course.
|
||||||
|
*
|
||||||
|
* @param border the race border to be drawn.
|
||||||
*/
|
*/
|
||||||
public void updateBorder(List<Limit> border) {
|
public void updateBorder(List<Limit> border) {
|
||||||
if (raceBorder == null) {
|
if (borderPoints == null) {
|
||||||
raceBorder = new Polygon();
|
borderPoints = border;
|
||||||
raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1));
|
rescaleRace(new ArrayList<>(borderPoints));
|
||||||
raceBorder.setStrokeWidth(3);
|
|
||||||
raceBorder.setFill(new Color(0,0,0,0));
|
|
||||||
findCanvasScaling();
|
|
||||||
}
|
}
|
||||||
List<Double> boundaryPoints = new ArrayList<>();
|
List<Double> boundaryPoints = new ArrayList<>();
|
||||||
for (Limit limit : border) {
|
for (Limit limit : border) {
|
||||||
@@ -220,42 +281,19 @@ public class GameView extends Pane {
|
|||||||
raceBorder.getPoints().setAll(boundaryPoints);
|
raceBorder.getPoints().setAll(boundaryPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGroups() {
|
/**
|
||||||
boatObjects.forEach((boat, boatObject) -> {});
|
* Rescales the race to the size of the window.
|
||||||
markObjects.forEach((mark, markObject) -> {});
|
*
|
||||||
|
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
||||||
|
*/
|
||||||
|
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
||||||
|
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||||
|
findMinMaxPoint(limitingCoordinates);
|
||||||
|
double minLonToMaxLon = scaleRaceExtremities();
|
||||||
|
calculateReferencePointLocation(minLonToMaxLon);
|
||||||
|
drawGoogleMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void updateBoatGroup(BoatGroup boatGroup) {
|
|
||||||
//// PriorityBlockingQueue<PositionUpdateData> movementQueue = StreamParser.boatLocations.get(boatGroup.getRaceId());
|
|
||||||
//// // giving the movementQueue a 5 packet buffer to account for slightly out of order packets
|
|
||||||
//// if (movementQueue.size() > 0) {
|
|
||||||
//// try {
|
|
||||||
//// PositionUpdateData positionPacket = movementQueue.take();
|
|
||||||
// Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
|
|
||||||
//// double heading = 360.0 / 0xffff * positionPacket.getHeading();
|
|
||||||
// boatGroup.setDestination(
|
|
||||||
// p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(),
|
|
||||||
// positionPacket.getTimeValid(), frameRate);
|
|
||||||
//// } catch (InterruptedException e){
|
|
||||||
//// e.printStackTrace();
|
|
||||||
//// }
|
|
||||||
////// }
|
|
||||||
//// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void updateMarkGroup (long raceId, MarkGroup markGroup) {
|
|
||||||
// PriorityBlockingQueue<PositionUpdateData> movementQueue = StreamParser.markLocations.get(raceId);
|
|
||||||
// if (movementQueue.size() > 0){
|
|
||||||
// try {
|
|
||||||
// PositionUpdateData positionPacket = movementQueue.take();
|
|
||||||
// Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
|
|
||||||
// markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId);
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws all the boats.
|
* Draws all the boats.
|
||||||
*/
|
*/
|
||||||
@@ -320,65 +358,27 @@ public class GameView extends Pane {
|
|||||||
return newAnnotation;
|
return newAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCourse(List<Mark> course) {
|
|
||||||
for (Mark mark : course) {
|
|
||||||
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
|
||||||
SingleMark sMark = (SingleMark) mark;
|
|
||||||
|
|
||||||
MarkObject markObject = new MarkObject(sMark, findScaledXY(sMark));
|
|
||||||
markObjects.put(sMark, markObject);
|
|
||||||
} else {
|
|
||||||
GateMark gMark = (GateMark) mark;
|
|
||||||
|
|
||||||
MarkObject markObject = new MarkObject(gMark, findScaledXY(gMark.getSingleMark1()),
|
|
||||||
findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list.
|
|
||||||
// markObjects.put(markObject.);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// gameObjects.addAll(markObjects);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawFps(int fps){
|
private void drawFps(int fps){
|
||||||
fpsDisplay.setText(String.format("%d FPS", fps));
|
fpsDisplay.setText(String.format("%d FPS", fps));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates x and y location for every marker that fits it to the canvas the race will be
|
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point
|
||||||
* drawn on.
|
* with the leftmost point, rightmost point, southern most point and northern most point
|
||||||
*/
|
|
||||||
private void fitMarksToCanvas() {
|
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
|
||||||
findMinMaxPoint();
|
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
|
||||||
//givePointsXY();
|
|
||||||
// updateBorder();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the marker
|
|
||||||
* with the leftmost marker, rightmost marker, southern most marker and northern most marker
|
|
||||||
* respectively.
|
* respectively.
|
||||||
*/
|
*/
|
||||||
private void findMinMaxPoint() {
|
private void findMinMaxPoint(List<GeoPoint> points) {
|
||||||
List<Limit> sortedPoints = new ArrayList<>();
|
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
||||||
// for (Limit limit : ) {
|
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||||
// sortedPoints.add(limit);
|
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||||
// }
|
GeoPoint maxLat = sortedPoints.get(sortedPoints.size()-1);
|
||||||
sortedPoints.sort(Comparator.comparingDouble(Limit::getLat));
|
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
||||||
Limit minLatMark = sortedPoints.get(0);
|
|
||||||
Limit maxLatMark = sortedPoints.get(sortedPoints.size()-1);
|
|
||||||
minLatPoint = new SingleMark(minLatMark.toString(), minLatMark.getLat(), minLatMark.getLng(), minLatMark.getSeqID(), minLatMark.getSeqID());
|
|
||||||
maxLatPoint = new SingleMark(maxLatMark.toString(), maxLatMark.getLat(), maxLatMark.getLng(), maxLatMark.getSeqID(), minLatMark.getSeqID());
|
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(Limit::getLng));
|
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||||
//If the course is on a point on the earth where longitudes wrap around.
|
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||||
Limit minLonMark = sortedPoints.get(0);
|
GeoPoint maxLon = sortedPoints.get(sortedPoints.size()-1);
|
||||||
Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1);
|
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
||||||
minLonPoint = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID(), minLonMark.getSeqID());
|
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
||||||
maxLonPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID(), minLonMark.getSeqID());
|
|
||||||
if (maxLonPoint.getLongitude() - minLonPoint.getLongitude() > 180) {
|
|
||||||
horizontalInversion = true;
|
horizontalInversion = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,25 +391,29 @@ public class GameView extends Pane {
|
|||||||
* maximum longitude.
|
* maximum longitude.
|
||||||
*/
|
*/
|
||||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
||||||
Mark referencePoint = minLatPoint;
|
GeoPoint referencePoint = minLatPoint;
|
||||||
double referenceAngle;
|
double referenceAngle;
|
||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
referenceAngle = Math.abs(
|
||||||
referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
||||||
|
);
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, maxLatPoint));
|
referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
||||||
|
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
||||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
||||||
referencePointY = referencePointY / 2;
|
referencePointY = referencePointY / 2;
|
||||||
referencePointY += bufferSize;
|
referencePointY += bufferSize;
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
||||||
} else {
|
} else {
|
||||||
referencePointY = canvasHeight - bufferSize;
|
referencePointY = canvasHeight - bufferSize;
|
||||||
|
referenceAngle = Math.abs(
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
Math.toRadians(
|
||||||
|
GeoUtility.getDistance(referencePoint, minLonPoint)
|
||||||
|
)
|
||||||
|
);
|
||||||
referencePointX = bufferSize;
|
referencePointX = bufferSize;
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
||||||
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
||||||
}
|
}
|
||||||
if(horizontalInversion) {
|
if(horizontalInversion) {
|
||||||
@@ -424,18 +428,21 @@ public class GameView extends Pane {
|
|||||||
*/
|
*/
|
||||||
private double scaleRaceExtremities() {
|
private double scaleRaceExtremities() {
|
||||||
|
|
||||||
double vertAngle = Math.abs(Mark.calculateHeadingRad(minLatPoint, maxLatPoint));
|
double vertAngle = Math.abs(
|
||||||
|
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
||||||
|
);
|
||||||
double vertDistance =
|
double vertDistance =
|
||||||
Math.cos(vertAngle) * Mark.calculateDistance(minLatPoint, maxLatPoint);
|
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
||||||
double horiAngle = Mark.calculateHeadingRad(minLonPoint, maxLonPoint);
|
double horiAngle = Math.abs(
|
||||||
|
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
||||||
|
);
|
||||||
if (horiAngle <= (Math.PI / 2)) {
|
if (horiAngle <= (Math.PI / 2)) {
|
||||||
horiAngle = (Math.PI / 2) - horiAngle;
|
horiAngle = (Math.PI / 2) - horiAngle;
|
||||||
} else {
|
} else {
|
||||||
horiAngle = horiAngle - (Math.PI / 2);
|
horiAngle = horiAngle - (Math.PI / 2);
|
||||||
}
|
}
|
||||||
double horiDistance =
|
double horiDistance =
|
||||||
Math.cos(horiAngle) * Mark.calculateDistance(minLonPoint, maxLonPoint);
|
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
||||||
|
|
||||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
||||||
|
|
||||||
@@ -449,22 +456,22 @@ public class GameView extends Pane {
|
|||||||
return horiDistance;
|
return horiDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Point2D findScaledXY(Mark unscaled) {
|
private Point2D findScaledXY(GeoPoint unscaled) {
|
||||||
return findScaledXY(unscaled.getLatitude(), unscaled.getLongitude());
|
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point2D findScaledXY (double unscaledLat, double unscaledLon) {
|
private Point2D findScaledXY (double unscaledLat, double unscaledLon) {
|
||||||
double distanceFromReference;
|
double distanceFromReference;
|
||||||
double angleFromReference;
|
double angleFromReference;
|
||||||
double xAxisLocation = referencePointX;
|
double xAxisLocation = referencePointX;
|
||||||
double yAxisLocation = referencePointY;
|
double yAxisLocation = referencePointY;
|
||||||
|
|
||||||
angleFromReference = Mark
|
angleFromReference = GeoUtility.getBearingRad(
|
||||||
.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat,
|
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
unscaledLon);
|
);
|
||||||
distanceFromReference = Mark
|
distanceFromReference = GeoUtility.getDistance(
|
||||||
.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat,
|
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
unscaledLon);
|
);
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
@@ -492,14 +499,14 @@ public class GameView extends Pane {
|
|||||||
*/
|
*/
|
||||||
private void findMetersPerPixel() {
|
private void findMetersPerPixel() {
|
||||||
Point2D p1, p2;
|
Point2D p1, p2;
|
||||||
Mark m1, m2;
|
GeoPoint g1, g2;
|
||||||
double theta, distance, dx, dy, dHorizontal, dVertical;
|
double theta, distance, dx, dy, dHorizontal, dVertical;
|
||||||
m1 = new SingleMark("m1", maxLatPoint.getLatitude(), minLonPoint.getLongitude(), 1, 0);
|
g1 = new GeoPoint(maxLatPoint.getLat(), minLonPoint.getLng());
|
||||||
m2 = new SingleMark("m2", minLatPoint.getLatitude(), maxLonPoint.getLongitude(), 2, 0);
|
g2 = new GeoPoint(minLatPoint.getLat(), maxLatPoint.getLng());
|
||||||
p1 = findScaledXY(m1);
|
p1 = findScaledXY(new GeoPoint(maxLatPoint.getLat(), minLonPoint.getLng()));
|
||||||
p2 = findScaledXY(m2);
|
p2 = findScaledXY(new GeoPoint(minLatPoint.getLat(), maxLatPoint.getLng()));
|
||||||
theta = Mark.calculateHeadingRad(m1, m2);
|
theta = GeoUtility.getBearingRad(g1, g2);
|
||||||
distance = Mark.calculateDistance(m1, m2);
|
distance = GeoUtility.getDistance(g1, g2);
|
||||||
dHorizontal = Math.abs(Math.sin(theta) * distance);
|
dHorizontal = Math.abs(Math.sin(theta) * distance);
|
||||||
dVertical = Math.abs(Math.cos(theta) * distance);
|
dVertical = Math.abs(Math.cos(theta) * distance);
|
||||||
dx = Math.abs(p1.getX() - p2.getX());
|
dx = Math.abs(p1.getX() - p2.getX());
|
||||||
|
|||||||
@@ -344,4 +344,6 @@ public class BoatObject extends Group {
|
|||||||
// boatAnnotations.setAsPlayer();
|
// boatAnnotations.setAsPlayer();
|
||||||
// isPlayer = true;
|
// isPlayer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateTrajectory(heading, velocity, scaleFactor)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package seng302.visualiser.fxObjects;
|
||||||
|
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polygon with default course border settings.
|
||||||
|
*/
|
||||||
|
public class CourseBorder extends Polygon {
|
||||||
|
public CourseBorder() {
|
||||||
|
this.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1));
|
||||||
|
this.setStrokeWidth(3);
|
||||||
|
this.setFill(new Color(0,0,0,0));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package seng302.visualiser.fxObjects;
|
||||||
|
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visual object representing a gate, intended to connect two mark objects.
|
||||||
|
*/
|
||||||
|
public class Gate extends Line {
|
||||||
|
|
||||||
|
public Gate () {
|
||||||
|
super.setStrokeWidth(2);
|
||||||
|
super.getStrokeDashArray().setAll(2d, 5d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gate (Paint colour) {
|
||||||
|
this();
|
||||||
|
super.setStroke(colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package seng302.visualiser.fxObjects;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.Group;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.shape.Circle;
|
|
||||||
import javafx.scene.shape.Line;
|
|
||||||
import seng302.model.mark.GateMark;
|
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.model.mark.MarkType;
|
|
||||||
import seng302.model.mark.SingleMark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grouping of javaFX objects needed to represent a Mark on screen.
|
|
||||||
*/
|
|
||||||
public class MarkObject extends Group {
|
|
||||||
|
|
||||||
private static int MARK_RADIUS = 5;
|
|
||||||
private static int LINE_THICKNESS = 2;
|
|
||||||
private static double DASHED_GAP_LEN = 2d;
|
|
||||||
private static double DASHED_LINE_LEN = 5d;
|
|
||||||
|
|
||||||
private List<Mark> marks = new ArrayList<>();
|
|
||||||
private Mark mainMark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for singleMark groups
|
|
||||||
* @param mark
|
|
||||||
* @param points
|
|
||||||
*/
|
|
||||||
public MarkObject(SingleMark mark, Point2D points) {
|
|
||||||
marks.add(mark);
|
|
||||||
mainMark = mark;
|
|
||||||
Color color = Color.BLACK;
|
|
||||||
if (mark.getName().equals("Start")){
|
|
||||||
color = Color.GREEN;
|
|
||||||
} else if (mark.getName().equals("Finish")){
|
|
||||||
color = Color.RED;
|
|
||||||
}
|
|
||||||
Circle markCircle;
|
|
||||||
markCircle = new Circle(
|
|
||||||
points.getX(),
|
|
||||||
points.getY(),
|
|
||||||
MARK_RADIUS,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
super.getChildren().add(markCircle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addLaylines(Line line1, Line line2) {
|
|
||||||
|
|
||||||
super.getChildren().addAll(line1, line2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void removeLaylines() {
|
|
||||||
ArrayList<Node> toRemove = new ArrayList<>();
|
|
||||||
for(Node node : super.getChildren()) {
|
|
||||||
if (node instanceof Line) {
|
|
||||||
Line layLine = (Line) node;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* OOHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHhhh
|
|
||||||
*/
|
|
||||||
if (layLine.getStrokeWidth() == 0.5){
|
|
||||||
toRemove.add(layLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.getChildren().removeAll(toRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MarkObject(GateMark mark, Point2D points1, Point2D points2) {
|
|
||||||
marks.add(mark.getSingleMark1());
|
|
||||||
marks.add(mark.getSingleMark2());
|
|
||||||
mainMark = mark;
|
|
||||||
Color color = Color.BLACK;
|
|
||||||
if (mark.getName().equals("Start")){
|
|
||||||
color = Color.GREEN;
|
|
||||||
} else if (mark.getName().equals("Finish")){
|
|
||||||
color = Color.RED;
|
|
||||||
}
|
|
||||||
Circle markCircle;
|
|
||||||
markCircle = new Circle(
|
|
||||||
points1.getX(),
|
|
||||||
points1.getY(),
|
|
||||||
MARK_RADIUS,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
super.getChildren().add(markCircle);
|
|
||||||
|
|
||||||
markCircle = new Circle(
|
|
||||||
points2.getX(),
|
|
||||||
points2.getY(),
|
|
||||||
MARK_RADIUS,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
super.getChildren().add(markCircle);
|
|
||||||
Line line = new Line(
|
|
||||||
points1.getX(),
|
|
||||||
points1.getY(),
|
|
||||||
points2.getX(),
|
|
||||||
points2.getY()
|
|
||||||
);
|
|
||||||
line.setStrokeWidth(LINE_THICKNESS);
|
|
||||||
line.setStroke(color);
|
|
||||||
if (mark.getMarkType() == MarkType.OPEN_GATE) {
|
|
||||||
line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN);
|
|
||||||
}
|
|
||||||
super.getChildren().add(line);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void moveMarkTo (double x, double y, long raceId)
|
|
||||||
{
|
|
||||||
if (mainMark.getMarkType() == MarkType.SINGLE_MARK) {
|
|
||||||
Circle markCircle = (Circle) super.getChildren().get(0);
|
|
||||||
//One of the test streams produced frequent, jittery movements. Added this as a fix.
|
|
||||||
if (Math.abs(markCircle.getCenterX() - x) > 5 || Math.abs(markCircle.getCenterY() - y) > 5) {
|
|
||||||
markCircle.setCenterX(x);
|
|
||||||
markCircle.setCenterY(y);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Circle markCircle1 = (Circle) super.getChildren().get(0);
|
|
||||||
Circle markCircle2 = (Circle) super.getChildren().get(1);
|
|
||||||
Line connectingLine = (Line) super.getChildren().get(2);
|
|
||||||
if (marks.get(0).getId() == raceId) {
|
|
||||||
if (Math.abs(markCircle1.getCenterX() - x) > 5 || Math.abs(markCircle1.getCenterY() - y) > 5) {
|
|
||||||
markCircle1.setCenterX(x);
|
|
||||||
markCircle1.setCenterY(y);
|
|
||||||
connectingLine.setStartX(markCircle1.getCenterX());
|
|
||||||
connectingLine.setStartY(markCircle1.getCenterY());
|
|
||||||
}
|
|
||||||
} else if (marks.get(1).getId() == raceId) {
|
|
||||||
if (Math.abs(markCircle2.getCenterX() - x) > 5 || Math.abs(markCircle2.getCenterY() - y) > 5) {
|
|
||||||
markCircle2.setCenterX(x);
|
|
||||||
markCircle2.setCenterY(y);
|
|
||||||
connectingLine.setEndX(markCircle2.getCenterX());
|
|
||||||
connectingLine.setEndY(markCircle2.getCenterY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasRaceId (int... raceIds) {
|
|
||||||
for (int id : raceIds)
|
|
||||||
for (Mark mark : marks)
|
|
||||||
if (id == mark.getId())
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long[] getRaceIds () {
|
|
||||||
long[] idArray = new long[marks.size()];
|
|
||||||
int i = 0;
|
|
||||||
for (Mark mark : marks)
|
|
||||||
idArray[i++] = mark.getId();
|
|
||||||
return idArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark getMainMark() {
|
|
||||||
return mainMark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package seng302.visualiser.fxObjects;
|
||||||
|
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visual object for a mark.
|
||||||
|
*/
|
||||||
|
public class Marker extends Circle {
|
||||||
|
|
||||||
|
public Marker() {
|
||||||
|
super.setRadius(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Marker(Paint colour) {
|
||||||
|
this();
|
||||||
|
super.setFill(colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,11 +7,11 @@ package seng302.visualiser.map;
|
|||||||
*
|
*
|
||||||
* Created by Haoming on 10/5/17
|
* Created by Haoming on 10/5/17
|
||||||
*/
|
*/
|
||||||
class Boundary {
|
public class Boundary {
|
||||||
|
|
||||||
private double northLat, eastLng, southLat, westLng;
|
private double northLat, eastLng, southLat, westLng;
|
||||||
|
|
||||||
Boundary(double northLat, double eastLng, double southLat, double westLng) {
|
public Boundary(double northLat, double eastLng, double southLat, double westLng) {
|
||||||
this.northLat = northLat;
|
this.northLat = northLat;
|
||||||
this.eastLng = eastLng;
|
this.eastLng = eastLng;
|
||||||
this.southLat = southLat;
|
this.southLat = southLat;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import java.net.URL;
|
|||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
|
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
|
||||||
@@ -22,12 +22,12 @@ public class CanvasMap {
|
|||||||
|
|
||||||
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
|
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
|
||||||
|
|
||||||
CanvasMap(Boundary boundary) {
|
public CanvasMap(Boundary boundary) {
|
||||||
this.boundary = boundary;
|
this.boundary = boundary;
|
||||||
calculateOptimalMapSize();
|
calculateOptimalMapSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Image getMapImage() {
|
public Image getMapImage() {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(getRequest());
|
URL url = new URL(getRequest());
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package seng302.visualiser.map;
|
package seng302.visualiser.map;
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An utility class useful to convert between Geo locations and Mercator projection
|
* An utility class useful to convert between Geo locations and Mercator projection
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import java.util.List;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
import seng302.model.Yacht;
|
import seng302.model.Yacht;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
public class YachtTest {
|
public class YachtTest {
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package seng302.server.simulator;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package seng302.visualiser.map;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.utilities.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for Mercator Project class.
|
* Unit test for Mercator Project class.
|
||||||
|
|||||||
Reference in New Issue
Block a user