Tools to view, edit and create 7dtd world-maps https://chrani.net/map-tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
6.0 KiB

import numpy as np
from PyQt5.QtCore import QPoint
from PyQt5.QtGui import QPixmap, QColor, QPainter, QImage, QCursor
from PyQt5.QtWidgets import (
QGridLayout
)
from einops import rearrange
from .region_label import RegionLabel
class RegionLabelCollection(QGridLayout):
label_collection = dict
currently_hovered_label = RegionLabel
blockshaped_map_data = np.array
def __init__(self, world_regions):
super().__init__()
self.world_regions = world_regions
self.label_collection = {}
self.create_label_collection(self.world_regions.zoom_adjusted_label_size)
def set_currently_hovered_label(self, region_label):
self.currently_hovered_label = region_label
for index, label in self.label_collection.items():
if region_label is not label:
label.is_selected = False
label.remove_graphics_effects()
if region_label is not None:
region_label.update_graphics_effect()
def center_mouse_on_hovered_label(self):
QCursor.setPos(self.currently_hovered_label.mapToGlobal(QPoint(
int(self.currently_hovered_label.width() / 2),
int(self.currently_hovered_label.height() / 2)
)))
@staticmethod
def create_region_string_from_grid_index(x=0, y=0) -> str:
# 7dtd seems to be peculiar about their coordinate system. I arrived at this by trial and error,
# I haven't really grasped the logic of it :)
return "r.{x}.{y}.7rg".format(
x=int(x - 16),
y=int((y - 16) + 1) * -1
)
@staticmethod
def create_grid_index_from_region_string(region_string: str) -> tuple:
split_string = region_string.split(".")
index_x = int(split_string[1]) + 16
index_y = (int(split_string[2]) * -1) + 16 - 1
return index_x, index_y
def get_adjacent_marked_region_labels(self, region_label: RegionLabel):
index_x, index_y = self.create_grid_index_from_region_string(region_label.region_string)
adjacent_region_labels = {
"top": self.label_collection.get(
self.create_region_string_from_grid_index(y=index_y - 1, x=index_x), None
),
"right": self.label_collection.get(
self.create_region_string_from_grid_index(y=index_y, x=index_x + 1), None
),
"bottom": self.label_collection.get(
self.create_region_string_from_grid_index(y=index_y + 1, x=index_x), None
),
"left": self.label_collection.get(
self.create_region_string_from_grid_index(y=index_y, x=index_x - 1), None
)
}
adjacent_marked_region_labels = {}
for direction, adjacent_region_label in adjacent_region_labels.items():
if adjacent_region_label is not None and adjacent_region_label.is_marked:
adjacent_marked_region_labels.update({direction: adjacent_region_label})
return adjacent_marked_region_labels
def toggle_marked(self, region_label=None):
if region_label is not None:
region_label.is_marked = not region_label.is_marked
adjacent_marked_region_labels = self.get_adjacent_marked_region_labels(region_label)
region_label.set_adjacent_marked_region_labels(adjacent_marked_region_labels)
region_label.update_style_effects()
for direction, adjacent_marked_region_label in adjacent_marked_region_labels.items():
neighbors_adjacent_marked_region_labels = self.get_adjacent_marked_region_labels(
adjacent_marked_region_label
)
adjacent_marked_region_label.set_adjacent_marked_region_labels(neighbors_adjacent_marked_region_labels)
adjacent_marked_region_label.update_style_effects()
@staticmethod
def toggle_open_in_context_menu(region_label=None):
if region_label is not None:
region_label.context_menu_is_shown = not region_label.context_menu_is_shown
region_label.update_graphics_effect()
def trigger_cursor_change(self, region_label=None):
if region_label is not None:
self.world_regions.trigger_cursor_change()
def create_label_collection(self, label_size):
for y in range(0, 32):
for x in range(0, 32):
self.create_label(x, y, label_size)
def create_label(self, x, y, size):
label = RegionLabel(self, x, y)
label.setFixedSize(size, size)
index = self.create_region_string_from_grid_index(x=x, y=y)
self.addWidget(label, y, x)
self.label_collection.update({index: label})
def change_label_size(self, size):
label = empty = object()
for index, label in self.label_collection.items():
label.setFixedSize(size, size)
if label is not empty:
label.parent().adjustSize()
def clear_viewer_grid(self):
for i in reversed(range(self.count())):
self.itemAt(i).widget().setParent(None)
return self
def update_label_collection_with_raw_map_data(self, raw_map_data, length, offset=0):
self.clear_viewer_grid().create_label_collection(self.world_regions.zoom_adjusted_label_size)
regions_per_row = int(length / 512)
raw_map_data = np.flipud(np.reshape(raw_map_data, (length, length)))
self.blockshaped_map_data = rearrange(raw_map_data, '(x dx) (y dy) -> x y dx dy', dx=512, dy=512)
for y in range(0, regions_per_row):
for x in range(0, regions_per_row):
chunk_raw_data = self.blockshaped_map_data[y][x]
chunk = QImage(chunk_raw_data.copy(), 512, 512, QImage.Format_Grayscale16)
grid_slot = self.create_region_string_from_grid_index(x=x + offset, y=y + offset)
region_label = self.label_collection.get(grid_slot)
region_label.set_raw_data_array(chunk_raw_data)
region_label.mark_as_region()
region_label.set_label_pixmap(chunk)