diff --git a/backend/lib/robots/3irobotix/ThreeIRobotixMapParser.js b/backend/lib/robots/3irobotix/ThreeIRobotixMapParser.js index dd11e962ae..7cdd53a77b 100644 --- a/backend/lib/robots/3irobotix/ThreeIRobotixMapParser.js +++ b/backend/lib/robots/3irobotix/ThreeIRobotixMapParser.js @@ -21,18 +21,89 @@ class ThreeIRobotixMapParser { const uniqueMapIdBytes = mapBuf.subarray(4,8); const uniqueMapId = uniqueMapIdBytes.readUInt32LE(); - if (uniqueMapId === 0 || flagData.MAP_IMAGE !== true || flagData.ROBOT_STATUS !== true) { + if (flagData.MAP_IMAGE !== true || flagData.ROBOT_STATUS !== true) { return null; } + let blocks; - const blocks = ThreeIRobotixMapParser.BUILD_BLOCK_INDEX(mapBuf, uniqueMapIdBytes, flagData); - const processedBlocks = ThreeIRobotixMapParser.PROCESS_BLOCKS(blocks); + if (uniqueMapId > 0) { + blocks = ThreeIRobotixMapParser.BUILD_BLOCK_INDEX(mapBuf, uniqueMapIdBytes, flagData); + } else { + if (flagData.MAP_IMAGE === true && flagData.PATH === true) { + blocks = ThreeIRobotixMapParser.BUILD_FALLBACK_INDEX(mapBuf, flagData); + } else { + return null; + } + } + + const processedBlocks = ThreeIRobotixMapParser.PROCESS_BLOCKS(blocks, uniqueMapId === 0); return ThreeIRobotixMapParser.POST_PROCESS_BLOCKS(processedBlocks, uniqueMapId); } + /** + * This is used for temporary maps (e.g., on initial cleanup when there are no segments yet) + * + * @param {Buffer} mapBuf + * @param {object} flagData + * @return {Array} + */ + static BUILD_FALLBACK_INDEX(mapBuf, flagData) { + const types = Object.entries(flagData).filter(([key, value]) => { + return value === true; + }).map(([key, value]) => { + return TYPE_FLAGS[key]; + }); + const foundChunks = []; + let offset = 0; + + types.forEach((type) => { + switch (type) { + case TYPE_FLAGS.ROBOT_STATUS: + foundChunks.push({ + type: TYPE_FLAGS.ROBOT_STATUS, + view: mapBuf.subarray(offset, offset + 48) + }); + + offset += 48; + break; + case TYPE_FLAGS.MAP_IMAGE: { + const header = ThreeIRobotixMapParser.PARSE_IMAGE_BLOCK_HEADER(mapBuf.subarray(offset)); + + if ( + Number.isInteger(header.height) && Number.isInteger(header.width) && + header.height > 0 && header.width > 0 + ) { + foundChunks.push({ + type: TYPE_FLAGS.MAP_IMAGE, + view: mapBuf.subarray(offset, offset + header.blockLength) + }); + } + + offset += header.blockLength; + + break; + } + case TYPE_FLAGS.PATH: { + const header = ThreeIRobotixMapParser.PARSE_PATH_BLOCK_HEADER(mapBuf.subarray(offset)); + + foundChunks.push({ + type: TYPE_FLAGS.PATH, + view: mapBuf.subarray(offset, offset + header.blockLength) + }); + + offset += header.blockLength; + + break; + } + } + }); + + return foundChunks; + } + /** * Because each block conveniently starts with the uniqueMapId, we can use that * to slice our map file into blocks that can then be processed further @@ -94,12 +165,13 @@ class ThreeIRobotixMapParser { /** * @param {Block[]} blocks + * @param {boolean} isTemporaryMap */ - static PROCESS_BLOCKS(blocks) { + static PROCESS_BLOCKS(blocks, isTemporaryMap) { const result = {}; blocks.forEach(block => { - result[block.type] = ThreeIRobotixMapParser.PARSE_BLOCK(block); + result[block.type] = ThreeIRobotixMapParser.PARSE_BLOCK(block, isTemporaryMap); }); return result; @@ -107,11 +179,12 @@ class ThreeIRobotixMapParser { /** * @param {Block} block + * @param {boolean} isTemporaryMap */ - static PARSE_BLOCK(block) { + static PARSE_BLOCK(block, isTemporaryMap) { switch (block.type) { case TYPE_FLAGS.MAP_IMAGE: - return ThreeIRobotixMapParser.PARSE_IMAGE_BLOCK(block); + return ThreeIRobotixMapParser.PARSE_IMAGE_BLOCK(block, isTemporaryMap); case TYPE_FLAGS.SEGMENT_NAMES: return ThreeIRobotixMapParser.PARSE_SEGMENT_NAMES_BLOCK(block); case TYPE_FLAGS.PATH: @@ -129,23 +202,32 @@ class ThreeIRobotixMapParser { } } + static PARSE_IMAGE_BLOCK_HEADER(buf) { + const headerData = { + mapId: buf.readUInt32LE(4), + valid: buf.readUInt32LE(8), + + height: buf.readUInt32LE(12), + width: buf.readUInt32LE(16), + + minX: buf.readFloatLE(20), + minY: buf.readFloatLE(24), + maxX: buf.readFloatLE(28), + maxY: buf.readFloatLE(32), + resolution: buf.readFloatLE(36), + }; + + headerData.blockLength = 40 + headerData.height * headerData.width; + + return headerData; + } + /** * @param {Block} block + * @param {boolean} isTemporaryMap */ - static PARSE_IMAGE_BLOCK(block) { - const header = { - mapId: block.view.readUInt32LE(4), - valid: block.view.readUInt32LE(8), - - height: block.view.readUInt32LE(12), - width: block.view.readUInt32LE(16), - - minX: block.view.readFloatLE(20), - minY: block.view.readFloatLE(24), - maxX: block.view.readFloatLE(28), - maxY: block.view.readFloatLE(32), - resolution: block.view.readFloatLE(36) - }; + static PARSE_IMAGE_BLOCK(block, isTemporaryMap) { + const header = ThreeIRobotixMapParser.PARSE_IMAGE_BLOCK_HEADER(block.view); if (header.height * header.width !== block.view.length - 40) { throw new Error("Image block does not contain the correct amount of pixels or invalid image header."); @@ -178,21 +260,24 @@ class ThreeIRobotixMapParser { pixels.floor.push([coords[0], coords[1]]); break; default: { - const isActive = val >= 60; - let segmentId = val; - - if (isActive) { - segmentId = segmentId - 50; //TODO: this can't be right but it works? - activeSegments[segmentId] = true; + if (!isTemporaryMap) { + const isActive = val >= 60; + let segmentId = val; + + if (isActive) { + segmentId = segmentId - 50; //TODO: this can't be right but it works? + activeSegments[segmentId] = true; + } + + if (!Array.isArray(pixels.segments[segmentId])) { + pixels.segments[segmentId] = []; + } + + pixels.segments[segmentId].push([coords[0], coords[1]]); + } else { + pixels.floor.push([coords[0], coords[1]]); } - - if (!Array.isArray(pixels.segments[segmentId])) { - pixels.segments[segmentId] = []; - } - - pixels.segments[segmentId].push([coords[0], coords[1]]); } - } } } @@ -248,18 +333,26 @@ class ThreeIRobotixMapParser { return segments; } + static PARSE_PATH_BLOCK_HEADER(buf) { + const headerData = { + // At offset 4 there's a poseId. No idea what that does + pathLength: buf.readUInt32LE(8) + }; + + headerData.blockLength = 12 + (headerData.pathLength * 9); + + return headerData; + } + /** * @param {Block} block */ static PARSE_PATH_BLOCK(block) { const points = []; - - // At offset 4 there's a poseId. No idea what that does - const pathLength = block.view.readUInt32LE(8); + const header = ThreeIRobotixMapParser.PARSE_PATH_BLOCK_HEADER(block.view); let offset = 12; - - for (let i = 0; i < pathLength; i++) { + for (let i = 0; i < header.pathLength; i++) { // The first byte is the mode. 0: taxiing, 1: cleaning const convertedCoordinates = ThreeIRobotixMapParser.CONVERT_TO_VALETUDO_COORDINATES( block.view.readFloatLE(offset + 1), @@ -426,6 +519,17 @@ class ThreeIRobotixMapParser { }, type: Map.PointMapEntity.TYPE.ROBOT_POSITION })); + } else if (uniqueMapId === 0 && blocks[TYPE_FLAGS.PATH]?.length >= 2) { + entities.push(new Map.PointMapEntity({ + points: [ + blocks[TYPE_FLAGS.PATH][blocks[TYPE_FLAGS.PATH].length - 2], + blocks[TYPE_FLAGS.PATH][blocks[TYPE_FLAGS.PATH].length - 1] + ], + metaData: { + angle: calculatedRobotAngle ?? 0 + }, + type: Map.PointMapEntity.TYPE.ROBOT_POSITION + })); } if (blocks[TYPE_FLAGS.CHARGER_LOCATION]) { diff --git a/backend/lib/robots/viomi/ViomiValetudoRobot.js b/backend/lib/robots/viomi/ViomiValetudoRobot.js index 566193bfc7..dd73488033 100644 --- a/backend/lib/robots/viomi/ViomiValetudoRobot.js +++ b/backend/lib/robots/viomi/ViomiValetudoRobot.js @@ -46,7 +46,8 @@ class ViomiValetudoRobot extends MiioValetudoRobot { carpetModeEnabled: undefined, lastOperationType: null, lastOperationAdditionalParams: [], - operationMode: undefined + operationMode: undefined, + vendorMapId: 0 }; this.registerCapability(new capabilities.ViomiBasicControlCapability({ @@ -474,8 +475,19 @@ class ViomiValetudoRobot extends MiioValetudoRobot { const map = ThreeIRobotixMapParser.PARSE(data); if (map !== null) { - this.state.map = map; - this.emitMapUpdated(); + if (map.metaData.vendorMapId > 0) { // Regular map + this.ephemeralState.vendorMapId = map.metaData.vendorMapId; + + this.state.map = map; + + this.emitMapUpdated(); + } else { // Temporary map + if (this.ephemeralState.vendorMapId === 0) { + this.state.map = map; // There is no previous full data so this is all we have + + this.emitMapUpdated(); + } // else: ignore since we already have a better map + } } return this.state.map; @@ -494,6 +506,14 @@ class ViomiValetudoRobot extends MiioValetudoRobot { } } + clearValetudoMap() { + this.ephemeralState.vendorMapId = 0; + + super.clearValetudoMap(); + + this.emitMapUpdated(); + } + getManufacturer() { return "Viomi"; } diff --git a/backend/lib/robots/viomi/capabilities/ViomiMapSegmentEditCapability.js b/backend/lib/robots/viomi/capabilities/ViomiMapSegmentEditCapability.js index 417ab25d36..1082787e0b 100644 --- a/backend/lib/robots/viomi/capabilities/ViomiMapSegmentEditCapability.js +++ b/backend/lib/robots/viomi/capabilities/ViomiMapSegmentEditCapability.js @@ -51,7 +51,7 @@ class ViomiMapSegmentEditCapability extends MapSegmentEditCapability { try { const result = await this.robot.sendCommand("arrange_room", { lang: this.lang, - mapId: this.robot.state.map.metaData.vendorMapId, + mapId: this.robot.ephemeralState.vendorMapId, roomArr: [[parseInt(segmentA.id), parseInt(segmentB.id)]], type: this.mapActions.JOIN_SEGMENT_TYPE }, { @@ -83,7 +83,7 @@ class ViomiMapSegmentEditCapability extends MapSegmentEditCapability { try { const result = await this.robot.sendCommand("arrange_room", { lang: this.lang, - mapId: this.robot.state.map.metaData.vendorMapId, + mapId: this.robot.ephemeralState.vendorMapId, pointArr: [[ 1, this.pointToViomiString(ThreeIRobotixMapParser.CONVERT_TO_THREEIROBOTIX_COORDINATES(pA.x, pA.y)), diff --git a/backend/lib/robots/viomi/capabilities/ViomiMapSegmentRenameCapability.js b/backend/lib/robots/viomi/capabilities/ViomiMapSegmentRenameCapability.js index 1019b85e62..847aa6b522 100644 --- a/backend/lib/robots/viomi/capabilities/ViomiMapSegmentRenameCapability.js +++ b/backend/lib/robots/viomi/capabilities/ViomiMapSegmentRenameCapability.js @@ -14,7 +14,7 @@ class ViomiMapSegmentRenameCapability extends MapSegmentRenameCapability { } await this.robot.sendCommand("rename_room", [ - this.robot.state.map.metaData.vendorMapId, + this.robot.ephemeralState.vendorMapId, 1, parseInt(segment.id), name diff --git a/backend/test/lib/robots/3irobotix/ThreeIRobotixMapParser_spec.js b/backend/test/lib/robots/3irobotix/ThreeIRobotixMapParser_spec.js index f1dd5d5c6d..c91d3f4b1e 100644 --- a/backend/test/lib/robots/3irobotix/ThreeIRobotixMapParser_spec.js +++ b/backend/test/lib/robots/3irobotix/ThreeIRobotixMapParser_spec.js @@ -85,7 +85,7 @@ describe("ThreeIRobotixMapParser", function () { actual.should.deepEqual(expected); }); - it("Should pre-process & ignore viomi v6 fw 41 map with no unique map id", async function() { + it("Should pre-process & ignore viomi v6 fw 41 map with no unique map id and no pixels", async function() { let data = await fs.readFile(path.join(__dirname, "/res/map/viomi_v6_41_no_uniquemapid.bin")); const preprocessedData = await ThreeIRobotixMapParser.PREPROCESS(data); @@ -94,4 +94,58 @@ describe("ThreeIRobotixMapParser", function () { should(actual).equal(null); }); + + it("Should pre-process & parse conga 3290 converted to viomi v6 fw 41 map with no unique map id but with pixels", async function() { + let data = await fs.readFile(path.join(__dirname, "/res/map/converted_3290_no_id.bin")); + let expected = JSON.parse(await fs.readFile(path.join(__dirname, "/res/map/converted_3290_no_id.json"), { encoding: "utf-8" })); + const preprocessedData = await ThreeIRobotixMapParser.PREPROCESS(data); + + const actual = ThreeIRobotixMapParser.PARSE(preprocessedData); + + + if (actual.metaData?.nonce) { + delete(actual.metaData.nonce); + } + + actual.layers.length.should.equal(expected.layers.length, "layerCount"); + + actual.layers.forEach((layer, i) => { + actual.layers[i].should.deepEqual(expected.layers[i]); + }); + + actual.entities.length.should.equal(expected.entities.length, "entitiesCount"); + + actual.entities.forEach((layer, i) => { + actual.entities[i].should.deepEqual(expected.entities[i]); + }); + + actual.should.deepEqual(expected); + }); + + it("Should pre-process & parse conga 3290 converted to viomi v6 fw 41 map with no unique map id but with segment pixels", async function() { + let data = await fs.readFile(path.join(__dirname, "/res/map/converted_3290_noid_segments.bin")); + let expected = JSON.parse(await fs.readFile(path.join(__dirname, "/res/map/converted_3290_noid_segments.json"), { encoding: "utf-8" })); + const preprocessedData = await ThreeIRobotixMapParser.PREPROCESS(data); + + const actual = ThreeIRobotixMapParser.PARSE(preprocessedData); + + + if (actual.metaData?.nonce) { + delete(actual.metaData.nonce); + } + + actual.layers.length.should.equal(expected.layers.length, "layerCount"); + + actual.layers.forEach((layer, i) => { + actual.layers[i].should.deepEqual(expected.layers[i]); + }); + + actual.entities.length.should.equal(expected.entities.length, "entitiesCount"); + + actual.entities.forEach((layer, i) => { + actual.entities[i].should.deepEqual(expected.entities[i]); + }); + + actual.should.deepEqual(expected); + }); }); diff --git a/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.bin b/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.bin new file mode 100644 index 0000000000..562291f466 Binary files /dev/null and b/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.bin differ diff --git a/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.json b/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.json new file mode 100644 index 0000000000..f80dc4a1ed --- /dev/null +++ b/backend/test/lib/robots/3irobotix/res/map/converted_3290_no_id.json @@ -0,0 +1,1398 @@ +{ + "__class": "ValetudoMap", + "metaData": { + "vendorMapId": 0, + "version": 2 + }, + "size": { + "x": 4000, + "y": 4000 + }, + "pixelSize": 5, + "layers": [ + { + "__class": "MapLayer", + "metaData": { + "area": 89750 + }, + "type": "floor", + "pixels": [], + "dimensions": { + "x": { + "min": 331, + "max": 426, + "mid": 379, + "avg": 387 + }, + "y": { + "min": 353, + "max": 451, + "mid": 402, + "avg": 398 + }, + "pixelCount": 3590 + }, + "compressedPixels": [ + 380, + 353, + 32, + 380, + 354, + 36, + 378, + 355, + 41, + 375, + 356, + 44, + 375, + 357, + 44, + 375, + 358, + 44, + 375, + 359, + 37, + 413, + 359, + 6, + 375, + 360, + 44, + 375, + 361, + 35, + 411, + 361, + 8, + 375, + 362, + 34, + 410, + 362, + 9, + 376, + 363, + 32, + 409, + 363, + 10, + 374, + 364, + 45, + 374, + 365, + 18, + 393, + 365, + 26, + 374, + 366, + 16, + 392, + 366, + 1, + 394, + 366, + 10, + 405, + 366, + 14, + 360, + 367, + 1, + 374, + 367, + 13, + 389, + 367, + 1, + 392, + 367, + 11, + 405, + 367, + 14, + 360, + 368, + 3, + 374, + 368, + 11, + 392, + 368, + 12, + 405, + 368, + 14, + 360, + 369, + 4, + 374, + 369, + 8, + 383, + 369, + 2, + 393, + 369, + 26, + 360, + 370, + 4, + 375, + 370, + 7, + 392, + 370, + 27, + 360, + 371, + 4, + 375, + 371, + 7, + 392, + 371, + 27, + 360, + 372, + 4, + 370, + 372, + 12, + 391, + 372, + 28, + 360, + 373, + 22, + 391, + 373, + 28, + 359, + 374, + 23, + 391, + 374, + 28, + 359, + 375, + 21, + 388, + 375, + 30, + 359, + 376, + 21, + 388, + 376, + 25, + 417, + 376, + 1, + 360, + 377, + 20, + 388, + 377, + 21, + 358, + 378, + 22, + 388, + 378, + 17, + 358, + 379, + 19, + 388, + 379, + 14, + 358, + 380, + 19, + 388, + 380, + 9, + 357, + 381, + 20, + 380, + 381, + 5, + 386, + 381, + 5, + 393, + 381, + 4, + 357, + 382, + 34, + 357, + 383, + 34, + 358, + 384, + 33, + 350, + 385, + 6, + 357, + 385, + 33, + 350, + 386, + 40, + 338, + 387, + 3, + 350, + 387, + 40, + 338, + 388, + 3, + 342, + 388, + 3, + 350, + 388, + 40, + 338, + 389, + 52, + 331, + 390, + 5, + 338, + 390, + 52, + 331, + 391, + 59, + 331, + 392, + 60, + 331, + 393, + 62, + 394, + 393, + 3, + 331, + 394, + 66, + 400, + 394, + 7, + 331, + 395, + 67, + 400, + 395, + 8, + 331, + 396, + 6, + 338, + 396, + 60, + 400, + 396, + 8, + 331, + 397, + 6, + 340, + 397, + 68, + 331, + 398, + 4, + 340, + 398, + 68, + 331, + 399, + 4, + 341, + 399, + 66, + 341, + 400, + 66, + 341, + 401, + 13, + 355, + 401, + 7, + 363, + 401, + 5, + 369, + 401, + 13, + 385, + 401, + 20, + 386, + 402, + 18, + 386, + 403, + 18, + 386, + 404, + 15, + 386, + 405, + 16, + 386, + 406, + 18, + 386, + 407, + 18, + 386, + 408, + 18, + 386, + 409, + 18, + 387, + 410, + 17, + 387, + 411, + 17, + 386, + 412, + 18, + 386, + 413, + 18, + 386, + 414, + 18, + 387, + 415, + 17, + 386, + 416, + 18, + 386, + 417, + 18, + 386, + 418, + 18, + 389, + 419, + 15, + 389, + 420, + 15, + 389, + 421, + 15, + 389, + 422, + 15, + 386, + 423, + 19, + 387, + 424, + 20, + 386, + 425, + 21, + 386, + 426, + 23, + 385, + 427, + 24, + 386, + 428, + 23, + 386, + 429, + 24, + 386, + 430, + 25, + 386, + 431, + 26, + 385, + 432, + 28, + 385, + 433, + 29, + 383, + 434, + 31, + 384, + 435, + 31, + 383, + 436, + 33, + 383, + 437, + 34, + 382, + 438, + 36, + 382, + 439, + 37, + 381, + 440, + 38, + 381, + 441, + 39, + 380, + 442, + 41, + 380, + 443, + 42, + 379, + 444, + 7, + 388, + 444, + 11, + 401, + 444, + 22, + 379, + 445, + 45, + 386, + 446, + 38, + 386, + 447, + 39, + 386, + 448, + 40, + 386, + 449, + 40, + 388, + 450, + 11, + 400, + 450, + 27, + 421, + 451, + 4 + ] + }, + { + "__class": "MapLayer", + "metaData": { + "area": 12125 + }, + "type": "wall", + "pixels": [], + "dimensions": { + "x": { + "min": 330, + "max": 427, + "mid": 379, + "avg": 382 + }, + "y": { + "min": 352, + "max": 452, + "mid": 402, + "avg": 395 + }, + "pixelCount": 485 + }, + "compressedPixels": [ + 379, + 352, + 34, + 379, + 353, + 1, + 412, + 353, + 5, + 377, + 354, + 3, + 416, + 354, + 4, + 377, + 355, + 1, + 419, + 355, + 1, + 374, + 356, + 1, + 419, + 356, + 1, + 374, + 357, + 1, + 419, + 357, + 1, + 374, + 358, + 1, + 419, + 358, + 1, + 374, + 359, + 1, + 419, + 359, + 1, + 374, + 360, + 1, + 419, + 360, + 1, + 374, + 361, + 1, + 419, + 361, + 1, + 374, + 362, + 1, + 419, + 362, + 1, + 373, + 363, + 3, + 419, + 363, + 1, + 373, + 364, + 1, + 419, + 364, + 1, + 373, + 365, + 1, + 419, + 365, + 1, + 359, + 366, + 1, + 373, + 366, + 1, + 390, + 366, + 1, + 404, + 366, + 1, + 419, + 366, + 1, + 359, + 367, + 1, + 373, + 367, + 1, + 390, + 367, + 2, + 403, + 367, + 2, + 419, + 367, + 1, + 359, + 368, + 1, + 373, + 368, + 1, + 404, + 368, + 1, + 419, + 368, + 1, + 359, + 369, + 1, + 364, + 369, + 1, + 373, + 369, + 1, + 382, + 369, + 1, + 419, + 369, + 1, + 359, + 370, + 1, + 364, + 370, + 1, + 373, + 370, + 2, + 382, + 370, + 3, + 419, + 370, + 1, + 359, + 371, + 1, + 364, + 371, + 1, + 369, + 371, + 6, + 382, + 371, + 1, + 419, + 371, + 1, + 359, + 372, + 1, + 364, + 372, + 6, + 382, + 372, + 1, + 419, + 372, + 1, + 358, + 373, + 2, + 382, + 373, + 1, + 390, + 373, + 1, + 419, + 373, + 1, + 358, + 374, + 1, + 382, + 374, + 1, + 387, + 374, + 4, + 419, + 374, + 1, + 358, + 375, + 1, + 380, + 375, + 3, + 387, + 375, + 1, + 418, + 375, + 2, + 358, + 376, + 1, + 380, + 376, + 1, + 387, + 376, + 1, + 357, + 377, + 3, + 380, + 377, + 1, + 387, + 377, + 1, + 357, + 378, + 1, + 380, + 378, + 1, + 387, + 378, + 1, + 357, + 379, + 1, + 377, + 379, + 4, + 387, + 379, + 1, + 356, + 380, + 2, + 377, + 380, + 1, + 379, + 380, + 9, + 356, + 381, + 1, + 377, + 381, + 3, + 385, + 381, + 1, + 391, + 381, + 2, + 356, + 382, + 1, + 391, + 382, + 6, + 356, + 383, + 1, + 391, + 383, + 1, + 349, + 384, + 9, + 391, + 384, + 1, + 349, + 385, + 1, + 356, + 385, + 1, + 390, + 385, + 2, + 337, + 386, + 3, + 349, + 386, + 1, + 390, + 386, + 1, + 337, + 387, + 1, + 341, + 387, + 5, + 349, + 387, + 1, + 390, + 387, + 1, + 337, + 388, + 1, + 341, + 388, + 1, + 345, + 388, + 5, + 390, + 388, + 1, + 330, + 389, + 8, + 390, + 389, + 1, + 330, + 390, + 1, + 336, + 390, + 2, + 390, + 390, + 1, + 330, + 391, + 1, + 390, + 391, + 2, + 330, + 392, + 1, + 391, + 392, + 7, + 330, + 393, + 1, + 393, + 393, + 1, + 397, + 393, + 1, + 399, + 393, + 9, + 330, + 394, + 1, + 397, + 394, + 3, + 407, + 394, + 2, + 330, + 395, + 1, + 398, + 395, + 2, + 408, + 395, + 1, + 330, + 396, + 1, + 337, + 396, + 1, + 398, + 396, + 2, + 408, + 396, + 1, + 330, + 397, + 1, + 337, + 397, + 3, + 408, + 397, + 1, + 330, + 398, + 1, + 335, + 398, + 3, + 339, + 398, + 1, + 408, + 398, + 1, + 330, + 399, + 1, + 335, + 399, + 1, + 339, + 399, + 2, + 407, + 399, + 2, + 330, + 400, + 6, + 340, + 400, + 1, + 407, + 400, + 1, + 340, + 401, + 1, + 354, + 401, + 1, + 362, + 401, + 1, + 368, + 401, + 1, + 382, + 401, + 3, + 405, + 401, + 3, + 340, + 402, + 43, + 384, + 402, + 2, + 404, + 402, + 2, + 385, + 403, + 1, + 404, + 403, + 1, + 385, + 404, + 1, + 401, + 404, + 4, + 385, + 405, + 1, + 402, + 405, + 3, + 385, + 406, + 1, + 404, + 406, + 1, + 385, + 407, + 1, + 404, + 407, + 1, + 385, + 408, + 1, + 404, + 408, + 1, + 385, + 409, + 1, + 404, + 409, + 1, + 385, + 410, + 2, + 404, + 410, + 1, + 385, + 411, + 2, + 404, + 411, + 1, + 385, + 412, + 1, + 404, + 412, + 1, + 385, + 413, + 1, + 404, + 413, + 1, + 385, + 414, + 1, + 404, + 414, + 1, + 385, + 415, + 2, + 404, + 415, + 1, + 385, + 416, + 1, + 404, + 416, + 1, + 385, + 417, + 1, + 404, + 417, + 1, + 385, + 418, + 1, + 404, + 418, + 1, + 385, + 419, + 4, + 404, + 419, + 1, + 388, + 420, + 1, + 404, + 420, + 1, + 388, + 421, + 1, + 404, + 421, + 1, + 385, + 422, + 4, + 404, + 422, + 2, + 405, + 423, + 3, + 407, + 424, + 1, + 407, + 425, + 2, + 384, + 427, + 1, + 384, + 428, + 2, + 385, + 429, + 1, + 385, + 430, + 1, + 384, + 431, + 2, + 384, + 432, + 1, + 383, + 433, + 2, + 386, + 444, + 2, + 399, + 444, + 2, + 378, + 445, + 1, + 378, + 446, + 8, + 385, + 447, + 1, + 385, + 448, + 1, + 385, + 449, + 1, + 385, + 450, + 3, + 399, + 450, + 1, + 387, + 451, + 34, + 425, + 451, + 3, + 420, + 452, + 6 + ] + } + ], + "entities": [ + { + "__class": "PathMapEntity", + "metaData": {}, + "points": [ + 2001, + 1998, + 2001, + 1999, + 2000, + 1999, + 2001, + 2000, + 2001, + 2000, + 2002, + 2000, + 2002, + 1999, + 2002, + 1999, + 2002, + 1999, + 2001, + 1998, + 2001, + 1998, + 2001, + 1998, + 2000, + 1999, + 2000, + 1999, + 2000, + 1999, + 2001, + 2000, + 2001, + 2000, + 1991, + 2001, + 1980, + 2002, + 1969, + 2003, + 1959, + 2003, + 1949, + 1995, + 1939, + 1983, + 1932, + 1971, + 1925, + 1961, + 1917, + 1956, + 1907, + 1956, + 1895, + 1964, + 1888, + 1974, + 1884, + 1984, + 1884, + 1989, + 1884, + 1988, + 1882, + 1988, + 1893, + 1992, + 1896, + 1991, + 1895, + 1991, + 1895, + 1992, + 1896, + 1981, + 1896, + 1970, + 1897, + 1960, + 1898, + 1950, + 1897, + 1948, + 1898, + 1947, + 1887, + 1944, + 1876, + 1942, + 1865, + 1939, + 1859, + 1937, + 1860, + 1937, + 1861, + 1937, + 1861, + 1936, + 1860, + 1936, + 1860, + 1936, + 1859, + 1936, + 1859, + 1936, + 1859, + 1937, + 1859, + 1937, + 1860, + 1937, + 1860, + 1938, + 1860, + 1936, + 1861, + 1936, + 1857, + 1925, + 1856, + 1915, + 1857, + 1905, + 1859, + 1894, + 1865, + 1884, + 1876, + 1875, + 1878, + 1873, + 1877, + 1873, + 1878, + 1873, + 1879, + 1874, + 1879, + 1873, + 1868, + 1874, + 1857, + 1875, + 1856, + 1876, + 1856, + 1876, + 1857, + 1876, + 1859, + 1886, + 1860, + 1897, + 1860, + 1907, + 1859, + 1919, + 1859, + 1929, + 1861, + 1938, + 1867, + 1944, + 1878, + 1947, + 1889, + 1945, + 1901, + 1944, + 1911, + 1946, + 1921, + 1956, + 1927, + 1966, + 1933, + 1976, + 1941, + 1987, + 1951, + 1997, + 1960, + 2007, + 1965, + 2018, + 1966, + 2028, + 1965, + 2039 + ], + "type": "path" + }, + { + "__class": "PointMapEntity", + "metaData": { + "angle": 185 + }, + "points": [ + 1965, + 2039 + ], + "type": "robot_position" + } + ] +} \ No newline at end of file diff --git a/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.bin b/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.bin new file mode 100644 index 0000000000..40ccef5aae Binary files /dev/null and b/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.bin differ diff --git a/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.json b/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.json new file mode 100644 index 0000000000..d2bfa5d0bc --- /dev/null +++ b/backend/test/lib/robots/3irobotix/res/map/converted_3290_noid_segments.json @@ -0,0 +1,2083 @@ +{ + "__class": "ValetudoMap", + "metaData": { + "vendorMapId": 0, + "version": 2 + }, + "size": { + "x": 4000, + "y": 4000 + }, + "pixelSize": 5, + "layers": [ + { + "__class": "MapLayer", + "metaData": { + "area": 151025 + }, + "type": "floor", + "pixels": [], + "dimensions": { + "x": { + "min": 331, + "max": 430, + "mid": 381, + "avg": 390 + }, + "y": { + "min": 307, + "max": 499, + "mid": 403, + "avg": 389 + }, + "pixelCount": 6041 + }, + "compressedPixels": [ + 385, + 307, + 19, + 385, + 308, + 19, + 385, + 309, + 19, + 385, + 310, + 20, + 386, + 311, + 22, + 381, + 312, + 27, + 382, + 313, + 25, + 382, + 314, + 25, + 383, + 315, + 24, + 383, + 316, + 24, + 383, + 317, + 24, + 382, + 318, + 25, + 384, + 319, + 23, + 384, + 320, + 23, + 384, + 321, + 23, + 384, + 322, + 23, + 359, + 323, + 2, + 384, + 323, + 23, + 359, + 324, + 2, + 384, + 324, + 23, + 359, + 325, + 3, + 385, + 325, + 22, + 360, + 326, + 3, + 369, + 326, + 5, + 383, + 326, + 24, + 360, + 327, + 3, + 369, + 327, + 6, + 384, + 327, + 23, + 359, + 328, + 4, + 369, + 328, + 6, + 384, + 328, + 22, + 360, + 329, + 1, + 362, + 329, + 1, + 371, + 329, + 5, + 385, + 329, + 21, + 371, + 330, + 5, + 384, + 330, + 22, + 365, + 331, + 1, + 370, + 331, + 6, + 384, + 331, + 22, + 365, + 332, + 1, + 371, + 332, + 6, + 387, + 332, + 19, + 365, + 333, + 1, + 373, + 333, + 4, + 387, + 333, + 19, + 370, + 334, + 1, + 373, + 334, + 4, + 378, + 334, + 1, + 387, + 334, + 19, + 367, + 335, + 12, + 387, + 335, + 19, + 367, + 336, + 4, + 372, + 336, + 7, + 387, + 336, + 19, + 367, + 337, + 4, + 372, + 337, + 7, + 387, + 337, + 19, + 368, + 338, + 11, + 386, + 338, + 20, + 370, + 339, + 35, + 370, + 340, + 35, + 370, + 341, + 35, + 371, + 342, + 34, + 372, + 343, + 33, + 373, + 344, + 32, + 373, + 345, + 32, + 374, + 346, + 31, + 375, + 347, + 30, + 375, + 348, + 30, + 376, + 349, + 28, + 377, + 350, + 27, + 378, + 351, + 26, + 378, + 352, + 26, + 379, + 353, + 26, + 380, + 354, + 24, + 380, + 355, + 15, + 396, + 355, + 8, + 379, + 356, + 25, + 381, + 357, + 22, + 381, + 358, + 23, + 406, + 358, + 3, + 381, + 359, + 23, + 406, + 359, + 3, + 381, + 360, + 1, + 383, + 360, + 21, + 406, + 360, + 3, + 383, + 361, + 28, + 346, + 362, + 4, + 384, + 362, + 27, + 347, + 363, + 9, + 359, + 363, + 13, + 385, + 363, + 26, + 335, + 364, + 1, + 339, + 364, + 1, + 347, + 364, + 24, + 386, + 364, + 25, + 335, + 365, + 9, + 347, + 365, + 25, + 387, + 365, + 24, + 335, + 366, + 11, + 349, + 366, + 24, + 388, + 366, + 23, + 334, + 367, + 14, + 351, + 367, + 23, + 388, + 367, + 23, + 334, + 368, + 16, + 351, + 368, + 1, + 354, + 368, + 21, + 388, + 368, + 23, + 332, + 369, + 20, + 354, + 369, + 22, + 390, + 369, + 21, + 332, + 370, + 20, + 353, + 370, + 24, + 391, + 370, + 20, + 332, + 371, + 20, + 353, + 371, + 25, + 391, + 371, + 20, + 333, + 372, + 18, + 353, + 372, + 26, + 391, + 372, + 19, + 332, + 373, + 17, + 350, + 373, + 1, + 353, + 373, + 27, + 392, + 373, + 11, + 405, + 373, + 4, + 332, + 374, + 18, + 353, + 374, + 28, + 382, + 374, + 1, + 391, + 374, + 12, + 405, + 374, + 4, + 332, + 375, + 10, + 343, + 375, + 7, + 352, + 375, + 31, + 391, + 375, + 19, + 332, + 376, + 10, + 343, + 376, + 7, + 352, + 376, + 31, + 391, + 376, + 19, + 332, + 377, + 1, + 335, + 377, + 10, + 346, + 377, + 4, + 352, + 377, + 16, + 370, + 377, + 14, + 392, + 377, + 18, + 338, + 378, + 4, + 344, + 378, + 6, + 351, + 378, + 34, + 392, + 378, + 18, + 344, + 379, + 44, + 390, + 379, + 20, + 344, + 380, + 66, + 344, + 381, + 66, + 344, + 382, + 66, + 344, + 383, + 66, + 344, + 384, + 66, + 344, + 385, + 66, + 343, + 386, + 60, + 405, + 386, + 4, + 331, + 387, + 1, + 339, + 387, + 2, + 343, + 387, + 60, + 405, + 387, + 3, + 331, + 388, + 11, + 343, + 388, + 65, + 331, + 389, + 77, + 331, + 390, + 77, + 331, + 391, + 76, + 331, + 392, + 77, + 411, + 392, + 20, + 338, + 393, + 1, + 340, + 393, + 1, + 346, + 393, + 3, + 351, + 393, + 3, + 355, + 393, + 12, + 368, + 393, + 21, + 390, + 393, + 19, + 411, + 393, + 20, + 346, + 394, + 1, + 348, + 394, + 1, + 363, + 394, + 3, + 368, + 394, + 21, + 390, + 394, + 41, + 366, + 395, + 17, + 385, + 395, + 4, + 390, + 395, + 41, + 366, + 396, + 23, + 390, + 396, + 41, + 366, + 397, + 20, + 391, + 397, + 40, + 366, + 398, + 20, + 391, + 398, + 40, + 366, + 399, + 20, + 387, + 399, + 43, + 366, + 400, + 19, + 387, + 400, + 4, + 392, + 400, + 38, + 366, + 401, + 20, + 387, + 401, + 4, + 392, + 401, + 5, + 398, + 401, + 32, + 366, + 402, + 7, + 374, + 402, + 21, + 398, + 402, + 32, + 366, + 403, + 5, + 373, + 403, + 21, + 399, + 403, + 31, + 366, + 404, + 1, + 370, + 404, + 24, + 399, + 404, + 31, + 366, + 405, + 27, + 405, + 405, + 25, + 366, + 406, + 26, + 405, + 406, + 25, + 365, + 407, + 27, + 405, + 407, + 25, + 365, + 408, + 27, + 405, + 408, + 25, + 361, + 409, + 30, + 403, + 409, + 20, + 361, + 410, + 6, + 368, + 410, + 17, + 386, + 410, + 4, + 402, + 410, + 21, + 360, + 411, + 7, + 368, + 411, + 15, + 386, + 411, + 5, + 402, + 411, + 21, + 378, + 412, + 4, + 401, + 412, + 22, + 401, + 413, + 22, + 401, + 414, + 22, + 401, + 415, + 22, + 401, + 416, + 22, + 401, + 417, + 21, + 401, + 418, + 21, + 401, + 419, + 21, + 401, + 420, + 21, + 401, + 421, + 21, + 401, + 422, + 21, + 401, + 423, + 21, + 401, + 424, + 21, + 401, + 425, + 21, + 401, + 426, + 21, + 401, + 427, + 21, + 400, + 428, + 22, + 400, + 429, + 22, + 398, + 430, + 24, + 399, + 431, + 23, + 399, + 432, + 23, + 399, + 433, + 23, + 399, + 434, + 23, + 399, + 435, + 23, + 399, + 436, + 23, + 398, + 437, + 17, + 416, + 437, + 4, + 398, + 438, + 23, + 398, + 439, + 24, + 398, + 440, + 24, + 398, + 441, + 24, + 397, + 442, + 25, + 397, + 443, + 25, + 397, + 444, + 25, + 397, + 445, + 25, + 397, + 446, + 25, + 397, + 447, + 25, + 398, + 448, + 24, + 398, + 449, + 24, + 397, + 450, + 17, + 416, + 450, + 5, + 403, + 451, + 11, + 416, + 451, + 4, + 404, + 452, + 11, + 402, + 453, + 13, + 402, + 454, + 14, + 402, + 455, + 14, + 402, + 456, + 14, + 403, + 457, + 14, + 403, + 458, + 13, + 403, + 459, + 13, + 403, + 460, + 13, + 403, + 461, + 14, + 403, + 462, + 14, + 403, + 463, + 15, + 403, + 464, + 14, + 403, + 465, + 14, + 403, + 466, + 14, + 403, + 467, + 15, + 403, + 468, + 15, + 403, + 469, + 15, + 403, + 470, + 14, + 403, + 471, + 14, + 403, + 472, + 15, + 403, + 473, + 10, + 403, + 474, + 10, + 403, + 475, + 12, + 403, + 476, + 11, + 403, + 477, + 12, + 403, + 478, + 12, + 403, + 479, + 12, + 403, + 480, + 11, + 402, + 481, + 12, + 402, + 482, + 12, + 402, + 483, + 13, + 402, + 484, + 11, + 402, + 485, + 12, + 402, + 486, + 11, + 404, + 487, + 10, + 404, + 488, + 10, + 404, + 489, + 6, + 412, + 489, + 2, + 404, + 490, + 9, + 404, + 491, + 10, + 404, + 492, + 10, + 404, + 493, + 10, + 404, + 494, + 9, + 404, + 495, + 9, + 404, + 496, + 7, + 413, + 496, + 1, + 404, + 497, + 8, + 404, + 498, + 7, + 407, + 499, + 1 + ] + }, + { + "__class": "MapLayer", + "metaData": { + "area": 15600 + }, + "type": "wall", + "pixels": [], + "dimensions": { + "x": { + "min": 330, + "max": 431, + "mid": 381, + "avg": 388 + }, + "y": { + "min": 306, + "max": 499, + "mid": 403, + "avg": 389 + }, + "pixelCount": 624 + }, + "compressedPixels": [ + 384, + 306, + 21, + 384, + 307, + 1, + 404, + 307, + 1, + 384, + 308, + 1, + 404, + 308, + 1, + 384, + 309, + 1, + 404, + 309, + 2, + 384, + 310, + 1, + 405, + 310, + 4, + 380, + 311, + 6, + 408, + 311, + 1, + 380, + 312, + 1, + 382, + 319, + 2, + 383, + 320, + 1, + 383, + 321, + 1, + 383, + 322, + 1, + 383, + 323, + 1, + 383, + 324, + 1, + 368, + 325, + 5, + 382, + 325, + 3, + 368, + 326, + 1, + 368, + 327, + 1, + 358, + 329, + 2, + 359, + 330, + 1, + 383, + 331, + 1, + 370, + 332, + 1, + 383, + 332, + 4, + 371, + 333, + 2, + 379, + 333, + 1, + 386, + 333, + 1, + 371, + 334, + 2, + 379, + 334, + 1, + 386, + 334, + 1, + 379, + 335, + 1, + 386, + 335, + 1, + 379, + 336, + 1, + 386, + 336, + 1, + 379, + 337, + 1, + 385, + 337, + 2, + 379, + 338, + 7, + 404, + 354, + 2, + 395, + 355, + 1, + 404, + 355, + 1, + 404, + 356, + 1, + 378, + 357, + 3, + 403, + 357, + 7, + 380, + 358, + 1, + 404, + 358, + 2, + 409, + 358, + 1, + 380, + 359, + 1, + 404, + 359, + 2, + 409, + 359, + 1, + 380, + 360, + 1, + 404, + 360, + 2, + 409, + 360, + 3, + 345, + 361, + 6, + 380, + 361, + 1, + 411, + 361, + 1, + 350, + 362, + 7, + 358, + 362, + 15, + 411, + 362, + 1, + 334, + 363, + 1, + 340, + 363, + 1, + 356, + 363, + 3, + 411, + 363, + 1, + 334, + 364, + 1, + 340, + 364, + 3, + 411, + 364, + 1, + 334, + 365, + 1, + 411, + 365, + 1, + 333, + 366, + 2, + 411, + 366, + 1, + 333, + 367, + 1, + 411, + 367, + 1, + 331, + 368, + 3, + 352, + 368, + 2, + 411, + 368, + 1, + 331, + 369, + 1, + 352, + 369, + 2, + 389, + 369, + 1, + 411, + 369, + 1, + 331, + 370, + 1, + 352, + 370, + 1, + 389, + 370, + 2, + 411, + 370, + 1, + 331, + 371, + 1, + 352, + 371, + 1, + 390, + 371, + 1, + 411, + 371, + 1, + 331, + 372, + 2, + 351, + 372, + 2, + 390, + 372, + 1, + 410, + 372, + 2, + 331, + 373, + 1, + 351, + 373, + 2, + 390, + 373, + 2, + 403, + 373, + 2, + 409, + 373, + 2, + 331, + 374, + 1, + 351, + 374, + 2, + 383, + 374, + 1, + 390, + 374, + 1, + 403, + 374, + 2, + 409, + 374, + 2, + 331, + 375, + 1, + 350, + 375, + 2, + 383, + 375, + 1, + 390, + 375, + 1, + 410, + 375, + 1, + 331, + 376, + 1, + 350, + 376, + 2, + 383, + 376, + 2, + 390, + 376, + 1, + 410, + 376, + 1, + 331, + 377, + 1, + 345, + 377, + 1, + 350, + 377, + 2, + 368, + 377, + 2, + 384, + 377, + 2, + 390, + 377, + 2, + 410, + 377, + 1, + 331, + 378, + 1, + 342, + 378, + 2, + 350, + 378, + 1, + 385, + 378, + 7, + 410, + 378, + 1, + 338, + 379, + 6, + 388, + 379, + 2, + 410, + 379, + 1, + 343, + 380, + 1, + 410, + 380, + 1, + 343, + 381, + 1, + 410, + 381, + 1, + 343, + 382, + 1, + 410, + 382, + 1, + 343, + 383, + 1, + 410, + 383, + 1, + 343, + 384, + 1, + 410, + 384, + 1, + 342, + 385, + 2, + 410, + 385, + 1, + 330, + 386, + 1, + 340, + 386, + 3, + 403, + 386, + 2, + 409, + 386, + 2, + 330, + 387, + 1, + 341, + 387, + 2, + 403, + 387, + 2, + 408, + 387, + 2, + 330, + 388, + 1, + 342, + 388, + 1, + 408, + 388, + 1, + 330, + 389, + 1, + 408, + 389, + 1, + 330, + 390, + 1, + 408, + 390, + 1, + 330, + 391, + 1, + 407, + 391, + 2, + 410, + 391, + 22, + 330, + 392, + 1, + 408, + 392, + 3, + 431, + 392, + 1, + 330, + 393, + 8, + 341, + 393, + 5, + 349, + 393, + 2, + 354, + 393, + 1, + 367, + 393, + 1, + 389, + 393, + 1, + 409, + 393, + 2, + 431, + 393, + 1, + 337, + 394, + 1, + 341, + 394, + 1, + 349, + 394, + 14, + 366, + 394, + 2, + 389, + 394, + 1, + 431, + 394, + 1, + 362, + 395, + 4, + 383, + 395, + 2, + 389, + 395, + 1, + 431, + 395, + 1, + 365, + 396, + 1, + 389, + 396, + 1, + 431, + 396, + 1, + 365, + 397, + 1, + 386, + 397, + 5, + 431, + 397, + 1, + 365, + 398, + 1, + 386, + 398, + 5, + 431, + 398, + 1, + 365, + 399, + 1, + 386, + 399, + 1, + 430, + 399, + 2, + 365, + 400, + 1, + 385, + 400, + 2, + 391, + 400, + 1, + 430, + 400, + 1, + 365, + 401, + 1, + 386, + 401, + 1, + 391, + 401, + 1, + 397, + 401, + 1, + 430, + 401, + 1, + 365, + 402, + 1, + 395, + 402, + 3, + 430, + 402, + 1, + 365, + 403, + 1, + 394, + 403, + 2, + 397, + 403, + 2, + 430, + 403, + 1, + 365, + 404, + 1, + 394, + 404, + 1, + 398, + 404, + 1, + 430, + 404, + 1, + 365, + 405, + 1, + 393, + 405, + 2, + 398, + 405, + 7, + 430, + 405, + 1, + 364, + 406, + 2, + 392, + 406, + 2, + 404, + 406, + 1, + 430, + 406, + 1, + 364, + 407, + 1, + 392, + 407, + 1, + 404, + 407, + 1, + 430, + 407, + 1, + 362, + 408, + 3, + 402, + 408, + 3, + 430, + 408, + 1, + 401, + 409, + 2, + 423, + 409, + 8, + 367, + 410, + 1, + 385, + 410, + 1, + 401, + 410, + 1, + 423, + 410, + 1, + 367, + 411, + 1, + 383, + 411, + 3, + 400, + 411, + 2, + 423, + 411, + 1, + 359, + 412, + 19, + 382, + 412, + 2, + 385, + 412, + 7, + 400, + 412, + 1, + 423, + 412, + 1, + 377, + 413, + 6, + 400, + 413, + 1, + 423, + 413, + 1, + 400, + 414, + 1, + 423, + 414, + 1, + 400, + 415, + 1, + 423, + 415, + 1, + 400, + 416, + 1, + 423, + 416, + 1, + 400, + 417, + 1, + 422, + 417, + 2, + 400, + 418, + 1, + 422, + 418, + 1, + 400, + 419, + 1, + 422, + 419, + 1, + 400, + 420, + 1, + 422, + 420, + 1, + 400, + 421, + 1, + 422, + 421, + 1, + 400, + 422, + 1, + 422, + 422, + 1, + 400, + 423, + 1, + 422, + 423, + 1, + 400, + 424, + 1, + 422, + 424, + 1, + 400, + 425, + 1, + 422, + 425, + 1, + 400, + 426, + 1, + 422, + 426, + 1, + 399, + 427, + 2, + 422, + 427, + 1, + 399, + 428, + 1, + 422, + 428, + 1, + 399, + 429, + 1, + 422, + 429, + 1, + 422, + 430, + 1, + 422, + 431, + 1, + 422, + 432, + 1, + 422, + 433, + 1, + 422, + 434, + 1, + 422, + 435, + 1, + 422, + 436, + 1, + 415, + 437, + 1, + 420, + 437, + 3, + 421, + 438, + 2, + 422, + 439, + 1, + 422, + 440, + 1, + 422, + 441, + 1, + 422, + 442, + 1, + 422, + 443, + 1, + 422, + 444, + 1, + 422, + 445, + 1, + 422, + 446, + 1, + 422, + 447, + 1, + 422, + 448, + 1, + 422, + 449, + 1, + 414, + 450, + 2, + 421, + 450, + 2, + 396, + 451, + 7, + 414, + 451, + 2, + 420, + 451, + 2, + 401, + 452, + 3, + 415, + 452, + 6, + 401, + 453, + 1, + 415, + 453, + 2, + 401, + 454, + 1, + 416, + 454, + 1, + 401, + 455, + 1, + 416, + 455, + 1, + 416, + 456, + 2, + 417, + 462, + 2, + 418, + 468, + 1, + 413, + 473, + 6, + 413, + 474, + 3, + 415, + 478, + 1, + 413, + 484, + 3, + 414, + 488, + 1, + 414, + 489, + 1, + 413, + 490, + 2, + 414, + 491, + 1, + 414, + 492, + 1, + 414, + 497, + 1, + 411, + 498, + 2, + 408, + 499, + 4 + ] + } + ], + "entities": [ + { + "__class": "PathMapEntity", + "metaData": {}, + "points": [ + 2015, + 1984, + 2016, + 1984, + 2015, + 1984, + 2025, + 1984, + 2038, + 1984, + 2042, + 1983, + 2041, + 1983, + 2041, + 1983, + 2041, + 1984, + 2030, + 1973, + 2024, + 1963, + 2021, + 1958, + 2022, + 1958, + 2011, + 1955, + 2001, + 1947, + 1999, + 1937, + 2002, + 1926, + 2007, + 1919, + 2018, + 1915, + 2029, + 1916, + 2034, + 1918, + 2034, + 1919, + 2036, + 1913, + 2035, + 1903, + 2036, + 1893, + 2035, + 1887 + ], + "type": "path" + }, + { + "__class": "PointMapEntity", + "metaData": { + "angle": -9 + }, + "points": [ + 2035, + 1887 + ], + "type": "robot_position" + } + ] +} \ No newline at end of file