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
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)
|
|
|