Pārlūkot izejas kodu

开发:initial commit

Mubai_Gao 8 mēneši atpakaļ
revīzija
60043cf283
55 mainītis faili ar 8536 papildinājumiem un 0 dzēšanām
  1. 448 0
      auto_fill_jewel_v3.xcodeproj/project.pbxproj
  2. 7 0
      auto_fill_jewel_v3.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  3. 8 0
      auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  4. 5 0
      auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcuserdata/gaomubai.xcuserdatad/IDEFindNavigatorScopes.plist
  5. BIN
      auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcuserdata/gaomubai.xcuserdatad/UserInterfaceState.xcuserstate
  6. 79 0
      auto_fill_jewel_v3.xcodeproj/xcshareddata/xcschemes/Test.xcscheme
  7. 24 0
      auto_fill_jewel_v3.xcodeproj/xcuserdata/gaomubai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  8. 22 0
      auto_fill_jewel_v3.xcodeproj/xcuserdata/gaomubai.xcuserdatad/xcschemes/xcschememanagement.plist
  9. 91 0
      auto_fill_jewel_v3/BoostGeometryTools.cpp
  10. 33 0
      auto_fill_jewel_v3/BoostGeometryTools.hpp
  11. 53 0
      auto_fill_jewel_v3/BoxPositionTool.cpp
  12. 39 0
      auto_fill_jewel_v3/BoxPositionTool.hpp
  13. 208 0
      auto_fill_jewel_v3/FillGlobalConfig.cpp
  14. 114 0
      auto_fill_jewel_v3/FillGlobalConfig.hpp
  15. 23 0
      auto_fill_jewel_v3/FillResult.hpp
  16. 513 0
      auto_fill_jewel_v3/LevelGenerate.cpp
  17. 82 0
      auto_fill_jewel_v3/LevelGenerate.hpp
  18. 351 0
      auto_fill_jewel_v3/RandomGridFiller.cpp
  19. 96 0
      auto_fill_jewel_v3/RandomGridFiller.hpp
  20. 27 0
      auto_fill_jewel_v3/SpriteData.hpp
  21. 3429 0
      auto_fill_jewel_v3/ajson5.h
  22. 102 0
      auto_fill_jewel_v3/contourdata.cpp
  23. 48 0
      auto_fill_jewel_v3/contourdata.h
  24. 28 0
      auto_fill_jewel_v3/contourdatatools.cpp
  25. 19 0
      auto_fill_jewel_v3/contourdatatools.hpp
  26. 270 0
      auto_fill_jewel_v3/main.cpp
  27. 16 0
      测试数据/sg_jewel_items.csv
  28. 18 0
      测试数据/sg_level_data.csv
  29. 5 0
      测试数据/sg_plate_items.csv
  30. 2356 0
      测试数据/测试关卡100.json
  31. 10 0
      测试数据/轮廓/sg_宝石轮廓/files.txt
  32. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_2_1.png
  33. 1 0
      测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_2_1.png.json
  34. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_yz.png
  35. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_1_1.png
  36. 1 0
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_1_1.png.json
  37. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_yz.png
  38. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_1_1.png
  39. 1 0
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_1_1.png.json
  40. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_yz.png
  41. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_1_1.png
  42. 1 0
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_1_1.png.json
  43. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_yz.png
  44. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_1_1.png
  45. 1 0
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_1_1.png.json
  46. BIN
      测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_yz.png
  47. 3 0
      测试数据/轮廓/sg_宝石轮廓/测试图片说明.txt
  48. BIN
      测试数据/轮廓/sg_盘子轮廓/pan-large_heng.png
  49. 1 0
      测试数据/轮廓/sg_盘子轮廓/pan-large_heng.png.json
  50. BIN
      测试数据/轮廓/sg_盘子轮廓/pan-large_shu.png
  51. 1 0
      测试数据/轮廓/sg_盘子轮廓/pan-large_shu.png.json
  52. BIN
      测试数据/轮廓/sg_盘子轮廓/pan-only1.png
  53. 1 0
      测试数据/轮廓/sg_盘子轮廓/pan-only1.png.json
  54. BIN
      测试数据/轮廓/sg_盘子轮廓/pan-small.png
  55. 1 0
      测试数据/轮廓/sg_盘子轮廓/pan-small.png.json

+ 448 - 0
auto_fill_jewel_v3.xcodeproj/project.pbxproj

@@ -0,0 +1,448 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 56;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		3BF911C02CFF032000E11762 /* BoostGeometryTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911AE2CFF032000E11762 /* BoostGeometryTools.cpp */; };
+		3BF911C12CFF032000E11762 /* BoxPositionTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911B02CFF032000E11762 /* BoxPositionTool.cpp */; };
+		3BF911C22CFF032000E11762 /* contourdata.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911B22CFF032000E11762 /* contourdata.cpp */; };
+		3BF911C32CFF032000E11762 /* contourdatatools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911B42CFF032000E11762 /* contourdatatools.cpp */; };
+		3BF911C42CFF032000E11762 /* FillGlobalConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911B62CFF032000E11762 /* FillGlobalConfig.cpp */; };
+		3BF911C52CFF032000E11762 /* LevelGenerate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911B92CFF032000E11762 /* LevelGenerate.cpp */; };
+		3BF911C62CFF032000E11762 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911BB2CFF032000E11762 /* main.cpp */; };
+		3BF911C72CFF032000E11762 /* RandomGridFiller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BF911BC2CFF032000E11762 /* RandomGridFiller.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		3BEDF7272CFEE64F0087F5CA /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		3BEDF7292CFEE64F0087F5CA /* Test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Test; sourceTree = BUILT_PRODUCTS_DIR; };
+		3BF9118C2CFF032000E11762 /* 测试图片说明.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "测试图片说明.txt"; sourceTree = "<group>"; };
+		3BF9118D2CFF032000E11762 /* files.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = files.txt; sourceTree = "<group>"; };
+		3BF9118E2CFF032000E11762 /* jewel_assher_002_2_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_assher_002_2_1.png; sourceTree = "<group>"; };
+		3BF9118F2CFF032000E11762 /* jewel_assher_002_2_1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jewel_assher_002_2_1.png.json; sourceTree = "<group>"; };
+		3BF911902CFF032000E11762 /* jewel_assher_002_yz.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_assher_002_yz.png; sourceTree = "<group>"; };
+		3BF911912CFF032000E11762 /* jewel_brillant_030_1_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_brillant_030_1_1.png; sourceTree = "<group>"; };
+		3BF911922CFF032000E11762 /* jewel_brillant_030_1_1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jewel_brillant_030_1_1.png.json; sourceTree = "<group>"; };
+		3BF911932CFF032000E11762 /* jewel_brillant_030_yz.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_brillant_030_yz.png; sourceTree = "<group>"; };
+		3BF911942CFF032000E11762 /* jewel_brillant_032_1_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_brillant_032_1_1.png; sourceTree = "<group>"; };
+		3BF911952CFF032000E11762 /* jewel_brillant_032_1_1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jewel_brillant_032_1_1.png.json; sourceTree = "<group>"; };
+		3BF911962CFF032000E11762 /* jewel_brillant_032_yz.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_brillant_032_yz.png; sourceTree = "<group>"; };
+		3BF911972CFF032000E11762 /* jewel_coussin_031_1_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_coussin_031_1_1.png; sourceTree = "<group>"; };
+		3BF911982CFF032000E11762 /* jewel_coussin_031_1_1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jewel_coussin_031_1_1.png.json; sourceTree = "<group>"; };
+		3BF911992CFF032000E11762 /* jewel_coussin_031_yz.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_coussin_031_yz.png; sourceTree = "<group>"; };
+		3BF9119A2CFF032000E11762 /* jewel_coussin_062_1_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_coussin_062_1_1.png; sourceTree = "<group>"; };
+		3BF9119B2CFF032000E11762 /* jewel_coussin_062_1_1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jewel_coussin_062_1_1.png.json; sourceTree = "<group>"; };
+		3BF9119C2CFF032000E11762 /* jewel_coussin_062_yz.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = jewel_coussin_062_yz.png; sourceTree = "<group>"; };
+		3BF9119E2CFF032000E11762 /* pan-large_heng.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pan-large_heng.png"; sourceTree = "<group>"; };
+		3BF9119F2CFF032000E11762 /* pan-large_heng.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "pan-large_heng.png.json"; sourceTree = "<group>"; };
+		3BF911A02CFF032000E11762 /* pan-large_shu.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pan-large_shu.png"; sourceTree = "<group>"; };
+		3BF911A12CFF032000E11762 /* pan-large_shu.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "pan-large_shu.png.json"; sourceTree = "<group>"; };
+		3BF911A22CFF032000E11762 /* pan-only1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pan-only1.png"; sourceTree = "<group>"; };
+		3BF911A32CFF032000E11762 /* pan-only1.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "pan-only1.png.json"; sourceTree = "<group>"; };
+		3BF911A42CFF032000E11762 /* pan-small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pan-small.png"; sourceTree = "<group>"; };
+		3BF911A52CFF032000E11762 /* pan-small.png.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "pan-small.png.json"; sourceTree = "<group>"; };
+		3BF911A82CFF032000E11762 /* 测试关卡100.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "测试关卡100.json"; sourceTree = "<group>"; };
+		3BF911A92CFF032000E11762 /* sg_jewel_items.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sg_jewel_items.csv; sourceTree = "<group>"; };
+		3BF911AA2CFF032000E11762 /* sg_level_data.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sg_level_data.csv; sourceTree = "<group>"; };
+		3BF911AB2CFF032000E11762 /* sg_plate_items.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sg_plate_items.csv; sourceTree = "<group>"; };
+		3BF911AD2CFF032000E11762 /* ajson5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ajson5.h; sourceTree = "<group>"; };
+		3BF911AE2CFF032000E11762 /* BoostGeometryTools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BoostGeometryTools.cpp; sourceTree = "<group>"; };
+		3BF911AF2CFF032000E11762 /* BoostGeometryTools.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BoostGeometryTools.hpp; sourceTree = "<group>"; };
+		3BF911B02CFF032000E11762 /* BoxPositionTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BoxPositionTool.cpp; sourceTree = "<group>"; };
+		3BF911B12CFF032000E11762 /* BoxPositionTool.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BoxPositionTool.hpp; sourceTree = "<group>"; };
+		3BF911B22CFF032000E11762 /* contourdata.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = contourdata.cpp; sourceTree = "<group>"; };
+		3BF911B32CFF032000E11762 /* contourdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contourdata.h; sourceTree = "<group>"; };
+		3BF911B42CFF032000E11762 /* contourdatatools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = contourdatatools.cpp; sourceTree = "<group>"; };
+		3BF911B52CFF032000E11762 /* contourdatatools.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = contourdatatools.hpp; sourceTree = "<group>"; };
+		3BF911B62CFF032000E11762 /* FillGlobalConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FillGlobalConfig.cpp; sourceTree = "<group>"; };
+		3BF911B72CFF032000E11762 /* FillGlobalConfig.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FillGlobalConfig.hpp; sourceTree = "<group>"; };
+		3BF911B82CFF032000E11762 /* FillResult.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FillResult.hpp; sourceTree = "<group>"; };
+		3BF911B92CFF032000E11762 /* LevelGenerate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelGenerate.cpp; sourceTree = "<group>"; };
+		3BF911BA2CFF032000E11762 /* LevelGenerate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LevelGenerate.hpp; sourceTree = "<group>"; };
+		3BF911BB2CFF032000E11762 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+		3BF911BC2CFF032000E11762 /* RandomGridFiller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RandomGridFiller.cpp; sourceTree = "<group>"; };
+		3BF911BD2CFF032000E11762 /* RandomGridFiller.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RandomGridFiller.hpp; sourceTree = "<group>"; };
+		3BF911BE2CFF032000E11762 /* SpriteData.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SpriteData.hpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		3BEDF7262CFEE64F0087F5CA /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		3BEDF7202CFEE64F0087F5CA = {
+			isa = PBXGroup;
+			children = (
+				3BF911AC2CFF032000E11762 /* 测试数据 */,
+				3BF911BF2CFF032000E11762 /* auto_fill_jewel_v3 */,
+				3BEDF72A2CFEE64F0087F5CA /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		3BEDF72A2CFEE64F0087F5CA /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				3BEDF7292CFEE64F0087F5CA /* Test */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		3BF9119D2CFF032000E11762 /* sg_宝石轮廓 */ = {
+			isa = PBXGroup;
+			children = (
+				3BF9118C2CFF032000E11762 /* 测试图片说明.txt */,
+				3BF9118D2CFF032000E11762 /* files.txt */,
+				3BF9118E2CFF032000E11762 /* jewel_assher_002_2_1.png */,
+				3BF9118F2CFF032000E11762 /* jewel_assher_002_2_1.png.json */,
+				3BF911902CFF032000E11762 /* jewel_assher_002_yz.png */,
+				3BF911912CFF032000E11762 /* jewel_brillant_030_1_1.png */,
+				3BF911922CFF032000E11762 /* jewel_brillant_030_1_1.png.json */,
+				3BF911932CFF032000E11762 /* jewel_brillant_030_yz.png */,
+				3BF911942CFF032000E11762 /* jewel_brillant_032_1_1.png */,
+				3BF911952CFF032000E11762 /* jewel_brillant_032_1_1.png.json */,
+				3BF911962CFF032000E11762 /* jewel_brillant_032_yz.png */,
+				3BF911972CFF032000E11762 /* jewel_coussin_031_1_1.png */,
+				3BF911982CFF032000E11762 /* jewel_coussin_031_1_1.png.json */,
+				3BF911992CFF032000E11762 /* jewel_coussin_031_yz.png */,
+				3BF9119A2CFF032000E11762 /* jewel_coussin_062_1_1.png */,
+				3BF9119B2CFF032000E11762 /* jewel_coussin_062_1_1.png.json */,
+				3BF9119C2CFF032000E11762 /* jewel_coussin_062_yz.png */,
+			);
+			path = "sg_宝石轮廓";
+			sourceTree = "<group>";
+		};
+		3BF911A62CFF032000E11762 /* sg_盘子轮廓 */ = {
+			isa = PBXGroup;
+			children = (
+				3BF9119E2CFF032000E11762 /* pan-large_heng.png */,
+				3BF9119F2CFF032000E11762 /* pan-large_heng.png.json */,
+				3BF911A02CFF032000E11762 /* pan-large_shu.png */,
+				3BF911A12CFF032000E11762 /* pan-large_shu.png.json */,
+				3BF911A22CFF032000E11762 /* pan-only1.png */,
+				3BF911A32CFF032000E11762 /* pan-only1.png.json */,
+				3BF911A42CFF032000E11762 /* pan-small.png */,
+				3BF911A52CFF032000E11762 /* pan-small.png.json */,
+			);
+			path = "sg_盘子轮廓";
+			sourceTree = "<group>";
+		};
+		3BF911A72CFF032000E11762 /* 轮廓 */ = {
+			isa = PBXGroup;
+			children = (
+				3BF9119D2CFF032000E11762 /* sg_宝石轮廓 */,
+				3BF911A62CFF032000E11762 /* sg_盘子轮廓 */,
+			);
+			path = "轮廓";
+			sourceTree = "<group>";
+		};
+		3BF911AC2CFF032000E11762 /* 测试数据 */ = {
+			isa = PBXGroup;
+			children = (
+				3BF911A72CFF032000E11762 /* 轮廓 */,
+				3BF911A82CFF032000E11762 /* 测试关卡100.json */,
+				3BF911A92CFF032000E11762 /* sg_jewel_items.csv */,
+				3BF911AA2CFF032000E11762 /* sg_level_data.csv */,
+				3BF911AB2CFF032000E11762 /* sg_plate_items.csv */,
+			);
+			path = "测试数据";
+			sourceTree = "<group>";
+		};
+		3BF911BF2CFF032000E11762 /* auto_fill_jewel_v3 */ = {
+			isa = PBXGroup;
+			children = (
+				3BF911AD2CFF032000E11762 /* ajson5.h */,
+				3BF911AE2CFF032000E11762 /* BoostGeometryTools.cpp */,
+				3BF911AF2CFF032000E11762 /* BoostGeometryTools.hpp */,
+				3BF911B02CFF032000E11762 /* BoxPositionTool.cpp */,
+				3BF911B12CFF032000E11762 /* BoxPositionTool.hpp */,
+				3BF911B22CFF032000E11762 /* contourdata.cpp */,
+				3BF911B32CFF032000E11762 /* contourdata.h */,
+				3BF911B42CFF032000E11762 /* contourdatatools.cpp */,
+				3BF911B52CFF032000E11762 /* contourdatatools.hpp */,
+				3BF911B62CFF032000E11762 /* FillGlobalConfig.cpp */,
+				3BF911B72CFF032000E11762 /* FillGlobalConfig.hpp */,
+				3BF911B82CFF032000E11762 /* FillResult.hpp */,
+				3BF911B92CFF032000E11762 /* LevelGenerate.cpp */,
+				3BF911BA2CFF032000E11762 /* LevelGenerate.hpp */,
+				3BF911BB2CFF032000E11762 /* main.cpp */,
+				3BF911BC2CFF032000E11762 /* RandomGridFiller.cpp */,
+				3BF911BD2CFF032000E11762 /* RandomGridFiller.hpp */,
+				3BF911BE2CFF032000E11762 /* SpriteData.hpp */,
+			);
+			path = auto_fill_jewel_v3;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		3BEDF7282CFEE64F0087F5CA /* Test */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 3BEDF7302CFEE64F0087F5CA /* Build configuration list for PBXNativeTarget "Test" */;
+			buildPhases = (
+				3BEDF7252CFEE64F0087F5CA /* Sources */,
+				3BEDF7262CFEE64F0087F5CA /* Frameworks */,
+				3BEDF7272CFEE64F0087F5CA /* CopyFiles */,
+				3BF911D52CFF11F300E11762 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Test;
+			productName = Test;
+			productReference = 3BEDF7292CFEE64F0087F5CA /* Test */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		3BEDF7212CFEE64F0087F5CA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = 1;
+				LastUpgradeCheck = 1540;
+				TargetAttributes = {
+					3BEDF7282CFEE64F0087F5CA = {
+						CreatedOnToolsVersion = 15.4;
+					};
+				};
+			};
+			buildConfigurationList = 3BEDF7242CFEE64F0087F5CA /* Build configuration list for PBXProject "auto_fill_jewel_v3" */;
+			compatibilityVersion = "Xcode 14.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+				"zh-Hans",
+			);
+			mainGroup = 3BEDF7202CFEE64F0087F5CA;
+			productRefGroup = 3BEDF72A2CFEE64F0087F5CA /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				3BEDF7282CFEE64F0087F5CA /* Test */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		3BF911D52CFF11F300E11762 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		3BEDF7252CFEE64F0087F5CA /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3BF911C22CFF032000E11762 /* contourdata.cpp in Sources */,
+				3BF911C52CFF032000E11762 /* LevelGenerate.cpp in Sources */,
+				3BF911C72CFF032000E11762 /* RandomGridFiller.cpp in Sources */,
+				3BF911C12CFF032000E11762 /* BoxPositionTool.cpp in Sources */,
+				3BF911C42CFF032000E11762 /* FillGlobalConfig.cpp in Sources */,
+				3BF911C62CFF032000E11762 /* main.cpp in Sources */,
+				3BF911C32CFF032000E11762 /* contourdatatools.cpp in Sources */,
+				3BF911C02CFF032000E11762 /* BoostGeometryTools.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		3BEDF72E2CFEE64F0087F5CA /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include/opencv4,
+					/usr/local/include,
+				);
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MACOSX_DEPLOYMENT_TARGET = 14.2;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		3BEDF72F2CFEE64F0087F5CA /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include/opencv4,
+					/usr/local/include,
+				);
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MACOSX_DEPLOYMENT_TARGET = 14.2;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		3BEDF7312CFEE64F0087F5CA /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				EXCLUDED_SOURCE_FILE_NAMES = "";
+				INCLUDED_SOURCE_FILE_NAMES = "";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		3BEDF7322CFEE64F0087F5CA /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				EXCLUDED_SOURCE_FILE_NAMES = "";
+				INCLUDED_SOURCE_FILE_NAMES = "";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		3BEDF7242CFEE64F0087F5CA /* Build configuration list for PBXProject "auto_fill_jewel_v3" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3BEDF72E2CFEE64F0087F5CA /* Debug */,
+				3BEDF72F2CFEE64F0087F5CA /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		3BEDF7302CFEE64F0087F5CA /* Build configuration list for PBXNativeTarget "Test" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3BEDF7312CFEE64F0087F5CA /* Debug */,
+				3BEDF7322CFEE64F0087F5CA /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 3BEDF7212CFEE64F0087F5CA /* Project object */;
+}

+ 7 - 0
auto_fill_jewel_v3.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:">
+   </FileRef>
+</Workspace>

+ 8 - 0
auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>

+ 5 - 0
auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcuserdata/gaomubai.xcuserdatad/IDEFindNavigatorScopes.plist

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array/>
+</plist>

BIN
auto_fill_jewel_v3.xcodeproj/project.xcworkspace/xcuserdata/gaomubai.xcuserdatad/UserInterfaceState.xcuserstate


+ 79 - 0
auto_fill_jewel_v3.xcodeproj/xcshareddata/xcschemes/Test.xcscheme

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1540"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES"
+      buildArchitectures = "Automatic">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3BEDF7282CFEE64F0087F5CA"
+               BuildableName = "Test"
+               BlueprintName = "Test"
+               ReferencedContainer = "container:auto_fill_jewel_v3.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      shouldAutocreateTestPlan = "YES">
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES"
+      viewDebuggingEnabled = "No">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "3BEDF7282CFEE64F0087F5CA"
+            BuildableName = "Test"
+            BlueprintName = "Test"
+            ReferencedContainer = "container:auto_fill_jewel_v3.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "3BEDF7282CFEE64F0087F5CA"
+            BuildableName = "Test"
+            BlueprintName = "Test"
+            ReferencedContainer = "container:auto_fill_jewel_v3.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 24 - 0
auto_fill_jewel_v3.xcodeproj/xcuserdata/gaomubai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Bucket
+   uuid = "E8A9E417-1971-4C44-92BE-A8056CA913CA"
+   type = "1"
+   version = "2.0">
+   <Breakpoints>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "A6E9211F-68C2-461B-BA27-C7863D610D44"
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "auto_fill_jewel_v3/main.cpp"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "147"
+            endingLineNumber = "147"
+            landmarkName = "writeLevelJson(resultPlateFillResults, resultPlateCenterPointArr, outfilename)"
+            landmarkType = "9">
+         </BreakpointContent>
+      </BreakpointProxy>
+   </Breakpoints>
+</Bucket>

+ 22 - 0
auto_fill_jewel_v3.xcodeproj/xcuserdata/gaomubai.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>Test.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>0</integer>
+		</dict>
+	</dict>
+	<key>SuppressBuildableAutocreation</key>
+	<dict>
+		<key>3BEDF7282CFEE64F0087F5CA</key>
+		<dict>
+			<key>primary</key>
+			<true/>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 91 - 0
auto_fill_jewel_v3/BoostGeometryTools.cpp

@@ -0,0 +1,91 @@
+//
+//  BoostGeometryTools.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "BoostGeometryTools.hpp"
+#define BOOSTGEOMETRYTOOLS_BOX_PT_CNT 5
+bool BoostGeometryTools::isAIntersectsB(BoostGeometryTools::BoostPolygon& polyA, BoostGeometryTools::BoostPolygon& polyB)
+{
+    return boost::geometry::intersects(polyA, polyB) ;
+}
+bool BoostGeometryTools::isAWithinB(BoostGeometryTools::BoostPolygon& polyA, BoostGeometryTools::BoostPolygon& polyB)
+{
+    return boost::geometry::within(polyA,polyB) ;
+}
+
+BoostGeometryTools::BoostPolygon BoostGeometryTools::makeBox( float lowerLeftX,float lowerLeftY,float wid,float hei )
+{
+    float xarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftX, lowerLeftX+wid, lowerLeftX+wid , lowerLeftX , lowerLeftX } ;
+    float yarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftY , lowerLeftY   , lowerLeftY+hei , lowerLeftY+hei , lowerLeftY } ;
+    BoostPolygon poly ;
+    for(int ip = 0 ; ip < BOOSTGEOMETRYTOOLS_BOX_PT_CNT;++ip ) {
+        poly.outer().push_back( {xarr[ip],yarr[ip]} ) ;
+    }
+    return poly ;
+}
+
+BoostGeometryTools::BoostPolygon BoostGeometryTools::makeRotatedBox( float lowerLeftX,float lowerLeftY,float wid,float hei,float rotdeg)
+{
+    const float DEG2RAD = 3.141592/180.0;
+    float rad = DEG2RAD*rotdeg ;
+    float xarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftX, lowerLeftX+wid, lowerLeftX+wid , lowerLeftX , lowerLeftX } ;
+    float yarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftY , lowerLeftY   , lowerLeftY+hei , lowerLeftY+hei , lowerLeftY } ;
+    BoostPolygon poly ;
+    for(int ip = 0 ; ip < BOOSTGEOMETRYTOOLS_BOX_PT_CNT;++ip ) {
+        float x1 = 0 ;
+        float y1 = 0 ;
+        rotatePoint(xarr[ip], yarr[ip], rad, x1, y1) ;
+        poly.outer().push_back( {x1,y1} ) ;
+    }
+    return poly ;
+}
+
+
+void BoostGeometryTools::rotatePoint( float x0, float y0, float rotRad, float& x1,float& y1) {
+    float cosval = cosf(rotRad) ;
+    float sinval = sinf(rotRad) ;
+    x1 = x0*cosval - y0*sinval ;
+    y1 = x0*sinval + y0*cosval ;
+}
+
+BoostGeometryTools::BoostPolygon BoostGeometryTools::makeRotateNTranslateBox( float lowerLeftX,float lowerLeftY,float wid,float hei,float rotdeg,float dx,float dy)
+{
+    const float DEG2RAD = 3.141592/180.0;
+    float rad = DEG2RAD*rotdeg ;
+    float xarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftX, lowerLeftX+wid, lowerLeftX+wid , lowerLeftX , lowerLeftX } ;
+    float yarr[BOOSTGEOMETRYTOOLS_BOX_PT_CNT] = { lowerLeftY , lowerLeftY   , lowerLeftY+hei , lowerLeftY+hei , lowerLeftY } ;
+    BoostPolygon poly ;
+    for(int ip = 0 ; ip < BOOSTGEOMETRYTOOLS_BOX_PT_CNT;++ip ) {
+        float x1 = 0 ;
+        float y1 = 0 ;
+        rotatePoint(xarr[ip], yarr[ip], rad, x1, y1) ;
+        poly.outer().push_back( {x1+dx,y1+dy} ) ;
+    }
+    return poly ;
+}
+
+BoostGeometryTools::BoostPolygon BoostGeometryTools::translatePolygon(BoostGeometryTools::BoostPolygon& poly,float dx,float dy)
+{
+    BoostPolygon newPoly = poly ;
+    for(auto it = newPoly.outer().begin(); it!=newPoly.outer().end();++it ) {
+        it->set<0>( it->get<0>() + dx ) ;
+        it->set<1>( it->get<1>() + dy ) ;
+    }
+    return newPoly ;
+}
+
+BoostGeometryTools::BoostPolygon BoostGeometryTools::convex_hull(BoostGeometryTools::BoostPolygon& poly)
+{
+    BoostGeometryTools::BoostPolygon hull ;
+    boost::geometry::convex_hull(poly, hull) ;
+    return hull ;
+}
+
+bool BoostGeometryTools::pointIntersetsBox(BoostGeometryTools::BoostPoint& ptA,BoostGeometryTools::BoostPolygon& polyB)
+{
+    return boost::geometry::intersects(ptA,polyB) ;
+}
+

+ 33 - 0
auto_fill_jewel_v3/BoostGeometryTools.hpp

@@ -0,0 +1,33 @@
+//
+//  BoostGeometryTools.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef BoostGeometryTools_hpp
+#define BoostGeometryTools_hpp
+
+#include <stdio.h>
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/geometries/polygon.hpp>
+
+struct BoostGeometryTools {
+    typedef boost::geometry::model::point<float,2,boost::geometry::cs::cartesian> BoostPoint;//定义点
+    typedef boost::geometry::model::polygon<BoostPoint,false,false> BoostPolygon;//定义多边形
+    typedef boost::geometry::model::box<BoostPoint> BoostBox;
+    
+    static bool isAIntersectsB(BoostPolygon& polyA, BoostPolygon& polyB);//检验多边形A和B是否相交
+    static bool isAWithinB(BoostPolygon& polyA, BoostPolygon& polyB) ;// 测试 A 在 B 的内部
+    
+    static BoostPolygon makeBox( float lowerLeftX,float lowerLeftY,float wid,float hei ) ;
+    static BoostPolygon makeRotatedBox( float lowerLeftX,float lowerLeftY,float wid,float hei,float rotdeg) ;//绕0,0点旋转
+    static BoostPolygon makeRotateNTranslateBox( float lowerLeftX,float lowerLeftY,float wid,float hei,float rotdeg,float dx,float dy) ;//先绕0,0点旋转,然后平移dx和dy
+    static void rotatePoint( float x0, float y0, float rotRad, float& x1,float& y1) ;//围绕0,0点旋转一个点,rotRad使用弧度
+    static BoostPolygon translatePolygon(BoostPolygon& poly,float dx,float dy) ;//平移一个多边形
+    static BoostPolygon convex_hull(BoostPolygon& poly) ;//计算外接包裹盒子多边形
+    static bool pointIntersetsBox(BoostPoint& ptA,BoostPolygon& polyB) ;//检验点是否在多边形内部
+} ;
+
+#endif /* BoostGeometryTools_hpp */

