Commit 513c0341c54e1d2ef6dbd1eeb624830faab35ad7
1 parent
07bf03cd80
Exists in
master
and in
1 other branch
add chart
Showing 11 changed files with 670 additions and 55 deletions Side-by-side Diff
- src/main/kotlin/application/VisualisationChart.kt
- src/main/kotlin/application/controller/DataPanelController.kt
- src/main/kotlin/application/controller/VesselListPanelController.kt
- src/main/kotlin/application/model/Message.kt
- src/main/kotlin/application/model/MessageData.kt
- src/main/kotlin/application/model/Vessel.kt
- src/main/kotlin/application/model/VesselGenerator.kt
- src/main/kotlin/map/MapDisplayer.kt
- src/main/resources/gui/dataPanel.fxml
- src/main/resources/gui/vesselListPanel.fxml
- src/main/resources/gui/windows.fxml
src/main/kotlin/application/VisualisationChart.kt
View file @
513c034
src/main/kotlin/application/controller/DataPanelController.kt
View file @
513c034
| 1 | +package application.controller | |
| 2 | + | |
| 3 | +import application.model.* | |
| 4 | +import javafx.collections.FXCollections | |
| 5 | +import javafx.collections.ObservableList | |
| 6 | +import javafx.fxml.FXML | |
| 7 | +import javafx.fxml.Initializable | |
| 8 | +import javafx.scene.chart.CategoryAxis | |
| 9 | +import javafx.scene.chart.NumberAxis | |
| 10 | +import javafx.scene.chart.ScatterChart | |
| 11 | +import javafx.scene.chart.XYChart.Data | |
| 12 | +import javafx.scene.chart.XYChart.Series | |
| 13 | +import javafx.scene.control.ListCell | |
| 14 | +import javafx.scene.control.ListView | |
| 15 | +import java.net.URL | |
| 16 | +import java.util.* | |
| 17 | + | |
| 18 | + | |
| 19 | +class DataPanelController : Initializable, SelectedVesselListener { | |
| 20 | + private var dataList: ObservableList<Pair<String, ArrayList<MessageData?>>> = FXCollections.observableArrayList() | |
| 21 | + private lateinit var timeData: ArrayList<MessageData?> | |
| 22 | + | |
| 23 | + @FXML | |
| 24 | + var dataListView = ListView<Pair<String, ArrayList<MessageData?>>>() | |
| 25 | + | |
| 26 | + @FXML | |
| 27 | + var xaxisNumber: CategoryAxis = CategoryAxis() | |
| 28 | + | |
| 29 | + @FXML | |
| 30 | + var yaxisNumber: NumberAxis = NumberAxis() | |
| 31 | + | |
| 32 | + @FXML | |
| 33 | + lateinit var scatterChartNumber: ScatterChart<String, Number> | |
| 34 | + | |
| 35 | + @FXML | |
| 36 | + var xaxisCategory: CategoryAxis = CategoryAxis() | |
| 37 | + | |
| 38 | + @FXML | |
| 39 | + var yaxisCategory: CategoryAxis = CategoryAxis() | |
| 40 | + | |
| 41 | + @FXML | |
| 42 | + lateinit var scatterChartCategory: ScatterChart<String, String> | |
| 43 | + | |
| 44 | + override fun initialize(location: URL?, resources: ResourceBundle?) { | |
| 45 | + xaxisNumber.animated = false | |
| 46 | + yaxisNumber.animated = false | |
| 47 | + xaxisCategory.animated = false | |
| 48 | + yaxisCategory.animated = false | |
| 49 | + setObservableSelectedVesselListener() | |
| 50 | + dataListView.items = dataList | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + dataListView.setCellFactory { | |
| 55 | + object : ListCell<Pair<String, ArrayList<MessageData?>>?>() { | |
| 56 | + override fun updateItem(item: Pair<String, ArrayList<MessageData?>>?, empty: Boolean) { | |
| 57 | + super.updateItem(item, empty) | |
| 58 | + text = if (empty) { | |
| 59 | + null | |
| 60 | + } else { | |
| 61 | + item?.first | |
| 62 | + } | |
| 63 | + } | |
| 64 | + } | |
| 65 | + } | |
| 66 | + | |
| 67 | + dataListView.selectionModel.selectedItemProperty().addListener { _, _, newValue -> | |
| 68 | + if (newValue == null){ | |
| 69 | + scatterChartCategory.data.clear() | |
| 70 | + scatterChartNumber.data.clear() | |
| 71 | + return@addListener | |
| 72 | + } | |
| 73 | + val serieNumber = Series<String, Number>() | |
| 74 | + val serieString = Series<String, String>() | |
| 75 | + | |
| 76 | + val getValueVisitorX = GetValueVisitor() | |
| 77 | + val getValueVisitorY = GetValueVisitor() | |
| 78 | + | |
| 79 | + | |
| 80 | + for (x in 0 until newValue?.second?.size!!) { | |
| 81 | + timeData[x]?.accept(getValueVisitorX) | |
| 82 | + newValue.second[x]?.accept(getValueVisitorY) | |
| 83 | + | |
| 84 | + if (getValueVisitorY.value.toDoubleOrNull() == null){ | |
| 85 | + serieString.data.add(Data<String, String>(getValueVisitorX.value, getValueVisitorY.value)) | |
| 86 | + } else{ | |
| 87 | + serieNumber.data.add(Data<String, Number>(getValueVisitorX.value, getValueVisitorY.value.toDouble())) | |
| 88 | + } | |
| 89 | + | |
| 90 | + } | |
| 91 | + | |
| 92 | + scatterChartNumber.data.clear() | |
| 93 | + scatterChartCategory.data.clear() | |
| 94 | + | |
| 95 | + if (getValueVisitorY.value.toDoubleOrNull() == null){ | |
| 96 | + serieString.data.add(Data<String, String>(getValueVisitorX.value, getValueVisitorY.value)) | |
| 97 | + scatterChartCategory.data.addAll(serieString) | |
| 98 | + setChartCategoryVisible() | |
| 99 | + xaxisCategory.label = "Date" | |
| 100 | + yaxisCategory.label = newValue.first | |
| 101 | + } else{ | |
| 102 | + serieNumber.data.add(Data<String, Number>(getValueVisitorX.value, getValueVisitorY.value.toDouble())) | |
| 103 | + scatterChartNumber.data.addAll(serieNumber) | |
| 104 | + setChartNumberVisible() | |
| 105 | + xaxisNumber.label = "Date" | |
| 106 | + yaxisNumber.label = newValue.first | |
| 107 | + } | |
| 108 | + | |
| 109 | + } | |
| 110 | + | |
| 111 | + } | |
| 112 | + | |
| 113 | + private fun setChartCategoryVisible(){ | |
| 114 | + scatterChartCategory.isVisible = true | |
| 115 | + scatterChartNumber.isVisible = false | |
| 116 | + } | |
| 117 | + | |
| 118 | + private fun setChartNumberVisible(){ | |
| 119 | + scatterChartCategory.isVisible = false | |
| 120 | + scatterChartNumber.isVisible = true | |
| 121 | + } | |
| 122 | + | |
| 123 | + private fun setObservableSelectedVesselListener() { | |
| 124 | + observableSelectedVessel.listeners.add(this) | |
| 125 | + } | |
| 126 | + | |
| 127 | + private fun populateTime(vessel: Vessel): ArrayList<MessageData?> { | |
| 128 | + val allTime: ArrayList<MessageData?> = vessel.getAllTime() | |
| 129 | + allTime.sortBy { (it as Time).value } | |
| 130 | + | |
| 131 | + return allTime | |
| 132 | + } | |
| 133 | + | |
| 134 | + private fun populateLatitude(vessel: Vessel): ArrayList<MessageData?> { | |
| 135 | + val allLatitude: ArrayList<MessageData?> = vessel.getAllLatitude() | |
| 136 | + allLatitude.sortBy { (it as Latitude).value } | |
| 137 | + | |
| 138 | + return allLatitude | |
| 139 | + } | |
| 140 | + | |
| 141 | + private fun populateLongitude(vessel: Vessel): ArrayList<MessageData?> { | |
| 142 | + val allLongitude: ArrayList<MessageData?> = vessel.getAllLongitude() | |
| 143 | + allLongitude.sortBy { (it as Longitude).value } | |
| 144 | + | |
| 145 | + return allLongitude | |
| 146 | + } | |
| 147 | + | |
| 148 | + private fun populateSpeedOverGround(vessel: Vessel): ArrayList<MessageData?> { | |
| 149 | + val allSpeedOverGround: ArrayList<MessageData?> = vessel.getAllSpeedOverGround() | |
| 150 | + allSpeedOverGround.sortBy { (it as SpeedOverGround).value } | |
| 151 | + | |
| 152 | + return allSpeedOverGround | |
| 153 | + } | |
| 154 | + | |
| 155 | + private fun populateCourseOverGround(vessel: Vessel): ArrayList<MessageData?> { | |
| 156 | + val allCourseOverGround: ArrayList<MessageData?> = vessel.getAllCourseOverGround() | |
| 157 | + allCourseOverGround.sortBy { (it as CourseOverGround).value } | |
| 158 | + | |
| 159 | + return allCourseOverGround | |
| 160 | + } | |
| 161 | + | |
| 162 | + private fun populateHeading(vessel: Vessel): ArrayList<MessageData?> { | |
| 163 | + val allHeading: ArrayList<MessageData?> = vessel.getAllHeading() | |
| 164 | + allHeading.sortBy { (it as Heading).value } | |
| 165 | + | |
| 166 | + return allHeading | |
| 167 | + } | |
| 168 | + | |
| 169 | + private fun populatVesselName(vessel: Vessel): ArrayList<MessageData?> { | |
| 170 | + val allVesselName: ArrayList<MessageData?> = vessel.getAllVesselName() | |
| 171 | + allVesselName.sortBy { (it as VesselName).value } | |
| 172 | + | |
| 173 | + return allVesselName | |
| 174 | + } | |
| 175 | + | |
| 176 | + private fun populatIMO(vessel: Vessel): ArrayList<MessageData?> { | |
| 177 | + val allIMO: ArrayList<MessageData?> = vessel.getAllIMO() | |
| 178 | + allIMO.sortBy { (it as IMO).value } | |
| 179 | + | |
| 180 | + return allIMO | |
| 181 | + } | |
| 182 | + | |
| 183 | + private fun populatCallSign(vessel: Vessel): ArrayList<MessageData?> { | |
| 184 | + val allCallSign: ArrayList<MessageData?> = vessel.getAllCallSign() | |
| 185 | + allCallSign.sortBy { (it as CallSign).value } | |
| 186 | + | |
| 187 | + return allCallSign | |
| 188 | + } | |
| 189 | + | |
| 190 | + private fun populatVesselType(vessel: Vessel): ArrayList<MessageData?> { | |
| 191 | + val allVesselType: ArrayList<MessageData?> = vessel.getAllVesselType() | |
| 192 | + allVesselType.sortBy { (it as VesselType).value } | |
| 193 | + | |
| 194 | + return allVesselType | |
| 195 | + } | |
| 196 | + | |
| 197 | + private fun populatStatus(vessel: Vessel): ArrayList<MessageData?> { | |
| 198 | + val allStatus: ArrayList<MessageData?> = vessel.getAllStatus() | |
| 199 | + allStatus.sortBy { (it as Status).value } | |
| 200 | + | |
| 201 | + return allStatus | |
| 202 | + } | |
| 203 | + | |
| 204 | + private fun populatLength(vessel: Vessel): ArrayList<MessageData?> { | |
| 205 | + val allLength: ArrayList<MessageData?> = vessel.getAllLength() | |
| 206 | + allLength.sortBy { (it as Length).value } | |
| 207 | + | |
| 208 | + return allLength | |
| 209 | + } | |
| 210 | + | |
| 211 | + private fun populatWidth(vessel: Vessel): ArrayList<MessageData?> { | |
| 212 | + val allWidth: ArrayList<MessageData?> = vessel.getAllWidth() | |
| 213 | + allWidth.sortBy { (it as Width).value } | |
| 214 | + | |
| 215 | + return allWidth | |
| 216 | + } | |
| 217 | + | |
| 218 | + private fun populatDraft(vessel: Vessel): ArrayList<MessageData?> { | |
| 219 | + val allDraft: ArrayList<MessageData?> = vessel.getAllDraft() | |
| 220 | + allDraft.sortBy { (it as Draft).value } | |
| 221 | + | |
| 222 | + return allDraft | |
| 223 | + } | |
| 224 | + | |
| 225 | + private fun populatCargo(vessel: Vessel): ArrayList<MessageData?> { | |
| 226 | + val allCargo: ArrayList<MessageData?> = vessel.getAllCargo() | |
| 227 | + allCargo.sortBy { (it as Cargo).value } | |
| 228 | + | |
| 229 | + return allCargo | |
| 230 | + } | |
| 231 | + | |
| 232 | + private fun populateDataList(vessel: Vessel) { | |
| 233 | + val data = arrayListOf<Pair<String, ArrayList<MessageData?>>>() | |
| 234 | + | |
| 235 | + timeData = populateTime(vessel) | |
| 236 | + | |
| 237 | + data.add(Pair("Latitude", populateLatitude(vessel))) | |
| 238 | + | |
| 239 | + data.add(Pair("Longitude", populateLongitude(vessel))) | |
| 240 | + | |
| 241 | + data.add(Pair("Speed Over Ground", populateSpeedOverGround(vessel))) | |
| 242 | + | |
| 243 | + data.add(Pair("Course Over Ground", populateCourseOverGround(vessel))) | |
| 244 | + | |
| 245 | + data.add(Pair("Heading", populateHeading(vessel))) | |
| 246 | + | |
| 247 | + data.add(Pair("Vessel Name", populatVesselName(vessel))) | |
| 248 | + | |
| 249 | + data.add(Pair("IMO", populatIMO(vessel))) | |
| 250 | + | |
| 251 | + data.add(Pair("Call Sign", populatCallSign(vessel))) | |
| 252 | + | |
| 253 | + data.add(Pair("Vessel Type", populatVesselType(vessel))) | |
| 254 | + | |
| 255 | + data.add(Pair("Status", populatStatus(vessel))) | |
| 256 | + | |
| 257 | + data.add(Pair("Length", populatLength(vessel))) | |
| 258 | + | |
| 259 | + data.add(Pair("Width", populatWidth(vessel))) | |
| 260 | + | |
| 261 | + data.add(Pair("Draft", populatDraft(vessel))) | |
| 262 | + | |
| 263 | + data.add(Pair("Cargo", populatCargo(vessel))) | |
| 264 | + | |
| 265 | + dataList.addAll(data) | |
| 266 | + } | |
| 267 | + | |
| 268 | + override fun onValueChanged(newValue: Vessel) { | |
| 269 | + dataList.clear() | |
| 270 | + populateDataList(newValue) | |
| 271 | + | |
| 272 | + } | |
| 273 | + | |
| 274 | +} |
src/main/kotlin/application/controller/VesselListPanelController.kt
View file @
513c034
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | var shipListView: ListView<Int> = ListView() |
| 18 | 18 | |
| 19 | 19 | |
| 20 | - var shipList: ObservableList<Int> = FXCollections.observableArrayList() | |
| 20 | + private var shipList: ObservableList<Int> = FXCollections.observableArrayList() | |
| 21 | 21 | |
| 22 | 22 | override fun initialize(location: URL?, resources: ResourceBundle?) { |
| 23 | 23 | shipListView.items = shipList |
src/main/kotlin/application/model/Message.kt
View file @
513c034
| ... | ... | @@ -3,34 +3,27 @@ |
| 3 | 3 | import java.time.LocalDateTime |
| 4 | 4 | |
| 5 | 5 | class Message(split: List<String>) { |
| 6 | - val mmsi: Int? = split[0].toIntOrNull() | |
| 7 | - val time: LocalDateTime = LocalDateTime.parse(split[1]) | |
| 8 | - val latitude: Double? = split[2].toDoubleOrNull() | |
| 9 | - val longitude: Double? = split[3].toDoubleOrNull() | |
| 10 | - val speedOverGround: Double? = split[4].toDoubleOrNull() | |
| 11 | - val courseOverGround: Double? = split[5].toDoubleOrNull() | |
| 12 | - val heading: Int? = split[6].toIntOrNull() | |
| 13 | - val vesselName: String? = split[7] | |
| 14 | - val imo: String? = split[8] | |
| 15 | - val callSign: String? = split[9] | |
| 16 | - val vesselType: Int? = split[10].toIntOrNull() | |
| 17 | - val status: String? = split[11] | |
| 18 | - val length: Double? = split[12].toDoubleOrNull() | |
| 19 | - val width: Double? = split[13].toDoubleOrNull() | |
| 20 | - val draft: Double? = split[14].toDoubleOrNull() | |
| 21 | - val cargo: Int? = split[15].toIntOrNull() | |
| 6 | + val mmsi = MMSI(split[0].toIntOrNull()) | |
| 7 | + val time = Time(LocalDateTime.parse(split[1])) | |
| 8 | + val latitude = Latitude(split[2].toDoubleOrNull()) | |
| 9 | + val longitude = Longitude(split[3].toDoubleOrNull()) | |
| 10 | + val speedOverGround = SpeedOverGround(split[4].toDoubleOrNull()) | |
| 11 | + val courseOverGround = CourseOverGround(split[5].toDoubleOrNull()) | |
| 12 | + val heading = Heading(split[6].toDoubleOrNull()) | |
| 13 | + val vesselName = VesselName(split[7]) | |
| 14 | + val imo = IMO(split[8]) | |
| 15 | + val callSign = CallSign(split[9]) | |
| 16 | + val vesselType = VesselType(split[10].toIntOrNull()) | |
| 17 | + val status = Status(split[11]) | |
| 18 | + val length = Length(split[12].toDoubleOrNull()) | |
| 19 | + val width = Width(split[13].toDoubleOrNull()) | |
| 20 | + val draft = Draft(split[14].toDoubleOrNull()) | |
| 21 | + val cargo = Cargo(split[15].toIntOrNull()) | |
| 22 | 22 | |
| 23 | - fun getHexColorStroke(): String{ | |
| 24 | - var hex = Integer.toHexString(this.mmsi!!) | |
| 25 | - if (hex.length > 6){ | |
| 26 | - hex = hex.substring(hex.length - 6) | |
| 27 | - } | |
| 28 | - return hex | |
| 29 | - } | |
| 30 | 23 | |
| 31 | - fun getHexColorFill(): String{ | |
| 32 | - var hex = Integer.toHexString(this.mmsi!! - 50) | |
| 33 | - if (hex.length > 6){ | |
| 24 | + fun getHexColorStroke(): String { | |
| 25 | + var hex = Integer.toHexString(this.mmsi.value!!) | |
| 26 | + if (hex.length > 6) { | |
| 34 | 27 | hex = hex.substring(hex.length - 6) |
| 35 | 28 | } |
| 36 | 29 | return hex |
src/main/kotlin/application/model/MessageData.kt
View file @
513c034
| 1 | +package application.model | |
| 2 | + | |
| 3 | +import java.time.LocalDateTime | |
| 4 | + | |
| 5 | +interface MessageDataVisitor { | |
| 6 | + fun visit(messageData: MMSI) | |
| 7 | + fun visit(messageData: Time) | |
| 8 | + fun visit(messageData: Latitude) | |
| 9 | + fun visit(messageData: Longitude) | |
| 10 | + fun visit(messageData: SpeedOverGround) | |
| 11 | + fun visit(messageData: CourseOverGround) | |
| 12 | + fun visit(messageData: Heading) | |
| 13 | + fun visit(messageData: VesselName) | |
| 14 | + fun visit(messageData: IMO) | |
| 15 | + fun visit(messageData: CallSign) | |
| 16 | + fun visit(messageData: VesselType) | |
| 17 | + fun visit(messageData: Status) | |
| 18 | + fun visit(messageData: Length) | |
| 19 | + fun visit(messageData: Width) | |
| 20 | + fun visit(messageData: Draft) | |
| 21 | + fun visit(messageData: Cargo) | |
| 22 | +} | |
| 23 | + | |
| 24 | +interface MessageData { | |
| 25 | + | |
| 26 | + fun accept(visitor: MessageDataVisitor) | |
| 27 | + | |
| 28 | +} | |
| 29 | + | |
| 30 | +data class MMSI(val value: Int?) : MessageData { | |
| 31 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 32 | +} | |
| 33 | + | |
| 34 | +data class Time(val value: LocalDateTime) : MessageData { | |
| 35 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 36 | +} | |
| 37 | + | |
| 38 | +data class Latitude(val value: Double?) : MessageData { | |
| 39 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 40 | +} | |
| 41 | + | |
| 42 | +data class Longitude(val value: Double?) : MessageData { | |
| 43 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 44 | +} | |
| 45 | + | |
| 46 | +data class SpeedOverGround(val value: Double?) : MessageData { | |
| 47 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 48 | +} | |
| 49 | + | |
| 50 | +data class CourseOverGround(val value: Double?) : MessageData { | |
| 51 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 52 | +} | |
| 53 | + | |
| 54 | +data class Heading(val value: Double?) : MessageData { | |
| 55 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 56 | +} | |
| 57 | + | |
| 58 | +data class VesselName(val value: String?) : MessageData { | |
| 59 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 60 | +} | |
| 61 | + | |
| 62 | +data class IMO(val value: String?) : MessageData { | |
| 63 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 64 | +} | |
| 65 | + | |
| 66 | +data class CallSign(val value: String?) : MessageData { | |
| 67 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 68 | +} | |
| 69 | + | |
| 70 | +data class VesselType(val value: Int?) : MessageData { | |
| 71 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 72 | +} | |
| 73 | + | |
| 74 | +data class Status(val value: String?) : MessageData { | |
| 75 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 76 | +} | |
| 77 | + | |
| 78 | +data class Length(val value: Double?) : MessageData { | |
| 79 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 80 | +} | |
| 81 | + | |
| 82 | +data class Width(val value: Double?) : MessageData { | |
| 83 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 84 | +} | |
| 85 | + | |
| 86 | +data class Draft(val value: Double?) : MessageData { | |
| 87 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 88 | +} | |
| 89 | + | |
| 90 | +data class Cargo(val value: Int?) : MessageData { | |
| 91 | + override fun accept(visitor: MessageDataVisitor) = visitor.visit(messageData = this) | |
| 92 | +} | |
| 93 | + | |
| 94 | +class GetValueVisitor() : MessageDataVisitor { | |
| 95 | + var value: String = "" | |
| 96 | + | |
| 97 | + override fun visit(messageData: MMSI) { | |
| 98 | + value = messageData.value.toString() | |
| 99 | + } | |
| 100 | + | |
| 101 | + override fun visit(messageData: Time) { | |
| 102 | + value = messageData.value.toString() | |
| 103 | + } | |
| 104 | + | |
| 105 | + override fun visit(messageData: Latitude) { | |
| 106 | + value = messageData.value.toString() | |
| 107 | + } | |
| 108 | + | |
| 109 | + override fun visit(messageData: Longitude) { | |
| 110 | + value = messageData.value.toString() | |
| 111 | + } | |
| 112 | + | |
| 113 | + override fun visit(messageData: SpeedOverGround) { | |
| 114 | + value = messageData.value.toString() | |
| 115 | + } | |
| 116 | + | |
| 117 | + override fun visit(messageData: CourseOverGround) { | |
| 118 | + value = messageData.value.toString() | |
| 119 | + } | |
| 120 | + | |
| 121 | + override fun visit(messageData: Heading) { | |
| 122 | + value = messageData.value.toString() | |
| 123 | + } | |
| 124 | + | |
| 125 | + override fun visit(messageData: VesselName) { | |
| 126 | + value = messageData.value.toString() | |
| 127 | + } | |
| 128 | + | |
| 129 | + override fun visit(messageData: IMO) { | |
| 130 | + value = messageData.value.toString() | |
| 131 | + } | |
| 132 | + | |
| 133 | + override fun visit(messageData: CallSign) { | |
| 134 | + value = messageData.value.toString() | |
| 135 | + } | |
| 136 | + | |
| 137 | + override fun visit(messageData: VesselType) { | |
| 138 | + value = messageData.value.toString() | |
| 139 | + } | |
| 140 | + | |
| 141 | + override fun visit(messageData: Status) { | |
| 142 | + value = messageData.value.toString() | |
| 143 | + } | |
| 144 | + | |
| 145 | + override fun visit(messageData: Length) { | |
| 146 | + value = messageData.value.toString() | |
| 147 | + } | |
| 148 | + | |
| 149 | + override fun visit(messageData: Width) { | |
| 150 | + value = messageData.value.toString() | |
| 151 | + } | |
| 152 | + | |
| 153 | + override fun visit(messageData: Draft) { | |
| 154 | + value = messageData.value.toString() | |
| 155 | + } | |
| 156 | + | |
| 157 | + override fun visit(messageData: Cargo) { | |
| 158 | + value = messageData.value.toString() | |
| 159 | + } | |
| 160 | + | |
| 161 | +} |
src/main/kotlin/application/model/Vessel.kt
View file @
513c034
| 1 | 1 | package application.model |
| 2 | 2 | |
| 3 | 3 | import java.time.LocalDateTime |
| 4 | +import java.time.ZoneOffset | |
| 4 | 5 | import java.util.* |
| 5 | 6 | |
| 6 | 7 | |
| 7 | -class Vessel(val mmsi : Int?) { | |
| 8 | +class Vessel(val mmsi: Int?) { | |
| 8 | 9 | val messages: SortedMap<LocalDateTime, Message> = sortedMapOf() |
| 10 | + | |
| 11 | + fun getAllTimeInMilliSeconde(): ArrayList<Long> { | |
| 12 | + val timeList = arrayListOf<Long>() | |
| 13 | + var timeInMilliSeconde: Long | |
| 14 | + messages.forEach { | |
| 15 | + timeInMilliSeconde = it.value.time.value.toEpochSecond(ZoneOffset.UTC).toInt().toLong() | |
| 16 | + timeList.add(timeInMilliSeconde) | |
| 17 | + } | |
| 18 | + return timeList | |
| 19 | + } | |
| 20 | + | |
| 21 | + fun getAllTime(): ArrayList<MessageData?> { | |
| 22 | + val timeList = arrayListOf<MessageData?>() | |
| 23 | + messages.forEach { | |
| 24 | + timeList.add(it.value.time) | |
| 25 | + } | |
| 26 | + | |
| 27 | + return timeList | |
| 28 | + } | |
| 29 | + | |
| 30 | + fun getAllLatitude(): ArrayList<MessageData?> { | |
| 31 | + val latitudeList = arrayListOf<MessageData?>() | |
| 32 | + messages.forEach { | |
| 33 | + latitudeList.add(it.value.latitude) | |
| 34 | + } | |
| 35 | + | |
| 36 | + return latitudeList | |
| 37 | + } | |
| 38 | + | |
| 39 | + fun getAllLongitude(): ArrayList<MessageData?> { | |
| 40 | + val longitudeList = arrayListOf<MessageData?>() | |
| 41 | + messages.forEach { | |
| 42 | + longitudeList.add(it.value.longitude) | |
| 43 | + } | |
| 44 | + | |
| 45 | + return longitudeList | |
| 46 | + } | |
| 47 | + | |
| 48 | + fun getAllSpeedOverGround(): ArrayList<MessageData?> { | |
| 49 | + val speedOverGroundList = arrayListOf<MessageData?>() | |
| 50 | + messages.forEach { | |
| 51 | + speedOverGroundList.add(it.value.speedOverGround) | |
| 52 | + } | |
| 53 | + | |
| 54 | + return speedOverGroundList | |
| 55 | + } | |
| 56 | + | |
| 57 | + fun getAllCourseOverGround(): ArrayList<MessageData?> { | |
| 58 | + val res = arrayListOf<MessageData?>() | |
| 59 | + messages.forEach { | |
| 60 | + res.add(it.value.courseOverGround) | |
| 61 | + } | |
| 62 | + | |
| 63 | + return res | |
| 64 | + } | |
| 65 | + | |
| 66 | + fun getAllHeading(): ArrayList<MessageData?> { | |
| 67 | + val res = arrayListOf<MessageData?>() | |
| 68 | + messages.forEach { | |
| 69 | + res.add(it.value.heading) | |
| 70 | + } | |
| 71 | + | |
| 72 | + return res | |
| 73 | + } | |
| 74 | + | |
| 75 | + fun getAllVesselName(): ArrayList<MessageData?> { | |
| 76 | + val res = arrayListOf<MessageData?>() | |
| 77 | + messages.forEach { | |
| 78 | + res.add(it.value.vesselName) | |
| 79 | + } | |
| 80 | + return res | |
| 81 | + } | |
| 82 | + | |
| 83 | + fun getAllIMO(): ArrayList<MessageData?> { | |
| 84 | + val res = arrayListOf<MessageData?>() | |
| 85 | + messages.forEach { | |
| 86 | + res.add(it.value.imo) | |
| 87 | + } | |
| 88 | + return res | |
| 89 | + } | |
| 90 | + | |
| 91 | + fun getAllCallSign(): ArrayList<MessageData?> { | |
| 92 | + val res = arrayListOf<MessageData?>() | |
| 93 | + messages.forEach { | |
| 94 | + res.add(it.value.callSign) | |
| 95 | + } | |
| 96 | + return res | |
| 97 | + } | |
| 98 | + | |
| 99 | + fun getAllVesselType(): ArrayList<MessageData?> { | |
| 100 | + val res = arrayListOf<MessageData?>() | |
| 101 | + messages.forEach { | |
| 102 | + res.add(it.value.vesselType) | |
| 103 | + } | |
| 104 | + return res | |
| 105 | + } | |
| 106 | + | |
| 107 | + fun getAllStatus(): ArrayList<MessageData?> { | |
| 108 | + val res = arrayListOf<MessageData?>() | |
| 109 | + messages.forEach { | |
| 110 | + res.add(it.value.status) | |
| 111 | + } | |
| 112 | + return res | |
| 113 | + } | |
| 114 | + | |
| 115 | + fun getAllLength(): ArrayList<MessageData?> { | |
| 116 | + val res = arrayListOf<MessageData?>() | |
| 117 | + messages.forEach { | |
| 118 | + res.add(it.value.length) | |
| 119 | + } | |
| 120 | + return res | |
| 121 | + } | |
| 122 | + | |
| 123 | + fun getAllWidth(): ArrayList<MessageData?> { | |
| 124 | + val res = arrayListOf<MessageData?>() | |
| 125 | + messages.forEach { | |
| 126 | + res.add(it.value.width) | |
| 127 | + } | |
| 128 | + return res | |
| 129 | + } | |
| 130 | + | |
| 131 | + fun getAllDraft(): ArrayList<MessageData?> { | |
| 132 | + val res = arrayListOf<MessageData?>() | |
| 133 | + messages.forEach { | |
| 134 | + res.add(it.value.draft) | |
| 135 | + } | |
| 136 | + return res | |
| 137 | + } | |
| 138 | + | |
| 139 | + fun getAllCargo(): ArrayList<MessageData?> { | |
| 140 | + val res = arrayListOf<MessageData?>() | |
| 141 | + messages.forEach { | |
| 142 | + res.add(it.value.cargo) | |
| 143 | + } | |
| 144 | + return res | |
| 145 | + } | |
| 146 | + | |
| 9 | 147 | } |
src/main/kotlin/application/model/VesselGenerator.kt
View file @
513c034
| ... | ... | @@ -13,10 +13,10 @@ |
| 13 | 13 | if (arrayMessage[0].toIntOrNull() !== null) { |
| 14 | 14 | val message = Message(arrayMessage) |
| 15 | 15 | messages.add(message) |
| 16 | - if (!vessels.containsKey(message.mmsi)){ | |
| 17 | - vessels[message.mmsi] = Vessel(message.mmsi!!) | |
| 16 | + if (!vessels.containsKey(message.mmsi.value)){ | |
| 17 | + vessels[message.mmsi.value] = Vessel(message.mmsi.value!!) | |
| 18 | 18 | } |
| 19 | - vessels[message.mmsi]?.messages?.set(message.time, message) | |
| 19 | + vessels[message.mmsi.value]?.messages?.set(message.time.value, message) | |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | } |
src/main/kotlin/map/MapDisplayer.kt
View file @
513c034
| ... | ... | @@ -39,7 +39,7 @@ |
| 39 | 39 | clearMap(map) |
| 40 | 40 | observableVessel.vessels.forEach { (_, value) -> |
| 41 | 41 | value.messages.forEach { (_, message) -> |
| 42 | - map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") | |
| 42 | + map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") | |
| 43 | 43 | } |
| 44 | 44 | } |
| 45 | 45 | } |
| 46 | 46 | |
| ... | ... | @@ -48,10 +48,10 @@ |
| 48 | 48 | clearMap(map) |
| 49 | 49 | observableVessel.vessels.forEach { (_, value) -> |
| 50 | 50 | value.messages.forEach { (_, message) -> |
| 51 | - if (selectedMMSI == message.mmsi) { | |
| 52 | - map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)") | |
| 51 | + if (selectedMMSI == message.mmsi.value) { | |
| 52 | + map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)") | |
| 53 | 53 | } else { |
| 54 | - map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") | |
| 54 | + map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") | |
| 55 | 55 | } |
| 56 | 56 | } |
| 57 | 57 | } |
| ... | ... | @@ -61,7 +61,7 @@ |
| 61 | 61 | clearMap(map) |
| 62 | 62 | observableVessel.vessels.forEach { (_, value) -> |
| 63 | 63 | value.messages.forEach { (_, message) -> |
| 64 | - map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 64 | + map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 65 | 65 | } |
| 66 | 66 | } |
| 67 | 67 | map.execScript("myMap.addLayer(markerClusters);") |
| 68 | 68 | |
| ... | ... | @@ -71,10 +71,10 @@ |
| 71 | 71 | clearMap(map) |
| 72 | 72 | observableVessel.vessels.forEach { (_, value) -> |
| 73 | 73 | value.messages.forEach { (_, message) -> |
| 74 | - if (selectedMMSI == message.mmsi) { | |
| 75 | - map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") | |
| 74 | + if (selectedMMSI == message.mmsi.value) { | |
| 75 | + map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") | |
| 76 | 76 | } else { |
| 77 | - map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 77 | + map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 | } |
| ... | ... | @@ -85,7 +85,7 @@ |
| 85 | 85 | clearMap(map) |
| 86 | 86 | observableVessel.vessels.forEach { (_, value) -> |
| 87 | 87 | value.messages.forEach { (_, message) -> |
| 88 | - map.execScript("heatLayer.addLatLng([${message.latitude}, ${message.longitude}]);") | |
| 88 | + map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") | |
| 89 | 89 | } |
| 90 | 90 | } |
| 91 | 91 | } |
| 92 | 92 | |
| ... | ... | @@ -94,10 +94,10 @@ |
| 94 | 94 | clearMap(map) |
| 95 | 95 | observableVessel.vessels.forEach { (_, value) -> |
| 96 | 96 | value.messages.forEach { (_, message) -> |
| 97 | - if (selectedMMSI == message.mmsi) { | |
| 98 | - map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") | |
| 97 | + if (selectedMMSI == message.mmsi.value) { | |
| 98 | + map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") | |
| 99 | 99 | } else { |
| 100 | - map.execScript("heatLayer.addLatLng([${message.latitude}, ${message.longitude}]);") | |
| 100 | + map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") | |
| 101 | 101 | } |
| 102 | 102 | } |
| 103 | 103 | } |
src/main/resources/gui/dataPanel.fxml
View file @
513c034
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | |
| 3 | +<?import javafx.scene.chart.*?> | |
| 4 | +<?import javafx.scene.control.*?> | |
| 5 | +<?import javafx.scene.layout.*?> | |
| 6 | + | |
| 7 | +<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.241" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.DataPanelController"> | |
| 8 | + <SplitPane dividerPositions="0.1705685618729097" prefHeight="212.0" prefWidth="254.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | |
| 9 | + <ListView fx:id="dataListView" layoutX="-73.0" layoutY="14.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | |
| 10 | + <StackPane prefHeight="150.0" prefWidth="200.0"> | |
| 11 | + <ScatterChart fx:id="scatterChartNumber"> | |
| 12 | + <xAxis> | |
| 13 | + <CategoryAxis side="BOTTOM" fx:id="xaxisNumber" /> | |
| 14 | + </xAxis> | |
| 15 | + <yAxis> | |
| 16 | + <NumberAxis fx:id="yaxisNumber" side="LEFT" /> | |
| 17 | + </yAxis> | |
| 18 | + </ScatterChart> | |
| 19 | + <ScatterChart fx:id="scatterChartCategory" visible="false"> | |
| 20 | + <xAxis> | |
| 21 | + <CategoryAxis side="BOTTOM" fx:id="xaxisCategory" /> | |
| 22 | + </xAxis> | |
| 23 | + <yAxis> | |
| 24 | + <CategoryAxis fx:id="yaxisCategory" side="LEFT" /> | |
| 25 | + </yAxis> | |
| 26 | + </ScatterChart> | |
| 27 | + </StackPane> | |
| 28 | + </SplitPane> | |
| 29 | +</AnchorPane> |
src/main/resources/gui/vesselListPanel.fxml
View file @
513c034
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | <top> |
| 9 | 9 | <AnchorPane prefHeight="33.0" prefWidth="200.0" BorderPane.alignment="CENTER"> |
| 10 | 10 | <children> |
| 11 | - <Button layoutX="74.0" layoutY="2.0" mnemonicParsing="false" text="Button" fx:id="buton" /> | |
| 11 | + <Button layoutX="74.0" layoutY="2.0" mnemonicParsing="false" text="Button" fx:id="button"/> | |
| 12 | 12 | </children></AnchorPane> |
| 13 | 13 | </top> |
| 14 | 14 | <center> |
src/main/resources/gui/windows.fxml
View file @
513c034
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | |
| 3 | -<?import javafx.scene.control.*?> | |
| 3 | +<?import javafx.scene.control.SplitPane?> | |
| 4 | 4 | <?import javafx.scene.layout.*?> |
| 5 | -<?import javafx.scene.shape.*?> | |
| 6 | - | |
| 7 | -<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1"> | |
| 5 | +<?import javafx.scene.shape.Line?> | |
| 6 | +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" | |
| 7 | + prefWidth="1200.0" xmlns="http://javafx.com/javafx/8.0.241" xmlns:fx="http://javafx.com/fxml/1"> | |
| 8 | 8 | <children> |
| 9 | - <fx:include source="menuBar.fxml" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | |
| 10 | - <SplitPane dividerPositions="0.29797979797979796" layoutY="39.0" prefHeight="865.0" prefWidth="1194.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="35.0"> | |
| 9 | + <fx:include source="menuBar.fxml" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" | |
| 10 | + AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> | |
| 11 | + <SplitPane dividerPositions="0.13772954924874792" layoutY="39.0" prefHeight="865.0" prefWidth="1194.0" | |
| 12 | + AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" | |
| 13 | + AnchorPane.topAnchor="35.0"> | |
| 11 | 14 | <items> |
| 12 | 15 | <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> |
| 13 | 16 | <children> |
| 14 | - <fx:include source="vesselListPanel.fxml" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | |
| 17 | + <fx:include source="vesselListPanel.fxml" AnchorPane.leftAnchor="0.0" | |
| 18 | + AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> | |
| 15 | 19 | </children> |
| 16 | 20 | </AnchorPane> |
| 17 | 21 | <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> |
| 18 | 22 | <children> |
| 19 | - <SplitPane dividerPositions="0.536" layoutX="127.0" layoutY="74.0" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | |
| 23 | + <SplitPane dividerPositions="0.536" layoutX="127.0" layoutY="74.0" orientation="VERTICAL" | |
| 24 | + prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" | |
| 25 | + AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | |
| 20 | 26 | <items> |
| 21 | - <fx:include source="mapPanel.fxml" /> | |
| 22 | - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" /> | |
| 27 | + <fx:include source="mapPanel.fxml"/> | |
| 28 | + <fx:include source="dataPanel.fxml"/> | |
| 23 | 29 | </items> |
| 24 | 30 | </SplitPane> |
| 25 | 31 | </children> |
| 26 | 32 | </AnchorPane> |
| 27 | 33 | </items> |
| 28 | 34 | </SplitPane> |
| 29 | - <Line endX="1101.0" endY="1.1444091796875E-5" layoutX="101.0" layoutY="35.0" startX="-100.0" /> | |
| 35 | + <Line endX="1101.0" endY="1.1444091796875E-5" layoutX="101.0" layoutY="35.0" startX="-100.0"/> | |
| 30 | 36 | </children> |
| 31 | 37 | </AnchorPane> |