"""
Companion manager for LAZ menu and actions.
Extracted from PyDraw.WolfMapViewer.
"""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
import wx
from ._action_kind import ActionKind
from .PyTranslate import _
from .PyVertex import cloud_vertices
from .PyVertexvectors import vector, wolfvertex
from .color_constants import getIfromRGB
if TYPE_CHECKING:
from .PyDraw import WolfMapViewer
[docs]
class LazManager:
"""Manages LAZ menu construction and menu actions."""
def __init__(self, viewer: "WolfMapViewer") -> None:
# ------------------------------------------------------------------
# Individual menu handlers
# ------------------------------------------------------------------
[docs]
def _on_init_laz(self, event: wx.MenuEvent) -> None:
self._viewer.init_laz_from_lazlasnpz()
[docs]
def _on_init_lazgrid(self, event: wx.MenuEvent) -> None:
self._viewer.init_laz_from_gridinfos()
[docs]
def _on_copy_zoom(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is None:
logging.warning(_('No gridded LAZ data loaded !'))
return
dlg = wx.DirDialog(None, _('Choose a directory to copy the files'), _('Copy files'), style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
dirout = dlg.GetPath()
dlg.Destroy()
curbounds = [[v.xmin, v.xmin + v.width], [v.ymin, v.ymin + v.height]]
v.mylazgrid.copy_files_in_bounds(curbounds, dirout)
[docs]
def _on_change_colors(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is not None:
v.mylazgrid.colors.interactive_update_colors()
[docs]
def _on_cloud_bridges(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.active_laz is None:
v.init_laz_from_lazlasnpz()
if v.active_laz is None:
return
mybridges = v.active_laz.get_data_class(10)
mycloud = cloud_vertices()
mycloud.init_from_nparray(mybridges)
mycloud.myprop.style = 2
mycloud.myprop.color = getIfromRGB([255, 102, 102])
mycloud.myprop.width = 0.5
if v.linked and v.linkedList is not None and len(v.linkedList) > 0:
for curframe in v.linkedList:
curframe.add_object('cloud', newobj=mycloud, ToCheck=True, id='Bridges')
else:
v.add_object('cloud', newobj=mycloud, ToCheck=True, id='Bridges')
[docs]
def _on_cloud_buildings(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.active_laz is None:
v.init_laz_from_lazlasnpz()
if v.active_laz is None:
return
mybuildings = v.active_laz.get_data_class(1)
mycloud = cloud_vertices()
mycloud.init_from_nparray(mybuildings)
mycloud.myprop.style = 2
mycloud.myprop.color = getIfromRGB([102, 102, 102])
mycloud.myprop.width = 0.5
if v.linked and v.linkedList is not None and len(v.linkedList) > 0:
for curframe in v.linkedList:
curframe.add_object('cloud', newobj=mycloud, ToCheck=True, id='Buildings')
else:
v.add_object('cloud', newobj=mycloud, ToCheck=True, id='Buildings')
[docs]
def _on_cloud_classes(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.active_laz is None:
v.init_laz_from_lazlasnpz()
if v.active_laz is None:
return
codes = v.active_laz.codes_unique
dlg = wx.MultiChoiceDialog(None, _('Choose the classes to plot'), _('Classes'), codes)
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
selected = [codes[cur] for cur in dlg.GetSelections()]
dlg.Destroy()
for curcode in selected:
mycloud = cloud_vertices()
mydata = v.active_laz.get_data_class(curcode)
mycloud.init_from_nparray(mydata)
mycloud.myprop.style = 2
mycloud.myprop.color = getIfromRGB([102, 102, 102])
mycloud.myprop.width = 0.5
if v.linked and v.linkedList is not None and len(v.linkedList) > 0:
for curframe in v.linkedList:
curframe.add_object('cloud', newobj=mycloud, ToCheck=True, id='Class {}'.format(curcode))
else:
v.add_object('cloud', newobj=mycloud, ToCheck=True, id='Class {}'.format(curcode))
[docs]
def _on_clip_lazgrid(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is None:
logging.warning(_('No gridded LAZ data loaded !'))
return
v.clip_laz_gridded()
if v.active_laz is None:
logging.error(_('No data found'))
return
if v.active_laz.data.shape[0] > 100_000_000:
dlg = wx.NumberEntryDialog(
None,
_('Your data selection is very large (>100 M)\nWould you like to descimate?\n\n{} points').format(v.active_laz.data.shape[0]),
_('Descimate factor'),
_('Decimation'),
0,
0,
100,
)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
descimate_fact = dlg.GetValue()
dlg.Destroy()
if descimate_fact > 0:
v.descimate_laz_data(descimate_fact)
[docs]
def _on_create_viewer(self, event: wx.MenuEvent) -> None:
v = self._viewer
laz_source = v._select_laz_source()
if laz_source is None:
logging.warning(_('No LAZ data loaded !'))
return
if laz_source is v.mylazgrid:
if v.mylazgrid is None:
logging.warning(_('No gridded LAZ data loaded !'))
return
v.clip_laz_gridded()
if v.active_laz.nb_points == 0:
logging.warning(_('No points in the active LAZ object -- Aborting !'))
return
v.active_laz.create_viewer(v._choice_laz_colormap(), v.mylazgrid.colors)
v.myviewerslaz.append(v.active_laz.viewer)
v.active_viewerlaz = v.myviewerslaz[-1]
else:
if v.active_laz.nb_points == 0:
logging.warning(_('No points in the active LAZ object -- Aborting !'))
return
v.active_laz.create_viewer()
v.myviewerslaz.append(v.active_laz.viewer)
v.active_viewerlaz = v.myviewerslaz[-1]
[docs]
def _on_filter_codes(self, event: wx.MenuEvent) -> None:
self._viewer.filter_active_laz()
[docs]
def _on_decimate(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.active_laz is None:
return
dlg = wx.NumberEntryDialog(
None,
_('Your dataset contains {} points.\nWould you like to descimate?').format(v.active_laz.num_points),
_('Decaimate factor'),
_('Decimation'),
0,
0,
100,
)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
descimate_fact = dlg.GetValue()
dlg.Destroy()
if descimate_fact > 0:
v.active_laz.descimate(descimate_fact)
logging.info(_('New count : {}').format(v.active_laz.num_points))
[docs]
def _on_plot_active_vec(self, event: wx.MenuEvent) -> None:
self._viewer.plot_laz_around_active_vec()
[docs]
def _on_plot_tmp_vec(self, event: wx.MenuEvent) -> None:
v = self._viewer
v.active_vector = vector()
v.active_vector.add_vertex(wolfvertex(0.0, 0.0))
v.mimicme()
v.start_action(ActionKind.LAZ_TMP_VECTOR, _('LAZ tmp'))
[docs]
def _on_fill_array(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is None:
logging.warning('')
return
if v.active_array is None:
logging.warning(_('No active array -- select an array first and retry!'))
return
v.fill_active_array_from_laz(v.active_array)
[docs]
def _on_select_cells(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is None:
logging.warning('')
return
if v.active_array is None:
logging.warning(_('No active array -- select an array first and retry!'))
return
v.select_active_array_from_laz(v.active_array)
[docs]
def _on_count_cells(self, event: wx.MenuEvent) -> None:
v = self._viewer
if v.mylazgrid is None:
logging.warning('')
return
if v.active_array is None:
logging.warning(_('No active array -- select an array first and retry!'))
return
v.count_active_array_from_laz(v.active_array)