+ 53 - 0
auto_fill_jewel_v3/BoxPositionTool.cpp

@@ -0,0 +1,53 @@
+//
+//  BoxPositionTool.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "BoxPositionTool.hpp"
+#include <iostream>
+using std::cout;
+using std::endl;
+
+void BoxPositionTool::solve(const int visWidth,const int visHeight, vector<vector<int>>& boxSizeArr, vector<vector<int>>& resultPositions)
+{
+    _boxes.clear() ;
+    int numSolv = boxSizeArr.size() ;
+    int boxIndex = 0 ;
+    for(int y = 0 ; y < visHeight; ++y ) {
+        for(int x = 0 ; x < visWidth; ++ x ) {
+            vector<int>& box = boxSizeArr[boxIndex] ;
+            if( withinContainer(x, y, box[0], box[1]) ) {
+                BoostGeometryTools::BoostPolygon poly=BoostGeometryTools::makeBox(x, y, box[0], box[1]) ;
+                if( interectsWithOthers(poly) == false ) {
+                    _boxes.push_back(poly) ;
+                    numSolv-- ;
+                    boxIndex++ ;
+                    resultPositions.push_back({x+box[0]/2, y+box[1]/2}) ;
+                    cout<<"debug box at x,y "<<x<<","<<y<<endl;
+                    x = x+box[0]-1 ;
+                }
+            }
+            if( numSolv==0 ) break ;
+        }
+        if( numSolv==0 ) break ;
+    }
+}
+
+bool BoxPositionTool::withinContainer(const int llx,const int lly,const int wid,const int hei)
+{
+    if( llx < 0 ) return false ;
+    if( llx + wid > BOXPOSITIONTOOL_CONTAINER_WIDTH )  return false ;
+    return true ;
+}
+bool BoxPositionTool::interectsWithOthers(BoostGeometryTools::BoostPolygon& poly)
+{
+    for(int io = 0 ; io < _boxes.size();++ io ) {
+        if( BoostGeometryTools::isAIntersectsB(poly, _boxes[io]) ) {
+            return true ;
+        }
+    }
+    return false ;
+}
+

+ 39 - 0
auto_fill_jewel_v3/BoxPositionTool.hpp

@@ -0,0 +1,39 @@
+//
+//  BoxPositionTool.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef BoxPositionTool_hpp
+#define BoxPositionTool_hpp
+
+#include "BoostGeometryTools.hpp"
+
+#include <stdio.h>
+#include <vector>
+using std::vector;
+
+#define BOXPOSITIONTOOL_CONTAINER_WIDTH 650
+
+struct BoxPositionTool {
+
+    
+    /// 算法从左下角开始填,向右,填满水平空间向上填,超出来的就想上填
+    /// @param visWidth 可视化区域宽度
+    /// @param visHeight 可视化区域高度
+    /// @param boxSizeArr 输入矩形数组,数据是宽和高
+    /// @param resultPositions 是输出结果,对应输入矩形顺序,每个数据是一个box中心在整个可视化区域的坐标。可视化区域坐标原点在左下角。
+    void solve(const int visWidth,const int visHeight,vector<vector<int>>& boxSizeArr, vector<vector<int>>& resultPositions ) ;
+    
+    /// 只考虑宽度方向是否放的下不,宽度最大不能超过 270+270+110=650
+    bool withinContainer(const int llx,const int lly,const int wid,const int hei) ;
+    bool interectsWithOthers(BoostGeometryTools::BoostPolygon& poly) ;
+    
+private:
+    vector<BoostGeometryTools::BoostPolygon> _boxes ;
+    
+    
+} ;
+
+#endif /* BoxPositionTool_hpp */

+ 208 - 0
auto_fill_jewel_v3/FillGlobalConfig.cpp

