Skip to content
Snippets Groups Projects
Commit 7b83d0d2 authored by Maryshca's avatar Maryshca
Browse files

major update

parent bb4bd07f
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,7 @@
## Как запустить?
`pip install dearpygui numpy paramiko scp python-dotenv`
`pip install dearpygui numpy paramiko scp python-dotenv tifffile`
`git clone http://tesla.parallel.ru/kuzmichovamary/gui.git`
......
import dearpygui.dearpygui as dpg
import tifffile
from utils import *
from remote_run import start_remote_execution
from constants import SPACE, TREE_COLOR, ROAD_COLOR, BUILDING_COLOR
from remote_run import start_remote_execution, start_model_build, get_server_output_structure
from map_edit import dump_height_map, load_height_map, update_texture
from styles import get_accent_color, apply_theme
from generator import LCZ
from config import load_config, dump_config
from dynamic_ui import construct_config_ui
from dynamic_ui import construct_config_ui, construct_model_output_structure_ui
def map_window_on_close_clb(s, a, u):
dpg.set_item_user_data('map_window', {'height_map': None, 'height_map_file_path': None, 'drawing': False, 'prev_coords': None, 'current_action': None})
delete_item_and_clear_alias(f'map_buildings_texture')
delete_item_and_clear_alias(f'map_trees_texture')
delete_item_and_clear_alias(f'map_roads_texture')
delete_item_children_and_clear_aliases(f'map_drawlist')
user_data = {
'buildings_map': None,
'trees_map': None,
'roads_map': None,
'height_map_file_path': None,
'drawing': False,
'prev_coords': None,
'current_action': None,
'max_height': 0,
'output_dirs': None,
}
dpg.set_item_user_data('map_window', user_data)
def set_file_path_clb(s, a, u):
file_path = a['file_path_name']
dpg.set_value(u, file_path)
def construct_config_ui_clb(s, a, u):
if not get_config_file_path():
return
delete_item_children_and_clear_aliases()
delete_config_items_and_clear_aliases()
update_config_values()
construct_config_ui(get_config_file_path(), get_config())
def map_open_clb(s, a, u):
height_map_file_path = a['file_path_name']
height_map = load_height_map(height_map_file_path)
set_map_window_value('height_map', height_map)
set_map_window_value('height_map_file_path', height_map_file_path)
update_texture(height_map)
dpg.show_item('map_window')
def generate_map_clb(s, a, u):
height_map = LCZ(config_path=f'configs/{s}.json').to_height_map()
################################################################################
#
# Config
#
################################################################################
set_map_window_value('height_map', height_map)
set_map_window_value('height_map_file_path', 'lcz.txt')
update_texture(height_map)
dpg.show_item('map_window')
def update_config_values():
config = get_config()
for path in config:
if dpg.does_item_exist(f'{get_config_file_path()}.{path}'):
config[path].value = dpg.get_value(f'{get_config_file_path()}.{path}')
set_main_window_value('config', config)
def map_save_clb(s, a, u):
dump_map(get_height_map(), get_height_map_file_path())
def config_save_as_clb(s, a, u):
update_config_values()
dump_config(get_config(), a['file_path_name'])
dpg.show_item('message_popup')
def map_save_as_clb(s, a, u):
dump_map(get_height_map(), a['file_path_name'])
def config_open_clb(s, a, u):
delete_config_items_and_clear_aliases()
config_file_path = a['file_path_name']
config = load_config(config_file_path)
set_main_window_value('config', config)
set_main_window_value('config_file_path', config_file_path)
construct_config_ui(a['file_path_name'], config)
def config_save_clb(s, a, u):
update_config_values()
dump_config(get_config(), get_config_file_path())
dpg.show_item('message_popup')
def open_map_save_as_dialog_clb(s, a, u):
dpg.show_item('map_save_as')
def open_config_open_dialog_clb(s, a, u):
dpg.show_item('config_open')
def open_map_open_dialog_clb(s, a, u):
dpg.show_item('map_open')
def show_config_search_window_clb(s, a, u):
dpg.show_item('search_popup')
def open_config_open_dialog_clb(s, a, u):
def open_config_save_as_dialog_clb(s, a, u):
dpg.show_item('config_open')
################################################################################
#
# Config Search
#
################################################################################
def search_clb(s, data, u):
if not get_config_file_path():
return
......@@ -70,59 +105,160 @@ def search_clb(s, data, u):
dpg.set_value(dpg.get_item_parent(dpg.get_item_parent(tag)), dpg.get_item_parent(tag))
change_color_temporarily('.'.join([get_config_file_path(), path, 'text']), color=get_accent_color())
def remote_run_clb(s, a, u):
if not get_config_file_path():
show_status_text('no config.txt specified. cannot run.')
return
update_config_values()
dump_config(get_config(), 'tmp.txt')
################################################################################
#
# Map edit
#
################################################################################
dpg.show_item('login_modal')
def construct_map_layers(w, h):
dpg.set_item_width('map_child_window', w)
dpg.set_item_height('map_child_window', h)
def apply_theme_clb(s, a, u):
apply_theme(s)
# dpg.add_texture_registry(tag='textures')
dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_buildings_texture', parent='textures')
dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_trees_texture', parent='textures')
dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_roads_texture', parent='textures')
def set_file_path_clb(s, a, u):
file_path = a['file_path_name']
dpg.set_value(u, file_path)
dpg.bind_item_theme('map_child_window', 'map_image_theme')
dpg.add_drawlist(w, h, tag=f'map_drawlist', parent='map_child_window', pos=[0, 0])
def show_config_search_window_clb(s, a, u):
dpg.show_item('search_popup')
dpg.draw_image(f'map_buildings_texture', color=BUILDING_COLOR, tag=f'map_buildings_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
dpg.draw_image(f'map_trees_texture', color=TREE_COLOR, tag=f'map_trees_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
dpg.draw_image(f'map_roads_texture', color=ROAD_COLOR, tag=f'map_roads_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
def start_remote_execution_clb(s, a, u):
start_remote_execution(dpg.get_value('server_username'), dpg.get_value('server_password'), dpg.get_value('gitlab_username'), dpg.get_value('gitlab_password'))
def map_open_clb(s, a, u):
height_map_file_path = a['file_path_name']
def update_config_values():
config = get_config()
for path in config:
if dpg.does_item_exist(f'{get_config_file_path()}.{path}'):
config[path].value = dpg.get_value(f'{get_config_file_path()}.{path}')
set_main_window_value('config', config)
if height_map_file_path.endswith('txt'):
height_map = load_height_map(height_map_file_path)
max_height = np.max(height_map)
height_map /= max_height
else:
height_map = tifffile.imread(height_map_file_path)
max_height = 1
def config_save_as_clb(s, a, u):
update_config_values()
dump_config(get_config(), a['file_path_name'])
dpg.show_item('message_popup')
h, w = height_map.shape
def config_open_clb(s, a, u):
delete_item_children_and_clear_aliases()
config_file_path = a['file_path_name']
config = load_config(config_file_path)
set_main_window_value('config', config)
set_main_window_value('config_file_path', config_file_path)
construct_config_ui(a['file_path_name'], config)
print(dpg.get_item_user_data('map_window'))
def config_save_clb(s, a, u):
update_config_values()
dump_config(get_config(), get_config_file_path())
set_map_window_value('buildings_map', height_map)
set_map_window_value('roads_map', np.zeros((h, w)))
set_map_window_value('trees_map', np.zeros((h, w)))
set_map_window_value('height_map_file_path', height_map_file_path)
set_map_window_value('max_height', max_height)
construct_map_layers(w, h)
update_texture()
dpg.show_item('map_window')
def generate_map_clb(s, a, u):
height_map = LCZ(config_path=f'configs/{s}.json').to_height_map(dtype=np.float64)
max_height = np.max(height_map)
height_map /= max_height
h, w = height_map.shape
set_map_window_value('buildings_map', height_map)
set_map_window_value('roads_map', np.zeros((h, w)))
set_map_window_value('trees_map', np.zeros((h, w)))
set_map_window_value('height_map_file_path', f'{dpg.generate_uuid()}.txt')
set_map_window_value('max_height', max_height)
construct_map_layers(w, h)
update_texture()
dpg.show_item('map_window')
def save_map(file_path):
if file_path.endswith('.tif') or file_path.endswith('.tiff'):
with TiffWriter(file_path) as tif:
tif.write(get_map_window_value('buildings_map'))
tif.write(get_map_window_value('roads_map'))
tif.write(get_map_window_value('trees_map'))
else:
dump_height_map(get_map_window_value('buildings_map'), file_path)
def map_save_clb(s, a, u):
file_path = get_height_map_file_path()
save_map(file_path)
dpg.show_item('message_popup')
def map_save_as_clb(s, a, u):
file_path = a['file_path_name']
save_map(file_path)
dpg.show_item('message_popup')
def open_map_save_as_dialog_clb(s, a, u):
dpg.show_item('map_save_as')
def open_map_open_dialog_clb(s, a, u):
dpg.show_item('map_open')
def set_action_clb(s, a, u):
set_map_window_value('current_action', s)
def set_action_none_clb(s, a, u):
set_map_window_value('current_action', None)
def open_config_save_as_dialog_clb(s, a, u):
dpg.show_item('config_open')
\ No newline at end of file
################################################################################
#
# Styles
#
################################################################################
def apply_theme_clb(s, a, u):
apply_theme(s)
################################################################################
#
# Remote execution
#
################################################################################
def start_remote_execution_clb(s, a, u):
dpg.configure_item('login_modal', show=False)
u = dpg.get_item_user_data('login_modal')
if u == 'build_model':
start_model_build(dpg.get_value('server_username'), dpg.get_value('server_password'), dpg.get_value('gitlab_username'), dpg.get_value('gitlab_password'))
elif u == 'run_on_lab_server':
start_remote_execution(dpg.get_value('server_username'), dpg.get_value('server_password'))
elif u == 'download_output':
s = get_server_output_structure(dpg.get_value('server_username'), dpg.get_value('server_password'))
folders, filepaths = parse_dirs(s)
delete_item_children_and_clear_aliases('output')
construct_model_output_structure_ui(filepaths, folders)
dpg.show_item('model_output_window')
def build_model_on_lab_server_clb(s, a, u):
pass
def show_get_credentials_modal_clb(s, a, u):
dpg.set_item_user_data('login_modal', u)
if u == 'run_on_lab_server':
if not get_config_file_path():
show_status_text('no config.txt specified. cannot run.')
return
update_config_values()
dump_config(get_config(), 'tmp.txt')
dpg.hide_item('gitlab_password')
dpg.hide_item('gitlab_username')
elif u == 'download_output':
dpg.hide_item('gitlab_password')
dpg.hide_item('gitlab_username')
dpg.show_item('login_modal')
\ No newline at end of file
......@@ -12,7 +12,7 @@ class CfgVar:
self.comment = comment
def __repr__(self):
return f"CfgVar(key={self.key}, value={self.value}, comment={self.comment})"
return f"CfgVar(key='{self.key}', value={self.value}, value_type='{self.value_type}', comment='{self.comment}')"
TokenType = Enum('TokenType', ['BRACE_OPEN', 'BRACE_CLOSE', 'VARIABLE', 'NAMESPACE'])
......
import os
from config import CfgVar
ROAD_COLOR = (221, 161, 94, 255)
TREE_COLOR = (96, 108, 56, 255)
BUILDING_COLOR = (188, 108, 37, 255)
EMISSION_POINT_COLOR = (255, 0, 0, 255)
TABS_UI = 'tabs_ui'
COLLAPSING_HEADERS_UI = 'collapsing_headers_ui'
WIDGET_WIDTH = 300
XOFFSET = 300
LCZS = ['compact_high_rise', 'compact_low_rise', 'compact_mid_rise', 'heavy_industry', 'large_low_rise', 'lightweight_low_rise', 'open_high_rise', 'open_low_rise', 'open_mid_rise', 'sparsley_build']
MAX_MAP_WIDTH = 2000
MAX_MAP_HEIGHT = 2000
EMISSION_POINT_CONFIG_VARIABLES = {
'value': CfgVar(key='value', value=28481176.531511, value_type='DOUBLE', comment=''),
'begin': CfgVar(key='begin', value=25200.0, value_type='DOUBLE', comment='[s]'),
'xpos': CfgVar(key='xpos', value=200.0, value_type='DOUBLE', comment='[m]'),
'ypos': CfgVar(key='ypos', value=200.0, value_type='DOUBLE', comment='[m]'),
'zpos': CfgVar(key='zpos', value=60.0, value_type='DOUBLE', comment='[m]'),
'sx': CfgVar(key='sx', value=20.0, value_type='DOUBLE', comment='[m]'),
'sy': CfgVar(key='sy', value=20.0, value_type='DOUBLE', comment='[m]'),
'sz': CfgVar(key='sz', value=10.0, value_type='DOUBLE', comment='[m]')
}
UIS = [TABS_UI, COLLAPSING_HEADERS_UI]
FONT_PATH = os.path.join('fonts', 'Montserrat-Medium.ttf')
......@@ -22,7 +43,11 @@ ACCENT = (5, 18, 19, 20, 15, 16, 35, 37, 34, 23, 22, 25, 26, 27, 28, 29, 10, 11,
PRIMARY = (2, 3, 39)
SECONDARY = (36, 33, 21, 24, 4, 7, 8, 9, 13, 14)
APPLY_ALPHA = (1, 22, 25, 31, 34, 16)
COLOR_TYPE_TO_DPG_ITEM = {'TEXT': (0, 1), 'PRIMARY': (2, 3, 39), 'SECONDARY': (36, 33, 21, 24, 4, 7, 8, 9, 13, 14), 'ACCENT': (5, 18, 19, 20, 15, 16, 35, 37, 34, 23, 22, 25, 26, 27, 28, 29, 10, 11, 12, 30, 31, 32, 49, 50)}
COLOR_TYPE_TO_DPG_ITEM = {
'TEXT': (0, 1),
'PRIMARY': (2, 3, 39),
'SECONDARY': (36, 33, 21, 24, 4, 7, 8, 9, 13, 14),
'ACCENT': (5, 18, 19, 20, 15, 16, 35, 37, 34, 23, 22, 25, 26, 27, 28, 29, 10, 11, 12, 30, 31, 32, 49, 50)}
COLOR_TO_COLOR_TYPE = {0: 'TEXT', 1: 'TEXT', 2: 'PRIMARY', 3: 'PRIMARY', 39: 'PRIMARY', 36: 'SECONDARY', 21: 'SECONDARY', 24: 'SECONDARY', 4: 'SECONDARY', 7: 'SECONDARY', 8: 'SECONDARY', 9: 'SECONDARY', 13: 'SECONDARY', 33: 'SECONDARY', 14: 'SECONDARY', 35: 'ACCENT', 20: 'ACCENT', 37: 'ACCENT', 22: 'ACCENT', 23: 'ACCENT', 5: 'ACCENT', 25: 'ACCENT', 26: 'ACCENT', 27: 'ACCENT', 28: 'ACCENT', 29: 'ACCENT', 10: 'ACCENT', 30: 'ACCENT', 11: 'ACCENT', 31: 'ACCENT', 12: 'ACCENT', 32: 'ACCENT', 49: 'ACCENT', 34: 'ACCENT', 15: 'ACCENT', 50: 'ACCENT', 16: 'ACCENT', 18: 'ACCENT', 19: 'ACCENT', 1: 'TEXT'}
BLUE = {
......
......@@ -3,6 +3,22 @@ import dearpygui.dearpygui as dpg
from utils import *
from constants import *
def check_every_child_checkbox(s, a):
parent = dpg.get_item_parent(s)
for child in dpg.get_item_children(parent, 1):
print(s, dpg.get_item_alias(child), child, dpg.get_item_type(child))
t = dpg.get_item_type(child)
if t == 'mvAppItemType::mvGroup':
dpg.set_value(dpg.get_item_children(child, 1)[1], a)
if t == 'mvAppItemType::mvCollapsingHeader':
checkbox = dpg.get_item_children(child, 1)[0]
dpg.set_value(checkbox, a)
check_every_child_checkbox(checkbox, a)
def folder_checkbox_clb(s, a, u):
check_every_child_checkbox(s, a)
def open_folder_dialog_clb(s, a, u):
dpg.show_item('set_folder_dialog')
dpg.set_item_user_data('set_folder_dialog', u)
......@@ -16,6 +32,109 @@ def construct_config_ui(config_file_path, config):
else:
construct_config_ui_collapsing_headers(config_file_path, config)
def add_item_to_config_ui(full_path):
config_file_path = get_config_file_path()
config = get_config()
if get_current_ui_type() == TABS_UI:
namespaces = full_path.split('.')
parent = config_file_path
for level in range(len(namespaces) - 1):
path = config_file_path + '.' + '.'.join(namespaces[:level+1])
tab_bar_exists, tab_bar_uuid = does_tab_bar_child_exist(parent)
if not tab_bar_exists:
tab_bar_uuid = dpg.add_tab_bar(parent=parent, callback=change_tab_bar_height_clb)
dpg.set_item_user_data(parent, dpg.get_item_user_data(parent) + 4 * SPACE + FONT_SIZE)
if not dpg.does_item_exist(path):
tab_uuid = dpg.add_tab(label=namespaces[level], parent=tab_bar_uuid)
dpg.add_child_window(parent=tab_uuid, tag=path, border=True, autosize_y=False, autosize_x=True)
dpg.set_item_user_data(path, 2 * SPACE)
parent = path
else:
namespaces = full_path.split('.')
parent = config_file_path
for level in range(len(namespaces) - 1):
path = config_file_path + '.' + '.'.join(namespaces[:level+1])
if not dpg.does_item_exist(path):
dpg.add_collapsing_header(label=namespaces[level], parent=parent, tag=path, indent=INDENT)
parent = path
if not dpg.does_item_exist(config_file_path + '.' + full_path):
create_widget(config_file_path, config, full_path)
def add_emission_point_and_update_ui(x, y):
emission_point = {
'value': CfgVar(key='value', value=28481176.531511, value_type='DOUBLE', comment=''),
'begin': CfgVar(key='begin', value=25200.0, value_type='DOUBLE', comment='[s]'),
'xpos': CfgVar(key='xpos', value=x, value_type='DOUBLE', comment='[m]'),
'ypos': CfgVar(key='ypos', value=y, value_type='DOUBLE', comment='[m]'),
'zpos': CfgVar(key='zpos', value=60.0, value_type='DOUBLE', comment='[m]'),
'sx': CfgVar(key='sx', value=20.0, value_type='DOUBLE', comment='[m]'),
'sy': CfgVar(key='sy', value=20.0, value_type='DOUBLE', comment='[m]'),
'sz': CfgVar(key='sz', value=10.0, value_type='DOUBLE', comment='[m]')
}
prefix = f'passive_tracers.tracer_{get_max_n_emission_point() + 1}.point_emission'
config = get_config()
for key in emission_point:
full_path = '.'.join([prefix, key])
config[full_path] = emission_point[key]
add_item_to_config_ui(full_path)
set_main_window_value('config', config)
def delete_emission_point_and_update_ui(x, y):
emission_point = {
'value': CfgVar(key='value', value=28481176.531511, value_type='DOUBLE', comment=''),
'begin': CfgVar(key='begin', value=25200.0, value_type='DOUBLE', comment='[s]'),
'xpos': CfgVar(key='xpos', value=x, value_type='DOUBLE', comment='[m]'),
'ypos': CfgVar(key='ypos', value=y, value_type='DOUBLE', comment='[m]'),
'zpos': CfgVar(key='zpos', value=60.0, value_type='DOUBLE', comment='[m]'),
'sx': CfgVar(key='sx', value=20.0, value_type='DOUBLE', comment='[m]'),
'sy': CfgVar(key='sy', value=20.0, value_type='DOUBLE', comment='[m]'),
'sz': CfgVar(key='sz', value=10.0, value_type='DOUBLE', comment='[m]')
}
prefix = f'passive_tracers.tracer_{get_max_n_emission_point() + 1}.point_emission'
config = get_config()
for key in emission_point:
full_path = '.'.join([prefix, key])
config[full_path] = emission_point[key]
add_item_to_config_ui(full_path)
set_main_window_value('config', config)
def construct_model_output_structure_ui(filepaths, folders):
dpg.add_collapsing_header(label='output', parent='model_output_window', tag='output_header', indent=0, default_open=True)
dpg.add_checkbox(label='select all', default_value=False, parent='output_header', tag='output', callback=folder_checkbox_clb)
for path in folders:
folders = path.split('/')
parent = 'output_header'
for folder in folders:
if not dpg.does_item_exist(f'{folder}_header'):
with dpg.collapsing_header(label=folder, parent=parent, tag=f'{folder}_header', indent=INDENT):
dpg.add_checkbox(label='select all', default_value=False, tag=folder, callback=folder_checkbox_clb)
parent = f'{folder}_header'
for filepath in filepaths:
if '/' not in filepath:
parent = 'output_header'
else:
parent = filepath.split('/')[-2] + '_header'
with dpg.group(horizontal=True, parent=parent, indent=INDENT, xoffset=XOFFSET):
dpg.add_text(filepath.split('/')[-1], tag=f'{filepath}.text')
dpg.add_checkbox(default_value=False, tag=filepath)
def construct_config_ui_collapsing_headers(config_file_path, config):
dpg.add_collapsing_header(label=config_file_path, parent='main', tag=config_file_path, indent=0, default_open=True)
......
......@@ -241,8 +241,8 @@ class LCZ:
file.write(f"{self.height} {self.width}\n")
file.write("\n".join([" ".join(list(map(str, row))) for row in lcz]))
def to_height_map(self, building=True, tree=False):
lcz = np.zeros((self.height, self.width), dtype=int)
def to_height_map(self, dtype=np.int64, building=True, tree=False):
lcz = np.zeros((self.height, self.width), dtype=dtype)
if building:
self.put_buildings(lcz)
if tree:
......
......@@ -2,50 +2,7 @@ import dearpygui.dearpygui as dpg
from utils import *
from callbacks import *
def mouse_down_callback():
if not get_height_map_path():
return
if not is_drawing():
set_map_window_value('prev_coords', dpg.get_mouse_pos())
set_map_window_value('drawing', True)
else:
x, y = dpg.get_mouse_pos()
px, py = get_prev_coords()
y += dpg.get_text_size('edit map')[1] + 2 * SPACE + dpg.get_y_scroll('map_window')
py += dpg.get_text_size('edit map')[1] + 2 * SPACE + dpg.get_y_scroll('map_window')
x += dpg.get_x_scroll('map_window')
px += dpg.get_x_scroll('map_window')
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_path():
return
coords = dpg.get_mouse_pos()
if get_current_action() == 'erase':
draw_rectangle(coords, 0)
elif get_current_action() == 'draw_rect':
height = dpg.get_value('height_input')
draw_rectangle(coords, np.max(get_height_map()) * height)
update_texture(get_height_map())
set_map_window_value('drawing', False)
dpg.hide_item('drawing_frame')
def draw_rectangle(coords, height):
y1, y2, x1, x2 = get_rect(get_prev_coords(), coords)
height_map = get_height_map()
height_map[y1:y2, x1:x2] = height
set_map_window_value('height_map', height_map)
from map_edit import mouse_down_callback, mouse_release_callback, mouse_click_callback
def on_ctrl_o(sender, app_data):
if dpg.is_key_down(dpg.mvKey_Control) and dpg.is_key_down(dpg.mvKey_O):
......@@ -79,11 +36,7 @@ def setup_handlers():
dpg.bind_item_handler_registry('main', 'main_handler')
dpg.set_viewport_resize_callback(change_height_)
with dpg.item_handler_registry(tag='map_handler'):
dpg.add_item_resize_handler(callback=set_action_none_clb)
dpg.bind_item_handler_registry('map_window', 'map_handler')
with dpg.handler_registry():
dpg.add_mouse_down_handler(callback=mouse_down_callback)
dpg.add_mouse_release_handler(callback=mouse_release_callback)
dpg.add_mouse_click_handler(button=1, callback=mouse_click_callback)
\ No newline at end of file
import dearpygui.dearpygui as dpg
from utils import *
from callbacks import *
from constants import MAX_MAP_WIDTH, MAX_MAP_HEIGHT, EMISSION_POINT_COLOR
from dynamic_ui import construct_config_ui, add_emission_point_and_update_ui
def load_height_map(file_path):
with open(file_path, "r") 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
height_map *= get_map_window_value('max_height')
file.write(f"{w} {h}\n")
for row in height_map:
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)
dpg.draw_polygon(coords, color=EMISSION_POINT_COLOR, fill=(255, 0, 0, 255), parent=f'{get_height_map_file_path()}map_drawlist', thickness=0)
texture_map = np.repeat(get_map_window_value(f'{dpg.get_value('layer')}_map'), 4)
print(texture_map.shape, np.all(texture_map == 0), f'map_{dpg.get_value('layer')}_texture', np.all(get_map_window_value(f'{dpg.get_value('layer')}_map') == 0))
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
dpg.hide_item('emission_values')
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
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:
dpg.set_item_width('emission_values', 300)
dpg.set_item_height('emission_values', 300)
dpg.set_item_pos('emission_values', dpg.get_drawing_mouse_pos())
dpg.show_item('emission_values')
dpg.set_value('emission_settings', f'value: {emission_points[n]['value']}\nbegin: {emission_points[n]['begin']}')
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 draw_triangle(array, x, y, side=30, color=1.):
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
for i in range(y - side, y + side):
for j in range(x - side, x + side):
if is_point_in_triangle(x1, y1, x2, y2, x3, y3, j, i):
array[i, j] = color
return array
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)
\ No newline at end of file
......@@ -10,39 +10,85 @@ import paramiko
from utils import show_status_text
HOST = "geophyslab.srcc.msu.ru"
REPOS = (
"git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-common.git",
"git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-wstgrid.git",
"git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nse-gabls1-urban-les.git"
HOST = 'geophyslab.srcc.msu.ru'
URBAN_LES_REPOS = (
'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-common.git',
'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-wstgrid.git',
'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nse-gabls1-urban-les.git'
)
def run_on_remote_server(username, password, gitlab_username, gitlab_password):
def build_model(server_username, server_password, gitlab_username, gitlab_password, repos=URBAN_LES_REPOS):
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(HOST, username=username, password=password)
scp = SCPClient(ssh.get_transport())
scp.put("tmp.txt", "./tmp.txt")
ssh.connect(HOST, username=server_username, password=server_password)
commands = [
"mkdir run",
"cd ./run"
'mkdir run',
'cd ./run'
]
# for repo in REPOS:
# commands.append(repo.format(username=gitlab_username, password=gitlab_password))
for repo in repos:
commands.append(repo.format(username=gitlab_username, password=gitlab_password))
commands += [
"cd ./nse-gabls1-urban-les/nse-gabls1-urban-les/",
#"chmod +x cpall.sh",
#"./cpall.sh ../../code",
"cd ../../code",
#"make -B MACHINE=local COMPILER=gnu",
"cp ../../tmp.txt ./config.txt",
"./nsenx"
'cd ./nse-gabls1-urban-les/nse-gabls1-urban-les/',
'chmod +x cpall.sh',
'./cpall.sh ../../code',
'cd ../../code',
'make -B MACHINE=local COMPILER=gnu -j 23',
]
commands = '; '.join(commands)
show_status_text(f'building model')
dpg.show_item('loading')
x, y = dpg.get_item_pos('status_text')
dpg.set_item_pos('loading', (x - 40, y))
stdin, stdout, stderr = ssh.exec_command(commands)
with open('log.txt', 'w') as file:
file.write(stdout.read().decode())
ssh.close()
show_status_text('')
dpg.hide_item('loading')
show_status_text('model builded:) log written to log.txt.')
except Exception as e:
show_status_text(f'error: {str(e)}')
def make_run_command():
command = f'mpirun -np {int(dpg.get_value('-np'))} ./nsenx'
if dpg.get_value('-arch') != 'cpu':
command += f' -arch {dpg.get_value('-arch')}'
if dpg.get_value('use-udump'):
command += f' -udump {dpg.get_value('-udump')}'
if dpg.get_value('use-model-output'):
command += f' -model-output {dpg.get_value('-model-output')}'
return command
def run_on_lab_server(username, password):
try:
show_status_text('model running...')
dpg.show_item('progress_bar')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(HOST, username=username, password=password)
scp = SCPClient(ssh.get_transport())
scp.put('tmp.txt', 'run/code/config.txt')
command = make_run_command()
commands = [
'cd ./run',
'cd ./code',
command
]
commands = '; '.join(commands)
......@@ -56,38 +102,57 @@ def run_on_remote_server(username, password, gitlab_username, gitlab_password):
output = stdout.channel.recv(512).decode()
update_progress(output)
log += '\n\n' + output
time.sleep(1)
# time.sleep(1)
output = stdout.read().decode()
dpg.set_value("progress_bar", 1.)
dpg.hide_item('loading')
dpg.set_value('progress_bar', 1.)
log += '\n\n' + output
with open("log.txt", "w") as res_file:
res_file.write(output)
with open('log.txt', 'w') as file:
file.write(log)
scp.close()
ssh.close()
show_status_text("success:) log written to log.txt.")
dpg.hide_item('progress_bar')
show_status_text('success:) log written to log.txt.')
except Exception as e:
show_status_text(f"error: {str(e)}")
show_status_text(f'error: {str(e)}')
def update_progress(output):
if not re.findall(r'([0-9]+)%', output):
progress = 0.0
show_status_text(f"building model")
def update_progress_building_model():
show_status_text(f'building model')
dpg.show_item('loading')
x, y = dpg.get_item_pos('status_text')
dpg.set_item_pos('loading', (x - 40, y))
def update_progress(output):
if not re.findall(r'([0-9]+)%', output):
progress = 0.0
else:
progress = int(re.findall(r'([0-9]+)%', output)[-1]) / 100
show_status_text('')
dpg.hide_item('loading')
dpg.set_value("progress_bar", progress)
dpg.set_value('progress_bar', progress)
def start_remote_execution(server_username, server_password, gitlab_username, gitlab_password):
dpg.configure_item("login_modal", show=False)
threading.Thread(target=run_on_remote_server, args=(server_username, server_password, gitlab_username, gitlab_password)).start()
def start_remote_execution(server_username, server_password):
threading.Thread(target=run_on_lab_server, args=(server_username, server_password)).start()
def start_model_build(server_username, server_password, gitlab_username, gitlab_password):
threading.Thread(target=build_model, args=(server_username, server_password, gitlab_username, gitlab_password)).start()
def get_server_output_structure(username, password):
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(HOST, username=username, password=password)
stdin, stdout, stderr = ssh.exec_command('cd ./run/code/output; find . -type f')
output = stdout.read().decode()
ssh.close()
return output
except Exception as e:
show_status_text(f'error: {str(e)}')
\ No newline at end of file
......@@ -8,6 +8,10 @@ from callbacks import *
def construct_main_window_ui():
with dpg.theme() as progress_bar_theme:
with dpg.theme_component(dpg.mvAll):
dpg.add_theme_color(dpg.mvThemeCol_FrameBg, (255, 255, 255, 100), category=dpg.mvThemeCat_Core)
with dpg.window(label='config file editor', tag='main', user_data={'config': None, 'config_file_path': None}):
with dpg.menu_bar():
with dpg.menu(label='config'):
......@@ -23,7 +27,10 @@ def construct_main_window_ui():
dpg.add_menu_item(label=lcz_type, check=False, callback=combo_menu(generate_map_clb), tag=lcz_type)
with dpg.menu(label='run'):
dpg.add_menu_item(label='run on lab server', callback=remote_run_clb, tag='remote_run')
dpg.add_menu_item(label='edit remote run default values', callback=lambda: dpg.show_item('remote_run_settings_window'))
dpg.add_menu_item(label='build model on lab server', callback=show_get_credentials_modal_clb, user_data='build_model')
dpg.add_menu_item(label='run on lab server', callback=show_get_credentials_modal_clb, user_data='run_on_lab_server')
dpg.add_menu_item(label='download output', callback=show_get_credentials_modal_clb, user_data='download_output')
with dpg.menu(label='view'):
with dpg.menu(label='ui', tag='ui'):
......@@ -36,12 +43,40 @@ def construct_main_window_ui():
dpg.add_menu_item(label=theme, check=True, default_value=False, callback=combo_menu(apply_theme_clb), tag=theme)
dpg.set_value('orange', True)
dpg.add_progress_bar(label='progress', default_value=0.0, tag='progress_bar', height=FONT_SIZE, width=200, pos=[dpg.get_viewport_width() // 2 - 100 + SPACE, SPACE])
dpg.add_progress_bar(label='progress', show=False, default_value=0.0, tag='progress_bar', height=FONT_SIZE, width=200, pos=[dpg.get_viewport_width() // 2 - 100 + SPACE, SPACE])
dpg.add_text('', tag='status_text', show=True)
dpg.add_loading_indicator(style=1, color=(255, 255, 255, 255), thickness=2, radius=2, tag='loading', show=False)
dpg.bind_item_theme('progress_bar', progress_bar_theme)
def construct_remote_run_settings_window():
xoffset = 400
width = 300
with dpg.window(label='remote run settings', show=False, tag='remote_run_settings_window', autosize=True, pos=[50, 50]):
with dpg.group(horizontal=True, xoffset=xoffset):
dpg.add_text('number of processes for mpi run')
dpg.add_input_int(default_value=8, width=width, min_value=1, max_value=200, min_clamped=True, max_clamped=True, tag='-np')
with dpg.group(horizontal=True, xoffset=xoffset):
dpg.add_text('arch')
dpg.add_radio_button(items=('gpu', 'cpu', 'mix'), label='arch', default_value='cpu', tag='-arch', horizontal=True)
with dpg.group(horizontal=True, xoffset=xoffset):
dpg.add_text('use dump')
dpg.add_checkbox(default_value=False, tag='use-udump', callback=lambda s, a, u: dpg.show_item('-udump-group') if a else dpg.hide_item('-udump-group'))
with dpg.group(horizontal=True, xoffset=xoffset, tag='-udump-group', show=False):
dpg.add_text('dump from this control points')
dpg.add_input_int(default_value=1, width=width, min_value=1, max_value=200, min_clamped=True, max_clamped=True, tag='-udump', enabled=False)
with dpg.group(horizontal=True, xoffset=xoffset):
dpg.add_text('write model stdout to file')
dpg.add_checkbox(default_value=False, tag='use-model-stdout', callback=lambda s, a, u: dpg.show_item('-model-stdout-group') if a else dpg.hide_item('-model-stdout-group'))
with dpg.group(horizontal=True, xoffset=xoffset, tag='-model-stdout-group', show=False):
dpg.add_text('filename')
dpg.add_input_text(default_value='log.txt', tag='-model-stdout', width=width, enabled=False)
def construct_model_output_window():
with dpg.window(label='select model output to download', show=False, tag='model_output_window', width=600, height=600, pos=[50, 50]):
dpg.add_button(label='download selected files')
def construct_crendentials_window():
with dpg.window(label='credentials', show=False, tag='login_modal', width=550, height=350):
with dpg.window(label='credentials', show=False, tag='login_modal', autosize=True, pos=[50, 50]):
dpg.add_input_text(label='server username', tag='server_username', password=False, default_value=os.getenv('SERVER_LOGIN', ''), width=300)
dpg.add_input_text(label='server password', tag='server_password', password=True, default_value=os.getenv('SERVER_PASS', ''), width=300)
dpg.add_input_text(label='gitlab username', tag='gitlab_username', password=False, default_value=os.getenv('GITLAB_LOGIN', ''), width=300)
......@@ -61,11 +96,15 @@ def construct_config_save_as_dialog():
def construct_map_open_dialog():
with dpg.file_dialog(directory_selector=False, show=False, callback=map_open_clb, tag='map_open', width=600, height=400):
dpg.add_file_extension('.txt', color=(0, 255, 0, 255))
dpg.add_file_extension('.tif', color=(0, 255, 0, 255))
dpg.add_file_extension('.tiff', color=(0, 255, 0, 255))
dpg.add_file_extension('.*', color=(255, 255, 255, 255))
def construct_map_save_as_dialog():
with dpg.file_dialog(directory_selector=False, show=False, callback=map_save_as_clb, tag='map_save_as', width=600, height=400):
dpg.add_file_extension('.txt', color=(0, 255, 0, 255))
dpg.add_file_extension('.tif', color=(0, 255, 0, 255))
dpg.add_file_extension('.tiff', color=(0, 255, 0, 255))
dpg.add_file_extension('.*', color=(255, 255, 255, 255))
def construct_set_file_path_dialog():
......@@ -81,18 +120,47 @@ def construct_search_window():
dpg.add_input_text(hint='search for...', on_enter=True, callback=search_clb, tag='search')
def construct_map_edit_window():
with dpg.texture_registry():
dpg.add_dynamic_texture(800, 800, np.zeros((800, 800, 4), dtype=np.uint8), tag='heatmap_texture')
user_data = {
'buildings_map': None,
'trees_map': None,
'roads_map': None,
'height_map_file_path': None,
'drawing': False,
'prev_coords': None,
'current_action': None,
'max_height': 0,
'output_dirs': None,
}
dpg.add_texture_registry(tag='textures')
with dpg.theme() as item_theme:
with dpg.theme_component(dpg.mvAll):
dpg.add_theme_color(dpg.mvThemeCol_ChildBg, (0, 0, 0, 0), category=dpg.mvThemeCat_Core)
dpg.add_theme_style(dpg.mvStyleVar_ChildRounding, 0, category=dpg.mvThemeCat_Core)
dpg.add_colormap_registry(label='colormap registry', tag='colormap_registry')
dpg.add_colormap(list(map(apply_tint, [[0, 0, 0], [100, 100, 100], [255, 255, 255]])), False, tag='colormap', parent='colormap_registry')
with dpg.theme(tag='map_image_theme'):
with dpg.theme_component(dpg.mvAll):
dpg.add_theme_style(dpg.mvStyleVar_WindowPadding, 0, 0, category=dpg.mvThemeCat_Core)
dpg.add_theme_style(dpg.mvStyleVar_ItemSpacing, 0, 0, category=dpg.mvThemeCat_Core)
dpg.add_theme_style(dpg.mvStyleVar_FramePadding, 0, 0, category=dpg.mvThemeCat_Core)
dpg.add_theme_style(dpg.mvStyleVar_ItemInnerSpacing, 0, 0, category=dpg.mvThemeCat_Core)
with dpg.window(label='edit map', tag='map_window', user_data={'height_map': None, 'height_map_file_path': None, 'drawing': False, 'prev_coords': None, 'current_action': None}, horizontal_scrollbar=True, show=False, width=600, height=400, pos=[20, 60], on_close=map_window_on_close_clb):
dpg.add_colormap_registry(label='colormap registry', tag='colormap_registry')
dpg.add_colormap(list(map(apply_tint_func(BUILDING_COLOR), [[0, 0, 0], [100, 100, 100], [255, 255, 255]])), False, tag='buildings_colormap', parent='colormap_registry')
dpg.add_colormap(list(map(apply_tint_func(TREE_COLOR), [[0, 0, 0], [100, 100, 100], [255, 255, 255]])), False, tag='trees_colormap', parent='colormap_registry')
dpg.add_colormap(list(map(apply_tint_func(ROAD_COLOR), [[255, 255, 255], [255, 255, 255], [255, 255, 255]])), False, tag='roads_colormap', parent='colormap_registry')
with dpg.window(
label='edit map',
tag='map_window',
user_data=user_data,
horizontal_scrollbar=True,
show=False,
width=600,
height=400,
pos=[20, 60],
on_close=map_window_on_close_clb):
with dpg.menu_bar():
with dpg.menu(label='file'):
dpg.add_menu_item(label='save', callback=map_save_clb, tag='map_save')
......@@ -100,15 +168,21 @@ def construct_map_edit_window():
with dpg.group(horizontal=True):
with dpg.group(width=200, tag='tools'):
dpg.add_radio_button(items=('buildings', 'trees', 'roads'), tag='layer', default_value='buildings', callback=lambda s, a, u: dpg.bind_colormap('height_input', f'{a}_colormap'))
dpg.add_button(label='erase', callback=set_action_clb, tag='erase')
dpg.add_button(label='draw rectangle', callback=set_action_clb, tag='draw_rect')
dpg.add_button(label='add rectangle', callback=set_action_clb, tag='draw_rect')
dpg.add_colormap_slider(tag='height_input')
dpg.bind_colormap(dpg.last_item(), 'colormap')
dpg.add_image('heatmap_texture', tint_color=(0, 119, 200, 255), tag='map')
dpg.bind_colormap(dpg.last_item(), 'buildings_colormap')
with dpg.child_window(no_scrollbar=True, no_scroll_with_mouse=True, menubar=False, border=True, tag='map_child_window'):
dpg.add_child_window(tag='drawing_frame', show=False, width=0, height=0)
with dpg.child_window(tag='emission_values', show=False, width=100, height=200):
dpg.add_button(label='delete', tag='delete_emission_point')#, callback=delete_emission_point_clb)
dpg.add_text(tag='emission_settings')
dpg.bind_item_theme('drawing_frame', item_theme)
dpg.bind_item_theme('map_child_window', 'map_image_theme')
def construct_ui():
......@@ -119,7 +193,10 @@ def construct_ui():
construct_map_open_dialog()
construct_map_save_as_dialog()
construct_map_edit_window()
construct_crendentials_window()
construct_remote_run_settings_window()
construct_model_output_window()
construct_config_save_as_dialog()
construct_config_open_dialog()
......
import dearpygui.dearpygui as dpg
import re
import threading
import numpy as np
import threading
import dearpygui.dearpygui as dpg
from constants import *
def parse_dirs(s):
filepaths = set(map(lambda x: x[2:], s.strip('\n').split('\n')[1:]))
dirs = set()
for path in filepaths:
lst = path.split('/')
dir_ = '/'.join(lst[:-1])
if dir_:
dirs.add(dir_)
return dirs, filepaths
def get_current_ui_type():
for child in dpg.get_item_children('ui', 1):
if dpg.get_value(child):
......@@ -26,11 +38,11 @@ def set_main_window_value(key, value):
data[key] = value
dpg.set_item_user_data('main', data)
def get_height_map_path():
return dpg.get_item_user_data('map_window')['height_map_file_path']
def get_main_window_value(key):
return dpg.get_item_user_data('main').get(key, None)
def get_height_map():
return dpg.get_item_user_data('map_window')['height_map']
def get_height_map_file_path():
return dpg.get_item_user_data('map_window')['height_map_file_path']
def is_drawing():
return dpg.get_item_user_data('map_window')['drawing']
......@@ -46,32 +58,66 @@ def set_map_window_value(key, value):
data[key] = value
dpg.set_item_user_data('map_window', data)
def get_map_window_value(key):
return dpg.get_item_user_data('map_window').get(key, None)
def show_status_text(message):
dpg.set_item_pos('status_text', (dpg.get_item_width('main') - dpg.get_text_size(message)[0] - 2 * SPACE, dpg.get_item_pos('status_text')[1]))
dpg.set_value('status_text', message)
def get_emission_points():
points = dict()
config = get_config()
for key in config:
if 'point_emission' in key:
point_n = re.findall(r'tracer_([0-9]+)', key)[-1]
if point_n not in points:
points[point_n] = dict()
points[point_n][config[key].key] = config[key].value
return points
def get_max_n_emission_point():
config = get_config()
n = 0
for key in config:
if 'point_emission' in key:
n = max(int(re.findall(r'tracer_([0-9]+)', key)[-1]), n)
return n
def apply_tint_func(tint):
tint = np.array(tint[:-1]) / 255
def func(color):
color = np.array(color) / 255
color *= tint
return list(map(int, (color * 255)))
return func
def apply_tint(color, tint=(0, 119, 200)):
tint = np.array(tint) / 255
color = np.array(color) / 255
color *= tint
return list(map(int, (color * 255)))
def path_iter(path, prefix=""):
namespaces = path.split('.')
for i in range(len(namespaces)):
yield prefix + '.' + '.'.join(namespaces[:i+1])
def delete_item_and_clear_alias(item):
alias = dpg.get_item_alias(item)
if alias:
dpg.remove_alias(alias)
if dpg.does_item_exist(item):
dpg.delete_item(item)
def delete_item_children_and_clear_aliases_(item):
def delete_item_children_and_clear_aliases(item):
if dpg.does_item_exist(item):
for child in dpg.get_item_children(item, 1):
delete_item_children_and_clear_aliases_(child)
delete_item_and_clear_alias(child)
delete_item_children_and_clear_aliases(child)
for child in dpg.get_item_children(item, 2):
delete_item_children_and_clear_aliases(child)
delete_item_and_clear_alias(item)
def delete_item_children_and_clear_aliases():
def delete_config_items_and_clear_aliases():
if len(dpg.get_item_children('main', 1)) > 1:
delete_item_children_and_clear_aliases_(dpg.get_item_children('main', 1)[1])
delete_item_and_clear_alias(dpg.get_item_children('main', 1)[1])
delete_item_children_and_clear_aliases(dpg.get_item_children('main', 1)[1])
####################################################################################
#
......@@ -87,66 +133,6 @@ def change_color_temporarily(text_tag, color, duration=1):
def revert_color(text_tag):
dpg.configure_item(text_tag, color=(255, 255, 255, 255))
####################################################################################
#
# edit map utils
#
####################################################################################
def update_texture(height_map):
max_height = np.max(height_map)
normalized_map = height_map / max_height
texture_data = normalized_map.flatten()
texture_data = np.tile(texture_data, (4, 1)).T.flatten()
texture_data.resize(800 * 800 * 4)
width, height = height_map.shape
dpg.set_value('heatmap_texture', texture_data)
def check_coords(x, y, w, h):
mx, my = dpg.get_item_pos('map')
mw, mh = dpg.get_item_width('map'), dpg.get_item_height('map')
return mx <= x <= x + w <= mx + mw and my <= y <= y + h <= my + mh
def apply_tint(color, tint=(0, 119, 200)):
tint = np.array(tint) / 255
color = np.array(color) / 255
color *= tint
return list(map(int, (color * 255)))
def adjust_coords(coords):
x, y = coords
return int(x - dpg.get_item_pos('map')[0] + dpg.get_x_scroll('map_window')), int(y - dpg.get_item_pos('map')[1] + dpg.get_text_size('edit map')[1] + 2 * SPACE + dpg.get_y_scroll('map_window'))
def get_rect(cur_pos, end_pos):
x1, y1 = adjust_coords(cur_pos)
x2, y2 = adjust_coords(end_pos)
if y2 < y1:
y1, y2 = y2, y1
if x2 < x1:
x1, x2 = x2, x1
return y1, y2, x1, x2
def load_height_map(file_path):
with open(file_path, "r") as file:
lines = file.readlines()[1:]
height_map = [list(map(int, line.strip().split())) for line in lines]
return np.array(height_map)
def dump_map(height_map, file_path):
with open(file_path, "w", encoding="utf-8") as file:
w, h = height_map.shape
file.write(f"{w} {h}\n")
for row in height_map:
file.write(" ".join(list(map(str, row))) + "\n")
####################################################################################
#
# main menu utils
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment