]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miio] add new map elements (#8637)
authorMarcel <marcelrv@users.noreply.github.com>
Sun, 4 Oct 2020 16:35:59 +0000 (18:35 +0200)
committerGitHub <noreply@github.com>
Sun, 4 Oct 2020 16:35:59 +0000 (09:35 -0700)
* [miio] add new map elements

Add newly found mapelements for obstacles

Signed-off-by: Marcel Verpaalen marcel@verpaalen.com
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapDraw.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapFileParser.java

index 851215bc123b2dec365f967e4b8a7df0e1f64f3a..2ba7c20eb7f50b7449501dc192cf0cb1f0001fe4 100644 (file)
@@ -33,6 +33,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import javax.imageio.ImageIO;
 
@@ -78,8 +82,8 @@ public class RRMapDraw {
     private static final Color ROOM9 = new Color(0xFc, 0xD4, 0x51);
     private static final Color ROOM10 = new Color(72, 201, 176);
     private static final Color ROOM11 = new Color(84, 153, 199);
-    private static final Color ROOM12 = new Color(133, 193, 233);
-    private static final Color ROOM13 = new Color(245, 176, 65);
+    private static final Color ROOM12 = new Color(255, 213, 209);
+    private static final Color ROOM13 = new Color(228, 228, 215);
     private static final Color ROOM14 = new Color(82, 190, 128);
     private static final Color ROOM15 = new Color(72, 201, 176);
     private static final Color ROOM16 = new Color(165, 105, 189);
@@ -132,6 +136,7 @@ public class RRMapDraw {
      */
     private void drawMap(Graphics2D g2d, float scale) {
         Stroke stroke = new BasicStroke(1.1f * scale);
+        Set<Integer> roomIds = new HashSet<Integer>();
         g2d.setStroke(stroke);
         for (int y = 0; y < rmfp.getImgHeight() - 1; y++) {
             for (int x = 0; x < rmfp.getImgWidth() + 1; x++) {
@@ -160,7 +165,8 @@ public class RRMapDraw {
                                 g2d.setColor(Color.BLACK);
                                 break;
                             case 7:
-                                g2d.setColor(ROOM_COLORS[Math.round(mapId / 2)]);
+                                g2d.setColor(ROOM_COLORS[mapId % 15]);
+                                roomIds.add(mapId);
                                 multicolor = true;
                                 break;
                             default:
@@ -173,6 +179,13 @@ public class RRMapDraw {
                 g2d.draw(new Line2D.Float(xPos, yP, xPos, yP));
             }
         }
+        if (logger.isDebugEnabled() && roomIds.size() > 0) {
+            StringBuilder sb = new StringBuilder();
+            for (Integer r : roomIds) {
+                sb.append(" " + r.toString());
+            }
+            logger.debug("Identified rooms in map:{}", sb.toString());
+        }
     }
 
     /**
@@ -275,20 +288,44 @@ public class RRMapDraw {
         g2d.setColor(COLOR_CHARGER_HALO);
         final float chargerX = toXCoord(rmfp.getChargerX()) * scale;
         final float chargerY = toYCoord(rmfp.getChargerY()) * scale;
-        drawCircle(g2d, chargerX, chargerY, radius);
+        drawCircle(g2d, chargerX, chargerY, radius, false);
         drawCenteredImg(g2d, scale / 8, "charger.png", chargerX, chargerY);
         radius = 3 * scale;
         g2d.setColor(COLOR_ROBO);
         final float roboX = toXCoord(rmfp.getRoboX()) * scale;
         final float roboY = toYCoord(rmfp.getRoboY()) * scale;
-        drawCircle(g2d, roboX, roboY, radius);
+        drawCircle(g2d, roboX, roboY, radius, false);
         if (scale > 1.5) {
             drawCenteredImg(g2d, scale / 15, "robo.png", roboX, roboY);
         }
     }
 
-    private void drawCircle(Graphics2D g2d, float x, float y, float radius) {
-        g2d.draw(new Ellipse2D.Double(x - radius, y - radius, 2.0 * radius, 2.0 * radius));
+    private void drawObstacles(Graphics2D g2d, float scale) {
+        float radius = 2 * scale;
+        Stroke stroke = new BasicStroke(3 * scale);
+        g2d.setStroke(stroke);
+        g2d.setColor(Color.MAGENTA);
+
+        Map<Integer, ArrayList<int[]>> obstacleMap = rmfp.getObstacles();
+        for (ArrayList<int[]> obstacles : obstacleMap.values()) {
+            obstacles.forEach(obstacle -> {
+                final float obstacleX = toXCoord(obstacle[0]) * scale;
+                final float obstacleY = toYCoord(obstacle[1]) * scale;
+                drawCircle(g2d, obstacleX, obstacleY, radius, true);
+                if (scale > 1.0) {
+                    drawCenteredImg(g2d, scale / 3, "obstacle-" + obstacle[2] + ".png", obstacleX, obstacleY + 15);
+                }
+            });
+        }
+    }
+
+    private void drawCircle(Graphics2D g2d, float x, float y, float radius, boolean fill) {
+        Ellipse2D.Double circle = new Ellipse2D.Double(x - radius, y - radius, 2.0 * radius, 2.0 * radius);
+        if (fill) {
+            g2d.fill(circle);
+        } else {
+            g2d.draw(circle);
+        }
     }
 
     private void drawCenteredImg(Graphics2D g2d, float scale, String imgFile, float x, float y) {
@@ -296,10 +333,10 @@ public class RRMapDraw {
         try {
             if (image != null) {
                 BufferedImage addImg = ImageIO.read(image);
-                int xpos = Math.round(x - (addImg.getWidth() / 2 * scale));
-                int ypos = Math.round(y - (addImg.getHeight() / 2 * scale));
+                int xpos = Math.round(x + (addImg.getWidth() / 2 * scale));
+                int ypos = Math.round(y + (addImg.getHeight() / 2 * scale));
                 AffineTransform at = new AffineTransform();
-                at.scale(scale, scale);
+                at.scale(-scale, -scale);
                 AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
                 g2d.drawImage(addImg, scaleOp, xpos, ypos);
             } else {
@@ -410,6 +447,7 @@ public class RRMapDraw {
         drawPath(g2d, scale);
         drawRobo(g2d, scale);
         drawGoTo(g2d, scale);
+        drawObstacles(g2d, scale);
         g2d = bi.createGraphics();
         drawOpenHabRocks(g2d, width, height, scale);
         return bi;
index 129c3c316988b5fab7e5e10dcce9e82e1b0bd24c..a26cd99d05baf42d896a2d63c2aa87abc576dea0 100644 (file)
@@ -52,6 +52,11 @@ public class RRMapFileParser {
     public static final int BLOCKS = 11;
     public static final int MFBZS_AREA = 12;
     public static final int OBSTACLES = 13;
+    public static final int IGNORED_OBSTACLES = 14;
+    public static final int OBSTACLES2 = 15;
+    public static final int IGNORED_OBSTACLES2 = 16;
+    public static final int CARPET_MAP = 17;
+
     public static final int DIGEST = 1024;
     public static final int HEADER = 0x7272;
 
@@ -84,8 +89,9 @@ public class RRMapFileParser {
     private Map<Integer, ArrayList<float[]>> areas = new HashMap<>();
     private ArrayList<float[]> walls = new ArrayList<>();
     private ArrayList<float[]> zones = new ArrayList<>();
-    private ArrayList<int[]> obstacles = new ArrayList<>();
+    private Map<Integer, ArrayList<int[]>> obstacles = new HashMap<>();
     private byte[] blocks = new byte[0];
+    private int[] carpetMap = {};
 
     private final Logger logger = LoggerFactory.getLogger(RRMapFileParser.class);
 
@@ -192,12 +198,62 @@ public class RRMapFileParser {
                     areas.put(Integer.valueOf(blocktype & 0xFF), area);
                     break;
                 case OBSTACLES:
+                case IGNORED_OBSTACLES:
                     int obstaclePairs = getUInt16(header, 0x08);
+                    ArrayList<int[]> obstacle = new ArrayList<>();
                     for (int obstaclePair = 0; obstaclePair < obstaclePairs; obstaclePair++) {
                         int x0 = getUInt16(data, obstaclePair * 5 + 0);
                         int y0 = getUInt16(data, obstaclePair * 5 + 2);
                         int u = data[obstaclePair * 5 + 0] & 0xFF;
-                        obstacles.add(new int[] { x0, y0, u });
+                        obstacle.add(new int[] { x0, y0, u });
+                    }
+                    obstacles.put(Integer.valueOf(blocktype & 0xFF), obstacle);
+                    break;
+                case OBSTACLES2:
+                    int obstacle2Pairs = getUInt16(header, 0x08);
+                    if (obstacle2Pairs == 0) {
+                        break;
+                    }
+                    int obstacleDataLenght = blockDataLength / obstacle2Pairs;
+                    logger.trace("block 15 records lenght: {}", obstacleDataLenght);
+                    ArrayList<int[]> obstacle2 = new ArrayList<>();
+                    for (int obstaclePair = 0; obstaclePair < obstacle2Pairs; obstaclePair++) {
+                        int x0 = getUInt16(data, obstaclePair * obstacleDataLenght + 0);
+                        int y0 = getUInt16(data, obstaclePair * obstacleDataLenght + 2);
+                        int u0 = getUInt16(data, obstaclePair * obstacleDataLenght + 4);
+                        int u1 = getUInt16(data, obstaclePair * obstacleDataLenght + 6);
+                        int u2 = getUInt32LE(data, obstaclePair * obstacleDataLenght + 8);
+                        if (obstacleDataLenght == 28) {
+                            if ((data[obstaclePair * obstacleDataLenght + 12] & 0xFF) == 0) {
+                                logger.trace("obstacle with photo: No text");
+                            } else {
+                                byte[] txt = getBytes(data, obstaclePair * obstacleDataLenght + 12, 16);
+                                logger.trace("obstacle with photo: {}", new String(txt));
+                            }
+                            obstacle2.add(new int[] { x0, y0, u0, u1, u2 });
+                        } else {
+                            int u3 = getUInt32LE(data, obstaclePair * obstacleDataLenght + 12);
+                            obstacle2.add(new int[] { x0, y0, u0, u1, u2, u3 });
+                            logger.trace("obstacle without photo.");
+                        }
+                    }
+                    obstacles.put(Integer.valueOf(blocktype & 0xFF), obstacle2);
+                    break;
+                case IGNORED_OBSTACLES2:
+                    int ignoredObstaclePairs = getUInt16(header, 0x08);
+                    ArrayList<int[]> ignoredObstacle = new ArrayList<>();
+                    for (int obstaclePair = 0; obstaclePair < ignoredObstaclePairs; obstaclePair++) {
+                        int x0 = getUInt16(data, obstaclePair * 6 + 0);
+                        int y0 = getUInt16(data, obstaclePair * 6 + 2);
+                        int u = getUInt16(data, obstaclePair * 6 + 4);
+                        ignoredObstacle.add(new int[] { x0, y0, u });
+                    }
+                    obstacles.put(Integer.valueOf(blocktype & 0xFF), ignoredObstacle);
+                    break;
+                case CARPET_MAP:
+                    carpetMap = new int[blockDataLength];
+                    for (int carpetNode = 0; carpetNode < blockDataLength; carpetNode++) {
+                        carpetMap[carpetNode] = data[carpetNode] & 0xFF;
                     }
                     break;
                 case BLOCKS:
@@ -285,7 +341,10 @@ public class RRMapFileParser {
         printAreaDetails(walls, pw);
         pw.printf("Zones:\t%d\r\n", zones.size());
         printAreaDetails(zones, pw);
-        pw.printf("Obstacles:\t%d\r\n", obstacles.size());
+        for (Integer obstacleType : obstacles.keySet()) {
+            pw.printf("Obstacles Type (%d):\t%d\r\n", obstacleType, obstacles.get(obstacleType).size());
+            printObstacleDetails(obstacles.get(obstacleType), pw);
+        }
         pw.printf("Blocks:\t%d\r\n", blocks.length);
         pw.print("Paths:");
         for (Integer p : pathsDetails.keySet()) {
@@ -301,7 +360,7 @@ public class RRMapFileParser {
 
     private void printAreaDetails(ArrayList<float[]> areas, PrintWriter pw) {
         areas.forEach(area -> {
-            pw.printf("\tArea coordinates:");
+            pw.print("\tArea coordinates:");
             for (int i = 0; i < area.length; i++) {
                 pw.printf("\t%.0f", area[i]);
             }
@@ -309,6 +368,16 @@ public class RRMapFileParser {
         });
     }
 
+    private void printObstacleDetails(ArrayList<int[]> obstacle, PrintWriter pw) {
+        obstacle.forEach(area -> {
+            pw.print("\tObstacle coordinates:");
+            for (int i = 0; i < area.length; i++) {
+                pw.printf("\t%d", area[i]);
+            }
+            pw.println();
+        });
+    }
+
     /**
      * Compute SHA-1 hash value for the byte array
      *
@@ -416,11 +485,15 @@ public class RRMapFileParser {
         return areas;
     }
 
-    public ArrayList<int[]> getObstacles() {
+    public Map<Integer, ArrayList<int[]>> getObstacles() {
         return obstacles;
     }
 
     public byte[] getBlocks() {
         return blocks;
     }
+
+    public final int[] getCarpetMap() {
+        return carpetMap;
+    }
 }