[miio] add new map elements (#8637)

* [miio] add new map elements

Add newly found mapelements for obstacles

Signed-off-by: Marcel Verpaalen marcel@verpaalen.com
This commit is contained in:
Marcel 2020-10-04 18:35:59 +02:00 committed by GitHub
parent bd4528dcf3
commit 9c6c80d41f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 15 deletions

View 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;

View 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;
}
}