@@ -0,0 +1,208 @@
+//
+//  FillGlobalConfig.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "FillGlobalConfig.hpp"
+using namespace ArduinoJson;
+#include <fstream>
+using std::ifstream;
+#include <boost/algorithm/string.hpp>
+
+FillGlobalConfig* FillGlobalConfig::_s_instance = nullptr ;
+
+bool FillGlobalConfig::init(string filename)
+{
+    _plateContours.clear();
+    _jewelContours.clear() ;
+    ifstream ifs( filename.c_str() );
+    if( ifs.good()==false ) return false ;
+    DynamicJsonBuffer buffer ;
+    JsonObject& root = buffer.parse(ifs) ;
+    string platedir = root["plate_contour_dir"].as<char*>() ;
+    string jeweldir = root["jewel_contour_dir"].as<char*>() ;
+    JsonArray& parr =root["plate_names"].as<JsonArray>() ;
+    JsonArray& jarr =root["jewel_names"].as<JsonArray>() ;
+    _plateContours.resize(parr.size());
+    _jewelContours.resize(jarr.size());
+    
+    for(int i=0;i<parr.size();++i ) {
+        string name1 = parr[i].as<char*>() ;
+        string fullname1 =  platedir + name1 ;
+        _plateContours[i]._name = name1 ;
+        _plateContours[i]._contour.readFromJsonFile(fullname1) ;
+    }
+    for(int i=0;i<jarr.size();++i ) {
+        string name1 = jarr[i].as<char*>() ;
+        string fullname1 =  jeweldir + name1 ;
+        _jewelContours[i]._name = name1 ;
+        _jewelContours[i]._contour.readFromJsonFile(fullname1) ;
+    }
+    return true;
+}
+
+FillGlobalConfig* FillGlobalConfig::getInstance()
+{
+    if( _s_instance == nullptr ) {
+        _s_instance = new FillGlobalConfig ;
+        _s_instance->init("config.json") ;
+        _s_instance->initJewelItems("sg_jewel_items.csv") ;
+        _s_instance->initLevelDatas("sg_level_data.csv") ;
+        _s_instance->initPlateItems("sg_plate_items.csv") ;
+    }
+    return _s_instance ;
+}
+
+ContourData* FillGlobalConfig::getContourDataByPngName(string& pngname)
+{
+    for(auto it = _jewelContours.begin(); it!=_jewelContours.end();++it ) {
+        if( it->_name.find(pngname) != string::npos ) {
+            return &(it->_contour) ;
+        }
+    }
+    return nullptr ;
+}
+
+bool FillGlobalConfig::initJewelItems( string filename )
+{
+    _mapJewelItems.clear() ;
+    ifstream ifs( filename.c_str() ) ;
+    if( ifs.good()==false ) return false ;
+    string line ;
+    //跳过第一行
+    std::getline(ifs, line) ;
+    
+    vector<string> tokens ;
+    while( std::getline(ifs, line) ) {
+        if( line.length() > 2 ) {
+            tokens.clear() ;
+            boost::split(tokens, line, boost::is_any_of(","));
+            if( tokens.size()>=13 ) {
+                JewelItem ji ;
+                ji._id = atof(tokens[0].c_str()) ;
+                ji._category = tokens[1] ;
+                ji._jewelName = tokens[2] ;
+                ji._code1 = tokens[3] ;
+                ji._code2 = tokens[4] ;
+                ji._size = (tokens[5].compare("SM")==0)?FILLGLOBALCONFIG_JEWELSIZE_SM:((tokens[5].compare("MD")==0)?FILLGLOBALCONFIG_JEWELSIZE_MD:FILLGLOBALCONFIG_JEWELSIZE_LG) ;
+                ji._scale = atof( tokens[6].c_str() ) ;
+                ji._pngName = tokens[7] ;
+                ji._yzName = tokens[8] ;
+                ji._contourName = tokens[9] ;
+                ji._bbWidth = atof( tokens[10].c_str() ) ;
+                ji._bbHeight = atof( tokens[11].c_str() ) ;
+                ji._etc = tokens[12] ;
+                _mapJewelItems[ji._id] = ji ;
+            }
+        }
+    }
+    return true ;
+}
+
+
+bool FillGlobalConfig::initLevelDatas( string filename )
+{
+    _mapLevelDatas.clear() ;
+    ifstream ifs( filename.c_str() ) ;
+    if( ifs.good()==false ) return false ;
+    string line ;
+    //跳过第一行
+    std::getline(ifs, line) ;
+    LevelData tempLevelData ;
+    tempLevelData._id = -1 ;//初始化
+    
+    vector<string> tokens ;
+    while( std::getline(ifs, line) ) {
+        bool isDataLine = false;
+        if( line.length() > 2 ) {
+            tokens.clear() ;
+            boost::split(tokens, line, boost::is_any_of(","));
+            if( tokens.size()>=6 ) {
+                isDataLine = true ;
+                int lid = atof(tokens[0].c_str()) ;
+                int subid = atof(tokens[1].c_str()) ;
+                int difficulty = atof(tokens[2].c_str()) ;
+                int jewId = atof(tokens[3].c_str()) ;
+                string jewSz = tokens[4]; //ignored
+                int grpcnt = atof( tokens[5].c_str() ) ;
+                if( tempLevelData._id == -1 ) {
+                    tempLevelData._id = lid ;
+                    tempLevelData._subId = subid ;
+                    tempLevelData._difficulty = difficulty ;
+                }
+                tempLevelData._jewelIds.push_back(jewId) ;
+                tempLevelData._cnts.push_back(grpcnt*3) ;
+            }
+        }
+        
+        if( isDataLine==false )
+        {
+            //出现空行, 记录临时关卡
+            if( tempLevelData._id>0 ) {
+                _mapLevelDatas[tempLevelData._id].push_back(tempLevelData) ;
+            }
+            //清空临时关卡数据
+            tempLevelData._id = -1 ;
+            tempLevelData._subId = -1 ;
+            tempLevelData._difficulty = -1;
+            tempLevelData._cnts.clear() ;
+            tempLevelData._jewelIds.clear() ;
+        }
+    }
+    //最后一个临时对象是否是有效关卡数据
+    if( tempLevelData._id>0 ) {
+        _mapLevelDatas[tempLevelData._id].push_back(tempLevelData) ;
+        tempLevelData._id = -1 ;
+        tempLevelData._cnts.clear() ;
+        tempLevelData._jewelIds.clear() ;
+    }
+    return true ;
+}
+
+
+bool FillGlobalConfig::initPlateItems( string filename )
+{
+    _mapPlateItems.clear() ;
+    _mapPlateIdArray.clear() ;
+    ifstream ifs( filename.c_str() ) ;
+    if( ifs.good()==false ) return false ;
+    string line ;
+    //跳过第一行
+    std::getline(ifs, line) ;
+    
+    vector<string> tokens ;
+    while( std::getline(ifs, line) ) {
+        if( line.length() > 2 ) {
+            tokens.clear() ;
+            boost::split(tokens, line, boost::is_any_of(","));
+            if( tokens.size()>=13 ) {
+                PlateItem pi ;
+                pi._id = atof(tokens[0].c_str()) ;
+                pi._name = tokens[1] ;
+                int sz = 0 ;
+                string szStr = tokens[2] ;
+                if( szStr.compare("SM")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_SM ;
+                else if( szStr.compare("MD")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_MD;
+                else if( szStr.compare("LG")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_LG;
+                else continue; //无效盘子跳过
+                pi._size = sz ;
+                pi._pngName = tokens[3] ;
+                pi._contourName = tokens[4] ;
+                pi._blx = atof( tokens[5].c_str() ) ;//bottom left
+                pi._bly = atof( tokens[6].c_str() ) ;
+                pi._trx = atof( tokens[7].c_str() ) ;//top right
+                pi._try = atof( tokens[8].c_str() ) ;
+                pi._bigJewCap = atof( tokens[9].c_str() ) ;
+                pi._bbwid = atof( tokens[10].c_str()) ;
+                pi._bbhei = atof( tokens[11].c_str()) ;
+                pi._etc = tokens[12] ;
+                _mapPlateItems[pi._id] = pi ;
+                _mapPlateIdArray[sz].push_back(pi._id) ;
+            }
+        }
+    }
+    return true ;
+}
+

+ 114 - 0
auto_fill_jewel_v3/FillGlobalConfig.hpp

@@ -0,0 +1,114 @@
+//
+//  FillGlobalConfig.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef FillGlobalConfig_hpp
+#define FillGlobalConfig_hpp
+
+#include <stdio.h>
+
+#include <stdio.h>
+#include "contourdata.h"
+#include <string>
+using std::string;
+#include "ajson5.h"
+#include <unordered_map>
+using std::unordered_map;
+#include <vector>
+using std::vector;
+
+#define FILLGLOBALCONFIG_JEWELSIZE_SM 0
+#define FILLGLOBALCONFIG_JEWELSIZE_MD 1
+#define FILLGLOBALCONFIG_JEWELSIZE_LG 2
+
+#define FILLGLOBALCONFIG_DIFFCULTY_NORM  0
+#define FILLGLOBALCONFIG_DIFFCULTY_HARD1 1
+#define FILLGLOBALCONFIG_DIFFCULTY_HARD2 2
+
+#define FILLGLOBALCONFIG_PLATESIZE_SM 1
+#define FILLGLOBALCONFIG_PLATESIZE_MD 2
+#define FILLGLOBALCONFIG_PLATESIZE_LG 3
+
+
+struct FillGlobalConfig {
+    
+    //这个结构体似乎不用了
+    struct ContourConfig {
+        string _name;
+        ContourData _contour ;
+    } ;
+    bool init(string filename) ;
+    bool initJewelItems( string filename ) ;
+    bool initLevelDatas( string filename ) ;
+    bool initPlateItems( string filename ) ;
+    
+    //静态全局单例
+    static FillGlobalConfig* getInstance() ;
+    
+    vector<ContourConfig> _plateContours ;
+    vector<ContourConfig> _jewelContours ;
+    ContourData* getContourDataByPngName(string& pngname) ;
+    
+    //宝石基本信息
+    struct JewelItem {
+        int _id ;
+        string _category;
+        string _jewelName;
+        string _code1;
+        string _code2;
+        int _size ; // 0-SM 1-MD 2-LG
+        float _scale;// 0.0-1.0
+        string _pngName;
+        string _yzName;
+        string _contourName;
+        float _bbWidth;
+        float _bbHeight;
+        string _etc; //备注信息
+    };
+    JewelItem* getJewelItemById(int jid){ return  _mapJewelItems.find(jid)!=_mapJewelItems.end()?(&_mapJewelItems[jid]):nullptr; }
+    int getJewelItemCount() { return _mapJewelItems.size() ; }
+    
+    
+    //关卡组成数据
+    struct LevelData {
+        int _id ;
+        int _subId ;
+        int _difficulty;//难度 0-普通, 1-难 , 2-极难
+        vector<int> _jewelIds ;
+        vector<int>    _cnts ;//宝石个数,读取的时候要把组数乘以3计算出宝石个数。
+    } ;
+    //levelId 是关卡主编号值, subIndex是子关卡的索引值(从0开始)
+    LevelData* getLevelData(int levelId,int subIndex) { return (_mapLevelDatas.find(levelId)!=_mapLevelDatas.end())?(&_mapLevelDatas[levelId][subIndex]):nullptr; }
+    int        getSubLevelCount(int levelId) { return (_mapLevelDatas.find(levelId)!=_mapLevelDatas.end())?(_mapLevelDatas[levelId].size()):0; }
+    
+    //盘子基本信息
+    struct PlateItem {
+        int _id ;
+        string _name;
+        int    _size ;// 0-MINI 1-SM 2-MD 3-LG
+        string _pngName ;
+        string _contourName;
+        float _blx,_bly,_trx,_try ;// bl for bottom-left, tr for top-right.
+        int    _bigJewCap ;//大宝石容量
+        float _bbwid,_bbhei ;//精灵图片尺寸
+        string _etc ;
+    } ;
+    PlateItem* getPlateItemById(int pid){ return  _mapPlateItems.find(pid)!=_mapPlateItems.end()?(&_mapPlateItems[pid]):nullptr; }
+    int getPlateItemCount( int plateSzId ) { return (_mapPlateIdArray.find(plateSzId)!=_mapPlateIdArray.end())?(_mapPlateIdArray[plateSzId].size()):0; }
+    PlateItem* getPlateItemBySzNIndex(int plateSzId,int index){ return (_mapPlateIdArray.find(plateSzId)!=_mapPlateIdArray.end())?( getPlateItemById(_mapPlateIdArray[plateSzId][index])):nullptr; }
+    
+private:
+    static FillGlobalConfig* _s_instance ;
+    
+    unordered_map<int, JewelItem>          _mapJewelItems ;
+    unordered_map<int, vector<LevelData> >    _mapLevelDatas ;// key 为主关卡编号, vector<LevelData> 为子关卡数组
+    unordered_map<int, PlateItem>          _mapPlateItems ;
+    unordered_map<int, vector<int> >       _mapPlateIdArray;  // key为小、中、大的整数编码值, value为该类型下面的盘子ID数组
+    
+} ;
+
+
+#endif /* FillGlobalConfig_hpp */

+ 23 - 0
auto_fill_jewel_v3/FillResult.hpp

@@ -0,0 +1,23 @@
+//
+//  FillResult.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef FillResult_hpp
+#define FillResult_hpp
+
+#include <stdio.h>
+
+struct FillResult {
+    float _x,_y ;// 宝石位置相对盘子左下角(原点)的坐标,盘子内部坐标,注意盘子有效填充区域和盘子精灵尺寸的区别。
+                 // 这里盘子的坐标原点指的是盘子精灵图片尺寸的左下角坐标。
+    float _rotdeg ;//旋转角度,单位角度
+    int _jewelTypeId ;//宝石类型ID
+    float _width; //宝石外接宽度
+    float _height;//宝石外接高度
+    
+} ;
+
+#endif /* FillResult_hpp */

+ 513 - 0
auto_fill_jewel_v3/LevelGenerate.cpp

@@ -0,0 +1,513 @@
+//
+//  LevelGenerate.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "LevelGenerate.hpp"
+#include <iostream>
+#include <cassert>
+#include <unordered_map>
+#include "FillGlobalConfig.hpp"
+#include <tuple>
+#include "BoxPositionTool.hpp"
+
+using namespace std;
+
+bool LevelGenerate::generate( FillGlobalConfig::LevelData levelData,
+                             vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
+                             vector<ContourData::Point>& resultPlateCenterPointArr
+                             )
+{
+    resultPlateFillResults.clear() ;
+    resultPlateCenterPointArr.clear() ;
+    
+    auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
+    uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
+    
+    srand(_seed);
+    unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;
+    FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
+    int bigJewelCnt = 0 ;
+    int midJewelCnt = 0;
+    int smlJewelCnt = 0 ;
+    for(int ij = 0 ; ij < levelData._jewelIds.size();++ ij ) {
+        int jewId = levelData._jewelIds[ij] ;
+        int    cnt =  levelData._cnts[ij] ;
+        FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
+        jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
+        if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
+            smlJewelCnt+=cnt ;
+        }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
+            midJewelCnt += cnt ;
+        }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
+            bigJewelCnt += cnt ;
+        }
+    }
+    //每个盘子类型小号宝石承载量
+    //按顺序分别为大横,大竖,小。这里不考虑迷你。
+    FillGlobalConfig::PlateItem* bigPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
+    FillGlobalConfig::PlateItem* midPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
+    FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
+    vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlate,midPlate,smlPlate} ;
+    int maxSmlJewCapPerPlate = 0;
+    int minSmlJewCapPerPlate = 99999 ;
+    for(int ip=0;ip<usedPlates.size();++ip ) {
+        maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
+        minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
+    }
+    //等效小宝石数量
+    int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
+    cout<<"bigJewelCnt "<<bigJewelCnt<<endl;
+    cout<<"midJewelCnt "<<midJewelCnt<<endl;
+    cout<<"smlJewelCnt "<<smlJewelCnt<<endl;
+    cout<<"effSmallJewelsCount "<<effSmallJewelsCount<<endl;
+    
+    //构建符合难度条件的盘子和层数组合
+    vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts(levelData._difficulty,effSmallJewelsCount);
+    if( resPlateNLyrCnt.size()==0 ) {
+        cout<<"failed at generatePlateTypeAndLayerCnts"<<endl;
+        return false ;
+    }
+    
+    //计算盘子的最大层数
+    int maxLyrCnt = 0;
+    for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
+    
+    //对每个盘子组合进行填充宝石
+    RandomGridFiller filler ;
+    filler._seed = this->_seed ;
+    
+    //构建每个盘子每个层的填充结果容器
+    vector< tuple<int,int,vector<FillResult>> > plateIdLyrFillResultsArray ;// tuple<plateId, layerIndex, fillresults_array >
+    
+    
+    //从顶到底部,逐层进行填充
+    int residues = 0 ;
+    for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
+        cout<<"for layer "<<nlayer<<endl;
+        
+        //满足该层数的所有盘子ID
+        vector<int> plateIdArr ;
+        for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) if(it->_layerCnt>=nlayer) plateIdArr.push_back(it->_plateId) ;
+        
+        //该层总计需要填充多少小宝石
+        int currLyrNeedEquvSmlCnt = 0 ;
+        for(int ip=0;ip<plateIdArr.size();++ip ) {
+            currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
+        }
+        cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
+        
+        //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
+        float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
+        unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
+        int choseEqSmCnt=0;
+        for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
+            choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
+        }
+        cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
+        
+        //逐个盘子填充
+        for(auto itpid = plateIdArr.begin();itpid!=plateIdArr.end();++itpid) {
+            vector<FillResult> fr = fillPlateOneLayer(filler, *itpid, chosenJewIdNCnt) ;
+            tuple<int,int,vector<FillResult>> plateLyrFillResult={*itpid,nlayer,fr} ;
+            plateIdLyrFillResultsArray.push_back(plateLyrFillResult);
+        }
+        
+        //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
+        residues = 0 ;
+        for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
+            if( itjn->second>0 ) {
+                residues+=itjn->second;
+                std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
+            }
+        }
+        cout<<"layer chosen jewels residues "<<residues<<endl;
+    }
+    
+    //查看库存是否全部用掉了
+    if( residues>0 ) {
+        int extraPlateCnt = 0 ;
+        //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
+        unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
+        while( residueJewIdAndCnts.size()>0 ) {
+            //新建一个小盘子
+            extraPlateCnt++;
+            cout<<"add extra plate "<< extraPlateCnt <<endl;
+            int plateId = smlPlate->_id ;
+            for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
+                vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
+                plateIdLyrFillResultsArray.push_back( {plateId,ilyr,frs} );
+                cout<<"add extra lyr "<<endl;
+                if( residueJewIdAndCnts.size()==0 ) break ;
+            }
+            if( residueJewIdAndCnts.size()==0 ) break ;
+        }
+    }
+    
+    //整理数据
+    regroupPlateLyrFillResults(plateIdLyrFillResultsArray, resultPlateFillResults);
+    
+    //摆放盘子
+    {
+        vector<int> plateIdArr1;
+        for(auto itp = resultPlateFillResults.begin();itp!=resultPlateFillResults.end();++itp) plateIdArr1.push_back( std::get<0>(*itp) );
+        placePlates(plateIdArr1, resultPlateCenterPointArr) ;
+    }
+    
+    
+    auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
+    uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
+    cout<<"duration "<<ms11-ms00<<endl;
+    return true ;
+}
+
+vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts( const int difficulty,const int totEquvSmallJewelCnt)
+{
+    assert(difficulty>=0&&difficulty<=2) ;
+    vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;
+    vector<LevelGenerate::PlateIdAndLayerCnt> results ;
+    assert(totEquvSmallJewelCnt>0) ;
+    
+    FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
+    FillGlobalConfig::PlateItem* bigPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
+    FillGlobalConfig::PlateItem* midPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
+    FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
+    vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlate,midPlate,smlPlate} ;
+    
+    //一个关卡最多出现大、中、小盘子个数
+    const int PLATE_BG_MAX_CNT = 9  ;// 1个大盘子=2两个中盘子=6个小盘子
+    const int PLATE_MD_MAX_CNT = 18 ;
+    const int PLATE_SM_MAX_CNT = 54 ;
+    //每个关卡最大容纳等效小盘子的个数 就是54个
+    //                                                 普通               难              极难
+    vector< vector<float> > diffPlateCntPercent0 = { {0.3,0.3,0.0}, {0.2,0.4,0.0}, {0.1,0.5,0.0} } ;
+    vector< vector<float> > diffPlateCntPercent1 = { {0.7,0.7,0.0}, {0.6,0.8,0.1}, {0.5,0.9,0.1} } ;
+    
+    for(int ipbig = 1; ipbig <= PLATE_BG_MAX_CNT; ++ ipbig ) {
+        for(int ipmid = 1 ; ipmid <= PLATE_MD_MAX_CNT; ++ ipmid ) {
+            int effsmPlateCnt = ipbig*6 + ipmid*3 ;
+            if( effsmPlateCnt>PLATE_SM_MAX_CNT ) continue ;
+            for(int ipsml = 0 ; ipsml <= PLATE_SM_MAX_CNT; ++ ipsml ) {
+                //等效小盘子个数
+                effsmPlateCnt += ipsml  ;
+                if( effsmPlateCnt>PLATE_SM_MAX_CNT ) continue ;
+                
+                float bigPlateCntPercent = ipbig*6.0 / effsmPlateCnt ;
+                float midPlateCntPercent = ipmid*3.0 / effsmPlateCnt ;
+                float smlPlateCntPercent = ipsml*1.0 / effsmPlateCnt ;
+                vector<float> percentArr = {bigPlateCntPercent,midPlateCntPercent,smlPlateCntPercent} ;
+                
+                //判断每个盘子百分比是否满足难度要求
+                bool percentOk = true ;
+                for(int iplatetype=0;iplatetype<percentArr.size();++iplatetype) {
+                    if( diffPlateCntPercent0[difficulty][iplatetype]>percentArr[iplatetype] || diffPlateCntPercent1[difficulty][iplatetype]<percentArr[iplatetype]  )
+                        percentOk=false;
+                }
+                if(!percentOk) continue ;//盘子百分比不符合要求,跳过
+                
+                //计算每个类型的层数
+                if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
+                    //全部两层
+                    vector<int> pidArr ;
+                    vector<int> capArr ;
+                    vector<int> lyrArr ;
+                    for(int it=0;it<ipbig;++it) { pidArr.push_back(bigPlate->_id);capArr.push_back(bigPlate->_bigJewCap*4); lyrArr.push_back(2); }
+                    for(int it=0;it<ipmid;++it) { pidArr.push_back(midPlate->_id);capArr.push_back(midPlate->_bigJewCap*4); lyrArr.push_back(2); }
+                    for(int it=0;it<ipsml;++it) { pidArr.push_back(smlPlate->_id);capArr.push_back(smlPlate->_bigJewCap*4); lyrArr.push_back(2); }
+                    bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt) ;
+                    if(!lyrOk) continue;
+                    
+                    //保存结果
+                    vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
+                    for(int it = 0 ; it < capArr.size(); ++ it ) {
+                        tres[it]._plateId = pidArr[it] ;
+                        tres[it]._layerCnt = lyrArr[it] ;
+                    }
+                    possibleResults.push_back(tres) ;
+                    
+                }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
+                    //全部3层
+                    vector<int> pidArr ;
+                    vector<int> capArr ;
+                    vector<int> lyrArr ;
+                    for(int it=0;it<ipbig;++it) { pidArr.push_back(bigPlate->_id);capArr.push_back(bigPlate->_bigJewCap*4); lyrArr.push_back(3); }
+                    for(int it=0;it<ipmid;++it) { pidArr.push_back(midPlate->_id);capArr.push_back(midPlate->_bigJewCap*4); lyrArr.push_back(3); }
+                    for(int it=0;it<ipsml;++it) { pidArr.push_back(smlPlate->_id);capArr.push_back(smlPlate->_bigJewCap*4); lyrArr.push_back(3); }
+                    bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt) ;
+                    if(!lyrOk) continue;
+                    //保存结果
+                    vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
+                    for(int it = 0 ; it < capArr.size(); ++ it ) {
+                        tres[it]._plateId = pidArr[it] ;
+                        tres[it]._layerCnt = lyrArr[it] ;
+                    }
+                    possibleResults.push_back(tres) ;
+                }else{
+                    //50% 2层, 50% 3层
+                    vector<int> pidArr ;
+                    vector<int> capArr ;
+                    vector<int> lyrArr ;
+                    for(int it=0;it<ipbig;++it) { pidArr.push_back(bigPlate->_id);capArr.push_back(bigPlate->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
+                    for(int it=0;it<ipmid;++it) { pidArr.push_back(midPlate->_id);capArr.push_back(midPlate->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
+                    for(int it=0;it<ipsml;++it) { pidArr.push_back(smlPlate->_id);capArr.push_back(smlPlate->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
+                    bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt) ;
+                    if(!lyrOk) continue;
+                    //保存结果
+                    vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
+                    for(int it = 0 ; it < capArr.size(); ++ it ) {
+                        tres[it]._plateId = pidArr[it] ;
+                        tres[it]._layerCnt = lyrArr[it] ;
+                    }
+                    possibleResults.push_back(tres) ;
+                }
+            }
+        }
+    }
+    //debug 查看全部符合要求的结果
+    if( possibleResults.size()> 0 ) {
+        int randindex = rand() % possibleResults.size();
+        results = possibleResults[randindex] ;
+    }
+    return results ;
+}
+
+
+//随机排序数组索引值
+vector<int> LevelGenerate::randIndices(const int count0 ) {
+    int count = count0 ;
+    vector<int> indices ;
+    unordered_map<int, bool> dict ;
+    while( count > 0 ) {
+        int r = rand()%count0;
+        if( dict.find(r) == dict.end() ) {
+            dict[r] = true ;
+            indices.push_back(r) ;
+            count-- ;
+        }
+    }
+    return indices;
+}
+ 
+
+bool LevelGenerate::isJustFilledAll2(
+                      const vector<int>& plateCaps,//每个盘子的容量
+                      const vector<int> eachPlateLyrCnt,//对应盘子的层数
+                      const int totSmlJewCnt )
+{
+    assert(plateCaps.size()>0);
+    assert(plateCaps.size()==eachPlateLyrCnt.size());
+    int fillcnt1 = 0;
+    for(int ip = 0 ;ip<plateCaps.size();++ip ) {
+        fillcnt1 += plateCaps[ip] * eachPlateLyrCnt[ip] ;
+    }
+    if( fillcnt1 < totSmlJewCnt ) return false ;
+    if( fillcnt1 == totSmlJewCnt ) return true ;
+    for(int ip = 0 ; ip < plateCaps.size();++ip ) {
+        int fillcnt2 = fillcnt1 - plateCaps[ip] ;
+        if( fillcnt2 < totSmlJewCnt ) {
+            return true ;
+        }
+    }
+    return false ;
+}
+
+unordered_map<int, int> LevelGenerate::randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages )
+{
+    int needEquvSmlCnt2 = needEquvSmlCnt ;
+    int storageEquvSmlCnt = 0 ;
+    int storageJewTypeCnt = jewStorages.size() ;
+    for(auto it=jewStorages.begin();it!=jewStorages.end();++it) storageEquvSmlCnt+= std::get<1>(it->second)*jewSz2SmlCnt(std::get<0>(it->second)) ;
+    unordered_map<int, int> res ;
+    const float solPer = fmax(0.0,fmin(solvedPercent,1.0f)) ;
+    
+    //首先尝试可解的百分比部分
+    int solEqSmGrpCnt = needEquvSmlCnt*solPer/3 ;
+    // 随机尝试solEqSmGrpCnt*2 次取宝石,每次取一组。
+    int loopCnt=solEqSmGrpCnt*storageJewTypeCnt*10;//随机迭代数量加大10倍,避免有始终选不到的情况
+    while( solEqSmGrpCnt> 0 && storageEquvSmlCnt>0 && loopCnt>0) {
+        int randJewI = rand()%storageJewTypeCnt ;
+        auto itjew = jewStorages.begin() ;
+        std::advance(itjew, randJewI) ;
+        int jid = itjew->first ;
+        int storage1 = std::get<1>( itjew->second ) ;
+        int oneGrpEqSmGrpCnt = jewSz2SmlCnt( std::get<0>(itjew->second) ) ;
+        if( storage1>=3 && oneGrpEqSmGrpCnt<=solEqSmGrpCnt ) {
+            //库存有,且满足所需可解组数
+            std::get<1>(itjew->second)-=3 ;
+            solEqSmGrpCnt -= oneGrpEqSmGrpCnt ;
+            storageEquvSmlCnt -= oneGrpEqSmGrpCnt*3 ;
+            needEquvSmlCnt2   -= oneGrpEqSmGrpCnt*3 ; //本次所需的剩余等效小宝石个数
+            res[jid] += 3 ;
+        }
+        --loopCnt ;
+    }
+    
+    //尝试剩余百分比和上一步剩余没有符合条件的个数
+    loopCnt = needEquvSmlCnt2*storageJewTypeCnt ;
+    int jindex = 0 ;
+    while( loopCnt>0 && needEquvSmlCnt2> 0 && storageEquvSmlCnt>0 ) {
+        auto itjew = jewStorages.begin() ;
+        std::advance(itjew, jindex) ;
+        int jid = itjew->first;
+        int sz =  std::get<0>(itjew->second) ;
+        int stor = std::get<1>(itjew->second) ;
+        int eqsmCnt = jewSz2SmlCnt(sz) ;
+        if( stor>0 && eqsmCnt <= needEquvSmlCnt2 ) {
+            std::get<1>(itjew->second)-=1 ;
+            needEquvSmlCnt2-=eqsmCnt ;
+            storageEquvSmlCnt-=eqsmCnt ;
+            res[jid] += 1 ;
+        }
+        ++jindex ; if(jindex>=storageJewTypeCnt) jindex=0;//循环取之,直到本层所需全部取完
+        --loopCnt;
+    }
+    return res ;
+}
+
+int LevelGenerate::jewSz2SmlCnt(int sz)
+{
+    switch (sz) {
+        case FILLGLOBALCONFIG_JEWELSIZE_LG:
+            return 4;break;
+        case FILLGLOBALCONFIG_JEWELSIZE_MD:
+            return 2;break;
+        default:
+            return 1;break;
+    }
+    return 1;
+}
+
+vector<FillResult> LevelGenerate::fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse )
+{
+    auto fgc = FillGlobalConfig::getInstance() ;
+    vector<RandomGridFiller::JewelBox> jewBoxArray ;
+    FillGlobalConfig::PlateItem* pl = FillGlobalConfig::getInstance()->getPlateItemById(plateId) ;
+    int plateEqSmCap = pl->_bigJewCap*4 ;
+    int jewTypeCnt = jewStoragesForUse.size() ;
+    int eqSmStorageCnt = 0 ;
+    for(auto it = jewStoragesForUse.begin();it!=jewStoragesForUse.end();++it) {
+        int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
+        eqSmStorageCnt+=it->second*jewEqSmCnt ;
+    }
+    static int s_debug_cnt = 0;
+    cout<<"debug "<< s_debug_cnt << " storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
+    unordered_map<int, int> jewForPlateMap ;// <jewId,Cnt>
+    int loopCnt = plateEqSmCap*jewTypeCnt*4;// 随机数量多给4倍
+    while(plateEqSmCap>0 && eqSmStorageCnt>0 && loopCnt>0 ) {
+        int radv = rand() % jewTypeCnt ;
+        auto it = jewStoragesForUse.begin() ;
+        std::advance(it, radv) ;
+        int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
+        if( it->second>0 ) {
+            if( jewEqSmCnt <= plateEqSmCap ) {
+                plateEqSmCap -= jewEqSmCnt ;
+                it->second -=1 ;
+                eqSmStorageCnt -= jewEqSmCnt ;
+                jewForPlateMap[it->first] += 1 ;
+                if( it->second== 0 ) {
+                    jewStoragesForUse.erase(it) ;
+                    jewTypeCnt-- ;
+                }
+            }
+        }else{
+            jewStoragesForUse.erase(it) ;
+            jewTypeCnt-- ;
+        }
+        --loopCnt ;
+    }
+    
+    cout<<"debug "<< s_debug_cnt ++ <<" storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
+    
+    for(auto it = jewForPlateMap.begin();it!=jewForPlateMap.end();++it) {
+        RandomGridFiller::JewelBox jbox ;
+        jbox._cnt = it->second ;
+        jbox._jewelTypeId = it->first ;
+        jbox._width = fgc->getJewelItemById(it->first)->_bbWidth ;
+        jbox._height = fgc->getJewelItemById(it->first)->_bbHeight ;
+        jewBoxArray.push_back(jbox) ;
+    }
+    
+    vector<FillResult> fillresults ;
+    filler.fill(jewBoxArray, pl->_blx, pl->_bly, pl->_trx, pl->_try, fillresults) ;
+    return fillresults ;
+}
+
+
+unordered_map<int, int> LevelGenerate::findUnfilledInStorages( unordered_map<int,tuple<int,int>>& jewStorages)
+{
+    unordered_map<int, int> res ;
+    for(auto itj = jewStorages.begin();itj!=jewStorages.end();++itj) {
+        int stor = std::get<1>(itj->second) ;
+        int jid = itj->first ;
+        if( stor>0 ) {
+            res[jid] = stor ;
+            std::get<1>(itj->second) = 0 ;
+        }
+    }
+    return res ;
+}
+
+
+void LevelGenerate::regroupPlateLyrFillResults( vector<tuple<int,int,vector<FillResult>>>& pidlyrFillArray, vector<tuple<int,vector<vector<FillResult>>>>& results )
+{
+    int currLayer = 1 ;//从底层到顶层构建结果数据结构
+    int num = pidlyrFillArray.size() ;
+    int nloop = num ;
+    while( nloop > 0 ) {
+        cout<<"regroup for layer "<<currLayer<<endl;
+        for( auto itlyr = pidlyrFillArray.begin(); itlyr!=pidlyrFillArray.end(); ++ itlyr ) {
+            int pid = std::get<0>( *itlyr ) ;
+            int lyr = std::get<1>( *itlyr ) ;
+            vector<FillResult>& frs = std::get<2>(*itlyr) ;
+            if(pid>=0) {
+                if( lyr==currLayer ) {
+                    if( lyr==1 ) {
+                        vector<vector<FillResult>> frArr = {frs} ;
+                        results.push_back( {pid, frArr } ) ;
+                        num-- ;
+                        std::get<0>( *itlyr ) = -1 ;
+                    }else {
+                        for(auto itr = results.begin();itr!=results.end();++itr ) {
+                            int pidr = std::get<0>(*itr) ;
+                            vector<vector<FillResult>>& frArr = std::get<1>(*itr) ;
+                            if( pidr == pid && frArr.size()==currLayer-1 ) {
+                                frArr.push_back(frs);
+                                num-- ;
+                                std::get<0>( *itlyr ) = -1 ;
+                                break ;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        currLayer++ ;
+        if( num==0 ) break ;
+        nloop--;
+    }
+    cout<<"last plate lyr num "<<num<<endl;
+}
+
+
+
+void LevelGenerate::placePlates( const vector<int>& plateIdArr, vector<ContourData::Point>& resultPlateCenterPointArr )
+{
+    auto fgc = FillGlobalConfig::getInstance() ;
+    vector<vector<int>> plateSizeArr ;
+    for(int ip = 0 ; ip < plateIdArr.size();++ip ) {
+        FillGlobalConfig::PlateItem* plate1 = fgc->getPlateItemById(plateIdArr[ip]) ;
+        vector<int> sz = { (int)plate1->_bbwid, (int)plate1->_bbhei } ;
+        plateSizeArr.push_back(sz) ;
+    }
+    BoxPositionTool positionTool ;
+    vector<vector<int>> resPosis ;
+    const int GAME_REGION_WIDTH = 640 ;
+    const int GAME_REGION_HEIGHT = 720 ;
+    positionTool.solve(GAME_REGION_WIDTH,GAME_REGION_HEIGHT,plateSizeArr, resPosis) ;
+    for(int ip=0;ip<resPosis.size();++ip ) {
+        resultPlateCenterPointArr.push_back( { (float)resPosis[ip][0] , (float)resPosis[ip][1]} ) ;
+    }
+}
+

+ 82 - 0
auto_fill_jewel_v3/LevelGenerate.hpp

@@ -0,0 +1,82 @@
+//
+//  LevelGenerate.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef LevelGenerate_hpp
+#define LevelGenerate_hpp
+
+#include <stdio.h>
+#include <string>
+using std::string;
+#include "contourdata.h"
+#include "FillGlobalConfig.hpp"
+#include "FillResult.hpp"
+#include "RandomGridFiller.hpp"
+#include <tuple>
+using std::tuple;
+
+struct LevelGenerate {
+public:
+    //盘子ID和层数
+    struct PlateIdAndLayerCnt {
+        PlateIdAndLayerCnt():_plateId(-1),_layerCnt(0){}
+        int _plateId ;
+        int _layerCnt ;
+    } ;
+    
+public:
+    LevelGenerate():_seed(11231627){}
+    
+    void setSeed(int s) { _seed = s  ;}
+    int getSeed() { return _seed ; }
+    
+    //盘子和宝石的组合有解返回true,反之返回false
+    bool generate( FillGlobalConfig::LevelData levelData,
+                  vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
+                  vector<ContourData::Point>& resultPlateCenterPointArr
+                  ) ;
+    
+private:
+    int _seed ;
+    
+    //根据难度数据和宝石总数计算需要使用的每个盘子的个数
+    vector<PlateIdAndLayerCnt> generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt);
+   
+    
+    //判断一个组合是否恰恰装入宝石个数,规则是如果少一个盘就恰好装不下.
+    bool isJustFilledAll2(
+                          const vector<int>& plateCaps,//每个盘子的容量
+                          const vector<int> eachPlateLyrCnt,//对应盘子的层数
+                          const int totSmlJewCnt) ;
+    
+    
+    vector<int> randIndices(const int count0 ) ;
+    
+    /// 随机从库存中取出needEquvSmlCnt个等效小宝石,取出的宝石从库存减掉
+    /// @param needEquvSmlCnt 需要取出的等价小宝石数量
+    /// @param unsolvedPercent 取出宝石的不可解百分比
+    /// @param jewStorages 库存数据,取出数据要从库存减去,key:jewId value:tuple<Sz,Cnt>
+    /// @return 返回宝石ID和对应的数量
+    unordered_map<int, int> randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages ) ;
+    
+    /// 填充一个盘子,用掉的宝石从库存减掉
+    vector<FillResult> fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse ) ;
+    
+    /// 宝石尺寸转等效小宝石数量
+    int jewSz2SmlCnt(int sz) ;
+    
+    /// 查找库存剩余的宝石,返回 jewId,Cnt,并扣除库存数量
+    unordered_map<int, int> findUnfilledInStorages(unordered_map<int,tuple<int,int>>& jewStorages);
+    
+    /// 整理结果数据为 关卡-盘子-层-宝石的层次结构
+    void regroupPlateLyrFillResults( vector<tuple<int,int,vector<FillResult>>>& pidlyrFillArray, vector<tuple<int,vector<vector<FillResult>>>>& results ) ;
+    
+    /// 摆放盘子
+    void placePlates( const vector<int>& plateIdArr, vector<ContourData::Point>& resultPlateCenterPointArr ) ;
+    
+} ;
+
+#endif /* LevelGenerate_hpp */

+ 351 - 0
auto_fill_jewel_v3/RandomGridFiller.cpp

@@ -0,0 +1,351 @@
+//
+//  RandomGridFiller.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "RandomGridFiller.hpp"
+#include "BoostGeometryTools.hpp"
+#include <iostream>
+#include <algorithm>
+using std::cout;
+using std::endl;
+
+void RandomGridFiller::fill( vector<JewelBox>& jewelsArray ,    //需要填充的宝石
+          float bottomLeftX,float bottomLeftY,//盘子有效区域
+          float topRightX,float topRightY,    //盘子有效区域
+          vector<FillResult>& results         //填充结果
+          )
+{
+    srand(_seed) ;
+    results.clear() ;
+    
+    if( jewelsArray.size()==0 ) return ;
+    float width = topRightX - bottomLeftX + 1;
+    float height = topRightY - bottomLeftY+ 1;
+    
+    float minJewWid = jewelsArray[0]._width ;
+    float minJewHei = jewelsArray[0]._height;
+    for(auto it = jewelsArray.begin()+1;it!=jewelsArray.end();++it ) {
+        minJewWid = fmin( minJewWid, it->_width ) ;
+        minJewHei = fmin( minJewHei, it->_height) ;
+    }
+    float gridWid = width/20;
+    float gridHei = height/20;
+    
+    int nrows = width / gridWid ;
+    int ncols = height/ gridHei ;
+
+    vector<ContourData::Point> potPositions ;
+    for(int irow = 0 ; irow < nrows; ++ irow )
+    {
+        for(int icol=0;icol<ncols;++icol)
+        {
+            ContourData::Point cp ;
+            cp.x = (icol+0.5) * gridWid ;
+            cp.y = (irow+0.5) * gridHei ;
+            potPositions.push_back(cp) ;
+        }
+    }
+    
+    const int TRY_CNT=5 ;
+    bool chosen = false ;
+    int chosenTotCoverage = 9999999 ;
+    float chosenTotDist = 999999 ;
+    for(int itry = 0 ;itry < TRY_CNT; ++ itry ) {
+        vector<FillResult> fillResults ;
+        float jewDistSum=0;
+        int cov = 0 ;
+        int badcnt = randomFillOneRound(jewelsArray, bottomLeftX, bottomLeftY, topRightX, topRightY, potPositions, fillResults, jewDistSum,gridWid,gridHei,cov);
+        cout<<"itry-"<<itry<<" badcnt "<<badcnt<<" jewDistSum "<<jewDistSum<<" cov "<<cov <<endl;
+        if( chosen==false ) {
+            chosen = true ;
+            chosenTotCoverage = cov ;
+            chosenTotDist = jewDistSum ;
+            results = fillResults ;
+        }else{
+            if( cov < chosenTotCoverage ) {
+                chosenTotCoverage = cov ;
+                chosenTotDist = jewDistSum ;
+                results = fillResults ;
+            }else if( cov == chosenTotCoverage ) {
+                if( chosenTotDist < jewDistSum ) {
+                    chosenTotCoverage = cov ;
+                    chosenTotDist = jewDistSum ;
+                    results = fillResults ;
+                }
+            }
+        }
+    }
+}
+
+int RandomGridFiller::randomFillOneRound( vector<JewelBox>& jewelsArray,
+                        float bottomLeftX,float bottomLeftY,//盘子有效区域
+                        float topRightX,float topRightY,    //盘子有效区域
+                        vector<ContourData::Point> potPositions, //潜在的点位
+                        vector<FillResult>& results,
+                        float& jewDistanceSum
+                        ,const float gridWid
+                        ,const float gridHei
+                        ,int& resultTotCov
+                        )
+{
+    results.clear() ;
+    vector<int> jewIndices ;
+    for(int ij=0;ij<jewelsArray.size();++ij ) {
+        for(int ic=0 ; ic < jewelsArray[ij]._cnt ; ++ ic ) {
+            jewIndices.push_back(ij) ;
+        }
+    }
+    //需要填充的数量
+    int num2fill = jewIndices.size() ;
+    
+    //盘子的有效区域矩形边界
+    BoostGeometryTools::BoostPolygon plateBox = BoostGeometryTools::makeRotatedBox(bottomLeftX, bottomLeftY, (topRightX-bottomLeftX+1), (topRightY-bottomLeftY), 0);
+    
+    //点位从外到内
+    vector<DistancePosition> distPositions ;
+    generateDistanceRandomSlotPositions((topRightX-bottomLeftX)/2, (topRightY-bottomLeftY)/2, potPositions, distPositions) ;
+    
+    //使用网格描述盘子点位占用情况
+    const int GRID_X_NUM = (topRightX - bottomLeftX+1)/gridWid ;
+    const int GRID_Y_NUM = (topRightY - bottomLeftY+1)/gridHei ;
+    
+    //每个宝石分配一个占用格点数据,用于标记该宝石在盘子中的痕迹
+    vector< GridData > jewelGridDataArray(jewIndices.size()) ;
+    for(int ij=0;ij<jewIndices.size();++ij ) {
+        jewelGridDataArray[ij].reset(bottomLeftX+gridWid/2, bottomLeftY+gridHei/2, gridWid, gridHei, GRID_X_NUM, GRID_Y_NUM) ;
+    }
+    
+    //随机打散宝石顺序
+    vector<int> resultsJewIndices ;
+    vector<int> randIndicesOfJewIndices = randIndices(jewIndices.size()) ;
+    for(int ij = 0 ; ij < randIndicesOfJewIndices.size() ; ++ij ) {
+        int randJewIndex = randIndicesOfJewIndices[ij] ;
+        int jewTypeIndex = jewIndices[randIndicesOfJewIndices[ij]] ;
+        JewelBox& jewBox = jewelsArray[jewTypeIndex] ;
+        int rotdeg = rand()%360 ;
+        BoostGeometryTools::BoostPolygon jewPoly = BoostGeometryTools::makeRotatedBox(
+                                                                                      -jewBox._width/2,
+                                                                                      -jewBox._height/2,
+                                                                                      jewBox._width,
+                                                                                      jewBox._height ,
+                                                                                      rotdeg) ;
+        vector<FillResult> tempFillResults ;
+        vector<int> sumOfTakenCountArray ;//保留占位数求和
+        const int NUM_TRY = distPositions.size() ;//最大尝试数量
+        int itry = 0 ;//尝试数量
+        //将潜在点位按照距离盘子中心的距离进行排序,宝石按照这个距离进行填入盘子
+        vector<int> positionIndices ;
+        //逐个尝试,尝试NUM_TRY,保留占位数求和最少的。
+        for(int ip = 0 ; ip < distPositions.size();++ ip ) {
+            if( distPositions[ip]._isTaken ) continue ;//位置占用跳过
+            ContourData::Point posi = distPositions[ip]._point ;
+            BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jewPoly, posi.x, posi.y) ;
+            //是否落在盘子内部
+            bool isJewWithinPlate = BoostGeometryTools::isAWithinB(jpoly2, plateBox) ;
+            if( isJewWithinPlate ) {
+                itry ++ ;
+                FillResult fr ;
+                fr._jewelTypeId = jewBox._jewelTypeId ;
+                fr._rotdeg = rotdeg ;
+                fr._x = posi.x ;
+                fr._y = posi.y ;
+                fr._width = jewBox._width ;
+                fr._height = jewBox._height ;
+                tempFillResults.push_back(fr) ;
+                int tsum = totalCoverageGridCount(jpoly2, jewelGridDataArray) ;
+                //cout<<"ij-"<<ij<<" itry-"<<itry<<" tsum "<<tsum<<endl;
+                sumOfTakenCountArray.push_back(tsum) ;
+                positionIndices.push_back(ip); //positionIndices.push_back(ip) ;
+                if( itry == NUM_TRY ) break ;
+            }
+        }
+        
+        //保留占位数最少的。
+        if( tempFillResults.size()>0 ) {
+            FillResult fr = tempFillResults[0] ;
+            int tsum = sumOfTakenCountArray[0] ;
+            int posiIndex =positionIndices[0] ;
+            for(int itry = 1 ; itry < tempFillResults.size();++ itry ) {
+                if( tsum > sumOfTakenCountArray[itry]) {
+                    tsum = sumOfTakenCountArray[itry] ;
+                    fr = tempFillResults[itry] ;
+                    posiIndex =positionIndices[itry] ;
+                }
+            }
+            distPositions[posiIndex]._isTaken = true ;//记录位置已经占用
+            num2fill-- ;
+            BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jewPoly, fr._x, fr._y) ;
+            setGridCoverageByBox(jpoly2, jewelGridDataArray[randJewIndex]);//写入子网格数据
+            results.push_back(fr);//记录最优结果
+            resultsJewIndices.push_back(randJewIndex) ;
+            //debug
+            //cout<<"ij-"<<ij<<" pos "<<fr._x<<","<<fr._y<< " cov " << tsum <<endl;
+        }
+    }
+    
+    //重新计算覆盖度(这个看上去好像解决不了什么问题)后面可以删掉这部分代码
+    vector<int> coverageArray(results.size(),0 ) ;
+    resultTotCov = 0;
+    for(int ij = 0 ; ij < results.size();++ij ) {
+        FillResult& fr = results[ij] ;
+        int jewIndex = resultsJewIndices[ij] ;
+        BoostGeometryTools::BoostPolygon jpoly = BoostGeometryTools::makeRotatedBox(-fr._width/2,-fr._height/2,
+                                                                                    fr._width,fr._height ,
+                                                                                    fr._rotdeg) ;
+        BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jpoly, fr._x, fr._y) ;
+        coverageArray[jewIndex] = totalCoverageGridCount(jpoly2, jewelGridDataArray, jewIndex ) ;
+        //cout<<"ji-"<<jewIndex<<" cov "<<coverageArray[jewIndex]<<" x,y "<< fr._x<<","<<fr._y <<endl;
+        resultTotCov += coverageArray[jewIndex] ;
+    }
+    
+    //计算宝石间距离求和
+    jewDistanceSum = 0 ;
+    for(int ifr = 0 ; ifr < results.size();++ ifr ) {
+        for(int jfr = ifr+1; jfr < results.size();++jfr ) {
+            float dx = results[ifr]._x - results[jfr]._x ;
+            float dy = results[ifr]._y - results[jfr]._y ;
+            jewDistanceSum += sqrtf( dx*dx+dy*dy ) ;
+        }
+    }
+    
+    return num2fill ;
+}
+
+
+//随机排序数组索引值
+vector<int> RandomGridFiller::randIndices(const int count0 ) {
+    int count = count0 ;
+    vector<int> indices ;
+    unordered_map<int, bool> dict ;
+    while( count > 0 ) {
+        int r = rand()%count0;
+        if( dict.find(r) == dict.end() ) {
+            dict[r] = true ;
+            indices.push_back(r) ;
+            count-- ;
+        }
+    }
+    return indices;
+}
+
+
+int RandomGridFiller::sumOfSubGridTakenCounts(const int x,const int y,const int radius,
+                                             const float gridwid,const float gridhei,const vector<vector<int>>& rowColSubGrid)
+{
+    int sum = 0 ;
+    
+    int gridXNum = rowColSubGrid[0].size() ;
+    int gridYNum = rowColSubGrid.size() ;
+    
+    int centerGridX = x*1.0 / gridwid + 0.5 ;
+    int centerGridY = y*1.0 / gridhei + 0.5 ;
+    int gridRadiusX = radius/gridwid ;
+    int gridRadiusY = radius/gridhei ;
+    for( int igridy = -gridRadiusY; igridy <= gridRadiusY; ++ igridy ) {
+        for(int igridx = -gridRadiusX; igridx <= gridRadiusX; ++ igridx ) {
+            int gridx = centerGridX + igridx ;
+            int gridy = centerGridY + igridy ;
+            if( gridx>=0 && gridx < gridXNum && gridy>=0 && gridy < gridYNum ) {
+                sum += rowColSubGrid[gridy][gridx] ;
+            }
+        }
+    }
+    return sum ;
+}
+
+void RandomGridFiller::subGridTakenCountsAddOne(const int x,const int y,const int radius,
+                                               const float gridwid,const float gridhei,vector<vector<int>>& rowColSubGrid)
+{
+    int gridXNum = rowColSubGrid[0].size() ;
+    int gridYNum = rowColSubGrid.size() ;
+    
+    int centerGridX = x*1.0 / gridwid + 0.5 ;
+    int centerGridY = y*1.0 / gridhei + 0.5 ;
+    int gridRadiusX = radius/gridwid ;
+    int gridRadiusY = radius/gridhei ;
+    for( int igridy = -gridRadiusY; igridy <= gridRadiusY; ++ igridy ) {
+        for(int igridx = -gridRadiusX; igridx <= gridRadiusX; ++ igridx ) {
+            int gridx = centerGridX + igridx ;
+            int gridy = centerGridY + igridy ;
+            if( gridx>=0 && gridx < gridXNum && gridy>=0 && gridy < gridYNum ) {
+                rowColSubGrid[gridy][gridx]+=1 ;
+            }
+        }
+    }
+}
+
+
+//多边形盖住的格点数量
+int RandomGridFiller::coverageGridCount( BoostGeometryTools::BoostPolygon& box, const GridData& grid )
+{
+    int sum = 0 ;
+    int nrows = grid._rows.size();
+    int ncols = 0;
+    if( nrows>0 ) ncols = grid._rows[0].size();
+    for(int irow = 0 ; irow < grid._rows.size();++ irow ) {
+        for(int icol=0;icol<ncols;++icol ) {
+            
+            bool taken = grid._rows[irow][icol] ;
+            if( taken ) {
+                BoostGeometryTools::BoostPoint bp ;
+                float x = grid._bottomLeftX + icol * grid._stepX ;
+                float y = grid._bottomLeftY + irow * grid._stepY ;
+                bp.set<0>(x);
+                bp.set<1>(y) ;
+                sum += BoostGeometryTools::pointIntersetsBox(bp, box)?1:0 ;
+            }
+        }
+    }
+    return sum ;
+}
+
+int RandomGridFiller::totalCoverageGridCount(BoostGeometryTools::BoostPolygon& box, const vector<GridData>& grids ,int excludeIndex)
+{
+    int sum = 0 ;
+    for(int ij=0;ij<grids.size();++ij ) {
+        sum += (ij!=excludeIndex)?coverageGridCount(box, grids[ij]):0 ;
+    }
+    return sum ;
+}
+
+
+//将覆盖的格点数据赋值
+void RandomGridFiller::setGridCoverageByBox( BoostGeometryTools::BoostPolygon& box, GridData& grid )
+{
+    int nrows = grid._rows.size();
+    int ncols = 0;
+    if( nrows>0 ) ncols = grid._rows[0].size();
+    for(int irow = 0 ; irow < grid._rows.size();++ irow ) {
+        for(int icol=0;icol<ncols;++icol ) {
+            BoostGeometryTools::BoostPoint bp ;
+            float x = grid._bottomLeftX + icol * grid._stepX ;
+            float y = grid._bottomLeftY + irow * grid._stepY ;
+            bp.set<0>(x);
+            bp.set<1>(y) ;
+            grid._rows[irow][icol] = BoostGeometryTools::pointIntersetsBox(bp, box) ;
+        }
+    }
+}
+
+void RandomGridFiller::generateDistanceRandomSlotPositions(const float centerx,const float centery,const vector<ContourData::Point>& points, vector<RandomGridFiller::DistancePosition>& results )
+{
+    results.clear() ;
+    vector<int> randindices = randIndices( points.size() ) ;
+    for(int ir = 0 ; ir <randindices.size();++ir ) {
+        ContourData::Point pt = points[randindices[ir]] ;
+        float dx = pt.x - centerx ;
+        float dy = pt.y - centery ;
+        float dist = sqrtf(dx*dx + dy*dy) ;
+        DistancePosition dp ;
+        dp._distance = dist ;
+        dp._isTaken = false ;
+        dp._point = pt ;
+        results.push_back(dp) ;
+    }
+    //排序
+    std::sort(results.begin(), results.end(), [](DistancePosition& p1,DistancePosition& p2)->bool{return p1._distance>p2._distance; } );
+}
+

