From b1e74bb24e7785176e59699cfe8eb4f217c958c8 Mon Sep 17 00:00:00 2001 From: zhang <zc857179121@qq.com> Date: 星期三, 10 九月 2025 10:10:46 +0800 Subject: [PATCH] 1 --- algo-zkd/src/main/java/com/algo/service/TaskAllocationService.java | 292 algo-zkd/src/main/java/com/algo/AlgorithmMain.java | 67 service/src/main/resources/mapper/system/UserMapper.xml | 0 service/pom.xml | 60 algo-zkd/src/main/java/com/algo/util/AgvTaskUtils.java | 65 algo-zkd/src/main/java/com/algo/expose/AlgoSupport.java | 25 algo-zkd/src/main/resources/META-INF/spring.factories | 2 algo-zkd/src/main/java/com/algo/util/JsonUtils.java | 486 LICENSE | 201 algo-zkd/src/main/java/com/algo/service/CollisionResolver.java | 306 web-server/src/main/java/com/algo/controller/UserController.java | 41 algo-zkd/ctu_task_data.json | 11 rpc-server/src/main/java/com/algo/SpringBootRpcServerApplication.java | 17 README.md | 19 service/src/main/java/com/algo/mapper/UserMapper.java | 13 algo-zkd/path_mapping.json | 11880 ++++++++++++++++++++ algo-zkd/ctu_agv_status2.json | 259 rpc-server/pom.xml | 42 algo-zkd/src/main/java/com/algo/model/PlannedPath.java | 99 .gitignore | 14 algo-zkd/src/main/java/com/algo/service/PathPlanningService.java | 828 + algo-zkd/src/main/java/com/algo/model/ExecutingTask.java | 172 api/src/main/java/com/algo/entity/User.java | 25 algo-zkd/src/main/java/com/algo/model/BackpackData.java | 123 algo-zkd/ctu_agv_status.json | 48 algo-zkd/src/main/java/com/algo/service/CollisionDetector.java | 567 algo-zkd/src/main/java/com/algo/model/PathCode.java | 136 web-server/src/main/resources/application.yml | 19 algo-zkd/ctu_task_data2.json | 92 algo-zkd/environment.json | 14960 ++++++++++++++++++++++++++ algo-zkd/pom.xml | 45 algo-zkd/src/main/java/com/algo/model/TaskData.java | 228 web-server/pom.xml | 41 algo-zkd/src/main/java/com/algo/model/CTUPhysicalConfig.java | 322 algo-zkd/src/main/java/com/algo/model/TaskAssignment.java | 183 algo-zkd/src/main/java/com/algo/service/RemainingPathProcessor.java | 416 algo-zkd/src/main/resources/application.yml | 8 algo-zkd/src/main/java/com/algo/service/AStarPathPlanner.java | 932 + algo-zkd/src/main/java/com/algo/service/ExecutingTaskExtractor.java | 478 algo-zkd/src/main/java/com/algo/service/PathPlanner.java | 64 api/pom.xml | 92 rpc-server/src/main/resources/application.yml | 85 algo-zkd/src/main/java/com/algo/SpringBootAplication.java | 15 api/src/main/java/com/algo/service/UserService.java | 20 algo-zkd/src/main/java/com/algo/expose/impl/AlgoSupportImpl.java | 26 algo-zkd/src/main/java/com/algo/model/AGVStatus.java | 379 rpc-server/target/classes/application.yml | 40 algo-zkd/src/main/java/com/algo/model/Conflict.java | 128 web-server/src/main/java/com/algo/SpringBootAplication.java | 17 service/src/main/java/com/algo/support/UserServiceSupport.java | 49 50 files changed, 34,400 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index f519d1f..7f68d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,11 @@ +# Compiled class file *.class + +# Log file +*.log + +# BlueJ files +*.ctxt # Mobile Tools for Java (J2ME) .mtj.tmp/ @@ -6,9 +13,14 @@ # Package Files # *.jar *.war +*.nar *.ear +*.zip +*.tar.gz +*.rar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +target .idea -.gitignore +.gitignore \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 2d98e73..ff19738 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,19 @@ -## algo-java +## 浠嬬粛 + +鏈」鐩妧鏈珯锛� +jdk8 + springboot + dubbo + mysql + redis + zookeeper + +api妯″潡鎻愪緵鏈�鍩虹鐨勫疄浣撶被锛屾灇涓剧被绛夛紝鏈�閲嶈鏄渶瑕佹毚闇插嚭鍘荤殑鎶借薄鎺ュ彛銆� + +service鍐欏叿浣撶殑鎺ュ彛鐨勫疄鐜扮被锛屾彁渚涘叿浣撶殑瀹炵幇绫汇�� + +rpc-server閲岄潰鏄竴涓惎鍔ㄧ被锛屽洜涓轰緷璧杝ervice妯″潡锛屽彲浠ョ悊瑙d负鐢熶骇鎻愪緵鑰呫�� + +web-server鍒欐槸涓昏鎻愪緵http鎺ュ彛缁欑涓夋柟锛屽鍓嶇璋冪敤锛屼篃鍙互寮曞叆鍏朵粬椤圭洰鐨刟pi妯″潡锛屼箣鍚庡彧瑕佹湁鐢熶骇鑰呮敞鍏ュ埌娉ㄥ唽涓績灏卞彲浠ユ彁渚涙湇鍔′簡锛岀洿鎺ヨ皟鐢╝pi閲岄潰鐨勬娊璞℃帴鍙f柟娉曘�� + +涓澶х殑鑰佸笀锛岃礋璐e啀service妯″潡閲屽啓绠楁硶鍗冲彲 - +1.service宸茬粡闆嗘垚浜唕edis鍜宮ysql涔熼兘鏈夌ず渚� +2.api妯″潡閲屽彧瑕佸啓鎺ュ彛锛屼緵绗笁鏂圭郴缁熶娇鐢� +3. \ No newline at end of file diff --git a/algo-zkd/ctu_agv_status.json b/algo-zkd/ctu_agv_status.json new file mode 100644 index 0000000..b9f494c --- /dev/null +++ b/algo-zkd/ctu_agv_status.json @@ -0,0 +1,48 @@ +[ + { + "agvId": "105", + "status": 0, + "position": "213", + "empty": "2", + "direction": "90", + "vol": 85, + "error": 0, + "autoCharge": 30, + "lowVol": 15, + "currentPathIndex": 1, + "nextPointArrivalTime": 1692345600000, + "backpack": [ + { + "index": 0, + "loaded": false, + "taskId": "TASK_001" + }, + { + "index": 1, + "loaded": false, + "taskId": null + }, + { + "index": 2, + "loaded": false, + "taskId": null + } + ], + + "physicalConfig": { + "maxSpeed": 2.0, + "normalSpeed": 1.5, + "maxAcceleration": 1.0, + "maxDeceleration": 1.5, + "turnTime90": 2.0, + "turnTime180": 4.0, + "minSafetyDistance": 3.0, + "minFollowingDistance": 2.0, + "ctuLength": 1.5, + "ctuWidth": 1.0, + "startupTime": 1.0, + "stopTime": 1.5, + "standardPointDistance": 1.0 + } + } +] \ No newline at end of file diff --git a/algo-zkd/ctu_agv_status2.json b/algo-zkd/ctu_agv_status2.json new file mode 100644 index 0000000..1ef389c --- /dev/null +++ b/algo-zkd/ctu_agv_status2.json @@ -0,0 +1,259 @@ +[ + { + "agvId": "CTU_001", + "status": 0, + "position": "1547", + "empty": "2", + "direction": "90", + "vol": 85, + "error": 0, + "autoCharge": 30, + "lowVol": 15, + "currentPathIndex": 1, + "nextPointArrivalTime": 1692345600000, + "backpack": [ + { + "index": 0, + "loaded": false, + "taskId": "TASK_001" + }, + { + "index": 1, + "loaded": false, + "taskId": null + }, + { + "index": 2, + "loaded": false, + "taskId": null + } + ], + + "physicalConfig": { + "maxSpeed": 2.0, + "normalSpeed": 1.5, + "maxAcceleration": 1.0, + "maxDeceleration": 1.5, + "turnTime90": 2.0, + "turnTime180": 4.0, + "minSafetyDistance": 3.0, + "minFollowingDistance": 2.0, + "ctuLength": 1.5, + "ctuWidth": 1.0, + "startupTime": 1.0, + "stopTime": 1.5, + "standardPointDistance": 1.0 + } + }, + { + "agvId": "CTU_002", + "status": 0, + "position": "592", + "empty": "3", + "direction": "270", + "vol": 75, + "error": 0, + "autoCharge": 30, + "lowVol": 15, + "currentPathIndex": 0, + "nextPointArrivalTime": 1692345620000, + "backpack": [ + { + "index": 0, + "loaded": false, + "taskId": null + }, + { + "index": 1, + "loaded": false, + "taskId": null + }, + { + "index": 2, + "loaded": false, + "taskId": null + } + ], + "remainingPath": { + "agvId": "CTU_002", + "segId": "SEG_002_CTU_002_pickup", + "codeList": [ + { + "code": "592", + "direction": "270", + "actionType": "2", + "taskId": "TASK_002", + "posType": null, + "lev": 0, + "isTargetPoint": false + }, + { + "code": "599", + "direction": "0", + "actionType": "2", + "taskId": "TASK_002", + "posType": null, + "lev": 0, + "isTargetPoint": false + }, + { + "code": "647", + "direction": "0", + "actionType": "2", + "taskId": "TASK_002", + "posType": "1", + "lev": 0, + "isTargetPoint": true + } + ] + }, + "physicalConfig": { + "maxSpeed": 2.0, + "normalSpeed": 1.5, + "maxAcceleration": 1.0, + "maxDeceleration": 1.5, + "turnTime90": 2.0, + "turnTime180": 4.0, + "minSafetyDistance": 3.0, + "minFollowingDistance": 2.0, + "ctuLength": 1.5, + "ctuWidth": 1.0, + "startupTime": 1.0, + "stopTime": 1.5, + "standardPointDistance": 1.0 + } + }, + { + "agvId": "CTU_003", + "status": 0, + "position": "733", + "empty": "3", + "direction": "0", + "vol": 90, + "error": 0, + "autoCharge": 30, + "lowVol": 15, + "currentPathIndex": 0, + "nextPointArrivalTime": 1692345640000, + "backpack": [ + { + "index": 0, + "loaded": false, + "taskId": null + }, + { + "index": 1, + "loaded": false, + "taskId": null + }, + { + "index": 2, + "loaded": false, + "taskId": null + } + ], + "remainingPath": null, + "physicalConfig": { + "maxSpeed": 2.0, + "normalSpeed": 1.5, + "maxAcceleration": 1.0, + "maxDeceleration": 1.5, + "turnTime90": 2.0, + "turnTime180": 4.0, + "minSafetyDistance": 3.0, + "minFollowingDistance": 2.0, + "ctuLength": 1.5, + "ctuWidth": 1.0, + "startupTime": 1.0, + "stopTime": 1.5, + "standardPointDistance": 1.0 + } + }, + { + "agvId": "CTU_004", + "status": 0, + "position": "686", + "empty": "2", + "direction": "180", + "vol": 25, + "error": 0, + "autoCharge": 30, + "lowVol": 15, + "currentPathIndex": 2, + "nextPointArrivalTime": 1692345660000, + "backpack": [ + { + "index": 0, + "loaded": true, + "taskId": "TASK_004" + }, + { + "index": 1, + "loaded": true, + "taskId": "TASK_005" + }, + { + "index": 2, + "loaded": false, + "taskId": null + } + ], + "remainingPath": { + "agvId": "CTU_004", + "segId": "SEG_004_CTU_004_charging", + "codeList": [ + { + "code": "686", + "direction": "180", + "actionType": "3", + "taskId": null, + "posType": null, + "lev": 0, + "isTargetPoint": false + }, + { + "code": "679", + "direction": "270", + "actionType": "3", + "taskId": null, + "posType": null, + "lev": 0, + "isTargetPoint": false + }, + { + "code": "654", + "direction": "270", + "actionType": "3", + "taskId": null, + "posType": null, + "lev": 0, + "isTargetPoint": false + }, + { + "code": "647", + "direction": "270", + "actionType": "3", + "taskId": null, + "posType": null, + "lev": 0, + "isTargetPoint": true + } + ] + }, + "physicalConfig": { + "maxSpeed": 2.0, + "normalSpeed": 1.5, + "maxAcceleration": 1.0, + "maxDeceleration": 1.5, + "turnTime90": 2.0, + "turnTime180": 4.0, + "minSafetyDistance": 3.0, + "minFollowingDistance": 2.0, + "ctuLength": 1.5, + "ctuWidth": 1.0, + "startupTime": 1.0, + "stopTime": 1.5, + "standardPointDistance": 1.0 + } + } +] \ No newline at end of file diff --git a/algo-zkd/ctu_task_data.json b/algo-zkd/ctu_task_data.json new file mode 100644 index 0000000..6a47b6a --- /dev/null +++ b/algo-zkd/ctu_task_data.json @@ -0,0 +1,11 @@ +[ + { + "taskId": "TASK_001", + "agvId": "105", + "start": "238", + "end": "250", + "type": "1", + "priority": 5, + "taskTime": "2023-08-18 10:00:00" + } +] \ No newline at end of file diff --git a/algo-zkd/ctu_task_data2.json b/algo-zkd/ctu_task_data2.json new file mode 100644 index 0000000..0a7558b --- /dev/null +++ b/algo-zkd/ctu_task_data2.json @@ -0,0 +1,92 @@ +[ + { + "taskId": "TASK_001", + "agvId": null, + "start": "346", + "end": "448", + "type": "2", + "priority": 5, + "taskTime": "2023-08-18 10:00:00" + }, + { + "taskId": "TASK_002", + "agvId": null, + "start": "592", + "end": "647", + "type": "1", + "priority": 3, + "taskTime": "2023-08-18 10:05:00" + }, + { + "taskId": "TASK_003", + "agvId": null, + "start": "733", + "end": "456", + "type": "3", + "priority": 4, + "taskTime": "2023-08-18 10:10:00" + }, + { + "taskId": "TASK_004", + "agvId": null, + "start": "686", + "end": "482", + "type": "2", + "priority": 6, + "taskTime": "2023-08-18 10:15:00" + }, + { + "taskId": "TASK_005", + "agvId": null, + "start": "679", + "end": "537", + "type": "1", + "priority": 2, + "taskTime": "2023-08-18 10:20:00" + }, + { + "taskId": "CHARGE_001", + "agvId": "CTU_004", + "start": "686", + "end": "647", + "type": "5", + "priority": 8, + "taskTime": "2023-08-18 10:25:00" + }, + { + "taskId": "STANDBY_001", + "agvId": "CTU_003", + "start": "733", + "end": "599", + "type": "4", + "priority": 1, + "taskTime": "2023-08-18 10:30:00" + }, + { + "taskId": "TASK_006", + "agvId": null, + "start": "544", + "end": "654", + "type": "3", + "priority": 7, + "taskTime": "2023-08-18 10:35:00" + }, + { + "taskId": "TASK_007", + "agvId": null, + "start": "490", + "end": "599", + "type": "1", + "priority": 4, + "taskTime": "2023-08-18 10:40:00" + }, + { + "taskId": "TASK_008", + "agvId": null, + "start": "456", + "end": "733", + "type": "2", + "priority": 3, + "taskTime": "2023-08-18 10:45:00" + } +] \ No newline at end of file diff --git a/algo-zkd/environment.json b/algo-zkd/environment.json new file mode 100644 index 0000000..6915ebc --- /dev/null +++ b/algo-zkd/environment.json @@ -0,0 +1,14960 @@ +{ + "width": 78, + "height": 50, + "stations": { + "2,48": { + "capacity": 4, + "load_position": [ + 3, + 48 + ], + "unload_position": [ + 1, + 48 + ] + }, + "5,48": { + "capacity": 4, + "load_position": [ + 6, + 48 + ], + "unload_position": [ + 4, + 48 + ] + }, + "8,48": { + "capacity": 4, + "load_position": [ + 9, + 48 + ], + "unload_position": [ + 7, + 48 + ] + }, + "12,48": { + "capacity": 4, + "load_position": [ + 13, + 48 + ], + "unload_position": [ + 11, + 48 + ] + }, + "18,48": { + "capacity": 4, + "load_position": [ + 19, + 48 + ], + "unload_position": [ + 17, + 48 + ] + }, + "21,48": { + "capacity": 4, + "load_position": [ + 22, + 48 + ], + "unload_position": [ + 20, + 48 + ] + }, + "24,48": { + "capacity": 4, + "load_position": [ + 25, + 48 + ], + "unload_position": [ + 23, + 48 + ] + }, + "28,48": { + "capacity": 4, + "load_position": [ + 29, + 48 + ], + "unload_position": [ + 27, + 48 + ] + }, + "34,48": { + "capacity": 4, + "load_position": [ + 35, + 48 + ], + "unload_position": [ + 33, + 48 + ] + }, + "37,48": { + "capacity": 4, + "load_position": [ + 38, + 48 + ], + "unload_position": [ + 36, + 48 + ] + }, + "40,48": { + "capacity": 4, + "load_position": [ + 41, + 48 + ], + "unload_position": [ + 39, + 48 + ] + }, + "44,48": { + "capacity": 4, + "load_position": [ + 45, + 48 + ], + "unload_position": [ + 43, + 48 + ] + }, + "50,48": { + "capacity": 4, + "load_position": [ + 51, + 48 + ], + "unload_position": [ + 49, + 48 + ] + }, + "53,48": { + "capacity": 4, + "load_position": [ + 54, + 48 + ], + "unload_position": [ + 52, + 48 + ] + }, + "56,48": { + "capacity": 4, + "load_position": [ + 57, + 48 + ], + "unload_position": [ + 55, + 48 + ] + }, + "60,48": { + "capacity": 4, + "load_position": [ + 61, + 48 + ], + "unload_position": [ + 59, + 48 + ] + }, + "66,48": { + "capacity": 4, + "load_position": [ + 67, + 48 + ], + "unload_position": [ + 65, + 48 + ] + }, + "69,48": { + "capacity": 4, + "load_position": [ + 70, + 48 + ], + "unload_position": [ + 68, + 48 + ] + }, + "72,48": { + "capacity": 4, + "load_position": [ + 73, + 48 + ], + "unload_position": [ + 71, + 48 + ] + }, + "76,48": { + "capacity": 4, + "load_position": [ + 77, + 48 + ], + "unload_position": [ + 75, + 48 + ] + } + }, + "paths": [ + { + "x": 17, + "y": 0 + }, + { + "x": 18, + "y": 0 + }, + { + "x": 19, + "y": 0 + }, + { + "x": 20, + "y": 0 + }, + { + "x": 21, + "y": 0 + }, + { + "x": 22, + "y": 0 + }, + { + "x": 23, + "y": 0 + }, + { + "x": 24, + "y": 0 + }, + { + "x": 25, + "y": 0 + }, + { + "x": 26, + "y": 0 + }, + { + "x": 27, + "y": 0 + }, + { + "x": 28, + "y": 0 + }, + { + "x": 29, + "y": 0 + }, + { + "x": 30, + "y": 0 + }, + { + "x": 31, + "y": 0 + }, + { + "x": 32, + "y": 0 + }, + { + "x": 33, + "y": 0 + }, + { + "x": 34, + "y": 0 + }, + { + "x": 35, + "y": 0 + }, + { + "x": 36, + "y": 0 + }, + { + "x": 37, + "y": 0 + }, + { + "x": 38, + "y": 0 + }, + { + "x": 39, + "y": 0 + }, + { + "x": 40, + "y": 0 + }, + { + "x": 41, + "y": 0 + }, + { + "x": 42, + "y": 0 + }, + { + "x": 43, + "y": 0 + }, + { + "x": 44, + "y": 0 + }, + { + "x": 45, + "y": 0 + }, + { + "x": 46, + "y": 0 + }, + { + "x": 47, + "y": 0 + }, + { + "x": 48, + "y": 0 + }, + { + "x": 49, + "y": 0 + }, + { + "x": 50, + "y": 0 + }, + { + "x": 51, + "y": 0 + }, + { + "x": 52, + "y": 0 + }, + { + "x": 53, + "y": 0 + }, + { + "x": 54, + "y": 0 + }, + { + "x": 55, + "y": 0 + }, + { + "x": 56, + "y": 0 + }, + { + "x": 57, + "y": 0 + }, + { + "x": 58, + "y": 0 + }, + { + "x": 59, + "y": 0 + }, + { + "x": 60, + "y": 0 + }, + { + "x": 61, + "y": 0 + }, + { + "x": 17, + "y": 1 + }, + { + "x": 19, + "y": 1 + }, + { + "x": 21, + "y": 1 + }, + { + "x": 23, + "y": 1 + }, + { + "x": 25, + "y": 1 + }, + { + "x": 27, + "y": 1 + }, + { + "x": 29, + "y": 1 + }, + { + "x": 31, + "y": 1 + }, + { + "x": 33, + "y": 1 + }, + { + "x": 35, + "y": 1 + }, + { + "x": 37, + "y": 1 + }, + { + "x": 39, + "y": 1 + }, + { + "x": 41, + "y": 1 + }, + { + "x": 43, + "y": 1 + }, + { + "x": 45, + "y": 1 + }, + { + "x": 47, + "y": 1 + }, + { + "x": 49, + "y": 1 + }, + { + "x": 51, + "y": 1 + }, + { + "x": 53, + "y": 1 + }, + { + "x": 55, + "y": 1 + }, + { + "x": 57, + "y": 1 + }, + { + "x": 59, + "y": 1 + }, + { + "x": 61, + "y": 1 + }, + { + "x": 17, + "y": 2 + }, + { + "x": 19, + "y": 2 + }, + { + "x": 21, + "y": 2 + }, + { + "x": 23, + "y": 2 + }, + { + "x": 25, + "y": 2 + }, + { + "x": 27, + "y": 2 + }, + { + "x": 29, + "y": 2 + }, + { + "x": 31, + "y": 2 + }, + { + "x": 33, + "y": 2 + }, + { + "x": 35, + "y": 2 + }, + { + "x": 37, + "y": 2 + }, + { + "x": 39, + "y": 2 + }, + { + "x": 41, + "y": 2 + }, + { + "x": 43, + "y": 2 + }, + { + "x": 45, + "y": 2 + }, + { + "x": 47, + "y": 2 + }, + { + "x": 49, + "y": 2 + }, + { + "x": 51, + "y": 2 + }, + { + "x": 53, + "y": 2 + }, + { + "x": 55, + "y": 2 + }, + { + "x": 57, + "y": 2 + }, + { + "x": 59, + "y": 2 + }, + { + "x": 61, + "y": 2 + }, + { + "x": 17, + "y": 3 + }, + { + "x": 19, + "y": 3 + }, + { + "x": 21, + "y": 3 + }, + { + "x": 23, + "y": 3 + }, + { + "x": 25, + "y": 3 + }, + { + "x": 27, + "y": 3 + }, + { + "x": 29, + "y": 3 + }, + { + "x": 31, + "y": 3 + }, + { + "x": 33, + "y": 3 + }, + { + "x": 35, + "y": 3 + }, + { + "x": 37, + "y": 3 + }, + { + "x": 39, + "y": 3 + }, + { + "x": 41, + "y": 3 + }, + { + "x": 43, + "y": 3 + }, + { + "x": 45, + "y": 3 + }, + { + "x": 47, + "y": 3 + }, + { + "x": 49, + "y": 3 + }, + { + "x": 51, + "y": 3 + }, + { + "x": 53, + "y": 3 + }, + { + "x": 55, + "y": 3 + }, + { + "x": 57, + "y": 3 + }, + { + "x": 59, + "y": 3 + }, + { + "x": 61, + "y": 3 + }, + { + "x": 17, + "y": 4 + }, + { + "x": 19, + "y": 4 + }, + { + "x": 21, + "y": 4 + }, + { + "x": 23, + "y": 4 + }, + { + "x": 25, + "y": 4 + }, + { + "x": 27, + "y": 4 + }, + { + "x": 29, + "y": 4 + }, + { + "x": 31, + "y": 4 + }, + { + "x": 33, + "y": 4 + }, + { + "x": 35, + "y": 4 + }, + { + "x": 37, + "y": 4 + }, + { + "x": 39, + "y": 4 + }, + { + "x": 41, + "y": 4 + }, + { + "x": 43, + "y": 4 + }, + { + "x": 45, + "y": 4 + }, + { + "x": 47, + "y": 4 + }, + { + "x": 49, + "y": 4 + }, + { + "x": 51, + "y": 4 + }, + { + "x": 53, + "y": 4 + }, + { + "x": 55, + "y": 4 + }, + { + "x": 57, + "y": 4 + }, + { + "x": 59, + "y": 4 + }, + { + "x": 61, + "y": 4 + }, + { + "x": 17, + "y": 5 + }, + { + "x": 19, + "y": 5 + }, + { + "x": 21, + "y": 5 + }, + { + "x": 23, + "y": 5 + }, + { + "x": 25, + "y": 5 + }, + { + "x": 27, + "y": 5 + }, + { + "x": 29, + "y": 5 + }, + { + "x": 31, + "y": 5 + }, + { + "x": 33, + "y": 5 + }, + { + "x": 35, + "y": 5 + }, + { + "x": 37, + "y": 5 + }, + { + "x": 39, + "y": 5 + }, + { + "x": 41, + "y": 5 + }, + { + "x": 43, + "y": 5 + }, + { + "x": 45, + "y": 5 + }, + { + "x": 47, + "y": 5 + }, + { + "x": 49, + "y": 5 + }, + { + "x": 51, + "y": 5 + }, + { + "x": 53, + "y": 5 + }, + { + "x": 55, + "y": 5 + }, + { + "x": 57, + "y": 5 + }, + { + "x": 59, + "y": 5 + }, + { + "x": 61, + "y": 5 + }, + { + "x": 17, + "y": 6 + }, + { + "x": 18, + "y": 6 + }, + { + "x": 19, + "y": 6 + }, + { + "x": 20, + "y": 6 + }, + { + "x": 21, + "y": 6 + }, + { + "x": 22, + "y": 6 + }, + { + "x": 23, + "y": 6 + }, + { + "x": 24, + "y": 6 + }, + { + "x": 25, + "y": 6 + }, + { + "x": 26, + "y": 6 + }, + { + "x": 27, + "y": 6 + }, + { + "x": 28, + "y": 6 + }, + { + "x": 29, + "y": 6 + }, + { + "x": 30, + "y": 6 + }, + { + "x": 31, + "y": 6 + }, + { + "x": 32, + "y": 6 + }, + { + "x": 33, + "y": 6 + }, + { + "x": 34, + "y": 6 + }, + { + "x": 35, + "y": 6 + }, + { + "x": 36, + "y": 6 + }, + { + "x": 37, + "y": 6 + }, + { + "x": 38, + "y": 6 + }, + { + "x": 39, + "y": 6 + }, + { + "x": 40, + "y": 6 + }, + { + "x": 41, + "y": 6 + }, + { + "x": 42, + "y": 6 + }, + { + "x": 43, + "y": 6 + }, + { + "x": 44, + "y": 6 + }, + { + "x": 45, + "y": 6 + }, + { + "x": 46, + "y": 6 + }, + { + "x": 47, + "y": 6 + }, + { + "x": 48, + "y": 6 + }, + { + "x": 49, + "y": 6 + }, + { + "x": 50, + "y": 6 + }, + { + "x": 51, + "y": 6 + }, + { + "x": 52, + "y": 6 + }, + { + "x": 53, + "y": 6 + }, + { + "x": 54, + "y": 6 + }, + { + "x": 55, + "y": 6 + }, + { + "x": 56, + "y": 6 + }, + { + "x": 57, + "y": 6 + }, + { + "x": 58, + "y": 6 + }, + { + "x": 59, + "y": 6 + }, + { + "x": 60, + "y": 6 + }, + { + "x": 61, + "y": 6 + }, + { + "x": 17, + "y": 7 + }, + { + "x": 19, + "y": 7 + }, + { + "x": 21, + "y": 7 + }, + { + "x": 23, + "y": 7 + }, + { + "x": 25, + "y": 7 + }, + { + "x": 27, + "y": 7 + }, + { + "x": 29, + "y": 7 + }, + { + "x": 31, + "y": 7 + }, + { + "x": 33, + "y": 7 + }, + { + "x": 35, + "y": 7 + }, + { + "x": 37, + "y": 7 + }, + { + "x": 39, + "y": 7 + }, + { + "x": 41, + "y": 7 + }, + { + "x": 43, + "y": 7 + }, + { + "x": 45, + "y": 7 + }, + { + "x": 47, + "y": 7 + }, + { + "x": 49, + "y": 7 + }, + { + "x": 51, + "y": 7 + }, + { + "x": 53, + "y": 7 + }, + { + "x": 55, + "y": 7 + }, + { + "x": 57, + "y": 7 + }, + { + "x": 59, + "y": 7 + }, + { + "x": 61, + "y": 7 + }, + { + "x": 17, + "y": 8 + }, + { + "x": 19, + "y": 8 + }, + { + "x": 21, + "y": 8 + }, + { + "x": 23, + "y": 8 + }, + { + "x": 25, + "y": 8 + }, + { + "x": 27, + "y": 8 + }, + { + "x": 29, + "y": 8 + }, + { + "x": 31, + "y": 8 + }, + { + "x": 33, + "y": 8 + }, + { + "x": 35, + "y": 8 + }, + { + "x": 37, + "y": 8 + }, + { + "x": 39, + "y": 8 + }, + { + "x": 41, + "y": 8 + }, + { + "x": 43, + "y": 8 + }, + { + "x": 45, + "y": 8 + }, + { + "x": 47, + "y": 8 + }, + { + "x": 49, + "y": 8 + }, + { + "x": 51, + "y": 8 + }, + { + "x": 53, + "y": 8 + }, + { + "x": 55, + "y": 8 + }, + { + "x": 57, + "y": 8 + }, + { + "x": 59, + "y": 8 + }, + { + "x": 61, + "y": 8 + }, + { + "x": 17, + "y": 9 + }, + { + "x": 19, + "y": 9 + }, + { + "x": 21, + "y": 9 + }, + { + "x": 23, + "y": 9 + }, + { + "x": 25, + "y": 9 + }, + { + "x": 27, + "y": 9 + }, + { + "x": 29, + "y": 9 + }, + { + "x": 31, + "y": 9 + }, + { + "x": 33, + "y": 9 + }, + { + "x": 35, + "y": 9 + }, + { + "x": 37, + "y": 9 + }, + { + "x": 39, + "y": 9 + }, + { + "x": 41, + "y": 9 + }, + { + "x": 43, + "y": 9 + }, + { + "x": 45, + "y": 9 + }, + { + "x": 47, + "y": 9 + }, + { + "x": 49, + "y": 9 + }, + { + "x": 51, + "y": 9 + }, + { + "x": 53, + "y": 9 + }, + { + "x": 55, + "y": 9 + }, + { + "x": 57, + "y": 9 + }, + { + "x": 59, + "y": 9 + }, + { + "x": 61, + "y": 9 + }, + { + "x": 17, + "y": 10 + }, + { + "x": 19, + "y": 10 + }, + { + "x": 21, + "y": 10 + }, + { + "x": 23, + "y": 10 + }, + { + "x": 25, + "y": 10 + }, + { + "x": 27, + "y": 10 + }, + { + "x": 29, + "y": 10 + }, + { + "x": 31, + "y": 10 + }, + { + "x": 33, + "y": 10 + }, + { + "x": 35, + "y": 10 + }, + { + "x": 37, + "y": 10 + }, + { + "x": 39, + "y": 10 + }, + { + "x": 41, + "y": 10 + }, + { + "x": 43, + "y": 10 + }, + { + "x": 45, + "y": 10 + }, + { + "x": 47, + "y": 10 + }, + { + "x": 49, + "y": 10 + }, + { + "x": 51, + "y": 10 + }, + { + "x": 53, + "y": 10 + }, + { + "x": 55, + "y": 10 + }, + { + "x": 57, + "y": 10 + }, + { + "x": 59, + "y": 10 + }, + { + "x": 61, + "y": 10 + }, + { + "x": 17, + "y": 11 + }, + { + "x": 19, + "y": 11 + }, + { + "x": 21, + "y": 11 + }, + { + "x": 23, + "y": 11 + }, + { + "x": 25, + "y": 11 + }, + { + "x": 27, + "y": 11 + }, + { + "x": 29, + "y": 11 + }, + { + "x": 31, + "y": 11 + }, + { + "x": 33, + "y": 11 + }, + { + "x": 35, + "y": 11 + }, + { + "x": 37, + "y": 11 + }, + { + "x": 39, + "y": 11 + }, + { + "x": 41, + "y": 11 + }, + { + "x": 43, + "y": 11 + }, + { + "x": 45, + "y": 11 + }, + { + "x": 47, + "y": 11 + }, + { + "x": 49, + "y": 11 + }, + { + "x": 51, + "y": 11 + }, + { + "x": 53, + "y": 11 + }, + { + "x": 55, + "y": 11 + }, + { + "x": 57, + "y": 11 + }, + { + "x": 59, + "y": 11 + }, + { + "x": 61, + "y": 11 + }, + { + "x": 1, + "y": 12 + }, + { + "x": 2, + "y": 12 + }, + { + "x": 3, + "y": 12 + }, + { + "x": 4, + "y": 12 + }, + { + "x": 5, + "y": 12 + }, + { + "x": 6, + "y": 12 + }, + { + "x": 7, + "y": 12 + }, + { + "x": 8, + "y": 12 + }, + { + "x": 9, + "y": 12 + }, + { + "x": 10, + "y": 12 + }, + { + "x": 11, + "y": 12 + }, + { + "x": 12, + "y": 12 + }, + { + "x": 13, + "y": 12 + }, + { + "x": 14, + "y": 12 + }, + { + "x": 15, + "y": 12 + }, + { + "x": 16, + "y": 12 + }, + { + "x": 17, + "y": 12 + }, + { + "x": 18, + "y": 12 + }, + { + "x": 19, + "y": 12 + }, + { + "x": 20, + "y": 12 + }, + { + "x": 21, + "y": 12 + }, + { + "x": 22, + "y": 12 + }, + { + "x": 23, + "y": 12 + }, + { + "x": 24, + "y": 12 + }, + { + "x": 25, + "y": 12 + }, + { + "x": 26, + "y": 12 + }, + { + "x": 27, + "y": 12 + }, + { + "x": 28, + "y": 12 + }, + { + "x": 29, + "y": 12 + }, + { + "x": 30, + "y": 12 + }, + { + "x": 31, + "y": 12 + }, + { + "x": 32, + "y": 12 + }, + { + "x": 33, + "y": 12 + }, + { + "x": 34, + "y": 12 + }, + { + "x": 35, + "y": 12 + }, + { + "x": 36, + "y": 12 + }, + { + "x": 37, + "y": 12 + }, + { + "x": 38, + "y": 12 + }, + { + "x": 39, + "y": 12 + }, + { + "x": 40, + "y": 12 + }, + { + "x": 41, + "y": 12 + }, + { + "x": 42, + "y": 12 + }, + { + "x": 43, + "y": 12 + }, + { + "x": 44, + "y": 12 + }, + { + "x": 45, + "y": 12 + }, + { + "x": 46, + "y": 12 + }, + { + "x": 47, + "y": 12 + }, + { + "x": 48, + "y": 12 + }, + { + "x": 49, + "y": 12 + }, + { + "x": 50, + "y": 12 + }, + { + "x": 51, + "y": 12 + }, + { + "x": 52, + "y": 12 + }, + { + "x": 53, + "y": 12 + }, + { + "x": 54, + "y": 12 + }, + { + "x": 55, + "y": 12 + }, + { + "x": 56, + "y": 12 + }, + { + "x": 57, + "y": 12 + }, + { + "x": 58, + "y": 12 + }, + { + "x": 59, + "y": 12 + }, + { + "x": 60, + "y": 12 + }, + { + "x": 61, + "y": 12 + }, + { + "x": 62, + "y": 12 + }, + { + "x": 63, + "y": 12 + }, + { + "x": 64, + "y": 12 + }, + { + "x": 65, + "y": 12 + }, + { + "x": 66, + "y": 12 + }, + { + "x": 67, + "y": 12 + }, + { + "x": 68, + "y": 12 + }, + { + "x": 69, + "y": 12 + }, + { + "x": 70, + "y": 12 + }, + { + "x": 71, + "y": 12 + }, + { + "x": 72, + "y": 12 + }, + { + "x": 73, + "y": 12 + }, + { + "x": 74, + "y": 12 + }, + { + "x": 75, + "y": 12 + }, + { + "x": 1, + "y": 13 + }, + { + "x": 3, + "y": 13 + }, + { + "x": 5, + "y": 13 + }, + { + "x": 7, + "y": 13 + }, + { + "x": 9, + "y": 13 + }, + { + "x": 11, + "y": 13 + }, + { + "x": 13, + "y": 13 + }, + { + "x": 15, + "y": 13 + }, + { + "x": 17, + "y": 13 + }, + { + "x": 19, + "y": 13 + }, + { + "x": 21, + "y": 13 + }, + { + "x": 23, + "y": 13 + }, + { + "x": 25, + "y": 13 + }, + { + "x": 27, + "y": 13 + }, + { + "x": 29, + "y": 13 + }, + { + "x": 31, + "y": 13 + }, + { + "x": 33, + "y": 13 + }, + { + "x": 35, + "y": 13 + }, + { + "x": 37, + "y": 13 + }, + { + "x": 39, + "y": 13 + }, + { + "x": 41, + "y": 13 + }, + { + "x": 43, + "y": 13 + }, + { + "x": 45, + "y": 13 + }, + { + "x": 47, + "y": 13 + }, + { + "x": 49, + "y": 13 + }, + { + "x": 51, + "y": 13 + }, + { + "x": 53, + "y": 13 + }, + { + "x": 55, + "y": 13 + }, + { + "x": 57, + "y": 13 + }, + { + "x": 59, + "y": 13 + }, + { + "x": 61, + "y": 13 + }, + { + "x": 63, + "y": 13 + }, + { + "x": 65, + "y": 13 + }, + { + "x": 67, + "y": 13 + }, + { + "x": 69, + "y": 13 + }, + { + "x": 71, + "y": 13 + }, + { + "x": 73, + "y": 13 + }, + { + "x": 75, + "y": 13 + }, + { + "x": 1, + "y": 14 + }, + { + "x": 3, + "y": 14 + }, + { + "x": 5, + "y": 14 + }, + { + "x": 7, + "y": 14 + }, + { + "x": 9, + "y": 14 + }, + { + "x": 11, + "y": 14 + }, + { + "x": 13, + "y": 14 + }, + { + "x": 15, + "y": 14 + }, + { + "x": 17, + "y": 14 + }, + { + "x": 19, + "y": 14 + }, + { + "x": 21, + "y": 14 + }, + { + "x": 23, + "y": 14 + }, + { + "x": 25, + "y": 14 + }, + { + "x": 27, + "y": 14 + }, + { + "x": 29, + "y": 14 + }, + { + "x": 31, + "y": 14 + }, + { + "x": 33, + "y": 14 + }, + { + "x": 35, + "y": 14 + }, + { + "x": 37, + "y": 14 + }, + { + "x": 39, + "y": 14 + }, + { + "x": 41, + "y": 14 + }, + { + "x": 43, + "y": 14 + }, + { + "x": 45, + "y": 14 + }, + { + "x": 47, + "y": 14 + }, + { + "x": 49, + "y": 14 + }, + { + "x": 51, + "y": 14 + }, + { + "x": 53, + "y": 14 + }, + { + "x": 55, + "y": 14 + }, + { + "x": 57, + "y": 14 + }, + { + "x": 59, + "y": 14 + }, + { + "x": 61, + "y": 14 + }, + { + "x": 63, + "y": 14 + }, + { + "x": 65, + "y": 14 + }, + { + "x": 67, + "y": 14 + }, + { + "x": 69, + "y": 14 + }, + { + "x": 71, + "y": 14 + }, + { + "x": 73, + "y": 14 + }, + { + "x": 75, + "y": 14 + }, + { + "x": 1, + "y": 15 + }, + { + "x": 3, + "y": 15 + }, + { + "x": 5, + "y": 15 + }, + { + "x": 7, + "y": 15 + }, + { + "x": 9, + "y": 15 + }, + { + "x": 11, + "y": 15 + }, + { + "x": 13, + "y": 15 + }, + { + "x": 15, + "y": 15 + }, + { + "x": 17, + "y": 15 + }, + { + "x": 19, + "y": 15 + }, + { + "x": 21, + "y": 15 + }, + { + "x": 23, + "y": 15 + }, + { + "x": 25, + "y": 15 + }, + { + "x": 27, + "y": 15 + }, + { + "x": 29, + "y": 15 + }, + { + "x": 31, + "y": 15 + }, + { + "x": 33, + "y": 15 + }, + { + "x": 35, + "y": 15 + }, + { + "x": 37, + "y": 15 + }, + { + "x": 39, + "y": 15 + }, + { + "x": 41, + "y": 15 + }, + { + "x": 43, + "y": 15 + }, + { + "x": 45, + "y": 15 + }, + { + "x": 47, + "y": 15 + }, + { + "x": 49, + "y": 15 + }, + { + "x": 51, + "y": 15 + }, + { + "x": 53, + "y": 15 + }, + { + "x": 55, + "y": 15 + }, + { + "x": 57, + "y": 15 + }, + { + "x": 59, + "y": 15 + }, + { + "x": 61, + "y": 15 + }, + { + "x": 63, + "y": 15 + }, + { + "x": 65, + "y": 15 + }, + { + "x": 67, + "y": 15 + }, + { + "x": 69, + "y": 15 + }, + { + "x": 71, + "y": 15 + }, + { + "x": 73, + "y": 15 + }, + { + "x": 75, + "y": 15 + }, + { + "x": 1, + "y": 16 + }, + { + "x": 3, + "y": 16 + }, + { + "x": 5, + "y": 16 + }, + { + "x": 7, + "y": 16 + }, + { + "x": 9, + "y": 16 + }, + { + "x": 11, + "y": 16 + }, + { + "x": 13, + "y": 16 + }, + { + "x": 15, + "y": 16 + }, + { + "x": 17, + "y": 16 + }, + { + "x": 19, + "y": 16 + }, + { + "x": 21, + "y": 16 + }, + { + "x": 23, + "y": 16 + }, + { + "x": 25, + "y": 16 + }, + { + "x": 27, + "y": 16 + }, + { + "x": 29, + "y": 16 + }, + { + "x": 31, + "y": 16 + }, + { + "x": 33, + "y": 16 + }, + { + "x": 35, + "y": 16 + }, + { + "x": 37, + "y": 16 + }, + { + "x": 39, + "y": 16 + }, + { + "x": 41, + "y": 16 + }, + { + "x": 43, + "y": 16 + }, + { + "x": 45, + "y": 16 + }, + { + "x": 47, + "y": 16 + }, + { + "x": 49, + "y": 16 + }, + { + "x": 51, + "y": 16 + }, + { + "x": 53, + "y": 16 + }, + { + "x": 55, + "y": 16 + }, + { + "x": 57, + "y": 16 + }, + { + "x": 59, + "y": 16 + }, + { + "x": 61, + "y": 16 + }, + { + "x": 63, + "y": 16 + }, + { + "x": 65, + "y": 16 + }, + { + "x": 67, + "y": 16 + }, + { + "x": 69, + "y": 16 + }, + { + "x": 71, + "y": 16 + }, + { + "x": 73, + "y": 16 + }, + { + "x": 75, + "y": 16 + }, + { + "x": 1, + "y": 17 + }, + { + "x": 3, + "y": 17 + }, + { + "x": 5, + "y": 17 + }, + { + "x": 7, + "y": 17 + }, + { + "x": 9, + "y": 17 + }, + { + "x": 11, + "y": 17 + }, + { + "x": 13, + "y": 17 + }, + { + "x": 15, + "y": 17 + }, + { + "x": 17, + "y": 17 + }, + { + "x": 19, + "y": 17 + }, + { + "x": 21, + "y": 17 + }, + { + "x": 23, + "y": 17 + }, + { + "x": 25, + "y": 17 + }, + { + "x": 27, + "y": 17 + }, + { + "x": 29, + "y": 17 + }, + { + "x": 31, + "y": 17 + }, + { + "x": 33, + "y": 17 + }, + { + "x": 35, + "y": 17 + }, + { + "x": 37, + "y": 17 + }, + { + "x": 39, + "y": 17 + }, + { + "x": 41, + "y": 17 + }, + { + "x": 43, + "y": 17 + }, + { + "x": 45, + "y": 17 + }, + { + "x": 47, + "y": 17 + }, + { + "x": 49, + "y": 17 + }, + { + "x": 51, + "y": 17 + }, + { + "x": 53, + "y": 17 + }, + { + "x": 55, + "y": 17 + }, + { + "x": 57, + "y": 17 + }, + { + "x": 59, + "y": 17 + }, + { + "x": 61, + "y": 17 + }, + { + "x": 63, + "y": 17 + }, + { + "x": 65, + "y": 17 + }, + { + "x": 67, + "y": 17 + }, + { + "x": 69, + "y": 17 + }, + { + "x": 71, + "y": 17 + }, + { + "x": 73, + "y": 17 + }, + { + "x": 75, + "y": 17 + }, + { + "x": 1, + "y": 18 + }, + { + "x": 3, + "y": 18 + }, + { + "x": 5, + "y": 18 + }, + { + "x": 7, + "y": 18 + }, + { + "x": 9, + "y": 18 + }, + { + "x": 11, + "y": 18 + }, + { + "x": 13, + "y": 18 + }, + { + "x": 15, + "y": 18 + }, + { + "x": 17, + "y": 18 + }, + { + "x": 19, + "y": 18 + }, + { + "x": 21, + "y": 18 + }, + { + "x": 23, + "y": 18 + }, + { + "x": 25, + "y": 18 + }, + { + "x": 27, + "y": 18 + }, + { + "x": 29, + "y": 18 + }, + { + "x": 31, + "y": 18 + }, + { + "x": 33, + "y": 18 + }, + { + "x": 35, + "y": 18 + }, + { + "x": 37, + "y": 18 + }, + { + "x": 39, + "y": 18 + }, + { + "x": 41, + "y": 18 + }, + { + "x": 43, + "y": 18 + }, + { + "x": 45, + "y": 18 + }, + { + "x": 47, + "y": 18 + }, + { + "x": 49, + "y": 18 + }, + { + "x": 51, + "y": 18 + }, + { + "x": 53, + "y": 18 + }, + { + "x": 55, + "y": 18 + }, + { + "x": 57, + "y": 18 + }, + { + "x": 59, + "y": 18 + }, + { + "x": 61, + "y": 18 + }, + { + "x": 63, + "y": 18 + }, + { + "x": 65, + "y": 18 + }, + { + "x": 67, + "y": 18 + }, + { + "x": 69, + "y": 18 + }, + { + "x": 71, + "y": 18 + }, + { + "x": 73, + "y": 18 + }, + { + "x": 75, + "y": 18 + }, + { + "x": 1, + "y": 19 + }, + { + "x": 3, + "y": 19 + }, + { + "x": 5, + "y": 19 + }, + { + "x": 7, + "y": 19 + }, + { + "x": 9, + "y": 19 + }, + { + "x": 11, + "y": 19 + }, + { + "x": 13, + "y": 19 + }, + { + "x": 15, + "y": 19 + }, + { + "x": 17, + "y": 19 + }, + { + "x": 19, + "y": 19 + }, + { + "x": 21, + "y": 19 + }, + { + "x": 23, + "y": 19 + }, + { + "x": 25, + "y": 19 + }, + { + "x": 27, + "y": 19 + }, + { + "x": 29, + "y": 19 + }, + { + "x": 31, + "y": 19 + }, + { + "x": 33, + "y": 19 + }, + { + "x": 35, + "y": 19 + }, + { + "x": 37, + "y": 19 + }, + { + "x": 39, + "y": 19 + }, + { + "x": 41, + "y": 19 + }, + { + "x": 43, + "y": 19 + }, + { + "x": 45, + "y": 19 + }, + { + "x": 47, + "y": 19 + }, + { + "x": 49, + "y": 19 + }, + { + "x": 51, + "y": 19 + }, + { + "x": 53, + "y": 19 + }, + { + "x": 55, + "y": 19 + }, + { + "x": 57, + "y": 19 + }, + { + "x": 59, + "y": 19 + }, + { + "x": 61, + "y": 19 + }, + { + "x": 63, + "y": 19 + }, + { + "x": 65, + "y": 19 + }, + { + "x": 67, + "y": 19 + }, + { + "x": 69, + "y": 19 + }, + { + "x": 71, + "y": 19 + }, + { + "x": 73, + "y": 19 + }, + { + "x": 75, + "y": 19 + }, + { + "x": 1, + "y": 20 + }, + { + "x": 3, + "y": 20 + }, + { + "x": 5, + "y": 20 + }, + { + "x": 7, + "y": 20 + }, + { + "x": 9, + "y": 20 + }, + { + "x": 11, + "y": 20 + }, + { + "x": 13, + "y": 20 + }, + { + "x": 15, + "y": 20 + }, + { + "x": 17, + "y": 20 + }, + { + "x": 19, + "y": 20 + }, + { + "x": 21, + "y": 20 + }, + { + "x": 23, + "y": 20 + }, + { + "x": 25, + "y": 20 + }, + { + "x": 27, + "y": 20 + }, + { + "x": 29, + "y": 20 + }, + { + "x": 31, + "y": 20 + }, + { + "x": 33, + "y": 20 + }, + { + "x": 35, + "y": 20 + }, + { + "x": 37, + "y": 20 + }, + { + "x": 39, + "y": 20 + }, + { + "x": 41, + "y": 20 + }, + { + "x": 43, + "y": 20 + }, + { + "x": 45, + "y": 20 + }, + { + "x": 47, + "y": 20 + }, + { + "x": 49, + "y": 20 + }, + { + "x": 51, + "y": 20 + }, + { + "x": 53, + "y": 20 + }, + { + "x": 55, + "y": 20 + }, + { + "x": 57, + "y": 20 + }, + { + "x": 59, + "y": 20 + }, + { + "x": 61, + "y": 20 + }, + { + "x": 63, + "y": 20 + }, + { + "x": 65, + "y": 20 + }, + { + "x": 67, + "y": 20 + }, + { + "x": 69, + "y": 20 + }, + { + "x": 71, + "y": 20 + }, + { + "x": 73, + "y": 20 + }, + { + "x": 75, + "y": 20 + }, + { + "x": 1, + "y": 21 + }, + { + "x": 3, + "y": 21 + }, + { + "x": 5, + "y": 21 + }, + { + "x": 7, + "y": 21 + }, + { + "x": 9, + "y": 21 + }, + { + "x": 11, + "y": 21 + }, + { + "x": 13, + "y": 21 + }, + { + "x": 15, + "y": 21 + }, + { + "x": 17, + "y": 21 + }, + { + "x": 19, + "y": 21 + }, + { + "x": 21, + "y": 21 + }, + { + "x": 23, + "y": 21 + }, + { + "x": 25, + "y": 21 + }, + { + "x": 27, + "y": 21 + }, + { + "x": 29, + "y": 21 + }, + { + "x": 31, + "y": 21 + }, + { + "x": 33, + "y": 21 + }, + { + "x": 35, + "y": 21 + }, + { + "x": 37, + "y": 21 + }, + { + "x": 39, + "y": 21 + }, + { + "x": 41, + "y": 21 + }, + { + "x": 43, + "y": 21 + }, + { + "x": 45, + "y": 21 + }, + { + "x": 47, + "y": 21 + }, + { + "x": 49, + "y": 21 + }, + { + "x": 51, + "y": 21 + }, + { + "x": 53, + "y": 21 + }, + { + "x": 55, + "y": 21 + }, + { + "x": 57, + "y": 21 + }, + { + "x": 59, + "y": 21 + }, + { + "x": 61, + "y": 21 + }, + { + "x": 63, + "y": 21 + }, + { + "x": 65, + "y": 21 + }, + { + "x": 67, + "y": 21 + }, + { + "x": 69, + "y": 21 + }, + { + "x": 71, + "y": 21 + }, + { + "x": 73, + "y": 21 + }, + { + "x": 75, + "y": 21 + }, + { + "x": 1, + "y": 22 + }, + { + "x": 2, + "y": 22 + }, + { + "x": 3, + "y": 22 + }, + { + "x": 4, + "y": 22 + }, + { + "x": 5, + "y": 22 + }, + { + "x": 6, + "y": 22 + }, + { + "x": 7, + "y": 22 + }, + { + "x": 8, + "y": 22 + }, + { + "x": 9, + "y": 22 + }, + { + "x": 10, + "y": 22 + }, + { + "x": 11, + "y": 22 + }, + { + "x": 12, + "y": 22 + }, + { + "x": 13, + "y": 22 + }, + { + "x": 14, + "y": 22 + }, + { + "x": 15, + "y": 22 + }, + { + "x": 16, + "y": 22 + }, + { + "x": 17, + "y": 22 + }, + { + "x": 18, + "y": 22 + }, + { + "x": 19, + "y": 22 + }, + { + "x": 20, + "y": 22 + }, + { + "x": 21, + "y": 22 + }, + { + "x": 22, + "y": 22 + }, + { + "x": 23, + "y": 22 + }, + { + "x": 24, + "y": 22 + }, + { + "x": 25, + "y": 22 + }, + { + "x": 26, + "y": 22 + }, + { + "x": 27, + "y": 22 + }, + { + "x": 28, + "y": 22 + }, + { + "x": 29, + "y": 22 + }, + { + "x": 30, + "y": 22 + }, + { + "x": 31, + "y": 22 + }, + { + "x": 32, + "y": 22 + }, + { + "x": 33, + "y": 22 + }, + { + "x": 34, + "y": 22 + }, + { + "x": 35, + "y": 22 + }, + { + "x": 36, + "y": 22 + }, + { + "x": 37, + "y": 22 + }, + { + "x": 38, + "y": 22 + }, + { + "x": 39, + "y": 22 + }, + { + "x": 40, + "y": 22 + }, + { + "x": 41, + "y": 22 + }, + { + "x": 42, + "y": 22 + }, + { + "x": 43, + "y": 22 + }, + { + "x": 44, + "y": 22 + }, + { + "x": 45, + "y": 22 + }, + { + "x": 46, + "y": 22 + }, + { + "x": 47, + "y": 22 + }, + { + "x": 48, + "y": 22 + }, + { + "x": 49, + "y": 22 + }, + { + "x": 50, + "y": 22 + }, + { + "x": 51, + "y": 22 + }, + { + "x": 52, + "y": 22 + }, + { + "x": 53, + "y": 22 + }, + { + "x": 54, + "y": 22 + }, + { + "x": 55, + "y": 22 + }, + { + "x": 56, + "y": 22 + }, + { + "x": 57, + "y": 22 + }, + { + "x": 58, + "y": 22 + }, + { + "x": 59, + "y": 22 + }, + { + "x": 60, + "y": 22 + }, + { + "x": 61, + "y": 22 + }, + { + "x": 62, + "y": 22 + }, + { + "x": 63, + "y": 22 + }, + { + "x": 64, + "y": 22 + }, + { + "x": 65, + "y": 22 + }, + { + "x": 66, + "y": 22 + }, + { + "x": 67, + "y": 22 + }, + { + "x": 68, + "y": 22 + }, + { + "x": 69, + "y": 22 + }, + { + "x": 70, + "y": 22 + }, + { + "x": 71, + "y": 22 + }, + { + "x": 72, + "y": 22 + }, + { + "x": 73, + "y": 22 + }, + { + "x": 74, + "y": 22 + }, + { + "x": 75, + "y": 22 + }, + { + "x": 1, + "y": 23 + }, + { + "x": 3, + "y": 23 + }, + { + "x": 5, + "y": 23 + }, + { + "x": 9, + "y": 23 + }, + { + "x": 11, + "y": 23 + }, + { + "x": 13, + "y": 23 + }, + { + "x": 17, + "y": 23 + }, + { + "x": 19, + "y": 23 + }, + { + "x": 21, + "y": 23 + }, + { + "x": 25, + "y": 23 + }, + { + "x": 27, + "y": 23 + }, + { + "x": 29, + "y": 23 + }, + { + "x": 33, + "y": 23 + }, + { + "x": 35, + "y": 23 + }, + { + "x": 37, + "y": 23 + }, + { + "x": 41, + "y": 23 + }, + { + "x": 43, + "y": 23 + }, + { + "x": 45, + "y": 23 + }, + { + "x": 49, + "y": 23 + }, + { + "x": 51, + "y": 23 + }, + { + "x": 53, + "y": 23 + }, + { + "x": 57, + "y": 23 + }, + { + "x": 59, + "y": 23 + }, + { + "x": 61, + "y": 23 + }, + { + "x": 65, + "y": 23 + }, + { + "x": 67, + "y": 23 + }, + { + "x": 69, + "y": 23 + }, + { + "x": 73, + "y": 23 + }, + { + "x": 75, + "y": 23 + }, + { + "x": 1, + "y": 24 + }, + { + "x": 3, + "y": 24 + }, + { + "x": 5, + "y": 24 + }, + { + "x": 9, + "y": 24 + }, + { + "x": 11, + "y": 24 + }, + { + "x": 13, + "y": 24 + }, + { + "x": 17, + "y": 24 + }, + { + "x": 19, + "y": 24 + }, + { + "x": 21, + "y": 24 + }, + { + "x": 25, + "y": 24 + }, + { + "x": 27, + "y": 24 + }, + { + "x": 29, + "y": 24 + }, + { + "x": 33, + "y": 24 + }, + { + "x": 35, + "y": 24 + }, + { + "x": 37, + "y": 24 + }, + { + "x": 41, + "y": 24 + }, + { + "x": 43, + "y": 24 + }, + { + "x": 45, + "y": 24 + }, + { + "x": 49, + "y": 24 + }, + { + "x": 51, + "y": 24 + }, + { + "x": 53, + "y": 24 + }, + { + "x": 57, + "y": 24 + }, + { + "x": 59, + "y": 24 + }, + { + "x": 61, + "y": 24 + }, + { + "x": 65, + "y": 24 + }, + { + "x": 67, + "y": 24 + }, + { + "x": 69, + "y": 24 + }, + { + "x": 73, + "y": 24 + }, + { + "x": 75, + "y": 24 + }, + { + "x": 1, + "y": 25 + }, + { + "x": 3, + "y": 25 + }, + { + "x": 5, + "y": 25 + }, + { + "x": 9, + "y": 25 + }, + { + "x": 11, + "y": 25 + }, + { + "x": 13, + "y": 25 + }, + { + "x": 17, + "y": 25 + }, + { + "x": 19, + "y": 25 + }, + { + "x": 21, + "y": 25 + }, + { + "x": 25, + "y": 25 + }, + { + "x": 27, + "y": 25 + }, + { + "x": 29, + "y": 25 + }, + { + "x": 33, + "y": 25 + }, + { + "x": 35, + "y": 25 + }, + { + "x": 37, + "y": 25 + }, + { + "x": 41, + "y": 25 + }, + { + "x": 43, + "y": 25 + }, + { + "x": 45, + "y": 25 + }, + { + "x": 49, + "y": 25 + }, + { + "x": 51, + "y": 25 + }, + { + "x": 53, + "y": 25 + }, + { + "x": 57, + "y": 25 + }, + { + "x": 59, + "y": 25 + }, + { + "x": 61, + "y": 25 + }, + { + "x": 65, + "y": 25 + }, + { + "x": 67, + "y": 25 + }, + { + "x": 69, + "y": 25 + }, + { + "x": 73, + "y": 25 + }, + { + "x": 75, + "y": 25 + }, + { + "x": 1, + "y": 26 + }, + { + "x": 3, + "y": 26 + }, + { + "x": 5, + "y": 26 + }, + { + "x": 9, + "y": 26 + }, + { + "x": 11, + "y": 26 + }, + { + "x": 13, + "y": 26 + }, + { + "x": 17, + "y": 26 + }, + { + "x": 19, + "y": 26 + }, + { + "x": 21, + "y": 26 + }, + { + "x": 25, + "y": 26 + }, + { + "x": 27, + "y": 26 + }, + { + "x": 29, + "y": 26 + }, + { + "x": 33, + "y": 26 + }, + { + "x": 35, + "y": 26 + }, + { + "x": 37, + "y": 26 + }, + { + "x": 41, + "y": 26 + }, + { + "x": 43, + "y": 26 + }, + { + "x": 45, + "y": 26 + }, + { + "x": 49, + "y": 26 + }, + { + "x": 51, + "y": 26 + }, + { + "x": 53, + "y": 26 + }, + { + "x": 57, + "y": 26 + }, + { + "x": 59, + "y": 26 + }, + { + "x": 61, + "y": 26 + }, + { + "x": 65, + "y": 26 + }, + { + "x": 67, + "y": 26 + }, + { + "x": 69, + "y": 26 + }, + { + "x": 73, + "y": 26 + }, + { + "x": 75, + "y": 26 + }, + { + "x": 1, + "y": 27 + }, + { + "x": 3, + "y": 27 + }, + { + "x": 5, + "y": 27 + }, + { + "x": 9, + "y": 27 + }, + { + "x": 11, + "y": 27 + }, + { + "x": 13, + "y": 27 + }, + { + "x": 17, + "y": 27 + }, + { + "x": 19, + "y": 27 + }, + { + "x": 21, + "y": 27 + }, + { + "x": 25, + "y": 27 + }, + { + "x": 27, + "y": 27 + }, + { + "x": 29, + "y": 27 + }, + { + "x": 33, + "y": 27 + }, + { + "x": 35, + "y": 27 + }, + { + "x": 37, + "y": 27 + }, + { + "x": 41, + "y": 27 + }, + { + "x": 43, + "y": 27 + }, + { + "x": 45, + "y": 27 + }, + { + "x": 49, + "y": 27 + }, + { + "x": 51, + "y": 27 + }, + { + "x": 53, + "y": 27 + }, + { + "x": 57, + "y": 27 + }, + { + "x": 59, + "y": 27 + }, + { + "x": 61, + "y": 27 + }, + { + "x": 65, + "y": 27 + }, + { + "x": 67, + "y": 27 + }, + { + "x": 69, + "y": 27 + }, + { + "x": 73, + "y": 27 + }, + { + "x": 75, + "y": 27 + }, + { + "x": 1, + "y": 28 + }, + { + "x": 3, + "y": 28 + }, + { + "x": 5, + "y": 28 + }, + { + "x": 7, + "y": 28 + }, + { + "x": 9, + "y": 28 + }, + { + "x": 11, + "y": 28 + }, + { + "x": 13, + "y": 28 + }, + { + "x": 15, + "y": 28 + }, + { + "x": 17, + "y": 28 + }, + { + "x": 19, + "y": 28 + }, + { + "x": 21, + "y": 28 + }, + { + "x": 23, + "y": 28 + }, + { + "x": 25, + "y": 28 + }, + { + "x": 27, + "y": 28 + }, + { + "x": 29, + "y": 28 + }, + { + "x": 31, + "y": 28 + }, + { + "x": 33, + "y": 28 + }, + { + "x": 35, + "y": 28 + }, + { + "x": 37, + "y": 28 + }, + { + "x": 39, + "y": 28 + }, + { + "x": 41, + "y": 28 + }, + { + "x": 43, + "y": 28 + }, + { + "x": 45, + "y": 28 + }, + { + "x": 47, + "y": 28 + }, + { + "x": 49, + "y": 28 + }, + { + "x": 51, + "y": 28 + }, + { + "x": 53, + "y": 28 + }, + { + "x": 55, + "y": 28 + }, + { + "x": 57, + "y": 28 + }, + { + "x": 59, + "y": 28 + }, + { + "x": 61, + "y": 28 + }, + { + "x": 63, + "y": 28 + }, + { + "x": 65, + "y": 28 + }, + { + "x": 67, + "y": 28 + }, + { + "x": 69, + "y": 28 + }, + { + "x": 71, + "y": 28 + }, + { + "x": 73, + "y": 28 + }, + { + "x": 75, + "y": 28 + }, + { + "x": 1, + "y": 29 + }, + { + "x": 3, + "y": 29 + }, + { + "x": 5, + "y": 29 + }, + { + "x": 7, + "y": 29 + }, + { + "x": 9, + "y": 29 + }, + { + "x": 11, + "y": 29 + }, + { + "x": 13, + "y": 29 + }, + { + "x": 15, + "y": 29 + }, + { + "x": 17, + "y": 29 + }, + { + "x": 19, + "y": 29 + }, + { + "x": 21, + "y": 29 + }, + { + "x": 23, + "y": 29 + }, + { + "x": 25, + "y": 29 + }, + { + "x": 27, + "y": 29 + }, + { + "x": 29, + "y": 29 + }, + { + "x": 31, + "y": 29 + }, + { + "x": 33, + "y": 29 + }, + { + "x": 35, + "y": 29 + }, + { + "x": 37, + "y": 29 + }, + { + "x": 39, + "y": 29 + }, + { + "x": 41, + "y": 29 + }, + { + "x": 43, + "y": 29 + }, + { + "x": 45, + "y": 29 + }, + { + "x": 47, + "y": 29 + }, + { + "x": 49, + "y": 29 + }, + { + "x": 51, + "y": 29 + }, + { + "x": 53, + "y": 29 + }, + { + "x": 55, + "y": 29 + }, + { + "x": 57, + "y": 29 + }, + { + "x": 59, + "y": 29 + }, + { + "x": 61, + "y": 29 + }, + { + "x": 63, + "y": 29 + }, + { + "x": 65, + "y": 29 + }, + { + "x": 67, + "y": 29 + }, + { + "x": 69, + "y": 29 + }, + { + "x": 71, + "y": 29 + }, + { + "x": 73, + "y": 29 + }, + { + "x": 75, + "y": 29 + }, + { + "x": 1, + "y": 30 + }, + { + "x": 3, + "y": 30 + }, + { + "x": 5, + "y": 30 + }, + { + "x": 7, + "y": 30 + }, + { + "x": 9, + "y": 30 + }, + { + "x": 11, + "y": 30 + }, + { + "x": 13, + "y": 30 + }, + { + "x": 15, + "y": 30 + }, + { + "x": 17, + "y": 30 + }, + { + "x": 19, + "y": 30 + }, + { + "x": 21, + "y": 30 + }, + { + "x": 23, + "y": 30 + }, + { + "x": 25, + "y": 30 + }, + { + "x": 27, + "y": 30 + }, + { + "x": 29, + "y": 30 + }, + { + "x": 31, + "y": 30 + }, + { + "x": 33, + "y": 30 + }, + { + "x": 35, + "y": 30 + }, + { + "x": 37, + "y": 30 + }, + { + "x": 39, + "y": 30 + }, + { + "x": 41, + "y": 30 + }, + { + "x": 43, + "y": 30 + }, + { + "x": 45, + "y": 30 + }, + { + "x": 47, + "y": 30 + }, + { + "x": 49, + "y": 30 + }, + { + "x": 51, + "y": 30 + }, + { + "x": 53, + "y": 30 + }, + { + "x": 55, + "y": 30 + }, + { + "x": 57, + "y": 30 + }, + { + "x": 59, + "y": 30 + }, + { + "x": 61, + "y": 30 + }, + { + "x": 63, + "y": 30 + }, + { + "x": 65, + "y": 30 + }, + { + "x": 67, + "y": 30 + }, + { + "x": 69, + "y": 30 + }, + { + "x": 71, + "y": 30 + }, + { + "x": 73, + "y": 30 + }, + { + "x": 75, + "y": 30 + }, + { + "x": 1, + "y": 31 + }, + { + "x": 3, + "y": 31 + }, + { + "x": 5, + "y": 31 + }, + { + "x": 7, + "y": 31 + }, + { + "x": 9, + "y": 31 + }, + { + "x": 11, + "y": 31 + }, + { + "x": 13, + "y": 31 + }, + { + "x": 15, + "y": 31 + }, + { + "x": 17, + "y": 31 + }, + { + "x": 19, + "y": 31 + }, + { + "x": 21, + "y": 31 + }, + { + "x": 23, + "y": 31 + }, + { + "x": 25, + "y": 31 + }, + { + "x": 27, + "y": 31 + }, + { + "x": 29, + "y": 31 + }, + { + "x": 31, + "y": 31 + }, + { + "x": 33, + "y": 31 + }, + { + "x": 35, + "y": 31 + }, + { + "x": 37, + "y": 31 + }, + { + "x": 39, + "y": 31 + }, + { + "x": 41, + "y": 31 + }, + { + "x": 43, + "y": 31 + }, + { + "x": 45, + "y": 31 + }, + { + "x": 47, + "y": 31 + }, + { + "x": 49, + "y": 31 + }, + { + "x": 51, + "y": 31 + }, + { + "x": 53, + "y": 31 + }, + { + "x": 55, + "y": 31 + }, + { + "x": 57, + "y": 31 + }, + { + "x": 59, + "y": 31 + }, + { + "x": 61, + "y": 31 + }, + { + "x": 63, + "y": 31 + }, + { + "x": 65, + "y": 31 + }, + { + "x": 67, + "y": 31 + }, + { + "x": 69, + "y": 31 + }, + { + "x": 71, + "y": 31 + }, + { + "x": 73, + "y": 31 + }, + { + "x": 75, + "y": 31 + }, + { + "x": 1, + "y": 32 + }, + { + "x": 2, + "y": 32 + }, + { + "x": 3, + "y": 32 + }, + { + "x": 4, + "y": 32 + }, + { + "x": 5, + "y": 32 + }, + { + "x": 6, + "y": 32 + }, + { + "x": 7, + "y": 32 + }, + { + "x": 8, + "y": 32 + }, + { + "x": 9, + "y": 32 + }, + { + "x": 10, + "y": 32 + }, + { + "x": 11, + "y": 32 + }, + { + "x": 12, + "y": 32 + }, + { + "x": 13, + "y": 32 + }, + { + "x": 14, + "y": 32 + }, + { + "x": 15, + "y": 32 + }, + { + "x": 16, + "y": 32 + }, + { + "x": 17, + "y": 32 + }, + { + "x": 18, + "y": 32 + }, + { + "x": 19, + "y": 32 + }, + { + "x": 20, + "y": 32 + }, + { + "x": 21, + "y": 32 + }, + { + "x": 22, + "y": 32 + }, + { + "x": 23, + "y": 32 + }, + { + "x": 24, + "y": 32 + }, + { + "x": 25, + "y": 32 + }, + { + "x": 26, + "y": 32 + }, + { + "x": 27, + "y": 32 + }, + { + "x": 28, + "y": 32 + }, + { + "x": 29, + "y": 32 + }, + { + "x": 30, + "y": 32 + }, + { + "x": 31, + "y": 32 + }, + { + "x": 32, + "y": 32 + }, + { + "x": 33, + "y": 32 + }, + { + "x": 34, + "y": 32 + }, + { + "x": 35, + "y": 32 + }, + { + "x": 36, + "y": 32 + }, + { + "x": 37, + "y": 32 + }, + { + "x": 38, + "y": 32 + }, + { + "x": 39, + "y": 32 + }, + { + "x": 40, + "y": 32 + }, + { + "x": 41, + "y": 32 + }, + { + "x": 42, + "y": 32 + }, + { + "x": 43, + "y": 32 + }, + { + "x": 44, + "y": 32 + }, + { + "x": 45, + "y": 32 + }, + { + "x": 46, + "y": 32 + }, + { + "x": 47, + "y": 32 + }, + { + "x": 48, + "y": 32 + }, + { + "x": 49, + "y": 32 + }, + { + "x": 50, + "y": 32 + }, + { + "x": 51, + "y": 32 + }, + { + "x": 52, + "y": 32 + }, + { + "x": 53, + "y": 32 + }, + { + "x": 54, + "y": 32 + }, + { + "x": 55, + "y": 32 + }, + { + "x": 56, + "y": 32 + }, + { + "x": 57, + "y": 32 + }, + { + "x": 58, + "y": 32 + }, + { + "x": 59, + "y": 32 + }, + { + "x": 60, + "y": 32 + }, + { + "x": 61, + "y": 32 + }, + { + "x": 62, + "y": 32 + }, + { + "x": 63, + "y": 32 + }, + { + "x": 64, + "y": 32 + }, + { + "x": 65, + "y": 32 + }, + { + "x": 66, + "y": 32 + }, + { + "x": 67, + "y": 32 + }, + { + "x": 68, + "y": 32 + }, + { + "x": 69, + "y": 32 + }, + { + "x": 70, + "y": 32 + }, + { + "x": 71, + "y": 32 + }, + { + "x": 72, + "y": 32 + }, + { + "x": 73, + "y": 32 + }, + { + "x": 74, + "y": 32 + }, + { + "x": 75, + "y": 32 + }, + { + "x": 76, + "y": 32 + }, + { + "x": 77, + "y": 32 + }, + { + "x": 1, + "y": 33 + }, + { + "x": 3, + "y": 33 + }, + { + "x": 5, + "y": 33 + }, + { + "x": 7, + "y": 33 + }, + { + "x": 9, + "y": 33 + }, + { + "x": 11, + "y": 33 + }, + { + "x": 13, + "y": 33 + }, + { + "x": 15, + "y": 33 + }, + { + "x": 17, + "y": 33 + }, + { + "x": 19, + "y": 33 + }, + { + "x": 21, + "y": 33 + }, + { + "x": 23, + "y": 33 + }, + { + "x": 25, + "y": 33 + }, + { + "x": 27, + "y": 33 + }, + { + "x": 29, + "y": 33 + }, + { + "x": 31, + "y": 33 + }, + { + "x": 33, + "y": 33 + }, + { + "x": 35, + "y": 33 + }, + { + "x": 37, + "y": 33 + }, + { + "x": 39, + "y": 33 + }, + { + "x": 41, + "y": 33 + }, + { + "x": 43, + "y": 33 + }, + { + "x": 45, + "y": 33 + }, + { + "x": 47, + "y": 33 + }, + { + "x": 49, + "y": 33 + }, + { + "x": 51, + "y": 33 + }, + { + "x": 53, + "y": 33 + }, + { + "x": 55, + "y": 33 + }, + { + "x": 57, + "y": 33 + }, + { + "x": 59, + "y": 33 + }, + { + "x": 61, + "y": 33 + }, + { + "x": 63, + "y": 33 + }, + { + "x": 65, + "y": 33 + }, + { + "x": 67, + "y": 33 + }, + { + "x": 69, + "y": 33 + }, + { + "x": 71, + "y": 33 + }, + { + "x": 73, + "y": 33 + }, + { + "x": 75, + "y": 33 + }, + { + "x": 77, + "y": 33 + }, + { + "x": 1, + "y": 34 + }, + { + "x": 3, + "y": 34 + }, + { + "x": 5, + "y": 34 + }, + { + "x": 7, + "y": 34 + }, + { + "x": 9, + "y": 34 + }, + { + "x": 11, + "y": 34 + }, + { + "x": 13, + "y": 34 + }, + { + "x": 15, + "y": 34 + }, + { + "x": 17, + "y": 34 + }, + { + "x": 19, + "y": 34 + }, + { + "x": 21, + "y": 34 + }, + { + "x": 23, + "y": 34 + }, + { + "x": 25, + "y": 34 + }, + { + "x": 27, + "y": 34 + }, + { + "x": 29, + "y": 34 + }, + { + "x": 31, + "y": 34 + }, + { + "x": 33, + "y": 34 + }, + { + "x": 35, + "y": 34 + }, + { + "x": 37, + "y": 34 + }, + { + "x": 39, + "y": 34 + }, + { + "x": 41, + "y": 34 + }, + { + "x": 43, + "y": 34 + }, + { + "x": 45, + "y": 34 + }, + { + "x": 47, + "y": 34 + }, + { + "x": 49, + "y": 34 + }, + { + "x": 51, + "y": 34 + }, + { + "x": 53, + "y": 34 + }, + { + "x": 55, + "y": 34 + }, + { + "x": 57, + "y": 34 + }, + { + "x": 59, + "y": 34 + }, + { + "x": 61, + "y": 34 + }, + { + "x": 63, + "y": 34 + }, + { + "x": 65, + "y": 34 + }, + { + "x": 67, + "y": 34 + }, + { + "x": 69, + "y": 34 + }, + { + "x": 71, + "y": 34 + }, + { + "x": 73, + "y": 34 + }, + { + "x": 75, + "y": 34 + }, + { + "x": 77, + "y": 34 + }, + { + "x": 1, + "y": 35 + }, + { + "x": 3, + "y": 35 + }, + { + "x": 5, + "y": 35 + }, + { + "x": 7, + "y": 35 + }, + { + "x": 9, + "y": 35 + }, + { + "x": 11, + "y": 35 + }, + { + "x": 13, + "y": 35 + }, + { + "x": 15, + "y": 35 + }, + { + "x": 17, + "y": 35 + }, + { + "x": 19, + "y": 35 + }, + { + "x": 21, + "y": 35 + }, + { + "x": 23, + "y": 35 + }, + { + "x": 25, + "y": 35 + }, + { + "x": 27, + "y": 35 + }, + { + "x": 29, + "y": 35 + }, + { + "x": 31, + "y": 35 + }, + { + "x": 33, + "y": 35 + }, + { + "x": 35, + "y": 35 + }, + { + "x": 37, + "y": 35 + }, + { + "x": 39, + "y": 35 + }, + { + "x": 41, + "y": 35 + }, + { + "x": 43, + "y": 35 + }, + { + "x": 45, + "y": 35 + }, + { + "x": 47, + "y": 35 + }, + { + "x": 49, + "y": 35 + }, + { + "x": 51, + "y": 35 + }, + { + "x": 53, + "y": 35 + }, + { + "x": 55, + "y": 35 + }, + { + "x": 57, + "y": 35 + }, + { + "x": 59, + "y": 35 + }, + { + "x": 61, + "y": 35 + }, + { + "x": 63, + "y": 35 + }, + { + "x": 65, + "y": 35 + }, + { + "x": 67, + "y": 35 + }, + { + "x": 69, + "y": 35 + }, + { + "x": 71, + "y": 35 + }, + { + "x": 73, + "y": 35 + }, + { + "x": 75, + "y": 35 + }, + { + "x": 77, + "y": 35 + }, + { + "x": 1, + "y": 36 + }, + { + "x": 3, + "y": 36 + }, + { + "x": 5, + "y": 36 + }, + { + "x": 7, + "y": 36 + }, + { + "x": 9, + "y": 36 + }, + { + "x": 11, + "y": 36 + }, + { + "x": 13, + "y": 36 + }, + { + "x": 15, + "y": 36 + }, + { + "x": 17, + "y": 36 + }, + { + "x": 19, + "y": 36 + }, + { + "x": 21, + "y": 36 + }, + { + "x": 23, + "y": 36 + }, + { + "x": 25, + "y": 36 + }, + { + "x": 27, + "y": 36 + }, + { + "x": 29, + "y": 36 + }, + { + "x": 31, + "y": 36 + }, + { + "x": 33, + "y": 36 + }, + { + "x": 35, + "y": 36 + }, + { + "x": 37, + "y": 36 + }, + { + "x": 39, + "y": 36 + }, + { + "x": 41, + "y": 36 + }, + { + "x": 43, + "y": 36 + }, + { + "x": 45, + "y": 36 + }, + { + "x": 47, + "y": 36 + }, + { + "x": 49, + "y": 36 + }, + { + "x": 51, + "y": 36 + }, + { + "x": 53, + "y": 36 + }, + { + "x": 55, + "y": 36 + }, + { + "x": 57, + "y": 36 + }, + { + "x": 59, + "y": 36 + }, + { + "x": 61, + "y": 36 + }, + { + "x": 63, + "y": 36 + }, + { + "x": 65, + "y": 36 + }, + { + "x": 67, + "y": 36 + }, + { + "x": 69, + "y": 36 + }, + { + "x": 71, + "y": 36 + }, + { + "x": 73, + "y": 36 + }, + { + "x": 75, + "y": 36 + }, + { + "x": 77, + "y": 36 + }, + { + "x": 1, + "y": 37 + }, + { + "x": 3, + "y": 37 + }, + { + "x": 5, + "y": 37 + }, + { + "x": 7, + "y": 37 + }, + { + "x": 9, + "y": 37 + }, + { + "x": 11, + "y": 37 + }, + { + "x": 13, + "y": 37 + }, + { + "x": 15, + "y": 37 + }, + { + "x": 17, + "y": 37 + }, + { + "x": 19, + "y": 37 + }, + { + "x": 21, + "y": 37 + }, + { + "x": 23, + "y": 37 + }, + { + "x": 25, + "y": 37 + }, + { + "x": 27, + "y": 37 + }, + { + "x": 29, + "y": 37 + }, + { + "x": 31, + "y": 37 + }, + { + "x": 33, + "y": 37 + }, + { + "x": 35, + "y": 37 + }, + { + "x": 37, + "y": 37 + }, + { + "x": 39, + "y": 37 + }, + { + "x": 41, + "y": 37 + }, + { + "x": 43, + "y": 37 + }, + { + "x": 45, + "y": 37 + }, + { + "x": 47, + "y": 37 + }, + { + "x": 49, + "y": 37 + }, + { + "x": 51, + "y": 37 + }, + { + "x": 53, + "y": 37 + }, + { + "x": 55, + "y": 37 + }, + { + "x": 57, + "y": 37 + }, + { + "x": 59, + "y": 37 + }, + { + "x": 61, + "y": 37 + }, + { + "x": 63, + "y": 37 + }, + { + "x": 65, + "y": 37 + }, + { + "x": 67, + "y": 37 + }, + { + "x": 69, + "y": 37 + }, + { + "x": 71, + "y": 37 + }, + { + "x": 73, + "y": 37 + }, + { + "x": 75, + "y": 37 + }, + { + "x": 77, + "y": 37 + }, + { + "x": 1, + "y": 38 + }, + { + "x": 3, + "y": 38 + }, + { + "x": 5, + "y": 38 + }, + { + "x": 7, + "y": 38 + }, + { + "x": 9, + "y": 38 + }, + { + "x": 11, + "y": 38 + }, + { + "x": 13, + "y": 38 + }, + { + "x": 15, + "y": 38 + }, + { + "x": 17, + "y": 38 + }, + { + "x": 19, + "y": 38 + }, + { + "x": 21, + "y": 38 + }, + { + "x": 23, + "y": 38 + }, + { + "x": 25, + "y": 38 + }, + { + "x": 27, + "y": 38 + }, + { + "x": 29, + "y": 38 + }, + { + "x": 31, + "y": 38 + }, + { + "x": 33, + "y": 38 + }, + { + "x": 35, + "y": 38 + }, + { + "x": 37, + "y": 38 + }, + { + "x": 39, + "y": 38 + }, + { + "x": 41, + "y": 38 + }, + { + "x": 43, + "y": 38 + }, + { + "x": 45, + "y": 38 + }, + { + "x": 47, + "y": 38 + }, + { + "x": 49, + "y": 38 + }, + { + "x": 51, + "y": 38 + }, + { + "x": 53, + "y": 38 + }, + { + "x": 55, + "y": 38 + }, + { + "x": 57, + "y": 38 + }, + { + "x": 59, + "y": 38 + }, + { + "x": 61, + "y": 38 + }, + { + "x": 63, + "y": 38 + }, + { + "x": 65, + "y": 38 + }, + { + "x": 67, + "y": 38 + }, + { + "x": 69, + "y": 38 + }, + { + "x": 71, + "y": 38 + }, + { + "x": 73, + "y": 38 + }, + { + "x": 75, + "y": 38 + }, + { + "x": 77, + "y": 38 + }, + { + "x": 1, + "y": 39 + }, + { + "x": 3, + "y": 39 + }, + { + "x": 5, + "y": 39 + }, + { + "x": 7, + "y": 39 + }, + { + "x": 9, + "y": 39 + }, + { + "x": 11, + "y": 39 + }, + { + "x": 13, + "y": 39 + }, + { + "x": 15, + "y": 39 + }, + { + "x": 17, + "y": 39 + }, + { + "x": 19, + "y": 39 + }, + { + "x": 21, + "y": 39 + }, + { + "x": 23, + "y": 39 + }, + { + "x": 25, + "y": 39 + }, + { + "x": 27, + "y": 39 + }, + { + "x": 29, + "y": 39 + }, + { + "x": 31, + "y": 39 + }, + { + "x": 33, + "y": 39 + }, + { + "x": 35, + "y": 39 + }, + { + "x": 37, + "y": 39 + }, + { + "x": 39, + "y": 39 + }, + { + "x": 41, + "y": 39 + }, + { + "x": 43, + "y": 39 + }, + { + "x": 45, + "y": 39 + }, + { + "x": 47, + "y": 39 + }, + { + "x": 49, + "y": 39 + }, + { + "x": 51, + "y": 39 + }, + { + "x": 53, + "y": 39 + }, + { + "x": 55, + "y": 39 + }, + { + "x": 57, + "y": 39 + }, + { + "x": 59, + "y": 39 + }, + { + "x": 61, + "y": 39 + }, + { + "x": 63, + "y": 39 + }, + { + "x": 65, + "y": 39 + }, + { + "x": 67, + "y": 39 + }, + { + "x": 69, + "y": 39 + }, + { + "x": 71, + "y": 39 + }, + { + "x": 73, + "y": 39 + }, + { + "x": 75, + "y": 39 + }, + { + "x": 77, + "y": 39 + }, + { + "x": 1, + "y": 40 + }, + { + "x": 3, + "y": 40 + }, + { + "x": 5, + "y": 40 + }, + { + "x": 7, + "y": 40 + }, + { + "x": 9, + "y": 40 + }, + { + "x": 11, + "y": 40 + }, + { + "x": 13, + "y": 40 + }, + { + "x": 15, + "y": 40 + }, + { + "x": 17, + "y": 40 + }, + { + "x": 19, + "y": 40 + }, + { + "x": 21, + "y": 40 + }, + { + "x": 23, + "y": 40 + }, + { + "x": 25, + "y": 40 + }, + { + "x": 27, + "y": 40 + }, + { + "x": 29, + "y": 40 + }, + { + "x": 31, + "y": 40 + }, + { + "x": 33, + "y": 40 + }, + { + "x": 35, + "y": 40 + }, + { + "x": 37, + "y": 40 + }, + { + "x": 39, + "y": 40 + }, + { + "x": 41, + "y": 40 + }, + { + "x": 43, + "y": 40 + }, + { + "x": 45, + "y": 40 + }, + { + "x": 47, + "y": 40 + }, + { + "x": 49, + "y": 40 + }, + { + "x": 51, + "y": 40 + }, + { + "x": 53, + "y": 40 + }, + { + "x": 55, + "y": 40 + }, + { + "x": 57, + "y": 40 + }, + { + "x": 59, + "y": 40 + }, + { + "x": 61, + "y": 40 + }, + { + "x": 63, + "y": 40 + }, + { + "x": 65, + "y": 40 + }, + { + "x": 67, + "y": 40 + }, + { + "x": 69, + "y": 40 + }, + { + "x": 71, + "y": 40 + }, + { + "x": 73, + "y": 40 + }, + { + "x": 75, + "y": 40 + }, + { + "x": 77, + "y": 40 + }, + { + "x": 1, + "y": 41 + }, + { + "x": 3, + "y": 41 + }, + { + "x": 5, + "y": 41 + }, + { + "x": 7, + "y": 41 + }, + { + "x": 9, + "y": 41 + }, + { + "x": 11, + "y": 41 + }, + { + "x": 13, + "y": 41 + }, + { + "x": 15, + "y": 41 + }, + { + "x": 17, + "y": 41 + }, + { + "x": 19, + "y": 41 + }, + { + "x": 21, + "y": 41 + }, + { + "x": 23, + "y": 41 + }, + { + "x": 25, + "y": 41 + }, + { + "x": 27, + "y": 41 + }, + { + "x": 29, + "y": 41 + }, + { + "x": 31, + "y": 41 + }, + { + "x": 33, + "y": 41 + }, + { + "x": 35, + "y": 41 + }, + { + "x": 37, + "y": 41 + }, + { + "x": 39, + "y": 41 + }, + { + "x": 41, + "y": 41 + }, + { + "x": 43, + "y": 41 + }, + { + "x": 45, + "y": 41 + }, + { + "x": 47, + "y": 41 + }, + { + "x": 49, + "y": 41 + }, + { + "x": 51, + "y": 41 + }, + { + "x": 53, + "y": 41 + }, + { + "x": 55, + "y": 41 + }, + { + "x": 57, + "y": 41 + }, + { + "x": 59, + "y": 41 + }, + { + "x": 61, + "y": 41 + }, + { + "x": 63, + "y": 41 + }, + { + "x": 65, + "y": 41 + }, + { + "x": 67, + "y": 41 + }, + { + "x": 69, + "y": 41 + }, + { + "x": 71, + "y": 41 + }, + { + "x": 73, + "y": 41 + }, + { + "x": 75, + "y": 41 + }, + { + "x": 77, + "y": 41 + }, + { + "x": 1, + "y": 42 + }, + { + "x": 2, + "y": 42 + }, + { + "x": 3, + "y": 42 + }, + { + "x": 4, + "y": 42 + }, + { + "x": 5, + "y": 42 + }, + { + "x": 6, + "y": 42 + }, + { + "x": 7, + "y": 42 + }, + { + "x": 8, + "y": 42 + }, + { + "x": 9, + "y": 42 + }, + { + "x": 10, + "y": 42 + }, + { + "x": 11, + "y": 42 + }, + { + "x": 12, + "y": 42 + }, + { + "x": 13, + "y": 42 + }, + { + "x": 14, + "y": 42 + }, + { + "x": 15, + "y": 42 + }, + { + "x": 16, + "y": 42 + }, + { + "x": 17, + "y": 42 + }, + { + "x": 18, + "y": 42 + }, + { + "x": 19, + "y": 42 + }, + { + "x": 20, + "y": 42 + }, + { + "x": 21, + "y": 42 + }, + { + "x": 22, + "y": 42 + }, + { + "x": 23, + "y": 42 + }, + { + "x": 24, + "y": 42 + }, + { + "x": 25, + "y": 42 + }, + { + "x": 26, + "y": 42 + }, + { + "x": 27, + "y": 42 + }, + { + "x": 28, + "y": 42 + }, + { + "x": 29, + "y": 42 + }, + { + "x": 30, + "y": 42 + }, + { + "x": 31, + "y": 42 + }, + { + "x": 32, + "y": 42 + }, + { + "x": 33, + "y": 42 + }, + { + "x": 34, + "y": 42 + }, + { + "x": 35, + "y": 42 + }, + { + "x": 36, + "y": 42 + }, + { + "x": 37, + "y": 42 + }, + { + "x": 38, + "y": 42 + }, + { + "x": 39, + "y": 42 + }, + { + "x": 40, + "y": 42 + }, + { + "x": 41, + "y": 42 + }, + { + "x": 42, + "y": 42 + }, + { + "x": 43, + "y": 42 + }, + { + "x": 44, + "y": 42 + }, + { + "x": 45, + "y": 42 + }, + { + "x": 46, + "y": 42 + }, + { + "x": 47, + "y": 42 + }, + { + "x": 48, + "y": 42 + }, + { + "x": 49, + "y": 42 + }, + { + "x": 50, + "y": 42 + }, + { + "x": 51, + "y": 42 + }, + { + "x": 52, + "y": 42 + }, + { + "x": 53, + "y": 42 + }, + { + "x": 54, + "y": 42 + }, + { + "x": 55, + "y": 42 + }, + { + "x": 56, + "y": 42 + }, + { + "x": 57, + "y": 42 + }, + { + "x": 58, + "y": 42 + }, + { + "x": 59, + "y": 42 + }, + { + "x": 60, + "y": 42 + }, + { + "x": 61, + "y": 42 + }, + { + "x": 62, + "y": 42 + }, + { + "x": 63, + "y": 42 + }, + { + "x": 64, + "y": 42 + }, + { + "x": 65, + "y": 42 + }, + { + "x": 66, + "y": 42 + }, + { + "x": 67, + "y": 42 + }, + { + "x": 68, + "y": 42 + }, + { + "x": 69, + "y": 42 + }, + { + "x": 70, + "y": 42 + }, + { + "x": 71, + "y": 42 + }, + { + "x": 72, + "y": 42 + }, + { + "x": 73, + "y": 42 + }, + { + "x": 74, + "y": 42 + }, + { + "x": 75, + "y": 42 + }, + { + "x": 76, + "y": 42 + }, + { + "x": 77, + "y": 42 + }, + { + "x": 1, + "y": 43 + }, + { + "x": 3, + "y": 43 + }, + { + "x": 5, + "y": 43 + }, + { + "x": 9, + "y": 43 + }, + { + "x": 11, + "y": 43 + }, + { + "x": 13, + "y": 43 + }, + { + "x": 17, + "y": 43 + }, + { + "x": 19, + "y": 43 + }, + { + "x": 21, + "y": 43 + }, + { + "x": 25, + "y": 43 + }, + { + "x": 27, + "y": 43 + }, + { + "x": 29, + "y": 43 + }, + { + "x": 33, + "y": 43 + }, + { + "x": 35, + "y": 43 + }, + { + "x": 37, + "y": 43 + }, + { + "x": 41, + "y": 43 + }, + { + "x": 43, + "y": 43 + }, + { + "x": 45, + "y": 43 + }, + { + "x": 49, + "y": 43 + }, + { + "x": 51, + "y": 43 + }, + { + "x": 53, + "y": 43 + }, + { + "x": 57, + "y": 43 + }, + { + "x": 59, + "y": 43 + }, + { + "x": 61, + "y": 43 + }, + { + "x": 65, + "y": 43 + }, + { + "x": 67, + "y": 43 + }, + { + "x": 69, + "y": 43 + }, + { + "x": 73, + "y": 43 + }, + { + "x": 75, + "y": 43 + }, + { + "x": 77, + "y": 43 + }, + { + "x": 1, + "y": 44 + }, + { + "x": 2, + "y": 44 + }, + { + "x": 3, + "y": 44 + }, + { + "x": 4, + "y": 44 + }, + { + "x": 5, + "y": 44 + }, + { + "x": 6, + "y": 44 + }, + { + "x": 7, + "y": 44 + }, + { + "x": 8, + "y": 44 + }, + { + "x": 9, + "y": 44 + }, + { + "x": 10, + "y": 44 + }, + { + "x": 11, + "y": 44 + }, + { + "x": 12, + "y": 44 + }, + { + "x": 13, + "y": 44 + }, + { + "x": 14, + "y": 44 + }, + { + "x": 15, + "y": 44 + }, + { + "x": 16, + "y": 44 + }, + { + "x": 17, + "y": 44 + }, + { + "x": 18, + "y": 44 + }, + { + "x": 19, + "y": 44 + }, + { + "x": 20, + "y": 44 + }, + { + "x": 21, + "y": 44 + }, + { + "x": 22, + "y": 44 + }, + { + "x": 23, + "y": 44 + }, + { + "x": 24, + "y": 44 + }, + { + "x": 25, + "y": 44 + }, + { + "x": 26, + "y": 44 + }, + { + "x": 27, + "y": 44 + }, + { + "x": 28, + "y": 44 + }, + { + "x": 29, + "y": 44 + }, + { + "x": 30, + "y": 44 + }, + { + "x": 31, + "y": 44 + }, + { + "x": 32, + "y": 44 + }, + { + "x": 33, + "y": 44 + }, + { + "x": 34, + "y": 44 + }, + { + "x": 35, + "y": 44 + }, + { + "x": 36, + "y": 44 + }, + { + "x": 37, + "y": 44 + }, + { + "x": 38, + "y": 44 + }, + { + "x": 39, + "y": 44 + }, + { + "x": 40, + "y": 44 + }, + { + "x": 41, + "y": 44 + }, + { + "x": 42, + "y": 44 + }, + { + "x": 43, + "y": 44 + }, + { + "x": 44, + "y": 44 + }, + { + "x": 45, + "y": 44 + }, + { + "x": 46, + "y": 44 + }, + { + "x": 47, + "y": 44 + }, + { + "x": 48, + "y": 44 + }, + { + "x": 49, + "y": 44 + }, + { + "x": 50, + "y": 44 + }, + { + "x": 51, + "y": 44 + }, + { + "x": 52, + "y": 44 + }, + { + "x": 53, + "y": 44 + }, + { + "x": 54, + "y": 44 + }, + { + "x": 55, + "y": 44 + }, + { + "x": 56, + "y": 44 + }, + { + "x": 57, + "y": 44 + }, + { + "x": 58, + "y": 44 + }, + { + "x": 59, + "y": 44 + }, + { + "x": 60, + "y": 44 + }, + { + "x": 61, + "y": 44 + }, + { + "x": 62, + "y": 44 + }, + { + "x": 63, + "y": 44 + }, + { + "x": 64, + "y": 44 + }, + { + "x": 65, + "y": 44 + }, + { + "x": 66, + "y": 44 + }, + { + "x": 67, + "y": 44 + }, + { + "x": 68, + "y": 44 + }, + { + "x": 69, + "y": 44 + }, + { + "x": 70, + "y": 44 + }, + { + "x": 71, + "y": 44 + }, + { + "x": 72, + "y": 44 + }, + { + "x": 73, + "y": 44 + }, + { + "x": 74, + "y": 44 + }, + { + "x": 75, + "y": 44 + }, + { + "x": 76, + "y": 44 + }, + { + "x": 77, + "y": 44 + }, + { + "x": 1, + "y": 45 + }, + { + "x": 3, + "y": 45 + }, + { + "x": 5, + "y": 45 + }, + { + "x": 9, + "y": 45 + }, + { + "x": 11, + "y": 45 + }, + { + "x": 13, + "y": 45 + }, + { + "x": 17, + "y": 45 + }, + { + "x": 19, + "y": 45 + }, + { + "x": 21, + "y": 45 + }, + { + "x": 25, + "y": 45 + }, + { + "x": 27, + "y": 45 + }, + { + "x": 29, + "y": 45 + }, + { + "x": 33, + "y": 45 + }, + { + "x": 35, + "y": 45 + }, + { + "x": 37, + "y": 45 + }, + { + "x": 41, + "y": 45 + }, + { + "x": 43, + "y": 45 + }, + { + "x": 45, + "y": 45 + }, + { + "x": 49, + "y": 45 + }, + { + "x": 51, + "y": 45 + }, + { + "x": 53, + "y": 45 + }, + { + "x": 57, + "y": 45 + }, + { + "x": 59, + "y": 45 + }, + { + "x": 61, + "y": 45 + }, + { + "x": 65, + "y": 45 + }, + { + "x": 67, + "y": 45 + }, + { + "x": 69, + "y": 45 + }, + { + "x": 73, + "y": 45 + }, + { + "x": 75, + "y": 45 + }, + { + "x": 77, + "y": 45 + }, + { + "x": 1, + "y": 46 + }, + { + "x": 3, + "y": 46 + }, + { + "x": 5, + "y": 46 + }, + { + "x": 9, + "y": 46 + }, + { + "x": 11, + "y": 46 + }, + { + "x": 13, + "y": 46 + }, + { + "x": 17, + "y": 46 + }, + { + "x": 19, + "y": 46 + }, + { + "x": 21, + "y": 46 + }, + { + "x": 25, + "y": 46 + }, + { + "x": 27, + "y": 46 + }, + { + "x": 29, + "y": 46 + }, + { + "x": 33, + "y": 46 + }, + { + "x": 35, + "y": 46 + }, + { + "x": 37, + "y": 46 + }, + { + "x": 41, + "y": 46 + }, + { + "x": 43, + "y": 46 + }, + { + "x": 45, + "y": 46 + }, + { + "x": 49, + "y": 46 + }, + { + "x": 51, + "y": 46 + }, + { + "x": 53, + "y": 46 + }, + { + "x": 57, + "y": 46 + }, + { + "x": 59, + "y": 46 + }, + { + "x": 61, + "y": 46 + }, + { + "x": 65, + "y": 46 + }, + { + "x": 67, + "y": 46 + }, + { + "x": 69, + "y": 46 + }, + { + "x": 73, + "y": 46 + }, + { + "x": 75, + "y": 46 + }, + { + "x": 77, + "y": 46 + }, + { + "x": 1, + "y": 47 + }, + { + "x": 2, + "y": 47 + }, + { + "x": 3, + "y": 47 + }, + { + "x": 4, + "y": 47 + }, + { + "x": 5, + "y": 47 + }, + { + "x": 6, + "y": 47 + }, + { + "x": 7, + "y": 47 + }, + { + "x": 8, + "y": 47 + }, + { + "x": 9, + "y": 47 + }, + { + "x": 11, + "y": 47 + }, + { + "x": 13, + "y": 47 + }, + { + "x": 17, + "y": 47 + }, + { + "x": 18, + "y": 47 + }, + { + "x": 19, + "y": 47 + }, + { + "x": 20, + "y": 47 + }, + { + "x": 21, + "y": 47 + }, + { + "x": 22, + "y": 47 + }, + { + "x": 23, + "y": 47 + }, + { + "x": 24, + "y": 47 + }, + { + "x": 25, + "y": 47 + }, + { + "x": 27, + "y": 47 + }, + { + "x": 29, + "y": 47 + }, + { + "x": 33, + "y": 47 + }, + { + "x": 34, + "y": 47 + }, + { + "x": 35, + "y": 47 + }, + { + "x": 36, + "y": 47 + }, + { + "x": 37, + "y": 47 + }, + { + "x": 38, + "y": 47 + }, + { + "x": 39, + "y": 47 + }, + { + "x": 40, + "y": 47 + }, + { + "x": 41, + "y": 47 + }, + { + "x": 43, + "y": 47 + }, + { + "x": 45, + "y": 47 + }, + { + "x": 49, + "y": 47 + }, + { + "x": 50, + "y": 47 + }, + { + "x": 51, + "y": 47 + }, + { + "x": 52, + "y": 47 + }, + { + "x": 53, + "y": 47 + }, + { + "x": 54, + "y": 47 + }, + { + "x": 55, + "y": 47 + }, + { + "x": 56, + "y": 47 + }, + { + "x": 57, + "y": 47 + }, + { + "x": 59, + "y": 47 + }, + { + "x": 61, + "y": 47 + }, + { + "x": 65, + "y": 47 + }, + { + "x": 66, + "y": 47 + }, + { + "x": 67, + "y": 47 + }, + { + "x": 68, + "y": 47 + }, + { + "x": 69, + "y": 47 + }, + { + "x": 70, + "y": 47 + }, + { + "x": 71, + "y": 47 + }, + { + "x": 72, + "y": 47 + }, + { + "x": 73, + "y": 47 + }, + { + "x": 75, + "y": 47 + }, + { + "x": 77, + "y": 47 + } + ], + "storage_areas": [ + { + "x": 18, + "y": 1 + }, + { + "x": 20, + "y": 1 + }, + { + "x": 22, + "y": 1 + }, + { + "x": 24, + "y": 1 + }, + { + "x": 26, + "y": 1 + }, + { + "x": 28, + "y": 1 + }, + { + "x": 30, + "y": 1 + }, + { + "x": 32, + "y": 1 + }, + { + "x": 34, + "y": 1 + }, + { + "x": 36, + "y": 1 + }, + { + "x": 38, + "y": 1 + }, + { + "x": 40, + "y": 1 + }, + { + "x": 42, + "y": 1 + }, + { + "x": 44, + "y": 1 + }, + { + "x": 46, + "y": 1 + }, + { + "x": 48, + "y": 1 + }, + { + "x": 50, + "y": 1 + }, + { + "x": 52, + "y": 1 + }, + { + "x": 54, + "y": 1 + }, + { + "x": 56, + "y": 1 + }, + { + "x": 58, + "y": 1 + }, + { + "x": 60, + "y": 1 + }, + { + "x": 18, + "y": 2 + }, + { + "x": 20, + "y": 2 + }, + { + "x": 22, + "y": 2 + }, + { + "x": 24, + "y": 2 + }, + { + "x": 26, + "y": 2 + }, + { + "x": 28, + "y": 2 + }, + { + "x": 30, + "y": 2 + }, + { + "x": 32, + "y": 2 + }, + { + "x": 34, + "y": 2 + }, + { + "x": 36, + "y": 2 + }, + { + "x": 38, + "y": 2 + }, + { + "x": 40, + "y": 2 + }, + { + "x": 42, + "y": 2 + }, + { + "x": 44, + "y": 2 + }, + { + "x": 46, + "y": 2 + }, + { + "x": 48, + "y": 2 + }, + { + "x": 50, + "y": 2 + }, + { + "x": 52, + "y": 2 + }, + { + "x": 54, + "y": 2 + }, + { + "x": 56, + "y": 2 + }, + { + "x": 58, + "y": 2 + }, + { + "x": 60, + "y": 2 + }, + { + "x": 18, + "y": 3 + }, + { + "x": 20, + "y": 3 + }, + { + "x": 22, + "y": 3 + }, + { + "x": 24, + "y": 3 + }, + { + "x": 26, + "y": 3 + }, + { + "x": 28, + "y": 3 + }, + { + "x": 30, + "y": 3 + }, + { + "x": 32, + "y": 3 + }, + { + "x": 34, + "y": 3 + }, + { + "x": 36, + "y": 3 + }, + { + "x": 38, + "y": 3 + }, + { + "x": 40, + "y": 3 + }, + { + "x": 42, + "y": 3 + }, + { + "x": 44, + "y": 3 + }, + { + "x": 46, + "y": 3 + }, + { + "x": 48, + "y": 3 + }, + { + "x": 50, + "y": 3 + }, + { + "x": 52, + "y": 3 + }, + { + "x": 54, + "y": 3 + }, + { + "x": 56, + "y": 3 + }, + { + "x": 58, + "y": 3 + }, + { + "x": 60, + "y": 3 + }, + { + "x": 18, + "y": 4 + }, + { + "x": 20, + "y": 4 + }, + { + "x": 22, + "y": 4 + }, + { + "x": 24, + "y": 4 + }, + { + "x": 26, + "y": 4 + }, + { + "x": 28, + "y": 4 + }, + { + "x": 30, + "y": 4 + }, + { + "x": 32, + "y": 4 + }, + { + "x": 34, + "y": 4 + }, + { + "x": 36, + "y": 4 + }, + { + "x": 38, + "y": 4 + }, + { + "x": 40, + "y": 4 + }, + { + "x": 42, + "y": 4 + }, + { + "x": 44, + "y": 4 + }, + { + "x": 46, + "y": 4 + }, + { + "x": 48, + "y": 4 + }, + { + "x": 50, + "y": 4 + }, + { + "x": 52, + "y": 4 + }, + { + "x": 54, + "y": 4 + }, + { + "x": 56, + "y": 4 + }, + { + "x": 58, + "y": 4 + }, + { + "x": 60, + "y": 4 + }, + { + "x": 18, + "y": 5 + }, + { + "x": 20, + "y": 5 + }, + { + "x": 22, + "y": 5 + }, + { + "x": 24, + "y": 5 + }, + { + "x": 26, + "y": 5 + }, + { + "x": 28, + "y": 5 + }, + { + "x": 30, + "y": 5 + }, + { + "x": 32, + "y": 5 + }, + { + "x": 34, + "y": 5 + }, + { + "x": 36, + "y": 5 + }, + { + "x": 38, + "y": 5 + }, + { + "x": 40, + "y": 5 + }, + { + "x": 42, + "y": 5 + }, + { + "x": 44, + "y": 5 + }, + { + "x": 46, + "y": 5 + }, + { + "x": 48, + "y": 5 + }, + { + "x": 50, + "y": 5 + }, + { + "x": 52, + "y": 5 + }, + { + "x": 54, + "y": 5 + }, + { + "x": 56, + "y": 5 + }, + { + "x": 58, + "y": 5 + }, + { + "x": 60, + "y": 5 + }, + { + "x": 18, + "y": 7 + }, + { + "x": 20, + "y": 7 + }, + { + "x": 22, + "y": 7 + }, + { + "x": 24, + "y": 7 + }, + { + "x": 26, + "y": 7 + }, + { + "x": 28, + "y": 7 + }, + { + "x": 30, + "y": 7 + }, + { + "x": 32, + "y": 7 + }, + { + "x": 34, + "y": 7 + }, + { + "x": 36, + "y": 7 + }, + { + "x": 38, + "y": 7 + }, + { + "x": 40, + "y": 7 + }, + { + "x": 42, + "y": 7 + }, + { + "x": 44, + "y": 7 + }, + { + "x": 46, + "y": 7 + }, + { + "x": 48, + "y": 7 + }, + { + "x": 50, + "y": 7 + }, + { + "x": 52, + "y": 7 + }, + { + "x": 54, + "y": 7 + }, + { + "x": 56, + "y": 7 + }, + { + "x": 58, + "y": 7 + }, + { + "x": 60, + "y": 7 + }, + { + "x": 18, + "y": 8 + }, + { + "x": 20, + "y": 8 + }, + { + "x": 22, + "y": 8 + }, + { + "x": 24, + "y": 8 + }, + { + "x": 26, + "y": 8 + }, + { + "x": 28, + "y": 8 + }, + { + "x": 30, + "y": 8 + }, + { + "x": 32, + "y": 8 + }, + { + "x": 34, + "y": 8 + }, + { + "x": 36, + "y": 8 + }, + { + "x": 38, + "y": 8 + }, + { + "x": 40, + "y": 8 + }, + { + "x": 42, + "y": 8 + }, + { + "x": 44, + "y": 8 + }, + { + "x": 46, + "y": 8 + }, + { + "x": 48, + "y": 8 + }, + { + "x": 50, + "y": 8 + }, + { + "x": 52, + "y": 8 + }, + { + "x": 54, + "y": 8 + }, + { + "x": 56, + "y": 8 + }, + { + "x": 58, + "y": 8 + }, + { + "x": 60, + "y": 8 + }, + { + "x": 18, + "y": 9 + }, + { + "x": 20, + "y": 9 + }, + { + "x": 22, + "y": 9 + }, + { + "x": 24, + "y": 9 + }, + { + "x": 26, + "y": 9 + }, + { + "x": 28, + "y": 9 + }, + { + "x": 30, + "y": 9 + }, + { + "x": 32, + "y": 9 + }, + { + "x": 34, + "y": 9 + }, + { + "x": 36, + "y": 9 + }, + { + "x": 38, + "y": 9 + }, + { + "x": 40, + "y": 9 + }, + { + "x": 42, + "y": 9 + }, + { + "x": 44, + "y": 9 + }, + { + "x": 46, + "y": 9 + }, + { + "x": 48, + "y": 9 + }, + { + "x": 50, + "y": 9 + }, + { + "x": 52, + "y": 9 + }, + { + "x": 54, + "y": 9 + }, + { + "x": 56, + "y": 9 + }, + { + "x": 58, + "y": 9 + }, + { + "x": 60, + "y": 9 + }, + { + "x": 18, + "y": 10 + }, + { + "x": 20, + "y": 10 + }, + { + "x": 22, + "y": 10 + }, + { + "x": 24, + "y": 10 + }, + { + "x": 26, + "y": 10 + }, + { + "x": 28, + "y": 10 + }, + { + "x": 30, + "y": 10 + }, + { + "x": 32, + "y": 10 + }, + { + "x": 34, + "y": 10 + }, + { + "x": 36, + "y": 10 + }, + { + "x": 38, + "y": 10 + }, + { + "x": 40, + "y": 10 + }, + { + "x": 42, + "y": 10 + }, + { + "x": 44, + "y": 10 + }, + { + "x": 46, + "y": 10 + }, + { + "x": 48, + "y": 10 + }, + { + "x": 50, + "y": 10 + }, + { + "x": 52, + "y": 10 + }, + { + "x": 54, + "y": 10 + }, + { + "x": 56, + "y": 10 + }, + { + "x": 58, + "y": 10 + }, + { + "x": 60, + "y": 10 + }, + { + "x": 18, + "y": 11 + }, + { + "x": 20, + "y": 11 + }, + { + "x": 22, + "y": 11 + }, + { + "x": 24, + "y": 11 + }, + { + "x": 26, + "y": 11 + }, + { + "x": 28, + "y": 11 + }, + { + "x": 30, + "y": 11 + }, + { + "x": 32, + "y": 11 + }, + { + "x": 34, + "y": 11 + }, + { + "x": 36, + "y": 11 + }, + { + "x": 38, + "y": 11 + }, + { + "x": 40, + "y": 11 + }, + { + "x": 42, + "y": 11 + }, + { + "x": 44, + "y": 11 + }, + { + "x": 46, + "y": 11 + }, + { + "x": 48, + "y": 11 + }, + { + "x": 50, + "y": 11 + }, + { + "x": 52, + "y": 11 + }, + { + "x": 54, + "y": 11 + }, + { + "x": 56, + "y": 11 + }, + { + "x": 58, + "y": 11 + }, + { + "x": 60, + "y": 11 + }, + { + "x": 0, + "y": 13 + }, + { + "x": 2, + "y": 13 + }, + { + "x": 4, + "y": 13 + }, + { + "x": 6, + "y": 13 + }, + { + "x": 8, + "y": 13 + }, + { + "x": 10, + "y": 13 + }, + { + "x": 12, + "y": 13 + }, + { + "x": 14, + "y": 13 + }, + { + "x": 16, + "y": 13 + }, + { + "x": 18, + "y": 13 + }, + { + "x": 20, + "y": 13 + }, + { + "x": 22, + "y": 13 + }, + { + "x": 24, + "y": 13 + }, + { + "x": 26, + "y": 13 + }, + { + "x": 28, + "y": 13 + }, + { + "x": 30, + "y": 13 + }, + { + "x": 32, + "y": 13 + }, + { + "x": 34, + "y": 13 + }, + { + "x": 36, + "y": 13 + }, + { + "x": 38, + "y": 13 + }, + { + "x": 40, + "y": 13 + }, + { + "x": 42, + "y": 13 + }, + { + "x": 44, + "y": 13 + }, + { + "x": 46, + "y": 13 + }, + { + "x": 48, + "y": 13 + }, + { + "x": 50, + "y": 13 + }, + { + "x": 52, + "y": 13 + }, + { + "x": 54, + "y": 13 + }, + { + "x": 56, + "y": 13 + }, + { + "x": 58, + "y": 13 + }, + { + "x": 60, + "y": 13 + }, + { + "x": 62, + "y": 13 + }, + { + "x": 64, + "y": 13 + }, + { + "x": 66, + "y": 13 + }, + { + "x": 68, + "y": 13 + }, + { + "x": 70, + "y": 13 + }, + { + "x": 72, + "y": 13 + }, + { + "x": 74, + "y": 13 + }, + { + "x": 0, + "y": 14 + }, + { + "x": 2, + "y": 14 + }, + { + "x": 4, + "y": 14 + }, + { + "x": 6, + "y": 14 + }, + { + "x": 8, + "y": 14 + }, + { + "x": 10, + "y": 14 + }, + { + "x": 12, + "y": 14 + }, + { + "x": 14, + "y": 14 + }, + { + "x": 16, + "y": 14 + }, + { + "x": 18, + "y": 14 + }, + { + "x": 20, + "y": 14 + }, + { + "x": 22, + "y": 14 + }, + { + "x": 24, + "y": 14 + }, + { + "x": 26, + "y": 14 + }, + { + "x": 28, + "y": 14 + }, + { + "x": 30, + "y": 14 + }, + { + "x": 32, + "y": 14 + }, + { + "x": 34, + "y": 14 + }, + { + "x": 36, + "y": 14 + }, + { + "x": 38, + "y": 14 + }, + { + "x": 40, + "y": 14 + }, + { + "x": 42, + "y": 14 + }, + { + "x": 44, + "y": 14 + }, + { + "x": 46, + "y": 14 + }, + { + "x": 48, + "y": 14 + }, + { + "x": 50, + "y": 14 + }, + { + "x": 52, + "y": 14 + }, + { + "x": 54, + "y": 14 + }, + { + "x": 56, + "y": 14 + }, + { + "x": 58, + "y": 14 + }, + { + "x": 60, + "y": 14 + }, + { + "x": 62, + "y": 14 + }, + { + "x": 64, + "y": 14 + }, + { + "x": 66, + "y": 14 + }, + { + "x": 68, + "y": 14 + }, + { + "x": 70, + "y": 14 + }, + { + "x": 72, + "y": 14 + }, + { + "x": 74, + "y": 14 + }, + { + "x": 0, + "y": 15 + }, + { + "x": 2, + "y": 15 + }, + { + "x": 4, + "y": 15 + }, + { + "x": 6, + "y": 15 + }, + { + "x": 8, + "y": 15 + }, + { + "x": 10, + "y": 15 + }, + { + "x": 12, + "y": 15 + }, + { + "x": 14, + "y": 15 + }, + { + "x": 16, + "y": 15 + }, + { + "x": 18, + "y": 15 + }, + { + "x": 20, + "y": 15 + }, + { + "x": 22, + "y": 15 + }, + { + "x": 24, + "y": 15 + }, + { + "x": 26, + "y": 15 + }, + { + "x": 28, + "y": 15 + }, + { + "x": 30, + "y": 15 + }, + { + "x": 32, + "y": 15 + }, + { + "x": 34, + "y": 15 + }, + { + "x": 36, + "y": 15 + }, + { + "x": 38, + "y": 15 + }, + { + "x": 40, + "y": 15 + }, + { + "x": 42, + "y": 15 + }, + { + "x": 44, + "y": 15 + }, + { + "x": 46, + "y": 15 + }, + { + "x": 48, + "y": 15 + }, + { + "x": 50, + "y": 15 + }, + { + "x": 52, + "y": 15 + }, + { + "x": 54, + "y": 15 + }, + { + "x": 56, + "y": 15 + }, + { + "x": 58, + "y": 15 + }, + { + "x": 60, + "y": 15 + }, + { + "x": 62, + "y": 15 + }, + { + "x": 64, + "y": 15 + }, + { + "x": 66, + "y": 15 + }, + { + "x": 68, + "y": 15 + }, + { + "x": 70, + "y": 15 + }, + { + "x": 72, + "y": 15 + }, + { + "x": 74, + "y": 15 + }, + { + "x": 0, + "y": 16 + }, + { + "x": 2, + "y": 16 + }, + { + "x": 4, + "y": 16 + }, + { + "x": 6, + "y": 16 + }, + { + "x": 8, + "y": 16 + }, + { + "x": 10, + "y": 16 + }, + { + "x": 12, + "y": 16 + }, + { + "x": 14, + "y": 16 + }, + { + "x": 16, + "y": 16 + }, + { + "x": 18, + "y": 16 + }, + { + "x": 20, + "y": 16 + }, + { + "x": 22, + "y": 16 + }, + { + "x": 24, + "y": 16 + }, + { + "x": 26, + "y": 16 + }, + { + "x": 28, + "y": 16 + }, + { + "x": 30, + "y": 16 + }, + { + "x": 32, + "y": 16 + }, + { + "x": 34, + "y": 16 + }, + { + "x": 36, + "y": 16 + }, + { + "x": 38, + "y": 16 + }, + { + "x": 40, + "y": 16 + }, + { + "x": 42, + "y": 16 + }, + { + "x": 44, + "y": 16 + }, + { + "x": 46, + "y": 16 + }, + { + "x": 48, + "y": 16 + }, + { + "x": 50, + "y": 16 + }, + { + "x": 52, + "y": 16 + }, + { + "x": 54, + "y": 16 + }, + { + "x": 56, + "y": 16 + }, + { + "x": 58, + "y": 16 + }, + { + "x": 60, + "y": 16 + }, + { + "x": 62, + "y": 16 + }, + { + "x": 64, + "y": 16 + }, + { + "x": 66, + "y": 16 + }, + { + "x": 68, + "y": 16 + }, + { + "x": 70, + "y": 16 + }, + { + "x": 72, + "y": 16 + }, + { + "x": 74, + "y": 16 + }, + { + "x": 0, + "y": 17 + }, + { + "x": 2, + "y": 17 + }, + { + "x": 4, + "y": 17 + }, + { + "x": 6, + "y": 17 + }, + { + "x": 8, + "y": 17 + }, + { + "x": 10, + "y": 17 + }, + { + "x": 12, + "y": 17 + }, + { + "x": 14, + "y": 17 + }, + { + "x": 16, + "y": 17 + }, + { + "x": 18, + "y": 17 + }, + { + "x": 20, + "y": 17 + }, + { + "x": 22, + "y": 17 + }, + { + "x": 24, + "y": 17 + }, + { + "x": 26, + "y": 17 + }, + { + "x": 28, + "y": 17 + }, + { + "x": 30, + "y": 17 + }, + { + "x": 32, + "y": 17 + }, + { + "x": 34, + "y": 17 + }, + { + "x": 36, + "y": 17 + }, + { + "x": 38, + "y": 17 + }, + { + "x": 40, + "y": 17 + }, + { + "x": 42, + "y": 17 + }, + { + "x": 44, + "y": 17 + }, + { + "x": 46, + "y": 17 + }, + { + "x": 48, + "y": 17 + }, + { + "x": 50, + "y": 17 + }, + { + "x": 52, + "y": 17 + }, + { + "x": 54, + "y": 17 + }, + { + "x": 56, + "y": 17 + }, + { + "x": 58, + "y": 17 + }, + { + "x": 60, + "y": 17 + }, + { + "x": 62, + "y": 17 + }, + { + "x": 64, + "y": 17 + }, + { + "x": 66, + "y": 17 + }, + { + "x": 68, + "y": 17 + }, + { + "x": 70, + "y": 17 + }, + { + "x": 72, + "y": 17 + }, + { + "x": 74, + "y": 17 + }, + { + "x": 0, + "y": 18 + }, + { + "x": 2, + "y": 18 + }, + { + "x": 4, + "y": 18 + }, + { + "x": 6, + "y": 18 + }, + { + "x": 8, + "y": 18 + }, + { + "x": 10, + "y": 18 + }, + { + "x": 12, + "y": 18 + }, + { + "x": 14, + "y": 18 + }, + { + "x": 16, + "y": 18 + }, + { + "x": 18, + "y": 18 + }, + { + "x": 20, + "y": 18 + }, + { + "x": 22, + "y": 18 + }, + { + "x": 24, + "y": 18 + }, + { + "x": 26, + "y": 18 + }, + { + "x": 28, + "y": 18 + }, + { + "x": 30, + "y": 18 + }, + { + "x": 32, + "y": 18 + }, + { + "x": 34, + "y": 18 + }, + { + "x": 36, + "y": 18 + }, + { + "x": 38, + "y": 18 + }, + { + "x": 40, + "y": 18 + }, + { + "x": 42, + "y": 18 + }, + { + "x": 44, + "y": 18 + }, + { + "x": 46, + "y": 18 + }, + { + "x": 48, + "y": 18 + }, + { + "x": 50, + "y": 18 + }, + { + "x": 52, + "y": 18 + }, + { + "x": 54, + "y": 18 + }, + { + "x": 56, + "y": 18 + }, + { + "x": 58, + "y": 18 + }, + { + "x": 60, + "y": 18 + }, + { + "x": 62, + "y": 18 + }, + { + "x": 64, + "y": 18 + }, + { + "x": 66, + "y": 18 + }, + { + "x": 68, + "y": 18 + }, + { + "x": 70, + "y": 18 + }, + { + "x": 72, + "y": 18 + }, + { + "x": 74, + "y": 18 + }, + { + "x": 0, + "y": 19 + }, + { + "x": 2, + "y": 19 + }, + { + "x": 4, + "y": 19 + }, + { + "x": 6, + "y": 19 + }, + { + "x": 8, + "y": 19 + }, + { + "x": 10, + "y": 19 + }, + { + "x": 12, + "y": 19 + }, + { + "x": 14, + "y": 19 + }, + { + "x": 16, + "y": 19 + }, + { + "x": 18, + "y": 19 + }, + { + "x": 20, + "y": 19 + }, + { + "x": 22, + "y": 19 + }, + { + "x": 24, + "y": 19 + }, + { + "x": 26, + "y": 19 + }, + { + "x": 28, + "y": 19 + }, + { + "x": 30, + "y": 19 + }, + { + "x": 32, + "y": 19 + }, + { + "x": 34, + "y": 19 + }, + { + "x": 36, + "y": 19 + }, + { + "x": 38, + "y": 19 + }, + { + "x": 40, + "y": 19 + }, + { + "x": 42, + "y": 19 + }, + { + "x": 44, + "y": 19 + }, + { + "x": 46, + "y": 19 + }, + { + "x": 48, + "y": 19 + }, + { + "x": 50, + "y": 19 + }, + { + "x": 52, + "y": 19 + }, + { + "x": 54, + "y": 19 + }, + { + "x": 56, + "y": 19 + }, + { + "x": 58, + "y": 19 + }, + { + "x": 60, + "y": 19 + }, + { + "x": 62, + "y": 19 + }, + { + "x": 64, + "y": 19 + }, + { + "x": 66, + "y": 19 + }, + { + "x": 68, + "y": 19 + }, + { + "x": 70, + "y": 19 + }, + { + "x": 72, + "y": 19 + }, + { + "x": 74, + "y": 19 + }, + { + "x": 0, + "y": 20 + }, + { + "x": 2, + "y": 20 + }, + { + "x": 4, + "y": 20 + }, + { + "x": 6, + "y": 20 + }, + { + "x": 8, + "y": 20 + }, + { + "x": 10, + "y": 20 + }, + { + "x": 12, + "y": 20 + }, + { + "x": 14, + "y": 20 + }, + { + "x": 16, + "y": 20 + }, + { + "x": 18, + "y": 20 + }, + { + "x": 20, + "y": 20 + }, + { + "x": 22, + "y": 20 + }, + { + "x": 24, + "y": 20 + }, + { + "x": 26, + "y": 20 + }, + { + "x": 28, + "y": 20 + }, + { + "x": 30, + "y": 20 + }, + { + "x": 32, + "y": 20 + }, + { + "x": 34, + "y": 20 + }, + { + "x": 36, + "y": 20 + }, + { + "x": 38, + "y": 20 + }, + { + "x": 40, + "y": 20 + }, + { + "x": 42, + "y": 20 + }, + { + "x": 44, + "y": 20 + }, + { + "x": 46, + "y": 20 + }, + { + "x": 48, + "y": 20 + }, + { + "x": 50, + "y": 20 + }, + { + "x": 52, + "y": 20 + }, + { + "x": 54, + "y": 20 + }, + { + "x": 56, + "y": 20 + }, + { + "x": 58, + "y": 20 + }, + { + "x": 60, + "y": 20 + }, + { + "x": 62, + "y": 20 + }, + { + "x": 64, + "y": 20 + }, + { + "x": 66, + "y": 20 + }, + { + "x": 68, + "y": 20 + }, + { + "x": 70, + "y": 20 + }, + { + "x": 72, + "y": 20 + }, + { + "x": 74, + "y": 20 + }, + { + "x": 0, + "y": 21 + }, + { + "x": 2, + "y": 21 + }, + { + "x": 4, + "y": 21 + }, + { + "x": 6, + "y": 21 + }, + { + "x": 8, + "y": 21 + }, + { + "x": 10, + "y": 21 + }, + { + "x": 12, + "y": 21 + }, + { + "x": 14, + "y": 21 + }, + { + "x": 16, + "y": 21 + }, + { + "x": 18, + "y": 21 + }, + { + "x": 20, + "y": 21 + }, + { + "x": 22, + "y": 21 + }, + { + "x": 24, + "y": 21 + }, + { + "x": 26, + "y": 21 + }, + { + "x": 28, + "y": 21 + }, + { + "x": 30, + "y": 21 + }, + { + "x": 32, + "y": 21 + }, + { + "x": 34, + "y": 21 + }, + { + "x": 36, + "y": 21 + }, + { + "x": 38, + "y": 21 + }, + { + "x": 40, + "y": 21 + }, + { + "x": 42, + "y": 21 + }, + { + "x": 44, + "y": 21 + }, + { + "x": 46, + "y": 21 + }, + { + "x": 48, + "y": 21 + }, + { + "x": 50, + "y": 21 + }, + { + "x": 52, + "y": 21 + }, + { + "x": 54, + "y": 21 + }, + { + "x": 56, + "y": 21 + }, + { + "x": 58, + "y": 21 + }, + { + "x": 60, + "y": 21 + }, + { + "x": 62, + "y": 21 + }, + { + "x": 64, + "y": 21 + }, + { + "x": 66, + "y": 21 + }, + { + "x": 68, + "y": 21 + }, + { + "x": 70, + "y": 21 + }, + { + "x": 72, + "y": 21 + }, + { + "x": 74, + "y": 21 + }, + { + "x": 0, + "y": 23 + }, + { + "x": 2, + "y": 23 + }, + { + "x": 4, + "y": 23 + }, + { + "x": 6, + "y": 23 + }, + { + "x": 8, + "y": 23 + }, + { + "x": 10, + "y": 23 + }, + { + "x": 12, + "y": 23 + }, + { + "x": 14, + "y": 23 + }, + { + "x": 16, + "y": 23 + }, + { + "x": 18, + "y": 23 + }, + { + "x": 20, + "y": 23 + }, + { + "x": 22, + "y": 23 + }, + { + "x": 24, + "y": 23 + }, + { + "x": 26, + "y": 23 + }, + { + "x": 28, + "y": 23 + }, + { + "x": 30, + "y": 23 + }, + { + "x": 32, + "y": 23 + }, + { + "x": 34, + "y": 23 + }, + { + "x": 36, + "y": 23 + }, + { + "x": 38, + "y": 23 + }, + { + "x": 40, + "y": 23 + }, + { + "x": 42, + "y": 23 + }, + { + "x": 44, + "y": 23 + }, + { + "x": 46, + "y": 23 + }, + { + "x": 48, + "y": 23 + }, + { + "x": 50, + "y": 23 + }, + { + "x": 52, + "y": 23 + }, + { + "x": 54, + "y": 23 + }, + { + "x": 56, + "y": 23 + }, + { + "x": 58, + "y": 23 + }, + { + "x": 60, + "y": 23 + }, + { + "x": 62, + "y": 23 + }, + { + "x": 64, + "y": 23 + }, + { + "x": 66, + "y": 23 + }, + { + "x": 68, + "y": 23 + }, + { + "x": 70, + "y": 23 + }, + { + "x": 72, + "y": 23 + }, + { + "x": 74, + "y": 23 + }, + { + "x": 0, + "y": 24 + }, + { + "x": 2, + "y": 24 + }, + { + "x": 4, + "y": 24 + }, + { + "x": 6, + "y": 24 + }, + { + "x": 8, + "y": 24 + }, + { + "x": 10, + "y": 24 + }, + { + "x": 12, + "y": 24 + }, + { + "x": 14, + "y": 24 + }, + { + "x": 16, + "y": 24 + }, + { + "x": 18, + "y": 24 + }, + { + "x": 20, + "y": 24 + }, + { + "x": 22, + "y": 24 + }, + { + "x": 24, + "y": 24 + }, + { + "x": 26, + "y": 24 + }, + { + "x": 28, + "y": 24 + }, + { + "x": 30, + "y": 24 + }, + { + "x": 32, + "y": 24 + }, + { + "x": 34, + "y": 24 + }, + { + "x": 36, + "y": 24 + }, + { + "x": 38, + "y": 24 + }, + { + "x": 40, + "y": 24 + }, + { + "x": 42, + "y": 24 + }, + { + "x": 44, + "y": 24 + }, + { + "x": 46, + "y": 24 + }, + { + "x": 48, + "y": 24 + }, + { + "x": 50, + "y": 24 + }, + { + "x": 52, + "y": 24 + }, + { + "x": 54, + "y": 24 + }, + { + "x": 56, + "y": 24 + }, + { + "x": 58, + "y": 24 + }, + { + "x": 60, + "y": 24 + }, + { + "x": 62, + "y": 24 + }, + { + "x": 64, + "y": 24 + }, + { + "x": 66, + "y": 24 + }, + { + "x": 68, + "y": 24 + }, + { + "x": 70, + "y": 24 + }, + { + "x": 72, + "y": 24 + }, + { + "x": 74, + "y": 24 + }, + { + "x": 0, + "y": 25 + }, + { + "x": 2, + "y": 25 + }, + { + "x": 4, + "y": 25 + }, + { + "x": 6, + "y": 25 + }, + { + "x": 8, + "y": 25 + }, + { + "x": 10, + "y": 25 + }, + { + "x": 12, + "y": 25 + }, + { + "x": 14, + "y": 25 + }, + { + "x": 16, + "y": 25 + }, + { + "x": 18, + "y": 25 + }, + { + "x": 20, + "y": 25 + }, + { + "x": 22, + "y": 25 + }, + { + "x": 24, + "y": 25 + }, + { + "x": 26, + "y": 25 + }, + { + "x": 28, + "y": 25 + }, + { + "x": 30, + "y": 25 + }, + { + "x": 32, + "y": 25 + }, + { + "x": 34, + "y": 25 + }, + { + "x": 36, + "y": 25 + }, + { + "x": 38, + "y": 25 + }, + { + "x": 40, + "y": 25 + }, + { + "x": 42, + "y": 25 + }, + { + "x": 44, + "y": 25 + }, + { + "x": 46, + "y": 25 + }, + { + "x": 48, + "y": 25 + }, + { + "x": 50, + "y": 25 + }, + { + "x": 52, + "y": 25 + }, + { + "x": 54, + "y": 25 + }, + { + "x": 56, + "y": 25 + }, + { + "x": 58, + "y": 25 + }, + { + "x": 60, + "y": 25 + }, + { + "x": 62, + "y": 25 + }, + { + "x": 64, + "y": 25 + }, + { + "x": 66, + "y": 25 + }, + { + "x": 68, + "y": 25 + }, + { + "x": 70, + "y": 25 + }, + { + "x": 72, + "y": 25 + }, + { + "x": 74, + "y": 25 + }, + { + "x": 0, + "y": 26 + }, + { + "x": 2, + "y": 26 + }, + { + "x": 4, + "y": 26 + }, + { + "x": 6, + "y": 26 + }, + { + "x": 8, + "y": 26 + }, + { + "x": 10, + "y": 26 + }, + { + "x": 12, + "y": 26 + }, + { + "x": 14, + "y": 26 + }, + { + "x": 16, + "y": 26 + }, + { + "x": 18, + "y": 26 + }, + { + "x": 20, + "y": 26 + }, + { + "x": 22, + "y": 26 + }, + { + "x": 24, + "y": 26 + }, + { + "x": 26, + "y": 26 + }, + { + "x": 28, + "y": 26 + }, + { + "x": 30, + "y": 26 + }, + { + "x": 32, + "y": 26 + }, + { + "x": 34, + "y": 26 + }, + { + "x": 36, + "y": 26 + }, + { + "x": 38, + "y": 26 + }, + { + "x": 40, + "y": 26 + }, + { + "x": 42, + "y": 26 + }, + { + "x": 44, + "y": 26 + }, + { + "x": 46, + "y": 26 + }, + { + "x": 48, + "y": 26 + }, + { + "x": 50, + "y": 26 + }, + { + "x": 52, + "y": 26 + }, + { + "x": 54, + "y": 26 + }, + { + "x": 56, + "y": 26 + }, + { + "x": 58, + "y": 26 + }, + { + "x": 60, + "y": 26 + }, + { + "x": 62, + "y": 26 + }, + { + "x": 64, + "y": 26 + }, + { + "x": 66, + "y": 26 + }, + { + "x": 68, + "y": 26 + }, + { + "x": 70, + "y": 26 + }, + { + "x": 72, + "y": 26 + }, + { + "x": 74, + "y": 26 + }, + { + "x": 0, + "y": 27 + }, + { + "x": 2, + "y": 27 + }, + { + "x": 4, + "y": 27 + }, + { + "x": 6, + "y": 27 + }, + { + "x": 8, + "y": 27 + }, + { + "x": 10, + "y": 27 + }, + { + "x": 12, + "y": 27 + }, + { + "x": 14, + "y": 27 + }, + { + "x": 16, + "y": 27 + }, + { + "x": 18, + "y": 27 + }, + { + "x": 20, + "y": 27 + }, + { + "x": 22, + "y": 27 + }, + { + "x": 24, + "y": 27 + }, + { + "x": 26, + "y": 27 + }, + { + "x": 28, + "y": 27 + }, + { + "x": 30, + "y": 27 + }, + { + "x": 32, + "y": 27 + }, + { + "x": 34, + "y": 27 + }, + { + "x": 36, + "y": 27 + }, + { + "x": 38, + "y": 27 + }, + { + "x": 40, + "y": 27 + }, + { + "x": 42, + "y": 27 + }, + { + "x": 44, + "y": 27 + }, + { + "x": 46, + "y": 27 + }, + { + "x": 48, + "y": 27 + }, + { + "x": 50, + "y": 27 + }, + { + "x": 52, + "y": 27 + }, + { + "x": 54, + "y": 27 + }, + { + "x": 56, + "y": 27 + }, + { + "x": 58, + "y": 27 + }, + { + "x": 60, + "y": 27 + }, + { + "x": 62, + "y": 27 + }, + { + "x": 64, + "y": 27 + }, + { + "x": 66, + "y": 27 + }, + { + "x": 68, + "y": 27 + }, + { + "x": 70, + "y": 27 + }, + { + "x": 72, + "y": 27 + }, + { + "x": 74, + "y": 27 + }, + { + "x": 0, + "y": 28 + }, + { + "x": 2, + "y": 28 + }, + { + "x": 4, + "y": 28 + }, + { + "x": 6, + "y": 28 + }, + { + "x": 8, + "y": 28 + }, + { + "x": 10, + "y": 28 + }, + { + "x": 12, + "y": 28 + }, + { + "x": 14, + "y": 28 + }, + { + "x": 16, + "y": 28 + }, + { + "x": 18, + "y": 28 + }, + { + "x": 20, + "y": 28 + }, + { + "x": 22, + "y": 28 + }, + { + "x": 24, + "y": 28 + }, + { + "x": 26, + "y": 28 + }, + { + "x": 28, + "y": 28 + }, + { + "x": 30, + "y": 28 + }, + { + "x": 32, + "y": 28 + }, + { + "x": 34, + "y": 28 + }, + { + "x": 36, + "y": 28 + }, + { + "x": 38, + "y": 28 + }, + { + "x": 40, + "y": 28 + }, + { + "x": 42, + "y": 28 + }, + { + "x": 44, + "y": 28 + }, + { + "x": 46, + "y": 28 + }, + { + "x": 48, + "y": 28 + }, + { + "x": 50, + "y": 28 + }, + { + "x": 52, + "y": 28 + }, + { + "x": 54, + "y": 28 + }, + { + "x": 56, + "y": 28 + }, + { + "x": 58, + "y": 28 + }, + { + "x": 60, + "y": 28 + }, + { + "x": 62, + "y": 28 + }, + { + "x": 64, + "y": 28 + }, + { + "x": 66, + "y": 28 + }, + { + "x": 68, + "y": 28 + }, + { + "x": 70, + "y": 28 + }, + { + "x": 72, + "y": 28 + }, + { + "x": 74, + "y": 28 + }, + { + "x": 0, + "y": 29 + }, + { + "x": 2, + "y": 29 + }, + { + "x": 4, + "y": 29 + }, + { + "x": 6, + "y": 29 + }, + { + "x": 8, + "y": 29 + }, + { + "x": 10, + "y": 29 + }, + { + "x": 12, + "y": 29 + }, + { + "x": 14, + "y": 29 + }, + { + "x": 16, + "y": 29 + }, + { + "x": 18, + "y": 29 + }, + { + "x": 20, + "y": 29 + }, + { + "x": 22, + "y": 29 + }, + { + "x": 24, + "y": 29 + }, + { + "x": 26, + "y": 29 + }, + { + "x": 28, + "y": 29 + }, + { + "x": 30, + "y": 29 + }, + { + "x": 32, + "y": 29 + }, + { + "x": 34, + "y": 29 + }, + { + "x": 36, + "y": 29 + }, + { + "x": 38, + "y": 29 + }, + { + "x": 40, + "y": 29 + }, + { + "x": 42, + "y": 29 + }, + { + "x": 44, + "y": 29 + }, + { + "x": 46, + "y": 29 + }, + { + "x": 48, + "y": 29 + }, + { + "x": 50, + "y": 29 + }, + { + "x": 52, + "y": 29 + }, + { + "x": 54, + "y": 29 + }, + { + "x": 56, + "y": 29 + }, + { + "x": 58, + "y": 29 + }, + { + "x": 60, + "y": 29 + }, + { + "x": 62, + "y": 29 + }, + { + "x": 64, + "y": 29 + }, + { + "x": 66, + "y": 29 + }, + { + "x": 68, + "y": 29 + }, + { + "x": 70, + "y": 29 + }, + { + "x": 72, + "y": 29 + }, + { + "x": 74, + "y": 29 + }, + { + "x": 0, + "y": 30 + }, + { + "x": 2, + "y": 30 + }, + { + "x": 4, + "y": 30 + }, + { + "x": 6, + "y": 30 + }, + { + "x": 8, + "y": 30 + }, + { + "x": 10, + "y": 30 + }, + { + "x": 12, + "y": 30 + }, + { + "x": 14, + "y": 30 + }, + { + "x": 16, + "y": 30 + }, + { + "x": 18, + "y": 30 + }, + { + "x": 20, + "y": 30 + }, + { + "x": 22, + "y": 30 + }, + { + "x": 24, + "y": 30 + }, + { + "x": 26, + "y": 30 + }, + { + "x": 28, + "y": 30 + }, + { + "x": 30, + "y": 30 + }, + { + "x": 32, + "y": 30 + }, + { + "x": 34, + "y": 30 + }, + { + "x": 36, + "y": 30 + }, + { + "x": 38, + "y": 30 + }, + { + "x": 40, + "y": 30 + }, + { + "x": 42, + "y": 30 + }, + { + "x": 44, + "y": 30 + }, + { + "x": 46, + "y": 30 + }, + { + "x": 48, + "y": 30 + }, + { + "x": 50, + "y": 30 + }, + { + "x": 52, + "y": 30 + }, + { + "x": 54, + "y": 30 + }, + { + "x": 56, + "y": 30 + }, + { + "x": 58, + "y": 30 + }, + { + "x": 60, + "y": 30 + }, + { + "x": 62, + "y": 30 + }, + { + "x": 64, + "y": 30 + }, + { + "x": 66, + "y": 30 + }, + { + "x": 68, + "y": 30 + }, + { + "x": 70, + "y": 30 + }, + { + "x": 72, + "y": 30 + }, + { + "x": 74, + "y": 30 + }, + { + "x": 0, + "y": 31 + }, + { + "x": 2, + "y": 31 + }, + { + "x": 4, + "y": 31 + }, + { + "x": 6, + "y": 31 + }, + { + "x": 8, + "y": 31 + }, + { + "x": 10, + "y": 31 + }, + { + "x": 12, + "y": 31 + }, + { + "x": 14, + "y": 31 + }, + { + "x": 16, + "y": 31 + }, + { + "x": 18, + "y": 31 + }, + { + "x": 20, + "y": 31 + }, + { + "x": 22, + "y": 31 + }, + { + "x": 24, + "y": 31 + }, + { + "x": 26, + "y": 31 + }, + { + "x": 28, + "y": 31 + }, + { + "x": 30, + "y": 31 + }, + { + "x": 32, + "y": 31 + }, + { + "x": 34, + "y": 31 + }, + { + "x": 36, + "y": 31 + }, + { + "x": 38, + "y": 31 + }, + { + "x": 40, + "y": 31 + }, + { + "x": 42, + "y": 31 + }, + { + "x": 44, + "y": 31 + }, + { + "x": 46, + "y": 31 + }, + { + "x": 48, + "y": 31 + }, + { + "x": 50, + "y": 31 + }, + { + "x": 52, + "y": 31 + }, + { + "x": 54, + "y": 31 + }, + { + "x": 56, + "y": 31 + }, + { + "x": 58, + "y": 31 + }, + { + "x": 60, + "y": 31 + }, + { + "x": 62, + "y": 31 + }, + { + "x": 64, + "y": 31 + }, + { + "x": 66, + "y": 31 + }, + { + "x": 68, + "y": 31 + }, + { + "x": 70, + "y": 31 + }, + { + "x": 72, + "y": 31 + }, + { + "x": 74, + "y": 31 + }, + { + "x": 0, + "y": 33 + }, + { + "x": 2, + "y": 33 + }, + { + "x": 4, + "y": 33 + }, + { + "x": 6, + "y": 33 + }, + { + "x": 8, + "y": 33 + }, + { + "x": 10, + "y": 33 + }, + { + "x": 12, + "y": 33 + }, + { + "x": 14, + "y": 33 + }, + { + "x": 16, + "y": 33 + }, + { + "x": 18, + "y": 33 + }, + { + "x": 20, + "y": 33 + }, + { + "x": 22, + "y": 33 + }, + { + "x": 24, + "y": 33 + }, + { + "x": 26, + "y": 33 + }, + { + "x": 28, + "y": 33 + }, + { + "x": 30, + "y": 33 + }, + { + "x": 32, + "y": 33 + }, + { + "x": 34, + "y": 33 + }, + { + "x": 36, + "y": 33 + }, + { + "x": 38, + "y": 33 + }, + { + "x": 40, + "y": 33 + }, + { + "x": 42, + "y": 33 + }, + { + "x": 44, + "y": 33 + }, + { + "x": 46, + "y": 33 + }, + { + "x": 48, + "y": 33 + }, + { + "x": 50, + "y": 33 + }, + { + "x": 52, + "y": 33 + }, + { + "x": 54, + "y": 33 + }, + { + "x": 56, + "y": 33 + }, + { + "x": 58, + "y": 33 + }, + { + "x": 60, + "y": 33 + }, + { + "x": 62, + "y": 33 + }, + { + "x": 64, + "y": 33 + }, + { + "x": 66, + "y": 33 + }, + { + "x": 68, + "y": 33 + }, + { + "x": 70, + "y": 33 + }, + { + "x": 72, + "y": 33 + }, + { + "x": 74, + "y": 33 + }, + { + "x": 0, + "y": 34 + }, + { + "x": 2, + "y": 34 + }, + { + "x": 4, + "y": 34 + }, + { + "x": 6, + "y": 34 + }, + { + "x": 8, + "y": 34 + }, + { + "x": 10, + "y": 34 + }, + { + "x": 12, + "y": 34 + }, + { + "x": 14, + "y": 34 + }, + { + "x": 16, + "y": 34 + }, + { + "x": 18, + "y": 34 + }, + { + "x": 20, + "y": 34 + }, + { + "x": 22, + "y": 34 + }, + { + "x": 24, + "y": 34 + }, + { + "x": 26, + "y": 34 + }, + { + "x": 28, + "y": 34 + }, + { + "x": 30, + "y": 34 + }, + { + "x": 32, + "y": 34 + }, + { + "x": 34, + "y": 34 + }, + { + "x": 36, + "y": 34 + }, + { + "x": 38, + "y": 34 + }, + { + "x": 40, + "y": 34 + }, + { + "x": 42, + "y": 34 + }, + { + "x": 44, + "y": 34 + }, + { + "x": 46, + "y": 34 + }, + { + "x": 48, + "y": 34 + }, + { + "x": 50, + "y": 34 + }, + { + "x": 52, + "y": 34 + }, + { + "x": 54, + "y": 34 + }, + { + "x": 56, + "y": 34 + }, + { + "x": 58, + "y": 34 + }, + { + "x": 60, + "y": 34 + }, + { + "x": 62, + "y": 34 + }, + { + "x": 64, + "y": 34 + }, + { + "x": 66, + "y": 34 + }, + { + "x": 68, + "y": 34 + }, + { + "x": 70, + "y": 34 + }, + { + "x": 72, + "y": 34 + }, + { + "x": 74, + "y": 34 + }, + { + "x": 0, + "y": 35 + }, + { + "x": 2, + "y": 35 + }, + { + "x": 4, + "y": 35 + }, + { + "x": 6, + "y": 35 + }, + { + "x": 8, + "y": 35 + }, + { + "x": 10, + "y": 35 + }, + { + "x": 12, + "y": 35 + }, + { + "x": 14, + "y": 35 + }, + { + "x": 16, + "y": 35 + }, + { + "x": 18, + "y": 35 + }, + { + "x": 20, + "y": 35 + }, + { + "x": 22, + "y": 35 + }, + { + "x": 24, + "y": 35 + }, + { + "x": 26, + "y": 35 + }, + { + "x": 28, + "y": 35 + }, + { + "x": 30, + "y": 35 + }, + { + "x": 32, + "y": 35 + }, + { + "x": 34, + "y": 35 + }, + { + "x": 36, + "y": 35 + }, + { + "x": 38, + "y": 35 + }, + { + "x": 40, + "y": 35 + }, + { + "x": 42, + "y": 35 + }, + { + "x": 44, + "y": 35 + }, + { + "x": 46, + "y": 35 + }, + { + "x": 48, + "y": 35 + }, + { + "x": 50, + "y": 35 + }, + { + "x": 52, + "y": 35 + }, + { + "x": 54, + "y": 35 + }, + { + "x": 56, + "y": 35 + }, + { + "x": 58, + "y": 35 + }, + { + "x": 60, + "y": 35 + }, + { + "x": 62, + "y": 35 + }, + { + "x": 64, + "y": 35 + }, + { + "x": 66, + "y": 35 + }, + { + "x": 68, + "y": 35 + }, + { + "x": 70, + "y": 35 + }, + { + "x": 72, + "y": 35 + }, + { + "x": 74, + "y": 35 + }, + { + "x": 0, + "y": 36 + }, + { + "x": 2, + "y": 36 + }, + { + "x": 4, + "y": 36 + }, + { + "x": 6, + "y": 36 + }, + { + "x": 8, + "y": 36 + }, + { + "x": 10, + "y": 36 + }, + { + "x": 12, + "y": 36 + }, + { + "x": 14, + "y": 36 + }, + { + "x": 16, + "y": 36 + }, + { + "x": 18, + "y": 36 + }, + { + "x": 20, + "y": 36 + }, + { + "x": 22, + "y": 36 + }, + { + "x": 24, + "y": 36 + }, + { + "x": 26, + "y": 36 + }, + { + "x": 28, + "y": 36 + }, + { + "x": 30, + "y": 36 + }, + { + "x": 32, + "y": 36 + }, + { + "x": 34, + "y": 36 + }, + { + "x": 36, + "y": 36 + }, + { + "x": 38, + "y": 36 + }, + { + "x": 40, + "y": 36 + }, + { + "x": 42, + "y": 36 + }, + { + "x": 44, + "y": 36 + }, + { + "x": 46, + "y": 36 + }, + { + "x": 48, + "y": 36 + }, + { + "x": 50, + "y": 36 + }, + { + "x": 52, + "y": 36 + }, + { + "x": 54, + "y": 36 + }, + { + "x": 56, + "y": 36 + }, + { + "x": 58, + "y": 36 + }, + { + "x": 60, + "y": 36 + }, + { + "x": 62, + "y": 36 + }, + { + "x": 64, + "y": 36 + }, + { + "x": 66, + "y": 36 + }, + { + "x": 68, + "y": 36 + }, + { + "x": 70, + "y": 36 + }, + { + "x": 72, + "y": 36 + }, + { + "x": 74, + "y": 36 + }, + { + "x": 0, + "y": 37 + }, + { + "x": 2, + "y": 37 + }, + { + "x": 4, + "y": 37 + }, + { + "x": 6, + "y": 37 + }, + { + "x": 8, + "y": 37 + }, + { + "x": 10, + "y": 37 + }, + { + "x": 12, + "y": 37 + }, + { + "x": 14, + "y": 37 + }, + { + "x": 16, + "y": 37 + }, + { + "x": 18, + "y": 37 + }, + { + "x": 20, + "y": 37 + }, + { + "x": 22, + "y": 37 + }, + { + "x": 24, + "y": 37 + }, + { + "x": 26, + "y": 37 + }, + { + "x": 28, + "y": 37 + }, + { + "x": 30, + "y": 37 + }, + { + "x": 32, + "y": 37 + }, + { + "x": 34, + "y": 37 + }, + { + "x": 36, + "y": 37 + }, + { + "x": 38, + "y": 37 + }, + { + "x": 40, + "y": 37 + }, + { + "x": 42, + "y": 37 + }, + { + "x": 44, + "y": 37 + }, + { + "x": 46, + "y": 37 + }, + { + "x": 48, + "y": 37 + }, + { + "x": 50, + "y": 37 + }, + { + "x": 52, + "y": 37 + }, + { + "x": 54, + "y": 37 + }, + { + "x": 56, + "y": 37 + }, + { + "x": 58, + "y": 37 + }, + { + "x": 60, + "y": 37 + }, + { + "x": 62, + "y": 37 + }, + { + "x": 64, + "y": 37 + }, + { + "x": 66, + "y": 37 + }, + { + "x": 68, + "y": 37 + }, + { + "x": 70, + "y": 37 + }, + { + "x": 72, + "y": 37 + }, + { + "x": 74, + "y": 37 + }, + { + "x": 0, + "y": 38 + }, + { + "x": 2, + "y": 38 + }, + { + "x": 4, + "y": 38 + }, + { + "x": 6, + "y": 38 + }, + { + "x": 8, + "y": 38 + }, + { + "x": 10, + "y": 38 + }, + { + "x": 12, + "y": 38 + }, + { + "x": 14, + "y": 38 + }, + { + "x": 16, + "y": 38 + }, + { + "x": 18, + "y": 38 + }, + { + "x": 20, + "y": 38 + }, + { + "x": 22, + "y": 38 + }, + { + "x": 24, + "y": 38 + }, + { + "x": 26, + "y": 38 + }, + { + "x": 28, + "y": 38 + }, + { + "x": 30, + "y": 38 + }, + { + "x": 32, + "y": 38 + }, + { + "x": 34, + "y": 38 + }, + { + "x": 36, + "y": 38 + }, + { + "x": 38, + "y": 38 + }, + { + "x": 40, + "y": 38 + }, + { + "x": 42, + "y": 38 + }, + { + "x": 44, + "y": 38 + }, + { + "x": 46, + "y": 38 + }, + { + "x": 48, + "y": 38 + }, + { + "x": 50, + "y": 38 + }, + { + "x": 52, + "y": 38 + }, + { + "x": 54, + "y": 38 + }, + { + "x": 56, + "y": 38 + }, + { + "x": 58, + "y": 38 + }, + { + "x": 60, + "y": 38 + }, + { + "x": 62, + "y": 38 + }, + { + "x": 64, + "y": 38 + }, + { + "x": 66, + "y": 38 + }, + { + "x": 68, + "y": 38 + }, + { + "x": 70, + "y": 38 + }, + { + "x": 72, + "y": 38 + }, + { + "x": 74, + "y": 38 + }, + { + "x": 0, + "y": 39 + }, + { + "x": 2, + "y": 39 + }, + { + "x": 4, + "y": 39 + }, + { + "x": 6, + "y": 39 + }, + { + "x": 8, + "y": 39 + }, + { + "x": 10, + "y": 39 + }, + { + "x": 12, + "y": 39 + }, + { + "x": 14, + "y": 39 + }, + { + "x": 16, + "y": 39 + }, + { + "x": 18, + "y": 39 + }, + { + "x": 20, + "y": 39 + }, + { + "x": 22, + "y": 39 + }, + { + "x": 24, + "y": 39 + }, + { + "x": 26, + "y": 39 + }, + { + "x": 28, + "y": 39 + }, + { + "x": 30, + "y": 39 + }, + { + "x": 32, + "y": 39 + }, + { + "x": 34, + "y": 39 + }, + { + "x": 36, + "y": 39 + }, + { + "x": 38, + "y": 39 + }, + { + "x": 40, + "y": 39 + }, + { + "x": 42, + "y": 39 + }, + { + "x": 44, + "y": 39 + }, + { + "x": 46, + "y": 39 + }, + { + "x": 48, + "y": 39 + }, + { + "x": 50, + "y": 39 + }, + { + "x": 52, + "y": 39 + }, + { + "x": 54, + "y": 39 + }, + { + "x": 56, + "y": 39 + }, + { + "x": 58, + "y": 39 + }, + { + "x": 60, + "y": 39 + }, + { + "x": 62, + "y": 39 + }, + { + "x": 64, + "y": 39 + }, + { + "x": 66, + "y": 39 + }, + { + "x": 68, + "y": 39 + }, + { + "x": 70, + "y": 39 + }, + { + "x": 72, + "y": 39 + }, + { + "x": 74, + "y": 39 + }, + { + "x": 0, + "y": 40 + }, + { + "x": 2, + "y": 40 + }, + { + "x": 4, + "y": 40 + }, + { + "x": 6, + "y": 40 + }, + { + "x": 8, + "y": 40 + }, + { + "x": 10, + "y": 40 + }, + { + "x": 12, + "y": 40 + }, + { + "x": 14, + "y": 40 + }, + { + "x": 16, + "y": 40 + }, + { + "x": 18, + "y": 40 + }, + { + "x": 20, + "y": 40 + }, + { + "x": 22, + "y": 40 + }, + { + "x": 24, + "y": 40 + }, + { + "x": 26, + "y": 40 + }, + { + "x": 28, + "y": 40 + }, + { + "x": 30, + "y": 40 + }, + { + "x": 32, + "y": 40 + }, + { + "x": 34, + "y": 40 + }, + { + "x": 36, + "y": 40 + }, + { + "x": 38, + "y": 40 + }, + { + "x": 40, + "y": 40 + }, + { + "x": 42, + "y": 40 + }, + { + "x": 44, + "y": 40 + }, + { + "x": 46, + "y": 40 + }, + { + "x": 48, + "y": 40 + }, + { + "x": 50, + "y": 40 + }, + { + "x": 52, + "y": 40 + }, + { + "x": 54, + "y": 40 + }, + { + "x": 56, + "y": 40 + }, + { + "x": 58, + "y": 40 + }, + { + "x": 60, + "y": 40 + }, + { + "x": 62, + "y": 40 + }, + { + "x": 64, + "y": 40 + }, + { + "x": 66, + "y": 40 + }, + { + "x": 68, + "y": 40 + }, + { + "x": 70, + "y": 40 + }, + { + "x": 72, + "y": 40 + }, + { + "x": 74, + "y": 40 + }, + { + "x": 0, + "y": 41 + }, + { + "x": 2, + "y": 41 + }, + { + "x": 4, + "y": 41 + }, + { + "x": 6, + "y": 41 + }, + { + "x": 8, + "y": 41 + }, + { + "x": 10, + "y": 41 + }, + { + "x": 12, + "y": 41 + }, + { + "x": 14, + "y": 41 + }, + { + "x": 16, + "y": 41 + }, + { + "x": 18, + "y": 41 + }, + { + "x": 20, + "y": 41 + }, + { + "x": 22, + "y": 41 + }, + { + "x": 24, + "y": 41 + }, + { + "x": 26, + "y": 41 + }, + { + "x": 28, + "y": 41 + }, + { + "x": 30, + "y": 41 + }, + { + "x": 32, + "y": 41 + }, + { + "x": 34, + "y": 41 + }, + { + "x": 36, + "y": 41 + }, + { + "x": 38, + "y": 41 + }, + { + "x": 40, + "y": 41 + }, + { + "x": 42, + "y": 41 + }, + { + "x": 44, + "y": 41 + }, + { + "x": 46, + "y": 41 + }, + { + "x": 48, + "y": 41 + }, + { + "x": 50, + "y": 41 + }, + { + "x": 52, + "y": 41 + }, + { + "x": 54, + "y": 41 + }, + { + "x": 56, + "y": 41 + }, + { + "x": 58, + "y": 41 + }, + { + "x": 60, + "y": 41 + }, + { + "x": 62, + "y": 41 + }, + { + "x": 64, + "y": 41 + }, + { + "x": 66, + "y": 41 + }, + { + "x": 68, + "y": 41 + }, + { + "x": 70, + "y": 41 + }, + { + "x": 72, + "y": 41 + }, + { + "x": 74, + "y": 41 + } + ], + "loading_areas": [ + { + "x": 3, + "y": 48 + }, + { + "x": 6, + "y": 48 + }, + { + "x": 9, + "y": 48 + }, + { + "x": 13, + "y": 48 + }, + { + "x": 19, + "y": 48 + }, + { + "x": 22, + "y": 48 + }, + { + "x": 25, + "y": 48 + }, + { + "x": 29, + "y": 48 + }, + { + "x": 35, + "y": 48 + }, + { + "x": 38, + "y": 48 + }, + { + "x": 41, + "y": 48 + }, + { + "x": 45, + "y": 48 + }, + { + "x": 51, + "y": 48 + }, + { + "x": 54, + "y": 48 + }, + { + "x": 57, + "y": 48 + }, + { + "x": 61, + "y": 48 + }, + { + "x": 67, + "y": 48 + }, + { + "x": 70, + "y": 48 + }, + { + "x": 73, + "y": 48 + }, + { + "x": 77, + "y": 48 + } + ], + "unloading_areas": [ + { + "x": 1, + "y": 48 + }, + { + "x": 4, + "y": 48 + }, + { + "x": 7, + "y": 48 + }, + { + "x": 11, + "y": 48 + }, + { + "x": 17, + "y": 48 + }, + { + "x": 20, + "y": 48 + }, + { + "x": 23, + "y": 48 + }, + { + "x": 27, + "y": 48 + }, + { + "x": 33, + "y": 48 + }, + { + "x": 36, + "y": 48 + }, + { + "x": 39, + "y": 48 + }, + { + "x": 43, + "y": 48 + }, + { + "x": 49, + "y": 48 + }, + { + "x": 52, + "y": 48 + }, + { + "x": 55, + "y": 48 + }, + { + "x": 59, + "y": 48 + }, + { + "x": 65, + "y": 48 + }, + { + "x": 68, + "y": 48 + }, + { + "x": 71, + "y": 48 + }, + { + "x": 75, + "y": 48 + } + ], + "obstacles": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 0 + }, + { + "x": 2, + "y": 0 + }, + { + "x": 3, + "y": 0 + }, + { + "x": 4, + "y": 0 + }, + { + "x": 5, + "y": 0 + }, + { + "x": 6, + "y": 0 + }, + { + "x": 7, + "y": 0 + }, + { + "x": 8, + "y": 0 + }, + { + "x": 9, + "y": 0 + }, + { + "x": 10, + "y": 0 + }, + { + "x": 11, + "y": 0 + }, + { + "x": 12, + "y": 0 + }, + { + "x": 13, + "y": 0 + }, + { + "x": 14, + "y": 0 + }, + { + "x": 15, + "y": 0 + }, + { + "x": 16, + "y": 0 + }, + { + "x": 62, + "y": 0 + }, + { + "x": 63, + "y": 0 + }, + { + "x": 64, + "y": 0 + }, + { + "x": 65, + "y": 0 + }, + { + "x": 66, + "y": 0 + }, + { + "x": 67, + "y": 0 + }, + { + "x": 68, + "y": 0 + }, + { + "x": 69, + "y": 0 + }, + { + "x": 70, + "y": 0 + }, + { + "x": 71, + "y": 0 + }, + { + "x": 72, + "y": 0 + }, + { + "x": 73, + "y": 0 + }, + { + "x": 74, + "y": 0 + }, + { + "x": 75, + "y": 0 + }, + { + "x": 76, + "y": 0 + }, + { + "x": 77, + "y": 0 + }, + { + "x": 0, + "y": 1 + }, + { + "x": 1, + "y": 1 + }, + { + "x": 2, + "y": 1 + }, + { + "x": 3, + "y": 1 + }, + { + "x": 4, + "y": 1 + }, + { + "x": 5, + "y": 1 + }, + { + "x": 6, + "y": 1 + }, + { + "x": 7, + "y": 1 + }, + { + "x": 8, + "y": 1 + }, + { + "x": 9, + "y": 1 + }, + { + "x": 10, + "y": 1 + }, + { + "x": 11, + "y": 1 + }, + { + "x": 12, + "y": 1 + }, + { + "x": 13, + "y": 1 + }, + { + "x": 14, + "y": 1 + }, + { + "x": 15, + "y": 1 + }, + { + "x": 16, + "y": 1 + }, + { + "x": 62, + "y": 1 + }, + { + "x": 63, + "y": 1 + }, + { + "x": 64, + "y": 1 + }, + { + "x": 65, + "y": 1 + }, + { + "x": 66, + "y": 1 + }, + { + "x": 67, + "y": 1 + }, + { + "x": 68, + "y": 1 + }, + { + "x": 69, + "y": 1 + }, + { + "x": 70, + "y": 1 + }, + { + "x": 71, + "y": 1 + }, + { + "x": 72, + "y": 1 + }, + { + "x": 73, + "y": 1 + }, + { + "x": 74, + "y": 1 + }, + { + "x": 75, + "y": 1 + }, + { + "x": 76, + "y": 1 + }, + { + "x": 77, + "y": 1 + }, + { + "x": 0, + "y": 2 + }, + { + "x": 1, + "y": 2 + }, + { + "x": 2, + "y": 2 + }, + { + "x": 3, + "y": 2 + }, + { + "x": 4, + "y": 2 + }, + { + "x": 5, + "y": 2 + }, + { + "x": 6, + "y": 2 + }, + { + "x": 7, + "y": 2 + }, + { + "x": 8, + "y": 2 + }, + { + "x": 9, + "y": 2 + }, + { + "x": 10, + "y": 2 + }, + { + "x": 11, + "y": 2 + }, + { + "x": 12, + "y": 2 + }, + { + "x": 13, + "y": 2 + }, + { + "x": 14, + "y": 2 + }, + { + "x": 15, + "y": 2 + }, + { + "x": 16, + "y": 2 + }, + { + "x": 62, + "y": 2 + }, + { + "x": 63, + "y": 2 + }, + { + "x": 64, + "y": 2 + }, + { + "x": 65, + "y": 2 + }, + { + "x": 66, + "y": 2 + }, + { + "x": 67, + "y": 2 + }, + { + "x": 68, + "y": 2 + }, + { + "x": 69, + "y": 2 + }, + { + "x": 70, + "y": 2 + }, + { + "x": 71, + "y": 2 + }, + { + "x": 72, + "y": 2 + }, + { + "x": 73, + "y": 2 + }, + { + "x": 74, + "y": 2 + }, + { + "x": 75, + "y": 2 + }, + { + "x": 76, + "y": 2 + }, + { + "x": 77, + "y": 2 + }, + { + "x": 0, + "y": 3 + }, + { + "x": 1, + "y": 3 + }, + { + "x": 2, + "y": 3 + }, + { + "x": 3, + "y": 3 + }, + { + "x": 4, + "y": 3 + }, + { + "x": 5, + "y": 3 + }, + { + "x": 6, + "y": 3 + }, + { + "x": 7, + "y": 3 + }, + { + "x": 8, + "y": 3 + }, + { + "x": 9, + "y": 3 + }, + { + "x": 10, + "y": 3 + }, + { + "x": 11, + "y": 3 + }, + { + "x": 12, + "y": 3 + }, + { + "x": 13, + "y": 3 + }, + { + "x": 14, + "y": 3 + }, + { + "x": 15, + "y": 3 + }, + { + "x": 16, + "y": 3 + }, + { + "x": 62, + "y": 3 + }, + { + "x": 63, + "y": 3 + }, + { + "x": 64, + "y": 3 + }, + { + "x": 65, + "y": 3 + }, + { + "x": 66, + "y": 3 + }, + { + "x": 67, + "y": 3 + }, + { + "x": 68, + "y": 3 + }, + { + "x": 69, + "y": 3 + }, + { + "x": 70, + "y": 3 + }, + { + "x": 71, + "y": 3 + }, + { + "x": 72, + "y": 3 + }, + { + "x": 73, + "y": 3 + }, + { + "x": 74, + "y": 3 + }, + { + "x": 75, + "y": 3 + }, + { + "x": 76, + "y": 3 + }, + { + "x": 77, + "y": 3 + }, + { + "x": 0, + "y": 4 + }, + { + "x": 1, + "y": 4 + }, + { + "x": 2, + "y": 4 + }, + { + "x": 3, + "y": 4 + }, + { + "x": 4, + "y": 4 + }, + { + "x": 5, + "y": 4 + }, + { + "x": 6, + "y": 4 + }, + { + "x": 7, + "y": 4 + }, + { + "x": 8, + "y": 4 + }, + { + "x": 9, + "y": 4 + }, + { + "x": 10, + "y": 4 + }, + { + "x": 11, + "y": 4 + }, + { + "x": 12, + "y": 4 + }, + { + "x": 13, + "y": 4 + }, + { + "x": 14, + "y": 4 + }, + { + "x": 15, + "y": 4 + }, + { + "x": 16, + "y": 4 + }, + { + "x": 62, + "y": 4 + }, + { + "x": 63, + "y": 4 + }, + { + "x": 64, + "y": 4 + }, + { + "x": 65, + "y": 4 + }, + { + "x": 66, + "y": 4 + }, + { + "x": 67, + "y": 4 + }, + { + "x": 68, + "y": 4 + }, + { + "x": 69, + "y": 4 + }, + { + "x": 70, + "y": 4 + }, + { + "x": 71, + "y": 4 + }, + { + "x": 72, + "y": 4 + }, + { + "x": 73, + "y": 4 + }, + { + "x": 74, + "y": 4 + }, + { + "x": 75, + "y": 4 + }, + { + "x": 76, + "y": 4 + }, + { + "x": 77, + "y": 4 + }, + { + "x": 0, + "y": 5 + }, + { + "x": 1, + "y": 5 + }, + { + "x": 2, + "y": 5 + }, + { + "x": 3, + "y": 5 + }, + { + "x": 4, + "y": 5 + }, + { + "x": 5, + "y": 5 + }, + { + "x": 6, + "y": 5 + }, + { + "x": 7, + "y": 5 + }, + { + "x": 8, + "y": 5 + }, + { + "x": 9, + "y": 5 + }, + { + "x": 10, + "y": 5 + }, + { + "x": 11, + "y": 5 + }, + { + "x": 12, + "y": 5 + }, + { + "x": 13, + "y": 5 + }, + { + "x": 14, + "y": 5 + }, + { + "x": 15, + "y": 5 + }, + { + "x": 16, + "y": 5 + }, + { + "x": 62, + "y": 5 + }, + { + "x": 63, + "y": 5 + }, + { + "x": 64, + "y": 5 + }, + { + "x": 65, + "y": 5 + }, + { + "x": 66, + "y": 5 + }, + { + "x": 67, + "y": 5 + }, + { + "x": 68, + "y": 5 + }, + { + "x": 69, + "y": 5 + }, + { + "x": 70, + "y": 5 + }, + { + "x": 71, + "y": 5 + }, + { + "x": 72, + "y": 5 + }, + { + "x": 73, + "y": 5 + }, + { + "x": 74, + "y": 5 + }, + { + "x": 75, + "y": 5 + }, + { + "x": 76, + "y": 5 + }, + { + "x": 77, + "y": 5 + }, + { + "x": 0, + "y": 6 + }, + { + "x": 1, + "y": 6 + }, + { + "x": 2, + "y": 6 + }, + { + "x": 3, + "y": 6 + }, + { + "x": 4, + "y": 6 + }, + { + "x": 5, + "y": 6 + }, + { + "x": 6, + "y": 6 + }, + { + "x": 7, + "y": 6 + }, + { + "x": 8, + "y": 6 + }, + { + "x": 9, + "y": 6 + }, + { + "x": 10, + "y": 6 + }, + { + "x": 11, + "y": 6 + }, + { + "x": 12, + "y": 6 + }, + { + "x": 13, + "y": 6 + }, + { + "x": 14, + "y": 6 + }, + { + "x": 15, + "y": 6 + }, + { + "x": 16, + "y": 6 + }, + { + "x": 62, + "y": 6 + }, + { + "x": 63, + "y": 6 + }, + { + "x": 64, + "y": 6 + }, + { + "x": 65, + "y": 6 + }, + { + "x": 66, + "y": 6 + }, + { + "x": 67, + "y": 6 + }, + { + "x": 68, + "y": 6 + }, + { + "x": 69, + "y": 6 + }, + { + "x": 70, + "y": 6 + }, + { + "x": 71, + "y": 6 + }, + { + "x": 72, + "y": 6 + }, + { + "x": 73, + "y": 6 + }, + { + "x": 74, + "y": 6 + }, + { + "x": 75, + "y": 6 + }, + { + "x": 76, + "y": 6 + }, + { + "x": 77, + "y": 6 + }, + { + "x": 0, + "y": 7 + }, + { + "x": 1, + "y": 7 + }, + { + "x": 2, + "y": 7 + }, + { + "x": 3, + "y": 7 + }, + { + "x": 4, + "y": 7 + }, + { + "x": 5, + "y": 7 + }, + { + "x": 6, + "y": 7 + }, + { + "x": 7, + "y": 7 + }, + { + "x": 8, + "y": 7 + }, + { + "x": 9, + "y": 7 + }, + { + "x": 10, + "y": 7 + }, + { + "x": 11, + "y": 7 + }, + { + "x": 12, + "y": 7 + }, + { + "x": 13, + "y": 7 + }, + { + "x": 14, + "y": 7 + }, + { + "x": 15, + "y": 7 + }, + { + "x": 16, + "y": 7 + }, + { + "x": 62, + "y": 7 + }, + { + "x": 63, + "y": 7 + }, + { + "x": 64, + "y": 7 + }, + { + "x": 65, + "y": 7 + }, + { + "x": 66, + "y": 7 + }, + { + "x": 67, + "y": 7 + }, + { + "x": 68, + "y": 7 + }, + { + "x": 69, + "y": 7 + }, + { + "x": 70, + "y": 7 + }, + { + "x": 71, + "y": 7 + }, + { + "x": 72, + "y": 7 + }, + { + "x": 73, + "y": 7 + }, + { + "x": 74, + "y": 7 + }, + { + "x": 75, + "y": 7 + }, + { + "x": 76, + "y": 7 + }, + { + "x": 77, + "y": 7 + }, + { + "x": 0, + "y": 8 + }, + { + "x": 1, + "y": 8 + }, + { + "x": 2, + "y": 8 + }, + { + "x": 3, + "y": 8 + }, + { + "x": 4, + "y": 8 + }, + { + "x": 5, + "y": 8 + }, + { + "x": 6, + "y": 8 + }, + { + "x": 7, + "y": 8 + }, + { + "x": 8, + "y": 8 + }, + { + "x": 9, + "y": 8 + }, + { + "x": 10, + "y": 8 + }, + { + "x": 11, + "y": 8 + }, + { + "x": 12, + "y": 8 + }, + { + "x": 13, + "y": 8 + }, + { + "x": 14, + "y": 8 + }, + { + "x": 15, + "y": 8 + }, + { + "x": 16, + "y": 8 + }, + { + "x": 62, + "y": 8 + }, + { + "x": 63, + "y": 8 + }, + { + "x": 64, + "y": 8 + }, + { + "x": 65, + "y": 8 + }, + { + "x": 66, + "y": 8 + }, + { + "x": 67, + "y": 8 + }, + { + "x": 68, + "y": 8 + }, + { + "x": 69, + "y": 8 + }, + { + "x": 70, + "y": 8 + }, + { + "x": 71, + "y": 8 + }, + { + "x": 72, + "y": 8 + }, + { + "x": 73, + "y": 8 + }, + { + "x": 74, + "y": 8 + }, + { + "x": 75, + "y": 8 + }, + { + "x": 76, + "y": 8 + }, + { + "x": 77, + "y": 8 + }, + { + "x": 0, + "y": 9 + }, + { + "x": 1, + "y": 9 + }, + { + "x": 2, + "y": 9 + }, + { + "x": 3, + "y": 9 + }, + { + "x": 4, + "y": 9 + }, + { + "x": 5, + "y": 9 + }, + { + "x": 6, + "y": 9 + }, + { + "x": 7, + "y": 9 + }, + { + "x": 8, + "y": 9 + }, + { + "x": 9, + "y": 9 + }, + { + "x": 10, + "y": 9 + }, + { + "x": 11, + "y": 9 + }, + { + "x": 12, + "y": 9 + }, + { + "x": 13, + "y": 9 + }, + { + "x": 14, + "y": 9 + }, + { + "x": 15, + "y": 9 + }, + { + "x": 16, + "y": 9 + }, + { + "x": 62, + "y": 9 + }, + { + "x": 63, + "y": 9 + }, + { + "x": 64, + "y": 9 + }, + { + "x": 65, + "y": 9 + }, + { + "x": 66, + "y": 9 + }, + { + "x": 67, + "y": 9 + }, + { + "x": 68, + "y": 9 + }, + { + "x": 69, + "y": 9 + }, + { + "x": 70, + "y": 9 + }, + { + "x": 71, + "y": 9 + }, + { + "x": 72, + "y": 9 + }, + { + "x": 73, + "y": 9 + }, + { + "x": 74, + "y": 9 + }, + { + "x": 75, + "y": 9 + }, + { + "x": 76, + "y": 9 + }, + { + "x": 77, + "y": 9 + }, + { + "x": 0, + "y": 10 + }, + { + "x": 1, + "y": 10 + }, + { + "x": 2, + "y": 10 + }, + { + "x": 3, + "y": 10 + }, + { + "x": 4, + "y": 10 + }, + { + "x": 5, + "y": 10 + }, + { + "x": 6, + "y": 10 + }, + { + "x": 7, + "y": 10 + }, + { + "x": 8, + "y": 10 + }, + { + "x": 9, + "y": 10 + }, + { + "x": 10, + "y": 10 + }, + { + "x": 11, + "y": 10 + }, + { + "x": 12, + "y": 10 + }, + { + "x": 13, + "y": 10 + }, + { + "x": 14, + "y": 10 + }, + { + "x": 15, + "y": 10 + }, + { + "x": 16, + "y": 10 + }, + { + "x": 62, + "y": 10 + }, + { + "x": 63, + "y": 10 + }, + { + "x": 64, + "y": 10 + }, + { + "x": 65, + "y": 10 + }, + { + "x": 66, + "y": 10 + }, + { + "x": 67, + "y": 10 + }, + { + "x": 68, + "y": 10 + }, + { + "x": 69, + "y": 10 + }, + { + "x": 70, + "y": 10 + }, + { + "x": 71, + "y": 10 + }, + { + "x": 72, + "y": 10 + }, + { + "x": 73, + "y": 10 + }, + { + "x": 74, + "y": 10 + }, + { + "x": 75, + "y": 10 + }, + { + "x": 76, + "y": 10 + }, + { + "x": 77, + "y": 10 + }, + { + "x": 0, + "y": 11 + }, + { + "x": 1, + "y": 11 + }, + { + "x": 2, + "y": 11 + }, + { + "x": 3, + "y": 11 + }, + { + "x": 4, + "y": 11 + }, + { + "x": 5, + "y": 11 + }, + { + "x": 6, + "y": 11 + }, + { + "x": 7, + "y": 11 + }, + { + "x": 8, + "y": 11 + }, + { + "x": 9, + "y": 11 + }, + { + "x": 10, + "y": 11 + }, + { + "x": 11, + "y": 11 + }, + { + "x": 12, + "y": 11 + }, + { + "x": 13, + "y": 11 + }, + { + "x": 14, + "y": 11 + }, + { + "x": 15, + "y": 11 + }, + { + "x": 16, + "y": 11 + }, + { + "x": 62, + "y": 11 + }, + { + "x": 63, + "y": 11 + }, + { + "x": 64, + "y": 11 + }, + { + "x": 65, + "y": 11 + }, + { + "x": 66, + "y": 11 + }, + { + "x": 67, + "y": 11 + }, + { + "x": 68, + "y": 11 + }, + { + "x": 69, + "y": 11 + }, + { + "x": 70, + "y": 11 + }, + { + "x": 71, + "y": 11 + }, + { + "x": 72, + "y": 11 + }, + { + "x": 73, + "y": 11 + }, + { + "x": 74, + "y": 11 + }, + { + "x": 75, + "y": 11 + }, + { + "x": 76, + "y": 11 + }, + { + "x": 77, + "y": 11 + }, + { + "x": 76, + "y": 12 + }, + { + "x": 77, + "y": 12 + }, + { + "x": 76, + "y": 13 + }, + { + "x": 77, + "y": 13 + }, + { + "x": 76, + "y": 14 + }, + { + "x": 77, + "y": 14 + }, + { + "x": 76, + "y": 15 + }, + { + "x": 77, + "y": 15 + }, + { + "x": 76, + "y": 16 + }, + { + "x": 77, + "y": 16 + }, + { + "x": 76, + "y": 17 + }, + { + "x": 77, + "y": 17 + }, + { + "x": 76, + "y": 18 + }, + { + "x": 77, + "y": 18 + }, + { + "x": 76, + "y": 19 + }, + { + "x": 77, + "y": 19 + }, + { + "x": 76, + "y": 20 + }, + { + "x": 77, + "y": 20 + }, + { + "x": 76, + "y": 21 + }, + { + "x": 77, + "y": 21 + }, + { + "x": 76, + "y": 22 + }, + { + "x": 77, + "y": 22 + }, + { + "x": 7, + "y": 23 + }, + { + "x": 15, + "y": 23 + }, + { + "x": 23, + "y": 23 + }, + { + "x": 31, + "y": 23 + }, + { + "x": 39, + "y": 23 + }, + { + "x": 47, + "y": 23 + }, + { + "x": 55, + "y": 23 + }, + { + "x": 63, + "y": 23 + }, + { + "x": 71, + "y": 23 + }, + { + "x": 76, + "y": 23 + }, + { + "x": 77, + "y": 23 + }, + { + "x": 7, + "y": 24 + }, + { + "x": 15, + "y": 24 + }, + { + "x": 23, + "y": 24 + }, + { + "x": 31, + "y": 24 + }, + { + "x": 39, + "y": 24 + }, + { + "x": 47, + "y": 24 + }, + { + "x": 55, + "y": 24 + }, + { + "x": 63, + "y": 24 + }, + { + "x": 71, + "y": 24 + }, + { + "x": 76, + "y": 24 + }, + { + "x": 77, + "y": 24 + }, + { + "x": 7, + "y": 25 + }, + { + "x": 15, + "y": 25 + }, + { + "x": 23, + "y": 25 + }, + { + "x": 31, + "y": 25 + }, + { + "x": 39, + "y": 25 + }, + { + "x": 47, + "y": 25 + }, + { + "x": 55, + "y": 25 + }, + { + "x": 63, + "y": 25 + }, + { + "x": 71, + "y": 25 + }, + { + "x": 76, + "y": 25 + }, + { + "x": 77, + "y": 25 + }, + { + "x": 7, + "y": 26 + }, + { + "x": 15, + "y": 26 + }, + { + "x": 23, + "y": 26 + }, + { + "x": 31, + "y": 26 + }, + { + "x": 39, + "y": 26 + }, + { + "x": 47, + "y": 26 + }, + { + "x": 55, + "y": 26 + }, + { + "x": 63, + "y": 26 + }, + { + "x": 71, + "y": 26 + }, + { + "x": 76, + "y": 26 + }, + { + "x": 77, + "y": 26 + }, + { + "x": 7, + "y": 27 + }, + { + "x": 15, + "y": 27 + }, + { + "x": 23, + "y": 27 + }, + { + "x": 31, + "y": 27 + }, + { + "x": 39, + "y": 27 + }, + { + "x": 47, + "y": 27 + }, + { + "x": 55, + "y": 27 + }, + { + "x": 63, + "y": 27 + }, + { + "x": 71, + "y": 27 + }, + { + "x": 76, + "y": 27 + }, + { + "x": 77, + "y": 27 + }, + { + "x": 76, + "y": 28 + }, + { + "x": 77, + "y": 28 + }, + { + "x": 76, + "y": 29 + }, + { + "x": 77, + "y": 29 + }, + { + "x": 76, + "y": 30 + }, + { + "x": 77, + "y": 30 + }, + { + "x": 76, + "y": 31 + }, + { + "x": 77, + "y": 31 + }, + { + "x": 0, + "y": 49 + }, + { + "x": 1, + "y": 49 + }, + { + "x": 2, + "y": 49 + }, + { + "x": 3, + "y": 49 + }, + { + "x": 4, + "y": 49 + }, + { + "x": 5, + "y": 49 + }, + { + "x": 6, + "y": 49 + }, + { + "x": 7, + "y": 49 + }, + { + "x": 8, + "y": 49 + }, + { + "x": 9, + "y": 49 + }, + { + "x": 10, + "y": 49 + }, + { + "x": 11, + "y": 49 + }, + { + "x": 12, + "y": 49 + }, + { + "x": 13, + "y": 49 + }, + { + "x": 14, + "y": 49 + }, + { + "x": 15, + "y": 49 + }, + { + "x": 16, + "y": 49 + }, + { + "x": 17, + "y": 49 + }, + { + "x": 18, + "y": 49 + }, + { + "x": 19, + "y": 49 + }, + { + "x": 20, + "y": 49 + }, + { + "x": 21, + "y": 49 + }, + { + "x": 22, + "y": 49 + }, + { + "x": 23, + "y": 49 + }, + { + "x": 24, + "y": 49 + }, + { + "x": 25, + "y": 49 + }, + { + "x": 26, + "y": 49 + }, + { + "x": 27, + "y": 49 + }, + { + "x": 28, + "y": 49 + }, + { + "x": 29, + "y": 49 + }, + { + "x": 30, + "y": 49 + }, + { + "x": 31, + "y": 49 + }, + { + "x": 32, + "y": 49 + }, + { + "x": 33, + "y": 49 + }, + { + "x": 34, + "y": 49 + }, + { + "x": 35, + "y": 49 + }, + { + "x": 36, + "y": 49 + }, + { + "x": 37, + "y": 49 + }, + { + "x": 38, + "y": 49 + }, + { + "x": 39, + "y": 49 + }, + { + "x": 40, + "y": 49 + }, + { + "x": 41, + "y": 49 + }, + { + "x": 42, + "y": 49 + }, + { + "x": 43, + "y": 49 + }, + { + "x": 44, + "y": 49 + }, + { + "x": 45, + "y": 49 + }, + { + "x": 46, + "y": 49 + }, + { + "x": 47, + "y": 49 + }, + { + "x": 48, + "y": 49 + }, + { + "x": 49, + "y": 49 + }, + { + "x": 50, + "y": 49 + }, + { + "x": 51, + "y": 49 + }, + { + "x": 52, + "y": 49 + }, + { + "x": 53, + "y": 49 + }, + { + "x": 54, + "y": 49 + }, + { + "x": 55, + "y": 49 + }, + { + "x": 56, + "y": 49 + }, + { + "x": 57, + "y": 49 + }, + { + "x": 58, + "y": 49 + }, + { + "x": 59, + "y": 49 + }, + { + "x": 60, + "y": 49 + }, + { + "x": 61, + "y": 49 + }, + { + "x": 62, + "y": 49 + }, + { + "x": 63, + "y": 49 + }, + { + "x": 64, + "y": 49 + }, + { + "x": 65, + "y": 49 + }, + { + "x": 66, + "y": 49 + }, + { + "x": 67, + "y": 49 + }, + { + "x": 68, + "y": 49 + }, + { + "x": 69, + "y": 49 + }, + { + "x": 70, + "y": 49 + }, + { + "x": 71, + "y": 49 + }, + { + "x": 72, + "y": 49 + }, + { + "x": 73, + "y": 49 + }, + { + "x": 74, + "y": 49 + }, + { + "x": 75, + "y": 49 + }, + { + "x": 76, + "y": 49 + }, + { + "x": 77, + "y": 49 + } + ] +} \ No newline at end of file diff --git a/algo-zkd/path_mapping.json b/algo-zkd/path_mapping.json new file mode 100644 index 0000000..bbb94bc --- /dev/null +++ b/algo-zkd/path_mapping.json @@ -0,0 +1,11880 @@ +{ + "path_id_to_coordinates": { + "338": [ + { + "x": 17, + "y": 0 + } + ], + "346": [ + { + "x": 18, + "y": 0 + } + ], + "393": [ + { + "x": 19, + "y": 0 + } + ], + "401": [ + { + "x": 20, + "y": 0 + } + ], + "448": [ + { + "x": 21, + "y": 0 + } + ], + "456": [ + { + "x": 22, + "y": 0 + } + ], + "482": [ + { + "x": 23, + "y": 0 + } + ], + "490": [ + { + "x": 24, + "y": 0 + } + ], + "537": [ + { + "x": 25, + "y": 0 + } + ], + "544": [ + { + "x": 26, + "y": 0 + } + ], + "592": [ + { + "x": 27, + "y": 0 + } + ], + "599": [ + { + "x": 28, + "y": 0 + } + ], + "647": [ + { + "x": 29, + "y": 0 + } + ], + "654": [ + { + "x": 30, + "y": 0 + } + ], + "679": [ + { + "x": 31, + "y": 0 + } + ], + "686": [ + { + "x": 32, + "y": 0 + } + ], + "733": [ + { + "x": 33, + "y": 0 + } + ], + "741": [ + { + "x": 34, + "y": 0 + } + ], + "788": [ + { + "x": 35, + "y": 0 + } + ], + "796": [ + { + "x": 36, + "y": 0 + } + ], + "843": [ + { + "x": 37, + "y": 0 + } + ], + "851": [ + { + "x": 38, + "y": 0 + } + ], + "877": [ + { + "x": 39, + "y": 0 + } + ], + "885": [ + { + "x": 40, + "y": 0 + } + ], + "932": [ + { + "x": 41, + "y": 0 + } + ], + "939": [ + { + "x": 42, + "y": 0 + } + ], + "987": [ + { + "x": 43, + "y": 0 + } + ], + "994": [ + { + "x": 44, + "y": 0 + } + ], + "1042": [ + { + "x": 45, + "y": 0 + } + ], + "1049": [ + { + "x": 46, + "y": 0 + } + ], + "1074": [ + { + "x": 47, + "y": 0 + } + ], + "1081": [ + { + "x": 48, + "y": 0 + } + ], + "1128": [ + { + "x": 49, + "y": 0 + } + ], + "1136": [ + { + "x": 50, + "y": 0 + } + ], + "1183": [ + { + "x": 51, + "y": 0 + } + ], + "1191": [ + { + "x": 52, + "y": 0 + } + ], + "1238": [ + { + "x": 53, + "y": 0 + } + ], + "1246": [ + { + "x": 54, + "y": 0 + } + ], + "1272": [ + { + "x": 55, + "y": 0 + } + ], + "1280": [ + { + "x": 56, + "y": 0 + } + ], + "1327": [ + { + "x": 57, + "y": 0 + } + ], + "1334": [ + { + "x": 58, + "y": 0 + } + ], + "1382": [ + { + "x": 59, + "y": 0 + } + ], + "1389": [ + { + "x": 60, + "y": 0 + } + ], + "1437": [ + { + "x": 61, + "y": 0 + } + ], + "337": [ + { + "x": 17, + "y": 1 + } + ], + "392": [ + { + "x": 19, + "y": 1 + } + ], + "447": [ + { + "x": 21, + "y": 1 + } + ], + "536": [ + { + "x": 25, + "y": 1 + } + ], + "591": [ + { + "x": 27, + "y": 1 + } + ], + "646": [ + { + "x": 29, + "y": 1 + } + ], + "732": [ + { + "x": 33, + "y": 1 + } + ], + "787": [ + { + "x": 35, + "y": 1 + } + ], + "842": [ + { + "x": 37, + "y": 1 + } + ], + "931": [ + { + "x": 41, + "y": 1 + } + ], + "986": [ + { + "x": 43, + "y": 1 + } + ], + "1041": [ + { + "x": 45, + "y": 1 + } + ], + "1127": [ + { + "x": 49, + "y": 1 + } + ], + "1182": [ + { + "x": 51, + "y": 1 + } + ], + "1237": [ + { + "x": 53, + "y": 1 + } + ], + "1326": [ + { + "x": 57, + "y": 1 + } + ], + "1381": [ + { + "x": 59, + "y": 1 + } + ], + "1436": [ + { + "x": 61, + "y": 1 + } + ], + "336": [ + { + "x": 17, + "y": 2 + } + ], + "391": [ + { + "x": 19, + "y": 2 + } + ], + "446": [ + { + "x": 21, + "y": 2 + } + ], + "481": [ + { + "x": 23, + "y": 2 + } + ], + "535": [ + { + "x": 25, + "y": 2 + } + ], + "590": [ + { + "x": 27, + "y": 2 + } + ], + "645": [ + { + "x": 29, + "y": 2 + } + ], + "678": [ + { + "x": 31, + "y": 2 + } + ], + "731": [ + { + "x": 33, + "y": 2 + } + ], + "786": [ + { + "x": 35, + "y": 2 + } + ], + "841": [ + { + "x": 37, + "y": 2 + } + ], + "876": [ + { + "x": 39, + "y": 2 + } + ], + "930": [ + { + "x": 41, + "y": 2 + } + ], + "985": [ + { + "x": 43, + "y": 2 + } + ], + "1040": [ + { + "x": 45, + "y": 2 + } + ], + "1073": [ + { + "x": 47, + "y": 2 + } + ], + "1126": [ + { + "x": 49, + "y": 2 + } + ], + "1181": [ + { + "x": 51, + "y": 2 + } + ], + "1236": [ + { + "x": 53, + "y": 2 + } + ], + "1271": [ + { + "x": 55, + "y": 2 + } + ], + "1325": [ + { + "x": 57, + "y": 2 + } + ], + "1380": [ + { + "x": 59, + "y": 2 + } + ], + "1435": [ + { + "x": 61, + "y": 2 + } + ], + "335": [ + { + "x": 17, + "y": 3 + } + ], + "390": [ + { + "x": 19, + "y": 3 + } + ], + "445": [ + { + "x": 21, + "y": 3 + } + ], + "480": [ + { + "x": 23, + "y": 3 + } + ], + "534": [ + { + "x": 25, + "y": 3 + } + ], + "589": [ + { + "x": 27, + "y": 3 + } + ], + "644": [ + { + "x": 29, + "y": 3 + } + ], + "677": [ + { + "x": 31, + "y": 3 + } + ], + "730": [ + { + "x": 33, + "y": 3 + } + ], + "785": [ + { + "x": 35, + "y": 3 + } + ], + "840": [ + { + "x": 37, + "y": 3 + } + ], + "875": [ + { + "x": 39, + "y": 3 + } + ], + "929": [ + { + "x": 41, + "y": 3 + } + ], + "984": [ + { + "x": 43, + "y": 3 + } + ], + "1039": [ + { + "x": 45, + "y": 3 + } + ], + "1072": [ + { + "x": 47, + "y": 3 + } + ], + "1125": [ + { + "x": 49, + "y": 3 + } + ], + "1180": [ + { + "x": 51, + "y": 3 + } + ], + "1235": [ + { + "x": 53, + "y": 3 + } + ], + "1270": [ + { + "x": 55, + "y": 3 + } + ], + "1324": [ + { + "x": 57, + "y": 3 + } + ], + "1379": [ + { + "x": 59, + "y": 3 + } + ], + "1434": [ + { + "x": 61, + "y": 3 + } + ], + "334": [ + { + "x": 17, + "y": 4 + } + ], + "389": [ + { + "x": 19, + "y": 4 + } + ], + "444": [ + { + "x": 21, + "y": 4 + } + ], + "479": [ + { + "x": 23, + "y": 4 + } + ], + "533": [ + { + "x": 25, + "y": 4 + } + ], + "588": [ + { + "x": 27, + "y": 4 + } + ], + "643": [ + { + "x": 29, + "y": 4 + } + ], + "676": [ + { + "x": 31, + "y": 4 + } + ], + "729": [ + { + "x": 33, + "y": 4 + } + ], + "784": [ + { + "x": 35, + "y": 4 + } + ], + "839": [ + { + "x": 37, + "y": 4 + } + ], + "874": [ + { + "x": 39, + "y": 4 + } + ], + "928": [ + { + "x": 41, + "y": 4 + } + ], + "983": [ + { + "x": 43, + "y": 4 + } + ], + "1038": [ + { + "x": 45, + "y": 4 + } + ], + "1071": [ + { + "x": 47, + "y": 4 + } + ], + "1124": [ + { + "x": 49, + "y": 4 + } + ], + "1179": [ + { + "x": 51, + "y": 4 + } + ], + "1234": [ + { + "x": 53, + "y": 4 + } + ], + "1269": [ + { + "x": 55, + "y": 4 + } + ], + "1323": [ + { + "x": 57, + "y": 4 + } + ], + "1378": [ + { + "x": 59, + "y": 4 + } + ], + "1433": [ + { + "x": 61, + "y": 4 + } + ], + "333": [ + { + "x": 17, + "y": 5 + } + ], + "388": [ + { + "x": 19, + "y": 5 + } + ], + "443": [ + { + "x": 21, + "y": 5 + } + ], + "532": [ + { + "x": 25, + "y": 5 + } + ], + "587": [ + { + "x": 27, + "y": 5 + } + ], + "642": [ + { + "x": 29, + "y": 5 + } + ], + "728": [ + { + "x": 33, + "y": 5 + } + ], + "783": [ + { + "x": 35, + "y": 5 + } + ], + "838": [ + { + "x": 37, + "y": 5 + } + ], + "927": [ + { + "x": 41, + "y": 5 + } + ], + "982": [ + { + "x": 43, + "y": 5 + } + ], + "1037": [ + { + "x": 45, + "y": 5 + } + ], + "1123": [ + { + "x": 49, + "y": 5 + } + ], + "1178": [ + { + "x": 51, + "y": 5 + } + ], + "1233": [ + { + "x": 53, + "y": 5 + } + ], + "1322": [ + { + "x": 57, + "y": 5 + } + ], + "1377": [ + { + "x": 59, + "y": 5 + } + ], + "1432": [ + { + "x": 61, + "y": 5 + } + ], + "332": [ + { + "x": 17, + "y": 6 + } + ], + "345": [ + { + "x": 18, + "y": 6 + } + ], + "387": [ + { + "x": 19, + "y": 6 + } + ], + "400": [ + { + "x": 20, + "y": 6 + } + ], + "442": [ + { + "x": 21, + "y": 6 + } + ], + "455": [ + { + "x": 22, + "y": 6 + } + ], + "478": [ + { + "x": 23, + "y": 6 + } + ], + "489": [ + { + "x": 24, + "y": 6 + } + ], + "531": [ + { + "x": 25, + "y": 6 + } + ], + "543": [ + { + "x": 26, + "y": 6 + } + ], + "586": [ + { + "x": 27, + "y": 6 + } + ], + "598": [ + { + "x": 28, + "y": 6 + } + ], + "641": [ + { + "x": 29, + "y": 6 + } + ], + "653": [ + { + "x": 30, + "y": 6 + } + ], + "675": [ + { + "x": 31, + "y": 6 + } + ], + "685": [ + { + "x": 32, + "y": 6 + } + ], + "727": [ + { + "x": 33, + "y": 6 + } + ], + "740": [ + { + "x": 34, + "y": 6 + } + ], + "782": [ + { + "x": 35, + "y": 6 + } + ], + "795": [ + { + "x": 36, + "y": 6 + } + ], + "837": [ + { + "x": 37, + "y": 6 + } + ], + "850": [ + { + "x": 38, + "y": 6 + } + ], + "873": [ + { + "x": 39, + "y": 6 + } + ], + "884": [ + { + "x": 40, + "y": 6 + } + ], + "926": [ + { + "x": 41, + "y": 6 + } + ], + "938": [ + { + "x": 42, + "y": 6 + } + ], + "981": [ + { + "x": 43, + "y": 6 + } + ], + "993": [ + { + "x": 44, + "y": 6 + } + ], + "1036": [ + { + "x": 45, + "y": 6 + } + ], + "1048": [ + { + "x": 46, + "y": 6 + } + ], + "1070": [ + { + "x": 47, + "y": 6 + } + ], + "1080": [ + { + "x": 48, + "y": 6 + } + ], + "1122": [ + { + "x": 49, + "y": 6 + } + ], + "1135": [ + { + "x": 50, + "y": 6 + } + ], + "1177": [ + { + "x": 51, + "y": 6 + } + ], + "1190": [ + { + "x": 52, + "y": 6 + } + ], + "1232": [ + { + "x": 53, + "y": 6 + } + ], + "1245": [ + { + "x": 54, + "y": 6 + } + ], + "1268": [ + { + "x": 55, + "y": 6 + } + ], + "1279": [ + { + "x": 56, + "y": 6 + } + ], + "1321": [ + { + "x": 57, + "y": 6 + } + ], + "1333": [ + { + "x": 58, + "y": 6 + } + ], + "1376": [ + { + "x": 59, + "y": 6 + } + ], + "1388": [ + { + "x": 60, + "y": 6 + } + ], + "1431": [ + { + "x": 61, + "y": 6 + } + ], + "331": [ + { + "x": 17, + "y": 7 + } + ], + "386": [ + { + "x": 19, + "y": 7 + } + ], + "441": [ + { + "x": 21, + "y": 7 + } + ], + "530": [ + { + "x": 25, + "y": 7 + } + ], + "585": [ + { + "x": 27, + "y": 7 + } + ], + "640": [ + { + "x": 29, + "y": 7 + } + ], + "726": [ + { + "x": 33, + "y": 7 + } + ], + "781": [ + { + "x": 35, + "y": 7 + } + ], + "836": [ + { + "x": 37, + "y": 7 + } + ], + "925": [ + { + "x": 41, + "y": 7 + } + ], + "980": [ + { + "x": 43, + "y": 7 + } + ], + "1035": [ + { + "x": 45, + "y": 7 + } + ], + "1121": [ + { + "x": 49, + "y": 7 + } + ], + "1176": [ + { + "x": 51, + "y": 7 + } + ], + "1231": [ + { + "x": 53, + "y": 7 + } + ], + "1320": [ + { + "x": 57, + "y": 7 + } + ], + "1375": [ + { + "x": 59, + "y": 7 + } + ], + "1430": [ + { + "x": 61, + "y": 7 + } + ], + "330": [ + { + "x": 17, + "y": 8 + } + ], + "385": [ + { + "x": 19, + "y": 8 + } + ], + "440": [ + { + "x": 21, + "y": 8 + } + ], + "477": [ + { + "x": 23, + "y": 8 + } + ], + "529": [ + { + "x": 25, + "y": 8 + } + ], + "584": [ + { + "x": 27, + "y": 8 + } + ], + "639": [ + { + "x": 29, + "y": 8 + } + ], + "674": [ + { + "x": 31, + "y": 8 + } + ], + "725": [ + { + "x": 33, + "y": 8 + } + ], + "780": [ + { + "x": 35, + "y": 8 + } + ], + "835": [ + { + "x": 37, + "y": 8 + } + ], + "872": [ + { + "x": 39, + "y": 8 + } + ], + "924": [ + { + "x": 41, + "y": 8 + } + ], + "979": [ + { + "x": 43, + "y": 8 + } + ], + "1034": [ + { + "x": 45, + "y": 8 + } + ], + "1069": [ + { + "x": 47, + "y": 8 + } + ], + "1120": [ + { + "x": 49, + "y": 8 + } + ], + "1175": [ + { + "x": 51, + "y": 8 + } + ], + "1230": [ + { + "x": 53, + "y": 8 + } + ], + "1267": [ + { + "x": 55, + "y": 8 + } + ], + "1319": [ + { + "x": 57, + "y": 8 + } + ], + "1374": [ + { + "x": 59, + "y": 8 + } + ], + "1429": [ + { + "x": 61, + "y": 8 + } + ], + "329": [ + { + "x": 17, + "y": 9 + } + ], + "384": [ + { + "x": 19, + "y": 9 + } + ], + "439": [ + { + "x": 21, + "y": 9 + } + ], + "476": [ + { + "x": 23, + "y": 9 + } + ], + "528": [ + { + "x": 25, + "y": 9 + } + ], + "583": [ + { + "x": 27, + "y": 9 + } + ], + "638": [ + { + "x": 29, + "y": 9 + } + ], + "673": [ + { + "x": 31, + "y": 9 + } + ], + "724": [ + { + "x": 33, + "y": 9 + } + ], + "779": [ + { + "x": 35, + "y": 9 + } + ], + "834": [ + { + "x": 37, + "y": 9 + } + ], + "871": [ + { + "x": 39, + "y": 9 + } + ], + "923": [ + { + "x": 41, + "y": 9 + } + ], + "978": [ + { + "x": 43, + "y": 9 + } + ], + "1033": [ + { + "x": 45, + "y": 9 + } + ], + "1068": [ + { + "x": 47, + "y": 9 + } + ], + "1119": [ + { + "x": 49, + "y": 9 + } + ], + "1174": [ + { + "x": 51, + "y": 9 + } + ], + "1229": [ + { + "x": 53, + "y": 9 + } + ], + "1266": [ + { + "x": 55, + "y": 9 + } + ], + "1318": [ + { + "x": 57, + "y": 9 + } + ], + "1373": [ + { + "x": 59, + "y": 9 + } + ], + "1428": [ + { + "x": 61, + "y": 9 + } + ], + "328": [ + { + "x": 17, + "y": 10 + } + ], + "383": [ + { + "x": 19, + "y": 10 + } + ], + "438": [ + { + "x": 21, + "y": 10 + } + ], + "475": [ + { + "x": 23, + "y": 10 + } + ], + "527": [ + { + "x": 25, + "y": 10 + } + ], + "582": [ + { + "x": 27, + "y": 10 + } + ], + "637": [ + { + "x": 29, + "y": 10 + } + ], + "672": [ + { + "x": 31, + "y": 10 + } + ], + "723": [ + { + "x": 33, + "y": 10 + } + ], + "778": [ + { + "x": 35, + "y": 10 + } + ], + "833": [ + { + "x": 37, + "y": 10 + } + ], + "870": [ + { + "x": 39, + "y": 10 + } + ], + "922": [ + { + "x": 41, + "y": 10 + } + ], + "977": [ + { + "x": 43, + "y": 10 + } + ], + "1032": [ + { + "x": 45, + "y": 10 + } + ], + "1067": [ + { + "x": 47, + "y": 10 + } + ], + "1118": [ + { + "x": 49, + "y": 10 + } + ], + "1173": [ + { + "x": 51, + "y": 10 + } + ], + "1228": [ + { + "x": 53, + "y": 10 + } + ], + "1265": [ + { + "x": 55, + "y": 10 + } + ], + "1317": [ + { + "x": 57, + "y": 10 + } + ], + "1372": [ + { + "x": 59, + "y": 10 + } + ], + "1427": [ + { + "x": 61, + "y": 10 + } + ], + "327": [ + { + "x": 17, + "y": 11 + } + ], + "382": [ + { + "x": 19, + "y": 11 + } + ], + "437": [ + { + "x": 21, + "y": 11 + } + ], + "526": [ + { + "x": 25, + "y": 11 + } + ], + "581": [ + { + "x": 27, + "y": 11 + } + ], + "636": [ + { + "x": 29, + "y": 11 + } + ], + "722": [ + { + "x": 33, + "y": 11 + } + ], + "777": [ + { + "x": 35, + "y": 11 + } + ], + "832": [ + { + "x": 37, + "y": 11 + } + ], + "921": [ + { + "x": 41, + "y": 11 + } + ], + "976": [ + { + "x": 43, + "y": 11 + } + ], + "1031": [ + { + "x": 45, + "y": 11 + } + ], + "1117": [ + { + "x": 49, + "y": 11 + } + ], + "1172": [ + { + "x": 51, + "y": 11 + } + ], + "1227": [ + { + "x": 53, + "y": 11 + } + ], + "1316": [ + { + "x": 57, + "y": 11 + } + ], + "1371": [ + { + "x": 59, + "y": 11 + } + ], + "1426": [ + { + "x": 61, + "y": 11 + } + ], + "35": [ + { + "x": 1, + "y": 12 + } + ], + "41": [ + { + "x": 2, + "y": 12 + } + ], + "76": [ + { + "x": 3, + "y": 12 + } + ], + "82": [ + { + "x": 4, + "y": 12 + } + ], + "117": [ + { + "x": 5, + "y": 12 + } + ], + "123": [ + { + "x": 6, + "y": 12 + } + ], + "141": [ + { + "x": 7, + "y": 12 + } + ], + "147": [ + { + "x": 8, + "y": 12 + } + ], + "182": [ + { + "x": 9, + "y": 12 + } + ], + "187": [ + { + "x": 10, + "y": 12 + } + ], + "223": [ + { + "x": 11, + "y": 12 + } + ], + "228": [ + { + "x": 12, + "y": 12 + } + ], + "264": [ + { + "x": 13, + "y": 12 + } + ], + "269": [ + { + "x": 14, + "y": 12 + } + ], + "286": [ + { + "x": 15, + "y": 12 + } + ], + "291": [ + { + "x": 16, + "y": 12 + } + ], + "326": [ + { + "x": 17, + "y": 12 + } + ], + "344": [ + { + "x": 18, + "y": 12 + } + ], + "381": [ + { + "x": 19, + "y": 12 + } + ], + "399": [ + { + "x": 20, + "y": 12 + } + ], + "436": [ + { + "x": 21, + "y": 12 + } + ], + "454": [ + { + "x": 22, + "y": 12 + } + ], + "474": [ + { + "x": 23, + "y": 12 + } + ], + "488": [ + { + "x": 24, + "y": 12 + } + ], + "525": [ + { + "x": 25, + "y": 12 + } + ], + "542": [ + { + "x": 26, + "y": 12 + } + ], + "580": [ + { + "x": 27, + "y": 12 + } + ], + "597": [ + { + "x": 28, + "y": 12 + } + ], + "635": [ + { + "x": 29, + "y": 12 + } + ], + "652": [ + { + "x": 30, + "y": 12 + } + ], + "671": [ + { + "x": 31, + "y": 12 + } + ], + "684": [ + { + "x": 32, + "y": 12 + } + ], + "721": [ + { + "x": 33, + "y": 12 + } + ], + "739": [ + { + "x": 34, + "y": 12 + } + ], + "776": [ + { + "x": 35, + "y": 12 + } + ], + "794": [ + { + "x": 36, + "y": 12 + } + ], + "831": [ + { + "x": 37, + "y": 12 + } + ], + "849": [ + { + "x": 38, + "y": 12 + } + ], + "869": [ + { + "x": 39, + "y": 12 + } + ], + "883": [ + { + "x": 40, + "y": 12 + } + ], + "920": [ + { + "x": 41, + "y": 12 + } + ], + "937": [ + { + "x": 42, + "y": 12 + } + ], + "975": [ + { + "x": 43, + "y": 12 + } + ], + "992": [ + { + "x": 44, + "y": 12 + } + ], + "1030": [ + { + "x": 45, + "y": 12 + } + ], + "1047": [ + { + "x": 46, + "y": 12 + } + ], + "1066": [ + { + "x": 47, + "y": 12 + } + ], + "1079": [ + { + "x": 48, + "y": 12 + } + ], + "1116": [ + { + "x": 49, + "y": 12 + } + ], + "1134": [ + { + "x": 50, + "y": 12 + } + ], + "1171": [ + { + "x": 51, + "y": 12 + } + ], + "1189": [ + { + "x": 52, + "y": 12 + } + ], + "1226": [ + { + "x": 53, + "y": 12 + } + ], + "1244": [ + { + "x": 54, + "y": 12 + } + ], + "1264": [ + { + "x": 55, + "y": 12 + } + ], + "1278": [ + { + "x": 56, + "y": 12 + } + ], + "1315": [ + { + "x": 57, + "y": 12 + } + ], + "1332": [ + { + "x": 58, + "y": 12 + } + ], + "1370": [ + { + "x": 59, + "y": 12 + } + ], + "1387": [ + { + "x": 60, + "y": 12 + } + ], + "1425": [ + { + "x": 61, + "y": 12 + } + ], + "1442": [ + { + "x": 62, + "y": 12 + } + ], + "1459": [ + { + "x": 63, + "y": 12 + } + ], + "1464": [ + { + "x": 64, + "y": 12 + } + ], + "1499": [ + { + "x": 65, + "y": 12 + } + ], + "1505": [ + { + "x": 66, + "y": 12 + } + ], + "1540": [ + { + "x": 67, + "y": 12 + } + ], + "1546": [ + { + "x": 68, + "y": 12 + } + ], + "1581": [ + { + "x": 69, + "y": 12 + } + ], + "1587": [ + { + "x": 70, + "y": 12 + } + ], + "1605": [ + { + "x": 71, + "y": 12 + } + ], + "1611": [ + { + "x": 72, + "y": 12 + } + ], + "1646": [ + { + "x": 73, + "y": 12 + } + ], + "1651": [ + { + "x": 74, + "y": 12 + } + ], + "1687": [ + { + "x": 75, + "y": 12 + } + ], + "34": [ + { + "x": 1, + "y": 13 + } + ], + "75": [ + { + "x": 3, + "y": 13 + } + ], + "116": [ + { + "x": 5, + "y": 13 + } + ], + "181": [ + { + "x": 9, + "y": 13 + } + ], + "222": [ + { + "x": 11, + "y": 13 + } + ], + "263": [ + { + "x": 13, + "y": 13 + } + ], + "325": [ + { + "x": 17, + "y": 13 + } + ], + "380": [ + { + "x": 19, + "y": 13 + } + ], + "435": [ + { + "x": 21, + "y": 13 + } + ], + "524": [ + { + "x": 25, + "y": 13 + } + ], + "579": [ + { + "x": 27, + "y": 13 + } + ], + "634": [ + { + "x": 29, + "y": 13 + } + ], + "720": [ + { + "x": 33, + "y": 13 + } + ], + "775": [ + { + "x": 35, + "y": 13 + } + ], + "830": [ + { + "x": 37, + "y": 13 + } + ], + "919": [ + { + "x": 41, + "y": 13 + } + ], + "974": [ + { + "x": 43, + "y": 13 + } + ], + "1029": [ + { + "x": 45, + "y": 13 + } + ], + "1115": [ + { + "x": 49, + "y": 13 + } + ], + "1170": [ + { + "x": 51, + "y": 13 + } + ], + "1225": [ + { + "x": 53, + "y": 13 + } + ], + "1314": [ + { + "x": 57, + "y": 13 + } + ], + "1369": [ + { + "x": 59, + "y": 13 + } + ], + "1424": [ + { + "x": 61, + "y": 13 + } + ], + "1498": [ + { + "x": 65, + "y": 13 + } + ], + "1539": [ + { + "x": 67, + "y": 13 + } + ], + "1580": [ + { + "x": 69, + "y": 13 + } + ], + "1645": [ + { + "x": 73, + "y": 13 + } + ], + "1686": [ + { + "x": 75, + "y": 13 + } + ], + "33": [ + { + "x": 1, + "y": 14 + } + ], + "74": [ + { + "x": 3, + "y": 14 + } + ], + "115": [ + { + "x": 5, + "y": 14 + } + ], + "140": [ + { + "x": 7, + "y": 14 + } + ], + "180": [ + { + "x": 9, + "y": 14 + } + ], + "221": [ + { + "x": 11, + "y": 14 + } + ], + "262": [ + { + "x": 13, + "y": 14 + } + ], + "285": [ + { + "x": 15, + "y": 14 + } + ], + "324": [ + { + "x": 17, + "y": 14 + } + ], + "379": [ + { + "x": 19, + "y": 14 + } + ], + "434": [ + { + "x": 21, + "y": 14 + } + ], + "473": [ + { + "x": 23, + "y": 14 + } + ], + "523": [ + { + "x": 25, + "y": 14 + } + ], + "578": [ + { + "x": 27, + "y": 14 + } + ], + "633": [ + { + "x": 29, + "y": 14 + } + ], + "670": [ + { + "x": 31, + "y": 14 + } + ], + "719": [ + { + "x": 33, + "y": 14 + } + ], + "774": [ + { + "x": 35, + "y": 14 + } + ], + "829": [ + { + "x": 37, + "y": 14 + } + ], + "868": [ + { + "x": 39, + "y": 14 + } + ], + "918": [ + { + "x": 41, + "y": 14 + } + ], + "973": [ + { + "x": 43, + "y": 14 + } + ], + "1028": [ + { + "x": 45, + "y": 14 + } + ], + "1065": [ + { + "x": 47, + "y": 14 + } + ], + "1114": [ + { + "x": 49, + "y": 14 + } + ], + "1169": [ + { + "x": 51, + "y": 14 + } + ], + "1224": [ + { + "x": 53, + "y": 14 + } + ], + "1263": [ + { + "x": 55, + "y": 14 + } + ], + "1313": [ + { + "x": 57, + "y": 14 + } + ], + "1368": [ + { + "x": 59, + "y": 14 + } + ], + "1423": [ + { + "x": 61, + "y": 14 + } + ], + "1458": [ + { + "x": 63, + "y": 14 + } + ], + "1497": [ + { + "x": 65, + "y": 14 + } + ], + "1538": [ + { + "x": 67, + "y": 14 + } + ], + "1579": [ + { + "x": 69, + "y": 14 + } + ], + "1604": [ + { + "x": 71, + "y": 14 + } + ], + "1644": [ + { + "x": 73, + "y": 14 + } + ], + "1685": [ + { + "x": 75, + "y": 14 + } + ], + "32": [ + { + "x": 1, + "y": 15 + } + ], + "73": [ + { + "x": 3, + "y": 15 + } + ], + "114": [ + { + "x": 5, + "y": 15 + } + ], + "179": [ + { + "x": 9, + "y": 15 + } + ], + "220": [ + { + "x": 11, + "y": 15 + } + ], + "261": [ + { + "x": 13, + "y": 15 + } + ], + "323": [ + { + "x": 17, + "y": 15 + } + ], + "378": [ + { + "x": 19, + "y": 15 + } + ], + "433": [ + { + "x": 21, + "y": 15 + } + ], + "522": [ + { + "x": 25, + "y": 15 + } + ], + "577": [ + { + "x": 27, + "y": 15 + } + ], + "632": [ + { + "x": 29, + "y": 15 + } + ], + "718": [ + { + "x": 33, + "y": 15 + } + ], + "773": [ + { + "x": 35, + "y": 15 + } + ], + "828": [ + { + "x": 37, + "y": 15 + } + ], + "917": [ + { + "x": 41, + "y": 15 + } + ], + "972": [ + { + "x": 43, + "y": 15 + } + ], + "1027": [ + { + "x": 45, + "y": 15 + } + ], + "1113": [ + { + "x": 49, + "y": 15 + } + ], + "1168": [ + { + "x": 51, + "y": 15 + } + ], + "1223": [ + { + "x": 53, + "y": 15 + } + ], + "1312": [ + { + "x": 57, + "y": 15 + } + ], + "1367": [ + { + "x": 59, + "y": 15 + } + ], + "1422": [ + { + "x": 61, + "y": 15 + } + ], + "1496": [ + { + "x": 65, + "y": 15 + } + ], + "1537": [ + { + "x": 67, + "y": 15 + } + ], + "1578": [ + { + "x": 69, + "y": 15 + } + ], + "1643": [ + { + "x": 73, + "y": 15 + } + ], + "1684": [ + { + "x": 75, + "y": 15 + } + ], + "31": [ + { + "x": 1, + "y": 16 + } + ], + "72": [ + { + "x": 3, + "y": 16 + } + ], + "113": [ + { + "x": 5, + "y": 16 + } + ], + "139": [ + { + "x": 7, + "y": 16 + } + ], + "178": [ + { + "x": 9, + "y": 16 + } + ], + "219": [ + { + "x": 11, + "y": 16 + } + ], + "260": [ + { + "x": 13, + "y": 16 + } + ], + "284": [ + { + "x": 15, + "y": 16 + } + ], + "322": [ + { + "x": 17, + "y": 16 + } + ], + "377": [ + { + "x": 19, + "y": 16 + } + ], + "432": [ + { + "x": 21, + "y": 16 + } + ], + "472": [ + { + "x": 23, + "y": 16 + } + ], + "521": [ + { + "x": 25, + "y": 16 + } + ], + "576": [ + { + "x": 27, + "y": 16 + } + ], + "631": [ + { + "x": 29, + "y": 16 + } + ], + "669": [ + { + "x": 31, + "y": 16 + } + ], + "717": [ + { + "x": 33, + "y": 16 + } + ], + "772": [ + { + "x": 35, + "y": 16 + } + ], + "827": [ + { + "x": 37, + "y": 16 + } + ], + "867": [ + { + "x": 39, + "y": 16 + } + ], + "916": [ + { + "x": 41, + "y": 16 + } + ], + "971": [ + { + "x": 43, + "y": 16 + } + ], + "1026": [ + { + "x": 45, + "y": 16 + } + ], + "1064": [ + { + "x": 47, + "y": 16 + } + ], + "1112": [ + { + "x": 49, + "y": 16 + } + ], + "1167": [ + { + "x": 51, + "y": 16 + } + ], + "1222": [ + { + "x": 53, + "y": 16 + } + ], + "1262": [ + { + "x": 55, + "y": 16 + } + ], + "1311": [ + { + "x": 57, + "y": 16 + } + ], + "1366": [ + { + "x": 59, + "y": 16 + } + ], + "1421": [ + { + "x": 61, + "y": 16 + } + ], + "1457": [ + { + "x": 63, + "y": 16 + } + ], + "1495": [ + { + "x": 65, + "y": 16 + } + ], + "1536": [ + { + "x": 67, + "y": 16 + } + ], + "1577": [ + { + "x": 69, + "y": 16 + } + ], + "1603": [ + { + "x": 71, + "y": 16 + } + ], + "1642": [ + { + "x": 73, + "y": 16 + } + ], + "1683": [ + { + "x": 75, + "y": 16 + } + ], + "30": [ + { + "x": 1, + "y": 17 + } + ], + "71": [ + { + "x": 3, + "y": 17 + } + ], + "112": [ + { + "x": 5, + "y": 17 + } + ], + "138": [ + { + "x": 7, + "y": 17 + } + ], + "177": [ + { + "x": 9, + "y": 17 + } + ], + "218": [ + { + "x": 11, + "y": 17 + } + ], + "259": [ + { + "x": 13, + "y": 17 + } + ], + "283": [ + { + "x": 15, + "y": 17 + } + ], + "321": [ + { + "x": 17, + "y": 17 + } + ], + "376": [ + { + "x": 19, + "y": 17 + } + ], + "431": [ + { + "x": 21, + "y": 17 + } + ], + "471": [ + { + "x": 23, + "y": 17 + } + ], + "520": [ + { + "x": 25, + "y": 17 + } + ], + "575": [ + { + "x": 27, + "y": 17 + } + ], + "630": [ + { + "x": 29, + "y": 17 + } + ], + "668": [ + { + "x": 31, + "y": 17 + } + ], + "716": [ + { + "x": 33, + "y": 17 + } + ], + "771": [ + { + "x": 35, + "y": 17 + } + ], + "826": [ + { + "x": 37, + "y": 17 + } + ], + "866": [ + { + "x": 39, + "y": 17 + } + ], + "915": [ + { + "x": 41, + "y": 17 + } + ], + "970": [ + { + "x": 43, + "y": 17 + } + ], + "1025": [ + { + "x": 45, + "y": 17 + } + ], + "1063": [ + { + "x": 47, + "y": 17 + } + ], + "1111": [ + { + "x": 49, + "y": 17 + } + ], + "1166": [ + { + "x": 51, + "y": 17 + } + ], + "1221": [ + { + "x": 53, + "y": 17 + } + ], + "1261": [ + { + "x": 55, + "y": 17 + } + ], + "1310": [ + { + "x": 57, + "y": 17 + } + ], + "1365": [ + { + "x": 59, + "y": 17 + } + ], + "1420": [ + { + "x": 61, + "y": 17 + } + ], + "1456": [ + { + "x": 63, + "y": 17 + } + ], + "1494": [ + { + "x": 65, + "y": 17 + } + ], + "1535": [ + { + "x": 67, + "y": 17 + } + ], + "1576": [ + { + "x": 69, + "y": 17 + } + ], + "1602": [ + { + "x": 71, + "y": 17 + } + ], + "1641": [ + { + "x": 73, + "y": 17 + } + ], + "1682": [ + { + "x": 75, + "y": 17 + } + ], + "29": [ + { + "x": 1, + "y": 18 + } + ], + "70": [ + { + "x": 3, + "y": 18 + } + ], + "111": [ + { + "x": 5, + "y": 18 + } + ], + "137": [ + { + "x": 7, + "y": 18 + } + ], + "176": [ + { + "x": 9, + "y": 18 + } + ], + "217": [ + { + "x": 11, + "y": 18 + } + ], + "258": [ + { + "x": 13, + "y": 18 + } + ], + "282": [ + { + "x": 15, + "y": 18 + } + ], + "320": [ + { + "x": 17, + "y": 18 + } + ], + "375": [ + { + "x": 19, + "y": 18 + } + ], + "430": [ + { + "x": 21, + "y": 18 + } + ], + "470": [ + { + "x": 23, + "y": 18 + } + ], + "519": [ + { + "x": 25, + "y": 18 + } + ], + "574": [ + { + "x": 27, + "y": 18 + } + ], + "629": [ + { + "x": 29, + "y": 18 + } + ], + "667": [ + { + "x": 31, + "y": 18 + } + ], + "715": [ + { + "x": 33, + "y": 18 + } + ], + "770": [ + { + "x": 35, + "y": 18 + } + ], + "825": [ + { + "x": 37, + "y": 18 + } + ], + "865": [ + { + "x": 39, + "y": 18 + } + ], + "914": [ + { + "x": 41, + "y": 18 + } + ], + "969": [ + { + "x": 43, + "y": 18 + } + ], + "1024": [ + { + "x": 45, + "y": 18 + } + ], + "1062": [ + { + "x": 47, + "y": 18 + } + ], + "1110": [ + { + "x": 49, + "y": 18 + } + ], + "1165": [ + { + "x": 51, + "y": 18 + } + ], + "1220": [ + { + "x": 53, + "y": 18 + } + ], + "1260": [ + { + "x": 55, + "y": 18 + } + ], + "1309": [ + { + "x": 57, + "y": 18 + } + ], + "1364": [ + { + "x": 59, + "y": 18 + } + ], + "1419": [ + { + "x": 61, + "y": 18 + } + ], + "1455": [ + { + "x": 63, + "y": 18 + } + ], + "1493": [ + { + "x": 65, + "y": 18 + } + ], + "1534": [ + { + "x": 67, + "y": 18 + } + ], + "1575": [ + { + "x": 69, + "y": 18 + } + ], + "1601": [ + { + "x": 71, + "y": 18 + } + ], + "1640": [ + { + "x": 73, + "y": 18 + } + ], + "1681": [ + { + "x": 75, + "y": 18 + } + ], + "28": [ + { + "x": 1, + "y": 19 + } + ], + "69": [ + { + "x": 3, + "y": 19 + } + ], + "110": [ + { + "x": 5, + "y": 19 + } + ], + "175": [ + { + "x": 9, + "y": 19 + } + ], + "216": [ + { + "x": 11, + "y": 19 + } + ], + "257": [ + { + "x": 13, + "y": 19 + } + ], + "319": [ + { + "x": 17, + "y": 19 + } + ], + "374": [ + { + "x": 19, + "y": 19 + } + ], + "429": [ + { + "x": 21, + "y": 19 + } + ], + "518": [ + { + "x": 25, + "y": 19 + } + ], + "573": [ + { + "x": 27, + "y": 19 + } + ], + "628": [ + { + "x": 29, + "y": 19 + } + ], + "714": [ + { + "x": 33, + "y": 19 + } + ], + "769": [ + { + "x": 35, + "y": 19 + } + ], + "824": [ + { + "x": 37, + "y": 19 + } + ], + "913": [ + { + "x": 41, + "y": 19 + } + ], + "968": [ + { + "x": 43, + "y": 19 + } + ], + "1023": [ + { + "x": 45, + "y": 19 + } + ], + "1109": [ + { + "x": 49, + "y": 19 + } + ], + "1164": [ + { + "x": 51, + "y": 19 + } + ], + "1219": [ + { + "x": 53, + "y": 19 + } + ], + "1308": [ + { + "x": 57, + "y": 19 + } + ], + "1363": [ + { + "x": 59, + "y": 19 + } + ], + "1418": [ + { + "x": 61, + "y": 19 + } + ], + "1492": [ + { + "x": 65, + "y": 19 + } + ], + "1533": [ + { + "x": 67, + "y": 19 + } + ], + "1574": [ + { + "x": 69, + "y": 19 + } + ], + "1639": [ + { + "x": 73, + "y": 19 + } + ], + "1680": [ + { + "x": 75, + "y": 19 + } + ], + "27": [ + { + "x": 1, + "y": 20 + } + ], + "68": [ + { + "x": 3, + "y": 20 + } + ], + "109": [ + { + "x": 5, + "y": 20 + } + ], + "136": [ + { + "x": 7, + "y": 20 + } + ], + "174": [ + { + "x": 9, + "y": 20 + } + ], + "215": [ + { + "x": 11, + "y": 20 + } + ], + "256": [ + { + "x": 13, + "y": 20 + } + ], + "281": [ + { + "x": 15, + "y": 20 + } + ], + "318": [ + { + "x": 17, + "y": 20 + } + ], + "373": [ + { + "x": 19, + "y": 20 + } + ], + "428": [ + { + "x": 21, + "y": 20 + } + ], + "469": [ + { + "x": 23, + "y": 20 + } + ], + "517": [ + { + "x": 25, + "y": 20 + } + ], + "572": [ + { + "x": 27, + "y": 20 + } + ], + "627": [ + { + "x": 29, + "y": 20 + } + ], + "666": [ + { + "x": 31, + "y": 20 + } + ], + "713": [ + { + "x": 33, + "y": 20 + } + ], + "768": [ + { + "x": 35, + "y": 20 + } + ], + "823": [ + { + "x": 37, + "y": 20 + } + ], + "864": [ + { + "x": 39, + "y": 20 + } + ], + "912": [ + { + "x": 41, + "y": 20 + } + ], + "967": [ + { + "x": 43, + "y": 20 + } + ], + "1022": [ + { + "x": 45, + "y": 20 + } + ], + "1061": [ + { + "x": 47, + "y": 20 + } + ], + "1108": [ + { + "x": 49, + "y": 20 + } + ], + "1163": [ + { + "x": 51, + "y": 20 + } + ], + "1218": [ + { + "x": 53, + "y": 20 + } + ], + "1259": [ + { + "x": 55, + "y": 20 + } + ], + "1307": [ + { + "x": 57, + "y": 20 + } + ], + "1362": [ + { + "x": 59, + "y": 20 + } + ], + "1417": [ + { + "x": 61, + "y": 20 + } + ], + "1454": [ + { + "x": 63, + "y": 20 + } + ], + "1491": [ + { + "x": 65, + "y": 20 + } + ], + "1532": [ + { + "x": 67, + "y": 20 + } + ], + "1573": [ + { + "x": 69, + "y": 20 + } + ], + "1600": [ + { + "x": 71, + "y": 20 + } + ], + "1638": [ + { + "x": 73, + "y": 20 + } + ], + "1679": [ + { + "x": 75, + "y": 20 + } + ], + "26": [ + { + "x": 1, + "y": 21 + } + ], + "67": [ + { + "x": 3, + "y": 21 + } + ], + "108": [ + { + "x": 5, + "y": 21 + } + ], + "173": [ + { + "x": 9, + "y": 21 + } + ], + "214": [ + { + "x": 11, + "y": 21 + } + ], + "255": [ + { + "x": 13, + "y": 21 + } + ], + "317": [ + { + "x": 17, + "y": 21 + } + ], + "372": [ + { + "x": 19, + "y": 21 + } + ], + "427": [ + { + "x": 21, + "y": 21 + } + ], + "516": [ + { + "x": 25, + "y": 21 + } + ], + "571": [ + { + "x": 27, + "y": 21 + } + ], + "626": [ + { + "x": 29, + "y": 21 + } + ], + "712": [ + { + "x": 33, + "y": 21 + } + ], + "767": [ + { + "x": 35, + "y": 21 + } + ], + "822": [ + { + "x": 37, + "y": 21 + } + ], + "911": [ + { + "x": 41, + "y": 21 + } + ], + "966": [ + { + "x": 43, + "y": 21 + } + ], + "1021": [ + { + "x": 45, + "y": 21 + } + ], + "1107": [ + { + "x": 49, + "y": 21 + } + ], + "1162": [ + { + "x": 51, + "y": 21 + } + ], + "1217": [ + { + "x": 53, + "y": 21 + } + ], + "1306": [ + { + "x": 57, + "y": 21 + } + ], + "1361": [ + { + "x": 59, + "y": 21 + } + ], + "1416": [ + { + "x": 61, + "y": 21 + } + ], + "1490": [ + { + "x": 65, + "y": 21 + } + ], + "1531": [ + { + "x": 67, + "y": 21 + } + ], + "1572": [ + { + "x": 69, + "y": 21 + } + ], + "1637": [ + { + "x": 73, + "y": 21 + } + ], + "1678": [ + { + "x": 75, + "y": 21 + } + ], + "25": [ + { + "x": 1, + "y": 22 + } + ], + "40": [ + { + "x": 2, + "y": 22 + } + ], + "66": [ + { + "x": 3, + "y": 22 + } + ], + "81": [ + { + "x": 4, + "y": 22 + } + ], + "107": [ + { + "x": 5, + "y": 22 + } + ], + "122": [ + { + "x": 6, + "y": 22 + } + ], + "135": [ + { + "x": 7, + "y": 22 + } + ], + "146": [ + { + "x": 8, + "y": 22 + } + ], + "172": [ + { + "x": 9, + "y": 22 + } + ], + "186": [ + { + "x": 10, + "y": 22 + } + ], + "213": [ + { + "x": 11, + "y": 22 + } + ], + "227": [ + { + "x": 12, + "y": 22 + } + ], + "254": [ + { + "x": 13, + "y": 22 + } + ], + "268": [ + { + "x": 14, + "y": 22 + } + ], + "280": [ + { + "x": 15, + "y": 22 + } + ], + "290": [ + { + "x": 16, + "y": 22 + } + ], + "316": [ + { + "x": 17, + "y": 22 + } + ], + "343": [ + { + "x": 18, + "y": 22 + } + ], + "371": [ + { + "x": 19, + "y": 22 + } + ], + "398": [ + { + "x": 20, + "y": 22 + } + ], + "426": [ + { + "x": 21, + "y": 22 + } + ], + "453": [ + { + "x": 22, + "y": 22 + } + ], + "468": [ + { + "x": 23, + "y": 22 + } + ], + "487": [ + { + "x": 24, + "y": 22 + } + ], + "515": [ + { + "x": 25, + "y": 22 + } + ], + "541": [ + { + "x": 26, + "y": 22 + } + ], + "570": [ + { + "x": 27, + "y": 22 + } + ], + "596": [ + { + "x": 28, + "y": 22 + } + ], + "625": [ + { + "x": 29, + "y": 22 + } + ], + "651": [ + { + "x": 30, + "y": 22 + } + ], + "665": [ + { + "x": 31, + "y": 22 + } + ], + "683": [ + { + "x": 32, + "y": 22 + } + ], + "711": [ + { + "x": 33, + "y": 22 + } + ], + "738": [ + { + "x": 34, + "y": 22 + } + ], + "766": [ + { + "x": 35, + "y": 22 + } + ], + "793": [ + { + "x": 36, + "y": 22 + } + ], + "821": [ + { + "x": 37, + "y": 22 + } + ], + "848": [ + { + "x": 38, + "y": 22 + } + ], + "863": [ + { + "x": 39, + "y": 22 + } + ], + "882": [ + { + "x": 40, + "y": 22 + } + ], + "910": [ + { + "x": 41, + "y": 22 + } + ], + "936": [ + { + "x": 42, + "y": 22 + } + ], + "965": [ + { + "x": 43, + "y": 22 + } + ], + "991": [ + { + "x": 44, + "y": 22 + } + ], + "1020": [ + { + "x": 45, + "y": 22 + } + ], + "1046": [ + { + "x": 46, + "y": 22 + } + ], + "1060": [ + { + "x": 47, + "y": 22 + } + ], + "1078": [ + { + "x": 48, + "y": 22 + } + ], + "1106": [ + { + "x": 49, + "y": 22 + } + ], + "1133": [ + { + "x": 50, + "y": 22 + } + ], + "1161": [ + { + "x": 51, + "y": 22 + } + ], + "1188": [ + { + "x": 52, + "y": 22 + } + ], + "1216": [ + { + "x": 53, + "y": 22 + } + ], + "1243": [ + { + "x": 54, + "y": 22 + } + ], + "1258": [ + { + "x": 55, + "y": 22 + } + ], + "1277": [ + { + "x": 56, + "y": 22 + } + ], + "1305": [ + { + "x": 57, + "y": 22 + } + ], + "1331": [ + { + "x": 58, + "y": 22 + } + ], + "1360": [ + { + "x": 59, + "y": 22 + } + ], + "1386": [ + { + "x": 60, + "y": 22 + } + ], + "1415": [ + { + "x": 61, + "y": 22 + } + ], + "1441": [ + { + "x": 62, + "y": 22 + } + ], + "1453": [ + { + "x": 63, + "y": 22 + } + ], + "1463": [ + { + "x": 64, + "y": 22 + } + ], + "1489": [ + { + "x": 65, + "y": 22 + } + ], + "1504": [ + { + "x": 66, + "y": 22 + } + ], + "1530": [ + { + "x": 67, + "y": 22 + } + ], + "1545": [ + { + "x": 68, + "y": 22 + } + ], + "1571": [ + { + "x": 69, + "y": 22 + } + ], + "1586": [ + { + "x": 70, + "y": 22 + } + ], + "1599": [ + { + "x": 71, + "y": 22 + } + ], + "1610": [ + { + "x": 72, + "y": 22 + } + ], + "1636": [ + { + "x": 73, + "y": 22 + } + ], + "1650": [ + { + "x": 74, + "y": 22 + } + ], + "1677": [ + { + "x": 75, + "y": 22 + } + ], + "24": [ + { + "x": 1, + "y": 23 + } + ], + "65": [ + { + "x": 3, + "y": 23 + } + ], + "106": [ + { + "x": 5, + "y": 23 + } + ], + "171": [ + { + "x": 9, + "y": 23 + } + ], + "212": [ + { + "x": 11, + "y": 23 + } + ], + "253": [ + { + "x": 13, + "y": 23 + } + ], + "315": [ + { + "x": 17, + "y": 23 + } + ], + "370": [ + { + "x": 19, + "y": 23 + } + ], + "425": [ + { + "x": 21, + "y": 23 + } + ], + "514": [ + { + "x": 25, + "y": 23 + } + ], + "569": [ + { + "x": 27, + "y": 23 + } + ], + "624": [ + { + "x": 29, + "y": 23 + } + ], + "710": [ + { + "x": 33, + "y": 23 + } + ], + "765": [ + { + "x": 35, + "y": 23 + } + ], + "820": [ + { + "x": 37, + "y": 23 + } + ], + "909": [ + { + "x": 41, + "y": 23 + } + ], + "964": [ + { + "x": 43, + "y": 23 + } + ], + "1019": [ + { + "x": 45, + "y": 23 + } + ], + "1105": [ + { + "x": 49, + "y": 23 + } + ], + "1160": [ + { + "x": 51, + "y": 23 + } + ], + "1215": [ + { + "x": 53, + "y": 23 + } + ], + "1304": [ + { + "x": 57, + "y": 23 + } + ], + "1359": [ + { + "x": 59, + "y": 23 + } + ], + "1414": [ + { + "x": 61, + "y": 23 + } + ], + "1488": [ + { + "x": 65, + "y": 23 + } + ], + "1529": [ + { + "x": 67, + "y": 23 + } + ], + "1570": [ + { + "x": 69, + "y": 23 + } + ], + "1635": [ + { + "x": 73, + "y": 23 + } + ], + "1676": [ + { + "x": 75, + "y": 23 + } + ], + "23": [ + { + "x": 1, + "y": 24 + } + ], + "64": [ + { + "x": 3, + "y": 24 + } + ], + "105": [ + { + "x": 5, + "y": 24 + } + ], + "170": [ + { + "x": 9, + "y": 24 + } + ], + "211": [ + { + "x": 11, + "y": 24 + } + ], + "252": [ + { + "x": 13, + "y": 24 + } + ], + "314": [ + { + "x": 17, + "y": 24 + } + ], + "369": [ + { + "x": 19, + "y": 24 + } + ], + "424": [ + { + "x": 21, + "y": 24 + } + ], + "513": [ + { + "x": 25, + "y": 24 + } + ], + "568": [ + { + "x": 27, + "y": 24 + } + ], + "623": [ + { + "x": 29, + "y": 24 + } + ], + "709": [ + { + "x": 33, + "y": 24 + } + ], + "764": [ + { + "x": 35, + "y": 24 + } + ], + "819": [ + { + "x": 37, + "y": 24 + } + ], + "908": [ + { + "x": 41, + "y": 24 + } + ], + "963": [ + { + "x": 43, + "y": 24 + } + ], + "1018": [ + { + "x": 45, + "y": 24 + } + ], + "1104": [ + { + "x": 49, + "y": 24 + } + ], + "1159": [ + { + "x": 51, + "y": 24 + } + ], + "1214": [ + { + "x": 53, + "y": 24 + } + ], + "1303": [ + { + "x": 57, + "y": 24 + } + ], + "1358": [ + { + "x": 59, + "y": 24 + } + ], + "1413": [ + { + "x": 61, + "y": 24 + } + ], + "1487": [ + { + "x": 65, + "y": 24 + } + ], + "1528": [ + { + "x": 67, + "y": 24 + } + ], + "1569": [ + { + "x": 69, + "y": 24 + } + ], + "1634": [ + { + "x": 73, + "y": 24 + } + ], + "1675": [ + { + "x": 75, + "y": 24 + } + ], + "22": [ + { + "x": 1, + "y": 25 + } + ], + "63": [ + { + "x": 3, + "y": 25 + } + ], + "104": [ + { + "x": 5, + "y": 25 + } + ], + "169": [ + { + "x": 9, + "y": 25 + } + ], + "210": [ + { + "x": 11, + "y": 25 + } + ], + "251": [ + { + "x": 13, + "y": 25 + } + ], + "313": [ + { + "x": 17, + "y": 25 + } + ], + "368": [ + { + "x": 19, + "y": 25 + } + ], + "423": [ + { + "x": 21, + "y": 25 + } + ], + "512": [ + { + "x": 25, + "y": 25 + } + ], + "567": [ + { + "x": 27, + "y": 25 + } + ], + "622": [ + { + "x": 29, + "y": 25 + } + ], + "708": [ + { + "x": 33, + "y": 25 + } + ], + "763": [ + { + "x": 35, + "y": 25 + } + ], + "818": [ + { + "x": 37, + "y": 25 + } + ], + "907": [ + { + "x": 41, + "y": 25 + } + ], + "962": [ + { + "x": 43, + "y": 25 + } + ], + "1017": [ + { + "x": 45, + "y": 25 + } + ], + "1103": [ + { + "x": 49, + "y": 25 + } + ], + "1158": [ + { + "x": 51, + "y": 25 + } + ], + "1213": [ + { + "x": 53, + "y": 25 + } + ], + "1302": [ + { + "x": 57, + "y": 25 + } + ], + "1357": [ + { + "x": 59, + "y": 25 + } + ], + "1412": [ + { + "x": 61, + "y": 25 + } + ], + "1486": [ + { + "x": 65, + "y": 25 + } + ], + "1527": [ + { + "x": 67, + "y": 25 + } + ], + "1568": [ + { + "x": 69, + "y": 25 + } + ], + "1633": [ + { + "x": 73, + "y": 25 + } + ], + "1674": [ + { + "x": 75, + "y": 25 + } + ], + "21": [ + { + "x": 1, + "y": 26 + } + ], + "62": [ + { + "x": 3, + "y": 26 + } + ], + "103": [ + { + "x": 5, + "y": 26 + } + ], + "168": [ + { + "x": 9, + "y": 26 + } + ], + "209": [ + { + "x": 11, + "y": 26 + } + ], + "250": [ + { + "x": 13, + "y": 26 + } + ], + "312": [ + { + "x": 17, + "y": 26 + } + ], + "367": [ + { + "x": 19, + "y": 26 + } + ], + "422": [ + { + "x": 21, + "y": 26 + } + ], + "511": [ + { + "x": 25, + "y": 26 + } + ], + "566": [ + { + "x": 27, + "y": 26 + } + ], + "621": [ + { + "x": 29, + "y": 26 + } + ], + "707": [ + { + "x": 33, + "y": 26 + } + ], + "762": [ + { + "x": 35, + "y": 26 + } + ], + "817": [ + { + "x": 37, + "y": 26 + } + ], + "906": [ + { + "x": 41, + "y": 26 + } + ], + "961": [ + { + "x": 43, + "y": 26 + } + ], + "1016": [ + { + "x": 45, + "y": 26 + } + ], + "1102": [ + { + "x": 49, + "y": 26 + } + ], + "1157": [ + { + "x": 51, + "y": 26 + } + ], + "1212": [ + { + "x": 53, + "y": 26 + } + ], + "1301": [ + { + "x": 57, + "y": 26 + } + ], + "1356": [ + { + "x": 59, + "y": 26 + } + ], + "1411": [ + { + "x": 61, + "y": 26 + } + ], + "1485": [ + { + "x": 65, + "y": 26 + } + ], + "1526": [ + { + "x": 67, + "y": 26 + } + ], + "1567": [ + { + "x": 69, + "y": 26 + } + ], + "1632": [ + { + "x": 73, + "y": 26 + } + ], + "1673": [ + { + "x": 75, + "y": 26 + } + ], + "20": [ + { + "x": 1, + "y": 27 + } + ], + "61": [ + { + "x": 3, + "y": 27 + } + ], + "102": [ + { + "x": 5, + "y": 27 + } + ], + "167": [ + { + "x": 9, + "y": 27 + } + ], + "208": [ + { + "x": 11, + "y": 27 + } + ], + "249": [ + { + "x": 13, + "y": 27 + } + ], + "311": [ + { + "x": 17, + "y": 27 + } + ], + "366": [ + { + "x": 19, + "y": 27 + } + ], + "421": [ + { + "x": 21, + "y": 27 + } + ], + "510": [ + { + "x": 25, + "y": 27 + } + ], + "565": [ + { + "x": 27, + "y": 27 + } + ], + "620": [ + { + "x": 29, + "y": 27 + } + ], + "706": [ + { + "x": 33, + "y": 27 + } + ], + "761": [ + { + "x": 35, + "y": 27 + } + ], + "816": [ + { + "x": 37, + "y": 27 + } + ], + "905": [ + { + "x": 41, + "y": 27 + } + ], + "960": [ + { + "x": 43, + "y": 27 + } + ], + "1015": [ + { + "x": 45, + "y": 27 + } + ], + "1101": [ + { + "x": 49, + "y": 27 + } + ], + "1156": [ + { + "x": 51, + "y": 27 + } + ], + "1211": [ + { + "x": 53, + "y": 27 + } + ], + "1300": [ + { + "x": 57, + "y": 27 + } + ], + "1355": [ + { + "x": 59, + "y": 27 + } + ], + "1410": [ + { + "x": 61, + "y": 27 + } + ], + "1484": [ + { + "x": 65, + "y": 27 + } + ], + "1525": [ + { + "x": 67, + "y": 27 + } + ], + "1566": [ + { + "x": 69, + "y": 27 + } + ], + "1631": [ + { + "x": 73, + "y": 27 + } + ], + "1672": [ + { + "x": 75, + "y": 27 + } + ], + "19": [ + { + "x": 1, + "y": 28 + } + ], + "60": [ + { + "x": 3, + "y": 28 + } + ], + "101": [ + { + "x": 5, + "y": 28 + } + ], + "134": [ + { + "x": 7, + "y": 28 + } + ], + "166": [ + { + "x": 9, + "y": 28 + } + ], + "207": [ + { + "x": 11, + "y": 28 + } + ], + "248": [ + { + "x": 13, + "y": 28 + } + ], + "279": [ + { + "x": 15, + "y": 28 + } + ], + "310": [ + { + "x": 17, + "y": 28 + } + ], + "365": [ + { + "x": 19, + "y": 28 + } + ], + "420": [ + { + "x": 21, + "y": 28 + } + ], + "467": [ + { + "x": 23, + "y": 28 + } + ], + "509": [ + { + "x": 25, + "y": 28 + } + ], + "564": [ + { + "x": 27, + "y": 28 + } + ], + "619": [ + { + "x": 29, + "y": 28 + } + ], + "664": [ + { + "x": 31, + "y": 28 + } + ], + "705": [ + { + "x": 33, + "y": 28 + } + ], + "760": [ + { + "x": 35, + "y": 28 + } + ], + "815": [ + { + "x": 37, + "y": 28 + } + ], + "862": [ + { + "x": 39, + "y": 28 + } + ], + "904": [ + { + "x": 41, + "y": 28 + } + ], + "959": [ + { + "x": 43, + "y": 28 + } + ], + "1014": [ + { + "x": 45, + "y": 28 + } + ], + "1059": [ + { + "x": 47, + "y": 28 + } + ], + "1100": [ + { + "x": 49, + "y": 28 + } + ], + "1155": [ + { + "x": 51, + "y": 28 + } + ], + "1210": [ + { + "x": 53, + "y": 28 + } + ], + "1257": [ + { + "x": 55, + "y": 28 + } + ], + "1299": [ + { + "x": 57, + "y": 28 + } + ], + "1354": [ + { + "x": 59, + "y": 28 + } + ], + "1409": [ + { + "x": 61, + "y": 28 + } + ], + "1452": [ + { + "x": 63, + "y": 28 + } + ], + "1483": [ + { + "x": 65, + "y": 28 + } + ], + "1524": [ + { + "x": 67, + "y": 28 + } + ], + "1565": [ + { + "x": 69, + "y": 28 + } + ], + "1598": [ + { + "x": 71, + "y": 28 + } + ], + "1630": [ + { + "x": 73, + "y": 28 + } + ], + "1671": [ + { + "x": 75, + "y": 28 + } + ], + "18": [ + { + "x": 1, + "y": 29 + } + ], + "59": [ + { + "x": 3, + "y": 29 + } + ], + "100": [ + { + "x": 5, + "y": 29 + } + ], + "165": [ + { + "x": 9, + "y": 29 + } + ], + "206": [ + { + "x": 11, + "y": 29 + } + ], + "247": [ + { + "x": 13, + "y": 29 + } + ], + "309": [ + { + "x": 17, + "y": 29 + } + ], + "364": [ + { + "x": 19, + "y": 29 + } + ], + "419": [ + { + "x": 21, + "y": 29 + } + ], + "508": [ + { + "x": 25, + "y": 29 + } + ], + "563": [ + { + "x": 27, + "y": 29 + } + ], + "618": [ + { + "x": 29, + "y": 29 + } + ], + "704": [ + { + "x": 33, + "y": 29 + } + ], + "759": [ + { + "x": 35, + "y": 29 + } + ], + "814": [ + { + "x": 37, + "y": 29 + } + ], + "903": [ + { + "x": 41, + "y": 29 + } + ], + "958": [ + { + "x": 43, + "y": 29 + } + ], + "1013": [ + { + "x": 45, + "y": 29 + } + ], + "1099": [ + { + "x": 49, + "y": 29 + } + ], + "1154": [ + { + "x": 51, + "y": 29 + } + ], + "1209": [ + { + "x": 53, + "y": 29 + } + ], + "1298": [ + { + "x": 57, + "y": 29 + } + ], + "1353": [ + { + "x": 59, + "y": 29 + } + ], + "1408": [ + { + "x": 61, + "y": 29 + } + ], + "1482": [ + { + "x": 65, + "y": 29 + } + ], + "1523": [ + { + "x": 67, + "y": 29 + } + ], + "1564": [ + { + "x": 69, + "y": 29 + } + ], + "1629": [ + { + "x": 73, + "y": 29 + } + ], + "1670": [ + { + "x": 75, + "y": 29 + } + ], + "17": [ + { + "x": 1, + "y": 30 + } + ], + "58": [ + { + "x": 3, + "y": 30 + } + ], + "99": [ + { + "x": 5, + "y": 30 + } + ], + "133": [ + { + "x": 7, + "y": 30 + } + ], + "164": [ + { + "x": 9, + "y": 30 + } + ], + "205": [ + { + "x": 11, + "y": 30 + } + ], + "246": [ + { + "x": 13, + "y": 30 + } + ], + "278": [ + { + "x": 15, + "y": 30 + } + ], + "308": [ + { + "x": 17, + "y": 30 + } + ], + "363": [ + { + "x": 19, + "y": 30 + } + ], + "418": [ + { + "x": 21, + "y": 30 + } + ], + "466": [ + { + "x": 23, + "y": 30 + } + ], + "507": [ + { + "x": 25, + "y": 30 + } + ], + "562": [ + { + "x": 27, + "y": 30 + } + ], + "617": [ + { + "x": 29, + "y": 30 + } + ], + "663": [ + { + "x": 31, + "y": 30 + } + ], + "703": [ + { + "x": 33, + "y": 30 + } + ], + "758": [ + { + "x": 35, + "y": 30 + } + ], + "813": [ + { + "x": 37, + "y": 30 + } + ], + "861": [ + { + "x": 39, + "y": 30 + } + ], + "902": [ + { + "x": 41, + "y": 30 + } + ], + "957": [ + { + "x": 43, + "y": 30 + } + ], + "1012": [ + { + "x": 45, + "y": 30 + } + ], + "1058": [ + { + "x": 47, + "y": 30 + } + ], + "1098": [ + { + "x": 49, + "y": 30 + } + ], + "1153": [ + { + "x": 51, + "y": 30 + } + ], + "1208": [ + { + "x": 53, + "y": 30 + } + ], + "1256": [ + { + "x": 55, + "y": 30 + } + ], + "1297": [ + { + "x": 57, + "y": 30 + } + ], + "1352": [ + { + "x": 59, + "y": 30 + } + ], + "1407": [ + { + "x": 61, + "y": 30 + } + ], + "1451": [ + { + "x": 63, + "y": 30 + } + ], + "1481": [ + { + "x": 65, + "y": 30 + } + ], + "1522": [ + { + "x": 67, + "y": 30 + } + ], + "1563": [ + { + "x": 69, + "y": 30 + } + ], + "1597": [ + { + "x": 71, + "y": 30 + } + ], + "1628": [ + { + "x": 73, + "y": 30 + } + ], + "1669": [ + { + "x": 75, + "y": 30 + } + ], + "16": [ + { + "x": 1, + "y": 31 + } + ], + "57": [ + { + "x": 3, + "y": 31 + } + ], + "98": [ + { + "x": 5, + "y": 31 + } + ], + "163": [ + { + "x": 9, + "y": 31 + } + ], + "204": [ + { + "x": 11, + "y": 31 + } + ], + "245": [ + { + "x": 13, + "y": 31 + } + ], + "307": [ + { + "x": 17, + "y": 31 + } + ], + "362": [ + { + "x": 19, + "y": 31 + } + ], + "417": [ + { + "x": 21, + "y": 31 + } + ], + "506": [ + { + "x": 25, + "y": 31 + } + ], + "561": [ + { + "x": 27, + "y": 31 + } + ], + "616": [ + { + "x": 29, + "y": 31 + } + ], + "702": [ + { + "x": 33, + "y": 31 + } + ], + "757": [ + { + "x": 35, + "y": 31 + } + ], + "812": [ + { + "x": 37, + "y": 31 + } + ], + "901": [ + { + "x": 41, + "y": 31 + } + ], + "956": [ + { + "x": 43, + "y": 31 + } + ], + "1011": [ + { + "x": 45, + "y": 31 + } + ], + "1097": [ + { + "x": 49, + "y": 31 + } + ], + "1152": [ + { + "x": 51, + "y": 31 + } + ], + "1207": [ + { + "x": 53, + "y": 31 + } + ], + "1296": [ + { + "x": 57, + "y": 31 + } + ], + "1351": [ + { + "x": 59, + "y": 31 + } + ], + "1406": [ + { + "x": 61, + "y": 31 + } + ], + "1480": [ + { + "x": 65, + "y": 31 + } + ], + "1521": [ + { + "x": 67, + "y": 31 + } + ], + "1562": [ + { + "x": 69, + "y": 31 + } + ], + "1627": [ + { + "x": 73, + "y": 31 + } + ], + "1668": [ + { + "x": 75, + "y": 31 + } + ], + "15": [ + { + "x": 1, + "y": 32 + } + ], + "39": [ + { + "x": 2, + "y": 32 + } + ], + "56": [ + { + "x": 3, + "y": 32 + } + ], + "80": [ + { + "x": 4, + "y": 32 + } + ], + "97": [ + { + "x": 5, + "y": 32 + } + ], + "121": [ + { + "x": 6, + "y": 32 + } + ], + "132": [ + { + "x": 7, + "y": 32 + } + ], + "145": [ + { + "x": 8, + "y": 32 + } + ], + "162": [ + { + "x": 9, + "y": 32 + } + ], + "185": [ + { + "x": 10, + "y": 32 + } + ], + "203": [ + { + "x": 11, + "y": 32 + } + ], + "226": [ + { + "x": 12, + "y": 32 + } + ], + "244": [ + { + "x": 13, + "y": 32 + } + ], + "267": [ + { + "x": 14, + "y": 32 + } + ], + "277": [ + { + "x": 15, + "y": 32 + } + ], + "289": [ + { + "x": 16, + "y": 32 + } + ], + "306": [ + { + "x": 17, + "y": 32 + } + ], + "342": [ + { + "x": 18, + "y": 32 + } + ], + "361": [ + { + "x": 19, + "y": 32 + } + ], + "397": [ + { + "x": 20, + "y": 32 + } + ], + "416": [ + { + "x": 21, + "y": 32 + } + ], + "452": [ + { + "x": 22, + "y": 32 + } + ], + "465": [ + { + "x": 23, + "y": 32 + } + ], + "486": [ + { + "x": 24, + "y": 32 + } + ], + "505": [ + { + "x": 25, + "y": 32 + } + ], + "540": [ + { + "x": 26, + "y": 32 + } + ], + "560": [ + { + "x": 27, + "y": 32 + } + ], + "595": [ + { + "x": 28, + "y": 32 + } + ], + "615": [ + { + "x": 29, + "y": 32 + } + ], + "650": [ + { + "x": 30, + "y": 32 + } + ], + "662": [ + { + "x": 31, + "y": 32 + } + ], + "682": [ + { + "x": 32, + "y": 32 + } + ], + "701": [ + { + "x": 33, + "y": 32 + } + ], + "737": [ + { + "x": 34, + "y": 32 + } + ], + "756": [ + { + "x": 35, + "y": 32 + } + ], + "792": [ + { + "x": 36, + "y": 32 + } + ], + "811": [ + { + "x": 37, + "y": 32 + } + ], + "847": [ + { + "x": 38, + "y": 32 + } + ], + "860": [ + { + "x": 39, + "y": 32 + } + ], + "881": [ + { + "x": 40, + "y": 32 + } + ], + "900": [ + { + "x": 41, + "y": 32 + } + ], + "935": [ + { + "x": 42, + "y": 32 + } + ], + "955": [ + { + "x": 43, + "y": 32 + } + ], + "990": [ + { + "x": 44, + "y": 32 + } + ], + "1010": [ + { + "x": 45, + "y": 32 + } + ], + "1045": [ + { + "x": 46, + "y": 32 + } + ], + "1057": [ + { + "x": 47, + "y": 32 + } + ], + "1077": [ + { + "x": 48, + "y": 32 + } + ], + "1096": [ + { + "x": 49, + "y": 32 + } + ], + "1132": [ + { + "x": 50, + "y": 32 + } + ], + "1151": [ + { + "x": 51, + "y": 32 + } + ], + "1187": [ + { + "x": 52, + "y": 32 + } + ], + "1206": [ + { + "x": 53, + "y": 32 + } + ], + "1242": [ + { + "x": 54, + "y": 32 + } + ], + "1255": [ + { + "x": 55, + "y": 32 + } + ], + "1276": [ + { + "x": 56, + "y": 32 + } + ], + "1295": [ + { + "x": 57, + "y": 32 + } + ], + "1330": [ + { + "x": 58, + "y": 32 + } + ], + "1350": [ + { + "x": 59, + "y": 32 + } + ], + "1385": [ + { + "x": 60, + "y": 32 + } + ], + "1405": [ + { + "x": 61, + "y": 32 + } + ], + "1440": [ + { + "x": 62, + "y": 32 + } + ], + "1450": [ + { + "x": 63, + "y": 32 + } + ], + "1462": [ + { + "x": 64, + "y": 32 + } + ], + "1479": [ + { + "x": 65, + "y": 32 + } + ], + "1503": [ + { + "x": 66, + "y": 32 + } + ], + "1520": [ + { + "x": 67, + "y": 32 + } + ], + "1544": [ + { + "x": 68, + "y": 32 + } + ], + "1561": [ + { + "x": 69, + "y": 32 + } + ], + "1585": [ + { + "x": 70, + "y": 32 + } + ], + "1596": [ + { + "x": 71, + "y": 32 + } + ], + "1609": [ + { + "x": 72, + "y": 32 + } + ], + "1626": [ + { + "x": 73, + "y": 32 + } + ], + "1649": [ + { + "x": 74, + "y": 32 + } + ], + "1667": [ + { + "x": 75, + "y": 32 + } + ], + "1690": [ + { + "x": 76, + "y": 32 + } + ], + "1706": [ + { + "x": 77, + "y": 32 + } + ], + "14": [ + { + "x": 1, + "y": 33 + } + ], + "55": [ + { + "x": 3, + "y": 33 + } + ], + "96": [ + { + "x": 5, + "y": 33 + } + ], + "161": [ + { + "x": 9, + "y": 33 + } + ], + "202": [ + { + "x": 11, + "y": 33 + } + ], + "243": [ + { + "x": 13, + "y": 33 + } + ], + "305": [ + { + "x": 17, + "y": 33 + } + ], + "360": [ + { + "x": 19, + "y": 33 + } + ], + "415": [ + { + "x": 21, + "y": 33 + } + ], + "504": [ + { + "x": 25, + "y": 33 + } + ], + "559": [ + { + "x": 27, + "y": 33 + } + ], + "614": [ + { + "x": 29, + "y": 33 + } + ], + "700": [ + { + "x": 33, + "y": 33 + } + ], + "755": [ + { + "x": 35, + "y": 33 + } + ], + "810": [ + { + "x": 37, + "y": 33 + } + ], + "899": [ + { + "x": 41, + "y": 33 + } + ], + "954": [ + { + "x": 43, + "y": 33 + } + ], + "1009": [ + { + "x": 45, + "y": 33 + } + ], + "1095": [ + { + "x": 49, + "y": 33 + } + ], + "1150": [ + { + "x": 51, + "y": 33 + } + ], + "1205": [ + { + "x": 53, + "y": 33 + } + ], + "1294": [ + { + "x": 57, + "y": 33 + } + ], + "1349": [ + { + "x": 59, + "y": 33 + } + ], + "1404": [ + { + "x": 61, + "y": 33 + } + ], + "1478": [ + { + "x": 65, + "y": 33 + } + ], + "1519": [ + { + "x": 67, + "y": 33 + } + ], + "1560": [ + { + "x": 69, + "y": 33 + } + ], + "1625": [ + { + "x": 73, + "y": 33 + } + ], + "1666": [ + { + "x": 75, + "y": 33 + } + ], + "1705": [ + { + "x": 77, + "y": 33 + } + ], + "13": [ + { + "x": 1, + "y": 34 + } + ], + "54": [ + { + "x": 3, + "y": 34 + } + ], + "95": [ + { + "x": 5, + "y": 34 + } + ], + "131": [ + { + "x": 7, + "y": 34 + } + ], + "160": [ + { + "x": 9, + "y": 34 + } + ], + "201": [ + { + "x": 11, + "y": 34 + } + ], + "242": [ + { + "x": 13, + "y": 34 + } + ], + "276": [ + { + "x": 15, + "y": 34 + } + ], + "304": [ + { + "x": 17, + "y": 34 + } + ], + "359": [ + { + "x": 19, + "y": 34 + } + ], + "414": [ + { + "x": 21, + "y": 34 + } + ], + "464": [ + { + "x": 23, + "y": 34 + } + ], + "503": [ + { + "x": 25, + "y": 34 + } + ], + "558": [ + { + "x": 27, + "y": 34 + } + ], + "613": [ + { + "x": 29, + "y": 34 + } + ], + "661": [ + { + "x": 31, + "y": 34 + } + ], + "699": [ + { + "x": 33, + "y": 34 + } + ], + "754": [ + { + "x": 35, + "y": 34 + } + ], + "809": [ + { + "x": 37, + "y": 34 + } + ], + "859": [ + { + "x": 39, + "y": 34 + } + ], + "898": [ + { + "x": 41, + "y": 34 + } + ], + "953": [ + { + "x": 43, + "y": 34 + } + ], + "1008": [ + { + "x": 45, + "y": 34 + } + ], + "1056": [ + { + "x": 47, + "y": 34 + } + ], + "1094": [ + { + "x": 49, + "y": 34 + } + ], + "1149": [ + { + "x": 51, + "y": 34 + } + ], + "1204": [ + { + "x": 53, + "y": 34 + } + ], + "1254": [ + { + "x": 55, + "y": 34 + } + ], + "1293": [ + { + "x": 57, + "y": 34 + } + ], + "1348": [ + { + "x": 59, + "y": 34 + } + ], + "1403": [ + { + "x": 61, + "y": 34 + } + ], + "1449": [ + { + "x": 63, + "y": 34 + } + ], + "1477": [ + { + "x": 65, + "y": 34 + } + ], + "1518": [ + { + "x": 67, + "y": 34 + } + ], + "1559": [ + { + "x": 69, + "y": 34 + } + ], + "1595": [ + { + "x": 71, + "y": 34 + } + ], + "1624": [ + { + "x": 73, + "y": 34 + } + ], + "1665": [ + { + "x": 75, + "y": 34 + } + ], + "1704": [ + { + "x": 77, + "y": 34 + } + ], + "12": [ + { + "x": 1, + "y": 35 + } + ], + "53": [ + { + "x": 3, + "y": 35 + } + ], + "94": [ + { + "x": 5, + "y": 35 + } + ], + "159": [ + { + "x": 9, + "y": 35 + } + ], + "200": [ + { + "x": 11, + "y": 35 + } + ], + "241": [ + { + "x": 13, + "y": 35 + } + ], + "303": [ + { + "x": 17, + "y": 35 + } + ], + "358": [ + { + "x": 19, + "y": 35 + } + ], + "413": [ + { + "x": 21, + "y": 35 + } + ], + "502": [ + { + "x": 25, + "y": 35 + } + ], + "557": [ + { + "x": 27, + "y": 35 + } + ], + "612": [ + { + "x": 29, + "y": 35 + } + ], + "698": [ + { + "x": 33, + "y": 35 + } + ], + "753": [ + { + "x": 35, + "y": 35 + } + ], + "808": [ + { + "x": 37, + "y": 35 + } + ], + "897": [ + { + "x": 41, + "y": 35 + } + ], + "952": [ + { + "x": 43, + "y": 35 + } + ], + "1007": [ + { + "x": 45, + "y": 35 + } + ], + "1093": [ + { + "x": 49, + "y": 35 + } + ], + "1148": [ + { + "x": 51, + "y": 35 + } + ], + "1203": [ + { + "x": 53, + "y": 35 + } + ], + "1292": [ + { + "x": 57, + "y": 35 + } + ], + "1347": [ + { + "x": 59, + "y": 35 + } + ], + "1402": [ + { + "x": 61, + "y": 35 + } + ], + "1476": [ + { + "x": 65, + "y": 35 + } + ], + "1517": [ + { + "x": 67, + "y": 35 + } + ], + "1558": [ + { + "x": 69, + "y": 35 + } + ], + "1623": [ + { + "x": 73, + "y": 35 + } + ], + "1664": [ + { + "x": 75, + "y": 35 + } + ], + "1703": [ + { + "x": 77, + "y": 35 + } + ], + "11": [ + { + "x": 1, + "y": 36 + } + ], + "52": [ + { + "x": 3, + "y": 36 + } + ], + "93": [ + { + "x": 5, + "y": 36 + } + ], + "130": [ + { + "x": 7, + "y": 36 + } + ], + "158": [ + { + "x": 9, + "y": 36 + } + ], + "199": [ + { + "x": 11, + "y": 36 + } + ], + "240": [ + { + "x": 13, + "y": 36 + } + ], + "275": [ + { + "x": 15, + "y": 36 + } + ], + "302": [ + { + "x": 17, + "y": 36 + } + ], + "357": [ + { + "x": 19, + "y": 36 + } + ], + "412": [ + { + "x": 21, + "y": 36 + } + ], + "463": [ + { + "x": 23, + "y": 36 + } + ], + "501": [ + { + "x": 25, + "y": 36 + } + ], + "556": [ + { + "x": 27, + "y": 36 + } + ], + "611": [ + { + "x": 29, + "y": 36 + } + ], + "660": [ + { + "x": 31, + "y": 36 + } + ], + "697": [ + { + "x": 33, + "y": 36 + } + ], + "752": [ + { + "x": 35, + "y": 36 + } + ], + "807": [ + { + "x": 37, + "y": 36 + } + ], + "858": [ + { + "x": 39, + "y": 36 + } + ], + "896": [ + { + "x": 41, + "y": 36 + } + ], + "951": [ + { + "x": 43, + "y": 36 + } + ], + "1006": [ + { + "x": 45, + "y": 36 + } + ], + "1055": [ + { + "x": 47, + "y": 36 + } + ], + "1092": [ + { + "x": 49, + "y": 36 + } + ], + "1147": [ + { + "x": 51, + "y": 36 + } + ], + "1202": [ + { + "x": 53, + "y": 36 + } + ], + "1253": [ + { + "x": 55, + "y": 36 + } + ], + "1291": [ + { + "x": 57, + "y": 36 + } + ], + "1346": [ + { + "x": 59, + "y": 36 + } + ], + "1401": [ + { + "x": 61, + "y": 36 + } + ], + "1448": [ + { + "x": 63, + "y": 36 + } + ], + "1475": [ + { + "x": 65, + "y": 36 + } + ], + "1516": [ + { + "x": 67, + "y": 36 + } + ], + "1557": [ + { + "x": 69, + "y": 36 + } + ], + "1594": [ + { + "x": 71, + "y": 36 + } + ], + "1622": [ + { + "x": 73, + "y": 36 + } + ], + "1663": [ + { + "x": 75, + "y": 36 + } + ], + "1702": [ + { + "x": 77, + "y": 36 + } + ], + "10": [ + { + "x": 1, + "y": 37 + } + ], + "51": [ + { + "x": 3, + "y": 37 + } + ], + "92": [ + { + "x": 5, + "y": 37 + } + ], + "129": [ + { + "x": 7, + "y": 37 + } + ], + "157": [ + { + "x": 9, + "y": 37 + } + ], + "198": [ + { + "x": 11, + "y": 37 + } + ], + "239": [ + { + "x": 13, + "y": 37 + } + ], + "274": [ + { + "x": 15, + "y": 37 + } + ], + "301": [ + { + "x": 17, + "y": 37 + } + ], + "356": [ + { + "x": 19, + "y": 37 + } + ], + "411": [ + { + "x": 21, + "y": 37 + } + ], + "462": [ + { + "x": 23, + "y": 37 + } + ], + "500": [ + { + "x": 25, + "y": 37 + } + ], + "555": [ + { + "x": 27, + "y": 37 + } + ], + "610": [ + { + "x": 29, + "y": 37 + } + ], + "659": [ + { + "x": 31, + "y": 37 + } + ], + "696": [ + { + "x": 33, + "y": 37 + } + ], + "751": [ + { + "x": 35, + "y": 37 + } + ], + "806": [ + { + "x": 37, + "y": 37 + } + ], + "857": [ + { + "x": 39, + "y": 37 + } + ], + "895": [ + { + "x": 41, + "y": 37 + } + ], + "950": [ + { + "x": 43, + "y": 37 + } + ], + "1005": [ + { + "x": 45, + "y": 37 + } + ], + "1054": [ + { + "x": 47, + "y": 37 + } + ], + "1091": [ + { + "x": 49, + "y": 37 + } + ], + "1146": [ + { + "x": 51, + "y": 37 + } + ], + "1201": [ + { + "x": 53, + "y": 37 + } + ], + "1252": [ + { + "x": 55, + "y": 37 + } + ], + "1290": [ + { + "x": 57, + "y": 37 + } + ], + "1345": [ + { + "x": 59, + "y": 37 + } + ], + "1400": [ + { + "x": 61, + "y": 37 + } + ], + "1447": [ + { + "x": 63, + "y": 37 + } + ], + "1474": [ + { + "x": 65, + "y": 37 + } + ], + "1515": [ + { + "x": 67, + "y": 37 + } + ], + "1556": [ + { + "x": 69, + "y": 37 + } + ], + "1593": [ + { + "x": 71, + "y": 37 + } + ], + "1621": [ + { + "x": 73, + "y": 37 + } + ], + "1662": [ + { + "x": 75, + "y": 37 + } + ], + "1701": [ + { + "x": 77, + "y": 37 + } + ], + "9": [ + { + "x": 1, + "y": 38 + } + ], + "50": [ + { + "x": 3, + "y": 38 + } + ], + "91": [ + { + "x": 5, + "y": 38 + } + ], + "128": [ + { + "x": 7, + "y": 38 + } + ], + "156": [ + { + "x": 9, + "y": 38 + } + ], + "197": [ + { + "x": 11, + "y": 38 + } + ], + "238": [ + { + "x": 13, + "y": 38 + } + ], + "273": [ + { + "x": 15, + "y": 38 + } + ], + "300": [ + { + "x": 17, + "y": 38 + } + ], + "355": [ + { + "x": 19, + "y": 38 + } + ], + "410": [ + { + "x": 21, + "y": 38 + } + ], + "461": [ + { + "x": 23, + "y": 38 + } + ], + "499": [ + { + "x": 25, + "y": 38 + } + ], + "554": [ + { + "x": 27, + "y": 38 + } + ], + "609": [ + { + "x": 29, + "y": 38 + } + ], + "658": [ + { + "x": 31, + "y": 38 + } + ], + "695": [ + { + "x": 33, + "y": 38 + } + ], + "750": [ + { + "x": 35, + "y": 38 + } + ], + "805": [ + { + "x": 37, + "y": 38 + } + ], + "856": [ + { + "x": 39, + "y": 38 + } + ], + "894": [ + { + "x": 41, + "y": 38 + } + ], + "949": [ + { + "x": 43, + "y": 38 + } + ], + "1004": [ + { + "x": 45, + "y": 38 + } + ], + "1053": [ + { + "x": 47, + "y": 38 + } + ], + "1090": [ + { + "x": 49, + "y": 38 + } + ], + "1145": [ + { + "x": 51, + "y": 38 + } + ], + "1200": [ + { + "x": 53, + "y": 38 + } + ], + "1251": [ + { + "x": 55, + "y": 38 + } + ], + "1289": [ + { + "x": 57, + "y": 38 + } + ], + "1344": [ + { + "x": 59, + "y": 38 + } + ], + "1399": [ + { + "x": 61, + "y": 38 + } + ], + "1446": [ + { + "x": 63, + "y": 38 + } + ], + "1473": [ + { + "x": 65, + "y": 38 + } + ], + "1514": [ + { + "x": 67, + "y": 38 + } + ], + "1555": [ + { + "x": 69, + "y": 38 + } + ], + "1592": [ + { + "x": 71, + "y": 38 + } + ], + "1620": [ + { + "x": 73, + "y": 38 + } + ], + "1661": [ + { + "x": 75, + "y": 38 + } + ], + "1700": [ + { + "x": 77, + "y": 38 + } + ], + "8": [ + { + "x": 1, + "y": 39 + } + ], + "49": [ + { + "x": 3, + "y": 39 + } + ], + "90": [ + { + "x": 5, + "y": 39 + } + ], + "155": [ + { + "x": 9, + "y": 39 + } + ], + "196": [ + { + "x": 11, + "y": 39 + } + ], + "237": [ + { + "x": 13, + "y": 39 + } + ], + "299": [ + { + "x": 17, + "y": 39 + } + ], + "354": [ + { + "x": 19, + "y": 39 + } + ], + "409": [ + { + "x": 21, + "y": 39 + } + ], + "498": [ + { + "x": 25, + "y": 39 + } + ], + "553": [ + { + "x": 27, + "y": 39 + } + ], + "608": [ + { + "x": 29, + "y": 39 + } + ], + "694": [ + { + "x": 33, + "y": 39 + } + ], + "749": [ + { + "x": 35, + "y": 39 + } + ], + "804": [ + { + "x": 37, + "y": 39 + } + ], + "893": [ + { + "x": 41, + "y": 39 + } + ], + "948": [ + { + "x": 43, + "y": 39 + } + ], + "1003": [ + { + "x": 45, + "y": 39 + } + ], + "1089": [ + { + "x": 49, + "y": 39 + } + ], + "1144": [ + { + "x": 51, + "y": 39 + } + ], + "1199": [ + { + "x": 53, + "y": 39 + } + ], + "1288": [ + { + "x": 57, + "y": 39 + } + ], + "1343": [ + { + "x": 59, + "y": 39 + } + ], + "1398": [ + { + "x": 61, + "y": 39 + } + ], + "1472": [ + { + "x": 65, + "y": 39 + } + ], + "1513": [ + { + "x": 67, + "y": 39 + } + ], + "1554": [ + { + "x": 69, + "y": 39 + } + ], + "1619": [ + { + "x": 73, + "y": 39 + } + ], + "1660": [ + { + "x": 75, + "y": 39 + } + ], + "1699": [ + { + "x": 77, + "y": 39 + } + ], + "7": [ + { + "x": 1, + "y": 40 + } + ], + "48": [ + { + "x": 3, + "y": 40 + } + ], + "89": [ + { + "x": 5, + "y": 40 + } + ], + "127": [ + { + "x": 7, + "y": 40 + } + ], + "154": [ + { + "x": 9, + "y": 40 + } + ], + "195": [ + { + "x": 11, + "y": 40 + } + ], + "236": [ + { + "x": 13, + "y": 40 + } + ], + "272": [ + { + "x": 15, + "y": 40 + } + ], + "298": [ + { + "x": 17, + "y": 40 + } + ], + "353": [ + { + "x": 19, + "y": 40 + } + ], + "408": [ + { + "x": 21, + "y": 40 + } + ], + "460": [ + { + "x": 23, + "y": 40 + } + ], + "497": [ + { + "x": 25, + "y": 40 + } + ], + "552": [ + { + "x": 27, + "y": 40 + } + ], + "607": [ + { + "x": 29, + "y": 40 + } + ], + "657": [ + { + "x": 31, + "y": 40 + } + ], + "693": [ + { + "x": 33, + "y": 40 + } + ], + "748": [ + { + "x": 35, + "y": 40 + } + ], + "803": [ + { + "x": 37, + "y": 40 + } + ], + "855": [ + { + "x": 39, + "y": 40 + } + ], + "892": [ + { + "x": 41, + "y": 40 + } + ], + "947": [ + { + "x": 43, + "y": 40 + } + ], + "1002": [ + { + "x": 45, + "y": 40 + } + ], + "1052": [ + { + "x": 47, + "y": 40 + } + ], + "1088": [ + { + "x": 49, + "y": 40 + } + ], + "1143": [ + { + "x": 51, + "y": 40 + } + ], + "1198": [ + { + "x": 53, + "y": 40 + } + ], + "1250": [ + { + "x": 55, + "y": 40 + } + ], + "1287": [ + { + "x": 57, + "y": 40 + } + ], + "1342": [ + { + "x": 59, + "y": 40 + } + ], + "1397": [ + { + "x": 61, + "y": 40 + } + ], + "1445": [ + { + "x": 63, + "y": 40 + } + ], + "1471": [ + { + "x": 65, + "y": 40 + } + ], + "1512": [ + { + "x": 67, + "y": 40 + } + ], + "1553": [ + { + "x": 69, + "y": 40 + } + ], + "1591": [ + { + "x": 71, + "y": 40 + } + ], + "1618": [ + { + "x": 73, + "y": 40 + } + ], + "1659": [ + { + "x": 75, + "y": 40 + } + ], + "1698": [ + { + "x": 77, + "y": 40 + } + ], + "6": [ + { + "x": 1, + "y": 41 + } + ], + "47": [ + { + "x": 3, + "y": 41 + } + ], + "88": [ + { + "x": 5, + "y": 41 + } + ], + "153": [ + { + "x": 9, + "y": 41 + } + ], + "194": [ + { + "x": 11, + "y": 41 + } + ], + "235": [ + { + "x": 13, + "y": 41 + } + ], + "297": [ + { + "x": 17, + "y": 41 + } + ], + "352": [ + { + "x": 19, + "y": 41 + } + ], + "407": [ + { + "x": 21, + "y": 41 + } + ], + "496": [ + { + "x": 25, + "y": 41 + } + ], + "551": [ + { + "x": 27, + "y": 41 + } + ], + "606": [ + { + "x": 29, + "y": 41 + } + ], + "692": [ + { + "x": 33, + "y": 41 + } + ], + "747": [ + { + "x": 35, + "y": 41 + } + ], + "802": [ + { + "x": 37, + "y": 41 + } + ], + "891": [ + { + "x": 41, + "y": 41 + } + ], + "946": [ + { + "x": 43, + "y": 41 + } + ], + "1001": [ + { + "x": 45, + "y": 41 + } + ], + "1087": [ + { + "x": 49, + "y": 41 + } + ], + "1142": [ + { + "x": 51, + "y": 41 + } + ], + "1197": [ + { + "x": 53, + "y": 41 + } + ], + "1286": [ + { + "x": 57, + "y": 41 + } + ], + "1341": [ + { + "x": 59, + "y": 41 + } + ], + "1396": [ + { + "x": 61, + "y": 41 + } + ], + "1470": [ + { + "x": 65, + "y": 41 + } + ], + "1511": [ + { + "x": 67, + "y": 41 + } + ], + "1552": [ + { + "x": 69, + "y": 41 + } + ], + "1617": [ + { + "x": 73, + "y": 41 + } + ], + "1658": [ + { + "x": 75, + "y": 41 + } + ], + "1697": [ + { + "x": 77, + "y": 41 + } + ], + "5": [ + { + "x": 1, + "y": 42 + } + ], + "38": [ + { + "x": 2, + "y": 42 + } + ], + "46": [ + { + "x": 3, + "y": 42 + } + ], + "79": [ + { + "x": 4, + "y": 42 + } + ], + "87": [ + { + "x": 5, + "y": 42 + } + ], + "120": [ + { + "x": 6, + "y": 42 + } + ], + "126": [ + { + "x": 7, + "y": 42 + } + ], + "144": [ + { + "x": 8, + "y": 42 + } + ], + "152": [ + { + "x": 9, + "y": 42 + } + ], + "184": [ + { + "x": 10, + "y": 42 + } + ], + "193": [ + { + "x": 11, + "y": 42 + } + ], + "225": [ + { + "x": 12, + "y": 42 + } + ], + "234": [ + { + "x": 13, + "y": 42 + } + ], + "266": [ + { + "x": 14, + "y": 42 + } + ], + "271": [ + { + "x": 15, + "y": 42 + } + ], + "288": [ + { + "x": 16, + "y": 42 + } + ], + "296": [ + { + "x": 17, + "y": 42 + } + ], + "341": [ + { + "x": 18, + "y": 42 + } + ], + "351": [ + { + "x": 19, + "y": 42 + } + ], + "396": [ + { + "x": 20, + "y": 42 + } + ], + "406": [ + { + "x": 21, + "y": 42 + } + ], + "451": [ + { + "x": 22, + "y": 42 + } + ], + "459": [ + { + "x": 23, + "y": 42 + } + ], + "485": [ + { + "x": 24, + "y": 42 + } + ], + "495": [ + { + "x": 25, + "y": 42 + } + ], + "539": [ + { + "x": 26, + "y": 42 + } + ], + "550": [ + { + "x": 27, + "y": 42 + } + ], + "594": [ + { + "x": 28, + "y": 42 + } + ], + "605": [ + { + "x": 29, + "y": 42 + } + ], + "649": [ + { + "x": 30, + "y": 42 + } + ], + "656": [ + { + "x": 31, + "y": 42 + } + ], + "681": [ + { + "x": 32, + "y": 42 + } + ], + "691": [ + { + "x": 33, + "y": 42 + } + ], + "736": [ + { + "x": 34, + "y": 42 + } + ], + "746": [ + { + "x": 35, + "y": 42 + } + ], + "791": [ + { + "x": 36, + "y": 42 + } + ], + "801": [ + { + "x": 37, + "y": 42 + } + ], + "846": [ + { + "x": 38, + "y": 42 + } + ], + "854": [ + { + "x": 39, + "y": 42 + } + ], + "880": [ + { + "x": 40, + "y": 42 + } + ], + "890": [ + { + "x": 41, + "y": 42 + } + ], + "934": [ + { + "x": 42, + "y": 42 + } + ], + "945": [ + { + "x": 43, + "y": 42 + } + ], + "989": [ + { + "x": 44, + "y": 42 + } + ], + "1000": [ + { + "x": 45, + "y": 42 + } + ], + "1044": [ + { + "x": 46, + "y": 42 + } + ], + "1051": [ + { + "x": 47, + "y": 42 + } + ], + "1076": [ + { + "x": 48, + "y": 42 + } + ], + "1086": [ + { + "x": 49, + "y": 42 + } + ], + "1131": [ + { + "x": 50, + "y": 42 + } + ], + "1141": [ + { + "x": 51, + "y": 42 + } + ], + "1186": [ + { + "x": 52, + "y": 42 + } + ], + "1196": [ + { + "x": 53, + "y": 42 + } + ], + "1241": [ + { + "x": 54, + "y": 42 + } + ], + "1249": [ + { + "x": 55, + "y": 42 + } + ], + "1275": [ + { + "x": 56, + "y": 42 + } + ], + "1285": [ + { + "x": 57, + "y": 42 + } + ], + "1329": [ + { + "x": 58, + "y": 42 + } + ], + "1340": [ + { + "x": 59, + "y": 42 + } + ], + "1384": [ + { + "x": 60, + "y": 42 + } + ], + "1395": [ + { + "x": 61, + "y": 42 + } + ], + "1439": [ + { + "x": 62, + "y": 42 + } + ], + "1444": [ + { + "x": 63, + "y": 42 + } + ], + "1461": [ + { + "x": 64, + "y": 42 + } + ], + "1469": [ + { + "x": 65, + "y": 42 + } + ], + "1502": [ + { + "x": 66, + "y": 42 + } + ], + "1510": [ + { + "x": 67, + "y": 42 + } + ], + "1543": [ + { + "x": 68, + "y": 42 + } + ], + "1551": [ + { + "x": 69, + "y": 42 + } + ], + "1584": [ + { + "x": 70, + "y": 42 + } + ], + "1590": [ + { + "x": 71, + "y": 42 + } + ], + "1608": [ + { + "x": 72, + "y": 42 + } + ], + "1616": [ + { + "x": 73, + "y": 42 + } + ], + "1648": [ + { + "x": 74, + "y": 42 + } + ], + "1657": [ + { + "x": 75, + "y": 42 + } + ], + "1689": [ + { + "x": 76, + "y": 42 + } + ], + "1696": [ + { + "x": 77, + "y": 42 + } + ], + "4": [ + { + "x": 1, + "y": 43 + } + ], + "45": [ + { + "x": 3, + "y": 43 + } + ], + "86": [ + { + "x": 5, + "y": 43 + } + ], + "151": [ + { + "x": 9, + "y": 43 + } + ], + "192": [ + { + "x": 11, + "y": 43 + } + ], + "233": [ + { + "x": 13, + "y": 43 + } + ], + "295": [ + { + "x": 17, + "y": 43 + } + ], + "350": [ + { + "x": 19, + "y": 43 + } + ], + "405": [ + { + "x": 21, + "y": 43 + } + ], + "494": [ + { + "x": 25, + "y": 43 + } + ], + "549": [ + { + "x": 27, + "y": 43 + } + ], + "604": [ + { + "x": 29, + "y": 43 + } + ], + "690": [ + { + "x": 33, + "y": 43 + } + ], + "745": [ + { + "x": 35, + "y": 43 + } + ], + "800": [ + { + "x": 37, + "y": 43 + } + ], + "889": [ + { + "x": 41, + "y": 43 + } + ], + "944": [ + { + "x": 43, + "y": 43 + } + ], + "999": [ + { + "x": 45, + "y": 43 + } + ], + "1085": [ + { + "x": 49, + "y": 43 + } + ], + "1140": [ + { + "x": 51, + "y": 43 + } + ], + "1195": [ + { + "x": 53, + "y": 43 + } + ], + "1284": [ + { + "x": 57, + "y": 43 + } + ], + "1339": [ + { + "x": 59, + "y": 43 + } + ], + "1394": [ + { + "x": 61, + "y": 43 + } + ], + "1468": [ + { + "x": 65, + "y": 43 + } + ], + "1509": [ + { + "x": 67, + "y": 43 + } + ], + "1550": [ + { + "x": 69, + "y": 43 + } + ], + "1615": [ + { + "x": 73, + "y": 43 + } + ], + "1656": [ + { + "x": 75, + "y": 43 + } + ], + "1695": [ + { + "x": 77, + "y": 43 + } + ], + "3": [ + { + "x": 1, + "y": 44 + } + ], + "37": [ + { + "x": 2, + "y": 44 + } + ], + "44": [ + { + "x": 3, + "y": 44 + } + ], + "78": [ + { + "x": 4, + "y": 44 + } + ], + "85": [ + { + "x": 5, + "y": 44 + } + ], + "119": [ + { + "x": 6, + "y": 44 + } + ], + "125": [ + { + "x": 7, + "y": 44 + } + ], + "143": [ + { + "x": 8, + "y": 44 + } + ], + "150": [ + { + "x": 9, + "y": 44 + } + ], + "183": [ + { + "x": 10, + "y": 44 + } + ], + "191": [ + { + "x": 11, + "y": 44 + } + ], + "224": [ + { + "x": 12, + "y": 44 + } + ], + "232": [ + { + "x": 13, + "y": 44 + } + ], + "265": [ + { + "x": 14, + "y": 44 + } + ], + "270": [ + { + "x": 15, + "y": 44 + } + ], + "287": [ + { + "x": 16, + "y": 44 + } + ], + "294": [ + { + "x": 17, + "y": 44 + } + ], + "340": [ + { + "x": 18, + "y": 44 + } + ], + "349": [ + { + "x": 19, + "y": 44 + } + ], + "395": [ + { + "x": 20, + "y": 44 + } + ], + "404": [ + { + "x": 21, + "y": 44 + } + ], + "450": [ + { + "x": 22, + "y": 44 + } + ], + "458": [ + { + "x": 23, + "y": 44 + } + ], + "484": [ + { + "x": 24, + "y": 44 + } + ], + "493": [ + { + "x": 25, + "y": 44 + } + ], + "538": [ + { + "x": 26, + "y": 44 + } + ], + "548": [ + { + "x": 27, + "y": 44 + } + ], + "593": [ + { + "x": 28, + "y": 44 + } + ], + "603": [ + { + "x": 29, + "y": 44 + } + ], + "648": [ + { + "x": 30, + "y": 44 + } + ], + "655": [ + { + "x": 31, + "y": 44 + } + ], + "680": [ + { + "x": 32, + "y": 44 + } + ], + "689": [ + { + "x": 33, + "y": 44 + } + ], + "735": [ + { + "x": 34, + "y": 44 + } + ], + "744": [ + { + "x": 35, + "y": 44 + } + ], + "790": [ + { + "x": 36, + "y": 44 + } + ], + "799": [ + { + "x": 37, + "y": 44 + } + ], + "845": [ + { + "x": 38, + "y": 44 + } + ], + "853": [ + { + "x": 39, + "y": 44 + } + ], + "879": [ + { + "x": 40, + "y": 44 + } + ], + "888": [ + { + "x": 41, + "y": 44 + } + ], + "933": [ + { + "x": 42, + "y": 44 + } + ], + "943": [ + { + "x": 43, + "y": 44 + } + ], + "988": [ + { + "x": 44, + "y": 44 + } + ], + "998": [ + { + "x": 45, + "y": 44 + } + ], + "1043": [ + { + "x": 46, + "y": 44 + } + ], + "1050": [ + { + "x": 47, + "y": 44 + } + ], + "1075": [ + { + "x": 48, + "y": 44 + } + ], + "1084": [ + { + "x": 49, + "y": 44 + } + ], + "1130": [ + { + "x": 50, + "y": 44 + } + ], + "1139": [ + { + "x": 51, + "y": 44 + } + ], + "1185": [ + { + "x": 52, + "y": 44 + } + ], + "1194": [ + { + "x": 53, + "y": 44 + } + ], + "1240": [ + { + "x": 54, + "y": 44 + } + ], + "1248": [ + { + "x": 55, + "y": 44 + } + ], + "1274": [ + { + "x": 56, + "y": 44 + } + ], + "1283": [ + { + "x": 57, + "y": 44 + } + ], + "1328": [ + { + "x": 58, + "y": 44 + } + ], + "1338": [ + { + "x": 59, + "y": 44 + } + ], + "1383": [ + { + "x": 60, + "y": 44 + } + ], + "1393": [ + { + "x": 61, + "y": 44 + } + ], + "1438": [ + { + "x": 62, + "y": 44 + } + ], + "1443": [ + { + "x": 63, + "y": 44 + } + ], + "1460": [ + { + "x": 64, + "y": 44 + } + ], + "1467": [ + { + "x": 65, + "y": 44 + } + ], + "1501": [ + { + "x": 66, + "y": 44 + } + ], + "1508": [ + { + "x": 67, + "y": 44 + } + ], + "1542": [ + { + "x": 68, + "y": 44 + } + ], + "1549": [ + { + "x": 69, + "y": 44 + } + ], + "1583": [ + { + "x": 70, + "y": 44 + } + ], + "1589": [ + { + "x": 71, + "y": 44 + } + ], + "1607": [ + { + "x": 72, + "y": 44 + } + ], + "1614": [ + { + "x": 73, + "y": 44 + } + ], + "1647": [ + { + "x": 74, + "y": 44 + } + ], + "1655": [ + { + "x": 75, + "y": 44 + } + ], + "1688": [ + { + "x": 76, + "y": 44 + } + ], + "1694": [ + { + "x": 77, + "y": 44 + } + ], + "2": [ + { + "x": 1, + "y": 45 + } + ], + "43": [ + { + "x": 3, + "y": 45 + } + ], + "84": [ + { + "x": 5, + "y": 45 + } + ], + "149": [ + { + "x": 9, + "y": 45 + } + ], + "190": [ + { + "x": 11, + "y": 45 + } + ], + "231": [ + { + "x": 13, + "y": 45 + } + ], + "293": [ + { + "x": 17, + "y": 45 + } + ], + "348": [ + { + "x": 19, + "y": 45 + } + ], + "403": [ + { + "x": 21, + "y": 45 + } + ], + "492": [ + { + "x": 25, + "y": 45 + } + ], + "547": [ + { + "x": 27, + "y": 45 + } + ], + "602": [ + { + "x": 29, + "y": 45 + } + ], + "688": [ + { + "x": 33, + "y": 45 + } + ], + "743": [ + { + "x": 35, + "y": 45 + } + ], + "798": [ + { + "x": 37, + "y": 45 + } + ], + "887": [ + { + "x": 41, + "y": 45 + } + ], + "942": [ + { + "x": 43, + "y": 45 + } + ], + "997": [ + { + "x": 45, + "y": 45 + } + ], + "1083": [ + { + "x": 49, + "y": 45 + } + ], + "1138": [ + { + "x": 51, + "y": 45 + } + ], + "1193": [ + { + "x": 53, + "y": 45 + } + ], + "1282": [ + { + "x": 57, + "y": 45 + } + ], + "1337": [ + { + "x": 59, + "y": 45 + } + ], + "1392": [ + { + "x": 61, + "y": 45 + } + ], + "1466": [ + { + "x": 65, + "y": 45 + } + ], + "1507": [ + { + "x": 67, + "y": 45 + } + ], + "1548": [ + { + "x": 69, + "y": 45 + } + ], + "1613": [ + { + "x": 73, + "y": 45 + } + ], + "1654": [ + { + "x": 75, + "y": 45 + } + ], + "1693": [ + { + "x": 77, + "y": 45 + } + ], + "189": [ + { + "x": 11, + "y": 46 + } + ], + "230": [ + { + "x": 13, + "y": 46 + } + ], + "546": [ + { + "x": 27, + "y": 46 + } + ], + "601": [ + { + "x": 29, + "y": 46 + } + ], + "941": [ + { + "x": 43, + "y": 46 + } + ], + "996": [ + { + "x": 45, + "y": 46 + } + ], + "1336": [ + { + "x": 59, + "y": 46 + } + ], + "1391": [ + { + "x": 61, + "y": 46 + } + ], + "1653": [ + { + "x": 75, + "y": 46 + } + ], + "1692": [ + { + "x": 77, + "y": 46 + } + ], + "1": [ + { + "x": 1, + "y": 47 + } + ], + "36": [ + { + "x": 2, + "y": 47 + } + ], + "42": [ + { + "x": 3, + "y": 47 + } + ], + "77": [ + { + "x": 4, + "y": 47 + } + ], + "83": [ + { + "x": 5, + "y": 47 + } + ], + "118": [ + { + "x": 6, + "y": 47 + } + ], + "124": [ + { + "x": 7, + "y": 47 + } + ], + "142": [ + { + "x": 8, + "y": 47 + } + ], + "148": [ + { + "x": 9, + "y": 47 + } + ], + "292": [ + { + "x": 17, + "y": 47 + } + ], + "339": [ + { + "x": 18, + "y": 47 + } + ], + "347": [ + { + "x": 19, + "y": 47 + } + ], + "394": [ + { + "x": 20, + "y": 47 + } + ], + "402": [ + { + "x": 21, + "y": 47 + } + ], + "449": [ + { + "x": 22, + "y": 47 + } + ], + "457": [ + { + "x": 23, + "y": 47 + } + ], + "483": [ + { + "x": 24, + "y": 47 + } + ], + "491": [ + { + "x": 25, + "y": 47 + } + ], + "687": [ + { + "x": 33, + "y": 47 + } + ], + "734": [ + { + "x": 34, + "y": 47 + } + ], + "742": [ + { + "x": 35, + "y": 47 + } + ], + "789": [ + { + "x": 36, + "y": 47 + } + ], + "797": [ + { + "x": 37, + "y": 47 + } + ], + "844": [ + { + "x": 38, + "y": 47 + } + ], + "852": [ + { + "x": 39, + "y": 47 + } + ], + "878": [ + { + "x": 40, + "y": 47 + } + ], + "886": [ + { + "x": 41, + "y": 47 + } + ], + "1082": [ + { + "x": 49, + "y": 47 + } + ], + "1129": [ + { + "x": 50, + "y": 47 + } + ], + "1137": [ + { + "x": 51, + "y": 47 + } + ], + "1184": [ + { + "x": 52, + "y": 47 + } + ], + "1192": [ + { + "x": 53, + "y": 47 + } + ], + "1239": [ + { + "x": 54, + "y": 47 + } + ], + "1247": [ + { + "x": 55, + "y": 47 + } + ], + "1273": [ + { + "x": 56, + "y": 47 + } + ], + "1281": [ + { + "x": 57, + "y": 47 + } + ], + "1465": [ + { + "x": 65, + "y": 47 + } + ], + "1500": [ + { + "x": 66, + "y": 47 + } + ], + "1506": [ + { + "x": 67, + "y": 47 + } + ], + "1541": [ + { + "x": 68, + "y": 47 + } + ], + "1547": [ + { + "x": 69, + "y": 47 + } + ], + "1582": [ + { + "x": 70, + "y": 47 + } + ], + "1588": [ + { + "x": 71, + "y": 47 + } + ], + "1606": [ + { + "x": 72, + "y": 47 + } + ], + "1612": [ + { + "x": 73, + "y": 47 + } + ] + }, + "coordinate_to_path_id": { + "17,0": 338, + "18,0": 346, + "19,0": 393, + "20,0": 401, + "21,0": 448, + "22,0": 456, + "23,0": 482, + "24,0": 490, + "25,0": 537, + "26,0": 544, + "27,0": 592, + "28,0": 599, + "29,0": 647, + "30,0": 654, + "31,0": 679, + "32,0": 686, + "33,0": 733, + "34,0": 741, + "35,0": 788, + "36,0": 796, + "37,0": 843, + "38,0": 851, + "39,0": 877, + "40,0": 885, + "41,0": 932, + "42,0": 939, + "43,0": 987, + "44,0": 994, + "45,0": 1042, + "46,0": 1049, + "47,0": 1074, + "48,0": 1081, + "49,0": 1128, + "50,0": 1136, + "51,0": 1183, + "52,0": 1191, + "53,0": 1238, + "54,0": 1246, + "55,0": 1272, + "56,0": 1280, + "57,0": 1327, + "58,0": 1334, + "59,0": 1382, + "60,0": 1389, + "61,0": 1437, + "17,1": 337, + "19,1": 392, + "21,1": 447, + "25,1": 536, + "27,1": 591, + "29,1": 646, + "33,1": 732, + "35,1": 787, + "37,1": 842, + "41,1": 931, + "43,1": 986, + "45,1": 1041, + "49,1": 1127, + "51,1": 1182, + "53,1": 1237, + "57,1": 1326, + "59,1": 1381, + "61,1": 1436, + "17,2": 336, + "19,2": 391, + "21,2": 446, + "23,2": 481, + "25,2": 535, + "27,2": 590, + "29,2": 645, + "31,2": 678, + "33,2": 731, + "35,2": 786, + "37,2": 841, + "39,2": 876, + "41,2": 930, + "43,2": 985, + "45,2": 1040, + "47,2": 1073, + "49,2": 1126, + "51,2": 1181, + "53,2": 1236, + "55,2": 1271, + "57,2": 1325, + "59,2": 1380, + "61,2": 1435, + "17,3": 335, + "19,3": 390, + "21,3": 445, + "23,3": 480, + "25,3": 534, + "27,3": 589, + "29,3": 644, + "31,3": 677, + "33,3": 730, + "35,3": 785, + "37,3": 840, + "39,3": 875, + "41,3": 929, + "43,3": 984, + "45,3": 1039, + "47,3": 1072, + "49,3": 1125, + "51,3": 1180, + "53,3": 1235, + "55,3": 1270, + "57,3": 1324, + "59,3": 1379, + "61,3": 1434, + "17,4": 334, + "19,4": 389, + "21,4": 444, + "23,4": 479, + "25,4": 533, + "27,4": 588, + "29,4": 643, + "31,4": 676, + "33,4": 729, + "35,4": 784, + "37,4": 839, + "39,4": 874, + "41,4": 928, + "43,4": 983, + "45,4": 1038, + "47,4": 1071, + "49,4": 1124, + "51,4": 1179, + "53,4": 1234, + "55,4": 1269, + "57,4": 1323, + "59,4": 1378, + "61,4": 1433, + "17,5": 333, + "19,5": 388, + "21,5": 443, + "25,5": 532, + "27,5": 587, + "29,5": 642, + "33,5": 728, + "35,5": 783, + "37,5": 838, + "41,5": 927, + "43,5": 982, + "45,5": 1037, + "49,5": 1123, + "51,5": 1178, + "53,5": 1233, + "57,5": 1322, + "59,5": 1377, + "61,5": 1432, + "17,6": 332, + "18,6": 345, + "19,6": 387, + "20,6": 400, + "21,6": 442, + "22,6": 455, + "23,6": 478, + "24,6": 489, + "25,6": 531, + "26,6": 543, + "27,6": 586, + "28,6": 598, + "29,6": 641, + "30,6": 653, + "31,6": 675, + "32,6": 685, + "33,6": 727, + "34,6": 740, + "35,6": 782, + "36,6": 795, + "37,6": 837, + "38,6": 850, + "39,6": 873, + "40,6": 884, + "41,6": 926, + "42,6": 938, + "43,6": 981, + "44,6": 993, + "45,6": 1036, + "46,6": 1048, + "47,6": 1070, + "48,6": 1080, + "49,6": 1122, + "50,6": 1135, + "51,6": 1177, + "52,6": 1190, + "53,6": 1232, + "54,6": 1245, + "55,6": 1268, + "56,6": 1279, + "57,6": 1321, + "58,6": 1333, + "59,6": 1376, + "60,6": 1388, + "61,6": 1431, + "17,7": 331, + "19,7": 386, + "21,7": 441, + "25,7": 530, + "27,7": 585, + "29,7": 640, + "33,7": 726, + "35,7": 781, + "37,7": 836, + "41,7": 925, + "43,7": 980, + "45,7": 1035, + "49,7": 1121, + "51,7": 1176, + "53,7": 1231, + "57,7": 1320, + "59,7": 1375, + "61,7": 1430, + "17,8": 330, + "19,8": 385, + "21,8": 440, + "23,8": 477, + "25,8": 529, + "27,8": 584, + "29,8": 639, + "31,8": 674, + "33,8": 725, + "35,8": 780, + "37,8": 835, + "39,8": 872, + "41,8": 924, + "43,8": 979, + "45,8": 1034, + "47,8": 1069, + "49,8": 1120, + "51,8": 1175, + "53,8": 1230, + "55,8": 1267, + "57,8": 1319, + "59,8": 1374, + "61,8": 1429, + "17,9": 329, + "19,9": 384, + "21,9": 439, + "23,9": 476, + "25,9": 528, + "27,9": 583, + "29,9": 638, + "31,9": 673, + "33,9": 724, + "35,9": 779, + "37,9": 834, + "39,9": 871, + "41,9": 923, + "43,9": 978, + "45,9": 1033, + "47,9": 1068, + "49,9": 1119, + "51,9": 1174, + "53,9": 1229, + "55,9": 1266, + "57,9": 1318, + "59,9": 1373, + "61,9": 1428, + "17,10": 328, + "19,10": 383, + "21,10": 438, + "23,10": 475, + "25,10": 527, + "27,10": 582, + "29,10": 637, + "31,10": 672, + "33,10": 723, + "35,10": 778, + "37,10": 833, + "39,10": 870, + "41,10": 922, + "43,10": 977, + "45,10": 1032, + "47,10": 1067, + "49,10": 1118, + "51,10": 1173, + "53,10": 1228, + "55,10": 1265, + "57,10": 1317, + "59,10": 1372, + "61,10": 1427, + "17,11": 327, + "19,11": 382, + "21,11": 437, + "25,11": 526, + "27,11": 581, + "29,11": 636, + "33,11": 722, + "35,11": 777, + "37,11": 832, + "41,11": 921, + "43,11": 976, + "45,11": 1031, + "49,11": 1117, + "51,11": 1172, + "53,11": 1227, + "57,11": 1316, + "59,11": 1371, + "61,11": 1426, + "1,12": 35, + "2,12": 41, + "3,12": 76, + "4,12": 82, + "5,12": 117, + "6,12": 123, + "7,12": 141, + "8,12": 147, + "9,12": 182, + "10,12": 187, + "11,12": 223, + "12,12": 228, + "13,12": 264, + "14,12": 269, + "15,12": 286, + "16,12": 291, + "17,12": 326, + "18,12": 344, + "19,12": 381, + "20,12": 399, + "21,12": 436, + "22,12": 454, + "23,12": 474, + "24,12": 488, + "25,12": 525, + "26,12": 542, + "27,12": 580, + "28,12": 597, + "29,12": 635, + "30,12": 652, + "31,12": 671, + "32,12": 684, + "33,12": 721, + "34,12": 739, + "35,12": 776, + "36,12": 794, + "37,12": 831, + "38,12": 849, + "39,12": 869, + "40,12": 883, + "41,12": 920, + "42,12": 937, + "43,12": 975, + "44,12": 992, + "45,12": 1030, + "46,12": 1047, + "47,12": 1066, + "48,12": 1079, + "49,12": 1116, + "50,12": 1134, + "51,12": 1171, + "52,12": 1189, + "53,12": 1226, + "54,12": 1244, + "55,12": 1264, + "56,12": 1278, + "57,12": 1315, + "58,12": 1332, + "59,12": 1370, + "60,12": 1387, + "61,12": 1425, + "62,12": 1442, + "63,12": 1459, + "64,12": 1464, + "65,12": 1499, + "66,12": 1505, + "67,12": 1540, + "68,12": 1546, + "69,12": 1581, + "70,12": 1587, + "71,12": 1605, + "72,12": 1611, + "73,12": 1646, + "74,12": 1651, + "75,12": 1687, + "1,13": 34, + "3,13": 75, + "5,13": 116, + "9,13": 181, + "11,13": 222, + "13,13": 263, + "17,13": 325, + "19,13": 380, + "21,13": 435, + "25,13": 524, + "27,13": 579, + "29,13": 634, + "33,13": 720, + "35,13": 775, + "37,13": 830, + "41,13": 919, + "43,13": 974, + "45,13": 1029, + "49,13": 1115, + "51,13": 1170, + "53,13": 1225, + "57,13": 1314, + "59,13": 1369, + "61,13": 1424, + "65,13": 1498, + "67,13": 1539, + "69,13": 1580, + "73,13": 1645, + "75,13": 1686, + "1,14": 33, + "3,14": 74, + "5,14": 115, + "7,14": 140, + "9,14": 180, + "11,14": 221, + "13,14": 262, + "15,14": 285, + "17,14": 324, + "19,14": 379, + "21,14": 434, + "23,14": 473, + "25,14": 523, + "27,14": 578, + "29,14": 633, + "31,14": 670, + "33,14": 719, + "35,14": 774, + "37,14": 829, + "39,14": 868, + "41,14": 918, + "43,14": 973, + "45,14": 1028, + "47,14": 1065, + "49,14": 1114, + "51,14": 1169, + "53,14": 1224, + "55,14": 1263, + "57,14": 1313, + "59,14": 1368, + "61,14": 1423, + "63,14": 1458, + "65,14": 1497, + "67,14": 1538, + "69,14": 1579, + "71,14": 1604, + "73,14": 1644, + "75,14": 1685, + "1,15": 32, + "3,15": 73, + "5,15": 114, + "9,15": 179, + "11,15": 220, + "13,15": 261, + "17,15": 323, + "19,15": 378, + "21,15": 433, + "25,15": 522, + "27,15": 577, + "29,15": 632, + "33,15": 718, + "35,15": 773, + "37,15": 828, + "41,15": 917, + "43,15": 972, + "45,15": 1027, + "49,15": 1113, + "51,15": 1168, + "53,15": 1223, + "57,15": 1312, + "59,15": 1367, + "61,15": 1422, + "65,15": 1496, + "67,15": 1537, + "69,15": 1578, + "73,15": 1643, + "75,15": 1684, + "1,16": 31, + "3,16": 72, + "5,16": 113, + "7,16": 139, + "9,16": 178, + "11,16": 219, + "13,16": 260, + "15,16": 284, + "17,16": 322, + "19,16": 377, + "21,16": 432, + "23,16": 472, + "25,16": 521, + "27,16": 576, + "29,16": 631, + "31,16": 669, + "33,16": 717, + "35,16": 772, + "37,16": 827, + "39,16": 867, + "41,16": 916, + "43,16": 971, + "45,16": 1026, + "47,16": 1064, + "49,16": 1112, + "51,16": 1167, + "53,16": 1222, + "55,16": 1262, + "57,16": 1311, + "59,16": 1366, + "61,16": 1421, + "63,16": 1457, + "65,16": 1495, + "67,16": 1536, + "69,16": 1577, + "71,16": 1603, + "73,16": 1642, + "75,16": 1683, + "1,17": 30, + "3,17": 71, + "5,17": 112, + "7,17": 138, + "9,17": 177, + "11,17": 218, + "13,17": 259, + "15,17": 283, + "17,17": 321, + "19,17": 376, + "21,17": 431, + "23,17": 471, + "25,17": 520, + "27,17": 575, + "29,17": 630, + "31,17": 668, + "33,17": 716, + "35,17": 771, + "37,17": 826, + "39,17": 866, + "41,17": 915, + "43,17": 970, + "45,17": 1025, + "47,17": 1063, + "49,17": 1111, + "51,17": 1166, + "53,17": 1221, + "55,17": 1261, + "57,17": 1310, + "59,17": 1365, + "61,17": 1420, + "63,17": 1456, + "65,17": 1494, + "67,17": 1535, + "69,17": 1576, + "71,17": 1602, + "73,17": 1641, + "75,17": 1682, + "1,18": 29, + "3,18": 70, + "5,18": 111, + "7,18": 137, + "9,18": 176, + "11,18": 217, + "13,18": 258, + "15,18": 282, + "17,18": 320, + "19,18": 375, + "21,18": 430, + "23,18": 470, + "25,18": 519, + "27,18": 574, + "29,18": 629, + "31,18": 667, + "33,18": 715, + "35,18": 770, + "37,18": 825, + "39,18": 865, + "41,18": 914, + "43,18": 969, + "45,18": 1024, + "47,18": 1062, + "49,18": 1110, + "51,18": 1165, + "53,18": 1220, + "55,18": 1260, + "57,18": 1309, + "59,18": 1364, + "61,18": 1419, + "63,18": 1455, + "65,18": 1493, + "67,18": 1534, + "69,18": 1575, + "71,18": 1601, + "73,18": 1640, + "75,18": 1681, + "1,19": 28, + "3,19": 69, + "5,19": 110, + "9,19": 175, + "11,19": 216, + "13,19": 257, + "17,19": 319, + "19,19": 374, + "21,19": 429, + "25,19": 518, + "27,19": 573, + "29,19": 628, + "33,19": 714, + "35,19": 769, + "37,19": 824, + "41,19": 913, + "43,19": 968, + "45,19": 1023, + "49,19": 1109, + "51,19": 1164, + "53,19": 1219, + "57,19": 1308, + "59,19": 1363, + "61,19": 1418, + "65,19": 1492, + "67,19": 1533, + "69,19": 1574, + "73,19": 1639, + "75,19": 1680, + "1,20": 27, + "3,20": 68, + "5,20": 109, + "7,20": 136, + "9,20": 174, + "11,20": 215, + "13,20": 256, + "15,20": 281, + "17,20": 318, + "19,20": 373, + "21,20": 428, + "23,20": 469, + "25,20": 517, + "27,20": 572, + "29,20": 627, + "31,20": 666, + "33,20": 713, + "35,20": 768, + "37,20": 823, + "39,20": 864, + "41,20": 912, + "43,20": 967, + "45,20": 1022, + "47,20": 1061, + "49,20": 1108, + "51,20": 1163, + "53,20": 1218, + "55,20": 1259, + "57,20": 1307, + "59,20": 1362, + "61,20": 1417, + "63,20": 1454, + "65,20": 1491, + "67,20": 1532, + "69,20": 1573, + "71,20": 1600, + "73,20": 1638, + "75,20": 1679, + "1,21": 26, + "3,21": 67, + "5,21": 108, + "9,21": 173, + "11,21": 214, + "13,21": 255, + "17,21": 317, + "19,21": 372, + "21,21": 427, + "25,21": 516, + "27,21": 571, + "29,21": 626, + "33,21": 712, + "35,21": 767, + "37,21": 822, + "41,21": 911, + "43,21": 966, + "45,21": 1021, + "49,21": 1107, + "51,21": 1162, + "53,21": 1217, + "57,21": 1306, + "59,21": 1361, + "61,21": 1416, + "65,21": 1490, + "67,21": 1531, + "69,21": 1572, + "73,21": 1637, + "75,21": 1678, + "1,22": 25, + "2,22": 40, + "3,22": 66, + "4,22": 81, + "5,22": 107, + "6,22": 122, + "7,22": 135, + "8,22": 146, + "9,22": 172, + "10,22": 186, + "11,22": 213, + "12,22": 227, + "13,22": 254, + "14,22": 268, + "15,22": 280, + "16,22": 290, + "17,22": 316, + "18,22": 343, + "19,22": 371, + "20,22": 398, + "21,22": 426, + "22,22": 453, + "23,22": 468, + "24,22": 487, + "25,22": 515, + "26,22": 541, + "27,22": 570, + "28,22": 596, + "29,22": 625, + "30,22": 651, + "31,22": 665, + "32,22": 683, + "33,22": 711, + "34,22": 738, + "35,22": 766, + "36,22": 793, + "37,22": 821, + "38,22": 848, + "39,22": 863, + "40,22": 882, + "41,22": 910, + "42,22": 936, + "43,22": 965, + "44,22": 991, + "45,22": 1020, + "46,22": 1046, + "47,22": 1060, + "48,22": 1078, + "49,22": 1106, + "50,22": 1133, + "51,22": 1161, + "52,22": 1188, + "53,22": 1216, + "54,22": 1243, + "55,22": 1258, + "56,22": 1277, + "57,22": 1305, + "58,22": 1331, + "59,22": 1360, + "60,22": 1386, + "61,22": 1415, + "62,22": 1441, + "63,22": 1453, + "64,22": 1463, + "65,22": 1489, + "66,22": 1504, + "67,22": 1530, + "68,22": 1545, + "69,22": 1571, + "70,22": 1586, + "71,22": 1599, + "72,22": 1610, + "73,22": 1636, + "74,22": 1650, + "75,22": 1677, + "1,23": 24, + "3,23": 65, + "5,23": 106, + "9,23": 171, + "11,23": 212, + "13,23": 253, + "17,23": 315, + "19,23": 370, + "21,23": 425, + "25,23": 514, + "27,23": 569, + "29,23": 624, + "33,23": 710, + "35,23": 765, + "37,23": 820, + "41,23": 909, + "43,23": 964, + "45,23": 1019, + "49,23": 1105, + "51,23": 1160, + "53,23": 1215, + "57,23": 1304, + "59,23": 1359, + "61,23": 1414, + "65,23": 1488, + "67,23": 1529, + "69,23": 1570, + "73,23": 1635, + "75,23": 1676, + "1,24": 23, + "3,24": 64, + "5,24": 105, + "9,24": 170, + "11,24": 211, + "13,24": 252, + "17,24": 314, + "19,24": 369, + "21,24": 424, + "25,24": 513, + "27,24": 568, + "29,24": 623, + "33,24": 709, + "35,24": 764, + "37,24": 819, + "41,24": 908, + "43,24": 963, + "45,24": 1018, + "49,24": 1104, + "51,24": 1159, + "53,24": 1214, + "57,24": 1303, + "59,24": 1358, + "61,24": 1413, + "65,24": 1487, + "67,24": 1528, + "69,24": 1569, + "73,24": 1634, + "75,24": 1675, + "1,25": 22, + "3,25": 63, + "5,25": 104, + "9,25": 169, + "11,25": 210, + "13,25": 251, + "17,25": 313, + "19,25": 368, + "21,25": 423, + "25,25": 512, + "27,25": 567, + "29,25": 622, + "33,25": 708, + "35,25": 763, + "37,25": 818, + "41,25": 907, + "43,25": 962, + "45,25": 1017, + "49,25": 1103, + "51,25": 1158, + "53,25": 1213, + "57,25": 1302, + "59,25": 1357, + "61,25": 1412, + "65,25": 1486, + "67,25": 1527, + "69,25": 1568, + "73,25": 1633, + "75,25": 1674, + "1,26": 21, + "3,26": 62, + "5,26": 103, + "9,26": 168, + "11,26": 209, + "13,26": 250, + "17,26": 312, + "19,26": 367, + "21,26": 422, + "25,26": 511, + "27,26": 566, + "29,26": 621, + "33,26": 707, + "35,26": 762, + "37,26": 817, + "41,26": 906, + "43,26": 961, + "45,26": 1016, + "49,26": 1102, + "51,26": 1157, + "53,26": 1212, + "57,26": 1301, + "59,26": 1356, + "61,26": 1411, + "65,26": 1485, + "67,26": 1526, + "69,26": 1567, + "73,26": 1632, + "75,26": 1673, + "1,27": 20, + "3,27": 61, + "5,27": 102, + "9,27": 167, + "11,27": 208, + "13,27": 249, + "17,27": 311, + "19,27": 366, + "21,27": 421, + "25,27": 510, + "27,27": 565, + "29,27": 620, + "33,27": 706, + "35,27": 761, + "37,27": 816, + "41,27": 905, + "43,27": 960, + "45,27": 1015, + "49,27": 1101, + "51,27": 1156, + "53,27": 1211, + "57,27": 1300, + "59,27": 1355, + "61,27": 1410, + "65,27": 1484, + "67,27": 1525, + "69,27": 1566, + "73,27": 1631, + "75,27": 1672, + "1,28": 19, + "3,28": 60, + "5,28": 101, + "7,28": 134, + "9,28": 166, + "11,28": 207, + "13,28": 248, + "15,28": 279, + "17,28": 310, + "19,28": 365, + "21,28": 420, + "23,28": 467, + "25,28": 509, + "27,28": 564, + "29,28": 619, + "31,28": 664, + "33,28": 705, + "35,28": 760, + "37,28": 815, + "39,28": 862, + "41,28": 904, + "43,28": 959, + "45,28": 1014, + "47,28": 1059, + "49,28": 1100, + "51,28": 1155, + "53,28": 1210, + "55,28": 1257, + "57,28": 1299, + "59,28": 1354, + "61,28": 1409, + "63,28": 1452, + "65,28": 1483, + "67,28": 1524, + "69,28": 1565, + "71,28": 1598, + "73,28": 1630, + "75,28": 1671, + "1,29": 18, + "3,29": 59, + "5,29": 100, + "9,29": 165, + "11,29": 206, + "13,29": 247, + "17,29": 309, + "19,29": 364, + "21,29": 419, + "25,29": 508, + "27,29": 563, + "29,29": 618, + "33,29": 704, + "35,29": 759, + "37,29": 814, + "41,29": 903, + "43,29": 958, + "45,29": 1013, + "49,29": 1099, + "51,29": 1154, + "53,29": 1209, + "57,29": 1298, + "59,29": 1353, + "61,29": 1408, + "65,29": 1482, + "67,29": 1523, + "69,29": 1564, + "73,29": 1629, + "75,29": 1670, + "1,30": 17, + "3,30": 58, + "5,30": 99, + "7,30": 133, + "9,30": 164, + "11,30": 205, + "13,30": 246, + "15,30": 278, + "17,30": 308, + "19,30": 363, + "21,30": 418, + "23,30": 466, + "25,30": 507, + "27,30": 562, + "29,30": 617, + "31,30": 663, + "33,30": 703, + "35,30": 758, + "37,30": 813, + "39,30": 861, + "41,30": 902, + "43,30": 957, + "45,30": 1012, + "47,30": 1058, + "49,30": 1098, + "51,30": 1153, + "53,30": 1208, + "55,30": 1256, + "57,30": 1297, + "59,30": 1352, + "61,30": 1407, + "63,30": 1451, + "65,30": 1481, + "67,30": 1522, + "69,30": 1563, + "71,30": 1597, + "73,30": 1628, + "75,30": 1669, + "1,31": 16, + "3,31": 57, + "5,31": 98, + "9,31": 163, + "11,31": 204, + "13,31": 245, + "17,31": 307, + "19,31": 362, + "21,31": 417, + "25,31": 506, + "27,31": 561, + "29,31": 616, + "33,31": 702, + "35,31": 757, + "37,31": 812, + "41,31": 901, + "43,31": 956, + "45,31": 1011, + "49,31": 1097, + "51,31": 1152, + "53,31": 1207, + "57,31": 1296, + "59,31": 1351, + "61,31": 1406, + "65,31": 1480, + "67,31": 1521, + "69,31": 1562, + "73,31": 1627, + "75,31": 1668, + "1,32": 15, + "2,32": 39, + "3,32": 56, + "4,32": 80, + "5,32": 97, + "6,32": 121, + "7,32": 132, + "8,32": 145, + "9,32": 162, + "10,32": 185, + "11,32": 203, + "12,32": 226, + "13,32": 244, + "14,32": 267, + "15,32": 277, + "16,32": 289, + "17,32": 306, + "18,32": 342, + "19,32": 361, + "20,32": 397, + "21,32": 416, + "22,32": 452, + "23,32": 465, + "24,32": 486, + "25,32": 505, + "26,32": 540, + "27,32": 560, + "28,32": 595, + "29,32": 615, + "30,32": 650, + "31,32": 662, + "32,32": 682, + "33,32": 701, + "34,32": 737, + "35,32": 756, + "36,32": 792, + "37,32": 811, + "38,32": 847, + "39,32": 860, + "40,32": 881, + "41,32": 900, + "42,32": 935, + "43,32": 955, + "44,32": 990, + "45,32": 1010, + "46,32": 1045, + "47,32": 1057, + "48,32": 1077, + "49,32": 1096, + "50,32": 1132, + "51,32": 1151, + "52,32": 1187, + "53,32": 1206, + "54,32": 1242, + "55,32": 1255, + "56,32": 1276, + "57,32": 1295, + "58,32": 1330, + "59,32": 1350, + "60,32": 1385, + "61,32": 1405, + "62,32": 1440, + "63,32": 1450, + "64,32": 1462, + "65,32": 1479, + "66,32": 1503, + "67,32": 1520, + "68,32": 1544, + "69,32": 1561, + "70,32": 1585, + "71,32": 1596, + "72,32": 1609, + "73,32": 1626, + "74,32": 1649, + "75,32": 1667, + "76,32": 1690, + "77,32": 1706, + "1,33": 14, + "3,33": 55, + "5,33": 96, + "9,33": 161, + "11,33": 202, + "13,33": 243, + "17,33": 305, + "19,33": 360, + "21,33": 415, + "25,33": 504, + "27,33": 559, + "29,33": 614, + "33,33": 700, + "35,33": 755, + "37,33": 810, + "41,33": 899, + "43,33": 954, + "45,33": 1009, + "49,33": 1095, + "51,33": 1150, + "53,33": 1205, + "57,33": 1294, + "59,33": 1349, + "61,33": 1404, + "65,33": 1478, + "67,33": 1519, + "69,33": 1560, + "73,33": 1625, + "75,33": 1666, + "77,33": 1705, + "1,34": 13, + "3,34": 54, + "5,34": 95, + "7,34": 131, + "9,34": 160, + "11,34": 201, + "13,34": 242, + "15,34": 276, + "17,34": 304, + "19,34": 359, + "21,34": 414, + "23,34": 464, + "25,34": 503, + "27,34": 558, + "29,34": 613, + "31,34": 661, + "33,34": 699, + "35,34": 754, + "37,34": 809, + "39,34": 859, + "41,34": 898, + "43,34": 953, + "45,34": 1008, + "47,34": 1056, + "49,34": 1094, + "51,34": 1149, + "53,34": 1204, + "55,34": 1254, + "57,34": 1293, + "59,34": 1348, + "61,34": 1403, + "63,34": 1449, + "65,34": 1477, + "67,34": 1518, + "69,34": 1559, + "71,34": 1595, + "73,34": 1624, + "75,34": 1665, + "77,34": 1704, + "1,35": 12, + "3,35": 53, + "5,35": 94, + "9,35": 159, + "11,35": 200, + "13,35": 241, + "17,35": 303, + "19,35": 358, + "21,35": 413, + "25,35": 502, + "27,35": 557, + "29,35": 612, + "33,35": 698, + "35,35": 753, + "37,35": 808, + "41,35": 897, + "43,35": 952, + "45,35": 1007, + "49,35": 1093, + "51,35": 1148, + "53,35": 1203, + "57,35": 1292, + "59,35": 1347, + "61,35": 1402, + "65,35": 1476, + "67,35": 1517, + "69,35": 1558, + "73,35": 1623, + "75,35": 1664, + "77,35": 1703, + "1,36": 11, + "3,36": 52, + "5,36": 93, + "7,36": 130, + "9,36": 158, + "11,36": 199, + "13,36": 240, + "15,36": 275, + "17,36": 302, + "19,36": 357, + "21,36": 412, + "23,36": 463, + "25,36": 501, + "27,36": 556, + "29,36": 611, + "31,36": 660, + "33,36": 697, + "35,36": 752, + "37,36": 807, + "39,36": 858, + "41,36": 896, + "43,36": 951, + "45,36": 1006, + "47,36": 1055, + "49,36": 1092, + "51,36": 1147, + "53,36": 1202, + "55,36": 1253, + "57,36": 1291, + "59,36": 1346, + "61,36": 1401, + "63,36": 1448, + "65,36": 1475, + "67,36": 1516, + "69,36": 1557, + "71,36": 1594, + "73,36": 1622, + "75,36": 1663, + "77,36": 1702, + "1,37": 10, + "3,37": 51, + "5,37": 92, + "7,37": 129, + "9,37": 157, + "11,37": 198, + "13,37": 239, + "15,37": 274, + "17,37": 301, + "19,37": 356, + "21,37": 411, + "23,37": 462, + "25,37": 500, + "27,37": 555, + "29,37": 610, + "31,37": 659, + "33,37": 696, + "35,37": 751, + "37,37": 806, + "39,37": 857, + "41,37": 895, + "43,37": 950, + "45,37": 1005, + "47,37": 1054, + "49,37": 1091, + "51,37": 1146, + "53,37": 1201, + "55,37": 1252, + "57,37": 1290, + "59,37": 1345, + "61,37": 1400, + "63,37": 1447, + "65,37": 1474, + "67,37": 1515, + "69,37": 1556, + "71,37": 1593, + "73,37": 1621, + "75,37": 1662, + "77,37": 1701, + "1,38": 9, + "3,38": 50, + "5,38": 91, + "7,38": 128, + "9,38": 156, + "11,38": 197, + "13,38": 238, + "15,38": 273, + "17,38": 300, + "19,38": 355, + "21,38": 410, + "23,38": 461, + "25,38": 499, + "27,38": 554, + "29,38": 609, + "31,38": 658, + "33,38": 695, + "35,38": 750, + "37,38": 805, + "39,38": 856, + "41,38": 894, + "43,38": 949, + "45,38": 1004, + "47,38": 1053, + "49,38": 1090, + "51,38": 1145, + "53,38": 1200, + "55,38": 1251, + "57,38": 1289, + "59,38": 1344, + "61,38": 1399, + "63,38": 1446, + "65,38": 1473, + "67,38": 1514, + "69,38": 1555, + "71,38": 1592, + "73,38": 1620, + "75,38": 1661, + "77,38": 1700, + "1,39": 8, + "3,39": 49, + "5,39": 90, + "9,39": 155, + "11,39": 196, + "13,39": 237, + "17,39": 299, + "19,39": 354, + "21,39": 409, + "25,39": 498, + "27,39": 553, + "29,39": 608, + "33,39": 694, + "35,39": 749, + "37,39": 804, + "41,39": 893, + "43,39": 948, + "45,39": 1003, + "49,39": 1089, + "51,39": 1144, + "53,39": 1199, + "57,39": 1288, + "59,39": 1343, + "61,39": 1398, + "65,39": 1472, + "67,39": 1513, + "69,39": 1554, + "73,39": 1619, + "75,39": 1660, + "77,39": 1699, + "1,40": 7, + "3,40": 48, + "5,40": 89, + "7,40": 127, + "9,40": 154, + "11,40": 195, + "13,40": 236, + "15,40": 272, + "17,40": 298, + "19,40": 353, + "21,40": 408, + "23,40": 460, + "25,40": 497, + "27,40": 552, + "29,40": 607, + "31,40": 657, + "33,40": 693, + "35,40": 748, + "37,40": 803, + "39,40": 855, + "41,40": 892, + "43,40": 947, + "45,40": 1002, + "47,40": 1052, + "49,40": 1088, + "51,40": 1143, + "53,40": 1198, + "55,40": 1250, + "57,40": 1287, + "59,40": 1342, + "61,40": 1397, + "63,40": 1445, + "65,40": 1471, + "67,40": 1512, + "69,40": 1553, + "71,40": 1591, + "73,40": 1618, + "75,40": 1659, + "77,40": 1698, + "1,41": 6, + "3,41": 47, + "5,41": 88, + "9,41": 153, + "11,41": 194, + "13,41": 235, + "17,41": 297, + "19,41": 352, + "21,41": 407, + "25,41": 496, + "27,41": 551, + "29,41": 606, + "33,41": 692, + "35,41": 747, + "37,41": 802, + "41,41": 891, + "43,41": 946, + "45,41": 1001, + "49,41": 1087, + "51,41": 1142, + "53,41": 1197, + "57,41": 1286, + "59,41": 1341, + "61,41": 1396, + "65,41": 1470, + "67,41": 1511, + "69,41": 1552, + "73,41": 1617, + "75,41": 1658, + "77,41": 1697, + "1,42": 5, + "2,42": 38, + "3,42": 46, + "4,42": 79, + "5,42": 87, + "6,42": 120, + "7,42": 126, + "8,42": 144, + "9,42": 152, + "10,42": 184, + "11,42": 193, + "12,42": 225, + "13,42": 234, + "14,42": 266, + "15,42": 271, + "16,42": 288, + "17,42": 296, + "18,42": 341, + "19,42": 351, + "20,42": 396, + "21,42": 406, + "22,42": 451, + "23,42": 459, + "24,42": 485, + "25,42": 495, + "26,42": 539, + "27,42": 550, + "28,42": 594, + "29,42": 605, + "30,42": 649, + "31,42": 656, + "32,42": 681, + "33,42": 691, + "34,42": 736, + "35,42": 746, + "36,42": 791, + "37,42": 801, + "38,42": 846, + "39,42": 854, + "40,42": 880, + "41,42": 890, + "42,42": 934, + "43,42": 945, + "44,42": 989, + "45,42": 1000, + "46,42": 1044, + "47,42": 1051, + "48,42": 1076, + "49,42": 1086, + "50,42": 1131, + "51,42": 1141, + "52,42": 1186, + "53,42": 1196, + "54,42": 1241, + "55,42": 1249, + "56,42": 1275, + "57,42": 1285, + "58,42": 1329, + "59,42": 1340, + "60,42": 1384, + "61,42": 1395, + "62,42": 1439, + "63,42": 1444, + "64,42": 1461, + "65,42": 1469, + "66,42": 1502, + "67,42": 1510, + "68,42": 1543, + "69,42": 1551, + "70,42": 1584, + "71,42": 1590, + "72,42": 1608, + "73,42": 1616, + "74,42": 1648, + "75,42": 1657, + "76,42": 1689, + "77,42": 1696, + "1,43": 4, + "3,43": 45, + "5,43": 86, + "9,43": 151, + "11,43": 192, + "13,43": 233, + "17,43": 295, + "19,43": 350, + "21,43": 405, + "25,43": 494, + "27,43": 549, + "29,43": 604, + "33,43": 690, + "35,43": 745, + "37,43": 800, + "41,43": 889, + "43,43": 944, + "45,43": 999, + "49,43": 1085, + "51,43": 1140, + "53,43": 1195, + "57,43": 1284, + "59,43": 1339, + "61,43": 1394, + "65,43": 1468, + "67,43": 1509, + "69,43": 1550, + "73,43": 1615, + "75,43": 1656, + "77,43": 1695, + "1,44": 3, + "2,44": 37, + "3,44": 44, + "4,44": 78, + "5,44": 85, + "6,44": 119, + "7,44": 125, + "8,44": 143, + "9,44": 150, + "10,44": 183, + "11,44": 191, + "12,44": 224, + "13,44": 232, + "14,44": 265, + "15,44": 270, + "16,44": 287, + "17,44": 294, + "18,44": 340, + "19,44": 349, + "20,44": 395, + "21,44": 404, + "22,44": 450, + "23,44": 458, + "24,44": 484, + "25,44": 493, + "26,44": 538, + "27,44": 548, + "28,44": 593, + "29,44": 603, + "30,44": 648, + "31,44": 655, + "32,44": 680, + "33,44": 689, + "34,44": 735, + "35,44": 744, + "36,44": 790, + "37,44": 799, + "38,44": 845, + "39,44": 853, + "40,44": 879, + "41,44": 888, + "42,44": 933, + "43,44": 943, + "44,44": 988, + "45,44": 998, + "46,44": 1043, + "47,44": 1050, + "48,44": 1075, + "49,44": 1084, + "50,44": 1130, + "51,44": 1139, + "52,44": 1185, + "53,44": 1194, + "54,44": 1240, + "55,44": 1248, + "56,44": 1274, + "57,44": 1283, + "58,44": 1328, + "59,44": 1338, + "60,44": 1383, + "61,44": 1393, + "62,44": 1438, + "63,44": 1443, + "64,44": 1460, + "65,44": 1467, + "66,44": 1501, + "67,44": 1508, + "68,44": 1542, + "69,44": 1549, + "70,44": 1583, + "71,44": 1589, + "72,44": 1607, + "73,44": 1614, + "74,44": 1647, + "75,44": 1655, + "76,44": 1688, + "77,44": 1694, + "1,45": 2, + "3,45": 43, + "5,45": 84, + "9,45": 149, + "11,45": 190, + "13,45": 231, + "17,45": 293, + "19,45": 348, + "21,45": 403, + "25,45": 492, + "27,45": 547, + "29,45": 602, + "33,45": 688, + "35,45": 743, + "37,45": 798, + "41,45": 887, + "43,45": 942, + "45,45": 997, + "49,45": 1083, + "51,45": 1138, + "53,45": 1193, + "57,45": 1282, + "59,45": 1337, + "61,45": 1392, + "65,45": 1466, + "67,45": 1507, + "69,45": 1548, + "73,45": 1613, + "75,45": 1654, + "77,45": 1693, + "11,46": 189, + "13,46": 230, + "27,46": 546, + "29,46": 601, + "43,46": 941, + "45,46": 996, + "59,46": 1336, + "61,46": 1391, + "75,46": 1653, + "77,46": 1692, + "1,47": 1, + "2,47": 36, + "3,47": 42, + "4,47": 77, + "5,47": 83, + "6,47": 118, + "7,47": 124, + "8,47": 142, + "9,47": 148, + "17,47": 292, + "18,47": 339, + "19,47": 347, + "20,47": 394, + "21,47": 402, + "22,47": 449, + "23,47": 457, + "24,47": 483, + "25,47": 491, + "33,47": 687, + "34,47": 734, + "35,47": 742, + "36,47": 789, + "37,47": 797, + "38,47": 844, + "39,47": 852, + "40,47": 878, + "41,47": 886, + "49,47": 1082, + "50,47": 1129, + "51,47": 1137, + "52,47": 1184, + "53,47": 1192, + "54,47": 1239, + "55,47": 1247, + "56,47": 1273, + "57,47": 1281, + "65,47": 1465, + "66,47": 1500, + "67,47": 1506, + "68,47": 1541, + "69,47": 1547, + "70,47": 1582, + "71,47": 1588, + "72,47": 1606, + "73,47": 1612 + }, + "total_path_cells": 1696, + "unique_path_ids": 1696 +} \ No newline at end of file diff --git a/algo-zkd/pom.xml b/algo-zkd/pom.xml new file mode 100644 index 0000000..d4b218e --- /dev/null +++ b/algo-zkd/pom.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.5.3</version> + <relativePath/> <!-- lookup parent from repository --> + </parent> + + + <groupId>com.zy</groupId> + <artifactId>algo-zkd</artifactId> + <version>1.0-SNAPSHOT</version> + + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + +</project> \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/AlgorithmMain.java b/algo-zkd/src/main/java/com/algo/AlgorithmMain.java new file mode 100644 index 0000000..e596e88 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/AlgorithmMain.java @@ -0,0 +1,67 @@ +package com.algo; + +import com.algo.model.AGVStatus; +import com.algo.model.TaskAssignment; +import com.algo.model.TaskData; +import com.algo.service.PathPlanningService; +import com.algo.service.TaskAllocationService; +import com.algo.util.AgvTaskUtils; +import com.algo.util.JsonUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; +import java.util.Map; + +@SpringBootTest +@RunWith(SpringRunner.class) +public class AlgorithmMain { + + + /** + * 浠诲姟鍒嗛厤娴嬭瘯 + */ + @Test + public void taskAllocationService() { + Map<String, Map<String, Integer>> pathMapping = JsonUtils.loadPathMapping("path_mapping.json"); + System.out.println(pathMapping); + Map<String, Object> environment = JsonUtils.loadEnvironment("environment.json"); + System.out.println(environment); + + TaskAllocationService taskAllocationService = new TaskAllocationService(pathMapping, environment); + + List<AGVStatus> agvStatusList = AgvTaskUtils.loadAgvStatus("ctu_agv_status.json"); + System.out.println(agvStatusList); + List<TaskData> taskList = AgvTaskUtils.loadTaskList("ctu_task_data.json"); + System.out.println(taskList); + + System.out.println("鎵ц浠诲姟鍒嗛厤鏂规硶锛�"); + List<TaskAssignment> taskAssignments = taskAllocationService.allocateTasks(agvStatusList, taskList); + System.out.println(taskAssignments); + System.out.println("楠岃瘉浠诲姟鍒嗛厤缁撴灉锛�"); + boolean validateAssignments = taskAllocationService.validateAssignments(taskAssignments); + System.out.println(validateAssignments); + } + + /** + * 璺緞浼樺寲娴嬭瘯 + */ + @Test + public void pathPlanningService() { + Map<String, Map<String, Integer>> pathMapping = JsonUtils.loadPathMapping("path_mapping.json"); + System.out.println(pathMapping); + Map<String, Object> environment = JsonUtils.loadEnvironment("environment.json"); + System.out.println(environment); + List<TaskData> taskList = AgvTaskUtils.loadTaskList("ctu_task_data.json"); + System.out.println(taskList); + + PathPlanningService pathPlanningService = new PathPlanningService(pathMapping, environment, taskList); + List<AGVStatus> agvStatusList = AgvTaskUtils.loadAgvStatus("ctu_agv_status.json"); + System.out.println(agvStatusList); + PathPlanningService.PathPlanningResult planningResult = pathPlanningService.planAllAgvPaths(agvStatusList, true, null); + System.out.println(planningResult); + } + +} diff --git a/algo-zkd/src/main/java/com/algo/SpringBootAplication.java b/algo-zkd/src/main/java/com/algo/SpringBootAplication.java new file mode 100644 index 0000000..17a1f75 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/SpringBootAplication.java @@ -0,0 +1,15 @@ +package com.algo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +public class SpringBootAplication { + + + public static void main(String[] args) { + SpringApplication.run(SpringBootAplication.class, args); + } +} + diff --git a/algo-zkd/src/main/java/com/algo/expose/AlgoSupport.java b/algo-zkd/src/main/java/com/algo/expose/AlgoSupport.java new file mode 100644 index 0000000..010bd27 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/expose/AlgoSupport.java @@ -0,0 +1,25 @@ +package com.algo.expose; + +import com.algo.model.AGVStatus; +import com.algo.model.TaskAssignment; +import com.algo.model.TaskData; +import com.algo.service.PathPlanningService; + +import java.util.List; + +public interface AlgoSupport { + /** + * 鍒嗛厤浠诲姟绠楁硶 + * + * @return + */ + List<TaskAssignment> allocateTasks(List<AGVStatus> agvStatusList, List<TaskData> taskList); + + /** + * 鎵捐矾寰勭畻娉� + * + * @return + */ + PathPlanningService.PathPlanningResult planAllAgvPaths(List<AGVStatus> agvStatusList, boolean flag, List<double[]> constraints); + +} diff --git a/algo-zkd/src/main/java/com/algo/expose/impl/AlgoSupportImpl.java b/algo-zkd/src/main/java/com/algo/expose/impl/AlgoSupportImpl.java new file mode 100644 index 0000000..ebbbeb4 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/expose/impl/AlgoSupportImpl.java @@ -0,0 +1,26 @@ +package com.algo.expose.impl; + +import com.algo.expose.AlgoSupport; +import com.algo.model.AGVStatus; +import com.algo.model.TaskAssignment; +import com.algo.model.TaskData; +import com.algo.service.PathPlanningService; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +public class AlgoSupportImpl implements AlgoSupport { + + + @Override + public List<TaskAssignment> allocateTasks(List<AGVStatus> agvStatusList, List<TaskData> taskList) { + return Collections.emptyList(); + } + + @Override + public PathPlanningService.PathPlanningResult planAllAgvPaths(List<AGVStatus> agvStatusList, boolean flag, List<double[]> constraints) { + return null; + } +} diff --git a/algo-zkd/src/main/java/com/algo/model/AGVStatus.java b/algo-zkd/src/main/java/com/algo/model/AGVStatus.java new file mode 100644 index 0000000..a2cb19c --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/AGVStatus.java @@ -0,0 +1,379 @@ +package com.algo.model; + +import java.util.List; +import java.util.Objects; + +/** + * AGV鐘舵�佷俊鎭� + * 鍖呭惈AGV鐨勫畬鏁寸姸鎬佹暟鎹紝鍖呮嫭鍓╀綑璺緞鍜孋TU鐗╃悊鍙傛暟 + */ +public class AGVStatus { + + /** + * AGV缂栧彿 + */ + private String agvId; + + /** + * AGV鐘舵�� + */ + private int status; + + /** + * AGV褰撳墠浣嶇疆 + */ + private String position; + + /** + * 绌鸿儗绡撴暟閲� + */ + private String empty; + + /** + * AGV鏂瑰悜瑙掑害 + */ + private String direction; + + /** + * 鐢靛帇鐢甸噺鍊� + */ + private int vol; + + /** + * 寮傚父鐮侊紝0琛ㄧず姝e父 + */ + private int error; + + /** + * 鑳岀瘬鏁版嵁鍒楄〃 + */ + private List<BackpackData> backpack; + + /** + * 浣庣數閲忚瀹氶槇鍊硷紝浣庝簬璇ュ�煎彲浠ュ幓鑷姩鍏呯數涔熷彲浠ョ户缁仛浠诲姟 + */ + private int autoCharge; + + /** + * 鏈�浣庣數閲忥紝鐢甸噺浣庝簬璇ュ�煎繀椤诲幓鍏呯數 + */ + private int lowVol; + + /** + * CTU鍓╀綑鏈畬鎴愮殑璺緞锛屾牸寮忎笌杈撳嚭璺緞鐩稿悓 + */ + private PlannedPath remainingPath; + + /** + * CTU鐗╃悊鍙傛暟閰嶇疆 + */ + private CTUPhysicalConfig physicalConfig; + + /** + * 褰撳墠鎵ц璺緞涓殑浣嶇疆绱㈠紩锛堜粠鍓╀綑璺緞寮�濮嬭绠楋級 + */ + private int currentPathIndex; + + /** + * 棰勮鍒拌揪涓嬩竴涓矾寰勭偣鐨勬椂闂存埑锛堟绉掞級 + */ + private long nextPointArrivalTime; + + // 鏋勯�犲嚱鏁� + public AGVStatus() { + this.physicalConfig = new CTUPhysicalConfig(); // 浣跨敤榛樿閰嶇疆 + this.currentPathIndex = 0; + this.nextPointArrivalTime = System.currentTimeMillis(); + } + + public AGVStatus(String agvId, int status, String position, String empty, + String direction, int vol, int error, List<BackpackData> backpack, + int autoCharge, int lowVol) { + this.agvId = agvId; + this.status = status; + this.position = position; + this.empty = empty; + this.direction = direction; + this.vol = vol; + this.error = error; + this.backpack = backpack; + this.autoCharge = autoCharge; + this.lowVol = lowVol; + this.physicalConfig = new CTUPhysicalConfig(); // 浣跨敤榛樿閰嶇疆 + this.currentPathIndex = 0; + this.nextPointArrivalTime = System.currentTimeMillis(); + } + + // 鍘熸湁鐨凣etter鍜孲etter鏂规硶 + public String getAgvId() { + return agvId; + } + + public void setAgvId(String agvId) { + this.agvId = agvId; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getEmpty() { + return empty; + } + + public void setEmpty(String empty) { + this.empty = empty; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public int getVol() { + return vol; + } + + public void setVol(int vol) { + this.vol = vol; + } + + public int getError() { + return error; + } + + public void setError(int error) { + this.error = error; + } + + public List<BackpackData> getBackpack() { + return backpack; + } + + public void setBackpack(List<BackpackData> backpack) { + this.backpack = backpack; + } + + public int getAutoCharge() { + return autoCharge; + } + + public void setAutoCharge(int autoCharge) { + this.autoCharge = autoCharge; + } + + public int getLowVol() { + return lowVol; + } + + public void setLowVol(int lowVol) { + this.lowVol = lowVol; + } + + // 鏂板鐨勫墿浣欒矾寰勫拰鐗╃悊鍙傛暟鐩稿叧鐨凣etter鍜孲etter鏂规硶 + public PlannedPath getRemainingPath() { + return remainingPath; + } + + public void setRemainingPath(PlannedPath remainingPath) { + this.remainingPath = remainingPath; + } + + public CTUPhysicalConfig getPhysicalConfig() { + return physicalConfig; + } + + public void setPhysicalConfig(CTUPhysicalConfig physicalConfig) { + this.physicalConfig = physicalConfig; + } + + public int getCurrentPathIndex() { + return currentPathIndex; + } + + public void setCurrentPathIndex(int currentPathIndex) { + this.currentPathIndex = currentPathIndex; + } + + public long getNextPointArrivalTime() { + return nextPointArrivalTime; + } + + public void setNextPointArrivalTime(long nextPointArrivalTime) { + this.nextPointArrivalTime = nextPointArrivalTime; + } + + /** + * 妫�鏌TU鏄惁鏈夊墿浣欐湭瀹屾垚鐨勮矾寰� + * + * @return true濡傛灉鏈夊墿浣欒矾寰� + */ + public boolean hasRemainingPath() { + return remainingPath != null && + remainingPath.getCodeList() != null && + !remainingPath.getCodeList().isEmpty() && + currentPathIndex < remainingPath.getCodeList().size(); + } + + /** + * 鑾峰彇鍓╀綑璺緞鐨勯暱搴︼紙浠庡綋鍓嶄綅缃紑濮嬶級 + * + * @return 鍓╀綑璺緞鐐规暟閲� + */ + public int getRemainingPathLength() { + if (!hasRemainingPath()) { + return 0; + } + return remainingPath.getCodeList().size() - currentPathIndex; + } + + /** + * 鑾峰彇褰撳墠姝e湪鎵ц鐨勮矾寰勭偣 + * + * @return 褰撳墠璺緞鐐癸紝濡傛灉娌℃湁鍒欒繑鍥瀗ull + */ + public PathCode getCurrentPathCode() { + if (!hasRemainingPath()) { + return null; + } + return remainingPath.getCodeList().get(currentPathIndex); + } + + /** + * 鑾峰彇涓嬩竴涓鍒拌揪鐨勮矾寰勭偣 + * + * @return 涓嬩竴涓矾寰勭偣锛屽鏋滄病鏈夊垯杩斿洖null + */ + public PathCode getNextPathCode() { + if (!hasRemainingPath() || currentPathIndex + 1 >= remainingPath.getCodeList().size()) { + return null; + } + return remainingPath.getCodeList().get(currentPathIndex + 1); + } + + /** + * 妫�鏌GV鏄惁鍙敤锛堢┖闂蹭笖闈炴晠闅滅姸鎬侊級 + * + * @return true濡傛灉AGV鍙敤 + */ + public boolean isAvailable() { + return error == 0 && status == 0 && vol > lowVol; + } + + /** + * 妫�鏌TU鏄惁鍙互鎺ュ彈鏂颁换鍔★紙鑰冭檻鍓╀綑璺緞锛� + * + * @return true濡傛灉鍙互鎺ュ彈鏂颁换鍔� + */ + public boolean canAcceptNewTask() { + // 濡傛灉鏈夊墿浣欒矾寰勶紝闇�瑕佺瓑寰呭畬鎴愬悗鎵嶈兘鎺ュ彈鏂颁换鍔� + // 闄ら潪鍓╀綑璺緞寰堢煭锛堟瘮濡傚彧鏈�1涓偣锛� + if (hasRemainingPath()) { + int remainingLength = getRemainingPathLength(); + return remainingLength <= 1; // 鍏佽鍦ㄥ嵆灏嗗畬鎴愬綋鍓嶈矾寰勬椂鎺ュ彈鏂颁换鍔� + } + return isAvailable(); + } + + /** + * 鑾峰彇鍙敤鐨勮儗绡撴暟閲� + * + * @return 鍙敤鑳岀瘬鏁伴噺 + */ + public int getAvailableBackpackCount() { + if (backpack == null || backpack.isEmpty()) { + return 0; + } + + int count = 0; + for (BackpackData bp : backpack) { + if (!bp.isLoaded() && bp.getTaskId() == null) { + count++; + } + } + return count; + } + + /** + * 鏌ユ壘鍙敤鐨勮儗绡撲綅缃� + * + * @return 鍙敤鑳岀瘬鐨勭储寮曪紝濡傛灉娌℃湁鍙敤鍒欒繑鍥�-1 + */ + public int findAvailableBackpackIndex() { + if (backpack == null || backpack.isEmpty()) { + return -1; + } + + for (BackpackData bp : backpack) { + if (!bp.isLoaded() && bp.getTaskId() == null) { + return bp.getIndex(); + } + } + return -1; + } + + /** + * 妫�鏌GV鏄惁闇�瑕佸厖鐢� + * + * @return true濡傛灉闇�瑕佸厖鐢� + */ + public boolean needsCharging() { + return vol <= autoCharge; + } + + /** + * 妫�鏌GV鏄惁蹇呴』鍏呯數 + * + * @return true濡傛灉蹇呴』鍏呯數 + */ + public boolean mustCharge() { + return vol <= lowVol; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AGVStatus agvStatus = (AGVStatus) o; + return Objects.equals(agvId, agvStatus.agvId); + } + + @Override + public int hashCode() { + return Objects.hash(agvId); + } + + @Override + public String toString() { + return "AGVStatus{" + + "agvId='" + agvId + '\'' + + ", status=" + status + + ", position='" + position + '\'' + + ", empty='" + empty + '\'' + + ", direction='" + direction + '\'' + + ", vol=" + vol + + ", error=" + error + + ", backpack=" + (backpack != null ? backpack.size() : 0) + + ", autoCharge=" + autoCharge + + ", lowVol=" + lowVol + + ", hasRemainingPath=" + hasRemainingPath() + + ", remainingPathLength=" + getRemainingPathLength() + + ", physicalConfig=" + physicalConfig + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/BackpackData.java b/algo-zkd/src/main/java/com/algo/model/BackpackData.java new file mode 100644 index 0000000..03ce368 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/BackpackData.java @@ -0,0 +1,123 @@ +package com.algo.model; + +import java.util.Objects; + +/** + * 鑳岀瘬鏁版嵁妯″瀷 + * 鍖呭惈鑳岀瘬鐨勭姸鎬佷俊鎭� + */ +public class BackpackData { + + /** + * 鑳岀瘬缂栧彿 + */ + private int index; + + /** + * 鏄惁杞借揣 + */ + private boolean loaded; + + /** + * 瀵瑰簲鐨勪换鍔$紪鍙� + */ + private String taskId; + + private boolean execute; + + // 鏋勯�犲嚱鏁� + public BackpackData() { + } + + public BackpackData(int index, boolean loaded, String taskId) { + this.index = index; + this.loaded = loaded; + this.taskId = taskId; + } + + // Getter鍜孲etter鏂规硶 + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public boolean isLoaded() { + return loaded; + } + + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public boolean isExecute() { + return execute; + } + + public void setExecute(boolean execute) { + this.execute = execute; + } + + /** + * 妫�鏌ヨ儗绡撴槸鍚﹀彲鐢紙鏈浇璐т笖鏃犱换鍔★級 + * + * @return true濡傛灉鑳岀瘬鍙敤 + */ + public boolean isAvailable() { + return !loaded && (taskId == null || taskId.trim().isEmpty()); + } + + /** + * 鍒嗛厤浠诲姟鍒拌儗绡� + * + * @param taskId 浠诲姟ID + * @return true濡傛灉鍒嗛厤鎴愬姛 + */ + public boolean assignTask(String taskId) { + if (isAvailable()) { + this.taskId = taskId; + return true; + } + return false; + } + + /** + * 娓呯┖鑳岀瘬浠诲姟 + */ + public void clearTask() { + this.taskId = null; + this.loaded = false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BackpackData that = (BackpackData) o; + return index == that.index; + } + + @Override + public int hashCode() { + return Objects.hash(index); + } + + @Override + public String toString() { + return "BackpackData{" + + "index=" + index + + ", loaded=" + loaded + + ", taskId='" + taskId + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/CTUPhysicalConfig.java b/algo-zkd/src/main/java/com/algo/model/CTUPhysicalConfig.java new file mode 100644 index 0000000..a63d923 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/CTUPhysicalConfig.java @@ -0,0 +1,322 @@ +package com.algo.model; + +/** + * CTU鐗╃悊鍙傛暟閰嶇疆绫� + * 鍖呭惈CTU杩愬姩鐨勫悇绉嶇墿鐞嗗弬鏁帮紝鐢ㄤ簬璺緞瑙勫垝鍜岀鎾炴娴� + */ +public class CTUPhysicalConfig { + + /** + * 鏈�澶хЩ鍔ㄩ�熷害 (绫�/绉�) + */ + private double maxSpeed; + + /** + * 姝e父绉诲姩閫熷害 (绫�/绉�) + */ + private double normalSpeed; + + /** + * 鏈�澶у姞閫熷害 (绫�/绉捖�) + */ + private double maxAcceleration; + + /** + * 鏈�澶у噺閫熷害 (绫�/绉捖�) + */ + private double maxDeceleration; + + /** + * 杞悜鏃堕棿 (绉�) - 90搴﹁浆鍚戞墍闇�鏃堕棿 + */ + private double turnTime90; + + /** + * 杞悜鏃堕棿 (绉�) - 180搴﹁浆鍚戞墍闇�鏃堕棿 + */ + private double turnTime180; + + /** + * CTU涔嬮棿鐨勬渶灏忓畨鍏ㄨ窛绂� (绫�) + */ + private double minSafetyDistance; + + /** + * CTU涔嬮棿鐨勬渶灏忚窡闅忚窛绂� (绫�) + */ + private double minFollowingDistance; + + /** + * CTU鐨勭墿鐞嗛暱搴� (绫�) + */ + private double ctuLength; + + /** + * CTU鐨勭墿鐞嗗搴� (绫�) + */ + private double ctuWidth; + + /** + * 鍚姩鏃堕棿 (绉�) - 浠庨潤姝㈠埌姝e父閫熷害鎵�闇�鏃堕棿 + */ + private double startupTime; + + /** + * 鍋滄鏃堕棿 (绉�) - 浠庢甯搁�熷害鍒伴潤姝㈡墍闇�鏃堕棿 + */ + private double stopTime; + + /** + * 璺緞鐐逛箣闂寸殑鏍囧噯璺濈 (绫�) + */ + private double standardPointDistance; + + // 榛樿鏋勯�犲嚱鏁� - 浣跨敤鎺ㄨ崘鐨勯粯璁ゅ�� + public CTUPhysicalConfig() { + this.maxSpeed = 2.0; // 2绫�/绉� + this.normalSpeed = 1.5; // 1.5绫�/绉� + this.maxAcceleration = 1.0; // 1绫�/绉捖� + this.maxDeceleration = 1.5; // 1.5绫�/绉捖� + this.turnTime90 = 2.0; // 90搴﹁浆鍚戦渶瑕�2绉� + this.turnTime180 = 4.0; // 180搴﹁浆鍚戦渶瑕�4绉� + this.minSafetyDistance = 3.0; // 鏈�灏忓畨鍏ㄨ窛绂�3绫� + this.minFollowingDistance = 2.0; // 鏈�灏忚窡闅忚窛绂�2绫� + this.ctuLength = 1.5; // CTU闀垮害1.5绫� + this.ctuWidth = 1.0; // CTU瀹藉害1绫� + this.startupTime = 1.0; // 鍚姩鏃堕棿1绉� + this.stopTime = 1.5; // 鍋滄鏃堕棿1.5绉� + this.standardPointDistance = 1.0; // 鏍囧噯璺緞鐐硅窛绂�1绫� + } + + // 瀹屾暣鍙傛暟鐨勬瀯閫犲嚱鏁� + public CTUPhysicalConfig(double maxSpeed, double normalSpeed, double maxAcceleration, + double maxDeceleration, double turnTime90, double turnTime180, + double minSafetyDistance, double minFollowingDistance, + double ctuLength, double ctuWidth, double startupTime, + double stopTime, double standardPointDistance) { + this.maxSpeed = maxSpeed; + this.normalSpeed = normalSpeed; + this.maxAcceleration = maxAcceleration; + this.maxDeceleration = maxDeceleration; + this.turnTime90 = turnTime90; + this.turnTime180 = turnTime180; + this.minSafetyDistance = minSafetyDistance; + this.minFollowingDistance = minFollowingDistance; + this.ctuLength = ctuLength; + this.ctuWidth = ctuWidth; + this.startupTime = startupTime; + this.stopTime = stopTime; + this.standardPointDistance = standardPointDistance; + } + + // Getter鍜孲etter鏂规硶 + public double getMaxSpeed() { + return maxSpeed; + } + + public void setMaxSpeed(double maxSpeed) { + this.maxSpeed = maxSpeed; + } + + public double getNormalSpeed() { + return normalSpeed; + } + + public void setNormalSpeed(double normalSpeed) { + this.normalSpeed = normalSpeed; + } + + public double getMaxAcceleration() { + return maxAcceleration; + } + + public void setMaxAcceleration(double maxAcceleration) { + this.maxAcceleration = maxAcceleration; + } + + public double getMaxDeceleration() { + return maxDeceleration; + } + + public void setMaxDeceleration(double maxDeceleration) { + this.maxDeceleration = maxDeceleration; + } + + public double getTurnTime90() { + return turnTime90; + } + + public void setTurnTime90(double turnTime90) { + this.turnTime90 = turnTime90; + } + + public double getTurnTime180() { + return turnTime180; + } + + public void setTurnTime180(double turnTime180) { + this.turnTime180 = turnTime180; + } + + public double getMinSafetyDistance() { + return minSafetyDistance; + } + + public void setMinSafetyDistance(double minSafetyDistance) { + this.minSafetyDistance = minSafetyDistance; + } + + public double getMinFollowingDistance() { + return minFollowingDistance; + } + + public void setMinFollowingDistance(double minFollowingDistance) { + this.minFollowingDistance = minFollowingDistance; + } + + public double getCtuLength() { + return ctuLength; + } + + public void setCtuLength(double ctuLength) { + this.ctuLength = ctuLength; + } + + public double getCtuWidth() { + return ctuWidth; + } + + public void setCtuWidth(double ctuWidth) { + this.ctuWidth = ctuWidth; + } + + public double getStartupTime() { + return startupTime; + } + + public void setStartupTime(double startupTime) { + this.startupTime = startupTime; + } + + public double getStopTime() { + return stopTime; + } + + public void setStopTime(double stopTime) { + this.stopTime = stopTime; + } + + public double getStandardPointDistance() { + return standardPointDistance; + } + + public void setStandardPointDistance(double standardPointDistance) { + this.standardPointDistance = standardPointDistance; + } + + /** + * 璁$畻浠庡綋鍓嶉�熷害鍔犻�熷埌鐩爣閫熷害鎵�闇�鐨勬椂闂� + * + * @param currentSpeed 褰撳墠閫熷害 + * @param targetSpeed 鐩爣閫熷害 + * @return 鎵�闇�鏃堕棿锛堢锛� + */ + public double getAccelerationTime(double currentSpeed, double targetSpeed) { + if (targetSpeed > currentSpeed) { + return (targetSpeed - currentSpeed) / maxAcceleration; + } else { + return (currentSpeed - targetSpeed) / maxDeceleration; + } + } + + /** + * 璁$畻浠庡綋鍓嶉�熷害鍔犻��/鍑忛�熷埌鐩爣閫熷害鎵�闇�鐨勮窛绂� + * + * @param currentSpeed 褰撳墠閫熷害 + * @param targetSpeed 鐩爣閫熷害 + * @return 鎵�闇�璺濈锛堢背锛� + */ + public double getAccelerationDistance(double currentSpeed, double targetSpeed) { + double time = getAccelerationTime(currentSpeed, targetSpeed); + return (currentSpeed + targetSpeed) * time / 2.0; + } + + /** + * 鏍规嵁璺緞鐐硅窛绂昏绠楃Щ鍔ㄦ椂闂� + * + * @param distance 璺濈锛堢背锛� + * @param currentSpeed 褰撳墠閫熷害 + * @return 绉诲姩鏃堕棿锛堢锛� + */ + public double getTravelTime(double distance, double currentSpeed) { + if (currentSpeed <= 0) { + currentSpeed = normalSpeed; + } + return distance / currentSpeed; + } + + /** + * 鏍规嵁鏂瑰悜鍙樺寲璁$畻杞悜鏃堕棿 + * + * @param fromDirection 璧峰鏂瑰悜瑙掑害 + * @param toDirection 鐩爣鏂瑰悜瑙掑害 + * @return 杞悜鏃堕棿锛堢锛� + */ + public double getTurnTime(String fromDirection, String toDirection) { + try { + double from = Double.parseDouble(fromDirection); + double to = Double.parseDouble(toDirection); + + // 璁$畻瑙掑害宸� + double angleDiff = Math.abs(to - from); + if (angleDiff > 180) { + angleDiff = 360 - angleDiff; + } + + // 鏍规嵁瑙掑害宸绠楄浆鍚戞椂闂� + if (angleDiff <= 5) { // 鍩烘湰鏃犺浆鍚� + return 0.0; + } else if (angleDiff <= 90) { + return turnTime90 * (angleDiff / 90.0); + } else if (angleDiff <= 180) { + return turnTime90 + (turnTime180 - turnTime90) * ((angleDiff - 90) / 90.0); + } else { + return turnTime180; + } + } catch (NumberFormatException e) { + // 濡傛灉鏂瑰悜涓嶆槸鏁板瓧锛岃繑鍥為粯璁よ浆鍚戞椂闂� + return turnTime90; + } + } + + /** + * 妫�鏌ヤ袱涓狢TU涔嬮棿鐨勮窛绂绘槸鍚︽弧瓒冲畨鍏ㄨ姹� + * + * @param distance 璺濈锛堢背锛� + * @param isFollowing 鏄惁涓鸿窡闅忔儏鍐� + * @return true濡傛灉璺濈瀹夊叏 + */ + public boolean isSafeDistance(double distance, boolean isFollowing) { + double minDistance = isFollowing ? minFollowingDistance : minSafetyDistance; + return distance >= minDistance; + } + + @Override + public String toString() { + return "CTUPhysicalConfig{" + + "maxSpeed=" + maxSpeed + + ", normalSpeed=" + normalSpeed + + ", maxAcceleration=" + maxAcceleration + + ", maxDeceleration=" + maxDeceleration + + ", turnTime90=" + turnTime90 + + ", turnTime180=" + turnTime180 + + ", minSafetyDistance=" + minSafetyDistance + + ", minFollowingDistance=" + minFollowingDistance + + ", ctuLength=" + ctuLength + + ", ctuWidth=" + ctuWidth + + ", startupTime=" + startupTime + + ", stopTime=" + stopTime + + ", standardPointDistance=" + standardPointDistance + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/Conflict.java b/algo-zkd/src/main/java/com/algo/model/Conflict.java new file mode 100644 index 0000000..43490de --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/Conflict.java @@ -0,0 +1,128 @@ +package com.algo.model; + +/** + * 鍐茬獊妯″瀷 + * 琛ㄧずAGV璺緞瑙勫垝涓殑鍐茬獊淇℃伅 + */ +public class Conflict { + + /** + * 鍐茬獊绫诲瀷锛歷ertex(椤剁偣鍐茬獊), edge(杈瑰啿绐�), follow(璺熼殢鍐茬獊) + */ + private String type; + + /** + * 鍐茬獊AGV1 + */ + private String agv1; + + /** + * 鍐茬獊AGV2 + */ + private String agv2; + + /** + * 鍐茬獊鍙戠敓鐨勬椂闂存 + */ + private int timeStep; + + /** + * AGV1鐨勫啿绐佷綅缃� + */ + private String position1; + + /** + * AGV2鐨勫啿绐佷綅缃� + */ + private String position2; + + /** + * 鍐茬獊鎻忚堪 + */ + private String description; + + // 鏋勯�犲嚱鏁� + public Conflict() { + } + + public Conflict(String type, String agv1, String agv2, int timeStep, + String position1, String position2, String description) { + this.type = type; + this.agv1 = agv1; + this.agv2 = agv2; + this.timeStep = timeStep; + this.position1 = position1; + this.position2 = position2; + this.description = description; + } + + // Getter鍜孲etter鏂规硶 + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAgv1() { + return agv1; + } + + public void setAgv1(String agv1) { + this.agv1 = agv1; + } + + public String getAgv2() { + return agv2; + } + + public void setAgv2(String agv2) { + this.agv2 = agv2; + } + + public int getTimeStep() { + return timeStep; + } + + public void setTimeStep(int timeStep) { + this.timeStep = timeStep; + } + + public String getPosition1() { + return position1; + } + + public void setPosition1(String position1) { + this.position1 = position1; + } + + public String getPosition2() { + return position2; + } + + public void setPosition2(String position2) { + this.position2 = position2; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "Conflict{" + + "type='" + type + '\'' + + ", agv1='" + agv1 + '\'' + + ", agv2='" + agv2 + '\'' + + ", timeStep=" + timeStep + + ", position1='" + position1 + '\'' + + ", position2='" + position2 + '\'' + + ", description='" + description + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/ExecutingTask.java b/algo-zkd/src/main/java/com/algo/model/ExecutingTask.java new file mode 100644 index 0000000..8a126d9 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/ExecutingTask.java @@ -0,0 +1,172 @@ +package com.algo.model; + +/** + * 鎵ц涓换鍔℃ā鍨� + * 琛ㄧずAGV褰撳墠姝e湪鎵ц鐨勪换鍔′俊鎭� + */ +public class ExecutingTask { + + /** + * AGV缂栧彿 + */ + private String agvId; + + /** + * 浠诲姟ID + */ + private String taskId; + + /** + * 褰撳墠浣嶇疆 + */ + private String currentPosition; + + /** + * 鐩爣浣嶇疆 + */ + private String targetPosition; + + /** + * 浠诲姟绫诲瀷 + */ + private String taskType; + + /** + * 鏄惁宸茶杞� + */ + private boolean loaded; + + /** + * 鑳岀瘬绱㈠紩 + */ + private int backpackIndex; + + /** + * 浠诲姟浼樺厛绾� + */ + private int priority; + + /** + * 璺濈璧风偣鐨勮窛绂� + */ + private double distanceToStart; + + /** + * 璺濈缁堢偣鐨勮窛绂� + */ + private double distanceToEnd; + + // 鏋勯�犲嚱鏁� + public ExecutingTask() { + } + + public ExecutingTask(String agvId, String taskId, String currentPosition, + String targetPosition, String taskType, boolean loaded, + int backpackIndex, int priority) { + this.agvId = agvId; + this.taskId = taskId; + this.currentPosition = currentPosition; + this.targetPosition = targetPosition; + this.taskType = taskType; + this.loaded = loaded; + this.backpackIndex = backpackIndex; + this.priority = priority; + } + + // Getter鍜孲etter鏂规硶 + public String getAgvId() { + return agvId; + } + + public void setAgvId(String agvId) { + this.agvId = agvId; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getCurrentPosition() { + return currentPosition; + } + + public void setCurrentPosition(String currentPosition) { + this.currentPosition = currentPosition; + } + + public String getTargetPosition() { + return targetPosition; + } + + public void setTargetPosition(String targetPosition) { + this.targetPosition = targetPosition; + } + + public String getTaskType() { + return taskType; + } + + public void setTaskType(String taskType) { + this.taskType = taskType; + } + + public boolean isLoaded() { + return loaded; + } + + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + public int getBackpackIndex() { + return backpackIndex; + } + + public void setBackpackIndex(int backpackIndex) { + this.backpackIndex = backpackIndex; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public double getDistanceToStart() { + return distanceToStart; + } + + public void setDistanceToStart(double distanceToStart) { + this.distanceToStart = distanceToStart; + } + + public double getDistanceToEnd() { + return distanceToEnd; + } + + public void setDistanceToEnd(double distanceToEnd) { + this.distanceToEnd = distanceToEnd; + } + + @Override + public String toString() { + return "ExecutingTask{" + + "agvId='" + agvId + '\'' + + ", taskId='" + taskId + '\'' + + ", currentPosition='" + currentPosition + '\'' + + ", targetPosition='" + targetPosition + '\'' + + ", taskType='" + taskType + '\'' + + ", loaded=" + loaded + + ", backpackIndex=" + backpackIndex + + ", priority=" + priority + + ", distanceToStart=" + distanceToStart + + ", distanceToEnd=" + distanceToEnd + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/PathCode.java b/algo-zkd/src/main/java/com/algo/model/PathCode.java new file mode 100644 index 0000000..27716dd --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/PathCode.java @@ -0,0 +1,136 @@ +package com.algo.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * 璺緞浠g爜妯″瀷 + * 琛ㄧず璺緞涓殑鍗曚釜鑺傜偣淇℃伅 + */ +public class PathCode { + + /** + * 璺緞鐐圭紪鍙� + */ + private String code; + + /** + * 鏂瑰悜瑙掑害 + */ + private String direction; + + /** + * 鍔ㄤ綔绫诲瀷 + */ + private String actionType; + + /** + * 浠诲姟ID + */ + private String taskId; + + /** + * 浣嶇疆绫诲瀷 + */ + private String posType; + + /** + * 鑳岀瘬灞傜骇 + */ + private int lev; + + /** + * 鏄惁涓虹洰鏍囩偣 + */ + @JsonProperty("isTargetPoint") + private boolean isTargetPoint; + + // 鏋勯�犲嚱鏁� + public PathCode() { + } + + public PathCode(String code, String direction) { + this.code = code; + this.direction = direction; + } + + public PathCode(String code, String direction, String actionType, String taskId, + String posType, int lev, boolean isTargetPoint) { + this.code = code; + this.direction = direction; + this.actionType = actionType; + this.taskId = taskId; + this.posType = posType; + this.lev = lev; + this.isTargetPoint = isTargetPoint; + } + + // Getter鍜孲etter鏂规硶 + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getActionType() { + return actionType; + } + + public void setActionType(String actionType) { + this.actionType = actionType; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getPosType() { + return posType; + } + + public void setPosType(String posType) { + this.posType = posType; + } + + public int getLev() { + return lev; + } + + public void setLev(int lev) { + this.lev = lev; + } + + public boolean isTargetPoint() { + return isTargetPoint; + } + + public void setTargetPoint(boolean targetPoint) { + isTargetPoint = targetPoint; + } + + @Override + public String toString() { + return "PathCode{" + + "code='" + code + '\'' + + ", direction='" + direction + '\'' + + ", actionType='" + actionType + '\'' + + ", taskId='" + taskId + '\'' + + ", posType='" + posType + '\'' + + ", lev=" + lev + + ", isTargetPoint=" + isTargetPoint + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/PlannedPath.java b/algo-zkd/src/main/java/com/algo/model/PlannedPath.java new file mode 100644 index 0000000..5acec9b --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/PlannedPath.java @@ -0,0 +1,99 @@ +package com.algo.model; + +import java.util.List; + +/** + * 瑙勫垝璺緞妯″瀷 + * 琛ㄧずAGV鐨勫畬鏁磋矾寰勮鍒掔粨鏋� + */ +public class PlannedPath { + + /** + * AGV缂栧彿 + */ + private String agvId; + + /** + * 娈佃惤ID + */ + private String segId; + + /** + * 璺緞浠g爜鍒楄〃 + */ + private List<PathCode> codeList; + + // 鏋勯�犲嚱鏁� + public PlannedPath() { + } + + public PlannedPath(String agvId, String segId, List<PathCode> codeList) { + this.agvId = agvId; + this.segId = segId; + this.codeList = codeList; + } + + // Getter鍜孲etter鏂规硶 + public String getAgvId() { + return agvId; + } + + public void setAgvId(String agvId) { + this.agvId = agvId; + } + + public String getSegId() { + return segId; + } + + public void setSegId(String segId) { + this.segId = segId; + } + + public List<PathCode> getCodeList() { + return codeList; + } + + public void setCodeList(List<PathCode> codeList) { + this.codeList = codeList; + } + + /** + * 鑾峰彇璺緞闀垮害 + * + * @return 璺緞闀垮害 + */ + public int getPathLength() { + return codeList != null ? codeList.size() : 0; + } + + /** + * 鑾峰彇璧峰浣嶇疆 + * + * @return 璧峰浣嶇疆缂栧彿 + */ + public String getStartPosition() { + return (codeList != null && !codeList.isEmpty()) ? codeList.get(0).getCode() : null; + } + + /** + * 鑾峰彇缁堢偣浣嶇疆 + * + * @return 缁堢偣浣嶇疆缂栧彿 + */ + public String getEndPosition() { + return (codeList != null && !codeList.isEmpty()) ? + codeList.get(codeList.size() - 1).getCode() : null; + } + + @Override + public String toString() { + return "PlannedPath{" + + "agvId='" + agvId + '\'' + + ", segId='" + segId + '\'' + + ", pathLength=" + getPathLength() + + ", startPosition='" + getStartPosition() + '\'' + + ", endPosition='" + getEndPosition() + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/TaskAssignment.java b/algo-zkd/src/main/java/com/algo/model/TaskAssignment.java new file mode 100644 index 0000000..3387536 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/TaskAssignment.java @@ -0,0 +1,183 @@ +package com.algo.model; + +import java.util.Objects; + +/** + * 浠诲姟鍒嗛厤缁撴灉鏁版嵁妯″瀷 + * 鍖呭惈浠诲姟鍒嗛厤鐨勫畬鏁寸粨鏋滀俊鎭� + */ +public class TaskAssignment { + + /** + * 浠诲姟ID + */ + private String taskId; + + /** + * 鍒嗛厤鐨凙GV缂栧彿 + */ + private String agvId; + + /** + * 鐗囨ID锛屾牸寮忥細浠诲姟缂栧彿_AGV缂栧彿_搴忓彿 + */ + private String segId; + + /** + * 浣跨敤鐨勮儗绡撶紪鍙� + */ + private String lev; + + /** + * 鍔ㄤ綔绫诲瀷锛歵ake鍙栬揣 put鏀捐揣 + */ + private String type; + + // 鍔ㄤ綔绫诲瀷甯搁噺 + public static final String TYPE_TAKE = "take"; // 鍙栬揣 + public static final String TYPE_PUT = "put"; // 鏀捐揣 + + // 鏋勯�犲嚱鏁� + public TaskAssignment() { + } + + public TaskAssignment(String taskId, String agvId, String segId, String lev, String type) { + this.taskId = taskId; + this.agvId = agvId; + this.segId = segId; + this.lev = lev; + this.type = type; + } + + // Getter鍜孲etter鏂规硶 + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getAgvId() { + return agvId; + } + + public void setAgvId(String agvId) { + this.agvId = agvId; + } + + public String getSegId() { + return segId; + } + + public void setSegId(String segId) { + this.segId = segId; + } + + public String getLev() { + return lev; + } + + public void setLev(String lev) { + this.lev = lev; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * 鐢熸垚鐗囨ID + * + * @param taskId 浠诲姟ID + * @param agvId AGV缂栧彿 + * @param sequence 搴忓彿锛�1琛ㄧず鍙栬揣锛�2琛ㄧず鏀捐揣锛� + * @return 鐗囨ID + */ + public static String generateSegId(String taskId, String agvId, int sequence) { + return taskId + "_" + agvId + "_" + sequence; + } + + /** + * 妫�鏌ユ槸鍚︿负鍙栬揣浠诲姟 + * + * @return true濡傛灉鏄彇璐т换鍔� + */ + public boolean isTakeTask() { + return TYPE_TAKE.equals(type); + } + + /** + * 妫�鏌ユ槸鍚︿负鏀捐揣浠诲姟 + * + * @return true濡傛灉鏄斁璐т换鍔� + */ + public boolean isPutTask() { + return TYPE_PUT.equals(type); + } + + /** + * 瑙f瀽鐗囨ID鑾峰彇搴忓彿 + * + * @return 搴忓彿锛屽鏋滆В鏋愬け璐ヨ繑鍥�0 + */ + public int parseSequenceFromSegId() { + if (segId == null || segId.trim().isEmpty()) { + return 0; + } + + try { + String[] parts = segId.split("_"); + if (parts.length >= 3) { + return Integer.parseInt(parts[2]); + } + } catch (NumberFormatException e) { + // 蹇界暐瑙f瀽閿欒 + } + + return 0; + } + + /** + * 楠岃瘉浠诲姟鍒嗛厤缁撴灉鏄惁鏈夋晥 + * + * @return true濡傛灉鏈夋晥 + */ + public boolean isValid() { + return taskId != null && !taskId.trim().isEmpty() && + agvId != null && !agvId.trim().isEmpty() && + segId != null && !segId.trim().isEmpty() && + lev != null && !lev.trim().isEmpty() && + type != null && (TYPE_TAKE.equals(type) || TYPE_PUT.equals(type)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TaskAssignment that = (TaskAssignment) o; + return Objects.equals(taskId, that.taskId) && + Objects.equals(agvId, that.agvId) && + Objects.equals(segId, that.segId); + } + + @Override + public int hashCode() { + return Objects.hash(taskId, agvId, segId); + } + + @Override + public String toString() { + return "TaskAssignment{" + + "taskId='" + taskId + '\'' + + ", agvId='" + agvId + '\'' + + ", segId='" + segId + '\'' + + ", lev='" + lev + '\'' + + ", type='" + type + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/model/TaskData.java b/algo-zkd/src/main/java/com/algo/model/TaskData.java new file mode 100644 index 0000000..463d6b5 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/model/TaskData.java @@ -0,0 +1,228 @@ +package com.algo.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +/** + * 浠诲姟鏁版嵁妯″瀷 + * 鍖呭惈浠诲姟鐨勫畬鏁翠俊鎭� + */ +public class TaskData { + + /** + * 浠诲姟ID + */ + private String taskId; + + /** + * AGV缂栧彿锛堜粎鍏呯數浠诲姟鍜屽幓寰呮満浣嶄换鍔′娇鐢級 + */ + private String agvId; + + /** + * 浠诲姟璧风偣 + */ + private String start; + + /** + * 浠诲姟缁堢偣 + */ + private String end; + + /** + * 浠诲姟绫诲瀷锛�1鍏ュ簱 2鍑哄簱 3绉诲簱 4鍘诲緟鏈轰綅 5鍏呯數 + */ + private String type; + + /** + * 浠诲姟浼樺厛绾э紝瓒婂ぇ浼樺厛绾ц秺楂� + */ + private int priority; + + /** + * 浠诲姟鍒涘缓鏃堕棿 + */ + private String taskTime; + + // 浠诲姟绫诲瀷甯搁噺 + public static final String TYPE_INBOUND = "1"; // 鍏ュ簱 + public static final String TYPE_OUTBOUND = "2"; // 鍑哄簱 + public static final String TYPE_MOVE = "3"; // 绉诲簱 + public static final String TYPE_STANDBY = "4"; // 鍘诲緟鏈轰綅 + public static final String TYPE_CHARGE = "5"; // 鍏呯數 + + // 鏋勯�犲嚱鏁� + public TaskData() { + } + + public TaskData(String taskId, String agvId, String start, String end, + String type, int priority, String taskTime) { + this.taskId = taskId; + this.agvId = agvId; + this.start = start; + this.end = end; + this.type = type; + this.priority = priority; + this.taskTime = taskTime; + } + + // Getter鍜孲etter鏂规硶 + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getAgvId() { + return agvId; + } + + public void setAgvId(String agvId) { + this.agvId = agvId; + } + + public String getStart() { + return start; + } + + public void setStart(String start) { + this.start = start; + } + + public String getEnd() { + return end; + } + + public void setEnd(String end) { + this.end = end; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public String getTaskTime() { + return taskTime; + } + + public void setTaskTime(String taskTime) { + this.taskTime = taskTime; + } + + /** + * 妫�鏌ユ槸鍚︿负杩愯緭浠诲姟锛堥渶瑕佸彇璐у拰閫佽揣锛� + * + * @return true濡傛灉鏄繍杈撲换鍔� + */ + public boolean isTransportTask() { + return TYPE_INBOUND.equals(type) || TYPE_OUTBOUND.equals(type) || TYPE_MOVE.equals(type); + } + + /** + * 妫�鏌ユ槸鍚︿负鍏呯數浠诲姟 + * + * @return true濡傛灉鏄厖鐢典换鍔� + */ + public boolean isChargeTask() { + return TYPE_CHARGE.equals(type); + } + + /** + * 妫�鏌ユ槸鍚︿负鍘诲緟鏈轰綅浠诲姟 + * + * @return true濡傛灉鏄幓寰呮満浣嶄换鍔� + */ + public boolean isStandbyTask() { + return TYPE_STANDBY.equals(type); + } + + /** + * 妫�鏌ユ槸鍚︿负鎸囧畾AGV鐨勪换鍔� + * + * @return true濡傛灉鏄寚瀹欰GV鐨勪换鍔� + */ + public boolean isAssignedToAgv() { + return agvId != null && !agvId.trim().isEmpty(); + } + + /** + * 瑙f瀽浠诲姟鍒涘缓鏃堕棿 + * + * @return LocalDateTime瀵硅薄 + */ + public LocalDateTime parseTaskTime() { + if (taskTime == null || taskTime.trim().isEmpty()) { + return null; + } + + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return LocalDateTime.parse(taskTime, formatter); + } catch (Exception e) { + return null; + } + } + + /** + * 鑾峰彇浠诲姟绫诲瀷鎻忚堪 + * + * @return 浠诲姟绫诲瀷鎻忚堪 + */ + public String getTypeDescription() { + switch (type) { + case TYPE_INBOUND: + return "鍏ュ簱"; + case TYPE_OUTBOUND: + return "鍑哄簱"; + case TYPE_MOVE: + return "绉诲簱"; + case TYPE_STANDBY: + return "鍘诲緟鏈轰綅"; + case TYPE_CHARGE: + return "鍏呯數"; + default: + return "鏈煡浠诲姟绫诲瀷"; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TaskData taskData = (TaskData) o; + return Objects.equals(taskId, taskData.taskId); + } + + @Override + public int hashCode() { + return Objects.hash(taskId); + } + + @Override + public String toString() { + return "TaskData{" + + "taskId='" + taskId + '\'' + + ", agvId='" + agvId + '\'' + + ", start='" + start + '\'' + + ", end='" + end + '\'' + + ", type='" + type + '\'' + + ", priority=" + priority + + ", taskTime='" + taskTime + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/AStarPathPlanner.java b/algo-zkd/src/main/java/com/algo/service/AStarPathPlanner.java new file mode 100644 index 0000000..4ae0129 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/AStarPathPlanner.java @@ -0,0 +1,932 @@ +package com.algo.service; + +import com.algo.model.CTUPhysicalConfig; +import com.algo.model.PathCode; +import com.algo.model.PlannedPath; +import com.algo.util.JsonUtils; + +import java.util.*; + +/** + * A*璺緞瑙勫垝鍣ㄥ疄鐜� + * 浣跨敤3D A*绠楁硶杩涜CTU鏃剁┖璺緞瑙勫垝锛屾敮鎸佺墿鐞嗙害鏉� + */ +public class AStarPathPlanner implements PathPlanner { + + /** + * 璺緞鏄犲皠琛� + */ + private final Map<String, Map<String, Integer>> pathMapping; + + /** + * 閭绘帴琛� + */ + private final Map<String, List<Map<String, String>>> adjacencyList; + + /** + * 鏃堕棿绮惧害锛堟绉掞級 + */ + private final long timeResolution = 1000; + + /** + * 鏈�澶ф悳绱㈡椂闂达紙姣锛� + */ + private final long maxSearchTime = 30000; // 30绉� + + /** + * 鏈�澶ф悳绱㈡繁搴� + */ + private final int maxSearchDepth = 15000; + + /** + * 璺濈缂撳瓨 - 浼樺寲锛氱紦瀛樿窛绂昏绠楃粨鏋� + */ + private final Map<String, Double> distanceCache = new HashMap<>(); + + /** + * 蹇�熻矾寰勭紦瀛� + */ + private final Map<String, List<String>> fastPathCache = new HashMap<>(); + + /** + * 鏋勯�犲嚱鏁� + * + * @param pathMapping 璺緞鏄犲皠琛� + */ + public AStarPathPlanner(Map<String, Map<String, Integer>> pathMapping) { + this.pathMapping = pathMapping; + this.adjacencyList = new HashMap<>(); + + // 鐩存帴鏋勫缓閭绘帴琛� + buildAdjacencyList(); + + // 棰勮绠楀父鐢ㄨ窛绂� + precomputeCommonDistances(); + + System.out.println("A*璺緞瑙勫垝鍣ㄥ垵濮嬪寲瀹屾垚锛岄偦鎺ヨ〃鍖呭惈 " + adjacencyList.size() + " 涓妭鐐�"); + } + + @Override + public PlannedPath planPath(String startCode, String endCode, List<double[]> constraints) { + // 鍏堝皾璇曞揩閫熻矾寰勮鍒掞紝澶辫触鍚庡啀浣跨敤瀹屾暣鐨勬椂绌鸿鍒� + PlannedPath fastPath = tryFastPathPlanning(startCode, endCode, constraints); + if (fastPath != null) { + return fastPath; + } + return planSpaceTimePath(startCode, endCode, constraints, null, null); + } + + @Override + public PlannedPath planPath(String startCode, String endCode) { + return planPath(startCode, endCode, null); + } + + /** + * 瑙勫垝鏃剁┖璺緞 + * + * @param startCode 璧峰璺緞鐐笽D + * @param endCode 鐩爣璺緞鐐笽D + * @param constraints 闈欐�佺害鏉熸潯浠� + * @param spaceTimeOccupancyMap 鏃剁┖鍗犵敤琛� + * @param physicalConfig CTU鐗╃悊閰嶇疆 + * @return 瑙勫垝鐨勮矾寰� + */ + public PlannedPath planSpaceTimePath(String startCode, String endCode, + List<double[]> constraints, + Map<String, String> spaceTimeOccupancyMap, + CTUPhysicalConfig physicalConfig) { + // 楠岃瘉杈撳叆 + if (!isValidPathPoint(startCode) || !isValidPathPoint(endCode)) { + System.out.println("鏃犳晥鐨勮矾寰勭偣: " + startCode + " 鎴� " + endCode); + return null; + } + + // 璧风偣鍜岀粓鐐圭浉鍚� + if (startCode.equals(endCode)) { + List<PathCode> codeList = new ArrayList<>(); + codeList.add(new PathCode(startCode, "90")); + return new PlannedPath("", "", codeList); + } + + // 浣跨敤榛樿鐗╃悊閰嶇疆 + if (physicalConfig == null) { + physicalConfig = createDefaultPhysicalConfig(); + } + + // 鑾峰彇璧风偣鍜岀粓鐐瑰潗鏍� + int[] startCoord = JsonUtils.getCoordinate(startCode, pathMapping); + int[] endCoord = JsonUtils.getCoordinate(endCode, pathMapping); + + if (startCoord == null || endCoord == null) { + System.out.println("鏃犳硶鑾峰彇鍧愭爣: " + startCode + " 鎴� " + endCode); + return null; + } + + System.out.println("寮�濮嬫椂绌篈*鎼滅储: " + startCode + " -> " + endCode); + + // 鏃剁┖A*绠楁硶瀹炵幇 + PlannedPath result = spaceTimeAStarSearch( + startCode, endCode, startCoord, endCoord, + constraints, spaceTimeOccupancyMap, physicalConfig + ); + + if (result != null) { + System.out.println("鏃剁┖璺緞瑙勫垝鎴愬姛锛岃矾寰勯暱搴�: " + result.getCodeList().size()); + } else { + System.out.println("鏃剁┖璺緞瑙勫垝澶辫触"); + } + + return result; + } + + /** + * 鏃剁┖A*鎼滅储绠楁硶瀹炵幇 + * + * @param startCode 璧峰璺緞鐐笽D + * @param endCode 鐩爣璺緞鐐笽D + * @param startCoord 璧峰鍧愭爣 + * @param endCoord 鐩爣鍧愭爣 + * @param constraints 绾︽潫鏉′欢 + * @param occupancyMap 鏃剁┖鍗犵敤琛� + * @param physicalConfig 鐗╃悊閰嶇疆 + * @return 瑙勫垝鐨勮矾寰� + */ + private PlannedPath spaceTimeAStarSearch(String startCode, String endCode, + int[] startCoord, int[] endCoord, + List<double[]> constraints, + Map<String, String> occupancyMap, + CTUPhysicalConfig physicalConfig) { + + // 浣跨敤浼樺厛闃熷垪瀹炵幇寮�鏀惧垪琛� + PriorityQueue<SpaceTimeAStarNode> openSet = new PriorityQueue<>( + Comparator.comparingDouble(n -> n.fScore) + ); + Set<String> closedSet = new HashSet<>(); + Map<String, Double> gScores = new HashMap<>(); + Map<String, SpaceTimeAStarNode> cameFrom = new HashMap<>(); + + // 璧峰鏃堕棿 + long startTime = System.currentTimeMillis(); + + // 鍒濆鍖栬捣濮嬭妭鐐� + SpaceTimeAStarNode startNode = new SpaceTimeAStarNode( + startCode, startCoord, startTime, 0, + spaceTimeHeuristic(startCoord, endCoord, startTime, physicalConfig) + ); + + openSet.offer(startNode); + String startKey = createSpaceTimeKey(startCode, startTime); + gScores.put(startKey, 0.0); + + // 鏋勫缓绾︽潫妫�鏌ュ櫒 + EnhancedConstraintChecker constraintChecker = new EnhancedConstraintChecker( + constraints, occupancyMap, pathMapping, physicalConfig + ); + + int searchDepth = 0; + long searchStartTime = System.currentTimeMillis(); + + while (!openSet.isEmpty()) { + // 妫�鏌ユ悳绱㈡椂闂村拰娣卞害闄愬埗 + if (System.currentTimeMillis() - searchStartTime > maxSearchTime || + searchDepth > maxSearchDepth) { + System.out.println("鎼滅储瓒呮椂鎴栬揪鍒版渶澶ф繁搴︼紝杩斿洖null"); + break; + } + + SpaceTimeAStarNode current = openSet.poll(); + String currentKey = createSpaceTimeKey(current.code, current.timePoint); + + if (closedSet.contains(currentKey)) { + continue; + } + + closedSet.add(currentKey); + searchDepth++; + + // 鍒拌揪鐩爣 + if (current.code.equals(endCode)) { + System.out.println("鎵惧埌鐩爣锛岄噸寤鸿矾寰勶紝鎼滅储娣卞害: " + searchDepth); + return reconstructSpaceTimePath(cameFrom, startNode, current, physicalConfig); + } + + // 鎵╁睍閭诲眳鑺傜偣 + expandNeighbors(current, endCoord, openSet, closedSet, gScores, cameFrom, + constraintChecker, physicalConfig); + } + + System.out.println("鏈壘鍒版湁鏁堣矾寰勶紝鎼滅储娣卞害: " + searchDepth); + return null; // 鏃犳硶鎵惧埌璺緞 + } + + /** + * 鎵╁睍閭诲眳鑺傜偣 + */ + private void expandNeighbors(SpaceTimeAStarNode current, int[] endCoord, + PriorityQueue<SpaceTimeAStarNode> openSet, + Set<String> closedSet, Map<String, Double> gScores, + Map<String, SpaceTimeAStarNode> cameFrom, + EnhancedConstraintChecker constraintChecker, + CTUPhysicalConfig physicalConfig) { + + // 鑾峰彇绌洪棿閭诲眳 + List<Map<String, String>> neighbors = getNeighbors(current.code); + + for (Map<String, String> neighbor : neighbors) { + String neighborCode = neighbor.get("code"); + String direction = neighbor.get("direction"); + + // 璁$畻绉诲姩鍒伴偦灞呯殑鏃堕棿鎴愭湰 + long travelTime = calculateTravelTime(current.code, neighborCode, direction, physicalConfig); + long arrivalTime = current.timePoint + travelTime; + + // 鏃堕棿瀵归綈鍒板垎杈ㄧ巼 + arrivalTime = alignToTimeResolution(arrivalTime); + + String neighborKey = createSpaceTimeKey(neighborCode, arrivalTime); + + if (closedSet.contains(neighborKey)) { + continue; + } + + // 绾︽潫妫�鏌� + if (!constraintChecker.isValidMove(current.code, neighborCode, + current.timePoint, arrivalTime)) { + continue; + } + + // 璁$畻G鍊� + double gScore = gScores.get(createSpaceTimeKey(current.code, current.timePoint)) + + travelTime / 1000.0; // 杞崲涓虹 + + // 鏇存柊鏈�浣宠矾寰� + if (!gScores.containsKey(neighborKey) || gScore < gScores.get(neighborKey)) { + gScores.put(neighborKey, gScore); + + // 鑾峰彇閭诲眳鍧愭爣 + int[] neighborCoord = JsonUtils.getCoordinate(neighborCode, pathMapping); + if (neighborCoord != null) { + // 鍒涘缓閭诲眳鑺傜偣 + SpaceTimeAStarNode neighborNode = new SpaceTimeAStarNode( + neighborCode, neighborCoord, arrivalTime, gScore, + gScore + spaceTimeHeuristic(neighborCoord, endCoord, arrivalTime, physicalConfig) + ); + + cameFrom.put(neighborKey, current); + openSet.offer(neighborNode); + } + } + } + + // 鍑忓皯绛夊緟閫夐」 - 鍙湪蹇呰鏃剁瓑寰咃紙20%姒傜巼锛� + if (Math.random() < 0.2) { + long waitTime = timeResolution; + long waitUntilTime = current.timePoint + waitTime; + String waitKey = createSpaceTimeKey(current.code, waitUntilTime); + + if (!closedSet.contains(waitKey) && + constraintChecker.isValidWait(current.code, current.timePoint, waitUntilTime)) { + + double waitGScore = gScores.get(createSpaceTimeKey(current.code, current.timePoint)) + + (waitTime / 1000.0); + + if (!gScores.containsKey(waitKey) || waitGScore < gScores.get(waitKey)) { + gScores.put(waitKey, waitGScore); + + SpaceTimeAStarNode waitNode = new SpaceTimeAStarNode( + current.code, current.coordinates, waitUntilTime, waitGScore, + waitGScore + spaceTimeHeuristic(current.coordinates, endCoord, waitUntilTime, physicalConfig) + ); + + cameFrom.put(waitKey, current); + openSet.offer(waitNode); + } + } + } + } + + /** + * 鏃剁┖鍚彂寮忓嚱鏁� + * + * @param coord1 褰撳墠鍧愭爣 + * @param coord2 鐩爣鍧愭爣 + * @param currentTime 褰撳墠鏃堕棿 + * @param physicalConfig 鐗╃悊閰嶇疆 + * @return 鍚彂寮忓�� + */ + private double spaceTimeHeuristic(int[] coord1, int[] coord2, long currentTime, CTUPhysicalConfig physicalConfig) { + // 绌洪棿璺濈 + double spatialDistance = Math.abs(coord1[0] - coord2[0]) + Math.abs(coord1[1] - coord2[1]); + + // 鏃堕棿鎴愭湰浼拌 + double timeEstimate = spatialDistance * physicalConfig.getStandardPointDistance() / physicalConfig.getNormalSpeed(); + + // 鑰冭檻杞悜鎴愭湰 + double turnPenalty = spatialDistance > 1 ? physicalConfig.getTurnTime90() : 0; + + return timeEstimate + turnPenalty; + } + + /** + * 璁$畻绉诲姩鏃堕棿 + * + * @param fromCode 璧峰浠g爜 + * @param toCode 鐩爣浠g爜 + * @param direction 绉诲姩鏂瑰悜 + * @param physicalConfig 鐗╃悊閰嶇疆 + * @return 绉诲姩鏃堕棿锛堟绉掞級 + */ + private long calculateTravelTime(String fromCode, String toCode, String direction, CTUPhysicalConfig physicalConfig) { + // 鍩烘湰绉诲姩鏃堕棿 + double distance = physicalConfig.getStandardPointDistance(); + double speed = physicalConfig.getNormalSpeed(); + long moveTime = (long) ((distance / speed) * 1000); + + // 杞悜鏃堕棿 + long turnTime = (long) (physicalConfig.getTurnTime90() * 1000 / 4); // 鍋囪骞冲潎杞悜鏃堕棿 + + return moveTime + turnTime; + } + + /** + * 閲嶅缓鏃剁┖璺緞 + * + * @param cameFrom 璺緞鏉ユ簮鏄犲皠 + * @param startNode 璧峰鑺傜偣 + * @param endNode 缁撴潫鑺傜偣 + * @param physicalConfig 鐗╃悊閰嶇疆 + * @return 閲嶅缓鐨勮矾寰� + */ + private PlannedPath reconstructSpaceTimePath(Map<String, SpaceTimeAStarNode> cameFrom, + SpaceTimeAStarNode startNode, + SpaceTimeAStarNode endNode, + CTUPhysicalConfig physicalConfig) { + List<SpaceTimeAStarNode> pathNodes = new ArrayList<>(); + SpaceTimeAStarNode current = endNode; + + // 鍙嶅悜閲嶅缓璺緞 + while (current != null) { + pathNodes.add(0, current); + String currentKey = createSpaceTimeKey(current.code, current.timePoint); + current = cameFrom.get(currentKey); + } + + // 杞崲涓篜athCode鍒楄〃 + List<PathCode> codeList = new ArrayList<>(); + for (int i = 0; i < pathNodes.size(); i++) { + SpaceTimeAStarNode node = pathNodes.get(i); + String direction = "90"; // 榛樿鏂瑰悜 + + // 璁$畻鏂瑰悜 + if (i < pathNodes.size() - 1) { + SpaceTimeAStarNode nextNode = pathNodes.get(i + 1); + direction = calculateDirection(node.code, nextNode.code); + } + + PathCode pathCode = new PathCode(node.code, direction); + + // 娣诲姞鏃堕棿淇℃伅 + // pathCode.setArrivalTime(node.timePoint); + + codeList.add(pathCode); + } + + return new PlannedPath("", "", codeList); + } + + /** + * 鍒涘缓鏃剁┖閿� + * + * @param code 浣嶇疆浠g爜 + * @param timePoint 鏃堕棿鐐� + * @return 鏃剁┖閿� + */ + private String createSpaceTimeKey(String code, long timePoint) { + return code + "_T" + timePoint; + } + + /** + * 鏃堕棿瀵归綈鍒板垎杈ㄧ巼 + * + * @param timePoint 鏃堕棿鐐� + * @return 瀵归綈鍚庣殑鏃堕棿 + */ + private long alignToTimeResolution(long timePoint) { + return (timePoint / timeResolution) * timeResolution; + } + + /** + * 鍒涘缓榛樿鐗╃悊閰嶇疆 + * + * @return 榛樿閰嶇疆 + */ + private CTUPhysicalConfig createDefaultPhysicalConfig() { + CTUPhysicalConfig config = new CTUPhysicalConfig(); + config.setMaxSpeed(2.0); + config.setNormalSpeed(1.5); + config.setMaxAcceleration(1.0); + config.setMaxDeceleration(1.5); + config.setTurnTime90(2.0); + config.setTurnTime180(4.0); + config.setMinSafetyDistance(3.0); + config.setMinFollowingDistance(2.0); + config.setCtuLength(1.2); + config.setCtuWidth(0.8); + config.setStartupTime(1.0); + config.setStopTime(0.5); + config.setStandardPointDistance(1.0); + return config; + } + + /** + * 璁$畻绉诲姩鏂瑰悜 + * + * @param fromCode 璧峰璺緞鐐� + * @param toCode 鐩爣璺緞鐐� + * @return 鏂瑰悜瑙掑害瀛楃涓� + */ + private String calculateDirection(String fromCode, String toCode) { + int[] fromCoord = JsonUtils.getCoordinate(fromCode, pathMapping); + int[] toCoord = JsonUtils.getCoordinate(toCode, pathMapping); + + if (fromCoord == null || toCoord == null) { + return "90"; + } + + int dx = toCoord[0] - fromCoord[0]; + int dy = toCoord[1] - fromCoord[1]; + + // 纭畾鏂瑰悜 + if (dx == 0 && dy == -1) return "270"; // 涓� + if (dx == 1 && dy == 0) return "0"; // 鍙� + if (dx == 0 && dy == 1) return "90"; // 涓� + if (dx == -1 && dy == 0) return "180"; // 宸� + + return "90"; // 榛樿鏂瑰悜 + } + + @Override + public boolean isValidPathPoint(String pathCode) { + return pathCode != null && pathMapping.containsKey(pathCode); + } + + @Override + public double calculateDistance(String startCode, String endCode) { + int[] startCoord = JsonUtils.getCoordinate(startCode, pathMapping); + int[] endCoord = JsonUtils.getCoordinate(endCode, pathMapping); + + if (startCoord == null || endCoord == null) { + return -1; + } + + return JsonUtils.calculateManhattanDistance(startCoord, endCoord); + } + + @Override + public Map<String, Map<String, Integer>> getPathMapping() { + return pathMapping; + } + + @Override + public List<Map<String, String>> getNeighbors(String pathCode) { + return adjacencyList.getOrDefault(pathCode, new ArrayList<>()); + } + + /** + * 鏋勫缓閭绘帴琛� + */ + private void buildAdjacencyList() { + // 鍒涘缓鍧愭爣鍒扮紪鍙风殑涓存椂鏄犲皠 + Map<String, String> tempCoordToCode = new HashMap<>(); + for (Map.Entry<String, Map<String, Integer>> entry : pathMapping.entrySet()) { + String code = entry.getKey(); + Map<String, Integer> coordMap = entry.getValue(); + + if (coordMap.containsKey("x") && coordMap.containsKey("y")) { + String coordKey = coordMap.get("x") + "," + coordMap.get("y"); + tempCoordToCode.put(coordKey, code); + } + } + + // 鍥涗釜鏂瑰悜锛氫笂銆佸彸銆佷笅銆佸乏 + int[][] directions = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}}; + String[] directionAngles = {"270", "0", "90", "180"}; + + for (Map.Entry<String, Map<String, Integer>> entry : pathMapping.entrySet()) { + String code = entry.getKey(); + Map<String, Integer> coordMap = entry.getValue(); + + if (!coordMap.containsKey("x") || !coordMap.containsKey("y")) { + continue; + } + + int x = coordMap.get("x"); + int y = coordMap.get("y"); + + List<Map<String, String>> neighbors = new ArrayList<>(); + + // 妫�鏌ュ洓涓柟鍚戠殑閭诲眳 + for (int i = 0; i < directions.length; i++) { + int newX = x + directions[i][0]; + int newY = y + directions[i][1]; + String coordKey = newX + "," + newY; + + String neighborCode = tempCoordToCode.get(coordKey); + if (neighborCode != null) { + Map<String, String> neighbor = new HashMap<>(); + neighbor.put("code", neighborCode); + neighbor.put("direction", directionAngles[i]); + neighbors.add(neighbor); + } + } + + adjacencyList.put(code, neighbors); + } + } + + /** + * 鏃剁┖A*鑺傜偣绫� + */ + private static class SpaceTimeAStarNode { + final String code; + final int[] coordinates; + final long timePoint; + final double gScore; + final double fScore; + + public SpaceTimeAStarNode(String code, int[] coordinates, long timePoint, + double gScore, double fScore) { + this.code = code; + this.coordinates = coordinates; + this.timePoint = timePoint; + this.gScore = gScore; + this.fScore = fScore; + } + } + + /** + * 绾︽潫妫�鏌ュ櫒 + */ + private static class EnhancedConstraintChecker { + private final List<double[]> staticConstraints; + private final Map<String, String> spaceTimeOccupancyMap; + private final Map<String, Map<String, Integer>> pathMapping; + private final CTUPhysicalConfig physicalConfig; + + public EnhancedConstraintChecker(List<double[]> staticConstraints, + Map<String, String> spaceTimeOccupancyMap, + Map<String, Map<String, Integer>> pathMapping, + CTUPhysicalConfig physicalConfig) { + this.staticConstraints = staticConstraints; + this.spaceTimeOccupancyMap = spaceTimeOccupancyMap != null ? spaceTimeOccupancyMap : new HashMap<>(); + this.pathMapping = pathMapping; + this.physicalConfig = physicalConfig; + } + + /** + * 妫�鏌ョЩ鍔ㄦ槸鍚︽湁鏁� + */ + public boolean isValidMove(String fromCode, String toCode, long fromTime, long toTime) { + // 妫�鏌ラ潤鎬佺害鏉� + if (!isValidStaticConstraint(toCode)) { + return false; + } + + // 妫�鏌ユ椂绌哄崰鐢� + if (!isValidSpaceTimeConstraint(toCode, toTime)) { + return false; + } + + // 妫�鏌ョ墿鐞嗙害鏉� + return isValidPhysicalConstraint(fromCode, toCode, fromTime, toTime); + } + + /** + * 妫�鏌ョ瓑寰呮槸鍚︽湁鏁� + */ + public boolean isValidWait(String code, long fromTime, long toTime) { + // 妫�鏌ユ椂绌哄崰鐢ㄦ湡闂存槸鍚︽湁鍐茬獊 + for (long t = fromTime; t <= toTime; t += 100) { // 100ms妫�鏌ラ棿闅� + if (!isValidSpaceTimeConstraint(code, t)) { + return false; + } + } + return true; + } + + private boolean isValidStaticConstraint(String pathCode) { + if (staticConstraints == null || staticConstraints.isEmpty()) { + return true; + } + + int[] coord = JsonUtils.getCoordinate(pathCode, pathMapping); + if (coord == null) { + return false; + } + + for (double[] constraint : staticConstraints) { + double cx = constraint[0]; + double cy = constraint[1]; + double radius = constraint[2]; + + double distance = Math.sqrt(Math.pow(coord[0] - cx, 2) + Math.pow(coord[1] - cy, 2)); + if (distance <= radius) { + return false; + } + } + + return true; + } + + private boolean isValidSpaceTimeConstraint(String pathCode, long timePoint) { + int[] coord = JsonUtils.getCoordinate(pathCode, pathMapping); + if (coord == null) { + return false; + } + + // 妫�鏌ョ簿纭殑鏃剁┖鍗犵敤 + String spaceTimeKey = coord[0] + "," + coord[1] + "," + (timePoint / 1000); + if (spaceTimeOccupancyMap.containsKey(spaceTimeKey)) { + return false; + } + + // 妫�鏌ュ懆鍥存椂闂存鐨勫崰鐢紙鑰冭檻瀹夊叏闂撮殧锛� + long safetyMargin = (long) (physicalConfig.getMinSafetyDistance() * 1000 / physicalConfig.getNormalSpeed()); + for (long t = timePoint - safetyMargin; t <= timePoint + safetyMargin; t += 100) { + String key = coord[0] + "," + coord[1] + "," + (t / 1000); + if (spaceTimeOccupancyMap.containsKey(key)) { + return false; + } + } + + return true; + } + + private boolean isValidPhysicalConstraint(String fromCode, String toCode, long fromTime, long toTime) { + // 鐗╃悊绾︽潫妫�鏌� + long timeDiff = toTime - fromTime; + double minTimeRequired = physicalConfig.getStandardPointDistance() / physicalConfig.getMaxSpeed() * 1000; + + // 鏃堕棿涓嶈兘灏忎簬鐗╃悊鏈�灏忔椂闂� + return timeDiff >= minTimeRequired; + } + } + + /** + * 蹇�熻矾寰勮鍒� - 鍏堝皾璇曠畝鍖栫┖闂磋矾寰勮鍒� + * 瀵逛簬杩戣窛绂昏矾寰勶紝鐩存帴杩斿洖缁撴灉閬垮厤澶嶆潅鐨勬椂绌鸿绠� + */ + private PlannedPath tryFastPathPlanning(String startCode, String endCode, List<double[]> constraints) { + // 妫�鏌ョ紦瀛� + String cacheKey = startCode + "->" + endCode; + if (fastPathCache.containsKey(cacheKey)) { + List<String> cachedPath = fastPathCache.get(cacheKey); + return convertToPlannedPath(cachedPath); + } + + // 璁$畻璺濈锛屽鏋滆窛绂昏緝杩戝垯浣跨敤蹇�熺畻娉� + double distance = getCachedDistance(startCode, endCode); + if (distance > 0 && distance <= 40) { // 40涓崟浣嶄互鍐呬娇鐢ㄥ揩閫熺畻娉� + List<String> fastPath = simpleAStarSearch(startCode, endCode, constraints); + if (fastPath != null && !fastPath.isEmpty()) { + fastPathCache.put(cacheKey, fastPath); // 缂撳瓨缁撴灉 + return convertToPlannedPath(fastPath); + } + } + + return null; // 蹇�熻矾寰勫け璐ワ紝闇�瑕佷娇鐢ㄥ畬鏁寸畻娉� + } + + /** + * 绠�鍖朅*鎼滅储 + */ + private List<String> simpleAStarSearch(String startCode, String endCode, List<double[]> constraints) { + int[] startCoord = JsonUtils.getCoordinate(startCode, pathMapping); + int[] endCoord = JsonUtils.getCoordinate(endCode, pathMapping); + + if (startCoord == null || endCoord == null) { + return null; + } + + PriorityQueue<SimpleAStarNode> openSet = new PriorityQueue<>( + Comparator.comparingDouble(n -> n.fScore) + ); + Set<String> closedSet = new HashSet<>(); + Map<String, Double> gScores = new HashMap<>(); + Map<String, SimpleAStarNode> cameFrom = new HashMap<>(); + + SimpleAStarNode startNode = new SimpleAStarNode( + startCode, startCoord, 0, spatialHeuristic(startCoord, endCoord) + ); + + openSet.offer(startNode); + gScores.put(startCode, 0.0); + + // 绠�鍖栫殑绾︽潫妫�鏌ュ櫒 + FastConstraintChecker constraintChecker = new FastConstraintChecker(constraints); + + int searchDepth = 0; + long searchStartTime = System.currentTimeMillis(); + + while (!openSet.isEmpty() && searchDepth < 3000) { + if (System.currentTimeMillis() - searchStartTime > 5000) { // 5绉掕秴鏃� + break; + } + + SimpleAStarNode current = openSet.poll(); + + if (closedSet.contains(current.code)) { + continue; + } + + closedSet.add(current.code); + searchDepth++; + + if (current.code.equals(endCode)) { + return reconstructSimplePath(cameFrom, startNode, current); + } + + // 鎵╁睍閭诲眳 + expandSimpleNeighbors(current, endCoord, openSet, closedSet, gScores, cameFrom, constraintChecker); + } + + return null; + } + + /** + * 棰勮绠楀父鐢ㄨ窛绂� + */ + private void precomputeCommonDistances() { + System.out.println("璺濈缂撳瓨鍒濆鍖栧畬鎴�"); + } + + /** + * 鑾峰彇缂撳瓨鐨勮窛绂� + */ + private double getCachedDistance(String from, String to) { + String key = from + "-" + to; + return distanceCache.computeIfAbsent(key, k -> { + int[] coord1 = JsonUtils.getCoordinate(from, pathMapping); + int[] coord2 = JsonUtils.getCoordinate(to, pathMapping); + if (coord1 != null && coord2 != null) { + return JsonUtils.calculateManhattanDistance(coord1, coord2); + } + return -1.0; + }); + } + + /** + * 绌洪棿鍚彂寮忓嚱鏁� + */ + private double spatialHeuristic(int[] coord1, int[] coord2) { + return Math.abs(coord1[0] - coord2[0]) + Math.abs(coord1[1] - coord2[1]); + } + + /** + * 鎵╁睍閭诲眳鑺傜偣 + */ + private void expandSimpleNeighbors(SimpleAStarNode current, int[] endCoord, + PriorityQueue<SimpleAStarNode> openSet, + Set<String> closedSet, Map<String, Double> gScores, + Map<String, SimpleAStarNode> cameFrom, + FastConstraintChecker constraintChecker) { + + List<Map<String, String>> neighbors = getNeighbors(current.code); + + for (Map<String, String> neighbor : neighbors) { + String neighborCode = neighbor.get("code"); + + if (closedSet.contains(neighborCode)) { + continue; + } + + if (!constraintChecker.isValidPosition(neighborCode)) { + continue; + } + + double edgeCost = getCachedDistance(current.code, neighborCode); + if (edgeCost < 0) edgeCost = 1.0; // 榛樿杈规潈閲� + + double gScore = gScores.get(current.code) + edgeCost; + + if (!gScores.containsKey(neighborCode) || gScore < gScores.get(neighborCode)) { + gScores.put(neighborCode, gScore); + + int[] neighborCoord = JsonUtils.getCoordinate(neighborCode, pathMapping); + if (neighborCoord != null) { + SimpleAStarNode neighborNode = new SimpleAStarNode( + neighborCode, neighborCoord, gScore, + gScore + spatialHeuristic(neighborCoord, endCoord) + ); + + cameFrom.put(neighborCode, current); + openSet.offer(neighborNode); + } + } + } + } + + /** + * 閲嶅缓绠�鍖栬矾寰� + */ + private List<String> reconstructSimplePath(Map<String, SimpleAStarNode> cameFrom, + SimpleAStarNode startNode, SimpleAStarNode endNode) { + List<String> path = new ArrayList<>(); + SimpleAStarNode current = endNode; + + while (current != null) { + path.add(0, current.code); + current = cameFrom.get(current.code); + } + + return path; + } + + /** + * 灏嗚矾寰勮浆鎹负PlannedPath + */ + private PlannedPath convertToPlannedPath(List<String> pathCodes) { + if (pathCodes == null || pathCodes.isEmpty()) { + return null; + } + + List<PathCode> codeList = new ArrayList<>(); + + for (int i = 0; i < pathCodes.size(); i++) { + String position = pathCodes.get(i); + String direction = "90"; // 榛樿鏂瑰悜 + + // 璁$畻鏂瑰悜 + if (i < pathCodes.size() - 1) { + direction = calculateDirection(position, pathCodes.get(i + 1)); + } + + PathCode pathCode = new PathCode(position, direction); + codeList.add(pathCode); + } + + return new PlannedPath("", "", codeList); + } + + /** + * A*鑺傜偣绫� + */ + private static class SimpleAStarNode { + final String code; + final int[] coordinates; + final double gScore; + final double fScore; + + public SimpleAStarNode(String code, int[] coordinates, double gScore, double fScore) { + this.code = code; + this.coordinates = coordinates; + this.gScore = gScore; + this.fScore = fScore; + } + } + + /** + * 绾︽潫妫�鏌ュ櫒 + */ + private class FastConstraintChecker { + private final Set<String> blockedPositions; + + public FastConstraintChecker(List<double[]> constraints) { + this.blockedPositions = new HashSet<>(); + precomputeBlockedPositions(constraints); + } + + private void precomputeBlockedPositions(List<double[]> constraints) { + if (constraints == null || constraints.isEmpty()) { + return; + } + + for (Map.Entry<String, Map<String, Integer>> entry : pathMapping.entrySet()) { + String pathCode = entry.getKey(); + int[] coord = JsonUtils.getCoordinate(pathCode, pathMapping); + + if (coord != null && isBlocked(coord, constraints)) { + blockedPositions.add(pathCode); + } + } + } + + private boolean isBlocked(int[] coord, List<double[]> constraints) { + for (double[] constraint : constraints) { + double cx = constraint[0]; + double cy = constraint[1]; + double radius = constraint[2]; + + double distance = Math.sqrt(Math.pow(coord[0] - cx, 2) + Math.pow(coord[1] - cy, 2)); + if (distance <= radius) { + return true; + } + } + return false; + } + + public boolean isValidPosition(String pathCode) { + return !blockedPositions.contains(pathCode); + } + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/CollisionDetector.java b/algo-zkd/src/main/java/com/algo/service/CollisionDetector.java new file mode 100644 index 0000000..2e378c5 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/CollisionDetector.java @@ -0,0 +1,567 @@ +package com.algo.service; + +import com.algo.model.CTUPhysicalConfig; +import com.algo.model.Conflict; +import com.algo.model.PathCode; +import com.algo.model.PlannedPath; +import com.algo.util.JsonUtils; + +import java.util.*; + +/** + * 纰版挒妫�娴嬪櫒锛堝寮虹増锛� + * 鐢ㄤ簬妫�娴婥TU璺緞涔嬮棿鐨勬椂绌哄啿绐侊紝鏀寔鐗╃悊鍙傛暟鍜岄珮绮惧害鏃堕棿妫�娴� + */ +public class CollisionDetector { + + /** + * 璺緞鏄犲皠琛� + */ + private final Map<String, Map<String, Integer>> pathMapping; + + /** + * 榛樿鏈�灏忓畨鍏ㄨ窛绂� + */ + private final double defaultMinDistance; + + /** + * 鏃堕棿绮惧害锛堟绉掞級 + */ + private final long timeResolution = 100; // 100姣鐨勬椂闂寸簿搴� + + /** + * 绌洪棿鍒嗚鲸鐜囷紙绫筹級 + */ + private final double spaceResolution = 0.1; // 10鍘樼背鐨勭┖闂寸簿搴� + + /** + * 鏋勯�犲嚱鏁� + * + * @param pathMapping 璺緞鏄犲皠琛� + * @param defaultMinDistance 榛樿鏈�灏忓畨鍏ㄨ窛绂� + */ + public CollisionDetector(Map<String, Map<String, Integer>> pathMapping, + double defaultMinDistance) { + this.pathMapping = pathMapping; + this.defaultMinDistance = defaultMinDistance; + } + + /** + * 鏋勯�犲嚱鏁帮紙浣跨敤榛樿鍙傛暟锛� + * + * @param pathMapping 璺緞鏄犲皠琛� + */ + public CollisionDetector(Map<String, Map<String, Integer>> pathMapping) { + this(pathMapping, 3.0); + } + + /** + * 妫�娴嬭矾寰勫啿绐侊紙澧炲己鐗堬紝鏀寔CTU鐗╃悊鍙傛暟锛� + * + * @param plannedPaths 瑙勫垝璺緞鍒楄〃 + * @return 鍐茬獊鍒楄〃 + */ + public List<Conflict> detectConflicts(List<PlannedPath> plannedPaths) { + List<Conflict> conflicts = new ArrayList<>(); + + if (plannedPaths == null || plannedPaths.size() < 2) { + return conflicts; + } + + System.out.println("寮�濮嬪寮虹増纰版挒妫�娴嬶紝璺緞鏁伴噺: " + plannedPaths.size()); + + // 鏋勫缓楂樼簿搴︽椂绌鸿〃 + Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable = buildEnhancedSpaceTimeTable(plannedPaths); + + // 妫�娴嬮《鐐瑰啿绐侊紙鍚屼竴鏃堕棿鍚屼竴浣嶇疆锛� + List<Conflict> vertexConflicts = detectEnhancedVertexConflicts(spaceTimeTable); + conflicts.addAll(vertexConflicts); + System.out.println("椤剁偣鍐茬獊鏁伴噺: " + vertexConflicts.size()); + + // 妫�娴嬭竟鍐茬獊锛圕TU浜ゆ崲浣嶇疆锛� + List<Conflict> edgeConflicts = detectEnhancedEdgeConflicts(spaceTimeTable); + conflicts.addAll(edgeConflicts); + System.out.println("杈瑰啿绐佹暟閲�: " + edgeConflicts.size()); + + // 妫�娴嬭窡闅忓啿绐侊紙CTU璺濈杩囪繎锛岃�冭檻鐗╃悊鍙傛暟锛� + List<Conflict> followingConflicts = detectEnhancedFollowingConflicts(spaceTimeTable); + conflicts.addAll(followingConflicts); + System.out.println("璺熼殢鍐茬獊鏁伴噺: " + followingConflicts.size()); + + // 妫�娴嬬墿鐞嗗昂瀵稿啿绐� + List<Conflict> physicalConflicts = detectPhysicalSizeConflicts(spaceTimeTable); + conflicts.addAll(physicalConflicts); + System.out.println("鐗╃悊灏哄鍐茬獊鏁伴噺: " + physicalConflicts.size()); + + System.out.println("澧炲己鐗堢鎾炴娴嬪畬鎴愶紝鎬诲啿绐佹暟閲�: " + conflicts.size()); + return conflicts; + } + + /** + * 鏋勫缓澧炲己鐨勬椂绌鸿〃锛堥珮绮惧害鏃堕棿鍜岀墿鐞嗗弬鏁帮級 + * + * @param plannedPaths 瑙勫垝璺緞鍒楄〃 + * @return 澧炲己鏃剁┖琛� + */ + private Map<Long, List<EnhancedSpaceTimeNode>> buildEnhancedSpaceTimeTable(List<PlannedPath> plannedPaths) { + Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable = new HashMap<>(); + + for (PlannedPath path : plannedPaths) { + String agvId = path.getAgvId(); + List<PathCode> codeList = path.getCodeList(); + + if (codeList == null || codeList.isEmpty()) { + continue; + } + + // 鑾峰彇CTU鐨勭墿鐞嗛厤缃紙杩欓噷闇�瑕佷粠鏌愪釜鍦版柟鑾峰彇锛屽彲鑳介渶瑕佹墿灞昉lannedPath绫伙級 + CTUPhysicalConfig physicalConfig = getPhysicalConfigForCTU(agvId); + + long currentTime = System.currentTimeMillis(); // 鍩哄噯鏃堕棿 + + for (int i = 0; i < codeList.size(); i++) { + PathCode pathCode = codeList.get(i); + String position = pathCode.getCode(); + + int[] coordinates = JsonUtils.getCoordinate(position, pathMapping); + if (coordinates != null) { + // 璁$畻绮剧‘鐨勫埌杈炬椂闂� + long arrivalTime = calculateArrivalTime(currentTime, i, codeList, physicalConfig); + + // 璁$畻鍋滅暀鏃堕棿 + long departureTime = calculateDepartureTime(arrivalTime, pathCode, physicalConfig); + + // 鍒涘缓鏃堕棿娈靛唴鐨勫涓椂闂寸偣 + for (long timePoint = arrivalTime; timePoint <= departureTime; timePoint += timeResolution) { + EnhancedSpaceTimeNode node = new EnhancedSpaceTimeNode( + agvId, position, coordinates, timePoint, arrivalTime, departureTime, physicalConfig + ); + + spaceTimeTable.computeIfAbsent(timePoint, k -> new ArrayList<>()).add(node); + } + } + } + } + + return spaceTimeTable; + } + + /** + * 鑾峰彇CTU鐨勭墿鐞嗛厤缃� + * + * @param agvId CTU缂栧彿 + * @return 鐗╃悊閰嶇疆 + */ + private CTUPhysicalConfig getPhysicalConfigForCTU(String agvId) { + // 杩欓噷搴旇浠庨厤缃鐞嗗櫒鎴栨暟鎹簱鑾峰彇瀹為檯鐨凜TU鐗╃悊鍙傛暟 + // 鏆傛椂杩斿洖榛樿閰嶇疆 + CTUPhysicalConfig config = new CTUPhysicalConfig(); + config.setMaxSpeed(2.0); + config.setNormalSpeed(1.5); + config.setMaxAcceleration(1.0); + config.setMaxDeceleration(1.5); + config.setTurnTime90(2.0); + config.setTurnTime180(4.0); + config.setMinSafetyDistance(defaultMinDistance); + config.setMinFollowingDistance(2.0); + config.setCtuLength(1.2); + config.setCtuWidth(0.8); + config.setStartupTime(1.0); + config.setStopTime(0.5); + config.setStandardPointDistance(1.0); + return config; + } + + /** + * 璁$畻鍒拌揪鏃堕棿 + * + * @param startTime 璧峰鏃堕棿 + * @param pathIndex 璺緞绱㈠紩 + * @param codeList 璺緞浠g爜鍒楄〃 + * @param config 鐗╃悊閰嶇疆 + * @return 鍒拌揪鏃堕棿 + */ + private long calculateArrivalTime(long startTime, int pathIndex, List<PathCode> codeList, CTUPhysicalConfig config) { + if (pathIndex == 0) { + return startTime; + } + + long travelTime = 0; + + for (int i = 1; i <= pathIndex; i++) { + PathCode currentCode = codeList.get(i); + PathCode previousCode = codeList.get(i - 1); + + // 璁$畻绉诲姩鏃堕棿 + double distance = config.getStandardPointDistance(); + double speed = config.getNormalSpeed(); + travelTime += (long) ((distance / speed) * 1000); // 杞崲涓烘绉� + + // 濡傛灉鏈夋柟鍚戝彉鍖栵紝澧炲姞杞悜鏃堕棿 + if (!currentCode.getDirection().equals(previousCode.getDirection())) { + double turnTime = calculateTurnTime(previousCode.getDirection(), currentCode.getDirection(), config); + travelTime += (long) (turnTime * 1000); + } + + // 鑰冭檻鍔犻�熷拰鍑忛�熸椂闂� + if (i == 1) { + travelTime += (long) (config.getStartupTime() * 1000); + } + } + + return startTime + travelTime; + } + + /** + * 璁$畻绂诲紑鏃堕棿 + * + * @param arrivalTime 鍒拌揪鏃堕棿 + * @param pathCode 璺緞浠g爜 + * @param config 鐗╃悊閰嶇疆 + * @return 绂诲紑鏃堕棿 + */ + private long calculateDepartureTime(long arrivalTime, PathCode pathCode, CTUPhysicalConfig config) { + long stayTime = 500; // 榛樿鍋滅暀鏃堕棿500姣 + + // 鏍规嵁璺緞浠g爜绫诲瀷纭畾鍋滅暀鏃堕棿 + if (pathCode.isTargetPoint()) { + if ("1".equals(pathCode.getPosType())) { // 鍙栬揣 + stayTime = 3000; // 鍙栬揣闇�瑕�3绉� + } else if ("2".equals(pathCode.getPosType())) { // 鏀捐揣 + stayTime = 2000; // 鏀捐揣闇�瑕�2绉� + } + } + + return arrivalTime + stayTime; + } + + /** + * 璁$畻杞悜鏃堕棿 + * + * @param fromDirection 璧峰鏂瑰悜 + * @param toDirection 鐩爣鏂瑰悜 + * @param config 鐗╃悊閰嶇疆 + * @return 杞悜鏃堕棿锛堢锛� + */ + private double calculateTurnTime(String fromDirection, String toDirection, CTUPhysicalConfig config) { + if (fromDirection.equals(toDirection)) { + return 0.0; + } + + // 绠�鍖栫殑鏂瑰悜杞崲璁$畻 + // 瀹為檯瀹炵幇涓渶瑕佹牴鎹叿浣撶殑鏂瑰悜缂栫爜璁$畻瑙掑害宸� + int angleDiff = Math.abs(Integer.parseInt(toDirection) - Integer.parseInt(fromDirection)); + angleDiff = Math.min(angleDiff, 4 - angleDiff); // 鑰冭檻鐜舰 + + switch (angleDiff) { + case 1: + return config.getTurnTime90(); + case 2: + return config.getTurnTime180(); + default: + return config.getTurnTime90() * angleDiff; + } + } + + /** + * 妫�娴嬪寮虹殑椤剁偣鍐茬獊 + * + * @param spaceTimeTable 鏃剁┖琛� + * @return 椤剁偣鍐茬獊鍒楄〃 + */ + private List<Conflict> detectEnhancedVertexConflicts(Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable) { + List<Conflict> conflicts = new ArrayList<>(); + + for (Map.Entry<Long, List<EnhancedSpaceTimeNode>> entry : spaceTimeTable.entrySet()) { + long timePoint = entry.getKey(); + List<EnhancedSpaceTimeNode> nodes = entry.getValue(); + + // 鎸変綅缃垎缁� + Map<String, List<EnhancedSpaceTimeNode>> positionGroups = new HashMap<>(); + for (EnhancedSpaceTimeNode node : nodes) { + positionGroups.computeIfAbsent(node.position, k -> new ArrayList<>()).add(node); + } + + // 妫�鏌ユ瘡涓綅缃槸鍚︽湁澶氫釜CTU + for (Map.Entry<String, List<EnhancedSpaceTimeNode>> posEntry : positionGroups.entrySet()) { + String position = posEntry.getKey(); + List<EnhancedSpaceTimeNode> ctuNodes = posEntry.getValue(); + + if (ctuNodes.size() > 1) { + // 杩涗竴姝ユ鏌ユ椂闂撮噸鍙� + for (int i = 0; i < ctuNodes.size(); i++) { + for (int j = i + 1; j < ctuNodes.size(); j++) { + EnhancedSpaceTimeNode node1 = ctuNodes.get(i); + EnhancedSpaceTimeNode node2 = ctuNodes.get(j); + + // 妫�鏌ユ椂闂存鏄惁閲嶅彔 + if (timeRangeOverlap(node1.arrivalTime, node1.departureTime, + node2.arrivalTime, node2.departureTime)) { + Conflict conflict = new Conflict( + "enhanced_vertex", + node1.agvId, + node2.agvId, + (int) (timePoint / 1000), // 杞崲涓虹鐢ㄤ簬鏄剧ず + position, + position, + String.format("CTU %s 鍜� %s 鍦ㄦ椂闂� %d 鍗犵敤鍚屼竴浣嶇疆 %s锛堟椂闂撮噸鍙狅級", + node1.agvId, node2.agvId, timePoint / 1000, position) + ); + conflicts.add(conflict); + } + } + } + } + } + } + + return conflicts; + } + + /** + * 妫�娴嬪寮虹殑杈瑰啿绐� + * + * @param spaceTimeTable 鏃剁┖琛� + * @return 杈瑰啿绐佸垪琛� + */ + private List<Conflict> detectEnhancedEdgeConflicts(Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable) { + List<Conflict> conflicts = new ArrayList<>(); + + if (spaceTimeTable.isEmpty()) { + return conflicts; + } + + List<Long> sortedTimes = new ArrayList<>(spaceTimeTable.keySet()); + Collections.sort(sortedTimes); + + for (int i = 0; i < sortedTimes.size() - 1; i++) { + long currentTime = sortedTimes.get(i); + long nextTime = sortedTimes.get(i + 1); + + // 鍙鏌ヨ繛缁殑鏃堕棿鐐� + if (nextTime - currentTime <= timeResolution * 2) { + List<EnhancedSpaceTimeNode> currentNodes = spaceTimeTable.get(currentTime); + List<EnhancedSpaceTimeNode> nextNodes = spaceTimeTable.get(nextTime); + + conflicts.addAll(detectPositionSwapping(currentNodes, nextNodes, currentTime, nextTime)); + } + } + + return conflicts; + } + + /** + * 妫�娴嬩綅缃氦鎹� + * + * @param currentNodes 褰撳墠鏃堕棿鐨勮妭鐐� + * @param nextNodes 涓嬩竴鏃堕棿鐨勮妭鐐� + * @param currentTime 褰撳墠鏃堕棿 + * @param nextTime 涓嬩竴鏃堕棿 + * @return 鍐茬獊鍒楄〃 + */ + private List<Conflict> detectPositionSwapping(List<EnhancedSpaceTimeNode> currentNodes, + List<EnhancedSpaceTimeNode> nextNodes, + long currentTime, long nextTime) { + List<Conflict> conflicts = new ArrayList<>(); + + Map<String, String> currentPositions = new HashMap<>(); + Map<String, String> nextPositions = new HashMap<>(); + + for (EnhancedSpaceTimeNode node : currentNodes) { + currentPositions.put(node.agvId, node.position); + } + + for (EnhancedSpaceTimeNode node : nextNodes) { + nextPositions.put(node.agvId, node.position); + } + + for (Map.Entry<String, String> entry1 : currentPositions.entrySet()) { + String ctu1 = entry1.getKey(); + String pos1Current = entry1.getValue(); + + for (Map.Entry<String, String> entry2 : currentPositions.entrySet()) { + String ctu2 = entry2.getKey(); + String pos2Current = entry2.getValue(); + + if (ctu1.compareTo(ctu2) >= 0) { + continue; + } + + String pos1Next = nextPositions.get(ctu1); + String pos2Next = nextPositions.get(ctu2); + + if (pos1Next != null && pos2Next != null && + pos1Current.equals(pos2Next) && pos2Current.equals(pos1Next)) { + + Conflict conflict = new Conflict( + "enhanced_edge", + ctu1, + ctu2, + (int) (currentTime / 1000), + pos1Current, + pos2Current, + String.format("CTU %s 鍜� %s 鍦ㄦ椂闂� %d-%d 浜ゆ崲浣嶇疆 %s<->%s", + ctu1, ctu2, currentTime / 1000, nextTime / 1000, pos1Current, pos2Current) + ); + conflicts.add(conflict); + } + } + } + + return conflicts; + } + + /** + * 妫�娴嬪寮虹殑璺熼殢鍐茬獊锛堣�冭檻CTU鐗╃悊鍙傛暟锛� + * + * @param spaceTimeTable 鏃剁┖琛� + * @return 璺熼殢鍐茬獊鍒楄〃 + */ + private List<Conflict> detectEnhancedFollowingConflicts(Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable) { + List<Conflict> conflicts = new ArrayList<>(); + + for (Map.Entry<Long, List<EnhancedSpaceTimeNode>> entry : spaceTimeTable.entrySet()) { + long timePoint = entry.getKey(); + List<EnhancedSpaceTimeNode> nodes = entry.getValue(); + + for (int i = 0; i < nodes.size(); i++) { + for (int j = i + 1; j < nodes.size(); j++) { + EnhancedSpaceTimeNode node1 = nodes.get(i); + EnhancedSpaceTimeNode node2 = nodes.get(j); + + double distance = calculateDistance(node1.coordinates, node2.coordinates); + double minSafeDistance = Math.max( + node1.physicalConfig.getMinFollowingDistance(), + node2.physicalConfig.getMinFollowingDistance() + ); + + if (distance > 0 && distance < minSafeDistance) { + Conflict conflict = new Conflict( + "enhanced_follow", + node1.agvId, + node2.agvId, + (int) (timePoint / 1000), + node1.position, + node2.position, + String.format("CTU %s 鍜� %s 鍦ㄦ椂闂� %d 璺濈杩囪繎 (%.2f < %.2f)", + node1.agvId, node2.agvId, timePoint / 1000, distance, minSafeDistance) + ); + conflicts.add(conflict); + } + } + } + } + + return conflicts; + } + + /** + * 妫�娴嬬墿鐞嗗昂瀵稿啿绐� + * + * @param spaceTimeTable 鏃剁┖琛� + * @return 鐗╃悊鍐茬獊鍒楄〃 + */ + private List<Conflict> detectPhysicalSizeConflicts(Map<Long, List<EnhancedSpaceTimeNode>> spaceTimeTable) { + List<Conflict> conflicts = new ArrayList<>(); + + for (Map.Entry<Long, List<EnhancedSpaceTimeNode>> entry : spaceTimeTable.entrySet()) { + long timePoint = entry.getKey(); + List<EnhancedSpaceTimeNode> nodes = entry.getValue(); + + for (int i = 0; i < nodes.size(); i++) { + for (int j = i + 1; j < nodes.size(); j++) { + EnhancedSpaceTimeNode node1 = nodes.get(i); + EnhancedSpaceTimeNode node2 = nodes.get(j); + + if (checkPhysicalCollision(node1, node2)) { + Conflict conflict = new Conflict( + "physical_size", + node1.agvId, + node2.agvId, + (int) (timePoint / 1000), + node1.position, + node2.position, + String.format("CTU %s 鍜� %s 鍦ㄦ椂闂� %d 鍙戠敓鐗╃悊灏哄鍐茬獊", + node1.agvId, node2.agvId, timePoint / 1000) + ); + conflicts.add(conflict); + } + } + } + } + + return conflicts; + } + + /** + * 妫�鏌ヤ袱涓狢TU鏄惁鍙戠敓鐗╃悊纰版挒 + * + * @param node1 CTU鑺傜偣1 + * @param node2 CTU鑺傜偣2 + * @return 鏄惁纰版挒 + */ + private boolean checkPhysicalCollision(EnhancedSpaceTimeNode node1, EnhancedSpaceTimeNode node2) { + double distance = calculateDistance(node1.coordinates, node2.coordinates); + + // 鑰冭檻CTU鐨勭墿鐞嗗昂瀵� + double ctu1Radius = Math.max(node1.physicalConfig.getCtuLength(), node1.physicalConfig.getCtuWidth()) / 2; + double ctu2Radius = Math.max(node2.physicalConfig.getCtuLength(), node2.physicalConfig.getCtuWidth()) / 2; + + double minClearance = ctu1Radius + ctu2Radius + spaceResolution; + + return distance > 0 && distance < minClearance; + } + + /** + * 妫�鏌ユ椂闂磋寖鍥存槸鍚﹂噸鍙� + * + * @param start1 寮�濮嬫椂闂�1 + * @param end1 缁撴潫鏃堕棿1 + * @param start2 寮�濮嬫椂闂�2 + * @param end2 缁撴潫鏃堕棿2 + * @return 鏄惁閲嶅彔 + */ + private boolean timeRangeOverlap(long start1, long end1, long start2, long end2) { + return Math.max(start1, start2) < Math.min(end1, end2); + } + + /** + * 璁$畻涓や釜鍧愭爣涔嬮棿鐨勮窛绂� + * + * @param coord1 鍧愭爣1 + * @param coord2 鍧愭爣2 + * @return 璺濈鍊� + */ + private double calculateDistance(int[] coord1, int[] coord2) { + if (coord1 == null || coord2 == null || coord1.length != 2 || coord2.length != 2) { + return -1; + } + + return Math.sqrt(Math.pow(coord1[0] - coord2[0], 2) + Math.pow(coord1[1] - coord2[1], 2)); + } + + /** + * 澧炲己鐨勬椂绌鸿妭鐐瑰唴閮ㄧ被 + */ + private static class EnhancedSpaceTimeNode { + final String agvId; + final String position; + final int[] coordinates; + final long timePoint; + final long arrivalTime; + final long departureTime; + final CTUPhysicalConfig physicalConfig; + + public EnhancedSpaceTimeNode(String agvId, String position, int[] coordinates, + long timePoint, long arrivalTime, long departureTime, + CTUPhysicalConfig physicalConfig) { + this.agvId = agvId; + this.position = position; + this.coordinates = coordinates; + this.timePoint = timePoint; + this.arrivalTime = arrivalTime; + this.departureTime = departureTime; + this.physicalConfig = physicalConfig; + } + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/CollisionResolver.java b/algo-zkd/src/main/java/com/algo/service/CollisionResolver.java new file mode 100644 index 0000000..cdf70d7 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/CollisionResolver.java @@ -0,0 +1,306 @@ +package com.algo.service; + +import com.algo.model.Conflict; +import com.algo.model.ExecutingTask; +import com.algo.model.PathCode; +import com.algo.model.PlannedPath; + +import java.util.*; + +/** + * 纰版挒瑙e喅鍣� + * 鐢ㄤ簬瑙e喅AGV璺緞涔嬮棿鐨勫啿绐� + */ +public class CollisionResolver { + + /** + * 纰版挒妫�娴嬪櫒 + */ + private final CollisionDetector collisionDetector; + + /** + * 鏋勯�犲嚱鏁� + * + * @param collisionDetector 纰版挒妫�娴嬪櫒 + */ + public CollisionResolver(CollisionDetector collisionDetector) { + this.collisionDetector = collisionDetector; + } + + /** + * 瑙e喅璺緞鍐茬獊 + * + * @param plannedPaths 瑙勫垝璺緞鍒楄〃 + * @param conflicts 鍐茬獊鍒楄〃 + * @param executingTasks 鎵ц涓换鍔″垪琛� + * @return 瑙e喅鍐茬獊鍚庣殑璺緞鍒楄〃 + */ + public List<PlannedPath> resolveConflicts(List<PlannedPath> plannedPaths, + List<Conflict> conflicts, + List<ExecutingTask> executingTasks) { + if (conflicts == null || conflicts.isEmpty()) { + return plannedPaths; + } + + System.out.println("寮�濮嬭В鍐� " + conflicts.size() + " 涓矾寰勫啿绐�"); + + // 鏋勫缓璺緞瀛楀吀渚夸簬蹇�熻闂� + Map<String, PlannedPath> pathsMap = new HashMap<>(); + for (PlannedPath path : plannedPaths) { + pathsMap.put(path.getAgvId(), path); + } + + // 鎸夋椂闂存鎺掑簭澶勭悊鍐茬獊 + List<Conflict> sortedConflicts = new ArrayList<>(conflicts); + sortedConflicts.sort(Comparator.comparingInt(Conflict::getTimeStep)); + + // 閫愪釜瑙e喅鍐茬獊 + for (Conflict conflict : sortedConflicts) { + resolveSingleConflict(pathsMap, conflict, executingTasks); + } + + List<PlannedPath> resolvedPaths = new ArrayList<>(pathsMap.values()); + + // 楠岃瘉瑙e喅缁撴灉 + List<Conflict> remainingConflicts = collisionDetector.detectConflicts(resolvedPaths); + System.out.println("鍐茬獊瑙e喅瀹屾垚锛屽墿浣欏啿绐佹暟閲�: " + remainingConflicts.size()); + + return resolvedPaths; + } + + /** + * 瑙e喅鍗曚釜鍐茬獊 + * + * @param pathsMap 璺緞鏄犲皠 + * @param conflict 鍐茬獊 + * @param executingTasks 鎵ц涓换鍔″垪琛� + */ + private void resolveSingleConflict(Map<String, PlannedPath> pathsMap, + Conflict conflict, + List<ExecutingTask> executingTasks) { + String conflictType = conflict.getType(); + + switch (conflictType) { + case "vertex": + resolveVertexConflict(pathsMap, conflict, executingTasks); + break; + case "edge": + resolveEdgeConflict(pathsMap, conflict, executingTasks); + break; + case "follow": + resolveFollowingConflict(pathsMap, conflict, executingTasks); + break; + default: + System.out.println("鏈煡鍐茬獊绫诲瀷: " + conflictType); + } + } + + /** + * 瑙e喅椤剁偣鍐茬獊 + * + * @param pathsMap 璺緞鏄犲皠 + * @param conflict 鍐茬獊 + * @param executingTasks 鎵ц涓换鍔″垪琛� + */ + private void resolveVertexConflict(Map<String, PlannedPath> pathsMap, + Conflict conflict, + List<ExecutingTask> executingTasks) { + String agv1 = conflict.getAgv1(); + String agv2 = conflict.getAgv2(); + int timeStep = conflict.getTimeStep(); + + // 璇勪及AGV浼樺厛绾� + AGVPriority priority1 = evaluateAgvPriority(agv1, pathsMap.get(agv1), executingTasks); + AGVPriority priority2 = evaluateAgvPriority(agv2, pathsMap.get(agv2), executingTasks); + + // 浼樺厛绾т綆鐨凙GV杩涜寤惰繜 + if (priority1.priorityScore >= priority2.priorityScore) { + // agv2浼樺厛绾т綆锛屽欢杩焌gv2 + addDelayToPath(pathsMap.get(agv2), timeStep, 1); + System.out.println("涓鸿В鍐抽《鐐瑰啿绐侊紝AGV " + agv2 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜1姝�"); + } else { + // agv1浼樺厛绾т綆锛屽欢杩焌gv1 + addDelayToPath(pathsMap.get(agv1), timeStep, 1); + System.out.println("涓鸿В鍐抽《鐐瑰啿绐侊紝AGV " + agv1 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜1姝�"); + } + } + + /** + * 瑙e喅杈瑰啿绐� + * + * @param pathsMap 璺緞鏄犲皠 + * @param conflict 鍐茬獊 + * @param executingTasks 鎵ц涓换鍔″垪琛� + */ + private void resolveEdgeConflict(Map<String, PlannedPath> pathsMap, + Conflict conflict, + List<ExecutingTask> executingTasks) { + String agv1 = conflict.getAgv1(); + String agv2 = conflict.getAgv2(); + int timeStep = conflict.getTimeStep(); + + // 璇勪及AGV浼樺厛绾� + AGVPriority priority1 = evaluateAgvPriority(agv1, pathsMap.get(agv1), executingTasks); + AGVPriority priority2 = evaluateAgvPriority(agv2, pathsMap.get(agv2), executingTasks); + + // 浼樺厛绾т綆鐨凙GV杩涜寤惰繜 + if (priority1.priorityScore >= priority2.priorityScore) { + // agv2浼樺厛绾т綆锛屽欢杩焌gv2 + addDelayToPath(pathsMap.get(agv2), timeStep, 2); + System.out.println("涓鸿В鍐宠竟鍐茬獊锛孉GV " + agv2 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜2姝�"); + } else { + // agv1浼樺厛绾т綆锛屽欢杩焌gv1 + addDelayToPath(pathsMap.get(agv1), timeStep, 2); + System.out.println("涓鸿В鍐宠竟鍐茬獊锛孉GV " + agv1 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜2姝�"); + } + } + + /** + * 瑙e喅璺熼殢鍐茬獊 + * + * @param pathsMap 璺緞鏄犲皠 + * @param conflict 鍐茬獊 + * @param executingTasks 鎵ц涓换鍔″垪琛� + */ + private void resolveFollowingConflict(Map<String, PlannedPath> pathsMap, + Conflict conflict, + List<ExecutingTask> executingTasks) { + String agv1 = conflict.getAgv1(); + String agv2 = conflict.getAgv2(); + int timeStep = conflict.getTimeStep(); + + // 璇勪及AGV浼樺厛绾� + AGVPriority priority1 = evaluateAgvPriority(agv1, pathsMap.get(agv1), executingTasks); + AGVPriority priority2 = evaluateAgvPriority(agv2, pathsMap.get(agv2), executingTasks); + + // 浼樺厛绾т綆鐨凙GV杩涜寤惰繜 + if (priority1.priorityScore >= priority2.priorityScore) { + // agv2浼樺厛绾т綆锛屽欢杩焌gv2 + addDelayToPath(pathsMap.get(agv2), timeStep, 1); + System.out.println("涓鸿В鍐宠窡闅忓啿绐侊紝AGV " + agv2 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜1姝�"); + } else { + // agv1浼樺厛绾т綆锛屽欢杩焌gv1 + addDelayToPath(pathsMap.get(agv1), timeStep, 1); + System.out.println("涓鸿В鍐宠窡闅忓啿绐侊紝AGV " + agv1 + " 鍦ㄦ椂闂存 " + timeStep + " 寤惰繜1姝�"); + } + } + + /** + * 璇勪及AGV浼樺厛绾� - 浼樺寲鐗堟湰锛屽彧淇濈暀蹇呰瀛楁 + * + * @param agvId AGV缂栧彿 + * @param path 璺緞 + * @param executingTasks 鎵ц涓换鍔″垪琛� + * @return AGV浼樺厛绾т俊鎭� + */ + private AGVPriority evaluateAgvPriority(String agvId, PlannedPath path, List<ExecutingTask> executingTasks) { + // 鏌ユ壘瀵瑰簲鐨勬墽琛屼换鍔� + ExecutingTask task = null; + for (ExecutingTask et : executingTasks) { + if (et.getAgvId().equals(agvId)) { + task = et; + break; + } + } + + double priorityScore = 0.0; + String explanation = "榛樿浼樺厛绾�"; + + if (task != null) { + String taskStatus = task.getTaskType(); + int taskPriority = task.getPriority(); + + // 鍩轰簬浠诲姟绫诲瀷鐨勪紭鍏堢骇璇勫垎 + switch (taskStatus) { + case "delivery": + priorityScore += 50; // 閫佽揣浠诲姟浼樺厛绾ч珮 + explanation = "閫佽揣浠诲姟 - 楂樹紭鍏堢骇"; + break; + case "pickup": + priorityScore += 30; // 鍙栬揣浠诲姟涓瓑浼樺厛绾� + explanation = "鍙栬揣浠诲姟 - 涓瓑浼樺厛绾�"; + break; + case "charging": + priorityScore += 20; // 鍏呯數浠诲姟浣庝紭鍏堢骇 + explanation = "鍏呯數浠诲姟 - 浣庝紭鍏堢骇"; + break; + default: + priorityScore += 10; // 鍏朵粬浠诲姟鏈�浣庝紭鍏堢骇 + explanation = "鍏朵粬浠诲姟 - 鏈�浣庝紭鍏堢骇"; + } + + // 浠诲姟浼樺厛绾у姞鎴� + priorityScore += taskPriority * 10; + + // 璺緞闀垮害鍥犲瓙锛堣矾寰勮秺鐭紭鍏堢骇瓒婇珮锛� + if (path != null && path.getCodeList() != null) { + double pathLengthFactor = Math.max(0, 50 - path.getCodeList().size()); + priorityScore += pathLengthFactor; + } + } + + return new AGVPriority(agvId, priorityScore, explanation); + } + + /** + * 涓鸿矾寰勬坊鍔犲欢杩� + * + * @param path 璺緞 + * @param timeStep 寤惰繜寮�濮嬬殑鏃堕棿姝� + * @param delaySteps 寤惰繜姝ユ暟 + */ + private void addDelayToPath(PlannedPath path, int timeStep, int delaySteps) { + if (path == null || path.getCodeList() == null || path.getCodeList().isEmpty()) { + return; + } + + List<PathCode> codeList = path.getCodeList(); + + // 纭繚鏃堕棿姝ュ湪鏈夋晥鑼冨洿鍐� + if (timeStep < 0 || timeStep >= codeList.size()) { + return; + } + + // 鑾峰彇寤惰繜浣嶇疆鐨勮矾寰勪唬鐮� + PathCode delayCode = codeList.get(timeStep); + + // 鍒涘缓寤惰繜姝ラ + List<PathCode> delaySteps_list = new ArrayList<>(); + for (int i = 0; i < delaySteps; i++) { + PathCode waitCode = new PathCode(delayCode.getCode(), delayCode.getDirection()); + waitCode.setActionType(delayCode.getActionType()); + waitCode.setTaskId(delayCode.getTaskId()); + waitCode.setPosType(delayCode.getPosType()); + waitCode.setLev(delayCode.getLev()); + waitCode.setTargetPoint(false); // 绛夊緟姝ラ涓嶆槸鐩爣鐐� + delaySteps_list.add(waitCode); + } + + // 鎻掑叆寤惰繜姝ラ + codeList.addAll(timeStep, delaySteps_list); + + // 鏇存柊璺緞 + path.setCodeList(codeList); + } + + /** + * AGV浼樺厛绾ц瘎浼扮粨鏋滃唴閮ㄧ被 - 浼樺寲鐗堟湰锛屽彧淇濈暀蹇呰瀛楁 + */ + private static class AGVPriority { + final String agvId; + final double priorityScore; + final String explanation; + + public AGVPriority(String agvId, double priorityScore, String explanation) { + this.agvId = agvId; + this.priorityScore = priorityScore; + this.explanation = explanation; + } + + @Override + public String toString() { + return String.format("AGV %s: 浼樺厛绾�=%.1f, 璇存槑=%s", + agvId, priorityScore, explanation); + } + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/ExecutingTaskExtractor.java b/algo-zkd/src/main/java/com/algo/service/ExecutingTaskExtractor.java new file mode 100644 index 0000000..233b0f0 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/ExecutingTaskExtractor.java @@ -0,0 +1,478 @@ +package com.algo.service; + +import com.algo.model.AGVStatus; +import com.algo.model.BackpackData; +import com.algo.model.ExecutingTask; +import com.algo.model.TaskData; +import com.algo.util.JsonUtils; + +import java.util.*; + +/** + * 鎵ц涓换鍔℃彁鍙栧櫒 + * 璐熻矗浠嶢GV鐘舵�佷腑鎻愬彇褰撳墠姝e湪鎵ц鐨勪换鍔� + */ +public class ExecutingTaskExtractor { + + /** + * 璺緞鏄犲皠琛� + */ + private Map<String, Map<String, Integer>> pathMapping; + + /** + * 浠诲姟鏁版嵁鏄犲皠琛� + */ + private Map<String, TaskData> taskDataMap; + + /** + * 鍧愭爣鍒拌矾寰勭紪鍙风殑鏄犲皠 + */ + private Map<String, String> coordToCode; + + /** + * 鍙栬揣浣嶇疆鍒楄〃 + */ + private List<String> pickupPositions; + + /** + * 鍏呯數浣嶇疆鍒楄〃 + */ + private List<String> chargingPositions; + + /** + * 閫佽揣浣嶇疆鍒楄〃 + */ + private List<String> deliveryPositions; + + /** + * 寰呮満浣嶇疆鍒楄〃 + */ + private List<String> standbyPositions; + + /** + * 鏋勯�犲嚱鏁� + * + * @param pathMapping 璺緞鏄犲皠琛� + * @param taskDataList 浠诲姟鏁版嵁鍒楄〃 + */ + public ExecutingTaskExtractor(Map<String, Map<String, Integer>> pathMapping, List<TaskData> taskDataList) { + this.pathMapping = pathMapping; + this.coordToCode = new HashMap<>(); + this.taskDataMap = new HashMap<>(); + + // 鏋勫缓浠诲姟鏁版嵁鏄犲皠琛� + if (taskDataList != null) { + for (TaskData taskData : taskDataList) { + taskDataMap.put(taskData.getTaskId(), taskData); + } + } + + // 棰勮绠楀潗鏍囨槧灏� + buildCoordToCodeMapping(); + + // 棰勫垎绫讳綅缃被鍨� + classifyPositions(); + + System.out.println("浠诲姟鎻愬彇鍣ㄥ垵濮嬪寲瀹屾垚锛屽垎绫讳綅缃細鍙栬揣=" + pickupPositions.size() + + ", 鍏呯數=" + chargingPositions.size() + + ", 閫佽揣=" + deliveryPositions.size() + + ", 寰呮満=" + standbyPositions.size() + + ", 浠诲姟鏁版嵁=" + taskDataMap.size()); + } + + /** + * 鎻愬彇鎵ц涓殑浠诲姟 + * + * @param agvStatusList AGV鐘舵�佸垪琛� + * @return 鎵ц涓换鍔″垪琛� + */ + public List<ExecutingTask> extractExecutingTasks(List<AGVStatus> agvStatusList) { + List<ExecutingTask> executingTasks = new ArrayList<>(); + + for (AGVStatus agvStatus : agvStatusList) { + List<ExecutingTask> agvTasks = extractAgvTasks(agvStatus); + executingTasks.addAll(agvTasks); + } + + System.out.println("鎻愬彇鍒� " + executingTasks.size() + " 涓墽琛屼腑浠诲姟"); + return executingTasks; + } + + /** + * 鎻愬彇鍗曚釜AGV鐨勬墽琛屼腑浠诲姟 + * + * @param agvStatus AGV鐘舵�� + * @return 鎵ц涓换鍔″垪琛� + */ + private List<ExecutingTask> extractAgvTasks(AGVStatus agvStatus) { + List<ExecutingTask> tasks = new ArrayList<>(); + + // 妫�鏌GV鏄惁鍙敤 + if (!agvStatus.isAvailable()) { + return tasks; + } + + // 鍒嗘瀽鑳岀瘬鐘舵�� + List<BackpackData> backpack = agvStatus.getBackpack(); + if (backpack == null || backpack.isEmpty()) { + return tasks; + } + + // 鍒嗗埆鏀堕泦宸茶杞藉拰鏈杞界殑浠诲姟 + List<BackpackData> loadedTasks = new ArrayList<>(); + List<BackpackData> unloadedTasks = new ArrayList<>(); + + for (BackpackData bp : backpack) { + if (bp.getTaskId() != null && !bp.getTaskId().trim().isEmpty()) { + TaskData taskData = getTaskData(bp.getTaskId()); + if (taskData != null) { + if (bp.isLoaded()) { + loadedTasks.add(bp); + } else { + unloadedTasks.add(bp); + } + } + } + } + + // 纭畾涓嬩竴姝ユ渶浼樿鍔� + ExecutingTask nextTask = determineNextBestAction(agvStatus, loadedTasks, unloadedTasks); + if (nextTask != null) { + tasks.add(nextTask); + } + + return tasks; + } + + /** + * 纭畾AGV涓嬩竴姝ユ渶浼樿鍔� + * 浣跨敤鍔犳潈鎴愭湰绠楁硶缁煎悎鑰冭檻璺濈鍜屼换鍔$被鍨� + * + * @param agvStatus AGV鐘舵�� + * @param loadedTasks 宸茶杞戒换鍔� + * @param unloadedTasks 鏈杞戒换鍔� + * @return 涓嬩竴姝ユ墽琛屼换鍔� + */ + private ExecutingTask determineNextBestAction(AGVStatus agvStatus, + List<BackpackData> loadedTasks, + List<BackpackData> unloadedTasks) { + String currentPosition = agvStatus.getPosition(); + List<TaskOption> taskOptions = new ArrayList<>(); + + // 1. 鏀堕泦鎵�鏈夊彲閫夌殑閫佽揣浠诲姟 + for (BackpackData task : loadedTasks) { + TaskData taskData = getTaskData(task.getTaskId()); + if (taskData != null && taskData.getEnd() != null) { + double distance = calculateDistance(currentPosition, taskData.getEnd()); + if (distance >= 0) { + double cost = calculateTaskCost(distance, "delivery", taskData.getPriority(), agvStatus); + taskOptions.add(new TaskOption(task, true, distance, cost, "delivery")); + } + } + } + + // 2. 鏀堕泦鎵�鏈夊彲閫夌殑鍙栬揣浠诲姟 + for (BackpackData task : unloadedTasks) { + TaskData taskData = getTaskData(task.getTaskId()); + if (taskData != null && taskData.getStart() != null) { + double distance = calculateDistance(currentPosition, taskData.getStart()); + if (distance >= 0) { + double cost = calculateTaskCost(distance, "pickup", taskData.getPriority(), agvStatus); + taskOptions.add(new TaskOption(task, false, distance, cost, "pickup")); + } + } + } + + // 3. 濡傛灉鐢甸噺涓嶈冻锛屾坊鍔犲厖鐢甸�夐」 + if (agvStatus.needsCharging()) { + String nearestCharging = findNearestChargingPosition(currentPosition); + if (nearestCharging != null && !nearestCharging.equals(currentPosition)) { + double distance = calculateDistance(currentPosition, nearestCharging); + if (distance >= 0) { + double cost = calculateChargingCost(distance, agvStatus.getVol(), agvStatus.getLowVol()); + taskOptions.add(new TaskOption(null, false, distance, cost, "charging")); + } + } + } + + // 4. 閫夋嫨鎴愭湰鏈�浣庣殑浠诲姟 + if (taskOptions.isEmpty()) { + return null; + } + + // 鎸夋垚鏈帓搴忥紝閫夋嫨鏈�浼橀�夐」 + taskOptions.sort(Comparator.comparingDouble(option -> option.cost)); + TaskOption bestOption = taskOptions.get(0); + + // 杈撳嚭鍐崇瓥鏃ュ織 + System.out.println("AGV " + agvStatus.getAgvId() + " 浠诲姟鍐崇瓥锛�"); + for (int i = 0; i < Math.min(3, taskOptions.size()); i++) { + TaskOption option = taskOptions.get(i); + System.out.println(" " + (i == 0 ? "[閫変腑]" : " ") + + " 绫诲瀷: " + option.taskType + + ", 璺濈: " + String.format("%.1f", option.distance) + + ", 鎴愭湰: " + String.format("%.2f", option.cost)); + } + + // 鍒涘缓鎵ц浠诲姟 + if ("charging".equals(bestOption.taskType)) { + String nearestCharging = findNearestChargingPosition(currentPosition); + return createChargingTask(agvStatus, nearestCharging); + } else { + return createExecutingTask(agvStatus, bestOption.backpackData, bestOption.isLoaded); + } + } + + /** + * 璁$畻浠诲姟鎴愭湰 + * + * @param distance 璺濈 + * @param taskType 浠诲姟绫诲瀷 + * @param taskPriority 浠诲姟浼樺厛绾� + * @param agvStatus AGV鐘舵�� + * @return 浠诲姟鎴愭湰 + */ + private double calculateTaskCost(double distance, String taskType, int taskPriority, AGVStatus agvStatus) { + // 鍩虹璺濈鎴愭湰 + double distanceCost = distance; + + // 浠诲姟绫诲瀷鏉冮噸 + double taskTypeWeight; + switch (taskType) { + case "delivery": + taskTypeWeight = 10.0; // 閫佽揣浠诲姟鍩虹鏉冮噸杈冧綆锛屼紭鍏堟墽琛� + break; + case "pickup": + taskTypeWeight = 15.0; // 鍙栬揣浠诲姟鍩虹鏉冮噸閫備腑 + break; + default: + taskTypeWeight = 20.0; + } + + // 浠诲姟浼樺厛绾у奖鍝嶏紙浼樺厛绾ц秺楂橈紝鏉冮噸瓒婁綆锛� + double priorityWeight = Math.max(1.0, 6.0 - taskPriority); + + // 鐢甸噺褰卞搷锛堢數閲忎綆鏃跺亸鍚戣繎璺濈浠诲姟锛� + double batteryFactor = 1.0; + if (agvStatus.needsCharging()) { + batteryFactor = 1.0 + (100.0 - agvStatus.getVol()) / 100.0; // 鐢甸噺瓒婁綆锛岃窛绂绘垚鏈秺楂� + } + + // 缁煎悎鎴愭湰璁$畻 + double totalCost = (distanceCost * batteryFactor) + (taskTypeWeight * priorityWeight); + + return totalCost; + } + + /** + * 璁$畻鍏呯數浠诲姟鎴愭湰 + * + * @param distance 鍒板厖鐢电偣鐨勮窛绂� + * @param currentVol 褰撳墠鐢甸噺 + * @param lowVol 鏈�浣庣數閲忛槇鍊� + * @return 鍏呯數浠诲姟鎴愭湰 + */ + private double calculateChargingCost(double distance, int currentVol, int lowVol) { + // 鍩虹璺濈鎴愭湰 + double distanceCost = distance; + + // 鐢甸噺绱ф�ョ▼搴︼紙鐢甸噺瓒婁綆锛屽厖鐢垫垚鏈秺浣庯紝鍗充紭鍏堢骇瓒婇珮锛� + double batteryUrgency; + if (currentVol <= lowVol) { + batteryUrgency = 5.0; // 蹇呴』鍏呯數锛屾瀬楂樹紭鍏堢骇 + } else { + // 鐢甸噺鍦╨owVol鍒癮utoCharge涔嬮棿锛岀嚎鎬ц绠楃揣鎬ョ▼搴� + batteryUrgency = 30.0 - (currentVol - lowVol) * 0.5; // 鐢甸噺瓒婁綆浼樺厛绾ц秺楂� + } + + return distanceCost + batteryUrgency; + } + + /** + * 浠诲姟閫夐」鍐呴儴绫� + */ + private static class TaskOption { + BackpackData backpackData; + boolean isLoaded; + double distance; + double cost; + String taskType; + + public TaskOption(BackpackData backpackData, boolean isLoaded, double distance, double cost, String taskType) { + this.backpackData = backpackData; + this.isLoaded = isLoaded; + this.distance = distance; + this.cost = cost; + this.taskType = taskType; + } + } + + /** + * 鑾峰彇浠诲姟鏁版嵁 + * + * @param taskId 浠诲姟ID + * @return 浠诲姟鏁版嵁 + */ + private TaskData getTaskData(String taskId) { + return taskDataMap.get(taskId); + } + + + /** + * 鏌ユ壘鏈�杩戠殑鍏呯數浣嶇疆 + * + * @param currentPosition 褰撳墠浣嶇疆 + * @return 鏈�杩戠殑鍏呯數浣嶇疆 + */ + private String findNearestChargingPosition(String currentPosition) { + String nearest = null; + double minDistance = Double.MAX_VALUE; + + for (String chargingPos : chargingPositions) { + if (!chargingPos.equals(currentPosition)) { + double distance = calculateDistance(currentPosition, chargingPos); + if (distance >= 0 && distance < minDistance) { + minDistance = distance; + nearest = chargingPos; + } + } + } + + return nearest; + } + + /** + * 鍒涘缓鎵ц浠诲姟 + * + * @param agvStatus AGV鐘舵�� + * @param backpackData 鑳岀瘬鏁版嵁 + * @param isLoaded 鏄惁宸茶杞� + * @return 鎵ц浠诲姟 + */ + private ExecutingTask createExecutingTask(AGVStatus agvStatus, BackpackData backpackData, boolean isLoaded) { + TaskData taskData = getTaskData(backpackData.getTaskId()); + if (taskData == null) { + return null; + } + + ExecutingTask task = new ExecutingTask(); + task.setAgvId(agvStatus.getAgvId()); + task.setTaskId(backpackData.getTaskId()); + task.setCurrentPosition(agvStatus.getPosition()); + task.setLoaded(isLoaded); + task.setBackpackIndex(backpackData.getIndex()); + task.setPriority(taskData.getPriority()); + + // 璁剧疆鐩爣浣嶇疆 + if (isLoaded) { + task.setTargetPosition(taskData.getEnd()); + task.setTaskType("delivery"); + } else { + task.setTargetPosition(taskData.getStart()); + task.setTaskType("pickup"); + } + + // 璁$畻璺濈 + task.setDistanceToStart(calculateDistance(agvStatus.getPosition(), taskData.getStart())); + task.setDistanceToEnd(calculateDistance(agvStatus.getPosition(), taskData.getEnd())); + + return task; + } + + /** + * 鍒涘缓鍏呯數浠诲姟 + * + * @param agvStatus AGV鐘舵�� + * @param chargingPosition 鍏呯數浣嶇疆 + * @return 鍏呯數浠诲姟 + */ + private ExecutingTask createChargingTask(AGVStatus agvStatus, String chargingPosition) { + ExecutingTask task = new ExecutingTask(); + task.setAgvId(agvStatus.getAgvId()); + task.setTaskId("CHARGING_" + agvStatus.getAgvId()); + task.setCurrentPosition(agvStatus.getPosition()); + task.setTargetPosition(chargingPosition); + task.setTaskType("charging"); + task.setLoaded(false); + task.setBackpackIndex(-1); + task.setPriority(1); // 鍏呯數浠诲姟浼樺厛绾ц緝楂� + + return task; + } + + /** + * 璁$畻涓や釜浣嶇疆涔嬮棿鐨勮窛绂� + * + * @param pos1 浣嶇疆1 + * @param pos2 浣嶇疆2 + * @return 璺濈鍊� + */ + private double calculateDistance(String pos1, String pos2) { + if (pos1 == null || pos2 == null) { + return -1; + } + + int[] coord1 = JsonUtils.getCoordinate(pos1, pathMapping); + int[] coord2 = JsonUtils.getCoordinate(pos2, pathMapping); + + if (coord1 == null || coord2 == null) { + return -1; + } + + return JsonUtils.calculateManhattanDistance(coord1, coord2); + } + + /** + * 鏋勫缓鍧愭爣鍒拌矾寰勭紪鍙风殑鏄犲皠 + */ + private void buildCoordToCodeMapping() { + for (Map.Entry<String, Map<String, Integer>> entry : pathMapping.entrySet()) { + String code = entry.getKey(); + Map<String, Integer> coordMap = entry.getValue(); + + if (coordMap.containsKey("x") && coordMap.containsKey("y")) { + String coordKey = coordMap.get("x") + "," + coordMap.get("y"); + coordToCode.put(coordKey, code); + } + } + } + + /** + * 棰勫垎绫讳綅缃被鍨� + */ + private void classifyPositions() { + pickupPositions = new ArrayList<>(); + chargingPositions = new ArrayList<>(); + deliveryPositions = new ArrayList<>(); + standbyPositions = new ArrayList<>(); + + for (String position : pathMapping.keySet()) { + if (position.startsWith("1")) { + pickupPositions.add(position); + } else if (position.startsWith("2")) { + chargingPositions.add(position); + } else if (position.startsWith("3")) { + deliveryPositions.add(position); + } else if (position.startsWith("4")) { + standbyPositions.add(position); + } + } + } + + // Getter鏂规硶 + public List<String> getPickupPositions() { + return pickupPositions; + } + + public List<String> getChargingPositions() { + return chargingPositions; + } + + public List<String> getDeliveryPositions() { + return deliveryPositions; + } + + public List<String> getStandbyPositions() { + return standbyPositions; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/PathPlanner.java b/algo-zkd/src/main/java/com/algo/service/PathPlanner.java new file mode 100644 index 0000000..1cccaf7 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/PathPlanner.java @@ -0,0 +1,64 @@ +package com.algo.service; + +import com.algo.model.PlannedPath; + +import java.util.List; +import java.util.Map; + +/** + * 璺緞瑙勫垝鍣ㄦ帴鍙� + * 瀹氫箟AGV璺緞瑙勫垝鏂规硶 + */ +public interface PathPlanner { + + /** + * 瑙勫垝鍗曚釜AGV鐨勮矾寰� + * + * @param startCode 璧峰璺緞鐐笽D + * @param endCode 鐩爣璺緞鐐笽D + * @param constraints 绾︽潫鏉′欢鍒楄〃 [x, y, radius] + * @return 瑙勫垝鐨勮矾寰勶紝澶辫触杩斿洖null + */ + PlannedPath planPath(String startCode, String endCode, List<double[]> constraints); + + /** + * 瑙勫垝鍗曚釜AGV鐨勮矾寰勶紙鏃犵害鏉熸潯浠讹級 + * + * @param startCode 璧峰璺緞鐐笽D + * @param endCode 鐩爣璺緞鐐笽D + * @return 瑙勫垝鐨勮矾寰勶紝澶辫触杩斿洖null + */ + PlannedPath planPath(String startCode, String endCode); + + /** + * 楠岃瘉璺緞鐐规槸鍚︽湁鏁� + * + * @param pathCode 璺緞鐐笽D + * @return true濡傛灉璺緞鐐规湁鏁� + */ + boolean isValidPathPoint(String pathCode); + + /** + * 璁$畻涓や釜璺緞鐐逛箣闂寸殑璺濈 + * + * @param startCode 璧峰璺緞鐐笽D + * @param endCode 鐩爣璺緞鐐笽D + * @return 璺濈鍊硷紝鏃犳晥璺緞鐐硅繑鍥�-1 + */ + double calculateDistance(String startCode, String endCode); + + /** + * 鑾峰彇璺緞鏄犲皠淇℃伅 + * + * @return 璺緞鏄犲皠琛� + */ + Map<String, Map<String, Integer>> getPathMapping(); + + /** + * 鑾峰彇閭绘帴鐐瑰垪琛� + * + * @param pathCode 璺緞鐐笽D + * @return 閭绘帴鐐瑰垪琛ㄥ強鍏舵柟鍚� + */ + List<Map<String, String>> getNeighbors(String pathCode); +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/PathPlanningService.java b/algo-zkd/src/main/java/com/algo/service/PathPlanningService.java new file mode 100644 index 0000000..9fef948 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/PathPlanningService.java @@ -0,0 +1,828 @@ +package com.algo.service; + +import com.algo.model.*; +import com.algo.util.JsonUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.concurrent.*; + +/** + * 璺緞瑙勫垝鏈嶅姟 + */ +public class PathPlanningService { + + /** + * 璺緞鏄犲皠琛� + */ + private Map<String, Map<String, Integer>> pathMapping; + + /** + * 鐜閰嶇疆 + */ + private Map<String, Object> environmentConfig; + + /** + * 鎵ц涓换鍔℃彁鍙� + */ + private ExecutingTaskExtractor taskExtractor; + + /** + * 璺緞瑙勫垝 + */ + private PathPlanner pathPlanner; + + /** + * 纰版挒妫�娴� + */ + private CollisionDetector collisionDetector; + + /** + * 纰版挒瑙e喅 + */ + private CollisionResolver collisionResolver; + + /** + * 鍓╀綑璺緞澶勭悊 + */ + private RemainingPathProcessor remainingPathProcessor; + + /** + * 绾跨▼姹犲ぇ灏� + */ + private final int threadPoolSize; + + /** + * 绾跨▼姹� + */ + private final ExecutorService executorService; + + /** + * CTU鎵瑰鐞嗗ぇ灏� + */ + private final int batchSize = 10; + + /** + * 鏋勯�犲嚱鏁� + * + * @param pathMapping 璺緞鏄犲皠琛� + * @param environmentConfig 鐜閰嶇疆 + * @param taskDataList 浠诲姟鏁版嵁鍒楄〃 + */ + public PathPlanningService(Map<String, Map<String, Integer>> pathMapping, + Map<String, Object> environmentConfig, + List<TaskData> taskDataList) { + this.pathMapping = pathMapping; + this.environmentConfig = environmentConfig; + + this.threadPoolSize = Math.max(4, Runtime.getRuntime().availableProcessors()); + this.executorService = Executors.newFixedThreadPool(threadPoolSize); + + // 鍒濆鍖� + initializeComponents(taskDataList); + + System.out.println("璺緞瑙勫垝鏈嶅姟鍒濆鍖栧畬鎴愶紙绾跨▼姹犲ぇ灏�: " + threadPoolSize + "锛�"); + } + + /** + * 鍒濆鍖栧悇涓粍浠� + * + * @param taskDataList 浠诲姟鏁版嵁鍒楄〃 + */ + private void initializeComponents(List<TaskData> taskDataList) { + // 鍒濆鍖栦换鍔℃彁鍙栧櫒 + this.taskExtractor = new ExecutingTaskExtractor(pathMapping, taskDataList); + + // 鍒濆鍖栬矾寰勮鍒掑櫒 + this.pathPlanner = new AStarPathPlanner(pathMapping); + + // 鍒濆鍖栫鎾炴娴嬪櫒 + this.collisionDetector = new CollisionDetector(pathMapping); + + // 鍒濆鍖栫鎾炶В鍐冲櫒 + this.collisionResolver = new CollisionResolver(collisionDetector); + + // 鍒濆鍖栧墿浣欒矾寰勫鐞嗗櫒 + this.remainingPathProcessor = new RemainingPathProcessor(pathMapping); + } + + /** + * 涓烘墍鏈塁TU瑙勫垝璺緞 + * + * @param agvStatusList CTU鐘舵�佸垪琛� + * @param includeIdleAgv 鏄惁鍖呭惈绌洪棽CTU + * @param constraints 璺緞绾︽潫鏉′欢 + * @return 璺緞瑙勫垝缁撴灉 + */ + public PathPlanningResult planAllAgvPaths(List<AGVStatus> agvStatusList, + boolean includeIdleAgv, + List<double[]> constraints) { + long startTime = System.currentTimeMillis(); + + System.out.println("寮�濮嬩负 " + agvStatusList.size() + " 涓狢TU瑙勫垝"); + + // 1. 鏋勫缓鐜版湁鍓╀綑璺緞鐨勬椂绌哄崰鐢ㄨ〃 + System.out.println("姝ラ1: 鏋勫缓鏃剁┖鍗犵敤琛�"); + Map<String, String> spaceTimeOccupancyMap = remainingPathProcessor.buildSpaceTimeOccupancyMap(agvStatusList); + System.out.println("鏃剁┖鍗犵敤琛ㄦ瀯寤哄畬鎴愶紝鍖呭惈 " + spaceTimeOccupancyMap.size() + " 涓崰鐢ㄧ偣"); + + // 2. 鍒嗙被澶勭悊CTU锛氭湁鍓╀綑璺緞鐨勫拰闇�瑕佹柊璺緞鐨� + List<AGVStatus> ctuWithRemainingPaths = new ArrayList<>(); + List<AGVStatus> ctuNeedingNewPaths = new ArrayList<>(); + + for (AGVStatus agv : agvStatusList) { + if (agv.hasRemainingPath()) { + ctuWithRemainingPaths.add(agv); + } else if (agv.canAcceptNewTask() || (includeIdleAgv && isAgvIdle(agv))) { + ctuNeedingNewPaths.add(agv); + } + } + + System.out.println("CTU鍒嗙被瀹屾垚: 鏈夊墿浣欒矾寰�=" + ctuWithRemainingPaths.size() + + ", 闇�瑕佹柊璺緞=" + ctuNeedingNewPaths.size()); + + // 3. 澶勭悊鏈夊墿浣欒矾寰勭殑CTU + List<PlannedPath> plannedPaths = new ArrayList<>(); + List<ExecutingTask> executingTasks = new ArrayList<>(); + Map<String, String> plannedAgvIds = new HashMap<>(); + + System.out.println("姝ラ2: 澶勭悊鏈夊墿浣欒矾寰勭殑CTU"); + for (AGVStatus agv : ctuWithRemainingPaths) { + PlannedPath remainingPath = processRemainingPath(agv); + if (remainingPath != null) { + plannedPaths.add(remainingPath); + plannedAgvIds.put(agv.getAgvId(), "REMAINING_PATH"); + + // 鍒涘缓瀵瑰簲鐨勬墽琛屼换鍔� + ExecutingTask task = createExecutingTaskFromRemainingPath(agv); + if (task != null) { + executingTasks.add(task); + } + + System.out.println("CTU " + agv.getAgvId() + " 鍓╀綑璺緞澶勭悊瀹屾垚锛岃矾寰勯暱搴�: " + + remainingPath.getCodeList().size()); + } + } + + // 4. 涓洪渶瑕佹柊璺緞鐨凜TU鎻愬彇鎵ц涓换鍔� + System.out.println("姝ラ3: 鎻愬彇闇�瑕佹柊璺緞鐨凜TU浠诲姟"); + List<ExecutingTask> newTasks = taskExtractor.extractExecutingTasks(ctuNeedingNewPaths); + System.out.println("鎻愬彇鍒� " + newTasks.size() + " 涓柊浠诲姟"); + + // 5. 涓烘柊浠诲姟瑙勫垝璺緞锛堣�冭檻鏃剁┖绾︽潫锛� + System.out.println("姝ラ4: 涓烘柊浠诲姟瑙勫垝璺緞"); + for (ExecutingTask task : newTasks) { + String agvId = task.getAgvId(); + String currentPos = task.getCurrentPosition(); + String targetPos = task.getTargetPosition(); + + // 閬垮厤閲嶅瑙勫垝 + if (plannedAgvIds.containsKey(agvId)) { + System.out.println("璺宠繃CTU " + agvId + "锛氬凡瑙勫垝璺緞"); + continue; + } + + // 楠岃瘉浣嶇疆淇℃伅 + if (currentPos == null || targetPos == null) { + System.out.println("CTU " + agvId + " 浣嶇疆淇℃伅鏃犳晥锛岃烦杩�"); + continue; + } + + // 鑾峰彇CTU鐘舵�佷俊鎭� + AGVStatus agvStatus = findAgvStatus(agvId, ctuNeedingNewPaths); + if (agvStatus == null) { + System.out.println("CTU " + agvId + " 鐘舵�佷俊鎭湭鎵惧埌锛岃烦杩�"); + continue; + } + + // 瑙勫垝鏃剁┖瀹夊叏鐨勮矾寰� + PlannedPath plannedPath = planPathWithSpaceTimeConstraints( + currentPos, targetPos, constraints, spaceTimeOccupancyMap, agvStatus + ); + + if (plannedPath != null) { + // 璁剧疆CTU淇℃伅 + plannedPath.setAgvId(agvId); + plannedPath.setSegId(generateSegId(task.getTaskId(), agvId, task.getTaskType())); + + // 澧炲己璺緞浠g爜淇℃伅 + enhancePathCodes(plannedPath, task); + + plannedPaths.add(plannedPath); + plannedAgvIds.put(agvId, targetPos); + executingTasks.add(task); + + // 鏇存柊鏃剁┖鍗犵敤琛� + updateSpaceTimeOccupancyMap(plannedPath, spaceTimeOccupancyMap, agvStatus); + + System.out.println("CTU " + agvId + " 璺緞瑙勫垝鎴愬姛锛�" + currentPos + " -> " + targetPos + + "锛岃矾寰勯暱搴�: " + plannedPath.getCodeList().size()); + } else { + System.out.println("CTU " + agvId + " 璺緞瑙勫垝澶辫触锛�" + currentPos + " -> " + targetPos); + } + } + + // 6. 澶勭悊绌洪棽CTU + if (includeIdleAgv) { + System.out.println("姝ラ5: 澶勭悊绌洪棽CTU"); + List<PlannedPath> idlePaths = planIdleAgvPathsWithConstraints( + ctuNeedingNewPaths, plannedAgvIds, constraints, spaceTimeOccupancyMap + ); + plannedPaths.addAll(idlePaths); + System.out.println("绌洪棽CTU璺緞瑙勫垝瀹屾垚锛屾暟閲�: " + idlePaths.size()); + } + + // 7. 鏈�缁堢鎾炴娴嬪拰瑙e喅锛堥拡瀵瑰悓鏃剁敓鎴愮殑鏂拌矾寰勶級 + System.out.println("姝ラ6: 鏈�缁堢鎾炴娴�"); + List<Conflict> conflicts = collisionDetector.detectConflicts(plannedPaths); + + if (!conflicts.isEmpty()) { + System.out.println("鍙戠幇 " + conflicts.size() + " 涓鎾烇紝寮�濮嬭В鍐�"); + plannedPaths = collisionResolver.resolveConflicts(plannedPaths, conflicts, executingTasks); + + // 閲嶆柊妫�娴嬪啿绐� + List<Conflict> remainingConflicts = collisionDetector.detectConflicts(plannedPaths); + conflicts = remainingConflicts; + } + + long endTime = System.currentTimeMillis(); + double totalTime = (endTime - startTime) / 1000.0; + + // 鏋勫缓缁撴灉 + PathPlanningResult result = new PathPlanningResult( + agvStatusList.size(), + executingTasks.size(), + plannedPaths.size(), + totalTime, + conflicts.size(), + conflicts.isEmpty(), + "A*_WITH_SPACETIME_CONSTRAINTS", + plannedPaths, + executingTasks + ); + + System.out.println("璺緞瑙勫垝瀹屾垚 - 鎬籆TU: " + result.getTotalAgvs() + + ", 鎵ц浠诲姟: " + result.getExecutingTasksCount() + + ", 瑙勫垝璺緞: " + result.getPlannedPathsCount() + + ", 鑰楁椂: " + result.getTotalPlanningTime() + "s" + + ", 鏃犲啿绐�: " + result.isCollisionFree()); + + return result; + } + + /** + * 澶勭悊CTU鐨勫墿浣欒矾寰� + * + * @param agv CTU鐘舵�� + * @return 澶勭悊鍚庣殑璺緞 + */ + private PlannedPath processRemainingPath(AGVStatus agv) { + if (!agv.hasRemainingPath()) { + return null; + } + + PlannedPath remainingPath = agv.getRemainingPath(); + List<PathCode> remainingCodes = new ArrayList<>(); + + // 浠庡綋鍓嶄綅缃紑濮嬶紝鑾峰彇鍓╀綑璺緞 + List<PathCode> originalCodes = remainingPath.getCodeList(); + for (int i = agv.getCurrentPathIndex(); i < originalCodes.size(); i++) { + remainingCodes.add(originalCodes.get(i)); + } + + // 鍒涘缓鏂扮殑璺緞瀵硅薄 + PlannedPath processedPath = new PlannedPath(); + processedPath.setAgvId(agv.getAgvId()); + processedPath.setCodeList(remainingCodes); + processedPath.setSegId(agv.getAgvId() + "_REMAINING_" + System.currentTimeMillis()); + + return processedPath; + } + + /** + * 浠庡墿浣欒矾寰勫垱寤烘墽琛屼换鍔� + * + * @param agv CTU鐘舵�� + * @return 鎵ц浠诲姟 + */ + private ExecutingTask createExecutingTaskFromRemainingPath(AGVStatus agv) { + if (!agv.hasRemainingPath()) { + return null; + } + + PlannedPath remainingPath = agv.getRemainingPath(); + List<PathCode> codeList = remainingPath.getCodeList(); + + if (codeList.isEmpty() || agv.getCurrentPathIndex() >= codeList.size()) { + return null; + } + + // 鑾峰彇褰撳墠浣嶇疆鍜岀洰鏍囦綅缃� + PathCode currentCode = codeList.get(agv.getCurrentPathIndex()); + PathCode targetCode = codeList.get(codeList.size() - 1); + + ExecutingTask task = new ExecutingTask(); + task.setAgvId(agv.getAgvId()); + task.setTaskId(remainingPath.getSegId()); + task.setCurrentPosition(currentCode.getCode()); + task.setTargetPosition(targetCode.getCode()); + task.setTaskType("remaining"); + task.setLoaded(false); // 鍋囪鍊� + task.setBackpackIndex(0); + task.setPriority(1); + + return task; + } + + /** + * 瑙勫垝甯︽椂绌虹害鏉熺殑璺緞 + * + * @param startPos 璧峰浣嶇疆 + * @param endPos 鐩爣浣嶇疆 + * @param constraints 绾︽潫鏉′欢 + * @param occupancyMap 鏃剁┖鍗犵敤琛� + * @param agvStatus CTU鐘舵�� + * @return 瑙勫垝鐨勮矾寰� + */ + private PlannedPath planPathWithSpaceTimeConstraints(String startPos, String endPos, + List<double[]> constraints, + Map<String, String> occupancyMap, + AGVStatus agvStatus) { + // 棣栧厛灏濊瘯鍩烘湰璺緞瑙勫垝 + PlannedPath basicPath = pathPlanner.planPath(startPos, endPos, constraints); + if (basicPath == null) { + return null; + } + + // 鎵惧埌瀹夊叏鐨勮捣濮嬫椂闂� + long safeStartTime = remainingPathProcessor.findSafeStartTime( + basicPath, occupancyMap, agvStatus.getPhysicalConfig() + ); + + // 璁剧疆璺緞鐨勬椂闂翠俊鎭� + enhancePathWithTimeInfo(basicPath, safeStartTime, agvStatus.getPhysicalConfig()); + + return basicPath; + } + + /** + * 璺緞鐨勬椂闂翠俊鎭� + * + * @param path 璺緞 + * @param startTime 璧峰鏃堕棿 + * @param config 鐗╃悊閰嶇疆 + */ + private void enhancePathWithTimeInfo(PlannedPath path, long startTime, CTUPhysicalConfig config) { + List<PathCode> codeList = path.getCodeList(); + if (codeList == null || codeList.isEmpty()) { + return; + } + + long currentTime = startTime; + + for (int i = 0; i < codeList.size(); i++) { + PathCode pathCode = codeList.get(i); + + // 璁剧疆棰勮鍒拌揪鏃堕棿 + + // 璁$畻鍒颁笅涓�涓偣鐨勬椂闂� + if (i < codeList.size() - 1) { + double travelTime = config.getStandardPointDistance() / config.getNormalSpeed(); + currentTime += (long) (travelTime * 1000); + + // 濡傛灉鏈夋柟鍚戝彉鍖栵紝澧炲姞杞悜鏃堕棿 + PathCode nextCode = codeList.get(i + 1); + if (!pathCode.getDirection().equals(nextCode.getDirection())) { + double turnTime = config.getTurnTime(pathCode.getDirection(), nextCode.getDirection()); + currentTime += (long) (turnTime * 1000); + } + } + } + } + + /** + * 鏇存柊鏃剁┖鍗犵敤琛� + * + * @param path 鏂拌矾寰� + * @param occupancyMap 鍗犵敤琛� + * @param agvStatus CTU鐘舵�� + */ + private void updateSpaceTimeOccupancyMap(PlannedPath path, Map<String, String> occupancyMap, + AGVStatus agvStatus) { + // 灏嗘柊璺緞娣诲姞鍒板崰鐢ㄨ〃涓� + List<PathCode> codeList = path.getCodeList(); + CTUPhysicalConfig config = agvStatus.getPhysicalConfig(); + + long currentTime = System.currentTimeMillis() / 1000; // 杞崲涓虹 + + for (PathCode pathCode : codeList) { + int[] coord = JsonUtils.getCoordinate(pathCode.getCode(), pathMapping); + if (coord != null) { + String spaceTimeKey = coord[0] + "," + coord[1] + "," + currentTime; + occupancyMap.put(spaceTimeKey, agvStatus.getAgvId()); + currentTime += 2; // 鍋囪姣忎釜鐐瑰仠鐣�2绉� + } + } + } + + /** + * 鏌ユ壘CTU鐘舵�� + * + * @param agvId CTU缂栧彿 + * @param agvList CTU鍒楄〃 + * @return CTU鐘舵�� + */ + private AGVStatus findAgvStatus(String agvId, List<AGVStatus> agvList) { + for (AGVStatus agv : agvList) { + if (agv.getAgvId().equals(agvId)) { + return agv; + } + } + return null; + } + + /** + * 瑙勫垝甯︾害鏉熺殑绌洪棽CTU璺緞 + * + * @param agvStatusList CTU鐘舵�佸垪琛� + * @param plannedAgvIds 宸茶鍒扖TU鏄犲皠 + * @param constraints 绾︽潫鏉′欢 + * @param occupancyMap 鏃剁┖鍗犵敤琛� + * @return 绌洪棽CTU璺緞鍒楄〃 + */ + private List<PlannedPath> planIdleAgvPathsWithConstraints(List<AGVStatus> agvStatusList, + Map<String, String> plannedAgvIds, + List<double[]> constraints, + Map<String, String> occupancyMap) { + List<PlannedPath> idlePaths = new ArrayList<>(); + + for (AGVStatus agvStatus : agvStatusList) { + String agvId = agvStatus.getAgvId(); + + // 璺宠繃宸茶鍒掔殑CTU + if (plannedAgvIds.containsKey(agvId)) { + continue; + } + + // 妫�鏌TU鏄惁绌洪棽 + if (isAgvIdle(agvStatus)) { + String currentPos = agvStatus.getPosition(); + String targetPos = getIdleAgvTarget(agvId, currentPos); + + if (targetPos != null && !targetPos.equals(currentPos)) { + PlannedPath idlePath = planPathWithSpaceTimeConstraints( + currentPos, targetPos, constraints, occupancyMap, agvStatus + ); + + if (idlePath != null) { + idlePath.setAgvId(agvId); + idlePath.setSegId(generateSegId("IDLE", agvId, "idle")); + + // 璁剧疆绌洪棽璺緞鐨勪唬鐮佷俊鎭� + enhanceIdlePathCodes(idlePath, agvStatus); + + idlePaths.add(idlePath); + plannedAgvIds.put(agvId, targetPos); + + // 鏇存柊鍗犵敤琛� + updateSpaceTimeOccupancyMap(idlePath, occupancyMap, agvStatus); + + System.out.println("绌洪棽CTU " + agvId + " 璺緞瑙勫垝鎴愬姛锛�" + currentPos + " -> " + targetPos); + } + } + } + } + + return idlePaths; + } + + /** + * 璺緞浠g爜淇℃伅 + * + * @param plannedPath 瑙勫垝璺緞 + * @param task 鎵ц浠诲姟 + */ + private void enhancePathCodes(PlannedPath plannedPath, ExecutingTask task) { + List<PathCode> codeList = plannedPath.getCodeList(); + if (codeList == null || codeList.isEmpty()) { + return; + } + + String actionType = "2"; // 浠诲姟绫诲瀷 + String taskId = task.getTaskId(); + int backpackLevel = task.getBackpackIndex(); + + for (int i = 0; i < codeList.size(); i++) { + PathCode pathCode = codeList.get(i); + + // 璁剧疆鍩烘湰淇℃伅 + pathCode.setActionType(actionType); + pathCode.setTaskId(taskId); + pathCode.setLev(backpackLevel); + + // 璁剧疆鐩爣鐐逛俊鎭� + if (i == codeList.size() - 1) { // 鏈�鍚庝竴涓偣 + pathCode.setTargetPoint(true); + if (task.isLoaded()) { + pathCode.setPosType("2"); // 鏀捐揣 + } else { + pathCode.setPosType("1"); // 鍙栬揣 + } + } else { + pathCode.setTargetPoint(false); + pathCode.setPosType(null); + } + } + } + + /** + * 绌洪棽璺緞浠g爜淇℃伅 + * + * @param plannedPath 瑙勫垝璺緞 + * @param agvStatus CTU鐘舵�� + */ + private void enhanceIdlePathCodes(PlannedPath plannedPath, AGVStatus agvStatus) { + List<PathCode> codeList = plannedPath.getCodeList(); + if (codeList == null || codeList.isEmpty()) { + return; + } + + String actionType = agvStatus.needsCharging() ? "3" : "4"; // 鍏呯數鎴栧緟鏈� + + for (PathCode pathCode : codeList) { + pathCode.setActionType(actionType); + pathCode.setTaskId(null); + pathCode.setPosType(null); + pathCode.setLev(0); + pathCode.setTargetPoint(false); + } + } + + /** + * 鍒ゆ柇CTU鏄惁绌洪棽 + * + * @param agvStatus CTU鐘舵�� + * @return true濡傛灉CTU绌洪棽 + */ + private boolean isAgvIdle(AGVStatus agvStatus) { + if (!agvStatus.isAvailable()) { + return false; + } + + // 妫�鏌ヨ儗绡撴槸鍚︽湁鎵ц涓殑浠诲姟 + List<BackpackData> backpack = agvStatus.getBackpack(); + if (backpack != null) { + for (BackpackData bp : backpack) { + if (bp.getTaskId() != null && !bp.getTaskId().trim().isEmpty()) { + return false; + } + } + } + + return true; + } + + /** + * 鑾峰彇绌洪棽CTU鐨勭洰鏍囦綅缃� + * + * @param agvId CTU缂栧彿 + * @param currentPosition 褰撳墠浣嶇疆 + * @return 鐩爣浣嶇疆 + */ + private String getIdleAgvTarget(String agvId, String currentPosition) { + // 鏍规嵁CTU ID鐨勫搱甯屽�奸�夋嫨浣嶇疆 + int hashValue = Math.abs(agvId.hashCode() % 1000); + + // 浼樺厛閫夋嫨鍏呯數浣嶇疆 + List<String> chargingPositions = taskExtractor.getChargingPositions(); + if (!chargingPositions.isEmpty()) { + for (String pos : chargingPositions) { + if (!pos.equals(currentPosition)) { + return pos; + } + } + } + + // 鍏舵閫夋嫨寰呮満浣嶇疆 + List<String> standbyPositions = taskExtractor.getStandbyPositions(); + if (!standbyPositions.isEmpty()) { + return standbyPositions.get(hashValue % standbyPositions.size()); + } + + return null; + } + + /** + * 鐢熸垚娈佃惤ID + * + * @param taskId 浠诲姟ID + * @param agvId CTU缂栧彿 + * @param taskType 浠诲姟绫诲瀷 + * @return 娈佃惤ID + */ + private String generateSegId(String taskId, String agvId, String taskType) { + return taskId + "_" + agvId + "_" + taskType; + } + + /** + * 璺緞瑙勫垝缁撴灉绫� + */ + public static class PathPlanningResult { + private int totalAgvs; + private int executingTasksCount; + private int plannedPathsCount; + private double totalPlanningTime; + private int conflictsDetected; + private boolean collisionFree; + private String algorithm; + private List<PlannedPath> plannedPaths; + private List<ExecutingTask> executingTasks; + + public PathPlanningResult(int totalAgvs, int executingTasksCount, int plannedPathsCount, + double totalPlanningTime, int conflictsDetected, boolean collisionFree, + String algorithm, List<PlannedPath> plannedPaths, List<ExecutingTask> executingTasks) { + this.totalAgvs = totalAgvs; + this.executingTasksCount = executingTasksCount; + this.plannedPathsCount = plannedPathsCount; + this.totalPlanningTime = totalPlanningTime; + this.conflictsDetected = conflictsDetected; + this.collisionFree = collisionFree; + this.algorithm = algorithm; + this.plannedPaths = plannedPaths; + this.executingTasks = executingTasks; + } + + // Getter鏂规硶 + public int getTotalAgvs() { + return totalAgvs; + } + + public int getExecutingTasksCount() { + return executingTasksCount; + } + + public int getPlannedPathsCount() { + return plannedPathsCount; + } + + public double getTotalPlanningTime() { + return totalPlanningTime; + } + + public int getConflictsDetected() { + return conflictsDetected; + } + + public boolean isCollisionFree() { + return collisionFree; + } + + public String getAlgorithm() { + return algorithm; + } + + public List<PlannedPath> getPlannedPaths() { + return plannedPaths; + } + + public List<ExecutingTask> getExecutingTasks() { + return executingTasks; + } + + @Override + public String toString() { + return "PathPlanningResult{" + + "totalAgvs=" + totalAgvs + + ", executingTasksCount=" + executingTasksCount + + ", plannedPathsCount=" + plannedPathsCount + + ", executingTasksCount=" + executingTasksCount + + ", totalPlanningTime=" + totalPlanningTime + + ", conflictsDetected=" + conflictsDetected + + ", collisionFree=" + executingTasksCount + + ", algorithm=" + algorithm + + ", plannedPaths=" + plannedPaths + + ", executingTasks='" + executingTasks + '\'' + + '}'; + } + } + + /** + * 骞惰瑙勫垝浠诲姟璺緞 + */ + private List<PlannedPath> planTasksInParallel(List<ExecutingTask> tasks, + List<double[]> constraints, + Map<String, String> spaceTimeOccupancyMap, + List<AGVStatus> agvStatusList) { + + List<PlannedPath> allPaths = Collections.synchronizedList(new ArrayList<>()); + + // 鎸変紭鍏堢骇鎺掑簭浠诲姟 + List<ExecutingTask> sortedTasks = new ArrayList<>(tasks); + sortedTasks.sort((t1, t2) -> Integer.compare(t2.getPriority(), t1.getPriority())); + + // 鍒嗘壒澶勭悊 + List<List<ExecutingTask>> batches = createBatches(sortedTasks, batchSize); + + for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { + List<ExecutingTask> batch = batches.get(batchIndex); + + System.out.println("澶勭悊鎵规 " + (batchIndex + 1) + "/" + batches.size() + + ", 浠诲姟鏁�: " + batch.size()); + + List<Future<PlannedPath>> futures = new ArrayList<>(); + + for (ExecutingTask task : batch) { + Future<PlannedPath> future = executorService.submit(() -> { + return planSingleTaskPath(task, constraints, spaceTimeOccupancyMap, agvStatusList); + }); + futures.add(future); + } + + for (Future<PlannedPath> future : futures) { + try { + PlannedPath path = future.get(60, TimeUnit.SECONDS); + if (path != null) { + allPaths.add(path); + System.out.println("CTU " + path.getAgvId() + " 璺緞瑙勫垝鎴愬姛"); + } + } catch (TimeoutException e) { + System.out.println("璺緞瑙勫垝瓒呮椂锛岃烦杩�"); + future.cancel(true); + } catch (Exception e) { + System.out.println("璺緞瑙勫垝寮傚父: " + e.getMessage()); + } + } + } + + return allPaths; + } + + /** + * 涓哄崟涓换鍔¤鍒掕矾寰� + */ + private PlannedPath planSingleTaskPath(ExecutingTask task, + List<double[]> constraints, + Map<String, String> spaceTimeOccupancyMap, + List<AGVStatus> agvStatusList) { + + String agvId = task.getAgvId(); + String currentPos = task.getCurrentPosition(); + String targetPos = task.getTargetPosition(); + + if (currentPos == null || targetPos == null) { + return null; + } + + // 鑾峰彇CTU鐘舵�佷俊鎭� + AGVStatus agvStatus = findAgvStatus(agvId, agvStatusList); + if (agvStatus == null) { + return null; + } + + // 瑙勫垝鏃剁┖瀹夊叏鐨勮矾寰� + PlannedPath plannedPath = planPathWithSpaceTimeConstraints( + currentPos, targetPos, constraints, spaceTimeOccupancyMap, agvStatus + ); + + if (plannedPath != null) { + // 璁剧疆CTU淇℃伅 + plannedPath.setAgvId(agvId); + plannedPath.setSegId(generateSegId(task.getTaskId(), agvId, task.getTaskType())); + + enhancePathCodes(plannedPath, task); + } + + return plannedPath; + } + + /** + * 鍒涘缓鎵规 + */ + private List<List<ExecutingTask>> createBatches(List<ExecutingTask> tasks, int batchSize) { + List<List<ExecutingTask>> batches = new ArrayList<>(); + + for (int i = 0; i < tasks.size(); i += batchSize) { + int end = Math.min(i + batchSize, tasks.size()); + batches.add(new ArrayList<>(tasks.subList(i, end))); + } + + return batches; + } + + /** + * 鍏抽棴鏈嶅姟 + */ + public void shutdown() { + if (executorService != null && !executorService.isShutdown()) { + executorService.shutdown(); + try { + if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/RemainingPathProcessor.java b/algo-zkd/src/main/java/com/algo/service/RemainingPathProcessor.java new file mode 100644 index 0000000..15f7545 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/RemainingPathProcessor.java @@ -0,0 +1,416 @@ +package com.algo.service; + +import com.algo.model.AGVStatus; +import com.algo.model.CTUPhysicalConfig; +import com.algo.model.PathCode; +import com.algo.model.PlannedPath; +import com.algo.util.JsonUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 鍓╀綑璺緞澶勭悊鍣� + * 璐熻矗澶勭悊CTU鏈畬鎴愯矾寰勭殑缁帴閫昏緫锛岀‘淇濇柊璺緞涓庡墿浣欒矾寰勭殑骞虫粦杩炴帴 + */ +public class RemainingPathProcessor { + + /** + * 璺緞鏄犲皠琛� + */ + private final Map<String, Map<String, Integer>> pathMapping; + + /** + * 绯荤粺褰撳墠鏃堕棿鍩哄噯锛堟绉掞級 + */ + private long systemBaseTime; + + public RemainingPathProcessor(Map<String, Map<String, Integer>> pathMapping) { + this.pathMapping = pathMapping; + this.systemBaseTime = System.currentTimeMillis(); + } + + /** + * 澶勭悊鎵�鏈塁TU鐨勫墿浣欒矾寰勶紝鏋勫缓鏃剁┖鍗犵敤琛� + * + * @param agvStatusList CTU鐘舵�佸垪琛� + * @return 鏃剁┖鍗犵敤琛紝key涓�"x,y,timeSlot"锛寁alue涓篊TU缂栧彿 + */ + public Map<String, String> buildSpaceTimeOccupancyMap(List<AGVStatus> agvStatusList) { + Map<String, String> occupancyMap = new HashMap<>(); + + for (AGVStatus agv : agvStatusList) { + if (agv.hasRemainingPath()) { + processRemainingPathOccupancy(agv, occupancyMap); + } + } + + return occupancyMap; + } + + /** + * 澶勭悊鍗曚釜CTU鐨勫墿浣欒矾寰勬椂绌哄崰鐢� + * + * @param agv CTU鐘舵�� + * @param occupancyMap 鏃剁┖鍗犵敤琛� + */ + private void processRemainingPathOccupancy(AGVStatus agv, Map<String, String> occupancyMap) { + PlannedPath remainingPath = agv.getRemainingPath(); + List<PathCode> codeList = remainingPath.getCodeList(); + CTUPhysicalConfig config = agv.getPhysicalConfig(); + + // 浠庡綋鍓嶄綅缃紑濮嬭绠楁椂绌哄崰鐢� + long currentTime = agv.getNextPointArrivalTime(); + int startIndex = agv.getCurrentPathIndex(); + + for (int i = startIndex; i < codeList.size(); i++) { + PathCode pathCode = codeList.get(i); + String position = pathCode.getCode(); + + // 鑾峰彇浣嶇疆鍧愭爣 + int[] coord = JsonUtils.getCoordinate(position, pathMapping); + if (coord == null) continue; + + // 璁$畻鍦ㄦ浣嶇疆鐨勫仠鐣欐椂闂� + double stayDuration = calculateStayDuration(agv, i, codeList, config); + + // 灏嗗仠鐣欐椂闂磋浆鎹负鏃堕棿鐗� + long startTimeSlot = currentTime / 1000; // 杞崲涓虹 + long endTimeSlot = (long) (currentTime / 1000 + stayDuration); + + // 鍗犵敤鏃剁┖ + for (long timeSlot = startTimeSlot; timeSlot <= endTimeSlot; timeSlot++) { + String spaceTimeKey = coord[0] + "," + coord[1] + "," + timeSlot; + occupancyMap.put(spaceTimeKey, agv.getAgvId()); + + // 鑰冭檻CTU鐨勭墿鐞嗗昂瀵革紝鍗犵敤鍛ㄥ洿鐨勬牸瀛� + occupyAdjacentSpaces(coord, timeSlot, agv.getAgvId(), occupancyMap, config); + } + + // 鏇存柊鍒颁笅涓�涓綅缃殑鏃堕棿 + currentTime += (long) (stayDuration * 1000); + if (i < codeList.size() - 1) { + PathCode nextPathCode = codeList.get(i + 1); + double travelTime = calculateTravelTime(pathCode, nextPathCode, config); + currentTime += (long) (travelTime * 1000); + } + } + } + + /** + * 鍗犵敤鐩搁偦绌洪棿锛堣�冭檻CTU鐗╃悊灏哄锛� + * + * @param centerCoord 涓績鍧愭爣 + * @param timeSlot 鏃堕棿鐗� + * @param agvId CTU缂栧彿 + * @param occupancyMap 鍗犵敤琛� + * @param config 鐗╃悊閰嶇疆 + */ + private void occupyAdjacentSpaces(int[] centerCoord, long timeSlot, String agvId, + Map<String, String> occupancyMap, CTUPhysicalConfig config) { + // 鏍规嵁CTU鐨勯暱搴﹀拰瀹藉害璁$畻闇�瑕佸崰鐢ㄧ殑鏍煎瓙鏁� + int lengthGrids = (int) Math.ceil(config.getCtuLength() / config.getStandardPointDistance()); + int widthGrids = (int) Math.ceil(config.getCtuWidth() / config.getStandardPointDistance()); + + // 鍗犵敤鍛ㄥ洿鐨勬牸瀛� + for (int dx = -lengthGrids / 2; dx <= lengthGrids / 2; dx++) { + for (int dy = -widthGrids / 2; dy <= widthGrids / 2; dy++) { + if (dx == 0 && dy == 0) continue; // 涓績鐐瑰凡缁忓崰鐢� + + int adjX = centerCoord[0] + dx; + int adjY = centerCoord[1] + dy; + String spaceTimeKey = adjX + "," + adjY + "," + timeSlot; + + // 鍙湁褰撹浣嶇疆鏈鍗犵敤鏃舵墠鍗犵敤 + if (!occupancyMap.containsKey(spaceTimeKey)) { + occupancyMap.put(spaceTimeKey, agvId); + } + } + } + } + + /** + * 璁$畻CTU鍦ㄦ寚瀹氳矾寰勭偣鐨勫仠鐣欐椂闂� + * + * @param agv CTU鐘舵�� + * @param pathIndex 璺緞鐐圭储寮� + * @param codeList 瀹屾暣璺緞浠g爜鍒楄〃 + * @param config 鐗╃悊閰嶇疆 + * @return 鍋滅暀鏃堕棿锛堢锛� + */ + private double calculateStayDuration(AGVStatus agv, int pathIndex, + List<PathCode> codeList, CTUPhysicalConfig config) { + PathCode currentCode = codeList.get(pathIndex); + + // 鍩虹鍋滅暀鏃堕棿 + double stayTime = 0.5; // 榛樿0.5绉� + + // 濡傛灉闇�瑕佽浆鍚戯紝澧炲姞杞悜鏃堕棿 + if (pathIndex < codeList.size() - 1) { + PathCode nextCode = codeList.get(pathIndex + 1); + String currentDirection = currentCode.getDirection(); + String nextDirection = nextCode.getDirection(); + + if (!currentDirection.equals(nextDirection)) { + stayTime += config.getTurnTime(currentDirection, nextDirection); + } + } + + // 濡傛灉鏄姩浣滅偣锛堝彇璐с�佹斁璐х瓑锛夛紝澧炲姞鎿嶄綔鏃堕棿 + if (currentCode.getActionType() != null) { + switch (currentCode.getActionType()) { + case "1": // 鍙栬揣 + stayTime += 3.0; // 鍙栬揣闇�瑕�3绉� + break; + case "2": // 鏀捐揣 + stayTime += 2.0; // 鏀捐揣闇�瑕�2绉� + break; + case "3": // 鍏呯數 + stayTime += 10.0; // 鍏呯數鍋滈潬闇�瑕�10绉� + break; + default: + stayTime += 1.0; // 鍏朵粬鍔ㄤ綔闇�瑕�1绉� + break; + } + } + + return stayTime; + } + + /** + * 璁$畻涓や釜璺緞鐐逛箣闂寸殑绉诲姩鏃堕棿 + * + * @param fromCode 璧峰璺緞鐐� + * @param toCode 鐩爣璺緞鐐� + * @param config 鐗╃悊閰嶇疆 + * @return 绉诲姩鏃堕棿锛堢锛� + */ + private double calculateTravelTime(PathCode fromCode, PathCode toCode, CTUPhysicalConfig config) { + // 鑾峰彇鍧愭爣 + int[] fromCoord = JsonUtils.getCoordinate(fromCode.getCode(), pathMapping); + int[] toCoord = JsonUtils.getCoordinate(toCode.getCode(), pathMapping); + + if (fromCoord == null || toCoord == null) { + return config.getStandardPointDistance() / config.getNormalSpeed(); + } + + // 璁$畻璺濈 + double distance = Math.sqrt(Math.pow(toCoord[0] - fromCoord[0], 2) + + Math.pow(toCoord[1] - fromCoord[1], 2)) * + config.getStandardPointDistance(); + + // 璁$畻绉诲姩鏃堕棿 + return config.getTravelTime(distance, config.getNormalSpeed()); + } + + /** + * 涓烘柊璺緞鏌ユ壘鍚堥�傜殑璧峰鏃堕棿锛岄伩鍏嶄笌鐜版湁璺緞鍐茬獊 + * + * @param newPath 鏂拌矾寰� + * @param occupancyMap 鐜版湁鏃剁┖鍗犵敤琛� + * @param config 鐗╃悊閰嶇疆 + * @return 寤鸿鐨勮捣濮嬫椂闂达紙姣锛� + */ + public long findSafeStartTime(PlannedPath newPath, Map<String, String> occupancyMap, + CTUPhysicalConfig config) { + if (newPath.getCodeList() == null || newPath.getCodeList().isEmpty()) { + return systemBaseTime; + } + + // 浠庡綋鍓嶆椂闂村紑濮嬶紝閫愭鍚戝悗鎼滅储瀹夊叏鐨勮捣濮嬫椂闂� + long currentTime = systemBaseTime; + long timeStep = 1000; // 1绉掓闀� + long maxSearchTime = currentTime + 300000; // 鏈�澶氭悳绱�5鍒嗛挓 + + while (currentTime < maxSearchTime) { + if (isPathTimeSafe(newPath, currentTime, occupancyMap, config)) { + return currentTime; + } + currentTime += timeStep; + } + + // 濡傛灉鎵句笉鍒板畨鍏ㄦ椂闂达紝杩斿洖杈冭繙鐨勬湭鏉ユ椂闂� + return maxSearchTime; + } + + /** + * 妫�鏌ユ寚瀹氭椂闂村紑濮嬬殑璺緞鏄惁瀹夊叏 + * + * @param path 璺緞 + * @param startTime 璧峰鏃堕棿 + * @param occupancyMap 鍗犵敤琛� + * @param config 鐗╃悊閰嶇疆 + * @return true濡傛灉瀹夊叏 + */ + private boolean isPathTimeSafe(PlannedPath path, long startTime, + Map<String, String> occupancyMap, CTUPhysicalConfig config) { + List<PathCode> codeList = path.getCodeList(); + long currentTime = startTime; + + for (int i = 0; i < codeList.size(); i++) { + PathCode pathCode = codeList.get(i); + int[] coord = JsonUtils.getCoordinate(pathCode.getCode(), pathMapping); + if (coord == null) continue; + + // 璁$畻鍦ㄦ浣嶇疆鐨勫仠鐣欐椂闂� + double stayDuration = 2.0; // 绠�鍖栬绠楋紝浣跨敤鍥哄畾鍋滅暀鏃堕棿 + long startTimeSlot = currentTime / 1000; + long endTimeSlot = (long) (currentTime / 1000 + stayDuration); + + // 妫�鏌ユ椂绌哄啿绐� + for (long timeSlot = startTimeSlot; timeSlot <= endTimeSlot; timeSlot++) { + String spaceTimeKey = coord[0] + "," + coord[1] + "," + timeSlot; + if (occupancyMap.containsKey(spaceTimeKey)) { + return false; // 鍙戠幇鍐茬獊 + } + + // 妫�鏌ュ畨鍏ㄨ窛绂诲唴鐨勫啿绐� + if (!isSafeFromOtherCTUs(coord, timeSlot, occupancyMap, config)) { + return false; + } + } + + // 鏇存柊鍒颁笅涓�涓綅缃殑鏃堕棿 + currentTime += (long) (stayDuration * 1000); + if (i < codeList.size() - 1) { + currentTime += (long) (config.getStandardPointDistance() / config.getNormalSpeed() * 1000); + } + } + + return true; + } + + /** + * 妫�鏌ユ寚瀹氫綅缃拰鏃堕棿鏄惁涓庡叾浠朇TU淇濇寔瀹夊叏璺濈 + * + * @param coord 浣嶇疆鍧愭爣 + * @param timeSlot 鏃堕棿鐗� + * @param occupancyMap 鍗犵敤琛� + * @param config 鐗╃悊閰嶇疆 + * @return true濡傛灉瀹夊叏 + */ + private boolean isSafeFromOtherCTUs(int[] coord, long timeSlot, + Map<String, String> occupancyMap, CTUPhysicalConfig config) { + int safetyRadius = (int) Math.ceil(config.getMinSafetyDistance() / config.getStandardPointDistance()); + + // 妫�鏌ュ畨鍏ㄥ崐寰勫唴鏄惁鏈夊叾浠朇TU + for (int dx = -safetyRadius; dx <= safetyRadius; dx++) { + for (int dy = -safetyRadius; dy <= safetyRadius; dy++) { + if (dx == 0 && dy == 0) continue; + + String checkKey = (coord[0] + dx) + "," + (coord[1] + dy) + "," + timeSlot; + if (occupancyMap.containsKey(checkKey)) { + // 璁$畻瀹為檯璺濈 + double distance = Math.sqrt(dx * dx + dy * dy) * config.getStandardPointDistance(); + if (distance < config.getMinSafetyDistance()) { + return false; // 璺濈澶繎 + } + } + } + } + + return true; + } + + /** + * 杩炴帴鍓╀綑璺緞鍜屾柊璺緞 + * + * @param agv CTU鐘舵�� + * @param newPath 鏂拌鍒掔殑璺緞 + * @return 杩炴帴鍚庣殑瀹屾暣璺緞 + */ + public PlannedPath connectRemainingAndNewPath(AGVStatus agv, PlannedPath newPath) { + if (!agv.hasRemainingPath()) { + // 娌℃湁鍓╀綑璺緞锛岀洿鎺ヨ繑鍥炴柊璺緞 + return newPath; + } + + PlannedPath remainingPath = agv.getRemainingPath(); + List<PathCode> remainingCodes = new ArrayList<>(); + + // 娣诲姞鍓╀綑璺緞锛堜粠褰撳墠浣嶇疆寮�濮嬶級 + List<PathCode> originalCodes = remainingPath.getCodeList(); + for (int i = agv.getCurrentPathIndex(); i < originalCodes.size(); i++) { + remainingCodes.add(originalCodes.get(i)); + } + + // 杩炴帴鏂拌矾寰� + if (newPath != null && newPath.getCodeList() != null) { + // 妫�鏌ヨ繛鎺ョ偣鏄惁涓�鑷达紝閬垮厤閲嶅 + if (!remainingCodes.isEmpty() && !newPath.getCodeList().isEmpty()) { + PathCode lastRemaining = remainingCodes.get(remainingCodes.size() - 1); + PathCode firstNew = newPath.getCodeList().get(0); + + if (lastRemaining.getCode().equals(firstNew.getCode())) { + // 璺宠繃閲嶅鐨勮繛鎺ョ偣 + for (int i = 1; i < newPath.getCodeList().size(); i++) { + remainingCodes.add(newPath.getCodeList().get(i)); + } + } else { + // 鐩存帴杩炴帴 + remainingCodes.addAll(newPath.getCodeList()); + } + } else { + remainingCodes.addAll(newPath.getCodeList()); + } + } + + // 鍒涘缓杩炴帴鍚庣殑璺緞 + PlannedPath connectedPath = new PlannedPath(); + connectedPath.setAgvId(agv.getAgvId()); + connectedPath.setCodeList(remainingCodes); + + // 鐢熸垚鏂扮殑娈佃惤ID + String segId = agv.getAgvId() + "_CONNECTED_" + System.currentTimeMillis(); + if (newPath != null && newPath.getSegId() != null) { + segId = newPath.getSegId() + "_EXTENDED"; + } + connectedPath.setSegId(segId); + + return connectedPath; + } + + /** + * 鏇存柊绯荤粺鍩哄噯鏃堕棿 + * + * @param baseTime 鏂扮殑鍩哄噯鏃堕棿 + */ + public void updateSystemBaseTime(long baseTime) { + this.systemBaseTime = baseTime; + } + + /** + * 鑾峰彇CTU棰勮瀹屾垚鍓╀綑璺緞鐨勬椂闂� + * + * @param agv CTU鐘舵�� + * @return 棰勮瀹屾垚鏃堕棿锛堟绉掞級 + */ + public long getEstimatedCompletionTime(AGVStatus agv) { + if (!agv.hasRemainingPath()) { + return System.currentTimeMillis(); + } + + PlannedPath remainingPath = agv.getRemainingPath(); + List<PathCode> codeList = remainingPath.getCodeList(); + CTUPhysicalConfig config = agv.getPhysicalConfig(); + + long currentTime = agv.getNextPointArrivalTime(); + + // 璁$畻瀹屾垚鍓╀綑璺緞鎵�闇�鐨勬椂闂� + for (int i = agv.getCurrentPathIndex(); i < codeList.size(); i++) { + double stayDuration = calculateStayDuration(agv, i, codeList, config); + currentTime += (long) (stayDuration * 1000); + + if (i < codeList.size() - 1) { + PathCode currentCode = codeList.get(i); + PathCode nextCode = codeList.get(i + 1); + double travelTime = calculateTravelTime(currentCode, nextCode, config); + currentTime += (long) (travelTime * 1000); + } + } + + return currentTime; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/service/TaskAllocationService.java b/algo-zkd/src/main/java/com/algo/service/TaskAllocationService.java new file mode 100644 index 0000000..dbe8985 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/service/TaskAllocationService.java @@ -0,0 +1,292 @@ +package com.algo.service; + +import com.algo.model.AGVStatus; +import com.algo.model.BackpackData; +import com.algo.model.TaskAssignment; +import com.algo.model.TaskData; +import com.algo.util.JsonUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 浠诲姟鍒嗛厤鏈嶅姟绫� + */ +public class TaskAllocationService { + + private Map<String, Map<String, Integer>> pathMapping; + private Map<String, Object> environmentConfig; + + /** + * 鏋勯�犲嚱鏁� + * + * @param pathMapping 璺緞鏄犲皠淇℃伅 + * @param environmentConfig 鐜閰嶇疆淇℃伅 + */ + public TaskAllocationService(Map<String, Map<String, Integer>> pathMapping, + Map<String, Object> environmentConfig) { + this.pathMapping = pathMapping; + this.environmentConfig = environmentConfig; + } + + /** + * 鎵ц浠诲姟鍒嗛厤 + * 鏍规嵁AGV鐘舵�佸拰浠诲姟鍒楄〃杩涜鏅鸿兘鍒嗛厤 + * + * @param agvStatusList AGV鐘舵�佸垪琛� + * @param taskList 浠诲姟鍒楄〃 + * @return 浠诲姟鍒嗛厤缁撴灉鍒楄〃 + */ + public List<TaskAssignment> allocateTasks(List<AGVStatus> agvStatusList, List<TaskData> taskList) { + System.out.println("寮�濮嬩换鍔″垎閰嶏紝AGV鏁伴噺: " + agvStatusList.size() + ", 浠诲姟鏁伴噺: " + taskList.size()); + + // 杈撳嚭鐜淇℃伅 + System.out.println("鐜淇℃伅锛氬搴�=" + environmentConfig.get("width") + + ", 楂樺害=" + environmentConfig.get("height") + + ", 宸ヤ綔绔欐暟閲�=" + environmentConfig.get("stationCount")); + + List<TaskAssignment> assignments = new ArrayList<>(); + + // 1. 杩囨护鍙敤鐨凙GV + List<AGVStatus> availableAgvs = agvStatusList.stream() + .filter(agv -> agv.isAvailable() && agv.getAvailableBackpackCount() > 0) + .collect(Collectors.toList()); + + System.out.println("鍙敤AGV鏁伴噺: " + availableAgvs.size()); + + if (availableAgvs.isEmpty()) { + System.out.println("娌℃湁鍙敤鐨凙GV锛屼换鍔″垎閰嶇粨鏉�"); + return assignments; + } + + // 2. 杩囨护闇�瑕佸垎閰嶇殑浠诲姟锛堟帓闄ゅ凡鎸囧畾AGV鐨勪换鍔★級 + List<TaskData> unassignedTasks = taskList.stream() + .filter(task -> !task.isAssignedToAgv() && task.isTransportTask()) + .collect(Collectors.toList()); + + System.out.println("闇�瑕佸垎閰嶇殑杩愯緭浠诲姟鏁伴噺: " + unassignedTasks.size()); + + // 3. 鎸変紭鍏堢骇鎺掑簭浠诲姟 + unassignedTasks.sort((t1, t2) -> Integer.compare(t2.getPriority(), t1.getPriority())); + + // 4. 浣跨敤鏅鸿兘鍒嗛厤绛栫暐锛堣�冭檻宸ヤ綔绔欎俊鎭級 + assignments.addAll(performIntelligentAllocation(availableAgvs, unassignedTasks)); + + System.out.println("浠诲姟鍒嗛厤瀹屾垚锛岀敓鎴愬垎閰嶇粨鏋滄暟閲�: " + assignments.size()); + + return assignments; + } + + /** + * 鎵ц鏅鸿兘鍒嗛厤绛栫暐 + * 鑰冭檻AGV浣嶇疆銆佷换鍔′綅缃�佽儗绡撳閲忋�佸伐浣滅珯瀹归噺绛夊洜绱� + * + * @param availableAgvs 鍙敤AGV鍒楄〃 + * @param tasks 寰呭垎閰嶄换鍔″垪琛� + * @return 鍒嗛厤缁撴灉鍒楄〃 + */ + private List<TaskAssignment> performIntelligentAllocation(List<AGVStatus> availableAgvs, List<TaskData> tasks) { + List<TaskAssignment> assignments = new ArrayList<>(); + + // 涓烘瘡涓狝GV缁存姢涓�涓伐浣滆礋杞借褰� + Map<String, Integer> agvWorkLoad = new HashMap<>(); + Map<String, Integer> agvUsedBackpacks = new HashMap<>(); + + for (AGVStatus agv : availableAgvs) { + agvWorkLoad.put(agv.getAgvId(), 0); + agvUsedBackpacks.put(agv.getAgvId(), 0); + } + + // 鎸夊湴鐞嗕綅缃垎缁勪换鍔★紙鑰冭檻宸ヤ綔绔欎俊鎭級 + Map<String, List<TaskData>> tasksByStartLocation = groupTasksByStartLocation(tasks); + + // 涓烘瘡涓綅缃垎缁勫垎閰岮GV + for (Map.Entry<String, List<TaskData>> entry : tasksByStartLocation.entrySet()) { + String startLocation = entry.getKey(); + List<TaskData> locationTasks = entry.getValue(); + + System.out.println("澶勭悊璧风偣 " + startLocation + " 鐨勪换鍔★紝鏁伴噺: " + locationTasks.size()); + + // 妫�鏌ユ槸鍚︿负宸ヤ綔绔� + if (JsonUtils.isStation(startLocation, environmentConfig)) { + Map<String, Object> stationInfo = JsonUtils.getStationInfo(startLocation, environmentConfig); + if (stationInfo != null) { + Integer capacity = (Integer) stationInfo.get("capacity"); + System.out.println("宸ヤ綔绔� " + startLocation + " 瀹归噺: " + capacity); + + // 闄愬埗鍚屾椂鍒嗛厤缁欒宸ヤ綔绔欑殑浠诲姟鏁伴噺锛堜笉瓒呰繃瀹归噺锛� + locationTasks = locationTasks.subList(0, Math.min(locationTasks.size(), capacity)); + } + } + + // 鎵惧埌璺濈璇ヤ綅缃渶杩戠殑AGV + AGVStatus bestAgv = findNearestAvailableAgv(availableAgvs, startLocation, agvUsedBackpacks); + + if (bestAgv != null) { + // 涓鸿AGV鍒嗛厤灏藉彲鑳藉鐨勪换鍔★紙鑰冭檻鑳岀瘬瀹归噺锛� + int availableBackpacks = bestAgv.getAvailableBackpackCount() - agvUsedBackpacks.get(bestAgv.getAgvId()); + int tasksToAssign = Math.min(locationTasks.size(), availableBackpacks); + + for (int i = 0; i < tasksToAssign; i++) { + TaskData task = locationTasks.get(i); + + // 鏌ユ壘鍙敤鐨勮儗绡撲綅缃� + int backpackIndex = findAvailableBackpackIndex(bestAgv, agvUsedBackpacks.get(bestAgv.getAgvId())); + + if (backpackIndex != -1) { + // 鍒涘缓鍙栬揣浠诲姟鍒嗛厤 + TaskAssignment takeAssignment = new TaskAssignment( + task.getTaskId(), + bestAgv.getAgvId(), + TaskAssignment.generateSegId(task.getTaskId(), bestAgv.getAgvId(), 1), + String.valueOf(backpackIndex), + TaskAssignment.TYPE_TAKE + ); + assignments.add(takeAssignment); + + // 鍒涘缓鏀捐揣浠诲姟鍒嗛厤 + TaskAssignment putAssignment = new TaskAssignment( + task.getTaskId(), + bestAgv.getAgvId(), + TaskAssignment.generateSegId(task.getTaskId(), bestAgv.getAgvId(), 2), + String.valueOf(backpackIndex), + TaskAssignment.TYPE_PUT + ); + assignments.add(putAssignment); + + // 鏇存柊AGV宸ヤ綔璐熻浇 + agvWorkLoad.put(bestAgv.getAgvId(), agvWorkLoad.get(bestAgv.getAgvId()) + 1); + agvUsedBackpacks.put(bestAgv.getAgvId(), agvUsedBackpacks.get(bestAgv.getAgvId()) + 1); + + System.out.println("鍒嗛厤浠诲姟 " + task.getTaskId() + " 缁橝GV " + bestAgv.getAgvId() + + " 鑳岀瘬 " + backpackIndex + " (璧风偣: " + startLocation + ")"); + } else { + System.out.println("AGV " + bestAgv.getAgvId() + " 娌℃湁鍙敤鐨勮儗绡撲綅缃�"); + break; + } + } + } else { + System.out.println("鏈壘鍒板彲鐢ㄧ殑AGV澶勭悊璧风偣 " + startLocation + " 鐨勪换鍔�"); + } + } + + return assignments; + } + + /** + * 鎸夎捣鐐逛綅缃垎缁勪换鍔� + * + * @param tasks 浠诲姟鍒楄〃 + * @return 鎸夎捣鐐瑰垎缁勭殑浠诲姟Map + */ + private Map<String, List<TaskData>> groupTasksByStartLocation(List<TaskData> tasks) { + Map<String, List<TaskData>> grouped = new HashMap<>(); + + for (TaskData task : tasks) { + String startLocation = task.getStart(); + grouped.computeIfAbsent(startLocation, k -> new ArrayList<>()).add(task); + } + + return grouped; + } + + /** + * 鏌ユ壘璺濈鎸囧畾浣嶇疆鏈�杩戠殑鍙敤AGV + * + * @param availableAgvs 鍙敤AGV鍒楄〃 + * @param targetLocation 鐩爣浣嶇疆 + * @param usedBackpacks 宸蹭娇鐢ㄨ儗绡撴暟閲忕粺璁� + * @return 鏈�杩戠殑鍙敤AGV + */ + private AGVStatus findNearestAvailableAgv(List<AGVStatus> availableAgvs, String targetLocation, Map<String, Integer> usedBackpacks) { + AGVStatus bestAgv = null; + double minDistance = Double.MAX_VALUE; + + int[] targetCoord = JsonUtils.getCoordinate(targetLocation, pathMapping); + if (targetCoord == null) { + System.out.println("鏃犳硶鑾峰彇鐩爣浣嶇疆 " + targetLocation + " 鐨勫潗鏍�"); + return availableAgvs.isEmpty() ? null : availableAgvs.get(0); + } + + for (AGVStatus agv : availableAgvs) { + // 妫�鏌GV鏄惁杩樻湁鍙敤鑳岀瘬 + int availableBackpacks = agv.getAvailableBackpackCount() - usedBackpacks.get(agv.getAgvId()); + if (availableBackpacks <= 0) { + continue; + } + + int[] agvCoord = JsonUtils.getCoordinate(agv.getPosition(), pathMapping); + if (agvCoord != null) { + double distance = JsonUtils.calculateManhattanDistance(agvCoord, targetCoord); + + // 鑰冭檻AGV鐨勫伐浣滆礋杞斤紙璺濈瓒婅繎涓旇礋杞借秺杞昏秺濂斤級 + double adjustedDistance = distance + usedBackpacks.get(agv.getAgvId()) * 2.0; + + if (adjustedDistance < minDistance) { + minDistance = adjustedDistance; + bestAgv = agv; + } + } + } + + return bestAgv; + } + + /** + * 鏌ユ壘AGV鐨勫彲鐢ㄨ儗绡撲綅缃� + * + * @param agv AGV鐘舵�� + * @param usedCount 宸蹭娇鐢ㄧ殑鑳岀瘬鏁伴噺 + * @return 鍙敤鑳岀瘬绱㈠紩锛屽鏋滄病鏈夊彲鐢ㄥ垯杩斿洖-1 + */ + private int findAvailableBackpackIndex(AGVStatus agv, int usedCount) { + if (agv.getBackpack() == null || agv.getBackpack().isEmpty()) { + return usedCount == 0 ? 0 : -1; + } + + int availableCount = 0; + for (BackpackData backpack : agv.getBackpack()) { + if (backpack.isAvailable()) { + if (availableCount >= usedCount) { + return backpack.getIndex(); + } + availableCount++; + } + } + + return -1; + } + + /** + * 楠岃瘉浠诲姟鍒嗛厤缁撴灉 + * + * @param assignments 鍒嗛厤缁撴灉鍒楄〃 + * @return 楠岃瘉鏄惁閫氳繃 + */ + public boolean validateAssignments(List<TaskAssignment> assignments) { + Map<String, Set<String>> agvBackpackUsage = new HashMap<>(); + + for (TaskAssignment assignment : assignments) { + if (!assignment.isValid()) { + System.out.println("鍙戠幇鏃犳晥鐨勪换鍔″垎閰�: " + assignment); + return false; + } + + String agvId = assignment.getAgvId(); + String backpackId = assignment.getLev(); + + agvBackpackUsage.computeIfAbsent(agvId, k -> new HashSet<>()).add(backpackId); + } + + // 妫�鏌ヨ儗绡撲娇鐢ㄥ啿绐� + for (Map.Entry<String, Set<String>> entry : agvBackpackUsage.entrySet()) { + String agvId = entry.getKey(); + Set<String> usedBackpacks = entry.getValue(); + + System.out.println("AGV " + agvId + " 浣跨敤鑳岀瘬: " + usedBackpacks); + } + + return true; + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/java/com/algo/util/AgvTaskUtils.java b/algo-zkd/src/main/java/com/algo/util/AgvTaskUtils.java new file mode 100644 index 0000000..ac715a0 --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/util/AgvTaskUtils.java @@ -0,0 +1,65 @@ +package com.algo.util; + +import com.algo.model.AGVStatus; +import com.algo.model.TaskData; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +public class AgvTaskUtils { + + /** + * 鍔犺浇鍜岃В鏋怉GV鐘舵�佸垪琛� + * + * @param filePath 鏂囦欢鍦板潃 + * @return AGV鐘舵�佸垪琛� + */ + public static List<AGVStatus> loadAgvStatus(String filePath) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 鐩存帴瑙f瀽JSON鏁扮粍涓篖ist<AGVStatus> + return objectMapper.readValue( + new File(filePath), + new TypeReference<List<AGVStatus>>() { + } + ); + } catch (FileNotFoundException e) { + System.err.println("AGV鐘舵�佸垪琛ㄦ枃浠朵笉瀛樺湪: " + e.getMessage()); + } catch (IOException e) { + System.err.println("璺緞AGV鐘舵�佸垪琛ㄦ枃浠惰鍙栭敊璇�: " + e.getMessage()); + } catch (Exception e) { + System.err.println("鍔犺浇AGV鐘舵�佸垪琛ㄦ枃浠跺け璐�: " + e.getMessage()); + } + return null; + } + + /** + * 鍔犺浇鍜岃В鏋愪换鍔″垪琛� + * + * @param filePath 鏂囦欢鍦板潃 + * @return 浠诲姟鍒楄〃 + */ + public static List<TaskData> loadTaskList(String filePath) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 鐩存帴瑙f瀽JSON鏁扮粍涓篖ist<TaskData>,浣跨敤TypeReference鎸囧畾娉涘瀷绫诲瀷锛岄伩鍏嶇被鍨嬫摝闄ゅ鑷寸殑杞崲閿欒 + return objectMapper.readValue( + new File(filePath), + new TypeReference<List<TaskData>>() { + } + ); + } catch (FileNotFoundException e) { + System.err.println("浠诲姟鍒楄〃鏂囦欢涓嶅瓨鍦�: " + e.getMessage()); + } catch (IOException e) { + System.err.println("浠诲姟鍒楄〃鏂囦欢璇诲彇閿欒: " + e.getMessage()); + } catch (Exception e) { + System.err.println("鍔犺浇浠诲姟鍒楄〃鏂囦欢澶辫触: " + e.getMessage()); + } + return null; + } + +} diff --git a/algo-zkd/src/main/java/com/algo/util/JsonUtils.java b/algo-zkd/src/main/java/com/algo/util/JsonUtils.java new file mode 100644 index 0000000..8ec1aff --- /dev/null +++ b/algo-zkd/src/main/java/com/algo/util/JsonUtils.java @@ -0,0 +1,486 @@ +package com.algo.util; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JSON鏂囦欢璇诲彇宸ュ叿绫� + * 鐢ㄤ簬璇诲彇鐜閰嶇疆鍜岃矾寰勬槧灏勬枃浠� + */ +public class JsonUtils { + + /** + * 璇诲彇JSON鏂囦欢鍐呭 + * + * @param filePath 鏂囦欢璺緞 + * @return JSON瀛楃涓插唴瀹� + * @throws IOException 鏂囦欢璇诲彇寮傚父 + */ + public static String readJsonFile(String filePath) throws IOException { + StringBuilder content = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } + } + return content.toString(); + } + + /** + * 瑙f瀽璺緞鏄犲皠JSON鍐呭 + * 姝g‘瑙f瀽path_mapping.json鐨勫疄闄呮牸寮忥細{"path_id_to_coordinates": {...}} + * + * @param jsonContent JSON鍐呭 + * @return 璺緞鏄犲皠Map锛宬ey涓鸿矾寰勭紪鍙凤紝value涓哄潗鏍囦俊鎭� + */ + public static Map<String, Map<String, Integer>> parsePathMapping(String jsonContent) { + Map<String, Map<String, Integer>> pathMapping = new HashMap<>(); + + try { + // 鎵惧埌path_id_to_coordinates閮ㄥ垎 + String pathIdSection = extractJsonSection(jsonContent, "path_id_to_coordinates"); + if (pathIdSection == null) { + System.err.println("鏈壘鍒皃ath_id_to_coordinates閮ㄥ垎"); + return pathMapping; + } + + String[] lines = pathIdSection.split("\n"); + String currentKey = null; + + for (String line : lines) { + line = line.trim(); + + // 鏌ユ壘璺緞ID + if (line.startsWith("\"") && line.contains("\":[")) { + int endIndex = line.indexOf("\":["); + currentKey = line.substring(1, endIndex); + pathMapping.put(currentKey, new HashMap<>()); + } + + // 鏌ユ壘鍧愭爣淇℃伅 + if (currentKey != null && line.contains("\"x\":")) { + String xStr = line.substring(line.indexOf("\"x\":") + 4); + xStr = xStr.substring(0, xStr.indexOf(",")).trim(); + try { + int x = Integer.parseInt(xStr); + pathMapping.get(currentKey).put("x", x); + } catch (NumberFormatException e) { + // 蹇界暐瑙f瀽閿欒 + } + } + + if (currentKey != null && line.contains("\"y\":")) { + String yStr = line.substring(line.indexOf("\"y\":") + 4); + if (yStr.contains(",")) { + yStr = yStr.substring(0, yStr.indexOf(",")).trim(); + } else if (yStr.contains("}")) { + yStr = yStr.substring(0, yStr.indexOf("}")).trim(); + } + try { + int y = Integer.parseInt(yStr); + pathMapping.get(currentKey).put("y", y); + } catch (NumberFormatException e) { + // 蹇界暐瑙f瀽閿欒 + } + } + } + + System.out.println("鎴愬姛瑙f瀽璺緞鏄犲皠锛屽寘鍚� " + pathMapping.size() + " 涓矾寰勭偣"); + + } catch (Exception e) { + System.err.println("瑙f瀽璺緞鏄犲皠JSON鏃跺彂鐢熼敊璇�: " + e.getMessage()); + } + + return pathMapping; + } + + /** + * 鍔犺浇鍜岃В鏋愯矾寰勬槧灏勬枃浠� + * 姝g‘瑙f瀽path_mapping.json鐨勫疄闄呮牸寮忥細{"path_id_to_coordinates": {...}} + * + * @param filePath 鏂囦欢鍦板潃 + * @return 璺緞鏄犲皠Map锛宬ey涓鸿矾寰勭紪鍙凤紝value涓哄潗鏍囦俊鎭� + */ + public static Map<String, Map<String, Integer>> loadPathMapping(String filePath) { + // 杞崲涓虹洰鏍囩粨鏋� Map<String, Map<String, Integer>> + Map<String, Map<String, Integer>> pathMapping = new HashMap<>(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 鍏堣В鏋愪负椤跺眰Map<String, Object> + Map<String, Object> topLevelMap = objectMapper.readValue( + new File(filePath), + Map.class + ); + + if (!topLevelMap.containsKey("path_id_to_coordinates")) { + System.err.println("鏈壘鍒皃ath_id_to_coordinates閮ㄥ垎"); + return pathMapping; + } + + // 澶勭悊 path_id_to_coordinates锛堝皢鍧愭爣鍒楄〃杞崲涓虹涓�涓潗鏍囩殑path_id鏄犲皠锛� + Map<String, Object> pathIdCoords = (Map<String, Object>) topLevelMap.get("path_id_to_coordinates"); + for (Map.Entry<String, Object> entry : pathIdCoords.entrySet()) { + // 淇濆瓨鏂瑰紡: 璺緞ID:{"x": , "y":} + String pathId = entry.getKey(); + Object coordsObj = entry.getValue(); + if (coordsObj instanceof List) { + List<?> coordsList = (List<?>) coordsObj; + if (!coordsList.isEmpty()) { + Map<?, ?> coordMap = (Map<?, ?>) coordsList.get(0); + int x = ((Number) coordMap.get("x")).intValue(); + int y = ((Number) coordMap.get("y")).intValue(); + Map<String, Integer> pointMap = new HashMap<>(); + pointMap.put("x", x); + pointMap.put("y", y); + pathMapping.put(pathId, pointMap); + } + } + } + + System.out.println("鎴愬姛瑙f瀽璺緞鏄犲皠锛屽寘鍚� " + pathMapping.size() + " 涓矾寰勭偣"); + } catch (FileNotFoundException e) { + System.err.println("璺緞鏄犲皠鏂囦欢涓嶅瓨鍦�: " + e.getMessage()); + } catch (IOException e) { + System.err.println("璺緞鏄犲皠鏂囦欢璇诲彇閿欒: " + e.getMessage()); + } catch (Exception e) { + System.err.println("鍔犺浇璺緞鏄犲皠鏂囦欢澶辫触: " + e.getMessage()); + } + return pathMapping; + } + + /** + * 瑙f瀽鐜閰嶇疆JSON鍐呭 + * 瑙f瀽environment.json涓殑stations淇℃伅 + * + * @param jsonContent JSON鍐呭 + * @return 鐜閰嶇疆Map + */ + public static Map<String, Object> parseEnvironmentConfig(String jsonContent) { + Map<String, Object> config = new HashMap<>(); + + try { + // 瑙f瀽width + if (jsonContent.contains("\"width\":")) { + String widthStr = jsonContent.substring(jsonContent.indexOf("\"width\":") + 8); + widthStr = widthStr.substring(0, widthStr.indexOf(",")).trim(); + try { + config.put("width", Integer.parseInt(widthStr)); + } catch (NumberFormatException e) { + config.put("width", 78); + } + } + + // 瑙f瀽height + if (jsonContent.contains("\"height\":")) { + String heightStr = jsonContent.substring(jsonContent.indexOf("\"height\":") + 9); + heightStr = heightStr.substring(0, heightStr.indexOf(",")).trim(); + try { + config.put("height", Integer.parseInt(heightStr)); + } catch (NumberFormatException e) { + config.put("height", 50); + } + } + + // 瑙f瀽stations淇℃伅 + Map<String, Map<String, Object>> stations = parseStations(jsonContent); + config.put("stations", stations); + config.put("stationCount", stations.size()); + + System.out.println("鎴愬姛瑙f瀽鐜閰嶇疆锛屽寘鍚� " + stations.size() + " 涓伐浣滅珯"); + + } catch (Exception e) { + System.err.println("瑙f瀽鐜閰嶇疆JSON鏃跺彂鐢熼敊璇�: " + e.getMessage()); + } + + return config; + } + + /** + * 鍔犺浇鍜岃В鏋愮幆澧冮厤缃枃浠� + * 瑙f瀽environment.json涓殑stations淇℃伅 + * + * @param filePath 鏂囦欢鍦板潃 + * @return 鐜閰嶇疆Map + */ + public static Map<String, Object> loadEnvironment(String filePath) { + // 杞崲涓虹洰鏍囩粨鏋� Map<String, Object> + Map<String, Object> environmentMap = new HashMap<>(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 鍏堣В鏋愪负椤跺眰Map<String, Object> + Map<String, Object> topLevelMap = objectMapper.readValue( + new File(filePath), + Map.class + ); + + // 瑙f瀽width + if (topLevelMap.containsKey("width")) { + environmentMap.put("width", Integer.parseInt(topLevelMap.get("width").toString())); + } else { + environmentMap.put("width", 78); + } + + // 瑙f瀽height + if (topLevelMap.containsKey("width")) { + environmentMap.put("height", Integer.parseInt(topLevelMap.get("height").toString())); + } else { + environmentMap.put("height", 50); + } + + // 瑙f瀽stations淇℃伅 + if (topLevelMap.containsKey("stations")) { + Map<String, Map<String, Object>> stations = new HashMap<>(); + Map<String, Object> stationMap = (Map<String, Object>) topLevelMap.get("stations"); + for (Map.Entry<String, Object> stationEntry : stationMap.entrySet()) { + // 宸ヤ綔绔橧D + String pathId = stationEntry.getKey(); + Map<String, Object> stationInfo = (Map<String, Object>) stationEntry.getValue(); + Map<String, Object> map = new HashMap<>(); + // 瑙f瀽capacity + if (stationInfo.containsKey("capacity")) { + map.put("capacity", Integer.parseInt(stationInfo.get("capacity").toString())); + } + // 瑙f瀽load_position鍜寀nload_position + if (stationInfo.containsKey("load_position")) { + List<Integer> loadPos = (List<Integer>) stationInfo.get("load_position"); + map.put("load_position", loadPos); + } + if (stationInfo.containsKey("unload_position")) { + List<Integer> unloadPos = (List<Integer>) stationInfo.get("unload_position"); + map.put("unload_position", unloadPos); + } + stations.put(pathId, map); + } + environmentMap.put("stations", stations); + environmentMap.put("stationCount", stations.size()); + System.out.println("鎴愬姛瑙f瀽鐜閰嶇疆锛屽寘鍚� " + stations.size() + " 涓伐浣滅珯"); + } + } catch (FileNotFoundException e) { + System.err.println("鐜閰嶇疆鏂囦欢涓嶅瓨鍦�: " + e.getMessage()); + } catch (IOException e) { + System.err.println("鐜閰嶇疆鏂囦欢璇诲彇閿欒: " + e.getMessage()); + } catch (Exception e) { + System.err.println("鍔犺浇鐜閰嶇疆鏂囦欢澶辫触: " + e.getMessage()); + } + return environmentMap; + } + + /** + * 瑙f瀽stations淇℃伅 + * + * @param jsonContent JSON鍐呭 + * @return stations Map + */ + private static Map<String, Map<String, Object>> parseStations(String jsonContent) { + Map<String, Map<String, Object>> stations = new HashMap<>(); + + try { + String stationsSection = extractJsonSection(jsonContent, "stations"); + if (stationsSection == null) { + return stations; + } + + String[] lines = stationsSection.split("\n"); + String currentStation = null; + + for (String line : lines) { + line = line.trim(); + + // 鏌ユ壘宸ヤ綔绔橧D + if (line.startsWith("\"") && line.contains("\":{")) { + int endIndex = line.indexOf("\":{"); + currentStation = line.substring(1, endIndex); + stations.put(currentStation, new HashMap<>()); + } + + // 瑙f瀽capacity + if (currentStation != null && line.contains("\"capacity\":")) { + String capacityStr = line.substring(line.indexOf("\"capacity\":") + 11); + capacityStr = capacityStr.substring(0, capacityStr.indexOf(",")).trim(); + try { + int capacity = Integer.parseInt(capacityStr); + stations.get(currentStation).put("capacity", capacity); + } catch (NumberFormatException e) { + // 蹇界暐瑙f瀽閿欒 + } + } + + // 瑙f瀽load_position鍜寀nload_position + if (currentStation != null && line.contains("\"load_position\":")) { + List<Integer> loadPos = parsePosition(stationsSection, currentStation, "load_position"); + if (loadPos != null) { + stations.get(currentStation).put("load_position", loadPos); + } + } + + if (currentStation != null && line.contains("\"unload_position\":")) { + List<Integer> unloadPos = parsePosition(stationsSection, currentStation, "unload_position"); + if (unloadPos != null) { + stations.get(currentStation).put("unload_position", unloadPos); + } + } + } + + } catch (Exception e) { + System.err.println("瑙f瀽stations淇℃伅鏃跺彂鐢熼敊璇�: " + e.getMessage()); + } + + return stations; + } + + /** + * 瑙f瀽浣嶇疆淇℃伅 + * + * @param content JSON鍐呭 + * @param stationId 宸ヤ綔绔橧D + * @param positionType 浣嶇疆绫诲瀷锛坙oad_position鎴杣nload_position锛� + * @return 浣嶇疆鍧愭爣鍒楄〃 + */ + private static List<Integer> parsePosition(String content, String stationId, String positionType) { + try { + String stationSection = content.substring(content.indexOf("\"" + stationId + "\":{")); + String positionSection = stationSection.substring(stationSection.indexOf("\"" + positionType + "\":")); + + String[] lines = positionSection.split("\n"); + List<Integer> position = new ArrayList<>(); + + for (String line : lines) { + line = line.trim(); + if (line.matches("\\d+,?")) { + String numStr = line.replaceAll("[,\\s]", ""); + try { + position.add(Integer.parseInt(numStr)); + } catch (NumberFormatException e) { + // 蹇界暐瑙f瀽閿欒 + } + } + if (line.contains("]")) { + break; + } + } + + return position.size() == 2 ? position : null; + } catch (Exception e) { + return null; + } + } + + /** + * 鎻愬彇JSON涓殑鐗瑰畾閮ㄥ垎 + * + * @param jsonContent JSON鍐呭 + * @param sectionName 閮ㄥ垎鍚嶇О + * @return 鎻愬彇鐨勯儴鍒嗗唴瀹� + */ + private static String extractJsonSection(String jsonContent, String sectionName) { + try { + String startPattern = "\"" + sectionName + "\": {"; + int startIndex = jsonContent.indexOf(startPattern); + if (startIndex == -1) { + return null; + } + + int braceCount = 0; + int currentIndex = startIndex + startPattern.length() - 1; + + while (currentIndex < jsonContent.length()) { + char ch = jsonContent.charAt(currentIndex); + if (ch == '{') { + braceCount++; + } else if (ch == '}') { + braceCount--; + if (braceCount == 0) { + break; + } + } + currentIndex++; + } + + return jsonContent.substring(startIndex + startPattern.length() - 1, currentIndex + 1); + } catch (Exception e) { + return null; + } + } + + /** + * 鑾峰彇璺緞鐐圭殑鍧愭爣 + * + * @param pathId 璺緞鐐笽D + * @param pathMapping 璺緞鏄犲皠 + * @return 鍧愭爣鏁扮粍 [x, y]锛屽鏋滄湭鎵惧埌杩斿洖null + */ + public static int[] getCoordinate(String pathId, Map<String, Map<String, Integer>> pathMapping) { + Map<String, Integer> coordMap = pathMapping.get(pathId); + if (coordMap != null && coordMap.containsKey("x") && coordMap.containsKey("y")) { + return new int[]{coordMap.get("x"), coordMap.get("y")}; + } + return null; + } + + /** + * 鑾峰彇宸ヤ綔绔欎俊鎭� + * + * @param stationId 宸ヤ綔绔橧D + * @param environmentConfig 鐜閰嶇疆 + * @return 宸ヤ綔绔欎俊鎭疢ap + */ + @SuppressWarnings("unchecked") + public static Map<String, Object> getStationInfo(String stationId, Map<String, Object> environmentConfig) { + Map<String, Map<String, Object>> stations = + (Map<String, Map<String, Object>>) environmentConfig.get("stations"); + + if (stations != null) { + return stations.get(stationId); + } + return null; + } + + /** + * 鍒ゆ柇浣嶇疆鏄惁涓哄伐浣滅珯 + * + * @param position 浣嶇疆瀛楃涓� + * @param environmentConfig 鐜閰嶇疆 + * @return 鏄惁涓哄伐浣滅珯 + */ + public static boolean isStation(String position, Map<String, Object> environmentConfig) { + return getStationInfo(position, environmentConfig) != null; + } + + /** + * 璁$畻涓ょ偣涔嬮棿鐨勬浖鍝堥】璺濈 + * + * @param coord1 鍧愭爣1 [x, y] + * @param coord2 鍧愭爣2 [x, y] + * @return 鏇煎搱椤胯窛绂� + */ + public static double calculateManhattanDistance(int[] coord1, int[] coord2) { + if (coord1 == null || coord2 == null || coord1.length != 2 || coord2.length != 2) { + return Double.MAX_VALUE; + } + + return Math.abs(coord1[0] - coord2[0]) + Math.abs(coord1[1] - coord2[1]); + } + + /** + * 璁$畻涓ょ偣涔嬮棿鐨勬鍑犻噷寰楄窛绂� + * + * @param coord1 鍧愭爣1 [x, y] + * @param coord2 鍧愭爣2 [x, y] + * @return 娆у嚑閲屽緱璺濈 + */ + public static double calculateEuclideanDistance(int[] coord1, int[] coord2) { + if (coord1 == null || coord2 == null || coord1.length != 2 || coord2.length != 2) { + return Double.MAX_VALUE; + } + + int dx = coord1[0] - coord2[0]; + int dy = coord1[1] - coord2[1]; + return Math.sqrt(dx * dx + dy * dy); + } +} \ No newline at end of file diff --git a/algo-zkd/src/main/resources/META-INF/spring.factories b/algo-zkd/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..82fa48f --- /dev/null +++ b/algo-zkd/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.algo.service.PathPlanningService + diff --git a/algo-zkd/src/main/resources/application.yml b/algo-zkd/src/main/resources/application.yml new file mode 100644 index 0000000..71bf4d7 --- /dev/null +++ b/algo-zkd/src/main/resources/application.yml @@ -0,0 +1,8 @@ +spring: + application: + name: web-server + +server: + port: 8083 + + diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 0000000..cbc555c --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.zy</groupId> + <artifactId>api</artifactId> + <version>1.0-SNAPSHOT</version> + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <dubbo.version>2.7.8</dubbo.version> + <curator.version>4.2.0</curator.version> + <curator-recipes.version>2.8.0</curator-recipes.version> + <zookeeper.version>3.6.3</zookeeper.version> + </properties> + + + <dependencies> + + <!-- Dubbo Spring Boot Starter --> + <dependency> + <groupId>org.apache.dubbo</groupId> + <artifactId>dubbo-spring-boot-starter</artifactId> + <version>2.7.8</version> + </dependency> + + + <!-- Dubbo Spring Boot Starter --> + <dependency> + <groupId>org.apache.dubbo</groupId> + <artifactId>dubbo-spring-boot-starter</artifactId> + <version>${dubbo.version}</version> + + </dependency> + + <!-- zookeeper娉ㄥ唽涓績 闇�瑕佸鍏ookeeper渚濊禆 --> + <dependency> + <groupId>org.apache.zookeeper</groupId> + <artifactId>zookeeper</artifactId> + <version>${zookeeper.version}</version> + <!-- 鎻愮ず涓巣ookeeper涓殑slf4j-log4j12-1.7.29.jar 鍖呭啿绐�--> + <!--鎺掗櫎杩欎釜slf4j-log4j12--> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </exclusion> + </exclusions> + </dependency> + + <!-- Zookeeper 瀹㈡埛绔� --> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-framework</artifactId> + <version>${curator.version}</version> + </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-recipes</artifactId> + <version>${curator-recipes.version}</version> + </dependency> + + <!-- mybatis-plus --> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus</artifactId> + <version>3.5.12</version> + </dependency> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-generator</artifactId> + <version>3.4.1</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.20</version> + <scope>provided</scope> + </dependency> + + </dependencies> + + +</project> \ No newline at end of file diff --git a/api/src/main/java/com/algo/entity/User.java b/api/src/main/java/com/algo/entity/User.java new file mode 100644 index 0000000..b70558e --- /dev/null +++ b/api/src/main/java/com/algo/entity/User.java @@ -0,0 +1,25 @@ +package com.algo.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("sys_user") +public class User implements Serializable { + + private String username; + + /** + * 瀵嗙爜 + */ + private String password; + + /** + * 鏄电О + */ + private String nickname; + + +} diff --git a/api/src/main/java/com/algo/service/UserService.java b/api/src/main/java/com/algo/service/UserService.java new file mode 100644 index 0000000..56b757e --- /dev/null +++ b/api/src/main/java/com/algo/service/UserService.java @@ -0,0 +1,20 @@ +package com.algo.service; + +import com.algo.entity.User; + +import java.util.List; + +//todo 杩欓噷鍐欎竴涓嚜瀹氫箟娉ㄨВ锛屼箣鍚庨�氳繃鑷畾涔夋敞瑙f潵鑾峰彇璇ユ帴鍙e拰瀹炵幇绫诲皢鍏舵敞鍐屽埌娉ㄥ唽涓績 +public interface UserService { + + /** + * 鏌ヨuser + */ + public User queryUser(); + + void add(String key, String value); + + String get(String key); + + List<User> getDataByMySql(); +} diff --git a/rpc-server/pom.xml b/rpc-server/pom.xml new file mode 100644 index 0000000..7931cf0 --- /dev/null +++ b/rpc-server/pom.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.5.3</version> + <relativePath/> <!-- lookup parent from repository --> + </parent> + + + <groupId>com.zy</groupId> + <artifactId>rpc-server</artifactId> + <version>1.0-SNAPSHOT</version> + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + + <dependency> + <groupId>com.zy</groupId> + <artifactId>service</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + </dependencies> + + +</project> \ No newline at end of file diff --git a/rpc-server/src/main/java/com/algo/SpringBootRpcServerApplication.java b/rpc-server/src/main/java/com/algo/SpringBootRpcServerApplication.java new file mode 100644 index 0000000..aeefc36 --- /dev/null +++ b/rpc-server/src/main/java/com/algo/SpringBootRpcServerApplication.java @@ -0,0 +1,17 @@ +package com.algo; + +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +@EnableDubbo +public class SpringBootRpcServerApplication { + + + public static void main(String[] args) { + SpringApplication.run(SpringBootRpcServerApplication.class, args); + } +} + diff --git a/rpc-server/src/main/resources/application.yml b/rpc-server/src/main/resources/application.yml new file mode 100644 index 0000000..91fe50e --- /dev/null +++ b/rpc-server/src/main/resources/application.yml @@ -0,0 +1,85 @@ +spring: + application: + name: rpc-server + mvc: + static-path-pattern: /** + + servlet: + multipart: + maxFileSize: 100MB + maxRequestSize: 100MB + jmx: + enabled: false + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://localhost:3306/jbly?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: xltys1995 + type: com.alibaba.druid.pool.DruidDataSource + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 30000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + test-while-idle: true + test-on-borrow: true + test-on-return: false + remove-abandoned: true + remove-abandoned-timeout: 1800 + #pool-prepared-statements: false + #max-pool-prepared-statement-per-connection-size: 20 + filters: stat, wall + validation-query: SELECT 'x' + aop-patterns: com.zy.*.*.service.* + stat-view-servlet: + url-pattern: /druid/* + reset-enable: true + login-username: admin + login-password: admin + enabled: true + + redis: + host: localhost + password: xltys1995 + port: 6379 + max: 30 + min: 10 + timeout: 5000 + index: 3 + + + +server: + port: 8082 + +dubbo: + application: + name: rpc-server + registry: + address: zookeeper://127.0.0.1:2181 + # protocol: zookeeper + # password: dreamtech + # username: zk_user + protocol: + name: dubbo + port: 20880 +# monitor: +# protocol: registry + + +mybatis-plus: + mapper-locations: classpath:mapper/*/*.xml + # global-config: + # field-strategy: 0 + configuration: + # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + map-underscore-to-camel-case: true + cache-enabled: true + global-config: + :banner: false + db-config: + id-type: auto + logic-delete-value: 1 + logic-not-delete-value: 0 \ No newline at end of file diff --git a/rpc-server/target/classes/application.yml b/rpc-server/target/classes/application.yml index 91fe50e..1923162 100644 --- a/rpc-server/target/classes/application.yml +++ b/rpc-server/target/classes/application.yml @@ -39,6 +39,12 @@ login-username: admin login-password: admin enabled: true + servlet: + multipart: + maxFileSize: 100MB + maxRequestSize: 100MB + jmx: + enabled: false redis: host: localhost @@ -49,37 +55,3 @@ timeout: 5000 index: 3 - - -server: - port: 8082 - -dubbo: - application: - name: rpc-server - registry: - address: zookeeper://127.0.0.1:2181 - # protocol: zookeeper - # password: dreamtech - # username: zk_user - protocol: - name: dubbo - port: 20880 -# monitor: -# protocol: registry - - -mybatis-plus: - mapper-locations: classpath:mapper/*/*.xml - # global-config: - # field-strategy: 0 - configuration: - # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - map-underscore-to-camel-case: true - cache-enabled: true - global-config: - :banner: false - db-config: - id-type: auto - logic-delete-value: 1 - logic-not-delete-value: 0 \ No newline at end of file diff --git a/service/pom.xml b/service/pom.xml new file mode 100644 index 0000000..c00155f --- /dev/null +++ b/service/pom.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.zy</groupId> + <artifactId>service</artifactId> + <version>1.0-SNAPSHOT</version> + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + + </properties> + + + <dependencies> + + <dependency> + <groupId>com.zy</groupId> + <artifactId>api</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + + <!-- 闆嗘垚redis渚濊禆 --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-redis</artifactId> + <version>2.0.3.RELEASE</version> + </dependency> + + <!-- mybatis-plus --> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-boot-starter</artifactId> + <version>3.4.1</version> + </dependency> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-generator</artifactId> + <version>3.4.1</version> + </dependency> + + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>5.1.47</version> + </dependency> + + <!-- druid --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>1.2.6</version> + </dependency> + + </dependencies> +</project> \ No newline at end of file diff --git a/service/src/main/java/com/algo/mapper/UserMapper.java b/service/src/main/java/com/algo/mapper/UserMapper.java new file mode 100644 index 0000000..d001c64 --- /dev/null +++ b/service/src/main/java/com/algo/mapper/UserMapper.java @@ -0,0 +1,13 @@ +package com.algo.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.algo.entity.User; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface UserMapper extends BaseMapper<User> { + + +} diff --git a/service/src/main/java/com/algo/support/UserServiceSupport.java b/service/src/main/java/com/algo/support/UserServiceSupport.java new file mode 100644 index 0000000..273c2a6 --- /dev/null +++ b/service/src/main/java/com/algo/support/UserServiceSupport.java @@ -0,0 +1,49 @@ +package com.algo.support; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.algo.entity.User; +import com.algo.mapper.UserMapper; +import com.algo.service.UserService; +import org.apache.dubbo.config.annotation.DubboService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.List; + + +@DubboService // 璇ユ敞瑙g敤浜庡皢褰撳墠绫诲璞″瓨鍏pring瀹瑰櫒涓�,鏃㈠彲浠ユ湰椤圭洰鏈嶅姟浣跨敤锛岀埗鎺ュ彛娉ㄨВ鑳藉姏涔熷彲浠ユ彁渚涚粰鍏朵粬椤圭洰浣跨敤 +public class UserServiceSupport implements UserService { + + @Autowired + private RedisTemplate<String, String> redisTemplate; + + @Autowired + private UserMapper userMapper; + + /** + * 鏌ヨuser + */ + @Override + public User queryUser() { + User user = new User(); + user.setNickname("1212"); + user.setUsername("寮犱笁"); + return user; + } + + @Override + public void add(String key, String value) { + redisTemplate.opsForValue().set(key, value); + } + + @Override + public String get(String key) { + return redisTemplate.opsForValue().get(key); + } + + @Override + public List<User> getDataByMySql() { + List<User> users = userMapper.selectList(new QueryWrapper<>()); + return users; + } +} diff --git a/service/target/classes/mapper/system/UserMapper.xml b/service/src/main/resources/mapper/system/UserMapper.xml similarity index 100% rename from service/target/classes/mapper/system/UserMapper.xml rename to service/src/main/resources/mapper/system/UserMapper.xml diff --git a/web-server/pom.xml b/web-server/pom.xml new file mode 100644 index 0000000..d96a396 --- /dev/null +++ b/web-server/pom.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.5.3</version> + <relativePath/> <!-- lookup parent from repository --> + </parent> + + + <groupId>com.zy</groupId> + <artifactId>web-server</artifactId> + <version>1.0-SNAPSHOT</version> + + + <properties> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + + <dependency> + <groupId>com.zy</groupId> + <artifactId>api</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/web-server/src/main/java/com/algo/SpringBootAplication.java b/web-server/src/main/java/com/algo/SpringBootAplication.java new file mode 100644 index 0000000..9e03a4e --- /dev/null +++ b/web-server/src/main/java/com/algo/SpringBootAplication.java @@ -0,0 +1,17 @@ +package com.algo; + +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +@EnableDubbo +public class SpringBootAplication { + + + public static void main(String[] args) { + SpringApplication.run(SpringBootAplication.class, args); + } +} + diff --git a/web-server/src/main/java/com/algo/controller/UserController.java b/web-server/src/main/java/com/algo/controller/UserController.java new file mode 100644 index 0000000..026d456 --- /dev/null +++ b/web-server/src/main/java/com/algo/controller/UserController.java @@ -0,0 +1,41 @@ +package com.algo.controller; + + +import com.algo.entity.User; +import com.algo.service.UserService; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class UserController { + + @DubboReference(timeout = 1000, check = false)//杩滅▼娉ㄥ叆 + private UserService userService; + + + @GetMapping("/user") + public String user() { + User user = userService.queryUser(); + return user.toString(); + } + + @GetMapping("/get") + public String get() { + return userService.get("user"); + } + + @GetMapping("/add") + public String add() { + userService.add("user", "123"); + return "ok"; + } + + @GetMapping("/user3") + public List<User> user3() { + return userService.getDataByMySql(); + + } +} diff --git a/web-server/src/main/resources/application.yml b/web-server/src/main/resources/application.yml new file mode 100644 index 0000000..fe4b540 --- /dev/null +++ b/web-server/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + application: + name: web-server + +server: + port: 8083 + +dubbo: + protocol: + name: dubbo + port: 20885 + application: + name: web-server + registry: + address: zookeeper://127.0.0.1:2181 + # password: dreamtech + # username: zk_user +# monitor: +# protocol: registry -- Gitblit v1.9.1