From e30a0c6b088bf0aec63b4945e02533392f5dfef9 Mon Sep 17 00:00:00 2001 From: Miguel Carvalho Date: Mon, 10 Feb 2025 10:43:26 +0000 Subject: [PATCH 1/5] plugins/videoreader/VideoReader: VideoReader now displays vehicle related information regarding its Estimated State. --- .../plugins/videoreader/VideoReader.java | 328 +++++++++++++++--- .../lsts/neptus/util/RenderStringUtils.java | 79 ++++- .../images/above_half_battery_video.png | Bin 0 -> 345 bytes src/resources/images/altitude_video.png | Bin 0 -> 491 bytes .../images/below_half_battery_video.png | Bin 0 -> 343 bytes src/resources/images/depth_video.png | Bin 0 -> 5012 bytes src/resources/images/full_battery_video.png | Bin 0 -> 334 bytes src/resources/images/low_battery_video.png | Bin 0 -> 359 bytes src/resources/images/no_battery_video.png | Bin 0 -> 341 bytes src/resources/images/position_video.png | Bin 0 -> 764 bytes src/resources/images/rpy_video.png | Bin 0 -> 1836 bytes src/resources/images/speed_video.png | Bin 0 -> 1156 bytes 12 files changed, 342 insertions(+), 65 deletions(-) create mode 100644 src/resources/images/above_half_battery_video.png create mode 100644 src/resources/images/altitude_video.png create mode 100644 src/resources/images/below_half_battery_video.png create mode 100644 src/resources/images/depth_video.png create mode 100644 src/resources/images/full_battery_video.png create mode 100644 src/resources/images/low_battery_video.png create mode 100644 src/resources/images/no_battery_video.png create mode 100644 src/resources/images/position_video.png create mode 100644 src/resources/images/rpy_video.png create mode 100644 src/resources/images/speed_video.png diff --git a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java index e2afe8d546..6fce617c1a 100644 --- a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java +++ b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java @@ -32,6 +32,9 @@ */ package pt.lsts.neptus.plugins.videoreader; +import com.google.common.eventbus.Subscribe; +import pt.lsts.imc.EstimatedState; +import pt.lsts.imc.FuelLevel; import pt.lsts.neptus.NeptusLog; import pt.lsts.neptus.console.ConsoleLayout; import pt.lsts.neptus.console.ConsolePanel; @@ -42,8 +45,11 @@ import pt.lsts.neptus.plugins.PluginUtils; import pt.lsts.neptus.plugins.Popup; import pt.lsts.neptus.plugins.update.Periodic; +import pt.lsts.neptus.types.coord.LocationType; import pt.lsts.neptus.util.ImageUtils; +import pt.lsts.neptus.util.RenderStringUtils; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenuItem; @@ -51,11 +57,16 @@ import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.Image; +import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -74,6 +85,13 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import static pt.lsts.neptus.types.coord.CoordinateUtil.latitudeAsPrettyString; +import static pt.lsts.neptus.types.coord.CoordinateUtil.longitudeAsPrettyString; +import static pt.lsts.neptus.util.AngleUtils.nomalizeAngleDegrees180; +import static pt.lsts.neptus.util.AngleUtils.nomalizeAngleDegrees360; +import static pt.lsts.neptus.util.ImageUtils.getImage; +import static pt.lsts.neptus.util.ImageUtils.getScaledImage; + @PluginDescription(name = "Video Reader", version = "0.1", experimental = true, author = "Paulo Dias", description = "Plugin to view IP Camera streams using FFMPEG", icon = "images/menus/camera.png", category = PluginDescription.CATEGORY.INTERFACE) @@ -147,6 +165,42 @@ public Thread newThread(Runnable r) { private final JLabel streamNameJLabel; private final JLabel streamWarnJLabel; + private double lastAspectRatio = (double) widthConsole /heightConsole; + + // JLabel for additional information + private String positionLabel = ""; + private String rpyLabel = ""; + private String velLabel = ""; + private String depthLabel = ""; + private String altitudeLabel = ""; + private String fuelLabel = ""; + + private final Image fuelFullImage = getImage("images/full_battery_video.png"); + private final Image fuelAboveHalfImage = getImage("images/above_half_battery_video.png"); + private final Image fuelBelowHalfImage = getImage("images/below_half_battery_video.png"); + private final Image fuelLowImage = getImage("images/low_battery_video.png"); + private final Image fuelEmptyImage = getImage("images/no_battery_video.png"); + private Image fuelImage = getImage("images/no_battery_video.png"); + private Image fuelIcon = getScaledImage(fuelImage, 18, 18, false); + private final Image positionImage = getImage("images/position_video.png"); + private Image positionIcon = getScaledImage(positionImage, 18, 18, false); + private final Image rpyImage = getImage("images/rpy_video.png"); + private Image rpyIcon = getScaledImage(rpyImage, 18, 18, false); + private final Image velImage = getImage("images/speed_video.png"); + private Image velIcon = getScaledImage(velImage, 18, 18, false); + private final Image depthImage = getImage("images/depth_video.png"); + private Image depthIcon = getScaledImage(depthImage, 18, 18, false); + private final Image altitudeImage = getImage("images/altitude_video.png"); + private Image altitudeIcon = getScaledImage(altitudeImage, 18, 18, false); + + private Image lastFuelImage = fuelImage; + + int infoFontSize = 14; + + JMenuItem showInfoItem; + + private boolean showVehicleInfo = false; + public VideoReader(ConsoleLayout console) { this(console, false); } @@ -155,6 +209,9 @@ public VideoReader(ConsoleLayout console, boolean usedInsideAnotherConsolePanel) super(console, usedInsideAnotherConsolePanel); removeAll(); + + initPopupMenu(); + this.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { @@ -205,6 +262,7 @@ private void updateSize(ComponentEvent evt) { streamWarnJLabel.setHorizontalAlignment(SwingConstants.CENTER); streamWarnJLabel.setVerticalAlignment(SwingConstants.BOTTOM); streamWarnJLabel.setVerticalTextPosition(SwingConstants.BOTTOM); + streamWarnJLabel.setText("⚠"); } @Override @@ -244,15 +302,97 @@ else if (onScreenImageLastGood != null && (onScreenImageLastGood.getWidth() == w streamNameJLabel.setSize((int) widthConsole, (int) bounds.getHeight() + 5); streamNameJLabel.paint(g); + int x = 10; + int y = heightConsole; + int iconSpacing = 5; + double scaleFactor = (double) (Math.min(widthConsole, heightConsole)) / ((double) (DEFAULT_WIDTH_CONSOLE + DEFAULT_HEIGHT_CONSOLE) / 2); + int fontSize = validateFontSize(g, (int) (14 * scaleFactor), positionLabel); + int iconSize = fontSize + 8; + Font font = new Font("Arial", Font.PLAIN, fontSize); + int lineHeight = (int) (fontSize * 2); + + if (showVehicleInfo) { + double aspectRatio = (double) widthConsole / heightConsole; + if (lastAspectRatio != aspectRatio) { + lastAspectRatio = aspectRatio; + + fuelIcon = getScaledImage(fuelImage, iconSize, iconSize, false); + rpyIcon = getScaledImage(rpyImage, iconSize, iconSize, false); + velIcon = getScaledImage(velImage, iconSize, iconSize, false); + depthIcon = getScaledImage(depthImage, iconSize, iconSize, false); + altitudeIcon = getScaledImage(altitudeImage, iconSize, iconSize, false); + positionIcon = getScaledImage(positionImage, iconSize, iconSize, false); + } + + if (lastFuelImage != fuelImage) { + lastFuelImage = fuelImage; + fuelIcon = getScaledImage(fuelImage, iconSize, iconSize, false); + } + + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); // 50% opacity + g2d.setComposite(composite); + g2d.setColor(Color.BLACK); + + int positionLabelWidth = getLabelWidth(g, fontSize, positionLabel); + int leftPanelRectWidth = (3 * x) + positionIcon.getWidth(this) + iconSpacing + positionLabelWidth; //(int) (200 * scaleFactor); + int leftPanelRectHeight = (int) ((lineHeight * 4) + (fontSize)); + g2d.fillRoundRect(-x, y - leftPanelRectHeight, leftPanelRectWidth, leftPanelRectHeight + x, 30, 30); + + int rpyLabelWidth = getLabelWidth(g, fontSize, rpyLabel); + int rightPanelRectWidth = (3 * x) + rpyIcon.getWidth(this) + iconSpacing + rpyLabelWidth; //(int) (200 * scaleFactor); + int rightPanelRectHeight = (int) ((lineHeight * 3) + (fontSize)); + g2d.fillRoundRect(x + widthConsole - rightPanelRectWidth, y - rightPanelRectHeight, rightPanelRectWidth + x, rightPanelRectHeight + x, 30, 30); + + Graphics2D g2dInfo = (Graphics2D) g; + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, fuelLabel, widthConsole, widthConsole, lineHeight * 2, fuelIcon, iconSpacing, lineHeight, true, true, this); + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, velLabel, widthConsole, widthConsole, y - (lineHeight * 2), velIcon, iconSpacing, lineHeight, false, true, this); + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, rpyLabel, widthConsole, widthConsole, y - (lineHeight), rpyIcon, iconSpacing, lineHeight, false, true, this); + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, depthLabel, widthConsole, x, y - (lineHeight * 3), depthIcon, iconSpacing, lineHeight, false, false, this); + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, altitudeLabel, widthConsole, x, y - (lineHeight * 2), altitudeIcon, iconSpacing, lineHeight, false, false, this); + RenderStringUtils.drawStringVideo(g2dInfo, font, Color.WHITE, positionLabel, widthConsole, x, y - (lineHeight), positionIcon, iconSpacing, lineHeight, false, false, this); + + g2dInfo.dispose(); + g2d.dispose(); + } + if (warn) { - String textWarn = "⚠"; - streamWarnJLabel.setText(textWarn); streamWarnJLabel.setSize((int) widthConsole, (int) heightConsole); streamWarnJLabel.paint(g); } } } + private int validateFontSize(Graphics g, int fontSize, String text){ + Graphics2D gTemp = (Graphics2D) g.create(); + Font font = new Font("Arial", Font.PLAIN, fontSize); + gTemp.setFont(font); + gTemp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gTemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + FontMetrics fm = gTemp.getFontMetrics(); + int textWidth = fm.stringWidth(text); + int textHeight = fm.getHeight(); + int res = (textWidth * 100) / widthConsole; + gTemp.dispose(); + if (res > 40) { + return infoFontSize; + } + infoFontSize = fontSize; + return fontSize; + } + + private int getLabelWidth(Graphics g, int fontSize, String text){ + Graphics2D gTemp = (Graphics2D) g.create(); + Font font = new Font("Arial", Font.PLAIN, fontSize); + gTemp.setFont(font); + gTemp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gTemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + FontMetrics fm = gTemp.getFontMetrics(); + gTemp.dispose(); + return fm.stringWidth(text); + } + private boolean isConnect() { return player != null && player.isStreamingActive() && !player.isStopRequest(); } @@ -271,7 +411,7 @@ private boolean isDisconnect() { } private void setupNoVideoImage() { - Image noVideoImage = ImageUtils.getImage(IMAGE_NO_VIDEO); + Image noVideoImage = getImage(IMAGE_NO_VIDEO); if (noVideoImage == null) { BufferedImage blackImage = ImageUtils.createCompatibleImage(1, 1, 255); blackImage.setRGB(0, 0, 0); @@ -280,7 +420,7 @@ private void setupNoVideoImage() { && noVideoImage.getHeight(null) > 0 && widthConsole >= 0 && heightConsole >= 0 //? ImageUtils.getScaledImage(noVideoImage, widthConsole, heightConsole, true) - ? Util.resizeBufferedImage(ImageUtils.toBufferedImage(ImageUtils.getImage("images/novideo.png")), new Dimension(widthConsole, heightConsole)) + ? Util.resizeBufferedImage(ImageUtils.toBufferedImage(getImage("images/novideo.png")), new Dimension(widthConsole, heightConsole)) : noVideoImage; BufferedImage onScreenImage = noVideoImage == null @@ -420,57 +560,77 @@ public void mouseClicked(MouseEvent e) { // } if (e.getButton() == MouseEvent.BUTTON3) { - popup = new JPopupMenu(); - JMenuItem item; - - popup.add(item = new JMenuItem(I18n.text("Connect to stream"), - ImageUtils.createImageIcon("images/menus/camera.png"))) - .addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - openIPCamManagementPanel(); - //service.execute(VideoReader.this::connectStream); - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK)); - - popup.add(item = new JMenuItem(I18n.text("Close stream connection"), - ImageUtils.createImageIcon("images/menus/exit.png"))) - .addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - NeptusLog.pub().info("Closing video stream"); - service.execute(VideoReader.this::disconnectStream); + popup.show((Component) e.getSource(), e.getX(), e.getY()); + } + } + }); + } + + private void initPopupMenu() { + popup = new JPopupMenu(); + JMenuItem item; + + popup.add(item = new JMenuItem(I18n.text("Connect to stream"), + ImageUtils.createImageIcon("images/menus/camera.png"))) + .addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + openIPCamManagementPanel(); + //service.execute(VideoReader.this::connectStream); + } + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK)); + + popup.add(item = new JMenuItem(I18n.text("Close stream connection"), + ImageUtils.createImageIcon("images/menus/exit.png"))) + .addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + NeptusLog.pub().info("Closing video stream"); + service.execute(VideoReader.this::disconnectStream); // noVideoLogoState = false; // isCleanTurnOffCam = true; // state = false; // ipCam = false; // closeCapture(capture); - repaint(500); - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK)); - - popup.addSeparator(); - - popup.add(item = new JMenuItem(I18n.text("Toggle Histogram filter"), - ImageUtils.createImageIcon("images/menus/histogram.png"))) - .addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - histogramFlag = !histogramFlag; - if (player != null) { - player.setHistogramFlag(histogramFlag); - } - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.ALT_MASK)); - - popup.add(item = new JMenuItem(I18n.text("Maximize window"), - ImageUtils.createImageIcon("images/menus/maximize.png"))) - .addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - maximizeVideoStreamPanel(); - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.ALT_MASK)); + repaint(500); + } + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK)); + + popup.addSeparator(); + + popup.add(item = new JMenuItem(I18n.text("Toggle Histogram filter"), + ImageUtils.createImageIcon("images/menus/histogram.png"))) + .addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + histogramFlag = !histogramFlag; + if (player != null) { + player.setHistogramFlag(histogramFlag); + } + } + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.ALT_MASK)); + + popup.add(item = new JMenuItem(I18n.text("Maximize window"), + ImageUtils.createImageIcon("images/menus/maximize.png"))) + .addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + maximizeVideoStreamPanel(); + } + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.ALT_MASK)); + + popup.addSeparator(); + + showInfoItem = new JCheckBoxMenuItem(I18n.text("Show vehicle information")); + + showInfoItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showVehicleInformation(); + } + }); + + popup.add(showInfoItem); + // popup.addSeparator(); @@ -482,10 +642,10 @@ public void actionPerformed(ActionEvent e) { // markSnap.setEnabled(false); // popup.add(markSnap, JMenuItem.CENTER_ALIGNMENT); - popup.show((Component) e.getSource(), e.getX(), e.getY()); - } - } - }); + } + + private void showVehicleInformation() { + showVehicleInfo = !showVehicleInfo; } private void maximizeVideoStreamPanel() { @@ -506,4 +666,64 @@ private void openIPCamManagementPanel() { // JPanel for IPCam Select (MigLayout) ipCamManagementPanel.show(camUrl); } + + @Subscribe + public void on(EstimatedState msg) { + String mainVehicleId = getMainVehicleId(); + if (!msg.getSourceName().equals(mainVehicleId)) + return; + + double latDeg = Math.toDegrees(msg.getLat()); + double lonDeg = Math.toDegrees(msg.getLon()); + LocationType position = new LocationType(latDeg, lonDeg).convertToAbsoluteLatLonDepth(); + String latStr = position.getLatitudeAsPrettyString(); + String lonStr = position.getLongitudeAsPrettyString(); + double roll = nomalizeAngleDegrees180(Math.toDegrees(msg.getPhi())); + String rollStr = String.format("%+04d", (int) roll).replace("+"," "); + double pitch = nomalizeAngleDegrees180(Math.toDegrees(msg.getTheta())); + String pitchStr = String.format("%+04d", (int) pitch).replace("+"," "); + double yaw = nomalizeAngleDegrees360(Math.toDegrees(msg.getPsi())); + String yawStr = String.format("%+04d", (int) yaw).replace("+"," "); + double vel = msg.getVx(); + String velStr = String.format("%+06.2f", vel).replace("+"," "); + if (velStr.equals("-00.00")) { + velStr = " 00.00"; + } + double depth = msg.getDepth(); + double altitude = msg.getAlt(); + + positionLabel = latStr + " / " + lonStr; + rpyLabel = rollStr + "°(R), " + pitchStr + "°(P), " + yawStr + "°(Y)"; + velLabel = velStr + " m/s"; + depthLabel = String.format("%.2f m", depth); + altitudeLabel = String.format("%.2f m", altitude); + } + + @Subscribe + public void on(FuelLevel msg) { + String mainVehicleId = getMainVehicleId(); + if (!msg.getSourceName().equals(mainVehicleId)) + return; + + double fuelLevel = msg.getValue(); + + if (fuelLevel >= 90.0) { + fuelImage = fuelFullImage; + } + else if (fuelLevel >= 60.0) { + fuelImage = fuelAboveHalfImage; + } + else if (fuelLevel >= 40.0) { + fuelImage = fuelBelowHalfImage; + } + + else if (fuelLevel >= 10.0) { + fuelImage = fuelLowImage; + } + else { + fuelImage = fuelEmptyImage; + } + + fuelLabel = String.format("%02d%%", (int) fuelLevel); + } } diff --git a/src/java/pt/lsts/neptus/util/RenderStringUtils.java b/src/java/pt/lsts/neptus/util/RenderStringUtils.java index 4efe15687a..ad5b934e6c 100644 --- a/src/java/pt/lsts/neptus/util/RenderStringUtils.java +++ b/src/java/pt/lsts/neptus/util/RenderStringUtils.java @@ -32,13 +32,20 @@ */ package pt.lsts.neptus.util; +import javax.swing.ImageIcon; +import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Image; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.font.GlyphVector; +import java.awt.image.ImageObserver; public class RenderStringUtils { @@ -59,31 +66,81 @@ private RenderStringUtils() { * @return */ public static void drawStringWOutline(Graphics2D g, Font font, Color textColor, Color outlineColor, String text, double x, double y) { - Graphics2D gtemp = (Graphics2D) g.create(); + Graphics2D gTemp = (Graphics2D) g.create(); try { - gtemp.setFont(font); - gtemp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - gtemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + gTemp.setFont(font); + gTemp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gTemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // Calculate dynamic outline thickness based on font size float outlineThickness = font.getSize() * 0.25f; - GlyphVector glyphVector = font.createGlyphVector(gtemp.getFontRenderContext(), text); + GlyphVector glyphVector = font.createGlyphVector(gTemp.getFontRenderContext(), text); Shape textShape = glyphVector.getOutline((int) (x), (int) (y)); // Draw the outline - gtemp.setColor(outlineColor); - gtemp.setStroke(new BasicStroke(outlineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // Thickness of the outline - gtemp.draw(textShape); + gTemp.setColor(outlineColor); + gTemp.setStroke(new BasicStroke(outlineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // Thickness of the outline + gTemp.draw(textShape); // Draw the fill - gtemp.setColor(textColor); - gtemp.fill(textShape); + gTemp.setColor(textColor); + gTemp.fill(textShape); } catch (Exception e) { e.printStackTrace(); } finally { - gtemp.dispose(); + gTemp.dispose(); + } + } + + public static void drawStringVideo(Graphics2D g, Font font, Color textColor, String text, double widthConsole, double x, double y, Image icon, int iconSpacing, int lineHeight, boolean background, boolean rightSide, ImageObserver io) { + Graphics2D gTemp = (Graphics2D) g.create(); + Graphics2D gBackground = (Graphics2D) g.create(); + try { + gTemp.setFont(font); + gTemp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gTemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + GlyphVector glyphVector = font.createGlyphVector(gTemp.getFontRenderContext(), text); + Shape textShape = glyphVector.getOutline((int) (x) + icon.getWidth(io) + iconSpacing, (int) (y)); + + FontMetrics fm = gTemp.getFontMetrics(); + int textWidth = fm.stringWidth(text); + int textHeight = fm.getHeight(); + + int rectX = -10; + int rectY = (int) ((int) y - (icon.getHeight(io) * 0.7) - ((double) lineHeight / 10)); + int rectWidth = (int) (x + icon.getWidth(io) + iconSpacing + textWidth) + (-2 * rectX); + int rectHeight = (int) (icon.getHeight(io) + ((double) lineHeight / 5)); + + if (rightSide) { + textShape = glyphVector.getOutline((float) ((int) (x) - textWidth - 10) , (int) (y)); + rectX = (int) x - icon.getWidth(io) - textWidth - (iconSpacing) - (-2 * rectX); + } + + if (background) { + AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); // 50% opacity + gBackground.setComposite(composite); + gBackground.setColor(Color.BLACK); + gBackground.fillRoundRect(rectX, rectY, rectWidth, rectHeight, 20, 20); + } + + gTemp.setColor(textColor); + gTemp.fill(textShape); + + if (rightSide) { + gTemp.drawImage(icon, (int) x - icon.getWidth(io) - textWidth - (iconSpacing) - 10, (int) ((int) y - (icon.getHeight(io) * 0.7)), io); + } + else { + gTemp.drawImage(icon, (int) x, (int) ((int) y - (icon.getHeight(io) * 0.7)), io); + } + } + catch (Exception e) { + e.printStackTrace(); + } finally { + gBackground.dispose(); + gTemp.dispose(); } } } diff --git a/src/resources/images/above_half_battery_video.png b/src/resources/images/above_half_battery_video.png new file mode 100644 index 0000000000000000000000000000000000000000..e698e004a8a950ba8917e0bc71eecace7764cadc GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wk0|O(s zr;B4q#hkY{qxl#e1zI20CGzWWC#knwP2`@jL$^ux!QbhA$C}d?Mfn)rE#CLN%PMrP zN7fu+K`>xmzY>&bi9`SZ literal 0 HcmV?d00001 diff --git a/src/resources/images/altitude_video.png b/src/resources/images/altitude_video.png new file mode 100644 index 0000000000000000000000000000000000000000..c57d7368dfb277c93e5e52ee1105a527035b209a GIT binary patch literal 491 zcmVJNRCt{2*-eTRK@f)FL`0djYxjBqWezal-`<6Ifw_Zw!4r5A z_ZH(13X0%%M(B;`PElM8Jd%JV|+K9 z6WmP^z!m&9o>htfuHx6?g=FvuUq^^I#+`qMG%A53bQ{)g;}bsT=b`&|N-hE~&&2ld z45vLCotD_%dHchF_r2o#LNf2tQo!3{r~RIg{SteVB4JB!uT|7KuR7a$dw`I*y)r~d zctjOqpqGaVv8!Gg>g5qax{$pR)>?}fVx)J+3UN`rGS<5jgmj^LC7iVuFT_NzP8Fh7 zuT1r71tDFCUI}BZZNLNk#1mXPPe{%wxp~jMbdea~&0I|H2KWNkHVMgVC1-tWykEPX zssE`C@U0a11-H%$$+5Dgl8jUnJe*wd{gyL~+=YjwL002ovPDHLkV1k>c+ZF%- literal 0 HcmV?d00001 diff --git a/src/resources/images/below_half_battery_video.png b/src/resources/images/below_half_battery_video.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6eeb8e06803cb5ad4c7cf7e061aa720b4c5477 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wk0|O(c zr;B4q#hkY{ee(_(2(%^U-?Db7T2Le`U>W<6Yf8s{=OyMIyXq${-EbiH2uq|=*}io9 zOEt!Ey>o>H!GQUJtVSc(kJLXk{nZI?tL3H2_+mV+OU~fE`KI;D+y-;+2a{^n=rpcg z@Zz+6p?Q%5V@}h({kpBW0Uf2F zss$O7onGj@`8HGe-mDs(we3HQUs})L`#A6avKM;aS6a>5AC>o~gTe~DWM4fJa&~v literal 0 HcmV?d00001 diff --git a/src/resources/images/depth_video.png b/src/resources/images/depth_video.png new file mode 100644 index 0000000000000000000000000000000000000000..8df2ee5649ea826dff22e0c177ef9d68c8d7be5b GIT binary patch literal 5012 zcmeHKX;c$g7OoI+!L3D62WX8^RK!XuAq7c66eJ)~qY$Ei%V<%lEJ7Bu5EgYBcLf(f zTTnn9Tw1^lcNE3lhQV_>>NhKUto@dT(hcmSHT9uSSv0fW{} zwxQ7>I#^o+hCPre9cnnzY^`$=kexc@tw0{%p+nhlXf{xPFlT_l1@aIu=YXMJ+kVys zAXA^-)~}}xWYy@Lr-~&(3@(dd?z;o#|#!=1>0q&XEoqf<~3w z9m3M)H`_`aQ-%zidg)|!^^J&%OV`3fdxiRb^#`+tRBi4;oS7RvhYTw zmyfCIYT7S+GL+?_Dj%eh2*% zX|!bi_x;MoRxz?3p6Gw85sR;uUFFO!b6t2dKF?6~EU&^b&p4~~vOaiW_)DyG{JpTN_G8us-SKfi9|YdX zNsSmay~TB8TiToLH}`GHwF}r}TfWCP`a|_U-kzJ6%R_5iR)_esB|cx8M5mwgIakAf za${53B-)DGMcb+x@6Ri$8&^|$c&L}nn$ro1Zw~LTqiy#pdYw9IXTF=Q+HRly+vNdI zWKe)M;m(fx^OPeG4D{JlQ2ZF`wYErr5f@1aEsQ4rXaLgT(4SfuWwCmaEhUXQvw#o9?3@tE<(aY1j2!N91ai0Q9cUG2~R|!AW)Dh zv>TLIYc%0nf~24TI7~*^dF})cj_^d~u!n#k-Emxi;_m!z5VH(w zP?dO8cdsZYIe_92o&pX*@L@j57r;D)TmVPN2?5L{d3+S*ptzjyutLcREI?<_;2@o9 z4Xz~FdacsBK@pDm28o4CE(`g%5)_4-6u>~poT1j5V?J)k)EY9xgi~yCJl*-IrvOC} z4iDvV+&?PKAq_@Qi4>-_by|0*v|u0@KrBwxDFCppgIF*>1Bsh-2ANJ5C1iFr-L7p3 zxK481go|(!2|&Bru&lEUyCDdMw7XBiNpy0xBKCi2QAEVUPtHfYfF9n7Z?I9TPXi{$V6JWJ(5h`4(BtiG+DA&$)^`DdikBm^@TmpsN zxgK(mKLHmO;HUuRE4cg!u7Ho=WP4Oy=tiBwWWf!juM+SGxB}&A{R71qZ%vfzr@mNJ zB$Wj~7>saX#Jz(s6zL$0-4QUG>KUC8d$a$G6K|_Rw>!e!tN5g|5$H;Iov!RM!`}K8u0RQvOn1|2MkqKE6(oTJT?x1-vZ9 ztvMMEUbK2fOrI)(+NkgD!UL&brH?)^+z3H^2UCLv?Z^PHYEUneSmNKS#)fVObM@b( zR6-D)D;D|6R8>Ex7bb2E9kO;;OFiGM;9-Sr-{6~zTj|GUr)(K38s#77|@_%V|yteQPq1&(e*>#98^i-ImylnyU#=4`%}5w4hAZmDXybtcI8w zr`xjV@!z~$Cwk$acY1GsCUhxOuJ1E9;bfWc&V&GHZd1apgw-zjxvmVSCvnOXe9iy2#Gm)5UoKG>WZw@`EN=kai3 zR^0r`gB}wC3jTPX!{4iwHRW8)`K|Wr#j7Wf&F?mdGNH82bX8J?i&$uI(KlxlT%siq7n<%tBezyon<>$zRa+hqVpO~E(TzqI(=A>EK@`vmz$#dUr+i@!- z_Fd$I&>vU*$f)z2=Cf$j))~1_o1(7xL&kvp&y}w6Hax1%et*HSt+YJu$?#QvwL=@F zk4s-wga*INu1_f-7x3SnI(K63cg9+Az!Kh9qK7?ivL7V^4)l(=_U;d+6aT z{87>7BJ=KT(#7{nH_FQL1>#rc^I?19>6sbRo4)`3+JBG$CAj2BR8J!`C$KT<)&xb?ZJhD#Qrlyho>xB@gMDPJBa`Q literal 0 HcmV?d00001 diff --git a/src/resources/images/full_battery_video.png b/src/resources/images/full_battery_video.png new file mode 100644 index 0000000000000000000000000000000000000000..7b49f06fde608ecc218d1c263f87b9c452a085bb GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wk0|O(2 zr;B4q#hkY{Pp>^>Akdnazr&VcyTS_=maB}q41(*GoY)WibD!2EAl6|hbg1wA_W2op z$4(}_nbQFV5)AbRL{>C#zx-^wuCepItyvDg#f0^?7kX#DY5eoHp-=V0ly4HzOyQ0f z&&U@}w^+b`rukm@v_r)KSITEH{A<4FKW!1ap7F)M!qFGL9Z+#=WIpOQW4E$_j^>8& z>0%PB`!2Q!FIJYlU>@_rf3==w0WVLK{EwwK*#F(S&b-{O@jj#9(zO+<7G%tGexdf} z(PY(oE#D*}#XnYm+HR=($hO}1V$Qqbt)}r?@BG;Q*!=r}Pbb$|xjtWZePZP%B?wrj a6TaPiqMw-f;c8$2F?hQAxvXTi>zVKLr!d)l$n@vEm%U|2aK$=c$T4`j`njxgN@xNA(@L2j literal 0 HcmV?d00001 diff --git a/src/resources/images/no_battery_video.png b/src/resources/images/no_battery_video.png new file mode 100644 index 0000000000000000000000000000000000000000..d380cc80a0324a18bfd42b7bd3c3089491b87706 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wk0|O(w zr;B4q#hkY{59S_n5NLh4SH+e=Q=^2b>6L=6fR2#Hp_dFh{$KR!UbJRI*|f>&mG}R8 zezy6RD$~>f1`-VG4@kXe(0(kQeusIrMRo2?&4NSgl?_(je8c&FU!%D9L({hrQC#Jb z8N%@&4T=u%+(_G8AJsHn$AsIDA^+x^bnh4QANYLzbA`>#t=0QNTdic2M15UDrQwBu zhb#2i_DIZ{zc5bgO^?}}1>sf~&F?%jza!4fEBdbSd(wgKS3d(2}BP7SCdOTH|w35 gEh-2Goadj4Tk-GM)-~0N2N+Hap00i_>zopr0MdYsQ2+n{ literal 0 HcmV?d00001 diff --git a/src/resources/images/position_video.png b/src/resources/images/position_video.png new file mode 100644 index 0000000000000000000000000000000000000000..739dfe98d005a3e9cf286446b814c711cbe62156 GIT binary patch literal 764 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 Date: Wed, 12 Feb 2025 13:50:26 +0000 Subject: [PATCH 2/5] plugins/videoreader/VideoReader: Replaced the notation from Y (Yaw) to H (Heading). --- .../java/pt/lsts/neptus/plugins/videoreader/VideoReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java index 6fce617c1a..0d49c96349 100644 --- a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java +++ b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java @@ -693,7 +693,7 @@ public void on(EstimatedState msg) { double altitude = msg.getAlt(); positionLabel = latStr + " / " + lonStr; - rpyLabel = rollStr + "°(R), " + pitchStr + "°(P), " + yawStr + "°(Y)"; + rpyLabel = rollStr + "°(R), " + pitchStr + "°(P), " + yawStr + "°(H)"; velLabel = velStr + " m/s"; depthLabel = String.format("%.2f m", depth); altitudeLabel = String.format("%.2f m", altitude); From 865e557c104531f0ae3e7a49961d07634a7ad97d Mon Sep 17 00:00:00 2001 From: Miguel Carvalho Date: Fri, 14 Feb 2025 16:27:26 +0000 Subject: [PATCH 3/5] plugins/videoreader/VideoReader: Updated images path to plugin folder. --- .../resources/images/above_half_battery_video.png | Bin .../src}/resources/images/altitude_video.png | Bin .../resources/images/below_half_battery_video.png | Bin .../src}/resources/images/depth_video.png | Bin .../src}/resources/images/full_battery_video.png | Bin .../src}/resources/images/low_battery_video.png | Bin .../src}/resources/images/no_battery_video.png | Bin .../src}/resources/images/position_video.png | Bin .../videoreader/src}/resources/images/rpy_video.png | Bin .../src}/resources/images/speed_video.png | Bin 10 files changed, 0 insertions(+), 0 deletions(-) rename {src => plugins-dev/videoreader/src}/resources/images/above_half_battery_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/altitude_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/below_half_battery_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/depth_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/full_battery_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/low_battery_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/no_battery_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/position_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/rpy_video.png (100%) rename {src => plugins-dev/videoreader/src}/resources/images/speed_video.png (100%) diff --git a/src/resources/images/above_half_battery_video.png b/plugins-dev/videoreader/src/resources/images/above_half_battery_video.png similarity index 100% rename from src/resources/images/above_half_battery_video.png rename to plugins-dev/videoreader/src/resources/images/above_half_battery_video.png diff --git a/src/resources/images/altitude_video.png b/plugins-dev/videoreader/src/resources/images/altitude_video.png similarity index 100% rename from src/resources/images/altitude_video.png rename to plugins-dev/videoreader/src/resources/images/altitude_video.png diff --git a/src/resources/images/below_half_battery_video.png b/plugins-dev/videoreader/src/resources/images/below_half_battery_video.png similarity index 100% rename from src/resources/images/below_half_battery_video.png rename to plugins-dev/videoreader/src/resources/images/below_half_battery_video.png diff --git a/src/resources/images/depth_video.png b/plugins-dev/videoreader/src/resources/images/depth_video.png similarity index 100% rename from src/resources/images/depth_video.png rename to plugins-dev/videoreader/src/resources/images/depth_video.png diff --git a/src/resources/images/full_battery_video.png b/plugins-dev/videoreader/src/resources/images/full_battery_video.png similarity index 100% rename from src/resources/images/full_battery_video.png rename to plugins-dev/videoreader/src/resources/images/full_battery_video.png diff --git a/src/resources/images/low_battery_video.png b/plugins-dev/videoreader/src/resources/images/low_battery_video.png similarity index 100% rename from src/resources/images/low_battery_video.png rename to plugins-dev/videoreader/src/resources/images/low_battery_video.png diff --git a/src/resources/images/no_battery_video.png b/plugins-dev/videoreader/src/resources/images/no_battery_video.png similarity index 100% rename from src/resources/images/no_battery_video.png rename to plugins-dev/videoreader/src/resources/images/no_battery_video.png diff --git a/src/resources/images/position_video.png b/plugins-dev/videoreader/src/resources/images/position_video.png similarity index 100% rename from src/resources/images/position_video.png rename to plugins-dev/videoreader/src/resources/images/position_video.png diff --git a/src/resources/images/rpy_video.png b/plugins-dev/videoreader/src/resources/images/rpy_video.png similarity index 100% rename from src/resources/images/rpy_video.png rename to plugins-dev/videoreader/src/resources/images/rpy_video.png diff --git a/src/resources/images/speed_video.png b/plugins-dev/videoreader/src/resources/images/speed_video.png similarity index 100% rename from src/resources/images/speed_video.png rename to plugins-dev/videoreader/src/resources/images/speed_video.png From 368619dceecb4b11daeb7f119a3f5a18ce1e2fe8 Mon Sep 17 00:00:00 2001 From: Miguel Carvalho Date: Wed, 26 Feb 2025 09:41:56 +0000 Subject: [PATCH 4/5] plugins/videoreader/VideoReader: Vehicle position is now properly converted to absolute. | Vehicle speed displayed is now properly computed. | Latitude and longitude notation is now changed at the same time as general preferences are saved. --- .../plugins/videoreader/VideoReader.java | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java index 0d49c96349..1397b46e72 100644 --- a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java +++ b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java @@ -38,6 +38,7 @@ import pt.lsts.neptus.NeptusLog; import pt.lsts.neptus.console.ConsoleLayout; import pt.lsts.neptus.console.ConsolePanel; +import pt.lsts.neptus.console.events.ConsoleEventMainSystemChange; import pt.lsts.neptus.console.notifications.Notification; import pt.lsts.neptus.i18n.I18n; import pt.lsts.neptus.plugins.NeptusProperty; @@ -45,9 +46,12 @@ import pt.lsts.neptus.plugins.PluginUtils; import pt.lsts.neptus.plugins.Popup; import pt.lsts.neptus.plugins.update.Periodic; +import pt.lsts.neptus.types.coord.CoordinateUtil; import pt.lsts.neptus.types.coord.LocationType; import pt.lsts.neptus.util.ImageUtils; import pt.lsts.neptus.util.RenderStringUtils; +import pt.lsts.neptus.util.conf.GeneralPreferences; +import pt.lsts.neptus.util.conf.PreferencesListener; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; @@ -85,8 +89,6 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; -import static pt.lsts.neptus.types.coord.CoordinateUtil.latitudeAsPrettyString; -import static pt.lsts.neptus.types.coord.CoordinateUtil.longitudeAsPrettyString; import static pt.lsts.neptus.util.AngleUtils.nomalizeAngleDegrees180; import static pt.lsts.neptus.util.AngleUtils.nomalizeAngleDegrees360; import static pt.lsts.neptus.util.ImageUtils.getImage; @@ -96,7 +98,7 @@ description = "Plugin to view IP Camera streams using FFMPEG", icon = "images/menus/camera.png", category = PluginDescription.CATEGORY.INTERFACE) @Popup(name = "Video Reader", width = 640, height = 480, icon = "images/menus/camera.png") -public class VideoReader extends ConsolePanel { +public class VideoReader extends ConsolePanel implements PreferencesListener { static final String BASE_FOLDER_FOR_URL_INI = "ipUrl.ini"; private static final int DEFAULT_WIDTH_CONSOLE = 640; @@ -195,12 +197,15 @@ public Thread newThread(Runnable r) { private Image lastFuelImage = fuelImage; - int infoFontSize = 14; + private int infoFontSize = 14; - JMenuItem showInfoItem; + private JMenuItem showInfoItem; private boolean showVehicleInfo = false; + private double positionLatDeg = Double.NaN; + private double positionLonDeg = Double.NaN; + public VideoReader(ConsoleLayout console) { this(console, false); } @@ -267,12 +272,14 @@ private void updateSize(ComponentEvent evt) { @Override public void initSubPanel() { + GeneralPreferences.addPreferencesListener(this); service.execute(Util::createIpUrlFile); //setMainVehicle(getConsole().getMainSystem()); } @Override public void cleanSubPanel() { + GeneralPreferences.removePreferencesListener(this); closingPanel = true; service.shutdown(); disconnectStream(); @@ -364,6 +371,17 @@ else if (onScreenImageLastGood != null && (onScreenImageLastGood.getWidth() == w } } + @Subscribe + public void mainVehicleChangeNotification(ConsoleEventMainSystemChange evt) { + fuelLabel = ""; + velLabel = ""; + rpyLabel = ""; + depthLabel = ""; + altitudeLabel = ""; + positionLabel = ""; + fuelImage = fuelEmptyImage; + } + private int validateFontSize(Graphics g, int fontSize, String text){ Graphics2D gTemp = (Graphics2D) g.create(); Font font = new Font("Arial", Font.PLAIN, fontSize); @@ -372,7 +390,6 @@ private int validateFontSize(Graphics g, int fontSize, String text){ gTemp.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); FontMetrics fm = gTemp.getFontMetrics(); int textWidth = fm.stringWidth(text); - int textHeight = fm.getHeight(); int res = (textWidth * 100) / widthConsole; gTemp.dispose(); if (res > 40) { @@ -675,7 +692,13 @@ public void on(EstimatedState msg) { double latDeg = Math.toDegrees(msg.getLat()); double lonDeg = Math.toDegrees(msg.getLon()); - LocationType position = new LocationType(latDeg, lonDeg).convertToAbsoluteLatLonDepth(); + LocationType position = new LocationType(latDeg, lonDeg); + position.setOffsetNorth(msg.getX()); + position.setOffsetEast(msg.getY()); + position.setOffsetDown(msg.getZ()); + position.convertToAbsoluteLatLonDepth(); + positionLatDeg = position.getLatitudeDegs(); + positionLonDeg = position.getLongitudeDegs(); String latStr = position.getLatitudeAsPrettyString(); String lonStr = position.getLongitudeAsPrettyString(); double roll = nomalizeAngleDegrees180(Math.toDegrees(msg.getPhi())); @@ -684,7 +707,9 @@ public void on(EstimatedState msg) { String pitchStr = String.format("%+04d", (int) pitch).replace("+"," "); double yaw = nomalizeAngleDegrees360(Math.toDegrees(msg.getPsi())); String yawStr = String.format("%+04d", (int) yaw).replace("+"," "); - double vel = msg.getVx(); + double vx = msg.getVx(); + double vy = msg.getVy(); + double vel = Math.sqrt(Math.pow(vx,2) + Math.pow(vy,2)); String velStr = String.format("%+06.2f", vel).replace("+"," "); if (velStr.equals("-00.00")) { velStr = " 00.00"; @@ -726,4 +751,15 @@ else if (fuelLevel >= 10.0) { fuelLabel = String.format("%02d%%", (int) fuelLevel); } + + @Override + public void preferencesUpdated() { + if (showVehicleInfo) { + if (!Double.isNaN(positionLatDeg) && !Double.isNaN(positionLonDeg)) { + String latStr = CoordinateUtil.latitudeAsPrettyString(positionLatDeg); + String lonStr = CoordinateUtil.latitudeAsPrettyString(positionLonDeg); + positionLabel = latStr + " / " + lonStr; + } + } + } } From 3d9b9ea5320a2fdc9ac3291562000a29bae7a2e6 Mon Sep 17 00:00:00 2001 From: Paulo Dias Date: Wed, 26 Feb 2025 15:51:47 +0000 Subject: [PATCH 5/5] plugins/videoreader/VideoReader: Fix longitude format call. --- .../java/pt/lsts/neptus/plugins/videoreader/VideoReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java index 1397b46e72..f32acd9cbb 100644 --- a/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java +++ b/plugins-dev/videoreader/src/java/pt/lsts/neptus/plugins/videoreader/VideoReader.java @@ -757,7 +757,7 @@ public void preferencesUpdated() { if (showVehicleInfo) { if (!Double.isNaN(positionLatDeg) && !Double.isNaN(positionLonDeg)) { String latStr = CoordinateUtil.latitudeAsPrettyString(positionLatDeg); - String lonStr = CoordinateUtil.latitudeAsPrettyString(positionLonDeg); + String lonStr = CoordinateUtil.longitudeAsPrettyString(positionLonDeg); positionLabel = latStr + " / " + lonStr; } }