+ 96 - 0
auto_fill_jewel_v3/RandomGridFiller.hpp

@@ -0,0 +1,96 @@
+//
+//  RandomGridFiller.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef RandomGridFiller_hpp
+#define RandomGridFiller_hpp
+
+#include <vector>
+#include <stdio.h>
+#include "FillResult.hpp"
+#include "contourdata.h"
+#include <unordered_map>
+#include "BoostGeometryTools.hpp"
+
+using std::unordered_map;
+using std::vector;
+
+struct RandomGridFiller {
+    //输入数据的结构 宝石的外接矩形
+    struct JewelBox {
+        inline JewelBox():_cnt(0),_width(0),_height(0),_jewelTypeId(-1){}
+        int   _cnt ;//宝石个数
+        float _width; //外接矩形宽度(像素)
+        float _height ;//外接矩形高度(像素)
+        int   _jewelTypeId ;
+    } ;
+    int _seed ;
+    
+    //对外接口
+    void fill( vector<JewelBox>& jewelsArray ,    //需要填充的宝石
+              float bottomLeftX,float bottomLeftY,//盘子有效区域
+              float topRightX,float topRightY,    //盘子有效区域
+              vector<FillResult>& results         //尝试五组只选择一个覆盖度最小的填充结果
+              );
+    
+private:
+    //潜在的点位
+    struct DistancePosition {
+        bool _isTaken ;
+        float _distance ;
+        ContourData::Point _point ;
+    } ;
+    
+    //格点占用数据
+    struct GridData {
+        inline void reset(float blx,float bly,float sx,float sy,int nrows,int ncols){
+            _bottomLeftX = blx;
+            _bottomLeftY = bly;
+            _stepX = sx ;
+            _stepY = sy ;
+            _rows.resize(nrows);
+            for(auto it=_rows.begin();it!=_rows.end();++it)it->resize(ncols,false);
+        }
+        inline void clearValues(){for(auto it=_rows.begin();it!=_rows.end();++it)it->resize(it->size(),false); }
+        
+        vector< vector<bool> > _rows ;
+        float _bottomLeftX, _bottomLeftY ;//左下角原点坐标
+        float _stepX,_stepY ;//格点间隔
+    } ;
+    
+    // 返回未填进去的宝石数量,目前看没有填进去已经表示本次填充失败了
+    int randomFillOneRound( vector<JewelBox>& jewelsArray,
+                            float bottomLeftX,float bottomLeftY,//盘子有效区域
+                            float topRightX,float topRightY,    //盘子有效区域
+                            vector<ContourData::Point> potPositions, //潜在的点位
+                            vector<FillResult>& results,
+                            float& jewDistanceSum               //宝石间距离求和,用于衡量宝石间的分散程度
+                            ,const float gridWid                      //盘子子网格宽度
+                            ,const float gridhei                      //盘子子网格高度
+                           ,int& resultTotCov                         //返回全部宝石格点叠盖度之和
+                           ) ;
+    //随机排序索引值
+    vector<int> randIndices(const int count0 );
+    
+    //假定每个网格覆盖一次宝石其对应的int值加一,下面函数用于统计某个点位(x,y)(盘子内部坐标,与subGrid对齐)周边半径个网格覆盖值的求和。
+    //最优条件是求和值为0。虽然宝石一般使用矩形描述,这里为了将点坐标覆盖的一个区域换算到 subGrid 格子数方便,使用圆形进行计算。
+    [[deprecated]]
+    int sumOfSubGridTakenCounts(const int x,const int y,const int radius,const float gridwid,const float gridhei,const vector<vector<int>>& rowColSubGrid);
+    //为中心点位x,y,半径radius的覆盖范围的subgrid占用数加1。
+    [[deprecated]]
+    void subGridTakenCountsAddOne(const int x,const int y,const int radius,const float gridwid,const float gridhei,vector<vector<int>>& rowColSubGrid);
+    
+    //多边形盖住的格点数量
+    int coverageGridCount( BoostGeometryTools::BoostPolygon& box, const GridData& grid ) ;
+    //全部覆盖求和,excludeIndex 不做比较的索引值
+    int totalCoverageGridCount(BoostGeometryTools::BoostPolygon& box, const vector<GridData>& grids , int excludeIndex=-1 ) ;
+    //将覆盖的格点数据赋值
+    void setGridCoverageByBox( BoostGeometryTools::BoostPolygon& box, GridData& grid ) ;
+    //按距离从外到内构建随机点位
+    void generateDistanceRandomSlotPositions(const float centerx,const float centery,const vector<ContourData::Point>& points, vector<DistancePosition>& results ) ;
+} ;
+
+#endif /* RandomGridFiller_hpp */

+ 27 - 0
auto_fill_jewel_v3/SpriteData.hpp

@@ -0,0 +1,27 @@
+//
+//  SpriteData.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef SpriteData_hpp
+#define SpriteData_hpp
+
+#include <stdio.h>
+#include <string>
+using std::string;
+
+struct SpriteData {
+    SpriteData():_x(0),_y(0),_scaleX(0),_scaleY(0),_rotate(0),_csx(0),_csy(0){}
+    
+    int _x,_y;
+    string _name;
+    int _typeIndex ;
+    float _scaleX,_scaleY ;
+    float _rotate;
+    float _csx,_csy;//contour scale x,y
+};
+
+
+#endif /* SpriteData_hpp */

+ 3429 - 0
auto_fill_jewel_v3/ajson5.h

