From c88cfe36986f3043d6a6789cd4014b09dd01c31f Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Mon, 20 May 2024 19:25:52 +0100 Subject: [PATCH 1/7] plugins/alert-intrusion/AlertIntrusion: Tweak to ignore old system data. --- .../alertintrusion/AlertIntrusion.java | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java index b5c58971fe..c8f2e575ba 100644 --- a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java +++ b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java @@ -170,12 +170,18 @@ void updateCollisions() { // (vehicle, ship) -> (distance, timestamp) final ConcurrentHashMap, Pair> collisions = new ConcurrentHashMap<>(); + final Date datetimeNow = new Date(); long timeSpanMillis = projectionTimeWindowValue * projectionTimeWindowUnit.getMicroseconds(); for (long timeOffset = 0; timeOffset < timeSpanMillis; timeOffset += 1_000L * collisionDistance / 4) { final long deltaTimeMillis = timeOffset; Arrays.stream(ImcSystemsHolder.lookupAllSystems()) .filter(system -> !system.getName().equalsIgnoreCase(mainSystemName)) .forEach(system -> { + Date dataAge = new Date(system.getLocationTimeMillis()); + if (dataAge.before(datetimeNow) && datetimeNow.getTime() - dataAge.getTime() + > minutesToHideSystemsWithoutKnownLocation * 60_000L) { + return; + } Date t = new Date(System.currentTimeMillis() + deltaTimeMillis); LocationType locationSystem = system.getLocation().getNewAbsoluteLatLonDepth(); LocationType locationMain = mainSystem.getLocation().getNewAbsoluteLatLonDepth(); @@ -187,6 +193,11 @@ void updateCollisions() { Arrays.stream(ExternalSystemsHolder.lookupAllSystems()) .filter(system -> !system.getName().equalsIgnoreCase(mainSystemName)) .forEach(system -> { + Date dataAge = new Date(system.getLocationTimeMillis()); + if (dataAge.before(datetimeNow) && datetimeNow.getTime() - dataAge.getTime() + > minutesToHideSystemsWithoutKnownLocation * 60_000L) { + return; + } Date t = new Date(System.currentTimeMillis() + deltaTimeMillis); LocationType locationSystem = system.getLocation().getNewAbsoluteLatLonDepth(); LocationType locationMain = mainSystem.getLocation().getNewAbsoluteLatLonDepth(); @@ -214,7 +225,7 @@ void updateCollisions() { }); long diff = System.currentTimeMillis() - start; - NeptusLog.pub().info("RiskAnalysis detected {} collisions in {} milliseconds.", collisions.size(), diff); + NeptusLog.pub().info("Risk detected {} collisions in {} milliseconds.", collisions.size(), diff); if (changed.get()) { layerPainter.triggerImageRebuild(); @@ -271,7 +282,7 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); - boolean askForLaterRepaint = false; + AtomicBoolean askForLaterRepaint = new AtomicBoolean(false); boolean recreateImage = layerPainter.paintPhaseStartTestRecreateImageAndRecreate(g, renderer); if (recreateImage) { @@ -280,7 +291,10 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { if (!collisionsTree.isEmpty() && collisionsTree.get(lastMainVehicle) != null && !collisionsTree.get(lastMainVehicle).isEmpty()) { Graphics2D gg = (Graphics2D) g2.create(); gg.translate(20, 100); - askForLaterRepaint |= !gg.drawImage(colregImage, null, null); + boolean res = !gg.drawImage(colregImage, null, null); + if (res) { + askForLaterRepaint.compareAndSet(false, true); + } gg.dispose(); int collisionSize = collisionsTree.get(lastMainVehicle).size(); @@ -304,12 +318,34 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { AtomicDouble distanceClosest = new AtomicDouble(Double.MAX_VALUE); AtomicReference timeClosest = new AtomicReference<>(null); collisionsTree.get(lastMainVehicle).forEach((time, pair) -> { - String ship = pair.first(); + String sysName = pair.first(); double distance = pair.second(); if (distance < distanceClosest.get()) { - shipClosest.set(ship); + shipClosest.set(sysName); distanceClosest.set(distance); timeClosest.set(time); + + LocationType loc = null; + ImcSystem sys = ImcSystemsHolder.lookupSystemByName(sysName); + if (sys != null) { + loc = sys.getLocation().getNewAbsoluteLatLonDepth(); + } else { + ExternalSystem esys = ExternalSystemsHolder.lookupSystem(sysName); + if (esys != null) { + loc = esys.getLocation().getNewAbsoluteLatLonDepth(); + } + } + if (loc != null) { + Graphics2D gg = (Graphics2D) g2.create(); + Point2D spos = renderer.getScreenPosition(loc); + gg.translate(spos.getX() - 20 - 8, spos.getY()); + boolean res = !gg.drawImage(colregImageSmall, null, null); + if (res) { + askForLaterRepaint.compareAndSet(false, true); + } + gg.dispose(); + } + } //Point2D pt = renderer.getScreenPosition(loc); }); @@ -330,7 +366,6 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { gg.dispose(); } - if (shipClosest.get() != null) { String sysName = shipClosest.get(); LocationType loc = null; @@ -344,17 +379,11 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { } } if (loc != null) { - Graphics2D gg = (Graphics2D) g2.create(); - Point2D spos = renderer.getScreenPosition(loc); - gg.translate(spos.getX() - 20 - 8, spos.getY()); - askForLaterRepaint |= !gg.drawImage(colregImageSmall, null, null); - - gg.dispose(); } } } layerPainter.paintPhaseEndFinishImageRecreateAndPaintImageCacheToRenderer(g, renderer); - if (askForLaterRepaint) { + if (askForLaterRepaint.get()) { layerPainter.triggerImageRebuild(); renderer.invalidate(); renderer.repaint(10); From bd423e310738fac8987191ca0e4750a2b249bf19 Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Wed, 24 Jul 2024 14:34:28 +0100 Subject: [PATCH 2/7] plugins/alliance/AisContactDb: Fix potential concurrent exception and small msgs cleanup. --- .../neptus/plugins/alliance/AisContactDb.java | 217 ++++++++++-------- 1 file changed, 126 insertions(+), 91 deletions(-) diff --git a/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/AisContactDb.java b/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/AisContactDb.java index 749f54502b..ee398d3a2d 100644 --- a/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/AisContactDb.java +++ b/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/AisContactDb.java @@ -37,10 +37,13 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; import java.util.Map.Entry; import java.util.Vector; @@ -53,6 +56,7 @@ import de.baderjene.aistoolkit.aisparser.message.Message05; import pt.lsts.neptus.NeptusLog; import pt.lsts.neptus.comm.SystemUtils; +import pt.lsts.neptus.comm.manager.imc.ImcSystem; import pt.lsts.neptus.comm.manager.imc.ImcSystemsHolder; import pt.lsts.neptus.plugins.alliance.NmeaPlotter.MTShip; import pt.lsts.neptus.systems.external.ExternalSystem; @@ -71,9 +75,10 @@ */ public class AisContactDb implements AISObserver { - private LinkedHashMap contacts = new LinkedHashMap<>(); - private LinkedHashMap labelCache = new LinkedHashMap<>(); - private LinkedHashMap> dimensionsCache = new LinkedHashMap<>(); + private final Object lock = new Object(); + private final Map contacts = new LinkedHashMap<>(); + private final Map labelCache = new LinkedHashMap<>(); + private final Map> dimensionsCache = new LinkedHashMap<>(); private File cache = new File(ConfigFetch.getConfFolder() + "/ais.cache"); @@ -85,6 +90,7 @@ public class AisContactDb implements AISObserver { public AisContactDb() { if (!cache.canRead()) return; + int count = 0; try { BufferedReader reader = new BufferedReader(new FileReader(cache)); @@ -99,7 +105,9 @@ public AisContactDb() { mmsi = Integer.parseInt(parts[0].replaceAll("^0x", ""), 16); } String name = parts[1].trim(); - labelCache.put(mmsi, name); + synchronized (lock) { + labelCache.put(mmsi, name); + } HashMap dimV = new HashMap<>(); for (int i = 2; i < parts.length; i++) { @@ -117,14 +125,17 @@ public AisContactDb() { } } } - if (dimV.size() > 0) - dimensionsCache.put(mmsi, dimV); + if (!dimV.isEmpty()) { + synchronized (lock) { + dimensionsCache.put(mmsi, dimV); + } + } line = reader.readLine(); count++; } reader.close(); - NeptusLog.pub().info("Read " + count + " vessel names from " + cache.getAbsolutePath()); + NeptusLog.pub().info("Read {} vessel names from {}", count, cache.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); @@ -133,27 +144,26 @@ public AisContactDb() { public void saveCache() { int count = 0; - try { - BufferedWriter writer = new BufferedWriter(new FileWriter(cache)); - - for (Entry entry : labelCache.entrySet()) { - StringBuilder sb = new StringBuilder(); - sb.append(entry.getKey()).append(",").append(entry.getValue()); - - HashMap dimV = dimensionsCache.get(entry.getKey()); - if (dimV != null) { - for (String n : dimV.keySet()) { - sb.append(","); - sb.append(n).append("=").append("" + dimV.get(n)); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(cache))) { + synchronized (lock) { + for (Entry entry : labelCache.entrySet()) { + StringBuilder sb = new StringBuilder(); + sb.append(entry.getKey()).append(",").append(entry.getValue()); + + HashMap dimV = dimensionsCache.get(entry.getKey()); + if (dimV != null) { + for (String n : dimV.keySet()) { + sb.append(","); + sb.append(n).append("=").append(dimV.get(n)); + } } - } - sb.append("\n"); - writer.write(sb.toString()); - count++; + sb.append("\n"); + writer.write(sb.toString()); + count++; + } } - writer.close(); - NeptusLog.pub().info("Wrote " + count + " vessel names to " + cache.getAbsolutePath()); + NeptusLog.pub().info("Wrote {} vessel names to {}", count, cache.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); @@ -161,7 +171,9 @@ public void saveCache() { } public String getNameForMMSI(int mmsi) { - return labelCache.get(mmsi); + synchronized (lock) { + return labelCache.get(mmsi); + } } public void processGGA(String sentence) { @@ -234,18 +246,21 @@ public void processRattm(String sentence) { if (id.isEmpty()) id = "radar-" + parts[1]; - if (ImcSystemsHolder.getSystemWithName(id) != null && ImcSystemsHolder.getSystemWithName(id).isActive()) { + ImcSystem sys = ImcSystemsHolder.getSystemWithName(id); + if (sys != null && sys.isActive()) { return; } - if (!contacts.containsKey(rid)) { - AisContact contact = new AisContact(rid); - contacts.put(rid, contact); - } + synchronized (lock) { + if (!contacts.containsKey(rid)) { + AisContact contact = new AisContact(rid); + contacts.put(rid, contact); + } - AisContact contact = contacts.get(rid); - contact.setLocation(newLoc); - contact.setLabel(id); + AisContact contact = contacts.get(rid); + contact.setLocation(newLoc); + contact.setLabel(id); + } } public void processBtll(String sentence) { @@ -284,12 +299,15 @@ public void processBtll(String sentence) { LocationType loc = new LocationType(lat, lon); - if (!contacts.containsKey(mmsi)) { - AisContact contact = new AisContact(mmsi); - contacts.put(mmsi, contact); + AisContact contact; + synchronized (lock) { + if (!contacts.containsKey(mmsi)) { + contact = new AisContact(mmsi); + contacts.put(mmsi, contact); + } else { + contact = contacts.get(mmsi); + } } - // System.out.println(mmsi); - AisContact contact = contacts.get(mmsi); contact.setLocation(loc); contact.setCog(heading); contact.setLabel(id); @@ -304,14 +322,16 @@ public void setMTShip(MTShip ship) { name = "SAT_"+ship.SHIP_ID; } AisContact contact; - if (!contacts.containsKey(mmsi)) { - contact = new AisContact(mmsi); - contacts.put(mmsi, contact); - } - else { - contact = contacts.get(mmsi); - contact.setLastUpdate((long)(ship.TIME * 1000.0)); - contacts.replace(mmsi, contact); + synchronized (lock) { + if (!contacts.containsKey(mmsi)) { + contact = new AisContact(mmsi); + contacts.put(mmsi, contact); + } + else { + contact = contacts.get(mmsi); + contact.setLastUpdate((long) (ship.TIME * 1000.0)); + contacts.replace(mmsi, contact); + } } contact.setLocation(new LocationType(ship.LAT, ship.LON)); contact.setHdg(ship.HEADING); @@ -343,16 +363,26 @@ public void processJson(String sentence) { } public void updateSystem(int mmsi, LocationType loc, double heading,long millis) { - AisContact contact = contacts.get(mmsi); + AisContact contact; + synchronized (lock) { + contact = contacts.get(mmsi); + } + if (contact == null) + return; + String name = contact.getLabel(); ExternalSystem sys = NMEAUtils.getAndRegisterExternalSystem(mmsi, name); sys.setLocation(loc, millis); sys.setAttitudeDegrees(heading > 360 ? contact.getCog() : heading,millis); - if (!dimensionsCache.containsKey(mmsi)) - dimensionsCache.put(mmsi, new HashMap()); - HashMap dimV = dimensionsCache.get(mmsi); + HashMap dimV; + synchronized (lock) { + if (!dimensionsCache.containsKey(mmsi)) { + dimensionsCache.put(mmsi, new HashMap<>()); + } + dimV = dimensionsCache.get(mmsi); + } sys.storeData(SystemUtils.MMSI_KEY, mmsi); @@ -408,50 +438,55 @@ public void updateSystem(int mmsi, LocationType loc, double heading,long millis) } @Override - public synchronized void update(Message arg0) { - int mmsi = arg0.getSourceMmsi(); - switch (arg0.getType()) { - case 1: - if (!contacts.containsKey(mmsi)) - contacts.put(mmsi, new AisContact(mmsi)); - contacts.get(mmsi).update((Message01) arg0); - if (labelCache.containsKey(mmsi)) - contacts.get(mmsi).setLabel(labelCache.get(mmsi)); - updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(),System.currentTimeMillis()); - break; - case 3: - if (!contacts.containsKey(mmsi)) - contacts.put(mmsi, new AisContact(mmsi)); - contacts.get(mmsi).update((Message03) arg0); - if (labelCache.containsKey(mmsi)) - contacts.get(mmsi).setLabel(labelCache.get(mmsi)); - updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(),System.currentTimeMillis()); - break; - case 5: - if (!contacts.containsKey(mmsi)) - contacts.put(mmsi, new AisContact(mmsi)); - contacts.get(mmsi).update((Message05) arg0); - String name = ((Message05) arg0).getVesselName().trim(); - labelCache.put(mmsi, name); - updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(),System.currentTimeMillis()); - break; - default: - NeptusLog.pub().warn("Ignoring AIS message of type " + arg0.getType()); - break; + public void update(Message arg0) { + synchronized (lock) { + int mmsi = arg0.getSourceMmsi(); + switch (arg0.getType()) { + case 1: + if (!contacts.containsKey(mmsi)) + contacts.put(mmsi, new AisContact(mmsi)); + contacts.get(mmsi).update((Message01) arg0); + if (labelCache.containsKey(mmsi)) + contacts.get(mmsi).setLabel(labelCache.get(mmsi)); + updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(), System.currentTimeMillis()); + break; + case 3: + if (!contacts.containsKey(mmsi)) + contacts.put(mmsi, new AisContact(mmsi)); + contacts.get(mmsi).update((Message03) arg0); + if (labelCache.containsKey(mmsi)) + contacts.get(mmsi).setLabel(labelCache.get(mmsi)); + updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(), System.currentTimeMillis()); + break; + case 5: + if (!contacts.containsKey(mmsi)) + contacts.put(mmsi, new AisContact(mmsi)); + contacts.get(mmsi).update((Message05) arg0); + String name = ((Message05) arg0).getVesselName().trim(); + labelCache.put(mmsi, name); + updateSystem(mmsi, contacts.get(mmsi).getLocation(), contacts.get(mmsi).getCog(), System.currentTimeMillis()); + break; + default: + NeptusLog.pub().warn("Ignoring AIS message of type " + arg0.getType()); + break; + } } } public synchronized void purge(long maximumAgeMillis) { Vector toRemove = new Vector<>(); - for (Entry entry : contacts.entrySet()) { - if (entry.getValue().ageMillis() > maximumAgeMillis) - toRemove.add(entry.getKey()); - } + synchronized (lock) { + for (Entry entry : contacts.entrySet()) { + if (entry.getValue().ageMillis() > maximumAgeMillis) { + toRemove.add(entry.getKey()); + } + } - for (int rem : toRemove) { - NeptusLog.pub().debug("Removing " + rem + " because is more than " + maximumAgeMillis + " milliseconds old."); - contacts.remove(rem); + for (int rem : toRemove) { + NeptusLog.pub().debug("Removing " + rem + " because is more than " + maximumAgeMillis + " milliseconds old."); + contacts.remove(rem); + } } } @@ -459,8 +494,8 @@ public synchronized void purge(long maximumAgeMillis) { * @return the contacts */ public Collection getContacts() { - Vector c = new Vector<>(); - c.addAll(this.contacts.values()); - return c; + synchronized (lock) { + return new ArrayList<>(contacts.values()); + } } } From 958f92d0cda569752cacb946998e93e4311c13be Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Wed, 24 Jul 2024 14:35:03 +0100 Subject: [PATCH 3/7] plugins/alliance/NmeaPlotter: Small cleanups. --- .../neptus/plugins/alliance/NmeaPlotter.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/NmeaPlotter.java b/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/NmeaPlotter.java index 29aba446c1..e1749be4a7 100644 --- a/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/NmeaPlotter.java +++ b/plugins-dev/alliance/src/java/pt/lsts/neptus/plugins/alliance/NmeaPlotter.java @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.Map; import javax.swing.BorderFactory; import javax.swing.JLabel; @@ -193,13 +194,13 @@ public class NmeaPlotter extends ConsoleLayer implements NmeaProvider { private boolean isUdpConnected = false; private boolean isTcpConnected = false; - private HashSet listeners = new HashSet<>(); - private AisContactDb contactDb = new AisContactDb(); - private AISParser parser = new AISParser(); + private final HashSet listeners = new HashSet<>(); + private final AisContactDb contactDb = new AisContactDb(); + private final AISParser parser = new AISParser(); private final AisContactManager aisManager = AisContactManager.getInstance(); - private LinkedHashMap lastLocs = new LinkedHashMap<>(); - private LinkedHashMap tracks = new LinkedHashMap<>(); + private final Map lastLocs = new LinkedHashMap<>(); + private final Map tracks = new LinkedHashMap<>(); @Periodic(millisBetweenUpdates = 5000) public void updateTracks() { @@ -435,7 +436,7 @@ public void run() { parseSentence(tk); } catch (Exception e) { - e.printStackTrace(); + NeptusLog.pub().warn("Error parsing sentence: {} :: {}", tk, e.getMessage()); } if (retransmitToNeptus) retransmit(tk); @@ -443,11 +444,11 @@ public void run() { LsfMessageLogger.log(new DevDataText(tk)); } } - catch (SocketTimeoutException e) { - continue; + catch (SocketTimeoutException | SocketException e) { + NeptusLog.pub().warn("Socket closed :: {}", e.getMessage()); } catch (Exception e) { - e.printStackTrace(); + NeptusLog.pub().warn("Socket closed due to error :: {}", e.getMessage()); break; } } @@ -457,7 +458,7 @@ public void run() { socket.close(); } catch (Exception e) { - e.printStackTrace(); + NeptusLog.pub().warn("Error closing socket :: {}", e.getMessage()); } finally { setTcpConnected(false); @@ -623,8 +624,7 @@ public void saveCache() { public void paint(Graphics2D g, StateRenderer2D renderer) { super.paint(g, renderer); - ArrayList els = new ArrayList<>(); - els.addAll(tracks.values()); + ArrayList els = new ArrayList<>(tracks.values()); for (ScatterPointsElement el : els) el.paint((Graphics2D) g.create(), renderer, renderer.getRotation()); From f7cbd1bc26db8b16d33c3a4f9b4b623464ac47eb Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Wed, 24 Jul 2024 14:36:06 +0100 Subject: [PATCH 4/7] plugins/alert-intrusion/AlertIntrusion: Cleanup. --- .../pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java index c8f2e575ba..f326da0cc6 100644 --- a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java +++ b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java @@ -92,13 +92,13 @@ public long getMicroseconds() { } } - @NeptusProperty(name = "Minimum distance allowed between AUVs and Ships (meters)", userLevel = NeptusProperty.LEVEL.REGULAR) + @NeptusProperty(name = "Minimum distance allowed between vehicle and ships (meters)", userLevel = NeptusProperty.LEVEL.REGULAR) public int collisionDistance = 100; @NeptusProperty(name = "Percentage of the critical distance to trigger the alert") public int collisionCriticalDistancePercentage = 20; @NeptusProperty(name = "Use course for calculation", userLevel = NeptusProperty.LEVEL.REGULAR) public boolean useCourseForCalculation = true; - @NeptusProperty(name = "Minimum Speed To Be Stopped", description = "Configures the maximum speed (m/s) for the system to be considered stopped (affects the drawing of the course/speed vector on the renderer)", + @NeptusProperty(name = "Minimum Speed To Be Stopped", description = "Configures the maximum speed (m/s) for the system to be considered stopped.", category = "Renderer", userLevel = NeptusProperty.LEVEL.REGULAR) public double minimumSpeedToBeStopped = 0.2; @NeptusProperty(name = "Minutes To Hide Systems Without Known Location", description = "Minutes after which systems disappear from render if inactive (0 to disable)", From 50bfcf073fcadf5e6d8cfa9f5f8feba30e76c726 Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Wed, 24 Jul 2024 17:32:48 +0100 Subject: [PATCH 5/7] plugins/alert-intrusion/AlertIntrusion: Cleanup. --- .../pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java index f326da0cc6..afcd48eef0 100644 --- a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java +++ b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java @@ -288,7 +288,8 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { if (recreateImage) { Graphics2D g2 = layerPainter.getImageGraphics(); // Paint what you want in the graphics - if (!collisionsTree.isEmpty() && collisionsTree.get(lastMainVehicle) != null && !collisionsTree.get(lastMainVehicle).isEmpty()) { + if (!collisionsTree.isEmpty() && collisionsTree.get(lastMainVehicle) != null + && !collisionsTree.get(lastMainVehicle).isEmpty()) { Graphics2D gg = (Graphics2D) g2.create(); gg.translate(20, 100); boolean res = !gg.drawImage(colregImage, null, null); From a469b70747973e0224d33405b7c25af3a5ffcc54 Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Thu, 25 Jul 2024 12:38:44 +0100 Subject: [PATCH 6/7] plugins/alert-intrusion/AlertIntrusion: Set look indicator for alert ship. --- .../alertintrusion/AlertIntrusion.java | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java index afcd48eef0..080ffd0506 100644 --- a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java +++ b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java @@ -49,6 +49,7 @@ import pt.lsts.neptus.systems.external.ExternalSystem; import pt.lsts.neptus.systems.external.ExternalSystemsHolder; import pt.lsts.neptus.types.coord.LocationType; +import pt.lsts.neptus.util.AngleUtils; import pt.lsts.neptus.util.ColorUtils; import pt.lsts.neptus.util.ImageUtils; import pt.lsts.util.WGS84Utilities; @@ -59,6 +60,7 @@ import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.text.SimpleDateFormat; @@ -92,6 +94,18 @@ public long getMicroseconds() { } } + private static final GeneralPath shapeArrow = new GeneralPath(); + static { + shapeArrow.moveTo(0, 0); + shapeArrow.curveTo(7, -3, 7, -3, 14, 0); + //shapeArrow.lineTo(14, 0); + shapeArrow.lineTo(7, -14); + shapeArrow.lineTo(0, 0); + } + + private final Color shapeColor = new Color(0xFF, 0xD0, 0x46, 100); + private final Color blackTransparentColor = ColorUtils.setTransparencyToColor(Color.black, 100); + @NeptusProperty(name = "Minimum distance allowed between vehicle and ships (meters)", userLevel = NeptusProperty.LEVEL.REGULAR) public int collisionDistance = 100; @NeptusProperty(name = "Percentage of the critical distance to trigger the alert") @@ -123,6 +137,8 @@ public long getMicroseconds() { private final JLabel infoLabel = new JLabel(""); + private final LookIndicatorSymbol lookIndicatorSymbol = new LookIndicatorSymbol(); + public AlertIntrusion() { super(); } @@ -302,11 +318,11 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { infoLabel.setText("# " + collisionSize); infoLabel.setHorizontalTextPosition(JLabel.CENTER); infoLabel.setHorizontalAlignment(JLabel.CENTER); - infoLabel.setBackground(ColorUtils.setTransparencyToColor(Color.black, 100)); + infoLabel.setBackground(blackTransparentColor); infoLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); infoLabel.setOpaque(true); gg = (Graphics2D) g2.create(); - gg.translate(20 + 50 + 2, 100 + 25); + gg.translate(20 + 50 + 5 + 2, 100 + 25); FontMetrics fontMetrics = gg.getFontMetrics(); Rectangle2D rectBounds = fontMetrics.getStringBounds(infoLabel.getText(), gg); infoLabel.setBounds(0, 0, (int) rectBounds.getWidth() + 10, (int) rectBounds.getHeight() + 10); @@ -357,7 +373,7 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { infoLabel.setForeground(Color.white); infoLabel.setHorizontalAlignment(JLabel.LEFT); Graphics2D gg = (Graphics2D) g2.create(); - gg.translate(20, 100 + 50 + 5); + gg.translate(20, 100 + 50 + 5 + 5); FontMetrics fontMetrics = gg.getFontMetrics(); Rectangle2D rectBounds = fontMetrics.getStringBounds(line1, gg); Rectangle2D rectBounds2 = fontMetrics.getStringBounds(line2, gg); @@ -379,7 +395,20 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { loc = esys.getLocation().getNewAbsoluteLatLonDepth(); } } + Point2D indicatorPoint = new Point2D.Double(20 + 25, 100 + 25); if (loc != null) { + Point2D pointShipClosest = renderer.getScreenPosition(loc); + double angleRad = calculateAngleToRotate(indicatorPoint, pointShipClosest); + + Graphics2D gg = (Graphics2D) g2.create(); + gg.translate(20 + 25, 100 + 25); + gg.rotate(Math.PI / 2 + angleRad); + gg.translate( -7,-25 - 2); + gg.setColor(shapeColor); + gg.fill(shapeArrow); + gg.setColor(Color.black); + gg.draw(shapeArrow); + gg.dispose(); } } } @@ -390,4 +419,23 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { renderer.repaint(10); } } + + private double calculateAngleToRotate(Point2D indicatorPoint, Point2D pointShipClosest) { + double angleRad = AngleUtils.nomalizeAngleRadsPi(AngleUtils.calcAngle( + indicatorPoint.getY(), indicatorPoint.getX(), + pointShipClosest.getY(), pointShipClosest.getX())); + double angleDeg = Math.toDegrees(angleRad); + if (angleRad >= 0 && angleRad <= Math.PI / 2) { + angleRad = Math.PI / 4; + } else if (angleRad >= Math.PI / 2 && angleRad <= Math.PI) { + angleRad = 3 *Math.PI / 4; + } else if (angleRad <= 0 && angleRad >= -Math.PI / 2) { + angleRad = -Math.PI / 4; + } else if (angleRad <= -Math.PI / 2 && angleRad >= -Math.PI) { + angleRad = -3 * Math.PI / 4; + } + double angleDeg1 = Math.toDegrees(angleRad); + System.out.println("angleDeg: " + angleDeg + " :: angleDeg1: " + angleDeg1); + return angleRad; + } } From 83934938223aeb4857d30a3011702f53538e614a Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Thu, 25 Jul 2024 13:50:03 +0100 Subject: [PATCH 7/7] plugins/alert-intrusion/AlertIntrusion: Tweak look indicator for alerted ship. --- .../alertintrusion/AlertIntrusion.java | 53 +++++++++++++++---- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java index 080ffd0506..ef05a4731a 100644 --- a/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java +++ b/plugins-dev/alert-intrusion/src/java/pt/lsts/neptus/plugins/alertintrusion/AlertIntrusion.java @@ -97,13 +97,14 @@ public long getMicroseconds() { private static final GeneralPath shapeArrow = new GeneralPath(); static { shapeArrow.moveTo(0, 0); - shapeArrow.curveTo(7, -3, 7, -3, 14, 0); + shapeArrow.curveTo(7, 3, 7, 3, 14, 0); //shapeArrow.lineTo(14, 0); shapeArrow.lineTo(7, -14); shapeArrow.lineTo(0, 0); } - private final Color shapeColor = new Color(0xFF, 0xD0, 0x46, 100); + private final Color shapeColor = new Color(0xFF, 0xD0, 0x46, 203); + private final Color shapeHighColor = new Color(255, 70, 70, 203); private final Color blackTransparentColor = ColorUtils.setTransparencyToColor(Color.black, 100); @NeptusProperty(name = "Minimum distance allowed between vehicle and ships (meters)", userLevel = NeptusProperty.LEVEL.REGULAR) @@ -383,8 +384,11 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { gg.dispose(); } - if (shipClosest.get() != null) { - String sysName = shipClosest.get(); + Point2D indicatorPoint = new Point2D.Double(20 + 25, 100 + 25); + AtomicReference mainlookAngle = new AtomicReference<>((short) 0); + boolean[] lookAngle = {false, false, false, false}; + collisionsTree.get(lastMainVehicle).forEach((time, pair) -> { + String sysName = pair.first(); LocationType loc = null; ImcSystem sys = ImcSystemsHolder.lookupSystemByName(sysName); if (sys != null) { @@ -395,16 +399,38 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { loc = esys.getLocation().getNewAbsoluteLatLonDepth(); } } - Point2D indicatorPoint = new Point2D.Double(20 + 25, 100 + 25); if (loc != null) { Point2D pointShipClosest = renderer.getScreenPosition(loc); - double angleRad = calculateAngleToRotate(indicatorPoint, pointShipClosest); + Pair angleRadAndQuadrant = calculateAngleToRotate(indicatorPoint, pointShipClosest); + if (angleRadAndQuadrant.second() == 0) { + lookAngle[0] = true; + } else if (angleRadAndQuadrant.second() == 1) { + lookAngle[1] = true; + } else if (angleRadAndQuadrant.second() == 2) { + lookAngle[2] = true; + } else if (angleRadAndQuadrant.second() == 3) { + lookAngle[3] = true; + } + if (shipClosest.get() != null) { + String closestSysName = shipClosest.get(); + if (closestSysName.equals(sysName)) { + mainlookAngle.set(angleRadAndQuadrant.second()); + } + } + } + }); + for (int i = 0; i < lookAngle.length; i++) { + if (lookAngle[i]) { Graphics2D gg = (Graphics2D) g2.create(); gg.translate(20 + 25, 100 + 25); - gg.rotate(Math.PI / 2 + angleRad); + gg.rotate(Math.PI / 2 + Math.PI / 4 * (2 * i + 1)); gg.translate( -7,-25 - 2); - gg.setColor(shapeColor); + if (mainlookAngle.get() == i) { + gg.setColor(shapeHighColor); + } else { + gg.setColor(shapeColor); + } gg.fill(shapeArrow); gg.setColor(Color.black); gg.draw(shapeArrow); @@ -412,6 +438,7 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { } } } + layerPainter.paintPhaseEndFinishImageRecreateAndPaintImageCacheToRenderer(g, renderer); if (askForLaterRepaint.get()) { layerPainter.triggerImageRebuild(); @@ -420,22 +447,26 @@ public void paint(Graphics2D g, StateRenderer2D renderer) { } } - private double calculateAngleToRotate(Point2D indicatorPoint, Point2D pointShipClosest) { + private Pair calculateAngleToRotate(Point2D indicatorPoint, Point2D pointShipClosest) { double angleRad = AngleUtils.nomalizeAngleRadsPi(AngleUtils.calcAngle( indicatorPoint.getY(), indicatorPoint.getX(), pointShipClosest.getY(), pointShipClosest.getX())); double angleDeg = Math.toDegrees(angleRad); + short quadrant = 0; if (angleRad >= 0 && angleRad <= Math.PI / 2) { angleRad = Math.PI / 4; } else if (angleRad >= Math.PI / 2 && angleRad <= Math.PI) { - angleRad = 3 *Math.PI / 4; + angleRad = 3 * Math.PI / 4; + quadrant = 1; } else if (angleRad <= 0 && angleRad >= -Math.PI / 2) { angleRad = -Math.PI / 4; + quadrant = 3; } else if (angleRad <= -Math.PI / 2 && angleRad >= -Math.PI) { angleRad = -3 * Math.PI / 4; + quadrant = 2; } double angleDeg1 = Math.toDegrees(angleRad); System.out.println("angleDeg: " + angleDeg + " :: angleDeg1: " + angleDeg1); - return angleRad; + return new Pair<>(angleRad, quadrant); } }