From 1ac12e37d9659ea09ed134cb9fd67b4d81734a6a Mon Sep 17 00:00:00 2001 From: PunChen Date: Sun, 11 May 2025 00:27:34 +0800 Subject: [PATCH 1/9] add simple mode draw circle --- .../gui/GuiAreaSelectionEditorNormal.java | 57 +++++++++++- .../gui/GuiAreaSelectionEditorSimple.java | 3 + .../litematica/selection/AreaSelection.java | 93 ++++++++++++++++++- .../selection/SelectionManager.java | 12 +++ .../litematica/selection/SelectionMode.java | 1 + .../masa/litematica/util/InventoryUtils.java | 9 +- .../assets/litematica/lang/en_us.json | 4 + .../assets/litematica/lang/zh_cn.json | 2 + 8 files changed, 173 insertions(+), 8 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java index c1bf24444e..77c1dc1aad 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java @@ -3,6 +3,8 @@ import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; + +import fi.dy.masa.malilib.MaLiLib; import net.minecraft.util.math.BlockPos; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.config.Hotkeys; @@ -35,6 +37,7 @@ import fi.dy.masa.malilib.interfaces.IStringConsumerFeedback; import fi.dy.masa.malilib.util.PositionUtils.CoordinateType; import fi.dy.masa.malilib.util.StringUtils; +import net.minecraft.util.math.Vec3i; public class GuiAreaSelectionEditorNormal extends GuiListBase implements ISelectionListener @@ -48,7 +51,9 @@ public class GuiAreaSelectionEditorNormal extends GuiListBase boxList = new ArrayList<>(); + this.subRegionBoxes.clear(); + try { + double offset = 0.0; + double c1x = cor1.getX() + offset; + double c1z = cor1.getZ() + offset; + double c1y = cor1.getY() + offset; + double c2x = cor2.getX() + offset; + double c2z = cor2.getZ() + offset; + double c2y = cor2.getY() + offset; + + double dis2 = calculateDistance2(c1x, c1z, c2x, c2z); + double dis = Math.sqrt(dis2); + double startX = c1x; + double startZ = c1z + Math.ceil(dis); + List posList = new ArrayList<>(); + posList.add(new double[]{startX, startZ}); + // 1/4圆 + MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); + while(startZ > c1z) { + double[][] nextPos = {{startX + 1, startZ}, {startX + 1, startZ - 1}, {startX, startZ - 1}}; + double[] disSquare = new double[3]; + disSquare[0] = Math.abs(calculateDistance2(nextPos[0][0], nextPos[0][1], c1x, c1z) - dis2); + disSquare[1] = Math.abs(calculateDistance2(nextPos[1][0], nextPos[1][1], c1x, c1z) - dis2); + disSquare[2] = Math.abs(calculateDistance2(nextPos[2][0], nextPos[2][1], c1x, c1z) - dis2); + int minIndex = 0; + double minDisSquare = Double.MAX_VALUE; + for (int i = 0; i < 3; ++i) { + if (disSquare[i] < minDisSquare) { + minDisSquare = disSquare[i]; + minIndex = i; + } + } + startX = nextPos[minIndex][0]; + startZ = nextPos[minIndex][1]; + posList.add(new double[]{startX, startZ}); + } + //关于x轴对称 1/2圆 + /* + ^z + | + |_____>x + (c1x,c1z) + */ + List newPosList = new ArrayList<>(); + for (double[] pos : posList) { + double syncPosX = pos[0]; + double syncPosZ = 2 * c1z - pos[1]; + newPosList.add(new double[]{syncPosX, syncPosZ}); + } + posList.addAll(newPosList); + //关于z轴对称 整个圆 + Box box = null; + for (double[] pos : posList) { + double curX = (int) pos[0]; + double curZ = (int) pos[1]; + double syncPosX = (int) (2 * c1x - pos[0]); + double syncPosZ = (int) (pos[1]); + + box = new Box(); + BlockPos pos1 = new BlockPos((int) curX, cor1.getY(), (int) curZ); + BlockPos pos2 = new BlockPos((int) syncPosX, cor1.getY(), (int) syncPosZ); + // 添加到多选区域列表中 + String name = "z" + curZ; + box.setSelectedCorner(Corner.CORNER_1); + this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); + this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); + this.currentBox = name; + this.subRegionBoxes.put(name, box); + boxList.add(box); + MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); + } + MaLiLib.logger.error(String.format("boxList size: %s", boxList.size())); + } catch (Exception e) { + MaLiLib.logger.error("createNewSubRegionBoxBatch ", e); + } + return "createNewSubRegionBoxBatch"; + } + public void clearCurrentSelectedCorner() { this.setCurrentSelectedCorner(Corner.NONE); diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java index 6ed0d40013..6ee6fbf890 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java @@ -718,6 +718,18 @@ public GuiBase getEditGui() return null; } } + else if (this.getSelectionMode() == SelectionMode.NORMAL) + { + if (selection != null) + { + return new GuiAreaSelectionEditorNormal(selection); + } + else + { + InfoUtils.showGuiOrActionBarMessage(MessageType.WARNING, "litematica.error.area_editor.open_gui.no_selection"); + return null; + } + } else { return new GuiAreaSelectionEditorSimple(selection); diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java index f82baff2ef..bb4570c479 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java @@ -5,6 +5,7 @@ public enum SelectionMode { NORMAL ("litematica.gui.label.area_selection.mode.normal"), +// COMPLEX ("litematica.gui.label.area_selection.mode.complex"), SIMPLE ("litematica.gui.label.area_selection.mode.simple"); private final String translationKey; diff --git a/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java b/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java index 451ff65f7b..900658d360 100644 --- a/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java @@ -4,6 +4,7 @@ import java.util.List; import javax.annotation.Nullable; +import fi.dy.masa.malilib.MaLiLib; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; @@ -113,11 +114,12 @@ public static void setPickedItemToHand(int sourceSlot, ItemStack stack, Minecraf public static void schematicWorldPickBlock(ItemStack stack, BlockPos pos, World schematicWorld, MinecraftClient mc) { + MaLiLib.logger.error("schematicWorldPickBlock stack.isEmpty() {} ", stack.isEmpty()); if (stack.isEmpty() == false) { PlayerInventory inv = mc.player.getInventory(); stack = stack.copy(); - + MaLiLib.logger.error("schematicWorldPickBlock EntityUtils.isCreativeMode(mc.player) {} ", EntityUtils.isCreativeMode(mc.player)); if (EntityUtils.isCreativeMode(mc.player)) { BlockEntity te = schematicWorld.getBlockEntity(pos); @@ -138,7 +140,9 @@ public static void schematicWorldPickBlock(ItemStack stack, BlockPos pos, } else { + MaLiLib.logger.error("schematicWorldPickBlock getSlotWithStack invoking {} {}", stack.toString(), pos.toString()); int slot = inv.getSlotWithStack(stack); + MaLiLib.logger.error("schematicWorldPickBlock getSlotWithStack ret slot {} selected slot {}", slot, inv.selectedSlot); boolean shouldPick = inv.selectedSlot != slot; if (shouldPick && slot != -1) @@ -147,8 +151,9 @@ public static void schematicWorldPickBlock(ItemStack stack, BlockPos pos, } else if (slot == -1 && Configs.Generic.PICK_BLOCK_SHULKERS.getBooleanValue()) { - slot = findSlotWithBoxWithItem(mc.player.playerScreenHandler, stack, false); + slot = findSlotWithBoxWithItem(mc.player.playerScreenHandler, stack, false); + MaLiLib.logger.error("schematicWorldPickBlock findSlotWithBoxWithItem ret slot {}", slot); if (slot != -1) { ItemStack boxStack = mc.player.playerScreenHandler.slots.get(slot).getStack(); diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index 30f131ac57..e0e00a383e 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -533,6 +533,8 @@ "litematica.gui.button.area_editor.create_schematic": "Save Schematic", "litematica.gui.button.area_editor.create_sub_region": "New sub-region", "litematica.gui.button.area_editor.origin_enabled": "Manual Origin: %s", + "litematica.gui.button.area_editor.generate_circle": "Generate Circle", + "litematica.gui.button.area_editor.circle_enabled": "Circle Mode: %s", "litematica.gui.button.area_editor.set_box_name": "Set", "litematica.gui.button.area_editor.set_selection_name": "Set", @@ -673,6 +675,7 @@ "litematica.gui.label.area_selection_box_count": "Boxes: %d", "litematica.gui.label.area_selection_origin": "Origin: %s", "litematica.gui.label.area_selection.mode.normal": "Normal", + "litematica.gui.label.area_selection.mode.complex": "Complex", "litematica.gui.label.area_selection.mode.simple": "Simple", "litematica.gui.label.block_info.state_client": "Client World Block State", @@ -798,6 +801,7 @@ "litematica.gui.title.area_editor_normal": "Area Editor (Normal/Multi-box mode)", "litematica.gui.title.area_editor_normal_schematic_projects": "Area Editor (§6§lSchematic VCS area§r)", "litematica.gui.title.area_editor_simple": "Area Editor (Simple mode)", + "litematica.gui.title.area_editor_complex": "Area Editor (Complex mode)", "litematica.gui.title.area_editor_sub_region": "Area Editor (sub-region)", "litematica.gui.title.area_editor.sub_region_name": "Sub-region name", "litematica.gui.title.area_selection_manager": "Area Selection Manager", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index feaa065334..78a356f4c6 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -533,6 +533,8 @@ "litematica.gui.button.area_editor.create_schematic": "保存原理图", "litematica.gui.button.area_editor.create_sub_region": "新建子区域", "litematica.gui.button.area_editor.origin_enabled": "手动来源:%s", + "litematica.gui.button.area_editor.generate_circle": "生成圆形", + "litematica.gui.button.area_editor.circle_enabled": "圆形模式:%s", "litematica.gui.button.area_editor.set_box_name": "set", "litematica.gui.button.area_editor.set_selection_name": "set", From 6eaa8e9216843cf931590445f98c756613000f59 Mon Sep 17 00:00:00 2001 From: PunChen Date: Sun, 11 May 2025 00:36:09 +0800 Subject: [PATCH 2/9] add simple mode draw circle-fix y --- .../java/fi/dy/masa/litematica/selection/AreaSelection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java index 1a39024ee0..bb02f460da 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java +++ b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java @@ -276,8 +276,8 @@ public String createNewSubRegionBoxBatch(BlockPos cor1, BlockPos cor2) { double syncPosZ = (int) (pos[1]); box = new Box(); - BlockPos pos1 = new BlockPos((int) curX, cor1.getY(), (int) curZ); - BlockPos pos2 = new BlockPos((int) syncPosX, cor1.getY(), (int) syncPosZ); + BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); + BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); // 添加到多选区域列表中 String name = "z" + curZ; box.setSelectedCorner(Corner.CORNER_1); From 895222f97ab2f6ad7e96555acb7da50d4689a826 Mon Sep 17 00:00:00 2001 From: PunChen Date: Tue, 13 May 2025 02:13:31 +0800 Subject: [PATCH 3/9] add complex mode 1. need fix why only printer works on normal mode 2.can not manually edit two corner postions --- .../gui/GuiAreaSelectionEditorComplex.java | 147 ++++++++++++++++++ .../gui/GuiAreaSelectionEditorNormal.java | 9 +- .../gui/GuiAreaSelectionEditorSimple.java | 3 - .../litematica/render/infohud/ToolHud.java | 4 + .../litematica/selection/AreaSelection.java | 4 +- .../selection/SelectionManager.java | 7 +- .../litematica/selection/SelectionMode.java | 2 +- .../assets/litematica/lang/en_us.json | 1 + .../assets/litematica/lang/zh_cn.json | 4 + 9 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java new file mode 100644 index 0000000000..51992817d6 --- /dev/null +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java @@ -0,0 +1,147 @@ +package fi.dy.masa.litematica.gui; + +import fi.dy.masa.litematica.data.DataManager; +import fi.dy.masa.litematica.gui.widgets.WidgetListSelectionSubRegions; +import fi.dy.masa.litematica.selection.AreaSelection; +import fi.dy.masa.litematica.selection.Box; +import fi.dy.masa.litematica.selection.SelectionManager; +import fi.dy.masa.litematica.util.PositionUtils; +import fi.dy.masa.litematica.util.PositionUtils.Corner; +import fi.dy.masa.malilib.MaLiLib; +import fi.dy.masa.malilib.gui.GuiTextFieldGeneric; +import fi.dy.masa.malilib.util.StringUtils; +import net.minecraft.util.math.BlockPos; + +import javax.annotation.Nullable; + +public class GuiAreaSelectionEditorComplex extends GuiAreaSelectionEditorNormal +{ + protected static String defaultBoxName = "DefaultComplexBox"; + + public GuiAreaSelectionEditorComplex(AreaSelection selection) + { + super(selection); + + if (DataManager.getSchematicProjectsManager().hasProjectOpen()) + { + this.title = StringUtils.translate("litematica.gui.title.area_editor_normal_schematic_projects"); + } + else + { + this.title = StringUtils.translate("litematica.gui.title.area_editor_complex"); + } + } + + @Override + public void initGui() + { + super.initGui(); + + if (this.selection != null) + { + this.createSelectionEditFields(); + this.addSubRegionFields(this.xOrigin, this.yNext); + this.updateCheckBoxes(); + } + else + { + this.addLabel(20, 30, 120, 12, 0xFFFFAA00, StringUtils.translate("litematica.error.area_editor.no_selection")); + } + } + + + @Override + protected int addSubRegionFields(int x, int y) + { + x = 12; +// String label = StringUtils.translate("litematica.gui.label.area_editor.box_name"); +// this.addLabel(x, y, -1, 16, 0xFFFFFFFF, label); +// y += 13; + +// boolean currentlyOn = this.selection.getExplicitOrigin() != null; +// this.createButtonOnOff(this.xOrigin, 24, -1, currentlyOn, ButtonListener.Type.TOGGLE_ORIGIN_ENABLED); +// x += this.createButton(x, y, -1, ButtonListener.Type.CREATE_SUB_REGION) + 4; + int width = 202; +// this.textFieldBoxName = new GuiTextFieldGeneric(x, y + 2, width, 16, this.textRenderer); +// this.textFieldBoxName.setText(this.getBox().getName()); +// this.addTextField(this.textFieldBoxName, new TextFieldListenerDummy()); +// this.createButton(x + width + 4, y, -1, ButtonListener.Type.SET_BOX_NAME); + y += 20; + + x = 12; + width = 68; + + int nextY = 0; + this.createCoordinateInputs(x, y, width, Corner.CORNER_1); + x += width + 42; + nextY = this.createCoordinateInputs(x, y, width, Corner.CORNER_2); + this.createButton(x + 10, nextY, -1, ButtonListener.Type.ANALYZE_AREA); + x += width + 42; + + // Manual Origin defined +// if (this.selection.getExplicitOrigin() != null) +// { +// this.createCoordinateInputs(x, y, width, Corner.NONE); +// } + + x = this.createButton(22, nextY, -1, ButtonListener.Type.CREATE_SCHEMATIC) + 26; + + x = this.createButton(22, nextY + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); + nextY += 22; + this.createButtonOnOff(22, nextY + 22, -1, circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); + + +// this.createCoordinateInputs(x, y, width, Corner.CORNER_1); +// this.createCoordinateInputs(x, y, width, Corner.CORNER_2); +// +// this.createButton(22, y + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); +// y += 22; +// this.createButtonOnOff(22, y + 22, -1, this.circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); + + + this.addRenderingDisabledWarning(250, 48); + + return y; + } + + @Override + protected Box getBox() + { + // 设置默认位置和名称 + Box selBox = this.selection.getSelectedSubRegionBox(); + this.selection.removeSelectedSubRegionBox(); + if (selBox != null) { + selBox.setName(defaultBoxName); + } else if (this.mc.player != null) { + BlockPos pos = fi.dy.masa.malilib.util.PositionUtils.getEntityBlockPos(this.mc.player); + selBox = new Box(pos, pos, defaultBoxName); + } else { + MaLiLib.logger.error("can not getSelectedSubRegionBox"); + selBox = new Box(); + selBox.setName(defaultBoxName); + } + this.selection.addSubRegionBox(selBox,false); + this.selection.setSelectedSubRegionBox(defaultBoxName); + return selBox; + } + + @Override + protected WidgetListSelectionSubRegions getListWidget() + { + return this.createListWidget(8, 116); + } + + @Override + protected void reCreateListWidget() + { +// super.createListWidget(8,116); + // NO-OP + } + + @Override + protected WidgetListSelectionSubRegions createListWidget(int listX, int listY) + { + return new WidgetListSelectionSubRegions(listX, listY, + this.getBrowserWidth(), this.getBrowserHeight(), this.selection, this); + } +} diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java index 77c1dc1aad..995492abf0 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java @@ -51,7 +51,7 @@ public class GuiAreaSelectionEditorNormal extends GuiListBase boxList = new ArrayList<>(); + String currentBoxName = this.getCurrentSubRegionBoxName(); + Box curBox = this.getSubRegionBox(currentBox); this.subRegionBoxes.clear(); + this.subRegionBoxes.put(currentBoxName, curBox);// 不删除当前选区 try { double offset = 0.0; double c1x = cor1.getX() + offset; @@ -283,7 +286,6 @@ public String createNewSubRegionBoxBatch(BlockPos cor1, BlockPos cor2) { box.setSelectedCorner(Corner.CORNER_1); this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); - this.currentBox = name; this.subRegionBoxes.put(name, box); boxList.add(box); MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java index 6ee6fbf890..aeee6c2457 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java @@ -8,6 +8,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import fi.dy.masa.litematica.gui.GuiAreaSelectionEditorComplex; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.entity.Entity; @@ -718,15 +719,15 @@ public GuiBase getEditGui() return null; } } - else if (this.getSelectionMode() == SelectionMode.NORMAL) + else if (this.getSelectionMode() == SelectionMode.COMPLEX) { if (selection != null) { - return new GuiAreaSelectionEditorNormal(selection); + return new GuiAreaSelectionEditorComplex(selection); } else { - InfoUtils.showGuiOrActionBarMessage(MessageType.WARNING, "litematica.error.area_editor.open_gui.no_selection"); + InfoUtils.showGuiOrActionBarMessage(MessageType.WARNING, "litematica.error.area_editor.open_gui.no_selection_complex"); return null; } } diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java index bb4570c479..eb2f2a44e5 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java @@ -5,7 +5,7 @@ public enum SelectionMode { NORMAL ("litematica.gui.label.area_selection.mode.normal"), -// COMPLEX ("litematica.gui.label.area_selection.mode.complex"), + COMPLEX ("litematica.gui.label.area_selection.mode.complex"), SIMPLE ("litematica.gui.label.area_selection.mode.simple"); private final String translationKey; diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index e0e00a383e..8b0b87d120 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -849,6 +849,7 @@ "litematica.hud.area_selection.origin": "Origin: %s", "litematica.hud.area_selection.selected_area_normal": "Area: %s", "litematica.hud.area_selection.selected_area_simple": "Area [§6Simple mode§r]: %s", + "litematica.hud.area_selection.selected_area_complex": "Area [§6Complex mode§r]: %s", "litematica.hud.area_selection.selected_sub_region": "Sub-region: %s", "litematica.hud.area_selection.selection_corners_mode": "Corners Mode: %s", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 78a356f4c6..59e846351f 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -470,6 +470,7 @@ "litematica.error.area_editor.create_sub_region.exists": "名为'%s' 子区域已经存在", "litematica.error.area_editor.no_selection": "无活动区域的选择", "litematica.error.area_editor.open_gui.no_selection": "当前处于选择模式:Normal,但当前未选择任何区域", + "litematica.error.area_editor.open_gui.no_selection_complex": "当前处于选择模式:Complex,但当前未选择任何区域", "litematica.error.area_editor.rename_sub_region.exists": "重命名子区域失败\n已存在子区域名字为 '%s'", "litematica.error.area_editor.switch_mode.no_selection": "无法切换到选择模式:Normal,因为当前没有选择区域.\n请在区域选择浏览器中选择一个区域或创建一个新的选择", @@ -675,6 +676,7 @@ "litematica.gui.label.area_selection_box_count": "框数: %d", "litematica.gui.label.area_selection_origin": "原点: %s", "litematica.gui.label.area_selection.mode.normal": "正常", + "litematica.gui.label.area_selection.mode.complex": "复合", "litematica.gui.label.area_selection.mode.simple": "简单", "litematica.gui.label.block_info.state_client": "客户端世界的方块信息", @@ -800,6 +802,7 @@ "litematica.gui.title.area_editor_normal": "区域编辑器(普通/多框模式)", "litematica.gui.title.area_editor_normal_schematic_projects": "区域编辑器 (§6§l图形项目区域§r)", "litematica.gui.title.area_editor_simple": "区域编辑器 (简单模式)", + "litematica.gui.title.area_editor_complex": "区域编辑器 (复合模式)", "litematica.gui.title.area_editor_sub_region": "区域编辑器 (子区域)", "litematica.gui.title.area_editor.sub_region_name": "子区域名称", "litematica.gui.title.area_selection_manager": "区域选择管理器", @@ -847,6 +850,7 @@ "litematica.hud.area_selection.origin": "原点: %s", "litematica.hud.area_selection.selected_area_normal": "区域: %s", "litematica.hud.area_selection.selected_area_simple": "区域 [§6简单模式§r]: %s", + "litematica.hud.area_selection.selected_area_complex": "区域 [§6复合模式§r]: %s", "litematica.hud.area_selection.selected_sub_region": "子区域: %s", "litematica.hud.area_selection.selection_corners_mode": "角点模式: %s", From 6a683a757b774b652e1eaf3d5b50991a1cd38bd9 Mon Sep 17 00:00:00 2001 From: PunChen Date: Wed, 14 May 2025 00:55:41 +0800 Subject: [PATCH 4/9] add complex mode 1. need fix why only printer works on normal mode 2.can not manually edit two corner postions 3.done: save to schematic file --- .../gui/GuiAreaSelectionEditorComplex.java | 35 +------------------ .../litematica/selection/AreaSelection.java | 5 +-- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java index 51992817d6..bc7c5b4126 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java @@ -4,16 +4,11 @@ import fi.dy.masa.litematica.gui.widgets.WidgetListSelectionSubRegions; import fi.dy.masa.litematica.selection.AreaSelection; import fi.dy.masa.litematica.selection.Box; -import fi.dy.masa.litematica.selection.SelectionManager; -import fi.dy.masa.litematica.util.PositionUtils; import fi.dy.masa.litematica.util.PositionUtils.Corner; import fi.dy.masa.malilib.MaLiLib; -import fi.dy.masa.malilib.gui.GuiTextFieldGeneric; import fi.dy.masa.malilib.util.StringUtils; import net.minecraft.util.math.BlockPos; -import javax.annotation.Nullable; - public class GuiAreaSelectionEditorComplex extends GuiAreaSelectionEditorNormal { protected static String defaultBoxName = "DefaultComplexBox"; @@ -54,22 +49,9 @@ public void initGui() protected int addSubRegionFields(int x, int y) { x = 12; -// String label = StringUtils.translate("litematica.gui.label.area_editor.box_name"); -// this.addLabel(x, y, -1, 16, 0xFFFFFFFF, label); -// y += 13; - -// boolean currentlyOn = this.selection.getExplicitOrigin() != null; -// this.createButtonOnOff(this.xOrigin, 24, -1, currentlyOn, ButtonListener.Type.TOGGLE_ORIGIN_ENABLED); -// x += this.createButton(x, y, -1, ButtonListener.Type.CREATE_SUB_REGION) + 4; - int width = 202; -// this.textFieldBoxName = new GuiTextFieldGeneric(x, y + 2, width, 16, this.textRenderer); -// this.textFieldBoxName.setText(this.getBox().getName()); -// this.addTextField(this.textFieldBoxName, new TextFieldListenerDummy()); -// this.createButton(x + width + 4, y, -1, ButtonListener.Type.SET_BOX_NAME); y += 20; - x = 12; - width = 68; + int width = 68; int nextY = 0; this.createCoordinateInputs(x, y, width, Corner.CORNER_1); @@ -78,27 +60,12 @@ protected int addSubRegionFields(int x, int y) this.createButton(x + 10, nextY, -1, ButtonListener.Type.ANALYZE_AREA); x += width + 42; - // Manual Origin defined -// if (this.selection.getExplicitOrigin() != null) -// { -// this.createCoordinateInputs(x, y, width, Corner.NONE); -// } - x = this.createButton(22, nextY, -1, ButtonListener.Type.CREATE_SCHEMATIC) + 26; x = this.createButton(22, nextY + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); nextY += 22; this.createButtonOnOff(22, nextY + 22, -1, circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); - -// this.createCoordinateInputs(x, y, width, Corner.CORNER_1); -// this.createCoordinateInputs(x, y, width, Corner.CORNER_2); -// -// this.createButton(22, y + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); -// y += 22; -// this.createButtonOnOff(22, y + 22, -1, this.circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); - - this.addRenderingDisabledWarning(250, 48); return y; diff --git a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java index 4696a048a9..0861c86d40 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java +++ b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java @@ -233,7 +233,7 @@ public String createNewSubRegionBoxBatch(BlockPos cor1, BlockPos cor2) { double dis2 = calculateDistance2(c1x, c1z, c2x, c2z); double dis = Math.sqrt(dis2); double startX = c1x; - double startZ = c1z + Math.ceil(dis); + double startZ = c1z + Math.round(dis); List posList = new ArrayList<>(); posList.add(new double[]{startX, startZ}); // 1/4圆 @@ -282,8 +282,9 @@ public String createNewSubRegionBoxBatch(BlockPos cor1, BlockPos cor2) { BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); // 添加到多选区域列表中 - String name = "z" + curZ; + String name = "z" + (int)curZ; box.setSelectedCorner(Corner.CORNER_1); + box.setName(name); this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); this.subRegionBoxes.put(name, box); From 3a4177022a9046f0e5fe94fb6919b6d5ab000a33 Mon Sep 17 00:00:00 2001 From: PunChen Date: Sat, 17 May 2025 02:11:22 +0800 Subject: [PATCH 5/9] remove complex mode due to litematica printer only use normal mode --- .../gui/GuiAreaSelectionEditorComplex.java | 228 +++++++++--------- .../litematica/render/infohud/ToolHud.java | 4 - .../selection/SelectionManager.java | 13 - .../litematica/selection/SelectionMode.java | 1 - .../assets/litematica/lang/en_us.json | 2 - .../assets/litematica/lang/zh_cn.json | 4 - 6 files changed, 114 insertions(+), 138 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java index bc7c5b4126..86946a0793 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorComplex.java @@ -1,114 +1,114 @@ -package fi.dy.masa.litematica.gui; - -import fi.dy.masa.litematica.data.DataManager; -import fi.dy.masa.litematica.gui.widgets.WidgetListSelectionSubRegions; -import fi.dy.masa.litematica.selection.AreaSelection; -import fi.dy.masa.litematica.selection.Box; -import fi.dy.masa.litematica.util.PositionUtils.Corner; -import fi.dy.masa.malilib.MaLiLib; -import fi.dy.masa.malilib.util.StringUtils; -import net.minecraft.util.math.BlockPos; - -public class GuiAreaSelectionEditorComplex extends GuiAreaSelectionEditorNormal -{ - protected static String defaultBoxName = "DefaultComplexBox"; - - public GuiAreaSelectionEditorComplex(AreaSelection selection) - { - super(selection); - - if (DataManager.getSchematicProjectsManager().hasProjectOpen()) - { - this.title = StringUtils.translate("litematica.gui.title.area_editor_normal_schematic_projects"); - } - else - { - this.title = StringUtils.translate("litematica.gui.title.area_editor_complex"); - } - } - - @Override - public void initGui() - { - super.initGui(); - - if (this.selection != null) - { - this.createSelectionEditFields(); - this.addSubRegionFields(this.xOrigin, this.yNext); - this.updateCheckBoxes(); - } - else - { - this.addLabel(20, 30, 120, 12, 0xFFFFAA00, StringUtils.translate("litematica.error.area_editor.no_selection")); - } - } - - - @Override - protected int addSubRegionFields(int x, int y) - { - x = 12; - y += 20; - - int width = 68; - - int nextY = 0; - this.createCoordinateInputs(x, y, width, Corner.CORNER_1); - x += width + 42; - nextY = this.createCoordinateInputs(x, y, width, Corner.CORNER_2); - this.createButton(x + 10, nextY, -1, ButtonListener.Type.ANALYZE_AREA); - x += width + 42; - - x = this.createButton(22, nextY, -1, ButtonListener.Type.CREATE_SCHEMATIC) + 26; - - x = this.createButton(22, nextY + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); - nextY += 22; - this.createButtonOnOff(22, nextY + 22, -1, circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); - - this.addRenderingDisabledWarning(250, 48); - - return y; - } - - @Override - protected Box getBox() - { - // 设置默认位置和名称 - Box selBox = this.selection.getSelectedSubRegionBox(); - this.selection.removeSelectedSubRegionBox(); - if (selBox != null) { - selBox.setName(defaultBoxName); - } else if (this.mc.player != null) { - BlockPos pos = fi.dy.masa.malilib.util.PositionUtils.getEntityBlockPos(this.mc.player); - selBox = new Box(pos, pos, defaultBoxName); - } else { - MaLiLib.logger.error("can not getSelectedSubRegionBox"); - selBox = new Box(); - selBox.setName(defaultBoxName); - } - this.selection.addSubRegionBox(selBox,false); - this.selection.setSelectedSubRegionBox(defaultBoxName); - return selBox; - } - - @Override - protected WidgetListSelectionSubRegions getListWidget() - { - return this.createListWidget(8, 116); - } - - @Override - protected void reCreateListWidget() - { -// super.createListWidget(8,116); - // NO-OP - } - - @Override - protected WidgetListSelectionSubRegions createListWidget(int listX, int listY) - { - return new WidgetListSelectionSubRegions(listX, listY, - this.getBrowserWidth(), this.getBrowserHeight(), this.selection, this); - } -} +//package fi.dy.masa.litematica.gui; +// +//import fi.dy.masa.litematica.data.DataManager; +//import fi.dy.masa.litematica.gui.widgets.WidgetListSelectionSubRegions; +//import fi.dy.masa.litematica.selection.AreaSelection; +//import fi.dy.masa.litematica.selection.Box; +//import fi.dy.masa.litematica.util.PositionUtils.Corner; +//import fi.dy.masa.malilib.MaLiLib; +//import fi.dy.masa.malilib.util.StringUtils; +//import net.minecraft.util.math.BlockPos; +// +//public class GuiAreaSelectionEditorComplex extends GuiAreaSelectionEditorNormal +//{ +// protected static String defaultBoxName = "DefaultComplexBox"; +// +// public GuiAreaSelectionEditorComplex(AreaSelection selection) +// { +// super(selection); +// +// if (DataManager.getSchematicProjectsManager().hasProjectOpen()) +// { +// this.title = StringUtils.translate("litematica.gui.title.area_editor_normal_schematic_projects"); +// } +// else +// { +// this.title = StringUtils.translate("litematica.gui.title.area_editor_complex"); +// } +// } +// +// @Override +// public void initGui() +// { +// super.initGui(); +// +// if (this.selection != null) +// { +// this.createSelectionEditFields(); +// this.addSubRegionFields(this.xOrigin, this.yNext); +// this.updateCheckBoxes(); +// } +// else +// { +// this.addLabel(20, 30, 120, 12, 0xFFFFAA00, StringUtils.translate("litematica.error.area_editor.no_selection")); +// } +// } +// +// +// @Override +// protected int addSubRegionFields(int x, int y) +// { +// x = 12; +// y += 20; +// +// int width = 68; +// +// int nextY = 0; +// this.createCoordinateInputs(x, y, width, Corner.CORNER_1); +// x += width + 42; +// nextY = this.createCoordinateInputs(x, y, width, Corner.CORNER_2); +// this.createButton(x + 10, nextY, -1, ButtonListener.Type.ANALYZE_AREA); +// x += width + 42; +// +// x = this.createButton(22, nextY, -1, ButtonListener.Type.CREATE_SCHEMATIC) + 26; +// +// x = this.createButton(22, nextY + 22, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); +// nextY += 22; +// this.createButtonOnOff(22, nextY + 22, -1, circleMode, ButtonListener.Type.TOGGLE_CIRCLE_ENABLED); +// +// this.addRenderingDisabledWarning(250, 48); +// +// return y; +// } +// +// @Override +// protected Box getBox() +// { +// // 设置默认位置和名称 +// Box selBox = this.selection.getSelectedSubRegionBox(); +// this.selection.removeSelectedSubRegionBox(); +// if (selBox != null) { +// selBox.setName(defaultBoxName); +// } else if (this.mc.player != null) { +// BlockPos pos = fi.dy.masa.malilib.util.PositionUtils.getEntityBlockPos(this.mc.player); +// selBox = new Box(pos, pos, defaultBoxName); +// } else { +// MaLiLib.logger.error("can not getSelectedSubRegionBox"); +// selBox = new Box(); +// selBox.setName(defaultBoxName); +// } +// this.selection.addSubRegionBox(selBox,false); +// this.selection.setSelectedSubRegionBox(defaultBoxName); +// return selBox; +// } +// +// @Override +// protected WidgetListSelectionSubRegions getListWidget() +// { +// return this.createListWidget(8, 116); +// } +// +// @Override +// protected void reCreateListWidget() +// { +//// super.createListWidget(8,116); +// // NO-OP +// } +// +// @Override +// protected WidgetListSelectionSubRegions createListWidget(int listX, int listY) +// { +// return new WidgetListSelectionSubRegions(listX, listY, +// this.getBrowserWidth(), this.getBrowserHeight(), this.selection, this); +// } +//} diff --git a/src/main/java/fi/dy/masa/litematica/render/infohud/ToolHud.java b/src/main/java/fi/dy/masa/litematica/render/infohud/ToolHud.java index 30d469a5ee..26b95fe179 100644 --- a/src/main/java/fi/dy/masa/litematica/render/infohud/ToolHud.java +++ b/src/main/java/fi/dy/masa/litematica/render/infohud/ToolHud.java @@ -165,10 +165,6 @@ protected void updateHudText() { lines.add(StringUtils.translate("litematica.hud.area_selection.selected_area_normal", name)); } - else if (sm.getSelectionMode() == SelectionMode.COMPLEX) - { - lines.add(StringUtils.translate("litematica.hud.area_selection.selected_area_complex", name)); - } else { lines.add(StringUtils.translate("litematica.hud.area_selection.selected_area_simple", name)); diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java index aeee6c2457..6ed0d40013 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionManager.java @@ -8,7 +8,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import fi.dy.masa.litematica.gui.GuiAreaSelectionEditorComplex; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.entity.Entity; @@ -719,18 +718,6 @@ public GuiBase getEditGui() return null; } } - else if (this.getSelectionMode() == SelectionMode.COMPLEX) - { - if (selection != null) - { - return new GuiAreaSelectionEditorComplex(selection); - } - else - { - InfoUtils.showGuiOrActionBarMessage(MessageType.WARNING, "litematica.error.area_editor.open_gui.no_selection_complex"); - return null; - } - } else { return new GuiAreaSelectionEditorSimple(selection); diff --git a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java index eb2f2a44e5..f82baff2ef 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java +++ b/src/main/java/fi/dy/masa/litematica/selection/SelectionMode.java @@ -5,7 +5,6 @@ public enum SelectionMode { NORMAL ("litematica.gui.label.area_selection.mode.normal"), - COMPLEX ("litematica.gui.label.area_selection.mode.complex"), SIMPLE ("litematica.gui.label.area_selection.mode.simple"); private final String translationKey; diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index 8b0b87d120..fafaff5de7 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -801,7 +801,6 @@ "litematica.gui.title.area_editor_normal": "Area Editor (Normal/Multi-box mode)", "litematica.gui.title.area_editor_normal_schematic_projects": "Area Editor (§6§lSchematic VCS area§r)", "litematica.gui.title.area_editor_simple": "Area Editor (Simple mode)", - "litematica.gui.title.area_editor_complex": "Area Editor (Complex mode)", "litematica.gui.title.area_editor_sub_region": "Area Editor (sub-region)", "litematica.gui.title.area_editor.sub_region_name": "Sub-region name", "litematica.gui.title.area_selection_manager": "Area Selection Manager", @@ -849,7 +848,6 @@ "litematica.hud.area_selection.origin": "Origin: %s", "litematica.hud.area_selection.selected_area_normal": "Area: %s", "litematica.hud.area_selection.selected_area_simple": "Area [§6Simple mode§r]: %s", - "litematica.hud.area_selection.selected_area_complex": "Area [§6Complex mode§r]: %s", "litematica.hud.area_selection.selected_sub_region": "Sub-region: %s", "litematica.hud.area_selection.selection_corners_mode": "Corners Mode: %s", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 59e846351f..78a356f4c6 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -470,7 +470,6 @@ "litematica.error.area_editor.create_sub_region.exists": "名为'%s' 子区域已经存在", "litematica.error.area_editor.no_selection": "无活动区域的选择", "litematica.error.area_editor.open_gui.no_selection": "当前处于选择模式:Normal,但当前未选择任何区域", - "litematica.error.area_editor.open_gui.no_selection_complex": "当前处于选择模式:Complex,但当前未选择任何区域", "litematica.error.area_editor.rename_sub_region.exists": "重命名子区域失败\n已存在子区域名字为 '%s'", "litematica.error.area_editor.switch_mode.no_selection": "无法切换到选择模式:Normal,因为当前没有选择区域.\n请在区域选择浏览器中选择一个区域或创建一个新的选择", @@ -676,7 +675,6 @@ "litematica.gui.label.area_selection_box_count": "框数: %d", "litematica.gui.label.area_selection_origin": "原点: %s", "litematica.gui.label.area_selection.mode.normal": "正常", - "litematica.gui.label.area_selection.mode.complex": "复合", "litematica.gui.label.area_selection.mode.simple": "简单", "litematica.gui.label.block_info.state_client": "客户端世界的方块信息", @@ -802,7 +800,6 @@ "litematica.gui.title.area_editor_normal": "区域编辑器(普通/多框模式)", "litematica.gui.title.area_editor_normal_schematic_projects": "区域编辑器 (§6§l图形项目区域§r)", "litematica.gui.title.area_editor_simple": "区域编辑器 (简单模式)", - "litematica.gui.title.area_editor_complex": "区域编辑器 (复合模式)", "litematica.gui.title.area_editor_sub_region": "区域编辑器 (子区域)", "litematica.gui.title.area_editor.sub_region_name": "子区域名称", "litematica.gui.title.area_selection_manager": "区域选择管理器", @@ -850,7 +847,6 @@ "litematica.hud.area_selection.origin": "原点: %s", "litematica.hud.area_selection.selected_area_normal": "区域: %s", "litematica.hud.area_selection.selected_area_simple": "区域 [§6简单模式§r]: %s", - "litematica.hud.area_selection.selected_area_complex": "区域 [§6复合模式§r]: %s", "litematica.hud.area_selection.selected_sub_region": "子区域: %s", "litematica.hud.area_selection.selection_corners_mode": "角点模式: %s", From 1ce273e0461e649490c527d23716224854a3d30a Mon Sep 17 00:00:00 2001 From: PunChen Date: Sat, 17 May 2025 04:29:17 +0800 Subject: [PATCH 6/9] add special mode to normal mode to generate circle and round-- todo optimize circle mode --- .../gui/GuiAreaSelectionEditorNormal.java | 65 +++++++++-- .../litematica/selection/AreaSelection.java | 107 +++++++++++++++--- .../assets/litematica/lang/en_us.json | 3 +- .../assets/litematica/lang/zh_cn.json | 5 +- 4 files changed, 148 insertions(+), 32 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java index 995492abf0..8ee07f234d 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java @@ -51,9 +51,10 @@ public class GuiAreaSelectionEditorNormal extends GuiListBase boxList = new ArrayList<>(); - String currentBoxName = this.getCurrentSubRegionBoxName(); - Box curBox = this.getSubRegionBox(currentBox); - this.subRegionBoxes.clear(); - this.subRegionBoxes.put(currentBoxName, curBox);// 不删除当前选区 + public String createNewSubRegionBoxRound(BlockPos cor1, BlockPos cor2) { + try { + double offset = 0.0; + double c1x = cor1.getX() + offset; + double c1z = cor1.getZ() + offset; + double c1y = cor1.getY() + offset; + double c2x = cor2.getX() + offset; + double c2z = cor2.getZ() + offset; + double c2y = cor2.getY() + offset; + + double dis2 = calculateDistance2(c1x, c1z, c2x, c2z); + double dis = Math.sqrt(dis2); + double startX = c1x; + double startZ = c1z + Math.round(dis); + List posList = new ArrayList<>(); + posList.add(new double[]{startX, startZ}); + // 1/4圆 + MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); + while(startZ > c1z) { + double[][] nextPos = {{startX + 1, startZ}, {startX + 1, startZ - 1}, {startX, startZ - 1}}; + double[] disSquare = new double[3]; + disSquare[0] = Math.abs(calculateDistance2(nextPos[0][0], nextPos[0][1], c1x, c1z) - dis2); + disSquare[1] = Math.abs(calculateDistance2(nextPos[1][0], nextPos[1][1], c1x, c1z) - dis2); + disSquare[2] = Math.abs(calculateDistance2(nextPos[2][0], nextPos[2][1], c1x, c1z) - dis2); + int minIndex = 0; + double minDisSquare = Double.MAX_VALUE; + for (int i = 0; i < 3; ++i) { + if (disSquare[i] < minDisSquare) { + minDisSquare = disSquare[i]; + minIndex = i; + } + } + startX = nextPos[minIndex][0]; + startZ = nextPos[minIndex][1]; + posList.add(new double[]{startX, startZ}); + } + //关于x轴对称 1/2圆 + /* + ^z + | + |_____>x + (c1x,c1z) + */ + List newPosList = new ArrayList<>(); + for (double[] pos : posList) { + double syncPosX = pos[0]; + double syncPosZ = 2 * c1z - pos[1]; + newPosList.add(new double[]{syncPosX, syncPosZ}); + } + posList.addAll(newPosList); + //关于z轴对称 整个圆 + for (double[] pos : posList) { + double curX = (int) pos[0]; + double curZ = (int) pos[1]; + double syncPosX = (int) (2 * c1x - pos[0]); + double syncPosZ = (int) (pos[1]); + + BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); + BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); + // 添加到多选区域列表中 + String name1 = "z1_" + (int)curZ; + String name2 = "z2_" + (int)curZ; + addOneBox(pos1,pos1,name1); + addOneBox(pos2,pos2,name2); + MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); + } + MaLiLib.logger.error(String.format("createNewSubRegionBoxRound boxList size: %s", posList.size())); + } catch (Exception e) { + MaLiLib.logger.error("createNewSubRegionBoxRound ", e); + } + return "createNewSubRegionBoxRound"; + } + + protected void addOneBox(BlockPos pos1, BlockPos pos2,String name) { + Box box = new Box(); + box.setSelectedCorner(Corner.CORNER_1); + box.setName(name); + this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); + this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); + this.subRegionBoxes.put(name, box); + } + + @Nullable + public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2) { try { double offset = 0.0; double c1x = cor1.getX() + offset; @@ -271,31 +349,24 @@ public String createNewSubRegionBoxBatch(BlockPos cor1, BlockPos cor2) { } posList.addAll(newPosList); //关于z轴对称 整个圆 - Box box = null; for (double[] pos : posList) { double curX = (int) pos[0]; double curZ = (int) pos[1]; double syncPosX = (int) (2 * c1x - pos[0]); double syncPosZ = (int) (pos[1]); - box = new Box(); BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); // 添加到多选区域列表中 - String name = "z" + (int)curZ; - box.setSelectedCorner(Corner.CORNER_1); - box.setName(name); - this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); - this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); - this.subRegionBoxes.put(name, box); - boxList.add(box); + String name = "z0_" + (int)curZ; + addOneBox(pos1, pos2, name); MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); } - MaLiLib.logger.error(String.format("boxList size: %s", boxList.size())); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle boxList size: %s", posList.size())); } catch (Exception e) { - MaLiLib.logger.error("createNewSubRegionBoxBatch ", e); + MaLiLib.logger.error("createNewSubRegionBoxCircle ", e); } - return "createNewSubRegionBoxBatch"; + return "createNewSubRegionBoxCircle"; } public void clearCurrentSelectedCorner() diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index fafaff5de7..dfab01d84b 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -534,7 +534,8 @@ "litematica.gui.button.area_editor.create_sub_region": "New sub-region", "litematica.gui.button.area_editor.origin_enabled": "Manual Origin: %s", "litematica.gui.button.area_editor.generate_circle": "Generate Circle", - "litematica.gui.button.area_editor.circle_enabled": "Circle Mode: %s", + "litematica.gui.button.area_editor.generate_round": "Generate Round", + "litematica.gui.button.area_editor.special_enabled": "Special Mode: %s", "litematica.gui.button.area_editor.set_box_name": "Set", "litematica.gui.button.area_editor.set_selection_name": "Set", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 78a356f4c6..219b2e0792 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -533,8 +533,9 @@ "litematica.gui.button.area_editor.create_schematic": "保存原理图", "litematica.gui.button.area_editor.create_sub_region": "新建子区域", "litematica.gui.button.area_editor.origin_enabled": "手动来源:%s", - "litematica.gui.button.area_editor.generate_circle": "生成圆形", - "litematica.gui.button.area_editor.circle_enabled": "圆形模式:%s", + "litematica.gui.button.area_editor.generate_circle": "生成圆圈", + "litematica.gui.button.area_editor.generate_round": "生成圆面", + "litematica.gui.button.area_editor.special_enabled": "特殊模式:%s", "litematica.gui.button.area_editor.set_box_name": "set", "litematica.gui.button.area_editor.set_selection_name": "set", From d6a820ef23b44c421cdded77196f0980d0af49a4 Mon Sep 17 00:00:00 2001 From: PunChen Date: Sun, 18 May 2025 02:47:35 +0800 Subject: [PATCH 7/9] use more efficiency algorithm, but can not use two circles for iron wall --- .../gui/GuiAreaSelectionEditorNormal.java | 10 +- .../litematica/selection/AreaSelection.java | 135 ++++++++++++------ .../assets/litematica/lang/en_us.json | 1 + .../assets/litematica/lang/zh_cn.json | 1 + 4 files changed, 105 insertions(+), 42 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java index 8ee07f234d..67fb67a767 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java @@ -188,7 +188,8 @@ protected void addCurrentSelectCorner(int curX, int curY) { this.createButton(curX, curY, -1, ButtonListener.Type.TOGGLE_GENERATE_CIRCLE); curY += 22; this.createButton(curX, curY, -1, ButtonListener.Type.TOGGLE_GENERATE_ROUND); - + curY += 22; + this.createButton(curX, curY, -1, ButtonListener.Type.TOGGLE_REMOVE_ALL_REGION); } protected void addRenderingDisabledWarning(int x, int y) @@ -619,9 +620,13 @@ public void actionPerformedWithButton(ButtonBase button, int mouseButton) } break; case TOGGLE_SPECIAL_ENABLED: - MaLiLib.logger.error("click TOGGLE_SPECIAL_ENABLED"); + MaLiLib.logger.error("click TOGGLE_SPECIAL_ENABLED " + specialMode); specialMode = !specialMode; break; + case TOGGLE_REMOVE_ALL_REGION: + MaLiLib.logger.error("click TOGGLE_REMOVE_ALL_REGION " + specialMode); + this.parent.selection.removeAllSubRegionBoxes(); + break; } this.parent.initGui(); // Re-create buttons/text fields @@ -635,6 +640,7 @@ public enum Type TOGGLE_SPECIAL_ENABLED ("litematica.gui.button.area_editor.special_enabled"), TOGGLE_GENERATE_CIRCLE ("litematica.gui.button.area_editor.generate_circle"), TOGGLE_GENERATE_ROUND ("litematica.gui.button.area_editor.generate_round"), + TOGGLE_REMOVE_ALL_REGION ("litematica.gui.button.area_editor.remove_all_region"), CREATE_SUB_REGION ("litematica.gui.button.area_editor.create_sub_region"), CREATE_SCHEMATIC ("litematica.gui.button.area_editor.create_schematic"), ANALYZE_AREA ("litematica.gui.button.area_editor.analyze_area"), diff --git a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java index 94780cb001..f50e47a7a4 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java +++ b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java @@ -275,10 +275,8 @@ public String createNewSubRegionBoxRound(BlockPos cor1, BlockPos cor2) { BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); // 添加到多选区域列表中 - String name1 = "z1_" + (int)curZ; - String name2 = "z2_" + (int)curZ; - addOneBox(pos1,pos1,name1); - addOneBox(pos2,pos2,name2); + String name = "z0_" + (int)curZ; + addOneBox(pos1,pos2,name); MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); } MaLiLib.logger.error(String.format("createNewSubRegionBoxRound boxList size: %s", posList.size())); @@ -292,11 +290,51 @@ protected void addOneBox(BlockPos pos1, BlockPos pos2,String name) { Box box = new Box(); box.setSelectedCorner(Corner.CORNER_1); box.setName(name); - this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); - this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); + box.setPos1(pos1); + box.setPos2(pos2); +// this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); +// this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); this.subRegionBoxes.put(name, box); } + protected int[][] directions = new int[][]{ + {1, 1}, + {1, 0}, + {1, -1}, + {0, -1}, +// {0, 0}, + {-1, 1}, + {-1, 0}, + {-1, 1}, + {0, 1}, + }; + protected int nextCircleBlock(int curX, int curZ, int centerX, int centerZ, double dis2, Set positionSets) { + int closestDir = -1; + double closestDis = Double.MAX_VALUE; + for(int ind = 0; ind < directions.length; ++ind) { + int[] dir = directions[ind]; + int nextX = curX + dir[0]; + int nextZ = curZ + dir[1]; + double dis2ToCenter = calculateDistance2(nextX + 0.5, nextZ+0.5, centerX, centerZ); + double dis = Math.abs(dis2ToCenter - dis2); + System.out.printf("dis: %s dis2:%s nextX:%s nextZ:%s", dis, dis2, nextX, nextZ); + if (closestDis > dis && !positionSets.contains(makeKey(nextX, nextZ))) { + closestDis = dis; + closestDir = ind; + } + } + return closestDir; + } + + protected String makeKey(int x, int z) { + return String.format("%s#%s", x, z); + } + + public void removeAllSubRegion() { + Box currentSelected = this.getSelectedSubRegionBox(); + this.subRegionBoxes.clear(); + this.addSubRegionBox(currentSelected, false); + } @Nullable public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2) { try { @@ -309,30 +347,42 @@ public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2) { double c2y = cor2.getY() + offset; double dis2 = calculateDistance2(c1x, c1z, c2x, c2z); - double dis = Math.sqrt(dis2); - double startX = c1x; - double startZ = c1z + Math.round(dis); +// double dis = Math.sqrt(dis2); +// double startX = c1x; +// double startZ = c1z + Math.floor(dis); List posList = new ArrayList<>(); - posList.add(new double[]{startX, startZ}); - // 1/4圆 - MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); - while(startZ > c1z) { - double[][] nextPos = {{startX + 1, startZ}, {startX + 1, startZ - 1}, {startX, startZ - 1}}; - double[] disSquare = new double[3]; - disSquare[0] = Math.abs(calculateDistance2(nextPos[0][0], nextPos[0][1], c1x, c1z) - dis2); - disSquare[1] = Math.abs(calculateDistance2(nextPos[1][0], nextPos[1][1], c1x, c1z) - dis2); - disSquare[2] = Math.abs(calculateDistance2(nextPos[2][0], nextPos[2][1], c1x, c1z) - dis2); - int minIndex = 0; - double minDisSquare = Double.MAX_VALUE; - for (int i = 0; i < 3; ++i) { - if (disSquare[i] < minDisSquare) { - minDisSquare = disSquare[i]; - minIndex = i; - } +// posList.add(new double[]{startX, startZ}); +// // 1/4圆 +// MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); + + // 1/8 circle + double R = Math.sqrt(dis2); + double pLast = -2 * R + 3; + double pNext; + double curX = c1x + R; + double curZ = c1z; + posList.add(new double[]{curX, curZ}); + while (curX - c1x >= curZ - c1z) { + if (pLast >= 0) { + pNext = pLast - 4 * (curX - c1x) + 4 * (curZ - c1z) + 10; + pLast = pNext; + curX = curX - 1; + curZ = curZ + 1; + } else { + pNext = pLast + 4 * (curZ - c1z) + 6; + pLast = pNext; + curX = curX; + curZ = curZ + 1; } - startX = nextPos[minIndex][0]; - startZ = nextPos[minIndex][1]; - posList.add(new double[]{startX, startZ}); + posList.add(new double[]{curX, curZ}); + } + // 1/4圆 + int len = posList.size(); + for (int i = 0; i < len; i++) { + double[] curPos = posList.get(i); + double nX = curPos[1] - c1z + c1x; + double nZ = curPos[0] - c1x + c1z; + posList.add(new double[]{nX, nZ}); } //关于x轴对称 1/2圆 /* @@ -341,34 +391,39 @@ public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2) { |_____>x (c1x,c1z) */ - List newPosList = new ArrayList<>(); - for (double[] pos : posList) { + len = posList.size(); + for (int i = 0; i < len; i++) { + double[] pos = posList.get(i); double syncPosX = pos[0]; double syncPosZ = 2 * c1z - pos[1]; - newPosList.add(new double[]{syncPosX, syncPosZ}); + posList.add(new double[]{syncPosX, syncPosZ}); } - posList.addAll(newPosList); //关于z轴对称 整个圆 for (double[] pos : posList) { - double curX = (int) pos[0]; - double curZ = (int) pos[1]; + curX = pos[0]; + curZ = pos[1]; double syncPosX = (int) (2 * c1x - pos[0]); double syncPosZ = (int) (pos[1]); - - BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); - BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); + BlockPos pos1 = new BlockPos((int) curX, (int) c1y, (int) curZ); + BlockPos pos2 = new BlockPos((int) syncPosX, (int) c2y, (int) syncPosZ); // 添加到多选区域列表中 - String name = "z0_" + (int)curZ; - addOneBox(pos1, pos2, name); + addOneBox(pos1, pos1, makeKey((int) curX, (int) curZ)); + addOneBox(pos2, pos2, makeKey((int) syncPosX, (int) syncPosZ)); MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); } - MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle boxList size: %s", posList.size())); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle posList size: %s", posList.size())); } catch (Exception e) { MaLiLib.logger.error("createNewSubRegionBoxCircle ", e); } return "createNewSubRegionBoxCircle"; } + public static void main(String[] args) { + BlockPos pos1 = new BlockPos(0,0,0); + BlockPos pos2 = new BlockPos(0,0,4); + new AreaSelection().createNewSubRegionBoxCircle(pos1, pos2); + } + public void clearCurrentSelectedCorner() { this.setCurrentSelectedCorner(Corner.NONE); diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index dfab01d84b..c143d475fb 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -535,6 +535,7 @@ "litematica.gui.button.area_editor.origin_enabled": "Manual Origin: %s", "litematica.gui.button.area_editor.generate_circle": "Generate Circle", "litematica.gui.button.area_editor.generate_round": "Generate Round", + "litematica.gui.button.area_editor.remove_all_region": "Remove All SubRegion", "litematica.gui.button.area_editor.special_enabled": "Special Mode: %s", "litematica.gui.button.area_editor.set_box_name": "Set", "litematica.gui.button.area_editor.set_selection_name": "Set", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 219b2e0792..6f187955d3 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -535,6 +535,7 @@ "litematica.gui.button.area_editor.origin_enabled": "手动来源:%s", "litematica.gui.button.area_editor.generate_circle": "生成圆圈", "litematica.gui.button.area_editor.generate_round": "生成圆面", + "litematica.gui.button.area_editor.remove_all_region": "删除所有子区域", "litematica.gui.button.area_editor.special_enabled": "特殊模式:%s", "litematica.gui.button.area_editor.set_box_name": "set", "litematica.gui.button.area_editor.set_selection_name": "set", From 87516e52371f88fa8755ebdd84fc4a469730b234 Mon Sep 17 00:00:00 2001 From: PunChen Date: Sun, 18 May 2025 08:17:37 +0800 Subject: [PATCH 8/9] add circle drawing, need fix rendering --- .../gui/GuiAreaSelectionEditorNormal.java | 14 +- .../litematica/selection/AreaSelection.java | 231 ++++++------------ .../assets/litematica/lang/en_us.json | 1 + .../assets/litematica/lang/zh_cn.json | 1 + 4 files changed, 89 insertions(+), 158 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java index 67fb67a767..1672adbe9f 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiAreaSelectionEditorNormal.java @@ -52,6 +52,7 @@ public class GuiAreaSelectionEditorNormal extends GuiListBase posList = new ArrayList<>(); posList.add(new double[]{startX, startZ}); // 1/4圆 - MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); - while(startZ > c1z) { + while (startZ > c1z) { double[][] nextPos = {{startX + 1, startZ}, {startX + 1, startZ - 1}, {startX, startZ - 1}}; - double[] disSquare = new double[3]; - disSquare[0] = Math.abs(calculateDistance2(nextPos[0][0], nextPos[0][1], c1x, c1z) - dis2); - disSquare[1] = Math.abs(calculateDistance2(nextPos[1][0], nextPos[1][1], c1x, c1z) - dis2); - disSquare[2] = Math.abs(calculateDistance2(nextPos[2][0], nextPos[2][1], c1x, c1z) - dis2); - int minIndex = 0; double minDisSquare = Double.MAX_VALUE; - for (int i = 0; i < 3; ++i) { - if (disSquare[i] < minDisSquare) { - minDisSquare = disSquare[i]; - minIndex = i; + for (int i = 0; i < 3; i++) { + double disSquare = Math.abs(calculateDistance2(nextPos[i][0], nextPos[i][1], c1x, c1z) - dis2); + if (disSquare < minDisSquare) { + minDisSquare = disSquare; + startX = nextPos[i][0]; + startZ = nextPos[i][1]; } } - startX = nextPos[minIndex][0]; - startZ = nextPos[minIndex][1]; posList.add(new double[]{startX, startZ}); } //关于x轴对称 1/2圆 - /* - ^z - | - |_____>x - (c1x,c1z) - */ - List newPosList = new ArrayList<>(); - for (double[] pos : posList) { + int len = posList.size(); + for (int i = 0; i < len; ++i) { + double[] pos = posList.get(i); double syncPosX = pos[0]; double syncPosZ = 2 * c1z - pos[1]; - newPosList.add(new double[]{syncPosX, syncPosZ}); + posList.add(new double[]{syncPosX, syncPosZ}); } - posList.addAll(newPosList); //关于z轴对称 整个圆 + Set seenPosLongSet = new HashSet<>(); for (double[] pos : posList) { double curX = (int) pos[0]; double curZ = (int) pos[1]; double syncPosX = (int) (2 * c1x - pos[0]); double syncPosZ = (int) (pos[1]); - BlockPos pos1 = new BlockPos((int) curX, (int)c1y, (int) curZ); - BlockPos pos2 = new BlockPos((int) syncPosX, (int)c2y, (int) syncPosZ); + int c1Y = (int) c1y; + int c2Y = (int) c2y; + + BlockPos pos1 = new BlockPos((int) curX, c1Y, (int) curZ); + BlockPos pos2 = new BlockPos((int) syncPosX, c2Y, (int) syncPosZ); // 添加到多选区域列表中 - String name = "z0_" + (int)curZ; - addOneBox(pos1,pos2,name); + if (onCircle) {//仅创建圆上节点,考虑y坐标 + BlockPos pos11 = new BlockPos(pos1.getX(), c1Y, pos1.getZ()); + BlockPos pos12 = new BlockPos(pos1.getX(), c2Y, pos1.getZ()); + addOneBox(pos11, pos12, makeKey(pos1.getX(), pos1.getZ())); + + BlockPos pos21 = new BlockPos(pos2.getX(), c1Y, pos2.getZ()); + BlockPos pos22 = new BlockPos(pos2.getX(), c2Y, pos2.getZ()); + addOneBox(pos21, pos22, makeKey(pos2.getX(), pos2.getZ())); + if (expand) { + seenPosLongSet.add(pos1.asLong()); + seenPosLongSet.add(pos2.asLong()); + expandPos(pos1, c1Y, c2Y,seenPosLongSet); + expandPos(pos2, c1Y, c2Y,seenPosLongSet); + } + } else { + String name = "z_" + (int) curZ;// 按照z轴坐标去重 + addOneBox(pos1, pos2, name); + } MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); } - MaLiLib.logger.error(String.format("createNewSubRegionBoxRound boxList size: %s", posList.size())); + seenPosLongSet.clear(); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle boxList size: %s", posList.size())); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle subRegionBoxes size: %s", this.subRegionBoxes.size())); } catch (Exception e) { - MaLiLib.logger.error("createNewSubRegionBoxRound ", e); + MaLiLib.logger.error("createNewSubRegionBoxCircle ", e); } - return "createNewSubRegionBoxRound"; + return "createNewSubRegionBoxCircle"; } + protected int[][] DIRECTIONS = new int[][]{{0,1},{1,0},{0,-1},{-1,0}}; + + protected void expandPos(BlockPos pos, int c1Y, int c2Y,Set seenPosLongSet) { + for (int[] dir : DIRECTIONS) { + BlockPos nextPos = new BlockPos(pos.getX() + dir[0], pos.getY(), pos.getZ() + dir[1]); + if (seenPosLongSet.contains(nextPos.asLong())) { + continue; + } + seenPosLongSet.add(nextPos.asLong()); + BlockPos pos1 = new BlockPos(nextPos.getX(),c1Y, nextPos.getZ()); + BlockPos pos2 = new BlockPos(nextPos.getX(),c2Y, nextPos.getZ()); + addOneBox(pos1, pos2,makeKey(nextPos.getX(), nextPos.getZ())); + } + } protected void addOneBox(BlockPos pos1, BlockPos pos2,String name) { Box box = new Box(); box.setSelectedCorner(Corner.CORNER_1); box.setName(name); - box.setPos1(pos1); - box.setPos2(pos2); -// this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); -// this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); + this.setSubRegionCornerPos(box, Corner.CORNER_1, pos1); + this.setSubRegionCornerPos(box, Corner.CORNER_2, pos2); this.subRegionBoxes.put(name, box); } - protected int[][] directions = new int[][]{ - {1, 1}, - {1, 0}, - {1, -1}, - {0, -1}, -// {0, 0}, - {-1, 1}, - {-1, 0}, - {-1, 1}, - {0, 1}, - }; - protected int nextCircleBlock(int curX, int curZ, int centerX, int centerZ, double dis2, Set positionSets) { - int closestDir = -1; - double closestDis = Double.MAX_VALUE; - for(int ind = 0; ind < directions.length; ++ind) { - int[] dir = directions[ind]; - int nextX = curX + dir[0]; - int nextZ = curZ + dir[1]; - double dis2ToCenter = calculateDistance2(nextX + 0.5, nextZ+0.5, centerX, centerZ); - double dis = Math.abs(dis2ToCenter - dis2); - System.out.printf("dis: %s dis2:%s nextX:%s nextZ:%s", dis, dis2, nextX, nextZ); - if (closestDis > dis && !positionSets.contains(makeKey(nextX, nextZ))) { - closestDis = dis; - closestDir = ind; - } - } - return closestDir; + + protected String makeKey(int x, int y, int z) { + return String.format("%s_%s_%s", x, y, z); } - protected String makeKey(int x, int z) { - return String.format("%s#%s", x, z); + protected String makeKey(int x,int z) { + return String.format("%s_%s", x, z); } public void removeAllSubRegion() { @@ -335,93 +338,11 @@ public void removeAllSubRegion() { this.subRegionBoxes.clear(); this.addSubRegionBox(currentSelected, false); } - @Nullable - public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2) { - try { - double offset = 0.0; - double c1x = cor1.getX() + offset; - double c1z = cor1.getZ() + offset; - double c1y = cor1.getY() + offset; - double c2x = cor2.getX() + offset; - double c2z = cor2.getZ() + offset; - double c2y = cor2.getY() + offset; - - double dis2 = calculateDistance2(c1x, c1z, c2x, c2z); -// double dis = Math.sqrt(dis2); -// double startX = c1x; -// double startZ = c1z + Math.floor(dis); - List posList = new ArrayList<>(); -// posList.add(new double[]{startX, startZ}); -// // 1/4圆 -// MaLiLib.logger.error(String.format("startZ:%s, endZ:%s, dis:%s", startZ, c1z, dis)); - - // 1/8 circle - double R = Math.sqrt(dis2); - double pLast = -2 * R + 3; - double pNext; - double curX = c1x + R; - double curZ = c1z; - posList.add(new double[]{curX, curZ}); - while (curX - c1x >= curZ - c1z) { - if (pLast >= 0) { - pNext = pLast - 4 * (curX - c1x) + 4 * (curZ - c1z) + 10; - pLast = pNext; - curX = curX - 1; - curZ = curZ + 1; - } else { - pNext = pLast + 4 * (curZ - c1z) + 6; - pLast = pNext; - curX = curX; - curZ = curZ + 1; - } - posList.add(new double[]{curX, curZ}); - } - // 1/4圆 - int len = posList.size(); - for (int i = 0; i < len; i++) { - double[] curPos = posList.get(i); - double nX = curPos[1] - c1z + c1x; - double nZ = curPos[0] - c1x + c1z; - posList.add(new double[]{nX, nZ}); - } - //关于x轴对称 1/2圆 - /* - ^z - | - |_____>x - (c1x,c1z) - */ - len = posList.size(); - for (int i = 0; i < len; i++) { - double[] pos = posList.get(i); - double syncPosX = pos[0]; - double syncPosZ = 2 * c1z - pos[1]; - posList.add(new double[]{syncPosX, syncPosZ}); - } - //关于z轴对称 整个圆 - for (double[] pos : posList) { - curX = pos[0]; - curZ = pos[1]; - double syncPosX = (int) (2 * c1x - pos[0]); - double syncPosZ = (int) (pos[1]); - BlockPos pos1 = new BlockPos((int) curX, (int) c1y, (int) curZ); - BlockPos pos2 = new BlockPos((int) syncPosX, (int) c2y, (int) syncPosZ); - // 添加到多选区域列表中 - addOneBox(pos1, pos1, makeKey((int) curX, (int) curZ)); - addOneBox(pos2, pos2, makeKey((int) syncPosX, (int) syncPosZ)); - MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); - } - MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle posList size: %s", posList.size())); - } catch (Exception e) { - MaLiLib.logger.error("createNewSubRegionBoxCircle ", e); - } - return "createNewSubRegionBoxCircle"; - } public static void main(String[] args) { BlockPos pos1 = new BlockPos(0,0,0); BlockPos pos2 = new BlockPos(0,0,4); - new AreaSelection().createNewSubRegionBoxCircle(pos1, pos2); + new AreaSelection().createNewSubRegionBoxCircle(pos1, pos2, true, true); } public void clearCurrentSelectedCorner() diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index c143d475fb..7ad9896dd6 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -537,6 +537,7 @@ "litematica.gui.button.area_editor.generate_round": "Generate Round", "litematica.gui.button.area_editor.remove_all_region": "Remove All SubRegion", "litematica.gui.button.area_editor.special_enabled": "Special Mode: %s", + "litematica.gui.button.area_editor.expand_circle_enabled": "Expand Circle: %s", "litematica.gui.button.area_editor.set_box_name": "Set", "litematica.gui.button.area_editor.set_selection_name": "Set", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 6f187955d3..195399190a 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -537,6 +537,7 @@ "litematica.gui.button.area_editor.generate_round": "生成圆面", "litematica.gui.button.area_editor.remove_all_region": "删除所有子区域", "litematica.gui.button.area_editor.special_enabled": "特殊模式:%s", + "litematica.gui.button.area_editor.expand_circle_enabled": "圆圈扩展:%s", "litematica.gui.button.area_editor.set_box_name": "set", "litematica.gui.button.area_editor.set_selection_name": "set", From 251c70189d104094c6144f38d6024db3c2d9d12b Mon Sep 17 00:00:00 2001 From: PunChen Date: Sun, 18 May 2025 21:58:01 +0800 Subject: [PATCH 9/9] add circle drawing, optimize box merging, reduce box numbers --- .../litematica/render/OverlayRenderer.java | 1 + .../litematica/selection/AreaSelection.java | 183 ++++++++++++++++-- 2 files changed, 168 insertions(+), 16 deletions(-) diff --git a/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java b/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java index a1e33d4cd8..e2eb22c4c9 100644 --- a/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java +++ b/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableMap; +import fi.dy.masa.malilib.MaLiLib; import org.joml.Matrix4f; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.block.BlockState; diff --git a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java index 81615ba7b6..cbf04cb588 100644 --- a/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java +++ b/src/main/java/fi/dy/masa/litematica/selection/AreaSelection.java @@ -1,15 +1,10 @@ package fi.dy.masa.litematica.selection; import java.util.*; -import java.util.function.Consumer; import java.util.function.Function; import javax.annotation.Nullable; import fi.dy.masa.malilib.MaLiLib; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import net.minecraft.block.Block; -import net.minecraft.block.BlockKeys; -import net.minecraft.util.math.Vec3d; import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -260,6 +255,7 @@ public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2, boolean } //关于z轴对称 整个圆 Set seenPosLongSet = new HashSet<>(); + List boxList = new ArrayList<>(); for (double[] pos : posList) { double curX = (int) pos[0]; double curZ = (int) pos[1]; @@ -275,25 +271,40 @@ public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2, boolean if (onCircle) {//仅创建圆上节点,考虑y坐标 BlockPos pos11 = new BlockPos(pos1.getX(), c1Y, pos1.getZ()); BlockPos pos12 = new BlockPos(pos1.getX(), c2Y, pos1.getZ()); - addOneBox(pos11, pos12, makeKey(pos1.getX(), pos1.getZ())); + boxList.add(new Box(pos11, pos12, makeKey(pos1.getX(), pos1.getZ()))); +// addOneBox(pos11, pos12, makeKey(pos1.getX(), pos1.getZ())); BlockPos pos21 = new BlockPos(pos2.getX(), c1Y, pos2.getZ()); BlockPos pos22 = new BlockPos(pos2.getX(), c2Y, pos2.getZ()); - addOneBox(pos21, pos22, makeKey(pos2.getX(), pos2.getZ())); + boxList.add(new Box(pos21, pos22, makeKey(pos2.getX(), pos2.getZ()))); +// addOneBox(pos21, pos22, makeKey(pos2.getX(), pos2.getZ())); if (expand) { seenPosLongSet.add(pos1.asLong()); seenPosLongSet.add(pos2.asLong()); - expandPos(pos1, c1Y, c2Y,seenPosLongSet); - expandPos(pos2, c1Y, c2Y,seenPosLongSet); + expandPos(boxList, pos1, c1Y, c2Y,seenPosLongSet); + expandPos(boxList,pos2, c1Y, c2Y,seenPosLongSet); } } else { String name = "z_" + (int) curZ;// 按照z轴坐标去重 - addOneBox(pos1, pos2, name); + boxList.add(new Box(pos1, pos2, name)); +// addOneBox(pos1, pos2, name); } - MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); +// MaLiLib.logger.error(String.format("(%s, %s, %s)|(%s, %s, %s)", curX, cor1.getY(), curZ, syncPosX, cor1.getY(), syncPosZ)); } seenPosLongSet.clear(); - MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle boxList size: %s", posList.size())); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle boxList size: %s", boxList.size())); + Map boxMap = mergeBoxList(boxList,true); + Map boxMap2 = mergeBoxList(new ArrayList<>(boxMap.values()),false); + MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle merged size: %s", boxMap.size())); + if (!onCircle) {// 按照z轴两个点去重, + Map newBoxMap = new HashMap<>(); + for (Box box : boxMap2.values()) { + newBoxMap.put(makeKey(box.getPos1().getZ(), box.getPos2().getZ()), box); + } + this.subRegionBoxes.putAll(newBoxMap); + } else { // 圆圈不存在两个box相同不需要去重 + this.subRegionBoxes.putAll(boxMap2); + } MaLiLib.logger.error(String.format("createNewSubRegionBoxCircle subRegionBoxes size: %s", this.subRegionBoxes.size())); } catch (Exception e) { MaLiLib.logger.error("createNewSubRegionBoxCircle ", e); @@ -301,9 +312,148 @@ public String createNewSubRegionBoxCircle(BlockPos cor1, BlockPos cor2, boolean return "createNewSubRegionBoxCircle"; } + protected boolean ifAnyNull(Box box) { + return box.getPos1() == null || box.getPos2() == null; + } + + protected boolean isBoxAdjX(Box box1, Box box2) { + if (Math.abs(box2.getPos1().getX() - box1.getPos2().getX()) > 1 && + Math.abs(box1.getPos1().getX() - box2.getPos2().getX()) > 1 + ) { + return false; + } + if (box1.getPos1().getZ() != box2.getPos1().getZ()) { + return false; + } + if (box1.getPos2().getZ() != box2.getPos2().getZ()) { + return false; + } + return true; + } + + protected boolean isBoxAdjZ(Box box1, Box box2) { + if (Math.abs(box2.getPos1().getZ() - box1.getPos2().getZ()) > 1 && + Math.abs(box1.getPos1().getZ() - box2.getPos2().getZ()) > 1 + ) { + return false; + } + if (box1.getPos1().getX() != box2.getPos1().getX()) { + return false; + } + if (box1.getPos2().getX() != box2.getPos2().getX()) { + return false; + } + return true; + } + public int multipleMax(int ... args) { + int ret = Integer.MIN_VALUE; + for (int x: args) { + ret = Math.max(ret, x); + } + return ret; + } + + public int multipleMin(int ... args) { + int ret = Integer.MAX_VALUE; + for (int x: args) { + ret = Math.min(ret, x); + } + return ret; + } + public List getAllCoordinatesByType(CoordinateType type, Box ...boxes) { + List values = new ArrayList<>(); + for (Box box: boxes) { + values.add(box.getCoordinate(Corner.CORNER_1,type)); + values.add(box.getCoordinate(Corner.CORNER_2,type)); + } + return values; + } + + protected Box mergeTwoBoxes(Box box1, Box box2) { + Box box = new Box(); + /* + * |------|12 |-------|22 |------|12 + * | | | | | | + * 11|------| 21|-------| 11|------| + */ + int p1x = multipleMin(getAllCoordinatesByType(CoordinateType.X, box1, box2).stream().mapToInt(o -> o).toArray()); + int p1y = multipleMin(getAllCoordinatesByType(CoordinateType.Y, box1, box2).stream().mapToInt(o -> o).toArray()); + int p1z = multipleMin(getAllCoordinatesByType(CoordinateType.Z, box1, box2).stream().mapToInt(o -> o).toArray()); + + int p2x = multipleMax(getAllCoordinatesByType(CoordinateType.X, box1, box2).stream().mapToInt(o -> o).toArray()); + int p2y = multipleMax(getAllCoordinatesByType(CoordinateType.Y, box1, box2).stream().mapToInt(o -> o).toArray()); + int p2z = multipleMax(getAllCoordinatesByType(CoordinateType.Z, box1, box2).stream().mapToInt(o -> o).toArray()); + + box.setPos1(new BlockPos(p1x, p1y, p1z)); + box.setPos2(new BlockPos(p2x, p2y, p2z)); + return box; + } + + protected Map mergeBoxList(List boxList,boolean xFirst) { + Map boxMap = new HashMap<>(); + if (boxList == null || boxList.isEmpty()) { + return boxMap; + } + Comparator xFirstFunction = (o1, o2) -> { + if (ifAnyNull(o1) || ifAnyNull(o2)) { + return 0; + } + if (o1.getPos1().getZ() != o2.getPos1().getZ()) { + return o1.getPos1().getZ() - o2.getPos1().getZ(); + } + return o1.getPos1().getX() - o2.getPos1().getX(); + }; + Comparator zFirstFunction = (o1, o2) -> { + if (ifAnyNull(o1) || ifAnyNull(o2)) { + return 0; + } + if (o1.getPos1().getX() != o2.getPos1().getX()) { + return o1.getPos1().getX() - o2.getPos1().getX(); + } + return o1.getPos1().getZ() - o2.getPos1().getZ(); + }; + Queue priorityQueue = new PriorityQueue<>(xFirst ? xFirstFunction : zFirstFunction); + // 坐标归一 + List newBoxList = boxList.stream().map(box -> { + BlockPos pos1 = box.getPos1(); + BlockPos pos2 = box.getPos1(); + if (pos1.getX() > pos2.getX() || pos1.getZ() > pos2.getZ()) { + return new Box(pos2, pos1, box.getName()); + } + return box; + }).toList(); + priorityQueue.addAll(newBoxList);// 堆排序 + String keyFmt = "merge_%s"; + int ind = 1; + while (priorityQueue.size() >= 2) { + Box curBox = priorityQueue.remove();// one box + Box nextBox = priorityQueue.remove();// next box + // x axis, first x equal + if (isBoxAdjX(curBox, nextBox)) { + Box merged = mergeTwoBoxes(curBox, nextBox); + priorityQueue.add(merged); + } else if (isBoxAdjZ(curBox, nextBox)) { // z axis, second z equal + Box merged = mergeTwoBoxes(curBox, nextBox); + priorityQueue.add(merged); + } else { + priorityQueue.add(nextBox); + boxMap.put(keyFmt.formatted(ind), curBox); + ++ind; + } + } + while (!priorityQueue.isEmpty()) { + Box box = priorityQueue.remove(); + boxMap.put(keyFmt.formatted(ind), box); + ++ind; + } + + return boxMap; + + } + protected int[][] DIRECTIONS = new int[][]{{0,1},{1,0},{0,-1},{-1,0}}; - protected void expandPos(BlockPos pos, int c1Y, int c2Y,Set seenPosLongSet) { + protected void expandPos(List boxList, BlockPos pos, int c1Y, int c2Y,Set seenPosLongSet) { for (int[] dir : DIRECTIONS) { BlockPos nextPos = new BlockPos(pos.getX() + dir[0], pos.getY(), pos.getZ() + dir[1]); if (seenPosLongSet.contains(nextPos.asLong())) { @@ -312,7 +462,8 @@ protected void expandPos(BlockPos pos, int c1Y, int c2Y,Set seenPosLongSet seenPosLongSet.add(nextPos.asLong()); BlockPos pos1 = new BlockPos(nextPos.getX(),c1Y, nextPos.getZ()); BlockPos pos2 = new BlockPos(nextPos.getX(),c2Y, nextPos.getZ()); - addOneBox(pos1, pos2,makeKey(nextPos.getX(), nextPos.getZ())); + boxList.add(new Box(pos1, pos2,makeKey(nextPos.getX(), nextPos.getZ()))); + //addOneBox(pos1, pos2,makeKey(nextPos.getX(), nextPos.getZ())); } } protected void addOneBox(BlockPos pos1, BlockPos pos2,String name) { @@ -341,8 +492,8 @@ public void removeAllSubRegion() { public static void main(String[] args) { BlockPos pos1 = new BlockPos(0,0,0); - BlockPos pos2 = new BlockPos(0,0,4); - new AreaSelection().createNewSubRegionBoxCircle(pos1, pos2, true, true); + BlockPos pos2 = new BlockPos(0,0,500); + new AreaSelection().createNewSubRegionBoxCircle(pos1, pos2, false, true); } public void clearCurrentSelectedCorner()