@@ -0,0 +1,3429 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+#ifdef __cplusplus
+
+#define ARDUINOJSON_VERSION "5.13.5"
+#define ARDUINOJSON_VERSION_MAJOR 5
+#define ARDUINOJSON_VERSION_MINOR 13
+#define ARDUINOJSON_VERSION_REVISION 5
+#include <stddef.h>  // for size_t
+#include <stdint.h>  // for uint8_t
+#include <string.h>
+namespace ArduinoJson {
+namespace Internals {
+class NonCopyable {
+ protected:
+  NonCopyable() {}
+ private:
+  NonCopyable(const NonCopyable&);
+  NonCopyable& operator=(const NonCopyable&);
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#ifndef ARDUINOJSON_EMBEDDED_MODE
+#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \
+    defined(__ARMCC_VERSION)
+#define ARDUINOJSON_EMBEDDED_MODE 1
+#else
+#define ARDUINOJSON_EMBEDDED_MODE 0
+#endif
+#endif
+#if ARDUINOJSON_EMBEDDED_MODE
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 0
+#endif
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#ifndef ARDUINOJSON_USE_INT64
+#define ARDUINOJSON_USE_INT64 0
+#endif
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 0
+#endif
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 0
+#endif
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
+#endif
+#else  // ARDUINOJSON_EMBEDDED_MODE
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 1
+#endif
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+#define ARDUINOJSON_USE_LONG_LONG 1
+#else
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#endif
+#ifndef ARDUINOJSON_USE_INT64
+#if defined(_MSC_VER) && _MSC_VER <= 1700
+#define ARDUINOJSON_USE_INT64 1
+#else
+#define ARDUINOJSON_USE_INT64 0
+#endif
+#endif
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 1
+#endif
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 1
+#endif
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
+#endif
+#endif  // ARDUINOJSON_EMBEDDED_MODE
+#ifdef ARDUINO
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
+#endif
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
+#endif
+#else  // ARDUINO
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
+#endif
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
+#endif
+#endif  // ARDUINO
+#ifndef ARDUINOJSON_ENABLE_PROGMEM
+#ifdef PROGMEM
+#define ARDUINOJSON_ENABLE_PROGMEM 1
+#else
+#define ARDUINOJSON_ENABLE_PROGMEM 0
+#endif
+#endif
+#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
+#ifdef ARDUINO_ARCH_AVR
+#define ARDUINOJSON_ENABLE_ALIGNMENT 0
+#else
+#define ARDUINOJSON_ENABLE_ALIGNMENT 1
+#endif
+#endif
+#ifndef ARDUINOJSON_ENABLE_DEPRECATED
+#define ARDUINOJSON_ENABLE_DEPRECATED 1
+#endif
+#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
+#endif
+#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
+#endif
+#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
+#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
+#endif
+namespace ArduinoJson {
+namespace Internals {
+#if ARDUINOJSON_USE_DOUBLE
+typedef double JsonFloat;
+#else
+typedef float JsonFloat;
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+#if ARDUINOJSON_USE_LONG_LONG
+typedef long long JsonInteger;
+typedef unsigned long long JsonUInt;
+#elif ARDUINOJSON_USE_INT64
+typedef __int64 JsonInteger;
+typedef unsigned _int64 JsonUInt;
+#else
+typedef long JsonInteger;
+typedef unsigned long JsonUInt;
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+namespace Internals {
+union JsonVariantContent {
+  JsonFloat asFloat;     // used for double and float
+  JsonUInt asInteger;    // used for bool, char, short, int and longs
+  const char* asString;  // asString can be null
+  JsonArray* asArray;    // asArray cannot be null
+  JsonObject* asObject;  // asObject cannot be null
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct JsonVariantDefault {
+  static T get() {
+    return T();
+  }
+};
+template <typename T>
+struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
+template <typename T>
+struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+namespace Internals {
+enum JsonVariantType {
+  JSON_UNDEFINED,         // JsonVariant has not been initialized
+  JSON_UNPARSED,          // JsonVariant contains an unparsed string
+  JSON_STRING,            // JsonVariant stores a const char*
+  JSON_BOOLEAN,           // JsonVariant stores a bool
+  JSON_POSITIVE_INTEGER,  // JsonVariant stores an JsonUInt
+  JSON_NEGATIVE_INTEGER,  // JsonVariant stores an JsonUInt that must be negated
+  JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArray
+  JSON_OBJECT,            // JsonVariant stores a pointer to a JsonObject
+  JSON_FLOAT              // JsonVariant stores a JsonFloat
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct JsonVariantAs {
+  typedef T type;
+};
+template <>
+struct JsonVariantAs<char*> {
+  typedef const char* type;
+};
+template <>
+struct JsonVariantAs<JsonArray> {
+  typedef JsonArray& type;
+};
+template <>
+struct JsonVariantAs<const JsonArray> {
+  typedef const JsonArray& type;
+};
+template <>
+struct JsonVariantAs<JsonObject> {
+  typedef JsonObject& type;
+};
+template <>
+struct JsonVariantAs<const JsonObject> {
+  typedef const JsonObject& type;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#ifdef _MSC_VER  // Visual Studio
+#define FORCE_INLINE  // __forceinline causes C4714 when returning std::string
+#define NO_INLINE __declspec(noinline)
+#define DEPRECATED(msg) __declspec(deprecated(msg))
+#elif defined(__GNUC__)  // GCC or Clang
+#define FORCE_INLINE __attribute__((always_inline))
+#define NO_INLINE __attribute__((noinline))
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define DEPRECATED(msg) __attribute__((deprecated(msg)))
+#else
+#define DEPRECATED(msg) __attribute__((deprecated))
+#endif
+#else  // Other compilers
+#define FORCE_INLINE
+#define NO_INLINE
+#define DEPRECATED(msg)
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename TImpl>
+class JsonVariantCasts {
+ public:
+#if ARDUINOJSON_ENABLE_DEPRECATED
+  DEPRECATED("use as<JsonArray>() instead")
+  FORCE_INLINE JsonArray &asArray() const {
+    return impl()->template as<JsonArray>();
+  }
+  DEPRECATED("use as<JsonObject>() instead")
+  FORCE_INLINE JsonObject &asObject() const {
+    return impl()->template as<JsonObject>();
+  }
+  DEPRECATED("use as<char*>() instead")
+  FORCE_INLINE const char *asString() const {
+    return impl()->template as<const char *>();
+  }
+#endif
+  FORCE_INLINE operator JsonArray &() const {
+    return impl()->template as<JsonArray &>();
+  }
+  FORCE_INLINE operator JsonObject &() const {
+    return impl()->template as<JsonObject &>();
+  }
+  template <typename T>
+  FORCE_INLINE operator T() const {
+    return impl()->template as<T>();
+  }
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <bool Condition, typename T = void>
+struct EnableIf {};
+template <typename T>
+struct EnableIf<true, T> {
+  typedef T type;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TBase, typename TDerived>
+class IsBaseOf {
+ protected:  // <- to avoid GCC's "all member functions in class are private"
+  typedef char Yes[1];
+  typedef char No[2];
+  static Yes &probe(const TBase *);
+  static No &probe(...);
+ public:
+  enum {
+    value = sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes)
+  };
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T, typename U>
+struct IsSame {
+  static const bool value = false;
+};
+template <typename T>
+struct IsSame<T, T> {
+  static const bool value = true;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsChar {
+  static const bool value = IsSame<T, char>::value ||
+                            IsSame<T, signed char>::value ||
+                            IsSame<T, unsigned char>::value;
+};
+template <typename T>
+struct IsChar<const T> : IsChar<T> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsConst {
+  static const bool value = false;
+};
+template <typename T>
+struct IsConst<const T> {
+  static const bool value = true;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct RemoveReference {
+  typedef T type;
+};
+template <typename T>
+struct RemoveReference<T&> {
+  typedef T type;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TString, typename Enable = void>
+struct StringTraits {
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+template <typename TString>
+struct StringTraits<const TString, void> : StringTraits<TString> {};
+template <typename TString>
+struct StringTraits<TString&, void> : StringTraits<TString> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#include <Stream.h>
+namespace ArduinoJson {
+namespace Internals {
+struct ArduinoStreamTraits {
+  class Reader {
+    Stream& _stream;
+    char _current, _next;
+   public:
+    Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {}
+    void move() {
+      _current = _next;
+      _next = 0;
+    }
+    char current() {
+      if (!_current) _current = read();
+      return _current;
+    }
+    char next() {
+      if (!_next) _next = read();
+      return _next;
+    }
+   private:
+    char read() {
+      char c = 0;
+      _stream.readBytes(&c, 1);
+      return c;
+    }
+  };
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+template <typename TStream>
+struct StringTraits<
+    TStream,
+    typename EnableIf<
+        IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type>
+    : ArduinoStreamTraits {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename TChar>
+struct CharPointerTraits {
+  class Reader {
+    const TChar* _ptr;
+   public:
+    Reader(const TChar* ptr)
+        : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
+    void move() {
+      ++_ptr;
+    }
+    char current() const {
+      return char(_ptr[0]);
+    }
+    char next() const {
+      return char(_ptr[1]);
+    }
+  };
+  static bool equals(const TChar* str, const char* expected) {
+    const char* actual = reinterpret_cast<const char*>(str);
+    if (!actual || !expected) return actual == expected;
+    return strcmp(actual, expected) == 0;
+  }
+  static bool is_null(const TChar* str) {
+    return !str;
+  }
+  typedef const char* duplicate_t;
+  template <typename Buffer>
+  static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
+    if (!str) return NULL;
+    size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy(dup, str, size);
+    return static_cast<duplicate_t>(dup);
+  }
+  static const bool has_append = false;
+  static const bool has_equals = true;
+  static const bool should_duplicate = !IsConst<TChar>::value;
+};
+template <typename TChar>
+struct StringTraits<TChar*, typename EnableIf<IsChar<TChar>::value>::type>
+    : CharPointerTraits<TChar> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#if ARDUINOJSON_ENABLE_PROGMEM
+namespace ArduinoJson {
+namespace Internals {
+template <>
+struct StringTraits<const __FlashStringHelper*, void> {
+  class Reader {
+    const char* _ptr;
+   public:
+    Reader(const __FlashStringHelper* ptr)
+        : _ptr(reinterpret_cast<const char*>(ptr)) {}
+    void move() {
+      _ptr++;
+    }
+    char current() const {
+      return pgm_read_byte_near(_ptr);
+    }
+    char next() const {
+      return pgm_read_byte_near(_ptr + 1);
+    }
+  };
+  static bool equals(const __FlashStringHelper* str, const char* expected) {
+    const char* actual = reinterpret_cast<const char*>(str);
+    if (!actual || !expected) return actual == expected;
+    return strcmp_P(expected, actual) == 0;
+  }
+  static bool is_null(const __FlashStringHelper* str) {
+    return !str;
+  }
+  typedef const char* duplicate_t;
+  template <typename Buffer>
+  static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
+    if (!str) return NULL;
+    size_t size = strlen_P((const char*)str) + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy_P(dup, (const char*)str, size);
+    return static_cast<duplicate_t>(dup);
+  }
+  static const bool has_append = false;
+  static const bool has_equals = true;
+  static const bool should_duplicate = true;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#endif
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#include <istream>
+namespace ArduinoJson {
+namespace Internals {
+struct StdStreamTraits {
+  class Reader {
+    std::istream& _stream;
+    char _current, _next;
+   public:
+    Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {}
+    void move() {
+      _current = _next;
+      _next = 0;
+    }
+    char current() {
+      if (!_current) _current = read();
+      return _current;
+    }
+    char next() {
+      if (!_next) _next = read();
+      return _next;
+    }
+   private:
+    Reader& operator=(const Reader&);  // Visual Studio C4512
+    char read() {
+      return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
+    }
+  };
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+template <typename TStream>
+struct StringTraits<
+    TStream,
+    typename EnableIf<IsBaseOf<
+        std::istream, typename RemoveReference<TStream>::type>::value>::type>
+    : StdStreamTraits {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#endif
+#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+#include <WString.h>
+#endif
+#if ARDUINOJSON_ENABLE_STD_STRING
+#include <string>
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename TString>
+struct StdStringTraits {
+  typedef const char* duplicate_t;
+  template <typename Buffer>
+  static duplicate_t duplicate(const TString& str, Buffer* buffer) {
+    if (!str.c_str()) return NULL;  // <- Arduino string can return NULL
+    size_t size = str.length() + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy(dup, str.c_str(), size);
+    return static_cast<duplicate_t>(dup);
+  }
+  static bool is_null(const TString& str) {
+    return !str.c_str();
+  }
+  struct Reader : CharPointerTraits<char>::Reader {
+    Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
+  };
+  static bool equals(const TString& str, const char* expected) {
+    const char* actual = str.c_str();
+    if (!actual || !expected) return actual == expected;
+    return 0 == strcmp(actual, expected);
+  }
+  static void append(TString& str, char c) {
+    str += c;
+  }
+  static void append(TString& str, const char* s) {
+    str += s;
+  }
+  static const bool has_append = true;
+  static const bool has_equals = true;
+  static const bool should_duplicate = true;
+};
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+template <>
+struct StringTraits<String, void> : StdStringTraits<String> {};
+template <>
+struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
+};
+#endif
+#if ARDUINOJSON_ENABLE_STD_STRING
+template <>
+struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+#endif
+namespace ArduinoJson {
+namespace Internals {
+class JsonVariantTag {};
+template <typename T>
+struct IsVariant : IsBaseOf<JsonVariantTag, T> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TImpl>
+class JsonVariantComparisons {
+ public:
+  template <typename TComparand>
+  friend bool operator==(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return variant.equals(comparand);
+  }
+  template <typename TComparand>
+  friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+  operator==(TComparand comparand, const JsonVariantComparisons &variant) {
+    return variant.equals(comparand);
+  }
+  template <typename TComparand>
+  friend bool operator!=(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return !variant.equals(comparand);
+  }
+  template <typename TComparand>
+  friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+  operator!=(TComparand comparand, const JsonVariantComparisons &variant) {
+    return !variant.equals(comparand);
+  }
+  template <typename TComparand>
+  friend bool operator<=(const JsonVariantComparisons &left, TComparand right) {
+    return left.as<TComparand>() <= right;
+  }
+  template <typename TComparand>
+  friend bool operator<=(TComparand comparand,
+                         const JsonVariantComparisons &variant) {
+    return comparand <= variant.as<TComparand>();
+  }
+  template <typename TComparand>
+  friend bool operator>=(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return variant.as<TComparand>() >= comparand;
+  }
+  template <typename TComparand>
+  friend bool operator>=(TComparand comparand,
+                         const JsonVariantComparisons &variant) {
+    return comparand >= variant.as<TComparand>();
+  }
+  template <typename TComparand>
+  friend bool operator<(const JsonVariantComparisons &varian,
+                        TComparand comparand) {
+    return varian.as<TComparand>() < comparand;
+  }
+  template <typename TComparand>
+  friend bool operator<(TComparand comparand,
+                        const JsonVariantComparisons &variant) {
+    return comparand < variant.as<TComparand>();
+  }
+  template <typename TComparand>
+  friend bool operator>(const JsonVariantComparisons &variant,
+                        TComparand comparand) {
+    return variant.as<TComparand>() > comparand;
+  }
+  template <typename TComparand>
+  friend bool operator>(TComparand comparand,
+                        const JsonVariantComparisons &variant) {
+    return comparand > variant.as<TComparand>();
+  }
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+  template <typename T>
+  const typename JsonVariantAs<T>::type as() const {
+    return impl()->template as<T>();
+  }
+  template <typename T>
+  bool is() const {
+    return impl()->template is<T>();
+  }
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_equals, bool>::type equals(
+      const TString &comparand) const {
+    const char *value = as<const char *>();
+    return StringTraits<TString>::equals(comparand, value);
+  }
+  template <typename TComparand>
+  typename EnableIf<!IsVariant<TComparand>::value &&
+                        !StringTraits<TComparand>::has_equals,
+                    bool>::type
+  equals(const TComparand &comparand) const {
+    return as<TComparand>() == comparand;
+  }
+  template <typename TVariant2>
+  bool equals(const JsonVariantComparisons<TVariant2> &right) const {
+    using namespace Internals;
+    if (is<bool>() && right.template is<bool>())
+      return as<bool>() == right.template as<bool>();
+    if (is<JsonInteger>() && right.template is<JsonInteger>())
+      return as<JsonInteger>() == right.template as<JsonInteger>();
+    if (is<JsonFloat>() && right.template is<JsonFloat>())
+      return as<JsonFloat>() == right.template as<JsonFloat>();
+    if (is<JsonArray>() && right.template is<JsonArray>())
+      return as<JsonArray>() == right.template as<JsonArray>();
+    if (is<JsonObject>() && right.template is<JsonObject>())
+      return as<JsonObject>() == right.template as<JsonObject>();
+    if (is<char *>() && right.template is<char *>())
+      return StringTraits<const char *>::equals(as<char *>(),
+                                                right.template as<char *>());
+    return false;
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsSignedIntegral {
+  static const bool value =
+      IsSame<T, signed char>::value || IsSame<T, signed short>::value ||
+      IsSame<T, signed int>::value || IsSame<T, signed long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+      IsSame<T, signed long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+      IsSame<T, signed __int64>::value ||
+#endif
+      false;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsUnsignedIntegral {
+  static const bool value =
+      IsSame<T, unsigned char>::value || IsSame<T, unsigned short>::value ||
+      IsSame<T, unsigned int>::value || IsSame<T, unsigned long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+      IsSame<T, unsigned long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+      IsSame<T, unsigned __int64>::value ||
+#endif
+      false;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsIntegral {
+  static const bool value = IsSignedIntegral<T>::value ||
+                            IsUnsignedIntegral<T>::value ||
+                            IsSame<T, char>::value;
+};
+template <typename T>
+struct IsIntegral<const T> : IsIntegral<T> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TImpl>
+class JsonVariantOr {
+ public:
+  template <typename T>
+  typename EnableIf<!IsIntegral<T>::value, T>::type operator|(
+      const T &defaultValue) const {
+    if (impl()->template is<T>())
+      return impl()->template as<T>();
+    else
+      return defaultValue;
+  }
+  const char *operator|(const char *defaultValue) const {
+    const char *value = impl()->template as<const char *>();
+    return value ? value : defaultValue;
+  }
+  template <typename Integer>
+  typename EnableIf<IsIntegral<Integer>::value, Integer>::type operator|(
+      const Integer &defaultValue) const {
+    if (impl()->template is<double>())
+      return impl()->template as<Integer>();
+    else
+      return defaultValue;
+  }
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+template <typename TImpl>
+class JsonVariantSubscripts {
+ public:
+  size_t size() const {
+    return impl()->template as<JsonArray>().size() +
+           impl()->template as<JsonObject>().size();
+  }
+  FORCE_INLINE const JsonArraySubscript operator[](size_t index) const;
+  FORCE_INLINE JsonArraySubscript operator[](size_t index);
+  template <typename TString>
+  FORCE_INLINE
+      typename EnableIf<StringTraits<TString>::has_equals,
+                        const JsonObjectSubscript<const TString &> >::type
+      operator[](const TString &key) const {
+    return impl()->template as<JsonObject>()[key];
+  }
+  template <typename TString>
+  FORCE_INLINE typename EnableIf<StringTraits<TString>::has_equals,
+                                 JsonObjectSubscript<const TString &> >::type
+  operator[](const TString &key) {
+    return impl()->template as<JsonObject>()[key];
+  }
+  template <typename TString>
+  FORCE_INLINE typename EnableIf<StringTraits<const TString *>::has_equals,
+                                 JsonObjectSubscript<const TString *> >::type
+  operator[](const TString *key) {
+    return impl()->template as<JsonObject>()[key];
+  }
+  template <typename TString>
+  FORCE_INLINE
+      typename EnableIf<StringTraits<TString *>::has_equals,
+                        const JsonObjectSubscript<const TString *> >::type
+      operator[](const TString *key) const {
+    return impl()->template as<JsonObject>()[key];
+  }
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class DummyPrint {
+ public:
+  size_t print(char) {
+    return 1;
+  }
+  size_t print(const char* s) {
+    return strlen(s);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TString>
+class DynamicStringBuilder {
+ public:
+  DynamicStringBuilder(TString &str) : _str(str) {}
+  size_t print(char c) {
+    StringTraits<TString>::append(_str, c);
+    return 1;
+  }
+  size_t print(const char *s) {
+    size_t initialLen = _str.length();
+    StringTraits<TString>::append(_str, s);
+    return _str.length() - initialLen;
+  }
+ private:
+  DynamicStringBuilder &operator=(const DynamicStringBuilder &);
+  TString &_str;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename Print>
+class IndentedPrint {
+ public:
+  explicit IndentedPrint(Print &p) : sink(&p) {
+    level = 0;
+    tabSize = 2;
+    isNewLine = true;
+  }
+  size_t print(char c) {
+    size_t n = 0;
+    if (isNewLine) n += writeTabs();
+    n += sink->print(c);
+    isNewLine = c == '\n';
+    return n;
+  }
+  size_t print(const char *s) {
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+  void indent() {
+    if (level < MAX_LEVEL) level++;
+  }
+  void unindent() {
+    if (level > 0) level--;
+  }
+  void setTabSize(uint8_t n) {
+    if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE;
+  }
+ private:
+  Print *sink;
+  uint8_t level : 4;
+  uint8_t tabSize : 3;
+  bool isNewLine : 1;
+  size_t writeTabs() {
+    size_t n = 0;
+    for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
+    return n;
+  }
+  static const int MAX_LEVEL = 15;    // because it's only 4 bits
+  static const int MAX_TAB_SIZE = 7;  // because it's only 3 bits
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class Encoding {
+ public:
+  static char escapeChar(char c) {
+    const char *p = escapeTable(false);
+    while (p[0] && p[1] != c) {
+      p += 2;
+    }
+    return p[0];
+  }
+  static char unescapeChar(char c) {
+    const char *p = escapeTable(true);
+    for (;;) {
+      if (p[0] == '\0') return c;
+      if (p[0] == c) return p[1];
+      p += 2;
+    }
+  }
+ private:
+  static const char *escapeTable(bool excludeIdenticals) {
+    return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0];
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+bool isNaN(T x) {
+  return x != x;
+}
+template <typename T>
+bool isInfinity(T x) {
+  return x != 0.0 && x * 2 == x;
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+#include <stdlib.h>  // for size_t
+namespace ArduinoJson {
+namespace Internals {
+template <typename T, typename F>
+struct alias_cast_t {
+  union {
+    F raw;
+    T data;
+  };
+};
+template <typename T, typename F>
+T alias_cast(F raw_data) {
+  alias_cast_t<T, F> ac;
+  ac.raw = raw_data;
+  return ac.data;
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T, size_t = sizeof(T)>
+struct FloatTraits {};
+template <typename T>
+struct FloatTraits<T, 8 /*64bits*/> {
+  typedef int64_t mantissa_type;
+  static const short mantissa_bits = 52;
+  static const mantissa_type mantissa_max =
+      (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+  typedef int16_t exponent_type;
+  static const exponent_type exponent_max = 308;
+  template <typename TExponent>
+  static T make_float(T m, TExponent e) {
+    if (e > 0) {
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= positiveBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    } else {
+      e = TExponent(-e);
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= negativeBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    }
+    return m;
+  }
+  static T positiveBinaryPowerOfTen(int index) {
+    static T factors[] = {
+        1e1,
+        1e2,
+        1e4,
+        1e8,
+        1e16,
+        forge(0x4693B8B5, 0xB5056E17),  // 1e32
+        forge(0x4D384F03, 0xE93FF9F5),  // 1e64
+        forge(0x5A827748, 0xF9301D32),  // 1e128
+        forge(0x75154FDD, 0x7F73BF3C)   // 1e256
+    };
+    return factors[index];
+  }
+  static T negativeBinaryPowerOfTen(int index) {
+    static T factors[] = {
+        forge(0x3FB99999, 0x9999999A),  // 1e-1
+        forge(0x3F847AE1, 0x47AE147B),  // 1e-2
+        forge(0x3F1A36E2, 0xEB1C432D),  // 1e-4
+        forge(0x3E45798E, 0xE2308C3A),  // 1e-8
+        forge(0x3C9CD2B2, 0x97D889BC),  // 1e-16
+        forge(0x3949F623, 0xD5A8A733),  // 1e-32
+        forge(0x32A50FFD, 0x44F4A73D),  // 1e-64
+        forge(0x255BBA08, 0xCF8C979D),  // 1e-128
+        forge(0x0AC80628, 0x64AC6F43)   // 1e-256
+    };
+    return factors[index];
+  }
+  static T negativeBinaryPowerOfTenPlusOne(int index) {
+    static T factors[] = {
+        1e0,
+        forge(0x3FB99999, 0x9999999A),  // 1e-1
+        forge(0x3F50624D, 0xD2F1A9FC),  // 1e-3
+        forge(0x3E7AD7F2, 0x9ABCAF48),  // 1e-7
+        forge(0x3CD203AF, 0x9EE75616),  // 1e-15
+        forge(0x398039D6, 0x65896880),  // 1e-31
+        forge(0x32DA53FC, 0x9631D10D),  // 1e-63
+        forge(0x25915445, 0x81B7DEC2),  // 1e-127
+        forge(0x0AFE07B2, 0x7DD78B14)   // 1e-255
+    };
+    return factors[index];
+  }
+  static T nan() {
+    return forge(0x7ff80000, 0x00000000);
+  }
+  static T inf() {
+    return forge(0x7ff00000, 0x00000000);
+  }
+  static T forge(uint32_t msb, uint32_t lsb) {
+    return alias_cast<T>((uint64_t(msb) << 32) | lsb);
+  }
+};
+template <typename T>
+struct FloatTraits<T, 4 /*32bits*/> {
+  typedef int32_t mantissa_type;
+  static const short mantissa_bits = 23;
+  static const mantissa_type mantissa_max =
+      (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+  typedef int8_t exponent_type;
+  static const exponent_type exponent_max = 38;
+  template <typename TExponent>
+  static T make_float(T m, TExponent e) {
+    if (e > 0) {
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= positiveBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    } else {
+      e = -e;
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= negativeBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    }
+    return m;
+  }
+  static T positiveBinaryPowerOfTen(int index) {
+    static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f};
+    return factors[index];
+  }
+  static T negativeBinaryPowerOfTen(int index) {
+    static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f};
+    return factors[index];
+  }
+  static T negativeBinaryPowerOfTenPlusOne(int index) {
+    static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f};
+    return factors[index];
+  }
+  static T forge(uint32_t bits) {
+    return alias_cast<T>(bits);
+  }
+  static T nan() {
+    return forge(0x7fc00000);
+  }
+  static T inf() {
+    return forge(0x7f800000);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TFloat>
+struct FloatParts {
+  uint32_t integral;
+  uint32_t decimal;
+  int16_t exponent;
+  int8_t decimalPlaces;
+  FloatParts(TFloat value) {
+    uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
+    decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
+    exponent = normalize(value);
+    integral = uint32_t(value);
+    for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
+      maxDecimalPart /= 10;
+      decimalPlaces--;
+    }
+    TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
+    decimal = uint32_t(remainder);
+    remainder = remainder - TFloat(decimal);
+    decimal += uint32_t(remainder * 2);
+    if (decimal >= maxDecimalPart) {
+      decimal = 0;
+      integral++;
+      if (exponent && integral >= 10) {
+        exponent++;
+        integral = 1;
+      }
+    }
+    while (decimal % 10 == 0 && decimalPlaces > 0) {
+      decimal /= 10;
+      decimalPlaces--;
+    }
+  }
+  static int16_t normalize(TFloat& value) {
+    typedef FloatTraits<TFloat> traits;
+    int16_t powersOf10 = 0;
+    int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
+    int bit = 1 << index;
+    if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
+      for (; index >= 0; index--) {
+        if (value >= traits::positiveBinaryPowerOfTen(index)) {
+          value *= traits::negativeBinaryPowerOfTen(index);
+          powersOf10 = int16_t(powersOf10 + bit);
+        }
+        bit >>= 1;
+      }
+    }
+    if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
+      for (; index >= 0; index--) {
+        if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) {
+          value *= traits::positiveBinaryPowerOfTen(index);
+          powersOf10 = int16_t(powersOf10 - bit);
+        }
+        bit >>= 1;
+      }
+    }
+    return powersOf10;
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename Print>
+class JsonWriter {
+ public:
+  explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
+  size_t bytesWritten() const {
+    return _length;
+  }
+  void beginArray() {
+    writeRaw('[');
+  }
+  void endArray() {
+    writeRaw(']');
+  }
+  void beginObject() {
+    writeRaw('{');
+  }
+  void endObject() {
+    writeRaw('}');
+  }
+  void writeColon() {
+    writeRaw(':');
+  }
+  void writeComma() {
+    writeRaw(',');
+  }
+  void writeBoolean(bool value) {
+    writeRaw(value ? "true" : "false");
+  }
+  void writeString(const char *value) {
+    if (!value) {
+      writeRaw("null");
+    } else {
+      writeRaw('\"');
+      while (*value) writeChar(*value++);
+      writeRaw('\"');
+    }
+  }
+  void writeChar(char c) {
+    char specialChar = Encoding::escapeChar(c);
+    if (specialChar) {
+      writeRaw('\\');
+      writeRaw(specialChar);
+    } else {
+      writeRaw(c);
+    }
+  }
+  template <typename TFloat>
+  void writeFloat(TFloat value) {
+    if (isNaN(value)) return writeRaw("NaN");
+    if (value < 0.0) {
+      writeRaw('-');
+      value = -value;
+    }
+    if (isInfinity(value)) return writeRaw("Infinity");
+    FloatParts<TFloat> parts(value);
+    writeInteger(parts.integral);
+    if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces);
+    if (parts.exponent < 0) {
+      writeRaw("e-");
+      writeInteger(-parts.exponent);
+    }
+    if (parts.exponent > 0) {
+      writeRaw('e');
+      writeInteger(parts.exponent);
+    }
+  }
+  template <typename UInt>
+  void writeInteger(UInt value) {
+    char buffer[22];
+    char *end = buffer + sizeof(buffer) - 1;
+    char *ptr = end;
+    *ptr = 0;
+    do {
+      *--ptr = char(value % 10 + '0');
+      value = UInt(value / 10);
+    } while (value);
+    writeRaw(ptr);
+  }
+  void writeDecimals(uint32_t value, int8_t width) {
+    char buffer[16];
+    char *ptr = buffer + sizeof(buffer) - 1;
+    *ptr = 0;
+    while (width--) {
+      *--ptr = char(value % 10 + '0');
+      value /= 10;
+    }
+    *--ptr = '.';
+    writeRaw(ptr);
+  }
+  void writeRaw(const char *s) {
+    _length += _sink.print(s);
+  }
+  void writeRaw(char c) {
+    _length += _sink.print(c);
+  }
+ protected:
+  Print &_sink;
+  size_t _length;
+ private:
+  JsonWriter &operator=(const JsonWriter &);  // cannot be assigned
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+class JsonVariant;
+namespace Internals {
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+template <typename Writer>
+class JsonSerializer {
+ public:
+  static void serialize(const JsonArray &, Writer &);
+  static void serialize(const JsonArraySubscript &, Writer &);
+  static void serialize(const JsonObject &, Writer &);
+  template <typename TKey>
+  static void serialize(const JsonObjectSubscript<TKey> &, Writer &);
+  static void serialize(const JsonVariant &, Writer &);
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename Print>
+class Prettyfier {
+ public:
+  explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
+    _previousChar = 0;
+    _inString = false;
+  }
+  size_t print(char c) {
+    size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
+    _previousChar = c;
+    return n;
+  }
+  size_t print(const char* s) {
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+ private:
+  Prettyfier& operator=(const Prettyfier&);  // cannot be assigned
+  bool inEmptyBlock() {
+    return _previousChar == '{' || _previousChar == '[';
+  }
+  size_t handleStringChar(char c) {
+    bool isQuote = c == '"' && _previousChar != '\\';
+    if (isQuote) _inString = false;
+    return _sink.print(c);
+  }
+  size_t handleMarkupChar(char c) {
+    switch (c) {
+      case '{':
+      case '[':
+        return writeBlockOpen(c);
+      case '}':
+      case ']':
+        return writeBlockClose(c);
+      case ':':
+        return writeColon();
+      case ',':
+        return writeComma();
+      case '"':
+        return writeQuoteOpen();
+      default:
+        return writeNormalChar(c);
+    }
+  }
+  size_t writeBlockClose(char c) {
+    size_t n = 0;
+    n += unindentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+  size_t writeBlockOpen(char c) {
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+  size_t writeColon() {
+    size_t n = 0;
+    n += _sink.print(": ");
+    return n;
+  }
+  size_t writeComma() {
+    size_t n = 0;
+    n += _sink.print(",\r\n");
+    return n;
+  }
+  size_t writeQuoteOpen() {
+    _inString = true;
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print('"');
+    return n;
+  }
+  size_t writeNormalChar(char c) {
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+  size_t indentIfNeeded() {
+    if (!inEmptyBlock()) return 0;
+    _sink.indent();
+    return _sink.print("\r\n");
+  }
+  size_t unindentIfNeeded() {
+    if (inEmptyBlock()) return 0;
+    _sink.unindent();
+    return _sink.print("\r\n");
+  }
+  char _previousChar;
+  IndentedPrint<Print>& _sink;
+  bool _inString;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class StaticStringBuilder {
+ public:
+  StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
+    *p = '\0';
+  }
+  size_t print(char c) {
+    if (p >= end) return 0;
+    *p++ = c;
+    *p = '\0';
+    return 1;
+  }
+  size_t print(const char *s) {
+    char *begin = p;
+    while (p < end && *s) *p++ = *s++;
+    *p = '\0';
+    return size_t(p - begin);
+  }
+ private:
+  char *end;
+  char *p;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#include <ostream>
+namespace ArduinoJson {
+namespace Internals {
+class StreamPrintAdapter {
+ public:
+  explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
+  size_t print(char c) {
+    _os << c;
+    return 1;
+  }
+  size_t print(const char* s) {
+    _os << s;
+    return strlen(s);
+  }
+ private:
+  StreamPrintAdapter& operator=(const StreamPrintAdapter&);
+  std::ostream& _os;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#endif  // ARDUINOJSON_ENABLE_STD_STREAM
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+class JsonPrintable {
+ public:
+  template <typename Print>
+  typename EnableIf<!StringTraits<Print>::has_append, size_t>::type printTo(
+      Print &print) const {
+    JsonWriter<Print> writer(print);
+    JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
+    return writer.bytesWritten();
+  }
+#if ARDUINOJSON_ENABLE_STD_STREAM
+  std::ostream &printTo(std::ostream &os) const {
+    StreamPrintAdapter adapter(os);
+    printTo(adapter);
+    return os;
+  }
+#endif
+  size_t printTo(char *buffer, size_t bufferSize) const {
+    StaticStringBuilder sb(buffer, bufferSize);
+    return printTo(sb);
+  }
+  template <size_t N>
+  size_t printTo(char (&buffer)[N]) const {
+    return printTo(buffer, N);
+  }
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_append, size_t>::type printTo(
+      TString &str) const {
+    DynamicStringBuilder<TString> sb(str);
+    return printTo(sb);
+  }
+  template <typename Print>
+  size_t prettyPrintTo(IndentedPrint<Print> &print) const {
+    Prettyfier<Print> p(print);
+    return printTo(p);
+  }
+  size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
+    StaticStringBuilder sb(buffer, bufferSize);
+    return prettyPrintTo(sb);
+  }
+  template <size_t N>
+  size_t prettyPrintTo(char (&buffer)[N]) const {
+    return prettyPrintTo(buffer, N);
+  }
+  template <typename Print>
+  typename EnableIf<!StringTraits<Print>::has_append, size_t>::type
+  prettyPrintTo(Print &print) const {
+    IndentedPrint<Print> indentedPrint(print);
+    return prettyPrintTo(indentedPrint);
+  }
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_append, size_t>::type
+  prettyPrintTo(TString &str) const {
+    DynamicStringBuilder<TString> sb(str);
+    return prettyPrintTo(sb);
+  }
+  size_t measureLength() const {
+    DummyPrint dp;
+    return printTo(dp);
+  }
+  size_t measurePrettyLength() const {
+    DummyPrint dp;
+    return prettyPrintTo(dp);
+  }
+ private:
+  const T &downcast() const {
+    return *static_cast<const T *>(this);
+  }
+};
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename T>
+inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
+  return v.printTo(os);
+}
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TImpl>
+class JsonVariantBase : public JsonPrintable<TImpl>,
+                        public JsonVariantCasts<TImpl>,
+                        public JsonVariantComparisons<TImpl>,
+                        public JsonVariantOr<TImpl>,
+                        public JsonVariantSubscripts<TImpl>,
+                        public JsonVariantTag {};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+class RawJsonString {
+ public:
+  explicit RawJsonString(T str) : _str(str) {}
+  operator T() const {
+    return _str;
+  }
+ private:
+  T _str;
+};
+template <typename String>
+struct StringTraits<RawJsonString<String>, void> {
+  static bool is_null(RawJsonString<String> source) {
+    return StringTraits<String>::is_null(static_cast<String>(source));
+  }
+  typedef RawJsonString<const char*> duplicate_t;
+  template <typename Buffer>
+  static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
+    return duplicate_t(StringTraits<String>::duplicate(source, buffer));
+  }
+  static const bool has_append = false;
+  static const bool has_equals = false;
+  static const bool should_duplicate = StringTraits<String>::should_duplicate;
+};
+}  // namespace Internals
+template <typename T>
+inline Internals::RawJsonString<T> RawJson(T str) {
+  return Internals::RawJsonString<T>(str);
+}
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsFloatingPoint {
+  static const bool value = IsSame<T, float>::value || IsSame<T, double>::value;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct RemoveConst {
+  typedef T type;
+};
+template <typename T>
+struct RemoveConst<const T> {
+  typedef T type;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
+  template <typename Print>
+  friend class Internals::JsonSerializer;
+ public:
+  JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
+  JsonVariant(bool value) {
+    using namespace Internals;
+    _type = JSON_BOOLEAN;
+    _content.asInteger = static_cast<JsonUInt>(value);
+  }
+  template <typename T>
+  JsonVariant(T value, typename Internals::EnableIf<
+                           Internals::IsFloatingPoint<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_FLOAT;
+    _content.asFloat = static_cast<JsonFloat>(value);
+  }
+  template <typename T>
+  DEPRECATED("Second argument is not supported anymore")
+  JsonVariant(T value, uint8_t,
+              typename Internals::EnableIf<
+                  Internals::IsFloatingPoint<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_FLOAT;
+    _content.asFloat = static_cast<JsonFloat>(value);
+  }
+  template <typename T>
+  JsonVariant(
+      T value,
+      typename Internals::EnableIf<Internals::IsSignedIntegral<T>::value ||
+                                   Internals::IsSame<T, char>::value>::type * =
+          0) {
+    using namespace Internals;
+    if (value >= 0) {
+      _type = JSON_POSITIVE_INTEGER;
+      _content.asInteger = static_cast<JsonUInt>(value);
+    } else {
+      _type = JSON_NEGATIVE_INTEGER;
+      _content.asInteger = static_cast<JsonUInt>(-value);
+    }
+  }
+  template <typename T>
+  JsonVariant(T value,
+              typename Internals::EnableIf<
+                  Internals::IsUnsignedIntegral<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_POSITIVE_INTEGER;
+    _content.asInteger = static_cast<JsonUInt>(value);
+  }
+  template <typename TChar>
+  JsonVariant(
+      const TChar *value,
+      typename Internals::EnableIf<Internals::IsChar<TChar>::value>::type * =
+          0) {
+    _type = Internals::JSON_STRING;
+    _content.asString = reinterpret_cast<const char *>(value);
+  }
+  JsonVariant(Internals::RawJsonString<const char *> value) {
+    _type = Internals::JSON_UNPARSED;
+    _content.asString = value;
+  }
+  JsonVariant(const JsonArray &array);
+  JsonVariant(const JsonObject &object);
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsIntegral<T>::value, T>::type
+  as() const {
+    return variantAsInteger<T>();
+  }
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsSame<T, bool>::value, T>::type
+  as() const {
+    return variantAsInteger<int>() != 0;
+  }
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value,
+                                     T>::type
+  as() const {
+    return variantAsFloat<T>();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+                                   Internals::IsSame<T, char *>::value,
+                               const char *>::type
+  as() const {
+    return variantAsString();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::StringTraits<T>::has_append, T>::type
+  as() const {
+    const char *cstr = variantAsString();
+    if (cstr) return T(cstr);
+    T s;
+    printTo(s);
+    return s;
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        JsonArray>::value,
+      JsonArray &>::type
+  as() const {
+    return variantAsArray();
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        const JsonArray>::value,
+      const JsonArray &>::type
+  as() const {
+    return variantAsArray();
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        JsonObject>::value,
+      JsonObject &>::type
+  as() const {
+    return variantAsObject();
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        const JsonObject>::value,
+      const JsonObject &>::type
+  as() const {
+    return variantAsObject();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, JsonVariant>::value,
+                               T>::type
+  as() const {
+    return *this;
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsIntegral<T>::value, bool>::type is()
+      const {
+    return variantIsInteger();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+  is() const {
+    return variantIsFloat();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, bool>::value, bool>::type
+  is() const {
+    return variantIsBoolean();
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+                                   Internals::IsSame<T, char *>::value ||
+                                   Internals::StringTraits<T>::has_append,
+                               bool>::type
+  is() const {
+    return variantIsString();
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveConst<
+                            typename Internals::RemoveReference<T>::type>::type,
+                        JsonArray>::value,
+      bool>::type
+  is() const {
+    return variantIsArray();
+  }
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveConst<
+                            typename Internals::RemoveReference<T>::type>::type,
+                        JsonObject>::value,
+      bool>::type
+  is() const {
+    return variantIsObject();
+  }
+  bool success() const {
+    return _type != Internals::JSON_UNDEFINED;
+  }
+ private:
+  JsonArray &variantAsArray() const;
+  JsonObject &variantAsObject() const;
+  const char *variantAsString() const;
+  template <typename T>
+  T variantAsFloat() const;
+  template <typename T>
+  T variantAsInteger() const;
+  bool variantIsBoolean() const;
+  bool variantIsFloat() const;
+  bool variantIsInteger() const;
+  bool variantIsArray() const {
+    return _type == Internals::JSON_ARRAY;
+  }
+  bool variantIsObject() const {
+    return _type == Internals::JSON_OBJECT;
+  }
+  bool variantIsString() const {
+    return _type == Internals::JSON_STRING ||
+           (_type == Internals::JSON_UNPARSED && _content.asString &&
+            !strcmp("null", _content.asString));
+  }
+  Internals::JsonVariantType _type;
+  Internals::JsonVariantContent _content;
+};
+DEPRECATED("Decimal places are ignored, use the float value instead")
+inline JsonVariant float_with_n_digits(float value, uint8_t) {
+  return JsonVariant(value);
+}
+DEPRECATED("Decimal places are ignored, use the double value instead")
+inline JsonVariant double_with_n_digits(double value, uint8_t) {
+  return JsonVariant(value);
+}
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct IsArray {
+  static const bool value = false;
+};
+template <typename T>
+struct IsArray<T[]> {
+  static const bool value = true;
+};
+template <typename T, size_t N>
+struct IsArray<T[N]> {
+  static const bool value = true;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+class JsonBuffer : Internals::NonCopyable {
+ public:
+  JsonArray &createArray();
+  JsonObject &createObject();
+  template <typename TString>
+  DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               const char *>::type strdup(const TString &src) {
+    return Internals::StringTraits<TString>::duplicate(src, this);
+  }
+  template <typename TString>
+  DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+  const char *strdup(TString *src) {
+    return Internals::StringTraits<TString *>::duplicate(src, this);
+  }
+  virtual void *alloc(size_t size) = 0;
+ protected:
+  ~JsonBuffer() {}
+  static FORCE_INLINE size_t round_size_up(size_t bytes) {
+#if ARDUINOJSON_ENABLE_ALIGNMENT
+    const size_t x = sizeof(void *) - 1;
+    return (bytes + x) & ~x;
+#else
+    return bytes;
+#endif
+  }
+};
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TChar>
+class StringWriter {
+ public:
+  class String {
+   public:
+    String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
+    void append(char c) {
+      *(*_writePtr)++ = TChar(c);
+    }
+    const char* c_str() const {
+      *(*_writePtr)++ = 0;
+      return reinterpret_cast<const char*>(_startPtr);
+    }
+   private:
+    TChar** _writePtr;
+    TChar* _startPtr;
+  };
+  StringWriter(TChar* buffer) : _ptr(buffer) {}
+  String startString() {
+    return String(&_ptr);
+  }
+ private:
+  TChar* _ptr;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TReader, typename TWriter>
+class JsonParser {
+ public:
+  JsonParser(JsonBuffer *buffer, TReader reader, TWriter writer,
+             uint8_t nestingLimit)
+      : _buffer(buffer),
+        _reader(reader),
+        _writer(writer),
+        _nestingLimit(nestingLimit) {}
+  JsonArray &parseArray();
+  JsonObject &parseObject();
+  JsonVariant parseVariant() {
+    JsonVariant result;
+    parseAnythingTo(&result);
+    return result;
+  }
+ private:
+  JsonParser &operator=(const JsonParser &);  // non-copiable
+  static bool eat(TReader &, char charToSkip);
+  FORCE_INLINE bool eat(char charToSkip) {
+    return eat(_reader, charToSkip);
+  }
+  const char *parseString();
+  bool parseAnythingTo(JsonVariant *destination);
+  inline bool parseArrayTo(JsonVariant *destination);
+  inline bool parseObjectTo(JsonVariant *destination);
+  inline bool parseStringTo(JsonVariant *destination);
+  static inline bool isBetween(char c, char min, char max) {
+    return min <= c && c <= max;
+  }
+  static inline bool canBeInNonQuotedString(char c) {
+    return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
+           isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
+  }
+  static inline bool isQuote(char c) {
+    return c == '\'' || c == '\"';
+  }
+  JsonBuffer *_buffer;
+  TReader _reader;
+  TWriter _writer;
+  uint8_t _nestingLimit;
+};
+template <typename TJsonBuffer, typename TString, typename Enable = void>
+struct JsonParserBuilder {
+  typedef typename StringTraits<TString>::Reader InputReader;
+  typedef JsonParser<InputReader, TJsonBuffer &> TParser;
+  static TParser makeParser(TJsonBuffer *buffer, TString &json,
+                            uint8_t nestingLimit) {
+    return TParser(buffer, InputReader(json), *buffer, nestingLimit);
+  }
+};
+template <typename TJsonBuffer, typename TChar>
+struct JsonParserBuilder<TJsonBuffer, TChar *,
+                         typename EnableIf<!IsConst<TChar>::value>::type> {
+  typedef typename StringTraits<TChar *>::Reader TReader;
+  typedef StringWriter<TChar> TWriter;
+  typedef JsonParser<TReader, TWriter> TParser;
+  static TParser makeParser(TJsonBuffer *buffer, TChar *json,
+                            uint8_t nestingLimit) {
+    return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
+  }
+};
+template <typename TJsonBuffer, typename TString>
+inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
+    TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {
+  return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json,
+                                                             nestingLimit);
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename TDerived>
+class JsonBufferBase : public JsonBuffer {
+ public:
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonArray &>::type
+  parseArray(const TString &json,
+             uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+  template <typename TString>
+  JsonArray &parseArray(
+      TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+  template <typename TString>
+  JsonArray &parseArray(
+      TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonObject &>::type
+  parseObject(const TString &json,
+              uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+  template <typename TString>
+  JsonObject &parseObject(
+      TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+  template <typename TString>
+  JsonObject &parseObject(
+      TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonVariant>::type
+  parse(const TString &json,
+        uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+  template <typename TString>
+  JsonVariant parse(TString *json,
+                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+  template <typename TString>
+  JsonVariant parse(TString &json,
+                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+ protected:
+  ~JsonBufferBase() {}
+ private:
+  TDerived *that() {
+    return static_cast<TDerived *>(this);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+namespace ArduinoJson {
+namespace Internals {
+class DefaultAllocator {
+ public:
+  void* allocate(size_t size) {
+    return malloc(size);
+  }
+  void deallocate(void* pointer) {
+    free(pointer);
+  }
+};
+template <typename TAllocator>
+class DynamicJsonBufferBase
+    : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > {
+  struct Block;
+  struct EmptyBlock {
+    Block* next;
+    size_t capacity;
+    size_t size;
+  };
+  struct Block : EmptyBlock {
+    uint8_t data[1];
+  };
+ public:
+  enum { EmptyBlockSize = sizeof(EmptyBlock) };
+  DynamicJsonBufferBase(size_t initialSize = 256)
+      : _head(NULL), _nextBlockCapacity(initialSize) {}
+  ~DynamicJsonBufferBase() {
+    clear();
+  }
+  size_t size() const {
+    size_t total = 0;
+    for (const Block* b = _head; b; b = b->next) total += b->size;
+    return total;
+  }
+  virtual void* alloc(size_t bytes) {
+    alignNextAlloc();
+    return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
+  }
+  void clear() {
+    Block* currentBlock = _head;
+    while (currentBlock != NULL) {
+      _nextBlockCapacity = currentBlock->capacity;
+      Block* nextBlock = currentBlock->next;
+      _allocator.deallocate(currentBlock);
+      currentBlock = nextBlock;
+    }
+    _head = 0;
+  }
+  class String {
+   public:
+    String(DynamicJsonBufferBase* parent)
+        : _parent(parent), _start(NULL), _length(0) {}
+    void append(char c) {
+      if (_parent->canAllocInHead(1)) {
+        char* end = static_cast<char*>(_parent->allocInHead(1));
+        *end = c;
+        if (_length == 0) _start = end;
+      } else {
+        char* newStart =
+            static_cast<char*>(_parent->allocInNewBlock(_length + 1));
+        if (_start && newStart) memcpy(newStart, _start, _length);
+        if (newStart) newStart[_length] = c;
+        _start = newStart;
+      }
+      _length++;
+    }
+    const char* c_str() {
+      append(0);
+      return _start;
+    }
+   private:
+    DynamicJsonBufferBase* _parent;
+    char* _start;
+    size_t _length;
+  };
+  String startString() {
+    return String(this);
+  }
+ private:
+  void alignNextAlloc() {
+    if (_head) _head->size = this->round_size_up(_head->size);
+  }
+  bool canAllocInHead(size_t bytes) const {
+    return _head != NULL && _head->size + bytes <= _head->capacity;
+  }
+  void* allocInHead(size_t bytes) {
+    void* p = _head->data + _head->size;
+    _head->size += bytes;
+    return p;
+  }
+  void* allocInNewBlock(size_t bytes) {
+    size_t capacity = _nextBlockCapacity;
+    if (bytes > capacity) capacity = bytes;
+    if (!addNewBlock(capacity)) return NULL;
+    _nextBlockCapacity *= 2;
+    return allocInHead(bytes);
+  }
+  bool addNewBlock(size_t capacity) {
+    size_t bytes = EmptyBlockSize + capacity;
+    Block* block = static_cast<Block*>(_allocator.allocate(bytes));
+    if (block == NULL) return false;
+    block->capacity = capacity;
+    block->size = 0;
+    block->next = _head;
+    _head = block;
+    return true;
+  }
+  TAllocator _allocator;
+  Block* _head;
+  size_t _nextBlockCapacity;
+};
+}  // namespace Internals
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
+typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator>
+    DynamicJsonBuffer;
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class JsonBufferAllocated {
+ public:
+  void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
+    if (!jsonBuffer) return NULL;
+    return jsonBuffer->alloc(n);
+  }
+  void operator delete(void *, JsonBuffer *)throw();
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+struct ListNode : public Internals::JsonBufferAllocated {
+  ListNode() throw() : next(NULL) {}
+  ListNode<T> *next;
+  T content;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+class ListConstIterator {
+ public:
+  explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
+  const T &operator*() const {
+    return _node->content;
+  }
+  const T *operator->() {
+    return &_node->content;
+  }
+  bool operator==(const ListConstIterator<T> &other) const {
+    return _node == other._node;
+  }
+  bool operator!=(const ListConstIterator<T> &other) const {
+    return _node != other._node;
+  }
+  ListConstIterator<T> &operator++() {
+    if (_node) _node = _node->next;
+    return *this;
+  }
+  ListConstIterator<T> &operator+=(size_t distance) {
+    while (_node && distance) {
+      _node = _node->next;
+      --distance;
+    }
+    return *this;
+  }
+ private:
+  const ListNode<T> *_node;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+class List;
+template <typename T>
+class ListIterator {
+  friend class List<T>;
+ public:
+  explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
+  T &operator*() const {
+    return _node->content;
+  }
+  T *operator->() {
+    return &_node->content;
+  }
+  bool operator==(const ListIterator<T> &other) const {
+    return _node == other._node;
+  }
+  bool operator!=(const ListIterator<T> &other) const {
+    return _node != other._node;
+  }
+  ListIterator<T> &operator++() {
+    if (_node) _node = _node->next;
+    return *this;
+  }
+  ListIterator<T> &operator+=(size_t distance) {
+    while (_node && distance) {
+      _node = _node->next;
+      --distance;
+    }
+    return *this;
+  }
+  operator ListConstIterator<T>() const {
+    return ListConstIterator<T>(_node);
+  }
+ private:
+  ListNode<T> *_node;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+class List {
+ public:
+  typedef T value_type;
+  typedef ListNode<T> node_type;
+  typedef ListIterator<T> iterator;
+  typedef ListConstIterator<T> const_iterator;
+  explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {}
+  bool success() const {
+    return _buffer != NULL;
+  }
+  size_t size() const {
+    size_t nodeCount = 0;
+    for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
+    return nodeCount;
+  }
+  iterator add() {
+    node_type *newNode = new (_buffer) node_type();
+    if (_firstNode) {
+      node_type *lastNode = _firstNode;
+      while (lastNode->next) lastNode = lastNode->next;
+      lastNode->next = newNode;
+    } else {
+      _firstNode = newNode;
+    }
+    return iterator(newNode);
+  }
+  iterator begin() {
+    return iterator(_firstNode);
+  }
+  iterator end() {
+    return iterator(NULL);
+  }
+  const_iterator begin() const {
+    return const_iterator(_firstNode);
+  }
+  const_iterator end() const {
+    return const_iterator(NULL);
+  }
+  void remove(iterator it) {
+    node_type *nodeToRemove = it._node;
+    if (!nodeToRemove) return;
+    if (nodeToRemove == _firstNode) {
+      _firstNode = nodeToRemove->next;
+    } else {
+      for (node_type *node = _firstNode; node; node = node->next)
+        if (node->next == nodeToRemove) node->next = nodeToRemove->next;
+    }
+  }
+ protected:
+  JsonBuffer *_buffer;
+ private:
+  node_type *_firstNode;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class ReferenceType {
+ public:
+  bool operator==(const ReferenceType& other) const {
+    return this == &other;
+  }
+  bool operator!=(const ReferenceType& other) const {
+    return this != &other;
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename Source, typename Enable = void>
+struct ValueSaver {
+  template <typename Destination>
+  static bool save(JsonBuffer*, Destination& destination, Source source) {
+    destination = source;
+    return true;
+  }
+};
+template <typename Source>
+struct ValueSaver<
+    Source, typename EnableIf<StringTraits<Source>::should_duplicate>::type> {
+  template <typename Destination>
+  static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
+    if (!StringTraits<Source>::is_null(source)) {
+      typename StringTraits<Source>::duplicate_t dup =
+          StringTraits<Source>::duplicate(source, buffer);
+      if (!dup) return false;
+      dest = dup;
+    } else {
+      dest = reinterpret_cast<const char*>(0);
+    }
+    return true;
+  }
+};
+template <typename Char>
+struct ValueSaver<
+    Char*, typename EnableIf<!StringTraits<Char*>::should_duplicate>::type> {
+  template <typename Destination>
+  static bool save(JsonBuffer*, Destination& dest, Char* source) {
+    dest = reinterpret_cast<const char*>(source);
+    return true;
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
+  (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type))
+namespace ArduinoJson {
+class JsonObject;
+class JsonBuffer;
+namespace Internals {
+class JsonArraySubscript;
+}
+class JsonArray : public Internals::JsonPrintable<JsonArray>,
+                  public Internals::ReferenceType,
+                  public Internals::NonCopyable,
+                  public Internals::List<JsonVariant>,
+                  public Internals::JsonBufferAllocated {
+ public:
+  explicit JsonArray(JsonBuffer *buffer) throw()
+      : Internals::List<JsonVariant>(buffer) {}
+  const Internals::JsonArraySubscript operator[](size_t index) const;
+  Internals::JsonArraySubscript operator[](size_t index);
+  template <typename T>
+  bool add(const T &value) {
+    return add_impl<const T &>(value);
+  }
+  template <typename T>
+  bool add(T *value) {
+    return add_impl<T *>(value);
+  }
+  template <typename T>
+  DEPRECATED("Second argument is not supported anymore")
+  bool add(T value, uint8_t) {
+    return add_impl<const JsonVariant &>(JsonVariant(value));
+  }
+  template <typename T>
+  bool set(size_t index, const T &value) {
+    return set_impl<const T &>(index, value);
+  }
+  template <typename T>
+  bool set(size_t index, T *value) {
+    return set_impl<T *>(index, value);
+  }
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+  set(size_t index, T value, uint8_t decimals) {
+    return set_impl<const JsonVariant &>(index, JsonVariant(value, decimals));
+  }
+  template <typename T>
+  typename Internals::JsonVariantAs<T>::type get(size_t index) const {
+    const_iterator it = begin() += index;
+    return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
+  }
+  template <typename T>
+  bool is(size_t index) const {
+    const_iterator it = begin() += index;
+    return it != end() ? it->is<T>() : false;
+  }
+  JsonArray &createNestedArray();
+  JsonObject &createNestedObject();
+  void remove(size_t index) {
+    remove(begin() += index);
+  }
+  using Internals::List<JsonVariant>::remove;
+  static JsonArray &invalid() {
+    static JsonArray instance(NULL);
+    return instance;
+  }
+  template <typename T, size_t N>
+  bool copyFrom(T (&array)[N]) {
+    return copyFrom(array, N);
+  }
+  template <typename T>
+  bool copyFrom(T *array, size_t len) {
+    bool ok = true;
+    for (size_t i = 0; i < len; i++) {
+      ok &= add(array[i]);
+    }
+    return ok;
+  }
+  template <typename T, size_t N1, size_t N2>
+  bool copyFrom(T (&array)[N1][N2]) {
+    bool ok = true;
+    for (size_t i = 0; i < N1; i++) {
+      JsonArray &nestedArray = createNestedArray();
+      for (size_t j = 0; j < N2; j++) {
+        ok &= nestedArray.add(array[i][j]);
+      }
+    }
+    return ok;
+  }
+  template <typename T, size_t N>
+  size_t copyTo(T (&array)[N]) const {
+    return copyTo(array, N);
+  }
+  template <typename T>
+  size_t copyTo(T *array, size_t len) const {
+    size_t i = 0;
+    for (const_iterator it = begin(); it != end() && i < len; ++it)
+      array[i++] = *it;
+    return i;
+  }
+  template <typename T, size_t N1, size_t N2>
+  void copyTo(T (&array)[N1][N2]) const {
+    size_t i = 0;
+    for (const_iterator it = begin(); it != end() && i < N1; ++it) {
+      it->as<JsonArray>().copyTo(array[i++]);
+    }
+  }
+#if ARDUINOJSON_ENABLE_DEPRECATED
+  DEPRECATED("use remove() instead")
+  FORCE_INLINE void removeAt(size_t index) {
+    return remove(index);
+  }
+#endif
+ private:
+  template <typename TValueRef>
+  bool set_impl(size_t index, TValueRef value) {
+    iterator it = begin() += index;
+    if (it == end()) return false;
+    return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+  }
+  template <typename TValueRef>
+  bool add_impl(TValueRef value) {
+    iterator it = Internals::List<JsonVariant>::add();
+    if (it == end()) return false;
+    return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+  }
+};
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonArray> {
+  static JsonArray &get() {
+    return JsonArray::invalid();
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+struct JsonPair {
+  const char* key;
+  JsonVariant value;
+};
+}  // namespace ArduinoJson
+#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
+  (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type))
+namespace ArduinoJson {
+class JsonArray;
+class JsonBuffer;
+namespace Internals {
+template <typename>
+class JsonObjectSubscript;
+}
+class JsonObject : public Internals::JsonPrintable<JsonObject>,
+                   public Internals::ReferenceType,
+                   public Internals::NonCopyable,
+                   public Internals::List<JsonPair>,
+                   public Internals::JsonBufferAllocated {
+ public:
+  explicit JsonObject(JsonBuffer* buffer) throw()
+      : Internals::List<JsonPair>(buffer) {}
+  template <typename TString>
+  Internals::JsonObjectSubscript<const TString&> operator[](
+      const TString& key) {
+    return Internals::JsonObjectSubscript<const TString&>(*this, key);
+  }
+  template <typename TString>
+  Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
+    return Internals::JsonObjectSubscript<TString*>(*this, key);
+  }
+  template <typename TString>
+  const Internals::JsonObjectSubscript<const TString&> operator[](
+      const TString& key) const {
+    return Internals::JsonObjectSubscript<const TString&>(
+        *const_cast<JsonObject*>(this), key);
+  }
+  template <typename TString>
+  const Internals::JsonObjectSubscript<TString*> operator[](
+      TString* key) const {
+    return Internals::JsonObjectSubscript<TString*>(
+        *const_cast<JsonObject*>(this), key);
+  }
+  template <typename TValue, typename TString>
+  bool set(const TString& key, const TValue& value) {
+    return set_impl<const TString&, const TValue&>(key, value);
+  }
+  template <typename TValue, typename TString>
+  bool set(const TString& key, TValue* value) {
+    return set_impl<const TString&, TValue*>(key, value);
+  }
+  template <typename TValue, typename TString>
+  bool set(TString* key, const TValue& value) {
+    return set_impl<TString*, const TValue&>(key, value);
+  }
+  template <typename TValue, typename TString>
+  bool set(TString* key, TValue* value) {
+    return set_impl<TString*, TValue*>(key, value);
+  }
+  template <typename TValue, typename TString>
+  DEPRECATED("Second argument is not supported anymore")
+  typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+                               bool>::type
+      set(const TString& key, TValue value, uint8_t) {
+    return set_impl<const TString&, const JsonVariant&>(key,
+                                                        JsonVariant(value));
+  }
+  template <typename TValue, typename TString>
+  DEPRECATED("Second argument is not supported anymore")
+  typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+                               bool>::type
+      set(TString* key, TValue value, uint8_t) {
+    return set_impl<TString*, const JsonVariant&>(key, JsonVariant(value));
+  }
+  template <typename TValue, typename TString>
+  typename Internals::JsonVariantAs<TValue>::type get(
+      const TString& key) const {
+    return get_impl<const TString&, TValue>(key);
+  }
+  template <typename TValue, typename TString>
+  typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
+    return get_impl<TString*, TValue>(key);
+  }
+  template <typename TValue, typename TString>
+  bool is(const TString& key) const {
+    return is_impl<const TString&, TValue>(key);
+  }
+  template <typename TValue, typename TString>
+  bool is(TString* key) const {
+    return is_impl<TString*, TValue>(key);
+  }
+  template <typename TString>
+  JsonArray& createNestedArray(const TString& key) {
+    return createNestedArray_impl<const TString&>(key);
+  }
+  template <typename TString>
+  JsonArray& createNestedArray(TString* key) {
+    return createNestedArray_impl<TString*>(key);
+  }
+  template <typename TString>
+  JsonObject& createNestedObject(const TString& key) {
+    return createNestedObject_impl<const TString&>(key);
+  }
+  template <typename TString>
+  JsonObject& createNestedObject(TString* key) {
+    return createNestedObject_impl<TString*>(key);
+  }
+  template <typename TString>
+  bool containsKey(const TString& key) const {
+    return findKey<const TString&>(key) != end();
+  }
+  template <typename TString>
+  bool containsKey(TString* key) const {
+    return findKey<TString*>(key) != end();
+  }
+  template <typename TString>
+  void remove(const TString& key) {
+    remove(findKey<const TString&>(key));
+  }
+  template <typename TString>
+  void remove(TString* key) {
+    remove(findKey<TString*>(key));
+  }
+  using Internals::List<JsonPair>::remove;
+  static JsonObject& invalid() {
+    static JsonObject instance(NULL);
+    return instance;
+  }
+ private:
+  template <typename TStringRef>
+  iterator findKey(TStringRef key) {
+    iterator it;
+    for (it = begin(); it != end(); ++it) {
+      if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
+    }
+    return it;
+  }
+  template <typename TStringRef>
+  const_iterator findKey(TStringRef key) const {
+    return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
+  }
+  template <typename TStringRef, typename TValue>
+  typename Internals::JsonVariantAs<TValue>::type get_impl(
+      TStringRef key) const {
+    const_iterator it = findKey<TStringRef>(key);
+    return it != end() ? it->value.as<TValue>()
+                       : Internals::JsonVariantDefault<TValue>::get();
+  }
+  template <typename TStringRef, typename TValueRef>
+  bool set_impl(TStringRef key, TValueRef value) {
+    if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
+    iterator it = findKey<TStringRef>(key);
+    if (it == end()) {
+      it = Internals::List<JsonPair>::add();
+      if (it == end()) return false;
+      bool key_ok =
+          Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
+      if (!key_ok) return false;
+    }
+    return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
+  }
+  template <typename TStringRef, typename TValue>
+  bool is_impl(TStringRef key) const {
+    const_iterator it = findKey<TStringRef>(key);
+    return it != end() ? it->value.is<TValue>() : false;
+  }
+  template <typename TStringRef>
+  JsonArray& createNestedArray_impl(TStringRef key);
+  template <typename TStringRef>
+  JsonObject& createNestedObject_impl(TStringRef key);
+};
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonObject> {
+  static JsonObject& get() {
+    return JsonObject::invalid();
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
+ public:
+  class String {
+   public:
+    String(StaticJsonBufferBase* parent) : _parent(parent) {
+      _start = parent->_buffer + parent->_size;
+    }
+    void append(char c) {
+      if (_parent->canAlloc(1)) {
+        char* last = static_cast<char*>(_parent->doAlloc(1));
+        *last = c;
+      }
+    }
+    const char* c_str() const {
+      if (_parent->canAlloc(1)) {
+        char* last = static_cast<char*>(_parent->doAlloc(1));
+        *last = '\0';
+        return _start;
+      } else {
+        return NULL;
+      }
+    }
+   private:
+    StaticJsonBufferBase* _parent;
+    char* _start;
+  };
+  StaticJsonBufferBase(char* buffer, size_t capa)
+      : _buffer(buffer), _capacity(capa), _size(0) {}
+  size_t capacity() const {
+    return _capacity;
+  }
+  size_t size() const {
+    return _size;
+  }
+  virtual void* alloc(size_t bytes) {
+    alignNextAlloc();
+    if (!canAlloc(bytes)) return NULL;
+    return doAlloc(bytes);
+  }
+  void clear() {
+    _size = 0;
+  }
+  String startString() {
+    return String(this);
+  }
+ protected:
+  ~StaticJsonBufferBase() {}
+ private:
+  void alignNextAlloc() {
+    _size = round_size_up(_size);
+  }
+  bool canAlloc(size_t bytes) const {
+    return _size + bytes <= _capacity;
+  }
+  void* doAlloc(size_t bytes) {
+    void* p = &_buffer[_size];
+    _size += bytes;
+    return p;
+  }
+  char* _buffer;
+  size_t _capacity;
+  size_t _size;
+};
+}  // namespace Internals
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+template <size_t CAPACITY>
+class StaticJsonBuffer : public Internals::StaticJsonBufferBase {
+ public:
+  explicit StaticJsonBuffer()
+      : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {}
+ private:
+  char _buffer[CAPACITY];
+};
+}  // namespace ArduinoJson
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename TInput>
+void skipSpacesAndComments(TInput& input) {
+  for (;;) {
+    switch (input.current()) {
+      case ' ':
+      case '\t':
+      case '\r':
+      case '\n':
+        input.move();
+        continue;
+      case '/':
+        switch (input.next()) {
+          case '*':
+            input.move();  // skip '/'
+            for (;;) {
+              input.move();
+              if (input.current() == '\0') return;
+              if (input.current() == '*' && input.next() == '/') {
+                input.move();  // skip '*'
+                input.move();  // skip '/'
+                break;
+              }
+            }
+            break;
+          case '/':
+            for (;;) {
+              input.move();
+              if (input.current() == '\0') return;
+              if (input.current() == '\n') break;
+            }
+            break;
+          default:
+            return;
+        }
+        break;
+      default:
+        return;
+    }
+  }
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
+    TReader &reader, char charToSkip) {
+  skipSpacesAndComments(reader);
+  if (reader.current() != charToSkip) return false;
+  reader.move();
+  return true;
+}
+template <typename TReader, typename TWriter>
+inline bool
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
+    JsonVariant *destination) {
+  skipSpacesAndComments(_reader);
+  switch (_reader.current()) {
+    case '[':
+      return parseArrayTo(destination);
+    case '{':
+      return parseObjectTo(destination);
+    default:
+      return parseStringTo(destination);
+  }
+}
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonArray &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() {
+  if (_nestingLimit == 0) return JsonArray::invalid();
+  _nestingLimit--;
+  JsonArray &array = _buffer->createArray();
+  if (!eat('[')) goto ERROR_MISSING_BRACKET;
+  if (eat(']')) goto SUCCESS_EMPTY_ARRAY;
+  for (;;) {
+    JsonVariant value;
+    if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+    if (!array.add(value)) goto ERROR_NO_MEMORY;
+    if (eat(']')) goto SUCCES_NON_EMPTY_ARRAY;
+    if (!eat(',')) goto ERROR_MISSING_COMMA;
+  }
+SUCCESS_EMPTY_ARRAY:
+SUCCES_NON_EMPTY_ARRAY:
+  _nestingLimit++;
+  return array;
+ERROR_INVALID_VALUE:
+ERROR_MISSING_BRACKET:
+ERROR_MISSING_COMMA:
+ERROR_NO_MEMORY:
+  return JsonArray::invalid();
+}
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo(
+    JsonVariant *destination) {
+  JsonArray &array = parseArray();
+  if (!array.success()) return false;
+  *destination = array;
+  return true;
+}
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonObject &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() {
+  if (_nestingLimit == 0) return JsonObject::invalid();
+  _nestingLimit--;
+  JsonObject &object = _buffer->createObject();
+  if (!eat('{')) goto ERROR_MISSING_BRACE;
+  if (eat('}')) goto SUCCESS_EMPTY_OBJECT;
+  for (;;) {
+    const char *key = parseString();
+    if (!key) goto ERROR_INVALID_KEY;
+    if (!eat(':')) goto ERROR_MISSING_COLON;
+    JsonVariant value;
+    if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+    if (!object.set(key, value)) goto ERROR_NO_MEMORY;
+    if (eat('}')) goto SUCCESS_NON_EMPTY_OBJECT;
+    if (!eat(',')) goto ERROR_MISSING_COMMA;
+  }
+SUCCESS_EMPTY_OBJECT:
+SUCCESS_NON_EMPTY_OBJECT:
+  _nestingLimit++;
+  return object;
+ERROR_INVALID_KEY:
+ERROR_INVALID_VALUE:
+ERROR_MISSING_BRACE:
+ERROR_MISSING_COLON:
+ERROR_MISSING_COMMA:
+ERROR_NO_MEMORY:
+  return JsonObject::invalid();
+}
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo(
+    JsonVariant *destination) {
+  JsonObject &object = parseObject();
+  if (!object.success()) return false;
+  *destination = object;
+  return true;
+}
+template <typename TReader, typename TWriter>
+inline const char *
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() {
+  typename RemoveReference<TWriter>::type::String str = _writer.startString();
+  skipSpacesAndComments(_reader);
+  char c = _reader.current();
+  if (isQuote(c)) {  // quotes
+    _reader.move();
+    char stopChar = c;
+    for (;;) {
+      c = _reader.current();
+      if (c == '\0') break;
+      _reader.move();
+      if (c == stopChar) break;
+      if (c == '\\') {
+        c = Encoding::unescapeChar(_reader.current());
+        if (c == '\0') break;
+        _reader.move();
+      }
+      str.append(c);
+    }
+  } else {  // no quotes
+    for (;;) {
+      if (!canBeInNonQuotedString(c)) break;
+      _reader.move();
+      str.append(c);
+      c = _reader.current();
+    }
+  }
+  return str.c_str();
+}
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseStringTo(
+    JsonVariant *destination) {
+  bool hasQuotes = isQuote(_reader.current());
+  const char *value = parseString();
+  if (value == NULL) return false;
+  if (hasQuotes) {
+    *destination = value;
+  } else {
+    *destination = RawJson(value);
+  }
+  return true;
+}
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+namespace ArduinoJson {
+namespace Internals {
+class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
+ public:
+  FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
+      : _array(array), _index(index) {}
+  FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
+    _array.set(_index, src);
+    return *this;
+  }
+  template <typename T>
+  FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
+    _array.set(_index, src);
+    return *this;
+  }
+  template <typename T>
+  FORCE_INLINE JsonArraySubscript& operator=(T* src) {
+    _array.set(_index, src);
+    return *this;
+  }
+  FORCE_INLINE bool success() const {
+    return _index < _array.size();
+  }
+  template <typename T>
+  FORCE_INLINE typename JsonVariantAs<T>::type as() const {
+    return _array.get<T>(_index);
+  }
+  template <typename T>
+  FORCE_INLINE bool is() const {
+    return _array.is<T>(_index);
+  }
+  template <typename TValue>
+  FORCE_INLINE bool set(const TValue& value) {
+    return _array.set(_index, value);
+  }
+  template <typename TValue>
+  FORCE_INLINE bool set(TValue* value) {
+    return _array.set(_index, value);
+  }
+  template <typename TValue>
+  DEPRECATED("Second argument is not supported anymore")
+  FORCE_INLINE bool set(const TValue& value, uint8_t) {
+    return _array.set(_index, value);
+  }
+ private:
+  JsonArray& _array;
+  const size_t _index;
+};
+template <typename TImpl>
+inline JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+    size_t index) {
+  return impl()->template as<JsonArray>()[index];
+}
+template <typename TImpl>
+inline const JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+    size_t index) const {
+  return impl()->template as<JsonArray>()[index];
+}
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream& operator<<(std::ostream& os,
+                                const JsonArraySubscript& source) {
+  return source.printTo(os);
+}
+#endif
+}  // namespace Internals
+inline Internals::JsonArraySubscript JsonArray::operator[](size_t index) {
+  return Internals::JsonArraySubscript(*this, index);
+}
+inline const Internals::JsonArraySubscript JsonArray::operator[](
+    size_t index) const {
+  return Internals::JsonArraySubscript(*const_cast<JsonArray*>(this), index);
+}
+}  // namespace ArduinoJson
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+namespace ArduinoJson {
+inline JsonArray &JsonArray::createNestedArray() {
+  if (!_buffer) return JsonArray::invalid();
+  JsonArray &array = _buffer->createArray();
+  add(array);
+  return array;
+}
+inline JsonObject &JsonArray::createNestedObject() {
+  if (!_buffer) return JsonObject::invalid();
+  JsonObject &object = _buffer->createObject();
+  add(object);
+  return object;
+}
+}  // namespace ArduinoJson
+inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
+  JsonArray *ptr = new (this) JsonArray(this);
+  return ptr ? *ptr : JsonArray::invalid();
+}
+inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() {
+  JsonObject *ptr = new (this) JsonObject(this);
+  return ptr ? *ptr : JsonObject::invalid();
+}
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+namespace ArduinoJson {
+namespace Internals {
+template <typename TStringRef>
+class JsonObjectSubscript
+    : public JsonVariantBase<JsonObjectSubscript<TStringRef> > {
+  typedef JsonObjectSubscript<TStringRef> this_type;
+ public:
+  FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key)
+      : _object(object), _key(key) {}
+  FORCE_INLINE this_type& operator=(const this_type& src) {
+    _object.set(_key, src);
+    return *this;
+  }
+  template <typename TValue>
+  FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, this_type&>::type
+  operator=(const TValue& src) {
+    _object.set(_key, src);
+    return *this;
+  }
+  template <typename TValue>
+  FORCE_INLINE this_type& operator=(TValue* src) {
+    _object.set(_key, src);
+    return *this;
+  }
+  FORCE_INLINE bool success() const {
+    return _object.containsKey(_key);
+  }
+  template <typename TValue>
+  FORCE_INLINE typename JsonVariantAs<TValue>::type as() const {
+    return _object.get<TValue>(_key);
+  }
+  template <typename TValue>
+  FORCE_INLINE bool is() const {
+    return _object.is<TValue>(_key);
+  }
+  template <typename TValue>
+  FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, bool>::type set(
+      const TValue& value) {
+    return _object.set(_key, value);
+  }
+  template <typename TValue>
+  FORCE_INLINE bool set(const TValue* value) {
+    return _object.set(_key, value);
+  }
+  template <typename TValue>
+  DEPRECATED("Second argument is not supported anymore")
+  FORCE_INLINE bool set(const TValue& value, uint8_t) {
+    return _object.set(_key, value);
+  }
+ private:
+  JsonObject& _object;
+  TStringRef _key;
+};
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename TStringRef>
+inline std::ostream& operator<<(std::ostream& os,
+                                const JsonObjectSubscript<TStringRef>& source) {
+  return source.printTo(os);
+}
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+namespace ArduinoJson {
+template <typename TStringRef>
+inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) {
+  if (!_buffer) return JsonArray::invalid();
+  JsonArray &array = _buffer->createArray();
+  set(key, array);
+  return array;
+}
+template <typename TStringRef>
+inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) {
+  if (!_buffer) return JsonObject::invalid();
+  JsonObject &object = _buffer->createObject();
+  set(key, object);
+  return object;
+}
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+inline bool isdigit(char c) {
+  return '0' <= c && c <= '9';
+}
+inline bool issign(char c) {
+  return '-' == c || c == '+';
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+inline bool isFloat(const char* s) {
+  if (!s) return false;
+  if (!strcmp(s, "NaN")) return true;
+  if (issign(*s)) s++;
+  if (!strcmp(s, "Infinity")) return true;
+  if (*s == '\0') return false;
+  while (isdigit(*s)) s++;
+  if (*s == '.') {
+    s++;
+    while (isdigit(*s)) s++;
+  }
+  if (*s == 'e' || *s == 'E') {
+    s++;
+    if (issign(*s)) s++;
+    if (!isdigit(*s)) return false;
+    while (isdigit(*s)) s++;
+  }
+  return *s == '\0';
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+inline bool isInteger(const char* s) {
+  if (!s || !*s) return false;
+  if (issign(*s)) s++;
+  while (isdigit(*s)) s++;
+  return *s == '\0';
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+inline T parseFloat(const char* s) {
+  typedef FloatTraits<T> traits;
+  typedef typename traits::mantissa_type mantissa_t;
+  typedef typename traits::exponent_type exponent_t;
+  if (!s) return 0;  // NULL
+  bool negative_result = false;
+  switch (*s) {
+    case '-':
+      negative_result = true;
+      s++;
+      break;
+    case '+':
+      s++;
+      break;
+  }
+  if (*s == 't') return 1;  // true
+  if (*s == 'n' || *s == 'N') return traits::nan();
+  if (*s == 'i' || *s == 'I')
+    return negative_result ? -traits::inf() : traits::inf();
+  mantissa_t mantissa = 0;
+  exponent_t exponent_offset = 0;
+  while (isdigit(*s)) {
+    if (mantissa < traits::mantissa_max / 10)
+      mantissa = mantissa * 10 + (*s - '0');
+    else
+      exponent_offset++;
+    s++;
+  }
+  if (*s == '.') {
+    s++;
+    while (isdigit(*s)) {
+      if (mantissa < traits::mantissa_max / 10) {
+        mantissa = mantissa * 10 + (*s - '0');
+        exponent_offset--;
+      }
+      s++;
+    }
+  }
+  int exponent = 0;
+  if (*s == 'e' || *s == 'E') {
+    s++;
+    bool negative_exponent = false;
+    if (*s == '-') {
+      negative_exponent = true;
+      s++;
+    } else if (*s == '+') {
+      s++;
+    }
+    while (isdigit(*s)) {
+      exponent = exponent * 10 + (*s - '0');
+      if (exponent + exponent_offset > traits::exponent_max) {
+        if (negative_exponent)
+          return negative_result ? -0.0f : 0.0f;
+        else
+          return negative_result ? -traits::inf() : traits::inf();
+      }
+      s++;
+    }
+    if (negative_exponent) exponent = -exponent;
+  }
+  exponent += exponent_offset;
+  T result = traits::make_float(static_cast<T>(mantissa), exponent);
+  return negative_result ? -result : result;
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+T parseInteger(const char *s) {
+  if (!s) return 0;  // NULL
+  if (*s == 't') return 1;  // "true"
+  T result = 0;
+  bool negative_result = false;
+  switch (*s) {
+    case '-':
+      negative_result = true;
+      s++;
+      break;
+    case '+':
+      s++;
+      break;
+  }
+  while (isdigit(*s)) {
+    result = T(result * 10 + T(*s - '0'));
+    s++;
+  }
+  return negative_result ? T(~result + 1) : result;
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
+namespace ArduinoJson {
+inline JsonVariant::JsonVariant(const JsonArray &array) {
+  if (array.success()) {
+    _type = Internals::JSON_ARRAY;
+    _content.asArray = const_cast<JsonArray *>(&array);
+  } else {
+    _type = Internals::JSON_UNDEFINED;
+    _content.asArray = 0;  // <- prevent warning 'maybe-uninitialized'
+  }
+}
+inline JsonVariant::JsonVariant(const JsonObject &object) {
+  if (object.success()) {
+    _type = Internals::JSON_OBJECT;
+    _content.asObject = const_cast<JsonObject *>(&object);
+  } else {
+    _type = Internals::JSON_UNDEFINED;
+    _content.asObject = 0;  // <- prevent warning 'maybe-uninitialized'
+  }
+}
+inline JsonArray &JsonVariant::variantAsArray() const {
+  if (_type == Internals::JSON_ARRAY) return *_content.asArray;
+  return JsonArray::invalid();
+}
+inline JsonObject &JsonVariant::variantAsObject() const {
+  if (_type == Internals::JSON_OBJECT) return *_content.asObject;
+  return JsonObject::invalid();
+}
+template <typename T>
+inline T JsonVariant::variantAsInteger() const {
+  using namespace Internals;
+  switch (_type) {
+    case JSON_UNDEFINED:
+      return 0;
+    case JSON_POSITIVE_INTEGER:
+    case JSON_BOOLEAN:
+      return T(_content.asInteger);
+    case JSON_NEGATIVE_INTEGER:
+      return T(~_content.asInteger + 1);
+    case JSON_STRING:
+    case JSON_UNPARSED:
+      return parseInteger<T>(_content.asString);
+    default:
+      return T(_content.asFloat);
+  }
+}
+inline const char *JsonVariant::variantAsString() const {
+  using namespace Internals;
+  if (_type == JSON_UNPARSED && _content.asString &&
+      !strcmp("null", _content.asString))
+    return NULL;
+  if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
+  return NULL;
+}
+template <typename T>
+inline T JsonVariant::variantAsFloat() const {
+  using namespace Internals;
+  switch (_type) {
+    case JSON_UNDEFINED:
+      return 0;
+    case JSON_POSITIVE_INTEGER:
+    case JSON_BOOLEAN:
+      return static_cast<T>(_content.asInteger);
+    case JSON_NEGATIVE_INTEGER:
+      return -static_cast<T>(_content.asInteger);
+    case JSON_STRING:
+    case JSON_UNPARSED:
+      return parseFloat<T>(_content.asString);
+    default:
+      return static_cast<T>(_content.asFloat);
+  }
+}
+inline bool JsonVariant::variantIsBoolean() const {
+  using namespace Internals;
+  if (_type == JSON_BOOLEAN) return true;
+  if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
+  return !strcmp(_content.asString, "true") ||
+         !strcmp(_content.asString, "false");
+}
+inline bool JsonVariant::variantIsInteger() const {
+  using namespace Internals;
+  return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
+         (_type == JSON_UNPARSED && isInteger(_content.asString));
+}
+inline bool JsonVariant::variantIsFloat() const {
+  using namespace Internals;
+  return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
+         _type == JSON_NEGATIVE_INTEGER ||
+         (_type == JSON_UNPARSED && isFloat(_content.asString));
+}
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
+  return source.printTo(os);
+}
+#endif
+}  // namespace ArduinoJson
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArray& array, Writer& writer) {
+  writer.beginArray();
+  JsonArray::const_iterator it = array.begin();
+  while (it != array.end()) {
+    serialize(*it, writer);
+    ++it;
+    if (it == array.end()) break;
+    writer.writeComma();
+  }
+  writer.endArray();
+}
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArraySubscript& arraySubscript, Writer& writer) {
+  serialize(arraySubscript.as<JsonVariant>(), writer);
+}
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObject& object, Writer& writer) {
+  writer.beginObject();
+  JsonObject::const_iterator it = object.begin();
+  while (it != object.end()) {
+    writer.writeString(it->key);
+    writer.writeColon();
+    serialize(it->value, writer);
+    ++it;
+    if (it == object.end()) break;
+    writer.writeComma();
+  }
+  writer.endObject();
+}
+template <typename Writer>
+template <typename TKey>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObjectSubscript<TKey>& objectSubscript, Writer& writer) {
+  serialize(objectSubscript.template as<JsonVariant>(), writer);
+}
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonVariant& variant, Writer& writer) {
+  switch (variant._type) {
+    case JSON_FLOAT:
+      writer.writeFloat(variant._content.asFloat);
+      return;
+    case JSON_ARRAY:
+      serialize(*variant._content.asArray, writer);
+      return;
+    case JSON_OBJECT:
+      serialize(*variant._content.asObject, writer);
+      return;
+    case JSON_STRING:
+      writer.writeString(variant._content.asString);
+      return;
+    case JSON_UNPARSED:
+      writer.writeRaw(variant._content.asString);
+      return;
+    case JSON_NEGATIVE_INTEGER:
+      writer.writeRaw('-');  // Falls through.
+    case JSON_POSITIVE_INTEGER:
+      writer.writeInteger(variant._content.asInteger);
+      return;
+    case JSON_BOOLEAN:
+      writer.writeBoolean(variant._content.asInteger != 0);
+      return;
+    default:  // JSON_UNDEFINED
+      return;
+  }
+}
+#ifdef __GNUC__
+#define ARDUINOJSON_PRAGMA(x) _Pragma(#x)
+#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg)
+#define ARDUINOJSON_STRINGIFY(S) #S
+#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \
+  ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 6 but version 5 is installed. Visit arduinojson.org to get more information.))
+#define StaticJsonDocument ARDUINOJSON_DEPRECATION_ERROR(StaticJsonDocument, class)
+#define DynamicJsonDocument ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonDocument, class)
+#define JsonDocument ARDUINOJSON_DEPRECATION_ERROR(JsonDocument, class)
+#define DeserializationError ARDUINOJSON_DEPRECATION_ERROR(DeserializationError, class)
+#define deserializeJson ARDUINOJSON_DEPRECATION_ERROR(deserializeJson, function)
+#define deserializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(deserializeMsgPack, function)
+#define serializeJson ARDUINOJSON_DEPRECATION_ERROR(serializeJson, function)
+#define serializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(serializeMsgPack, function)
+#define serializeJsonPretty ARDUINOJSON_DEPRECATION_ERROR(serializeJsonPretty, function)
+#define measureMsgPack ARDUINOJSON_DEPRECATION_ERROR(measureMsgPack, function)
+#define measureJson ARDUINOJSON_DEPRECATION_ERROR(measureJson, function)
+#define measureJsonPretty ARDUINOJSON_DEPRECATION_ERROR(measureJsonPretty, function)
+#endif
+
+using namespace ArduinoJson;
+
+#else
+
+#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp
+
+#endif

+ 102 - 0
auto_fill_jewel_v3/contourdata.cpp

@@ -0,0 +1,102 @@
+//
+//  contourdata.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "contourdata.h"
+#include <cmath>
+using namespace ArduinoJson;
+
+
+
+ContourData::ContourData() {}
+
+
+bool ContourData::readFromJsonFile(string jsonfilename)
+{
+    return readFromJsonFile(jsonfilename,1,1);
+}
+
+// 缩放和旋转是有顺序要求的,根据试验统一使用先旋转然后再缩放。
+bool ContourData::readFromJsonFile(string jsonfilename,float scalex,float scaley)
+{
+    _points.clear() ;
+    ifstream ifs( jsonfilename.c_str() ) ;
+    if( ifs.good()==false ) return false ;
+    DynamicJsonBuffer jsonBuffer ;
+    JsonArray& root = jsonBuffer.parse(ifs);
+    for(int ip = 0 ; ip < root.size(); ++ ip ) {
+        JsonArray& point = root[ip].as<JsonArray>() ;
+        Point pt ;
+        pt.x = point[0].as<float>()*scalex ;
+        pt.y = point[1].as<float>()*scaley ;
+        _points.push_back(pt) ;
+    }
+    return true ;
+}
+bool ContourData::readFromJsonFile(string jsonfilename,int translateX, int translateY, float scalex,float scaley)
+{
+    bool ok = readFromJsonFile(  jsonfilename,  scalex,  scaley) ;
+    for(auto it = _points.begin(); it!=_points.end(); ++ it ) {
+        it->x += translateX;
+        it->y += translateY;
+    }
+    return ok;
+}
+
+bool ContourData::getBoundingBox( float& xmin,float& ymin, float& xmax, float& ymax )
+{
+    if(_points.size()==0) return false ;
+    xmin = xmax = _points[0].x ;
+    ymin = ymax = _points[0].y ;
+    for(int i = 1 ; i<_points.size();++i ) {
+        xmin = std::min(xmin , _points[i].x) ;
+        xmax = std::max(xmax,_points[i].x) ;
+        ymin = std::min(ymin , _points[i].y) ;
+        ymax = std::max(ymax,_points[i].y) ;
+    }
+    return true ;
+}
+
+ContourData ContourData::copyAndScale(float scalex,float scaley)
+{
+    ContourData cd ;
+    cd._points = this->_points ;
+    for(auto it = cd._points.begin();it!=cd._points.end();++it ) {
+        it->x = it->x * scalex ;
+        it->y = it->y * scaley ;
+    }
+    return cd ;
+}
+
+void ContourData::rotate( float rotdeg )
+{
+    for(int i = 0 ; i<_points.size();++i ) {
+        _points[i] = rotateOnePoint( _points[i], rotdeg) ;
+    }
+}
+ContourData::Point ContourData::rotateOnePoint( ContourData::Point pt0, float rotateAng)
+{
+    const float DEG2RAD = 3.141592/180.0;
+    float rad = rotateAng*DEG2RAD;
+    float cosval = cosf(rad) ;
+    float sinval = sinf(rad) ;
+    ContourData::Point pt1 ;
+    pt1.x = pt0.x*cosval - pt0.y*sinval ;
+    pt1.y = pt0.x*sinval + pt0.y*cosval ;
+    return pt1 ;
+}
+
+
+void ContourData::togglePointOrder()
+{
+    int half = _points.size()/2 ;
+    int n = _points.size()-1 ;
+    for(int i = 0 ; i<half;++i ) {
+        Point pt = _points[i] ;
+        _points[i] = _points[n-i] ;
+        _points[n-i] = pt ;
+    }
+}

+ 48 - 0
auto_fill_jewel_v3/contourdata.h

@@ -0,0 +1,48 @@
+//
+//  contourdata.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef contourdata_hpp
+#define contourdata_hpp
+
+// 定义轮廓数据 by wf 2024-11-13
+#include "ajson5.h"
+#include <fstream>
+#include <vector>
+#include <string>
+using std::string;
+using std::vector;
+using std::ifstream;
+
+class ContourData
+{
+public:
+    struct Point {
+        float x,y;
+    };
+    ContourData();
+    //从json读取点数据
+    bool readFromJsonFile(string jsonfilename);
+    bool readFromJsonFile(string jsonfilename,float scalex,float scaley);
+    bool readFromJsonFile(string jsonfilename,int translateX, int translateY, float scalex,float scaley);
+    
+    //点数据
+    vector<Point> _points ;
+    //计算包围盒子
+    bool getBoundingBox( float& xmin,float& ymin, float& xmax, float& ymax ) ;
+    
+    //新建一个副本并进行缩放然后返回
+    ContourData copyAndScale(float scalex,float scaley) ;
+    //旋转轮廓多边形
+    void rotate( float rotdeg ) ;
+    //旋转一个点
+    Point rotateOnePoint( ContourData::Point pt0, float rotateAng);
+    //切换点序,顺时针逆时针
+    void togglePointOrder() ;
+
+};
+
+#endif /* contourdata_hpp */

+ 28 - 0
auto_fill_jewel_v3/contourdatatools.cpp

@@ -0,0 +1,28 @@
+//
+//  contourdatatools.cpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#include "contourdatatools.hpp"
+
+ContourData ContourDataTools::convex_hull(ContourData& cd)
+{
+    BoostGeometryTools::BoostPolygon poly ;
+    for(int i=0;i<cd._points.size();++i ) {
+        BoostGeometryTools::BoostPoint bpt ;
+        bpt.set<0>(cd._points[i].x) ;
+        bpt.set<1>(cd._points[i].y) ;
+        poly.outer().push_back( bpt ) ;
+    }
+    BoostGeometryTools::BoostPolygon hull = BoostGeometryTools::convex_hull(poly);
+    ContourData newCd ;
+    for(int i=0;i<hull.outer().size();++i ) {
+        ContourData::Point cpt ;
+        cpt.x = hull.outer()[i].get<0>() ;
+        cpt.y = hull.outer()[i].get<1>() ;
+        newCd._points.push_back( cpt );
+    }
+    return newCd ;
+}

+ 19 - 0
auto_fill_jewel_v3/contourdatatools.hpp

@@ -0,0 +1,19 @@
+//
+//  contourdatatools.hpp
+//  Test
+//
+//  Created by 高慕白 on 2024/12/3.
+//
+
+#ifndef contourdatatools_hpp
+#define contourdatatools_hpp
+
+#include <stdio.h>
+#include "contourdata.h"
+#include "BoostGeometryTools.hpp"
+
+struct ContourDataTools {
+    static ContourData convex_hull(ContourData& cd) ;
+};
+
+#endif /* contourdatatools_hpp */

+ 270 - 0
auto_fill_jewel_v3/main.cpp

@@ -0,0 +1,270 @@
+#include <iostream>
+#include <string>
+#include <vector>
+#include "SpriteData.hpp"
+#include "ajson5.h"
+#include "contourdata.h"
+
+#include "LevelGenerate.hpp"
+#include "FillGlobalConfig.hpp"
+#include "RandomGridFiller.hpp"
+#include "BoostGeometryTools.hpp"
+#include <opencv2/core.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <sstream>
+#include <ctime>
+#include <chrono>
+
+using namespace ArduinoJson;
+using namespace std;
+
+
+bool writeLevelJson(vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
+                    vector<ContourData::Point>& resultPlateCenterPointArr,
+                    string outfilename);
+
+int getGidByFileName(JsonArray *jTileSets, FillGlobalConfig::PlateItem* plate);
+
+int main(int argc, const char * argv[]) {
+    cout<<"A program to generate level. 2024-11-23"<<endl;
+    cout<<"usage:auto_fill_jewel_v3"<<endl;
+    cout<<"version v3.0"<<endl ;
+//    if( argc!=2 ) {
+//        cout<<"缺少参数"<<endl;
+//        return 11 ;
+//    }
+
+    string outname = "测试关卡100.json" ;
+
+    FillGlobalConfig::getInstance() ; //inited
+
+    vector<tuple<int,vector<vector<FillResult>>>> resultPlateFillResults;
+    vector<ContourData::Point> resultPlateCenterPointArr;
+
+    LevelGenerate genv3 ;
+    genv3.generate( *FillGlobalConfig::getInstance()->getLevelData(100, 0),
+                   resultPlateFillResults,
+                   resultPlateCenterPointArr
+                   ) ;
+
+    cout<<"write result to "<<outname<<endl;
+    writeLevelJson(resultPlateFillResults, resultPlateCenterPointArr, outname);
+
+
+//    string levelCsvfilename = argv[1] ;
+//    LevelInputConfig levelInputConfig ;
+//    bool isok = levelInputConfig.readFromCsv(levelCsvfilename) ;
+//    LevelGenerate genv3 ;
+//    genv3.generate(levelInputConfig) ;
+
+    if(false)
+    {//测试6个大的
+        const float BIG_JEW_WID = 80  ;
+        vector<RandomGridFiller::JewelBox> jewBoxArray ;
+        RandomGridFiller::JewelBox jb1,jb2 ;
+        jb1._cnt = 3  ;
+        jb1._height = BIG_JEW_WID ;
+        jb1._width = BIG_JEW_WID*0.67;
+        jb1._jewelTypeId = 1 ;
+
+        jb2._cnt = 3*2  ;
+        jb2._height = BIG_JEW_WID*0.75    ;
+        jb2._width = BIG_JEW_WID*0.75  ;
+        jb2._jewelTypeId = 2 ;
+        jewBoxArray.push_back(jb1) ;
+        jewBoxArray.push_back(jb2) ;
+
+        auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
+        uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
+
+        RandomGridFiller RBFiller ;
+        RBFiller._seed = 5 ;
+        vector< vector<FillResult> > results(1) ;
+        RBFiller.fill(jewBoxArray, 5, 14 , 200, 265, results[0] ) ;
+
+        auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
+        uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
+        cout<<"duration(ms) "<<ms11-ms00<<endl;
+
+        for(int ires = 0 ;ires < results.size();++ ires ) {
+            cv::Mat plateimage = cv::Mat::zeros( 270, 210, CV_8UC3 );
+            for(int ibox = 0 ; ibox < results[ires].size(); ++ ibox ) {
+                FillResult& fr = results[ires][ibox] ;
+                BoostGeometryTools::BoostPolygon poly1 = BoostGeometryTools::makeRotateNTranslateBox(-fr._width/2, -fr._height/2, fr._width, fr._height, results[ires][ibox]._rotdeg, results[ires][ibox]._x, results[ires][ibox]._y) ;
+                vector<cv::Point> cvpoints ;
+                for(int ipt = 0 ;ipt < poly1.outer().size();++ ipt ) {
+                    cv::Point p2 ;
+                    p2.x = poly1.outer()[ipt].get<0>();
+                    p2.y = poly1.outer()[ipt].get<1>() ;
+                    cvpoints.push_back(p2) ;
+                }
+                cv::polylines(plateimage, cvpoints, true, cv::Scalar(rand()%255,rand()%255,rand()%255));
+            }
+            //
+            stringstream ss ;
+            ss<<"win"<<ires ;
+            cv::imshow( ss.str().c_str() , plateimage );
+
+        }
+
+        cv::waitKey();
+
+    }
+
+    
+    
+    
+    return 0;
+}
+
+int getGidByFileName(JsonArray &jTileSets, FillGlobalConfig::PlateItem* plate) {
+    static int gid = 0;
+    for (int i = 0; i < jTileSets.size(); i++){
+        if (jTileSets[i]["image"] == plate->_pngName){
+            return static_cast<int>(jTileSets[i]["firstgid"]);
+        }
+    }
+    gid ++;
+    JsonObject& obj = jTileSets.createNestedObject();
+    obj["firstgid"] = gid;
+    obj["image"] = plate->_pngName;
+    obj["imageheight"] = plate->_bbhei;
+    obj["imagewidth"] = plate->_bbwid;
+    obj["margin"] = 0;
+    obj["name"] = plate->_name;
+    obj.createNestedObject("properties");
+    obj["spacing"] = 0;
+    obj["tileheight"] = plate->_bbhei;
+    obj["tilewidth"] = plate->_bbwid;
+    return gid;
+}
+
+bool writeLevelJson(vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
+                 vector<ContourData::Point>& resultPlateCenterPointArr,
+                 string outfilename)
+{
+    auto fgc = FillGlobalConfig::getInstance() ;
+    int totalJewelCnt = 0 ;
+    for(auto itp = resultPlateFillResults.begin();itp!=resultPlateFillResults.end();++itp) {
+        int plateId = std::get<0>( *itp ) ;
+        vector<vector<FillResult>>& frArr = std::get<1>( *itp );
+        for(auto itfr = frArr.begin(); itfr!=frArr.end();++itfr ) {
+            totalJewelCnt+=itfr->size() ;
+        }
+    }
+    DynamicJsonBuffer jsonBufferTiled;
+    DynamicJsonBuffer jsonBuffer;
+    
+    JsonObject& tiledRoot = jsonBufferTiled.createObject();
+    JsonObject& root = jsonBuffer.createObject();
+    
+    tiledRoot["height"] = 18;
+    
+    JsonArray& jLayerArr = tiledRoot.createNestedArray("layers");
+    JsonObject& lyrObj = jLayerArr.createNestedObject();
+    lyrObj["draworder"] = "topdown";
+    lyrObj["height"] = 18;
+    lyrObj["name"] = "Layer";
+    JsonArray& jObjArr = lyrObj.createNestedArray("objects"); //盘子信息
+    lyrObj["opacity"] = 1;
+    lyrObj["type"] = "objectgroup";
+    lyrObj["visible"] = true;
+    lyrObj["width"] = 16;
+    lyrObj["x"] = 0;
+    lyrObj["y"] = 0;
+    tiledRoot["nextobjectid"] = 4;
+    tiledRoot["orientation"] = "orthogonal";
+    tiledRoot.createNestedArray("properties");
+    tiledRoot["renderorder"] = "right-down";
+    tiledRoot["tileheight"] = 40;
+    JsonArray& jTileSets = tiledRoot.createNestedArray("tilesets"); //盘子纹理图
+    tiledRoot["tilewidth"] = 40;
+    tiledRoot["version"] = 1;
+    tiledRoot["width"] = 16;
+    
+    root.createNestedObject("target");//not used.
+    root["bgtem"] = "no"; //背景redream文件
+    root["jewel_count"] = totalJewelCnt ;
+    JsonArray& jplatesArr = root.createNestedArray("plates");
+    int ids = 1;
+    for (int i = 0; i < resultPlateFillResults.size(); i ++){
+        auto itp = resultPlateFillResults.begin() ;
+        std::advance(itp, i) ;
+        int plateId = std::get<0>( *itp ) ;
+        
+        JsonObject& tiledPlateObj = jObjArr.createNestedObject();
+        tiledPlateObj["gid"] = getGidByFileName(jTileSets, fgc->getPlateItemById(plateId));
+        tiledPlateObj["height"] = 0;
+        tiledPlateObj["id"] = ids;
+        tiledPlateObj["name"] = "plate";
+        tiledPlateObj.createNestedObject("properties");
+        tiledPlateObj["rotation"] = 0;
+        tiledPlateObj["type"] = "";
+        tiledPlateObj["visible"] = true;
+        tiledPlateObj["width"] = 0;
+        float platex = resultPlateCenterPointArr[i].x;
+        float platey = resultPlateCenterPointArr[i].y;
+        tiledPlateObj["x"] = platex - fgc->getPlateItemById(plateId)->_bbwid / 2;
+        tiledPlateObj["y"] = platey - fgc->getPlateItemById(plateId)->_bbhei / 2;
+        
+        vector<vector<FillResult>>& frArr = std::get<1>( *itp );
+        
+        JsonObject& plateObj = jplatesArr.createNestedObject();
+        plateObj["typeId"] = plateId ;
+        plateObj["plateId"] = ids++;
+        plateObj["x"] = platex;
+        plateObj["y"] = platey;
+        plateObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName;
+        plateObj["sizeX"] = fgc->getPlateItemById(plateId)->_bbwid;
+        plateObj["sizeY"] = fgc->getPlateItemById(plateId)->_bbhei;
+        JsonArray& layerArr = plateObj.createNestedArray("layers");
+        for(int il = 0 ; il < frArr.size() ; ++il ) {
+            vector<FillResult>& frs = frArr[il];
+            JsonObject& lyrObj = layerArr.createNestedObject();
+            lyrObj["rotate"] = 0.0;
+            lyrObj["scale_x"] = 1.0;
+            lyrObj["scale_y"] = 1.0;
+            lyrObj["scale"] = 1.0;
+            lyrObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName;
+            lyrObj["lyrId"] = ids++;
+            lyrObj["zorder"] = il+1;
+            
+            JsonArray& posArr = lyrObj.createNestedArray("position");
+            posArr.add(platex);
+            posArr.add(platey);
+            JsonArray& screwArr = lyrObj.createNestedArray("screws");
+            for(int ij = 0 ;ij < frs.size();++ ij ) {
+                FillResult& fr = frs[ij];
+                FillGlobalConfig::JewelItem* jewPtr = fgc->getJewelItemById(fr._jewelTypeId);
+                if( fr._jewelTypeId>=0 ) {  // -1 is removed.
+                    JsonObject& jobj = screwArr.createNestedObject();
+                    jobj["rotate"] = fr._rotdeg;
+                    jobj["scale_x"] = jewPtr->_scale;
+                    jobj["scale_y"] = jewPtr->_scale;
+                    jobj["csx"] = 0;
+                    jobj["csy"] = 0;
+                    jobj["scale"] = jewPtr->_scale;
+                    jobj["sprite_frame_name"] = jewPtr->_pngName;
+                    jobj["screwId"] = ids++;
+                    jobj["typeId"] = fr._jewelTypeId ;
+                    JsonArray& posArr2 = jobj.createNestedArray("position");
+                    posArr2.add( fr._x ); // 钉子中心在游戏区域的坐标(原点左下角)
+                    posArr2.add( fr._y );
+                }
+            }
+        }
+    }
+    string jsonText ;
+    root.printTo(jsonText);
+    ofstream ofs( outfilename.c_str() );
+    if( ofs.good()==false ) return false;
+    ofs<<jsonText;
+    jsonText.clear();
+    tiledRoot.printTo(jsonText);
+    outfilename.insert(outfilename.size() - 5, "Tiled");
+    ofstream ofsTiled( outfilename.c_str() );
+    if( ofsTiled.good()==false ) return false;
+    ofsTiled<<jsonText;
+    return true;
+}

+ 16 - 0
测试数据/sg_jewel_items.csv

@@ -0,0 +1,16 @@
+唯一编码,元素种类,元素名称,编码1,编码2,尺寸,精灵缩放,精灵图片名称,阴影图片名称,轮廓名称,包围盒子宽度,包围盒子高度,备注
+1,jewel,assher,002,1,SM,0.50,jewel_assher_002_2_1.png,jewel_assher_002_yz.png,jewel_assher_002_2_1.png.json,40,40,no
+2,jewel,assher,002,1,MD,0.75,jewel_assher_002_2_1.png,jewel_assher_002_yz.png,jewel_assher_002_2_1.png.json,60,60,no
+3,jewel,assher,002,1,LG,1.00,jewel_assher_002_2_1.png,jewel_assher_002_yz.png,jewel_assher_002_2_1.png.json,80,80,no
+4,jewel,brillant,030,1,SM,0.50,jewel_brillant_030_1_1.png,jewel_brillant_030_yz.png,jewel_brillant_030_1_1.png.json,40,40,no
+5,jewel,brillant,030,1,MD,0.75,jewel_brillant_030_1_1.png,jewel_brillant_030_yz.png,jewel_brillant_030_1_1.png.json,60,60,no
+6,jewel,brillant,030,1,LG,1.00,jewel_brillant_030_1_1.png,jewel_brillant_030_yz.png,jewel_brillant_030_1_1.png.json,80,80,no
+7,jewel,brillant,032,1,SM,0.50,jewel_brillant_032_1_1.png,jewel_brillant_032_yz.png,jewel_brillant_032_1_1.png.json,40,40,no
+8,jewel,brillant,032,1,MD,0.75,jewel_brillant_032_1_1.png,jewel_brillant_032_yz.png,jewel_brillant_032_1_1.png.json,60,60,no
+9,jewel,brillant,032,1,LG,1.00,jewel_brillant_032_1_1.png,jewel_brillant_032_yz.png,jewel_brillant_032_1_1.png.json,80,80,no
+10,jewel,coussin,031,1,SM,0.50,jewel_coussin_031_1_1.png,jewel_coussin_031_yz.png,jewel_coussin_031_1_1.png.json,40,40,no
+11,jewel,coussin,031,1,MD,0.75,jewel_coussin_031_1_1.png,jewel_coussin_031_yz.png,jewel_coussin_031_1_1.png.json,60,60,no
+12,jewel,coussin,031,1,LG,1.00,jewel_coussin_031_1_1.png,jewel_coussin_031_yz.png,jewel_coussin_031_1_1.png.json,80,80,no
+13,jewel,coussin,062,1,SM,0.50,jewel_coussin_062_1_1.png,jewel_coussin_062_yz.png,jewel_coussin_062_1_1.png.json,40,40,no
+14,jewel,coussin,062,1,MD,0.75,jewel_coussin_062_1_1.png,jewel_coussin_062_yz.png,jewel_coussin_062_1_1.png.json,60,60,no
+15,jewel,coussin,062,1,LG,1.00,jewel_coussin_062_1_1.png,jewel_coussin_062_yz.png,jewel_coussin_062_1_1.png.json,80,80,no

+ 18 - 0
测试数据/sg_level_data.csv

@@ -0,0 +1,18 @@
+关卡编号,关卡子编号,难度,宝石ID,宝石尺寸,组数
+100,1,2,1,SM,3
+100,1,2,4,SM,3
+100,1,2,7,SM,3
+100,1,2,10,SM,3
+100,1,2,13,SM,3
+100,1,2,2,MD,6
+100,1,2,5,MD,6
+100,1,2,8,MD,6
+100,1,2,11,MD,6
+100,1,2,14,MD,6
+
+1,1,0,2,MD,1
+1,1,0,4,SM,1
+1,1,0,8,MD,1
+
+1,2,0,4,SM,1
+1,2,0,14,MD,2

+ 5 - 0
测试数据/sg_plate_items.csv

@@ -0,0 +1,5 @@
+盘子唯一编号,名称,尺寸,精灵图片名称,轮廓名称,有效区域左下x,有效区域左下y,有效区域右上x,有效区域右上y,大宝石容量,图片宽度,图片高度,备注
+1,大横,LG,pan-large_heng.png,pan-large_heng.png.json,5,14,264,205,6,270,210,no
+2,大竖,LG,pan-large_shu.png,pan-large_shu.png.json,5,14,204,265,6,210,270,no
+3,中,MD,pan-small.png,pan-small.png.json,5,8,204,129,3,210,135,no
+4,小,SM,pan-only1.png,pan-only1.png.json,5,14,104,113,1,110,118,no

+ 2356 - 0
测试数据/测试关卡100.json

@@ -0,0 +1,2356 @@
+{
+    "target": {},
+    "bgtem": "no",
+    "jewel_count": 135,
+    "plates": [
+        {
+            "typeId": 1,
+            "plateId": 1,
+            "x": 135,
+            "y": 105,
+            "sprite_frame_name": "pan-large_heng.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-large_heng.png",
+                    "lyrId": 2,
+                    "zorder": 1,
+                    "position": [
+                        135,
+                        105
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 305,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 3,
+                            "typeId": 5,
+                            "position": [
+                                349.5,
+                                263.4000244
+                            ]
+                        },
+                        {
+                            "rotate": 137,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 4,
+                            "typeId": 14,
+                            "position": [
+                                193.5,
+                                263.4000244
+                            ]
+                        },
+                        {
+                            "rotate": 0,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 5,
+                            "typeId": 4,
+                            "position": [
+                                375.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 355,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 6,
+                            "typeId": 7,
+                            "position": [
+                                375.5,
+                                225
+                            ]
+                        },
+                        {
+                            "rotate": 121,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 7,
+                            "typeId": 2,
+                            "position": [
+                                193.5,
+                                167.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 60,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 8,
+                            "typeId": 11,
+                            "position": [
+                                336.5,
+                                177
+                            ]
+                        },
+                        {
+                            "rotate": 296,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 9,
+                            "typeId": 5,
+                            "position": [
+                                271.5,
+                                263.4000244
+                            ]
+                        },
+                        {
+                            "rotate": 169,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 10,
+                            "typeId": 4,
+                            "position": [
+                                167.5,
+                                215.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 104,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 11,
+                            "typeId": 2,
+                            "position": [
+                                271.5,
+                                157.8000031
+                            ]
+                        },
+                        {
+                            "rotate": 222,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 12,
+                            "typeId": 11,
+                            "position": [
+                                232.5,
+                                215.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 182,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 13,
+                            "typeId": 11,
+                            "position": [
+                                297.5,
+                                215.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 251,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 14,
+                            "typeId": 14,
+                            "position": [
+                                180.5,
+                                157.8000031
+                            ]
+                        },
+                        {
+                            "rotate": 210,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 15,
+                            "typeId": 4,
+                            "position": [
+                                323.5,
+                                282.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 62,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 16,
+                            "typeId": 7,
+                            "position": [
+                                232.5,
+                                282.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 356,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 17,
+                            "typeId": 1,
+                            "position": [
+                                375.5,
+                                186.6000061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-large_heng.png",
+                    "lyrId": 18,
+                    "zorder": 2,
+                    "position": [
+                        135,
+                        105
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 305,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 19,
+                            "typeId": 1,
+                            "position": [
+                                362.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 137,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 20,
+                            "typeId": 4,
+                            "position": [
+                                362.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 0,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 21,
+                            "typeId": 8,
+                            "position": [
+                                180.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 355,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 22,
+                            "typeId": 11,
+                            "position": [
+                                362.5,
+                                225
+                            ]
+                        },
+                        {
+                            "rotate": 121,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 23,
+                            "typeId": 13,
+                            "position": [
+                                167.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 60,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 24,
+                            "typeId": 8,
+                            "position": [
+                                193.5,
+                                205.8000031
+                            ]
+                        },
+                        {
+                            "rotate": 296,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 25,
+                            "typeId": 1,
+                            "position": [
+                                310.5,
+                                282.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 169,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 26,
+                            "typeId": 8,
+                            "position": [
+                                232.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 104,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 27,
+                            "typeId": 2,
+                            "position": [
+                                297.5,
+                                157.8000031
+                            ]
+                        },
+                        {
+                            "rotate": 222,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 28,
+                            "typeId": 1,
+                            "position": [
+                                219.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 182,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 29,
+                            "typeId": 8,
+                            "position": [
+                                310.5,
+                                225
+                            ]
+                        },
+                        {
+                            "rotate": 251,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 30,
+                            "typeId": 2,
+                            "position": [
+                                245.5,
+                                186.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 210,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 31,
+                            "typeId": 8,
+                            "position": [
+                                349.5,
+                                177
+                            ]
+                        },
+                        {
+                            "rotate": 62,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 32,
+                            "typeId": 11,
+                            "position": [
+                                258.5,
+                                244.2000122
+                            ]
+                        },
+                        {
+                            "rotate": 356,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 33,
+                            "typeId": 1,
+                            "position": [
+                                375.5,
+                                282.6000061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-large_heng.png",
+                    "lyrId": 34,
+                    "zorder": 3,
+                    "position": [
+                        135,
+                        105
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 263,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 35,
+                            "typeId": 11,
+                            "position": [
+                                362.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 3,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 36,
+                            "typeId": 14,
+                            "position": [
+                                180.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 236,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 37,
+                            "typeId": 11,
+                            "position": [
+                                349.5,
+                                167.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 30,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 38,
+                            "typeId": 1,
+                            "position": [
+                                167.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 356,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 39,
+                            "typeId": 7,
+                            "position": [
+                                375.5,
+                                225
+                            ]
+                        },
+                        {
+                            "rotate": 62,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 40,
+                            "typeId": 1,
+                            "position": [
+                                167.5,
+                                215.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 112,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 41,
+                            "typeId": 10,
+                            "position": [
+                                310.5,
+                                282.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 167,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 42,
+                            "typeId": 5,
+                            "position": [
+                                245.5,
+                                273
+                            ]
+                        },
+                        {
+                            "rotate": 34,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 43,
+                            "typeId": 14,
+                            "position": [
+                                206.5,
+                                177
+                            ]
+                        },
+                        {
+                            "rotate": 273,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 44,
+                            "typeId": 8,
+                            "position": [
+                                284.5,
+                                157.8000031
+                            ]
+                        },
+                        {
+                            "rotate": 62,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 45,
+                            "typeId": 4,
+                            "position": [
+                                323.5,
+                                234.6000061
+                            ]
+                        },
+                        {
+                            "rotate": 202,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 46,
+                            "typeId": 14,
+                            "position": [
+                                271.5,
+                                215.3999939
+                            ]
+                        },
+                        {
+                            "rotate": 150,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 47,
+                            "typeId": 10,
+                            "position": [
+                                232.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 314,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 48,
+                            "typeId": 2,
+                            "position": [
+                                206.5,
+                                244.2000122
+                            ]
+                        },
+                        {
+                            "rotate": 94,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 49,
+                            "typeId": 13,
+                            "position": [
+                                375.5,
+                                148.1999969
+                            ]
+                        },
+                        {
+                            "rotate": 74,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 50,
+                            "typeId": 7,
+                            "position": [
+                                323.5,
+                                196.2000122
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "typeId": 3,
+            "plateId": 51,
+            "x": 376,
+            "y": 67,
+            "sprite_frame_name": "pan-small.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 52,
+                    "zorder": 1,
+                    "position": [
+                        376,
+                        67
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 254,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 53,
+                            "typeId": 5,
+                            "position": [
+                                541,
+                                155.4499969
+                            ]
+                        },
+                        {
+                            "rotate": 295,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 54,
+                            "typeId": 11,
+                            "position": [
+                                421,
+                                155.4499969
+                            ]
+                        },
+                        {
+                            "rotate": 31,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 55,
+                            "typeId": 5,
+                            "position": [
+                                481,
+                                118.8499985
+                            ]
+                        },
+                        {
+                            "rotate": 317,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 56,
+                            "typeId": 11,
+                            "position": [
+                                531,
+                                118.8499985
+                            ]
+                        },
+                        {
+                            "rotate": 170,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 57,
+                            "typeId": 5,
+                            "position": [
+                                421,
+                                112.75
+                            ]
+                        },
+                        {
+                            "rotate": 126,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 58,
+                            "typeId": 7,
+                            "position": [
+                                471,
+                                167.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 72,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 59,
+                            "typeId": 4,
+                            "position": [
+                                501,
+                                167.6499939
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 60,
+                    "zorder": 2,
+                    "position": [
+                        376,
+                        67
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 189,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 61,
+                            "typeId": 8,
+                            "position": [
+                                541,
+                                161.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 103,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 62,
+                            "typeId": 5,
+                            "position": [
+                                421,
+                                155.4499969
+                            ]
+                        },
+                        {
+                            "rotate": 111,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 63,
+                            "typeId": 11,
+                            "position": [
+                                491,
+                                118.8499985
+                            ]
+                        },
+                        {
+                            "rotate": 258,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 64,
+                            "typeId": 11,
+                            "position": [
+                                421,
+                                112.75
+                            ]
+                        },
+                        {
+                            "rotate": 85,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 65,
+                            "typeId": 2,
+                            "position": [
+                                481,
+                                161.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 200,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 66,
+                            "typeId": 8,
+                            "position": [
+                                541,
+                                118.8499985
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 67,
+                    "zorder": 3,
+                    "position": [
+                        376,
+                        67
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 89,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 68,
+                            "typeId": 7,
+                            "position": [
+                                551,
+                                173.75
+                            ]
+                        },
+                        {
+                            "rotate": 303,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 69,
+                            "typeId": 2,
+                            "position": [
+                                431,
+                                149.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 179,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 70,
+                            "typeId": 11,
+                            "position": [
+                                541,
+                                106.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 174,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 71,
+                            "typeId": 13,
+                            "position": [
+                                511,
+                                173.75
+                            ]
+                        },
+                        {
+                            "rotate": 22,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 72,
+                            "typeId": 10,
+                            "position": [
+                                461,
+                                106.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 109,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 73,
+                            "typeId": 14,
+                            "position": [
+                                491,
+                                155.4499969
+                            ]
+                        },
+                        {
+                            "rotate": 213,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 74,
+                            "typeId": 13,
+                            "position": [
+                                411,
+                                106.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 104,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 75,
+                            "typeId": 11,
+                            "position": [
+                                481,
+                                112.75
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "typeId": 3,
+            "plateId": 76,
+            "x": 376,
+            "y": 203,
+            "sprite_frame_name": "pan-small.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 77,
+                    "zorder": 1,
+                    "position": [
+                        376,
+                        203
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 125,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 78,
+                            "typeId": 2,
+                            "position": [
+                                531,
+                                285.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 267,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 79,
+                            "typeId": 5,
+                            "position": [
+                                421,
+                                297.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 272,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 80,
+                            "typeId": 8,
+                            "position": [
+                                481,
+                                242.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 35,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 81,
+                            "typeId": 4,
+                            "position": [
+                                411,
+                                242.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 54,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 82,
+                            "typeId": 4,
+                            "position": [
+                                481,
+                                303.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 71,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 83,
+                            "typeId": 5,
+                            "position": [
+                                541,
+                                254.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 297,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 84,
+                            "typeId": 5,
+                            "position": [
+                                451,
+                                254.8500061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 85,
+                    "zorder": 2,
+                    "position": [
+                        376,
+                        203
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 125,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 86,
+                            "typeId": 2,
+                            "position": [
+                                531,
+                                285.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 267,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 87,
+                            "typeId": 11,
+                            "position": [
+                                421,
+                                297.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 272,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 88,
+                            "typeId": 2,
+                            "position": [
+                                481,
+                                242.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 35,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 89,
+                            "typeId": 7,
+                            "position": [
+                                411,
+                                242.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 54,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 90,
+                            "typeId": 7,
+                            "position": [
+                                481,
+                                303.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 71,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 91,
+                            "typeId": 11,
+                            "position": [
+                                541,
+                                254.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 297,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 92,
+                            "typeId": 11,
+                            "position": [
+                                451,
+                                254.8500061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 93,
+                    "zorder": 3,
+                    "position": [
+                        376,
+                        203
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 62,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 94,
+                            "typeId": 11,
+                            "position": [
+                                531,
+                                285.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 202,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 95,
+                            "typeId": 5,
+                            "position": [
+                                421,
+                                291.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 150,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 96,
+                            "typeId": 14,
+                            "position": [
+                                471,
+                                254.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 314,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 97,
+                            "typeId": 13,
+                            "position": [
+                                481,
+                                303.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 94,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 98,
+                            "typeId": 14,
+                            "position": [
+                                541,
+                                248.75
+                            ]
+                        },
+                        {
+                            "rotate": 74,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 99,
+                            "typeId": 8,
+                            "position": [
+                                421,
+                                248.75
+                            ]
+                        },
+                        {
+                            "rotate": 137,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 100,
+                            "typeId": 10,
+                            "position": [
+                                551,
+                                303.6499939
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "typeId": 3,
+            "plateId": 101,
+            "x": 105,
+            "y": 278,
+            "sprite_frame_name": "pan-small.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 102,
+                    "zorder": 1,
+                    "position": [
+                        105,
+                        278
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 20,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 103,
+                            "typeId": 4,
+                            "position": [
+                                280,
+                                378.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 212,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 104,
+                            "typeId": 8,
+                            "position": [
+                                160,
+                                360.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 104,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 105,
+                            "typeId": 5,
+                            "position": [
+                                270,
+                                323.75
+                            ]
+                        },
+                        {
+                            "rotate": 273,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 106,
+                            "typeId": 5,
+                            "position": [
+                                210,
+                                317.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 57,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 107,
+                            "typeId": 5,
+                            "position": [
+                                220,
+                                360.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 99,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 108,
+                            "typeId": 2,
+                            "position": [
+                                150,
+                                323.75
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 109,
+                    "zorder": 2,
+                    "position": [
+                        105,
+                        278
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 189,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 110,
+                            "typeId": 5,
+                            "position": [
+                                270,
+                                372.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 103,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 111,
+                            "typeId": 14,
+                            "position": [
+                                150,
+                                366.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 111,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 112,
+                            "typeId": 5,
+                            "position": [
+                                220,
+                                329.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 258,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 113,
+                            "typeId": 5,
+                            "position": [
+                                150,
+                                323.75
+                            ]
+                        },
+                        {
+                            "rotate": 85,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 114,
+                            "typeId": 8,
+                            "position": [
+                                210,
+                                372.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 200,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_030_1_1.png",
+                            "screwId": 115,
+                            "typeId": 5,
+                            "position": [
+                                270,
+                                329.8500061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 116,
+                    "zorder": 3,
+                    "position": [
+                        105,
+                        278
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 214,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 117,
+                            "typeId": 8,
+                            "position": [
+                                260,
+                                360.3500061
+                            ]
+                        },
+                        {
+                            "rotate": 206,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 118,
+                            "typeId": 14,
+                            "position": [
+                                160,
+                                366.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 153,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 119,
+                            "typeId": 10,
+                            "position": [
+                                180,
+                                317.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 87,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 120,
+                            "typeId": 1,
+                            "position": [
+                                140,
+                                311.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 272,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 121,
+                            "typeId": 1,
+                            "position": [
+                                280,
+                                311.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 17,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 122,
+                            "typeId": 13,
+                            "position": [
+                                230,
+                                311.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 358,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 123,
+                            "typeId": 7,
+                            "position": [
+                                210,
+                                384.75
+                            ]
+                        },
+                        {
+                            "rotate": 303,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 124,
+                            "typeId": 8,
+                            "position": [
+                                210,
+                                329.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 273,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 125,
+                            "typeId": 13,
+                            "position": [
+                                280,
+                                384.75
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "typeId": 3,
+            "plateId": 126,
+            "x": 316,
+            "y": 339,
+            "sprite_frame_name": "pan-small.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 127,
+                    "zorder": 1,
+                    "position": [
+                        316,
+                        339
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 189,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 128,
+                            "typeId": 2,
+                            "position": [
+                                481,
+                                433.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 103,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 129,
+                            "typeId": 2,
+                            "position": [
+                                361,
+                                427.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 111,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 130,
+                            "typeId": 2,
+                            "position": [
+                                431,
+                                390.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 258,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 131,
+                            "typeId": 2,
+                            "position": [
+                                361,
+                                384.75
+                            ]
+                        },
+                        {
+                            "rotate": 85,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 132,
+                            "typeId": 2,
+                            "position": [
+                                421,
+                                433.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 200,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 133,
+                            "typeId": 2,
+                            "position": [
+                                481,
+                                390.8500061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 134,
+                    "zorder": 2,
+                    "position": [
+                        316,
+                        339
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 189,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 135,
+                            "typeId": 14,
+                            "position": [
+                                481,
+                                433.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 103,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 136,
+                            "typeId": 11,
+                            "position": [
+                                361,
+                                427.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 111,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 137,
+                            "typeId": 14,
+                            "position": [
+                                431,
+                                390.8500061
+                            ]
+                        },
+                        {
+                            "rotate": 258,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 138,
+                            "typeId": 14,
+                            "position": [
+                                361,
+                                384.75
+                            ]
+                        },
+                        {
+                            "rotate": 85,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 139,
+                            "typeId": 14,
+                            "position": [
+                                421,
+                                433.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 200,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 140,
+                            "typeId": 14,
+                            "position": [
+                                481,
+                                390.8500061
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-small.png",
+                    "lyrId": 141,
+                    "zorder": 3,
+                    "position": [
+                        316,
+                        339
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 214,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 142,
+                            "typeId": 10,
+                            "position": [
+                                491,
+                                439.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 206,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 143,
+                            "typeId": 8,
+                            "position": [
+                                371,
+                                427.4500122
+                            ]
+                        },
+                        {
+                            "rotate": 153,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 144,
+                            "typeId": 13,
+                            "position": [
+                                491,
+                                378.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 87,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 145,
+                            "typeId": 8,
+                            "position": [
+                                441,
+                                378.6499939
+                            ]
+                        },
+                        {
+                            "rotate": 272,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 146,
+                            "typeId": 14,
+                            "position": [
+                                441,
+                                433.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 17,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 147,
+                            "typeId": 10,
+                            "position": [
+                                371,
+                                372.5499878
+                            ]
+                        },
+                        {
+                            "rotate": 358,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 148,
+                            "typeId": 13,
+                            "position": [
+                                491,
+                                415.25
+                            ]
+                        },
+                        {
+                            "rotate": 303,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 149,
+                            "typeId": 10,
+                            "position": [
+                                401,
+                                384.75
+                            ]
+                        },
+                        {
+                            "rotate": 273,
+                            "scale_x": 0.5,
+                            "scale_y": 0.5,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.5,
+                            "sprite_frame_name": "jewel_coussin_031_1_1.png",
+                            "screwId": 150,
+                            "typeId": 10,
+                            "position": [
+                                351,
+                                372.5499878
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "typeId": 4,
+            "plateId": 151,
+            "x": 477,
+            "y": 331,
+            "sprite_frame_name": "pan-only1.png",
+            "layers": [
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-only1.png",
+                    "lyrId": 152,
+                    "zorder": 1,
+                    "position": [
+                        477,
+                        331
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 24,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_assher_002_2_1.png",
+                            "screwId": 153,
+                            "typeId": 2,
+                            "position": [
+                                539.5,
+                                403.5
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-only1.png",
+                    "lyrId": 154,
+                    "zorder": 2,
+                    "position": [
+                        477,
+                        331
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 239,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 155,
+                            "typeId": 14,
+                            "position": [
+                                539.5,
+                                398.5
+                            ]
+                        },
+                        {
+                            "rotate": 93,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_coussin_062_1_1.png",
+                            "screwId": 156,
+                            "typeId": 14,
+                            "position": [
+                                514.5,
+                                378.5
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "rotate": 0,
+                    "scale_x": 1,
+                    "scale_y": 1,
+                    "scale": 1,
+                    "sprite_frame_name": "pan-only1.png",
+                    "lyrId": 157,
+                    "zorder": 3,
+                    "position": [
+                        477,
+                        331
+                    ],
+                    "screws": [
+                        {
+                            "rotate": 239,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 158,
+                            "typeId": 8,
+                            "position": [
+                                539.5,
+                                398.5
+                            ]
+                        },
+                        {
+                            "rotate": 93,
+                            "scale_x": 0.75,
+                            "scale_y": 0.75,
+                            "csx": 0,
+                            "csy": 0,
+                            "scale": 0.75,
+                            "sprite_frame_name": "jewel_brillant_032_1_1.png",
+                            "screwId": 159,
+                            "typeId": 8,
+                            "position": [
+                                514.5,
+                                378.5
+                            ]
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}

+ 10 - 0
测试数据/轮廓/sg_宝石轮廓/files.txt

@@ -0,0 +1,10 @@
+jewel_assher_002_2_1.png
+jewel_assher_002_yz.png
+jewel_brillant_030_1_1.png
+jewel_brillant_030_yz.png
+jewel_brillant_032_1_1.png
+jewel_brillant_032_yz.png
+jewel_coussin_031_1_1.png
+jewel_coussin_031_yz.png
+jewel_coussin_062_1_1.png
+jewel_coussin_062_yz.png

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_2_1.png


+ 1 - 0
测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_2_1.png.json

@@ -0,0 +1 @@
+[  [-24,40], [-30,39], [-38,31], [-38,10], [-39,-25], [-27,-38], [29,-38], [37,-30], [38,0], [39,29], [28,40], [-24,40]  ]

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_assher_002_yz.png


BIN
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_1_1.png


+ 1 - 0
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_1_1.png.json

@@ -0,0 +1 @@
+[  [-6,40], [-10,39], [-13,38], [-16,37], [-19,35], [-22,33], [-32,24], [-34,21], [-35,18], [-36,15], [-37,12], [-38,7], [-39,-5], [-38,-9], [-37,-12], [-36,-15], [-34,-18], [-33,-21], [-30,-24], [-26,-29], [-22,-32], [-19,-34], [-15,-35], [-12,-37], [-9,-37], [7,-38], [10,-37], [13,-36], [16,-34], [19,-33], [25,-28], [31,-22], [33,-19], [34,-16], [35,-13], [36,-10], [37,-5], [38,5], [37,10], [36,14], [34,17], [33,20], [30,24], [22,33], [19,35], [16,36], [13,37], [10,38], [6,39], [-6,40]  ]

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_030_yz.png


BIN
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_1_1.png


+ 1 - 0
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_1_1.png.json

@@ -0,0 +1 @@
+[  [-2,40], [-8,39], [-12,38], [-15,37], [-18,35], [-21,33], [-25,30], [-29,27], [-32,23], [-34,20], [-35,16], [-37,13], [-38,10], [-38,5], [-39,-3], [-38,-9], [-37,-12], [-35,-15], [-34,-18], [-32,-21], [-29,-25], [-26,-29], [-22,-32], [-19,-34], [-16,-35], [-13,-36], [-9,-37], [-3,-38], [2,-39], [8,-38], [12,-37], [15,-35], [18,-34], [21,-32], [25,-29], [29,-26], [32,-22], [34,-19], [35,-16], [36,-13], [37,-10], [38,-4], [39,4], [38,10], [37,13], [35,16], [34,19], [32,22], [29,26], [26,30], [22,33], [19,35], [15,36], [12,38], [9,38], [3,39], [-2,40]  ]

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_brillant_032_yz.png


BIN
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_1_1.png


+ 1 - 0
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_1_1.png.json

@@ -0,0 +1 @@
+[  [-7,40], [-15,39], [-19,38], [-22,37], [-26,34], [-32,29], [-34,26], [-35,23], [-36,20], [-37,16], [-38,10], [-39,-10], [-38,-16], [-37,-20], [-36,-23], [-34,-26], [-31,-30], [-27,-34], [-24,-35], [-21,-37], [-18,-37], [-11,-38], [3,-39], [10,-38], [15,-37], [20,-36], [23,-35], [26,-33], [29,-31], [33,-27], [34,-24], [35,-21], [36,-18], [37,-13], [38,12], [37,18], [36,23], [35,26], [33,29], [28,35], [25,36], [22,37], [17,38], [10,39], [-7,40]  ]

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_031_yz.png


BIN
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_1_1.png


+ 1 - 0
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_1_1.png.json

@@ -0,0 +1 @@
+[  [-2,39], [-14,38], [-20,37], [-23,36], [-26,34], [-29,33], [-34,28], [-35,25], [-37,22], [-38,19], [-38,15], [-39,7], [-40,-6], [-39,-14], [-38,-19], [-37,-22], [-35,-25], [-34,-28], [-29,-33], [-26,-35], [-23,-36], [-20,-37], [-14,-37], [14,-38], [21,-37], [24,-36], [27,-34], [33,-29], [34,-26], [36,-23], [37,-20], [37,-16], [38,-7], [39,12], [38,18], [37,22], [36,25], [34,28], [30,33], [27,34], [24,36], [21,37], [18,37], [10,38], [-2,39]  ]

BIN
测试数据/轮廓/sg_宝石轮廓/jewel_coussin_062_yz.png


+ 3 - 0
测试数据/轮廓/sg_宝石轮廓/测试图片说明.txt

@@ -0,0 +1,3 @@
+这里测试图片重新调整尺寸到大宝石80x80像素。未来上线程序不能保证具体图片大小。
+2024-11-28
+

BIN
测试数据/轮廓/sg_盘子轮廓/pan-large_heng.png


+ 1 - 0
测试数据/轮廓/sg_盘子轮廓/pan-large_heng.png.json

@@ -0,0 +1 @@
+[  [-129,99], [-129,-90], [128,-90], [128,99], [-129,99]  ]

BIN
测试数据/轮廓/sg_盘子轮廓/pan-large_shu.png


+ 1 - 0
测试数据/轮廓/sg_盘子轮廓/pan-large_shu.png.json

@@ -0,0 +1 @@
+[  [-99,129], [-99,-120], [98,-120], [98,129], [-99,129]  ]

BIN
测试数据/轮廓/sg_盘子轮廓/pan-only1.png


+ 1 - 0
测试数据/轮廓/sg_盘子轮廓/pan-only1.png.json

@@ -0,0 +1 @@
+[  [-49,53], [-49,-44], [48,-44], [48,53], [-49,53]  ]

BIN
测试数据/轮廓/sg_盘子轮廓/pan-small.png


+ 1 - 0
测试数据/轮廓/sg_盘子轮廓/pan-small.png.json

@@ -0,0 +1 @@
+[  [-99,61], [-99,-59], [98,-59], [98,61], [-99,61]  ]