import dearpygui.dearpygui as dpg import numpy as np from utils import get_map_window_value, get_config_file_path, is_drawing, get_current_action, set_map_window_value, get_emission_points, get_prev_coords, get_height_map_file_path from map_edit_constants import EMISSION_POINT_COLOR from dynamic_ui import add_emission_point_and_update_ui def load_height_map(file_path): with open(file_path, "r", encoding='utf-8') as file: lines = file.readlines()[1:] height_map = [list(map(int, line.strip().split())) for line in lines] return np.array(height_map, dtype=np.float64) def dump_height_map(height_map, file_path): with open(file_path, "w", encoding="utf-8") as file: w, h = height_map.shape data = height_map * get_map_window_value('max_height') file.write(f"{w} {h}\n") for row in data: file.write(" ".join(list(map(str, map(int, row)))) + "\n") def update_texture(): if get_config_file_path(): emission_points = get_emission_points() for n in emission_points: x = int(emission_points[n]['xpos']) y = int(emission_points[n]['ypos']) coords = get_triangle_coords(x, y) tag = f'emission_point_{n}_triangle' if not dpg.does_item_exist(tag): dpg.draw_polygon(coords, color=EMISSION_POINT_COLOR, fill=(255, 0, 0, 255), tag=tag, parent='map_drawlist', thickness=0) texture_map = np.repeat(get_map_window_value(f'{dpg.get_value('layer')}_map'), 4) texture_map[3::4] = (texture_map[::4] != 0) dpg.set_value(f'map_{dpg.get_value('layer')}_texture', texture_map) def mouse_pos_to_height_map_coords(coords): return map(int, coords) def check_coords(x, y, w, h): return 0 <= x <= x + w <= dpg.get_item_width('map_child_window') and 0 <= y <= y + h <= dpg.get_item_height('map_child_window') def get_rect(cur_pos, end_pos): x1, y1 = mouse_pos_to_height_map_coords(cur_pos) x2, y2 = mouse_pos_to_height_map_coords(end_pos) if y2 < y1: y1, y2 = y2, y1 if x2 < x1: x1, x2 = x2, x1 return y1, y2, x1, x2 def mouse_down_callback(): if not get_height_map_file_path(): return if not dpg.is_item_focused('map_child_window'): return if not is_drawing(): set_map_window_value('prev_coords', dpg.get_drawing_mouse_pos()) set_map_window_value('drawing', True) else: if get_current_action() == 'erase' or get_current_action() == 'draw_rect': x, y = dpg.get_drawing_mouse_pos() px, py = get_prev_coords() w, h = abs(x - px), abs(y - py) x, y = min(x, px), min(y, py) if w > 0 and h > 0 and check_coords(x, y, w, h): dpg.set_item_pos('drawing_frame', [min(x, px), min(y, py)]) dpg.set_item_width('drawing_frame', w) dpg.set_item_height('drawing_frame', h) dpg.show_item('drawing_frame') def mouse_release_callback(): if not get_height_map_file_path(): return if not dpg.is_item_focused('map_child_window'): return coords = dpg.get_drawing_mouse_pos() if get_current_action() == 'erase': draw_rectangle(coords, 0) elif get_current_action() == 'draw_rect': layer = dpg.get_value('layer') if layer == 'roads': height = 1. else: height = dpg.get_value('height_input') draw_rectangle(coords, height) update_texture() set_map_window_value('drawing', False) dpg.hide_item('drawing_frame') def mouse_click_callback(): if not get_height_map_file_path(): return if not get_config_file_path(): return if dpg.is_item_visible('emission_settings_window'): dpg.hide_item('emission_settings_window') return emission_points = get_emission_points() x, y = dpg.get_drawing_mouse_pos() is_pos_emission_point, n = is_mouse_pos_emission_point(x, y, emission_points) if is_pos_emission_point: for key in emission_points[n]: dpg.set_value(f'emission_point_{key}', emission_points[n][key]) dpg.set_item_user_data('emission_settings_window', n) dpg.set_item_pos('emission_settings_window', dpg.get_drawing_mouse_pos()) dpg.show_item('emission_settings_window') else: if 0 <= x < dpg.get_item_width('map_child_window') and 0 <= y < dpg.get_item_height('map_child_window'): add_emission_point_and_update_ui(x, y) update_texture() def draw_rectangle(coords, height): y1, y2, x1, x2 = get_rect(get_prev_coords(), coords) map_type = f'{dpg.get_value('layer')}_map' height_map = get_map_window_value(map_type) height_map[y1:y2, x1:x2] = height set_map_window_value(map_type, height_map) def is_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y): denominator = ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3)) a = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / denominator b = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / denominator c = 1 - a - b return 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1 def is_mouse_pos_emission_point(posx, posy, emission_points, side=30): h = (3 ** 0.5 / 2) * side for n in emission_points: x = emission_points[n]['xpos'] y = emission_points[n]['ypos'] x1, y1 = x, y - (2 / 3) * h x2, y2 = x + side / 2, y + (1 / 3) * h x3, y3 = x - side / 2, y + (1 / 3) * h if is_point_in_triangle(x1, y1, x2, y2, x3, y3, posx, posy): return True, n return False, 0 def get_triangle_coords(x, y, side=30): h = (3 ** 0.5 / 2) * side x1, y1 = x, y - (2 / 3) * h x2, y2 = x + side / 2, y + (1 / 3) * h x3, y3 = x - side / 2, y + (1 / 3) * h return (x1, y1), (x2, y2), (x3, y3)