wolfhece 2.1.117__py3-none-any.whl → 2.1.119__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wolfhece/PyDraw.py CHANGED
@@ -25,9 +25,11 @@ try:
25
25
  import glob
26
26
  import traceback
27
27
  from datetime import datetime, timedelta
28
+ from sklearn import linear_model, datasets
29
+
28
30
  except ImportError as e:
29
31
  print(e)
30
- raise ImportError("Error importing wxPython, numpy, PIL, json, glob, traceback. Please check your installation.")
32
+ raise ImportError("Error importing wxPython, numpy, PIL, json, glob, traceback, sklearn. Please check your installation.")
31
33
 
32
34
  try:
33
35
  from osgeo import gdal
@@ -84,7 +86,7 @@ try:
84
86
  from .Results2DGPU import wolfres2DGPU
85
87
  from .PyCrosssections import crosssections, profile, Interpolator, Interpolators
86
88
  from .GraphNotebook import PlotNotebook
87
- from .lazviewer.laz_viewer import myviewer, read_laz, clip_data_xyz, xyz_laz_grids, choices_laz_colormap, Classification_LAZ
89
+ from .lazviewer.laz_viewer import myviewer, read_laz, clip_data_xyz, xyz_laz_grids, choices_laz_colormap, Classification_LAZ, Wolf_LAZ_Data, viewer as viewerlaz
88
90
  from . import Lidar2002
89
91
  from .picc import Picc_data, Cadaster_data
90
92
  from .wolf_zi_db import ZI_Databse_Elt, PlansTerrier
@@ -112,6 +114,7 @@ try:
112
114
  from .lagrangian.particle_system_ui import Particle_system_to_draw as Particle_system
113
115
  from .opengl.py3d import Wolf_Viewer3D
114
116
  from .pyGui1D import GuiNotebook1D
117
+ from .matplotlib_fig import Matplotlib_Figure as MplFig
115
118
  except ImportError as e:
116
119
  print(e)
117
120
  raise ImportError("Error importing pyshields, pyviews, PyConfig, GraphProfile, pybridges, tools_mpl, wolf_tiles, lagrangian.particle_system_ui, opengl.py3d, pyGui1D. Please check your installation.")
@@ -557,6 +560,7 @@ class draw_type(Enum):
557
560
  WMSFORE = 'wms-foreground'
558
561
  TILES = 'tiles'
559
562
  IMAGESTILES = 'imagestiles'
563
+ LAZ = 'laz'
560
564
 
561
565
  class Colors_1to9(wx.Frame):
562
566
 
@@ -1171,6 +1175,8 @@ class WolfMapViewer(wx.Frame):
1171
1175
  myimagestiles: list[ImagesTiles]
1172
1176
  mypartsystems: list[Particle_system]
1173
1177
  myviewers3d:list[Wolf_Viewer3D]
1178
+ mylazdata:list[Wolf_LAZ_Data]
1179
+
1174
1180
  sim_explorers: dict[Wolfresults_2D:Sim_Explorer]
1175
1181
 
1176
1182
  canvas: GLCanvas # canvas OpenGL
@@ -1196,10 +1202,12 @@ class WolfMapViewer(wx.Frame):
1196
1202
  active_imagestiles: ImagesTiles
1197
1203
  active_particle_system: Particle_system
1198
1204
  active_viewer3d: Wolf_Viewer3D
1205
+ active_viewerlaz: viewerlaz
1199
1206
  active_bridges: Bridges
1200
1207
  active_bridge: Bridge
1201
1208
  active_weirs : Weirs
1202
1209
  active_weir : Weir
1210
+ active_laz : Wolf_LAZ_Data
1203
1211
 
1204
1212
  def __init__(self,
1205
1213
  wxparent = None,
@@ -1275,9 +1283,7 @@ class WolfMapViewer(wx.Frame):
1275
1283
  self.forcemimic = True
1276
1284
  self.currently_readresults = False
1277
1285
 
1278
- self.mylazdata = None
1279
- # self.mylazdata_colors = None
1280
- self.mylazgrid = None
1286
+ self.mylazgrid:xyz_laz_grids = None # LAZ grid preprocessed by Numpy
1281
1287
 
1282
1288
  self.colors1to9 = Colors_1to9(self)
1283
1289
 
@@ -1309,7 +1315,7 @@ class WolfMapViewer(wx.Frame):
1309
1315
  self.menuimagestiles = None
1310
1316
 
1311
1317
  self.filemenu = wx.Menu()
1312
- openitem = self.filemenu.Append(wx.ID_OPEN, _('Open/Add project'), _('Open a complete project from file'))
1318
+ openitem = self.filemenu.Append(wx.ID_OPEN, _('Open/Add project'), _('Open a full project from file'))
1313
1319
  saveproject = self.filemenu.Append(wx.ID_ANY, _('Save project as...'), _('Save the current project to file'))
1314
1320
  self.filemenu.AppendSeparator()
1315
1321
  saveitem = self.filemenu.Append(wx.ID_SAVE, _('Save'), _('Save all checked arrays or vectors to files'))
@@ -1535,6 +1541,7 @@ class WolfMapViewer(wx.Frame):
1535
1541
  self.active_res2d = None
1536
1542
  self.active_particle_system = None
1537
1543
  self.active_viewer3d = None
1544
+ self.active_viewerlaz = None
1538
1545
  self.active_landmap:PlansTerrier = None
1539
1546
  self.active_tile = None
1540
1547
  self.selected_treeitem = None
@@ -1543,6 +1550,7 @@ class WolfMapViewer(wx.Frame):
1543
1550
  self.active_bridge = None
1544
1551
  self.active_weirs = None
1545
1552
  self.active_weir = None
1553
+ self.active_laz = None
1546
1554
 
1547
1555
  curtool = self.tools[ID_SORTALONG] = {}
1548
1556
  curtool['menu'] = self.sortalong
@@ -1591,14 +1599,15 @@ class WolfMapViewer(wx.Frame):
1591
1599
 
1592
1600
  self.root = self.treelist.GetRootItem()
1593
1601
  self.treelist.AppendColumn(_('Objects to plot'))
1594
- self.myitemsarray = self.treelist.AppendItem(self.root, _("Arrays"))
1602
+ self.myitemsarray = self.treelist.AppendItem(self.root, _("Arrays"))
1595
1603
  self.myitemsvector = self.treelist.AppendItem(self.root, _("Vectors"))
1596
- self.myitemscloud = self.treelist.AppendItem(self.root, _("Clouds"))
1597
- self.myitemstri = self.treelist.AppendItem(self.root, _("Triangulations"))
1598
- self.myitemsres2d = self.treelist.AppendItem(self.root, _("Wolf2D"))
1599
- self.myitemsps = self.treelist.AppendItem(self.root, _("Particle systems"))
1604
+ self.myitemscloud = self.treelist.AppendItem(self.root, _("Clouds"))
1605
+ self.myitemslaz = self.treelist.AppendItem(self.root, _("Laz"))
1606
+ self.myitemstri = self.treelist.AppendItem(self.root, _("Triangulations"))
1607
+ self.myitemsres2d = self.treelist.AppendItem(self.root, _("Wolf2D"))
1608
+ self.myitemsps = self.treelist.AppendItem(self.root, _("Particle systems"))
1600
1609
  self.myitemsothers = self.treelist.AppendItem(self.root, _("Others"))
1601
- self.myitemsviews = self.treelist.AppendItem(self.root, _("Views"))
1610
+ self.myitemsviews = self.treelist.AppendItem(self.root, _("Views"))
1602
1611
  self.myitemswmsback = self.treelist.AppendItem(self.root, _("WMS-background"))
1603
1612
  self.myitemswmsfore = self.treelist.AppendItem(self.root, _("WMS-foreground"))
1604
1613
 
@@ -1922,17 +1931,20 @@ class WolfMapViewer(wx.Frame):
1922
1931
  self.menulaz.AppendSubMenu(self.menulazdata, _('LAZ data'))
1923
1932
  self.menulaz.AppendSubMenu(self.menulazgrid, _('LAZ grid'))
1924
1933
 
1925
- readlaz = self.menulazdata.Append(wx.ID_ANY, _('Initialize from npz'), _('LAZ from Numpy array'))
1926
- readlaz_gridinfo = self.menulazgrid.Append(wx.ID_ANY, _('Initialize from GridInfos'), _('LAZ from gridinfos - subgridding of LAZ files'), kind=wx.ITEM_CHECK)
1934
+ readlaz = self.menulazdata.Append(wx.ID_ANY, _('Initialize from laz, las or npz'), _('LAZ data from one specific file (type laz, las or npz)'))
1935
+ readlaz_gridinfo = self.menulazgrid.Append(wx.ID_ANY, _('Initialize from directory'), _('LAZ GRID stored in a directory - subgridding of LAZ files'), kind=wx.ITEM_CHECK)
1936
+ updatecolors_laz = self.menulazgrid.Append(wx.ID_ANY, _('Change colors - Classification'), _('Change color map associated to the current classification'),)
1927
1937
 
1928
- bridgelaz = self.menulazdata.Append(wx.ID_ANY, _('Create cloud points from bridges'), _('LAZ Bridge'))
1929
- buildinglaz = self.menulazdata.Append(wx.ID_ANY, _('Create cloud points from buildings'), _('LAZ Buildings'))
1938
+ bridgelaz = self.menulazdata.Append(wx.ID_ANY, _('Create cloud points from bridges'), _('Extract bridge from LAZ data as cloud points (class 10)'))
1939
+ buildinglaz = self.menulazdata.Append(wx.ID_ANY, _('Create cloud points from buildings'), _('Extract buildings from LAZ data as cloud points (class 1)'))
1940
+ classlaz = self.menulazdata.Append(wx.ID_ANY, _('Create cloud points from specified classes'), _('Extract cloud points from LAZ data (class to specify)'))
1930
1941
 
1931
1942
  croplaz = self.menulaz.Append(wx.ID_ANY, _('Clip LAZ grid on current zoom'), _('Select LAZ data based on the visible screen extent'),)
1932
1943
  viewlaz = self.menulaz.Append(wx.ID_ANY, _('Create LAZ viewer'), _('Create a LAZ Viewer based on loaded data'))
1944
+ filterlaz = self.menulaz.Append(wx.ID_ANY, _('Filter data based on codes'), _('Filter LAZ data based on codes'),)
1945
+ descimate_laz = self.menulaz.Append(wx.ID_ANY, _('Descimate LAZ data'), _('Descimate LAZ data'),)
1933
1946
  aroundlaz = self.menulaz.Append(wx.ID_ANY, _('Plot LAZ around active vector'), _('Display a Matplotlib plot with the LAZ values around the active vector/polyline'),)
1934
1947
  pick_aroundlaz = self.menulaz.Append(wx.ID_ANY, _('Plot LAZ around temporary vector'), _('Display a Matplotlib plot with the LAZ values around a temporary vector/polyline -- Right clicks to add points + Enter'),)
1935
- updatecolors_laz = self.menulaz.Append(wx.ID_ANY, _('Change colors - Classification'), _('Change color map associated to the current classification'),)
1936
1948
  fillarray_laz = self.menulaz.Append(wx.ID_ANY, _('Fill active array from LAZ data'), _('Fill an array from the LAZ data'),)
1937
1949
  selectarray_laz = self.menulaz.Append(wx.ID_ANY, _('Select cells in array from LAZ data'), _('Select nodes in active array from the LAZ data'),)
1938
1950
  countarray_laz = self.menulaz.Append(wx.ID_ANY, _('Count LAZ data in cells'), _('Count the number of LAZ data in each cell of the matrix'),)
@@ -3890,10 +3902,13 @@ class WolfMapViewer(wx.Frame):
3890
3902
  self.mywmsfore = []
3891
3903
  self.myres2D = []
3892
3904
  self.myviewers3d = []
3905
+ self.myviewerslaz = []
3906
+ self.mylazdata = []
3907
+
3893
3908
  self.sim_explorers = {}
3894
3909
 
3895
3910
  # liste des éléments modifiable dans l'arbre
3896
- self.all_lists = [self.myarrays, self.myvectors, self.myclouds, self.mytri, self.myothers, self.myviews, self.myres2D, self.mytiles, self.myimagestiles, self.mypartsystems, self.myviewers3d]
3911
+ self.all_lists = [self.myarrays, self.myvectors, self.myclouds, self.mytri, self.myothers, self.myviews, self.myres2D, self.mytiles, self.myimagestiles, self.mypartsystems, self.myviewers3d, self.myviewerslaz]
3897
3912
 
3898
3913
  self.menu_options = wx.Menu()
3899
3914
  self._change_title = self.menu_options.Append(wx.ID_ANY, _('Change title'), _('Change title of the window'))
@@ -3995,7 +4010,7 @@ class WolfMapViewer(wx.Frame):
3995
4010
  self.ymin = self.mousey - height / 2.
3996
4011
  self.ymax = self.ymin + height
3997
4012
 
3998
- def setbounds(self,updatescale=True):
4013
+ def setbounds(self, updatescale=True):
3999
4014
  """
4000
4015
  Calcule les limites visibles de la fenêtrte graphique sur base des
4001
4016
  facteurs d'échelle courants
@@ -5524,22 +5539,66 @@ class WolfMapViewer(wx.Frame):
5524
5539
  """ Clip laz grid on current zoom """
5525
5540
 
5526
5541
  if self.mylazgrid is None:
5542
+ logging.warning(_('No laz grid -- Please initialize it !'))
5527
5543
  return
5528
5544
 
5529
5545
  curbounds = [[self.xmin, self.xmin + self.width], [self.ymin, self.ymin + self.height]]
5530
5546
 
5531
- self.mylazdata = self.mylazgrid.scan(curbounds)
5547
+ if self.active_laz is None:
5548
+ newobj = Wolf_LAZ_Data()
5549
+ newobj.classification = self.mylazgrid.colors
5550
+ newobj.from_grid(self.mylazgrid, curbounds)
5551
+
5552
+ self.add_object('laz', newobj= newobj)
5553
+
5554
+ else:
5555
+ dlg = wx.MessageDialog(None, _('Do you want to keep the current data ?'), _('Keep data ?'), wx.YES_NO | wx.ICON_QUESTION)
5556
+ ret = dlg.ShowModal()
5557
+
5558
+ if ret == wx.ID_YES:
5559
+ newobj = Wolf_LAZ_Data()
5560
+ newobj.classification = self.mylazgrid.colors
5561
+ newobj.from_grid(self.mylazgrid, curbounds)
5562
+
5563
+ self.add_object('laz', newobj= newobj)
5564
+
5565
+ else:
5566
+
5567
+ self.active_laz.from_grid(self.mylazgrid, curbounds)
5532
5568
 
5533
- logging.info(_('Clip LAZ grid on current zoom {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
5569
+ logging.info(_('Clip LAZ grid on current zoom'))
5570
+ logging.info(_('Bounds {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
5571
+ logging.info(_('Nb points : {}').format(self.active_laz.num_points))
5534
5572
 
5535
- def decimate_laz_data(self, factor:int = 10):
5536
- """ Decimate data """
5573
+ def filter_active_laz(self):
5574
+ """ Filter active laz data """
5537
5575
 
5538
- if self.mylazdata is None:
5576
+ if self.active_laz is None:
5539
5577
  logging.warning(_('No laz data'))
5540
5578
  return
5541
5579
 
5542
- self.mylazdata = self.mylazdata[::factor]
5580
+ codes = self.active_laz.codes_unique()
5581
+
5582
+ names = [self.active_laz.classification.classification[curcode][0] for curcode in codes]
5583
+
5584
+ with wx.MultiChoiceDialog(None, _('Choose the codes to keep'), _('Codes'), names) as dlg:
5585
+ if dlg.ShowModal() == wx.ID_OK:
5586
+ used_codes = dlg.GetSelections()
5587
+ used_codes = [codes[cur] for cur in used_codes]
5588
+ self.active_laz.filter_data(used_codes)
5589
+
5590
+ logging.info(_('Filter done - Nb points : {}').format(self.active_laz.num_points))
5591
+ else:
5592
+ logging.info(_('Filter cancelled'))
5593
+
5594
+ def descimate_laz_data(self, factor:int = 10):
5595
+ """ Descimate data """
5596
+
5597
+ if self.active_laz is None:
5598
+ logging.warning(_('No laz data'))
5599
+ return
5600
+
5601
+ self.active_laz.descimate(factor)
5543
5602
 
5544
5603
  def select_active_array_from_laz(self, array:WolfArray = None, used_codes:list = None, chunk_size:float = 500.):
5545
5604
  """ select some nodes from laz data
@@ -5548,6 +5607,7 @@ class WolfMapViewer(wx.Frame):
5548
5607
  :param used_codes: codes to use
5549
5608
  """
5550
5609
  if self.mylazgrid is None:
5610
+ logging.info(_('No laz grid - Aborting !'))
5551
5611
  return
5552
5612
 
5553
5613
  if array is None:
@@ -5581,19 +5641,19 @@ class WolfMapViewer(wx.Frame):
5581
5641
  curbounds = [[curx, curx + chunk_size], [cury, cury + chunk_size]]
5582
5642
 
5583
5643
  logging.info(_('Scan {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
5584
- self.mylazdata = self.mylazgrid.scan(curbounds)
5644
+ mylazdata = self.mylazgrid.scan(curbounds)
5585
5645
  # logging.info(_('Scan done'))
5586
5646
 
5587
5647
  data = {}
5588
5648
  for curcode in used_codes:
5589
- data[curcode] = self.mylazdata[self.mylazdata[:, 3] == curcode]
5649
+ data[curcode] = mylazdata[mylazdata[:, 3] == curcode]
5590
5650
 
5591
5651
  for curdata in data.values():
5592
5652
 
5593
5653
  if curdata.shape[0] == 0:
5594
5654
  continue
5595
5655
 
5596
- i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1]) #= np.float32(self.mylazdata[:, 2])
5656
+ i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1])
5597
5657
 
5598
5658
  keys = np.vstack((i,j)).T
5599
5659
 
@@ -5616,6 +5676,7 @@ class WolfMapViewer(wx.Frame):
5616
5676
  """
5617
5677
 
5618
5678
  if self.mylazgrid is None:
5679
+ logging.info(_('No laz grid - Aborting !'))
5619
5680
  return
5620
5681
 
5621
5682
  if array is None:
@@ -5679,16 +5740,16 @@ class WolfMapViewer(wx.Frame):
5679
5740
  curbounds = [[curx, curx + chunk_size], [cury, cury + chunk_size]]
5680
5741
 
5681
5742
  logging.info(_('Scan {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
5682
- self.mylazdata = self.mylazgrid.scan(curbounds)
5743
+ mylazdata = self.mylazgrid.scan(curbounds)
5683
5744
  # logging.info(_('Scan done'))
5684
5745
 
5685
- if len(self.mylazdata) == 0:
5746
+ if len(mylazdata) == 0:
5686
5747
  continue
5687
5748
 
5688
5749
  # Test codes
5689
5750
  data = {}
5690
5751
  for curcode in used_codes:
5691
- data[curcode] = self.mylazdata[self.mylazdata[:, 3] == curcode]
5752
+ data[curcode] = mylazdata[mylazdata[:, 3] == curcode]
5692
5753
 
5693
5754
  # Treat data for each code
5694
5755
  for curdata in data.values():
@@ -5699,7 +5760,7 @@ class WolfMapViewer(wx.Frame):
5699
5760
  logging.info(_('Code {} : {} points'.format(curdata[0,3], curdata.shape[0])))
5700
5761
 
5701
5762
  # get i,j from x,y
5702
- i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1]) #= np.float32(self.mylazdata[:, 2])
5763
+ i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1])
5703
5764
 
5704
5765
  # keep only valid points -- inside the array
5705
5766
  used = np.where((i >=0) & (i < array.nbx) & (j >=0) & (j < array.nby))[0]
@@ -5766,6 +5827,7 @@ class WolfMapViewer(wx.Frame):
5766
5827
  """
5767
5828
 
5768
5829
  if self.mylazgrid is None:
5830
+ logging.info(_('No laz grid - Aborting !'))
5769
5831
  return
5770
5832
 
5771
5833
  if array is None:
@@ -5801,15 +5863,15 @@ class WolfMapViewer(wx.Frame):
5801
5863
  curbounds = [[curx, curx + chunk_size], [cury, cury + chunk_size]]
5802
5864
 
5803
5865
  logging.info(_('Scan {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
5804
- self.mylazdata = self.mylazgrid.scan(curbounds)
5866
+ mylazdata = self.mylazgrid.scan(curbounds)
5805
5867
 
5806
- if len(self.mylazdata) == 0:
5868
+ if len(mylazdata) == 0:
5807
5869
  continue
5808
5870
 
5809
5871
  # Test codes
5810
5872
  data = {}
5811
5873
  for curcode in used_codes:
5812
- data[curcode] = self.mylazdata[self.mylazdata[:, 3] == curcode]
5874
+ data[curcode] = mylazdata[mylazdata[:, 3] == curcode]
5813
5875
 
5814
5876
  # Treat data for each code
5815
5877
  for curdata in data.values():
@@ -5820,7 +5882,7 @@ class WolfMapViewer(wx.Frame):
5820
5882
  logging.info(_('Code {} : {} points'.format(curdata[0,3], curdata.shape[0])))
5821
5883
 
5822
5884
  # get i,j from x,y
5823
- i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1]) #= np.float32(self.mylazdata[:, 2])
5885
+ i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1])
5824
5886
 
5825
5887
  # keep only valid points -- inside the array
5826
5888
  used = np.where((i >=0) & (i < array.nbx) & (j >=0) & (j < array.nby))[0]
@@ -5877,26 +5939,48 @@ class WolfMapViewer(wx.Frame):
5877
5939
 
5878
5940
  logging.info(_('Counting done'))
5879
5941
 
5880
- def init_laz_from_numpy(self, fn=None):
5881
- """ Read LAZ data stored in numpy array"""
5942
+ def init_laz_from_lazlasnpz(self, fn=None):
5943
+ """ Read LAZ data stored in one file
5944
+
5945
+ :param fn: filename (extension .laz, .las, .npz)
5946
+ """
5882
5947
 
5883
5948
  if fn is None:
5884
5949
  filternpz = "npz (*.npz)|*.npz|LAZ (*.laz)|*.laz|LAS (*.las)|*.las|all (*.*)|*.*"
5885
- dlg = wx.FileDialog(None, _('Choose LAS file'), wildcard=filternpz)
5950
+ dlg = wx.FileDialog(None, _('Choose a file containing LAS data'), wildcard=filternpz)
5886
5951
  ret = dlg.ShowModal()
5887
5952
  if ret != wx.ID_OK:
5953
+ dlg.Destroy()
5888
5954
  return
5889
5955
 
5890
5956
  fn = dlg.GetPath()
5957
+ dlg.Destroy()
5958
+
5959
+ self.mylazdata.append(Wolf_LAZ_Data())
5960
+ self.active_laz = self.mylazdata[-1]
5961
+ self.active_laz.from_file(fn)
5891
5962
 
5892
- self.mylazdata = read_laz(fn)
5893
- # self.mylazdata_colors = Classification_LAZ()
5894
- # self.mylazdata_colors.init_2023()
5963
+ logging.info(_('LAZ data read from file : ')+ fn)
5964
+ logging.info(_('Stored in internal variable'))
5895
5965
 
5896
5966
  if self.linked:
5897
5967
  if len(self.linkedList) > 0:
5898
5968
  for curframe in self.linkedList:
5899
- curframe.mylazdata = self.mylazdata
5969
+ if not curframe is self:
5970
+ curframe.mylazdata.append(self.active_laz)
5971
+
5972
+ def _choice_laz_classification(self):
5973
+
5974
+ dlg = wx.SingleChoiceDialog(None, _('Choose the classification'), _('Classification'), ['SPW-Geofit 2023', 'SPW 2013-2014'], wx.CHOICEDLG_STYLE)
5975
+ ret = dlg.ShowModal()
5976
+ if ret != wx.ID_OK:
5977
+ dlg.Destroy()
5978
+ return None
5979
+
5980
+ classification = dlg.GetStringSelection()
5981
+ dlg.Destroy()
5982
+
5983
+ return classification
5900
5984
 
5901
5985
  def init_laz_from_gridinfos(self, dirlaz:str = None, classification:Literal['SPW-Geofit 2023', 'SPW 2013-2014'] = 'SPW-Geofit 2023'):
5902
5986
 
@@ -5911,15 +5995,13 @@ class WolfMapViewer(wx.Frame):
5911
5995
  self.mylazgrid = xyz_laz_grids(dirlaz)
5912
5996
 
5913
5997
  if classification not in ['SPW-Geofit 2023', 'SPW 2013-2014']:
5914
- dlg = wx.SingleChoiceDialog(None, _('Choose the classification'), _('Classification'), ['SPW-Geofit 2023', 'SPW 2013-2014'], wx.CHOICEDLG_STYLE)
5915
- ret = dlg.ShowModal()
5916
- if ret != wx.ID_OK:
5917
- dlg.Destroy()
5918
- return
5919
- classification = dlg.GetStringSelection()
5920
- dlg.Destroy()
5921
5998
 
5922
- if classification == 'SPW 2013-2014':
5999
+ classification = self._choice_laz_classification()
6000
+
6001
+ if classification is None:
6002
+ logging.warning(_('No classification chosen - Abort !'))
6003
+ return
6004
+ elif classification == 'SPW 2013-2014':
5923
6005
  self.mylazgrid.colors.init_2013()
5924
6006
  else:
5925
6007
  self.mylazgrid.colors.init_2023()
@@ -6129,15 +6211,23 @@ class WolfMapViewer(wx.Frame):
6129
6211
  def _select_laz_source(self):
6130
6212
  """ Select laz source """
6131
6213
 
6132
- if self.mylazdata is None and self.mylazgrid is None:
6133
- logging.warning(_('No LAZ data loaded !'))
6214
+ if self.active_laz is None and self.mylazgrid is None:
6215
+ logging.warning(_('No LAZ data loaded/initialized !'))
6134
6216
  return None
6135
- elif self.mylazdata is None:
6217
+ elif self.active_laz is None:
6218
+ # No active laz data
6136
6219
  laz_source = self.mylazgrid
6137
6220
  elif self.mylazgrid is None:
6138
- laz_source = self.mylazdata
6221
+ # No laz grid
6222
+ laz_source = self.active_laz
6139
6223
  else:
6140
- choices = [_('From current loaded data'), _('From GridInfos')]
6224
+ # We have both
6225
+ choices = [_('From active LAZ data'), _('From newly extracted data')]
6226
+
6227
+ keys = self.get_list_keys(draw_type.LAZ, None)
6228
+ if len(keys) > 1:
6229
+ choices.append(_('From multiple LAZ data'))
6230
+
6141
6231
  dlg = wx.SingleChoiceDialog(None, _("Pick a data source"), "Choices", choices)
6142
6232
  ret = dlg.ShowModal()
6143
6233
  if ret == wx.ID_CANCEL:
@@ -6149,12 +6239,46 @@ class WolfMapViewer(wx.Frame):
6149
6239
  dlg.Destroy()
6150
6240
 
6151
6241
  if idx == 0:
6152
- laz_source = self.mylazdata
6153
- else:
6242
+ laz_source = self.active_laz
6243
+ elif idx == 1:
6154
6244
  laz_source = self.mylazgrid
6245
+ else:
6246
+ dlg = wx.MultiChoiceDialog(None, _('Choose the LAZ data to use\n\nIf multiple, a new one will be created !'), _('LAZ data'), keys)
6247
+ if dlg.ShowModal() == wx.ID_OK:
6248
+ used_keys = dlg.GetSelections()
6249
+ used_keys = [keys[cur] for cur in used_keys]
6250
+ laz_source = Wolf_LAZ_Data()
6251
+ for curkey in used_keys:
6252
+ laz_source.merge(self.get_obj_from_id(curkey, draw_type.LAZ))
6253
+
6254
+ self.add_object('laz', newobj=laz_source, id = 'Merged LAZ data')
6255
+ dlg.Destroy()
6256
+ else:
6257
+ dlg.Destroy()
6258
+ return None
6155
6259
 
6156
6260
  return laz_source
6157
6261
 
6262
+ def _choice_laz_colormap(self) -> int:
6263
+
6264
+ choices, ass_values = choices_laz_colormap()
6265
+ dlg = wx.SingleChoiceDialog(None, _("Pick a colormap"), "Choices", choices)
6266
+
6267
+ if self.active_laz is not None:
6268
+ dlg.SetSelection(ass_values.index(self.active_laz.associated_color))
6269
+
6270
+ ret = dlg.ShowModal()
6271
+ if ret == wx.ID_CANCEL:
6272
+ dlg.Destroy()
6273
+ return
6274
+
6275
+ colormap = dlg.GetStringSelection()
6276
+ idx = choices.index(colormap)
6277
+ dlg.Destroy()
6278
+
6279
+ return ass_values[idx]
6280
+
6281
+
6158
6282
  def OnMenubar(self, event: wx.MenuEvent):
6159
6283
  """
6160
6284
  Gestion des clicks sur le menu quel que soit le niveau
@@ -6498,7 +6622,13 @@ class WolfMapViewer(wx.Frame):
6498
6622
 
6499
6623
  dlg.Destroy()
6500
6624
 
6501
- fig, ax = self.active_vector.plot_mpl(True, False)
6625
+ # Création d'un graphique matplotlib sous wx
6626
+ figmpl = MplFig()
6627
+ figmpl.presets()
6628
+ figmpl.Hide()
6629
+ fig, ax = figmpl.get_figax()
6630
+
6631
+ # fig, ax = self.active_vector.plot_mpl(True, False)
6502
6632
 
6503
6633
  linkedarrays = self.get_linked_arrays()
6504
6634
 
@@ -6528,8 +6658,10 @@ class WolfMapViewer(wx.Frame):
6528
6658
  ax.plot([curs-.1, curs+.1], [curz+tolval, curz+tolval], c='black', linewidth=0.5)
6529
6659
  ax.plot([curs-.1, curs+.1], [curz-tolval, curz-tolval], c='black', linewidth=0.5)
6530
6660
 
6531
- fig.canvas.draw()
6532
- fig.canvas.flush_events()
6661
+ # fig.canvas.draw()
6662
+ # fig.canvas.flush_events()
6663
+
6664
+ figmpl.Show()
6533
6665
 
6534
6666
  elif itemlabel == _("Compute and apply unique colormap on all..."):
6535
6667
  self.uniquecolormap()
@@ -6550,6 +6682,7 @@ class WolfMapViewer(wx.Frame):
6550
6682
  self.filter_inundation()
6551
6683
 
6552
6684
  elif itemlabel == _("Plot active polygons..."):
6685
+
6553
6686
  if self.active_zone is None:
6554
6687
  logging.warning(_('No active zone ! -- please select a zone containing polygons !'))
6555
6688
  return
@@ -6579,7 +6712,14 @@ class WolfMapViewer(wx.Frame):
6579
6712
  logging.info(_('Sole polygon detected'))
6580
6713
  plotzone = [self.active_zone]
6581
6714
 
6582
- fig, ax = plt.subplots(1, 1)
6715
+ # Création d'un graphique matplotlib sous wx
6716
+ figmpl = MplFig()
6717
+ figmpl.presets()
6718
+ figmpl.Hide()
6719
+
6720
+ fig, ax = figmpl.get_figax()
6721
+
6722
+ # fig, ax = plt.subplots(1, 1)
6583
6723
 
6584
6724
  linkedarrays = {}
6585
6725
 
@@ -6620,9 +6760,12 @@ class WolfMapViewer(wx.Frame):
6620
6760
  # sole polygon
6621
6761
  plotzone[0].plot_linked_polygons(fig, ax, linkedarrays, linked_vec=linkedvecs)
6622
6762
 
6623
- ax.grid()
6624
- ax.legend()
6625
- fig.show()
6763
+ # ax.grid()
6764
+ # ax.legend()
6765
+ # fig.show()
6766
+
6767
+ figmpl.Show()
6768
+ figmpl.CenterOnScreen()
6626
6769
 
6627
6770
  elif itemlabel == _("Manage banks..."):
6628
6771
 
@@ -6801,18 +6944,20 @@ class WolfMapViewer(wx.Frame):
6801
6944
 
6802
6945
  self.save_project(filename, absolute= abspath)
6803
6946
 
6804
- elif itemlabel == _('Initialize from npz'):
6805
- self.init_laz_from_numpy()
6947
+ elif itemlabel == _('Initialize from laz, las or npz'):
6948
+ self.init_laz_from_lazlasnpz()
6806
6949
 
6807
- elif itemlabel == _('Initialize from GridInfos'):
6950
+ elif itemlabel == _('Initialize from directory'):
6808
6951
  self.init_laz_from_gridinfos()
6809
6952
 
6810
6953
  elif itemlabel == _('Create cloud points from bridges'):
6811
- if self.mylazdata is None:
6812
- self.init_laz_from_numpy()
6813
6954
 
6814
- mybridges = self.mylazdata[np.where(self.mylazdata[:, 3] == 10)]
6955
+ if self.active_laz is None:
6956
+ self.init_laz_from_lazlasnpz()
6957
+
6958
+ mybridges = self.active_laz.get_data_class(10)
6815
6959
  mycloud = cloud_vertices()
6960
+
6816
6961
  mycloud.init_from_nparray(mybridges)
6817
6962
  mycloud.myprop.style = 2
6818
6963
  mycloud.myprop.color = getIfromRGB([255, 102, 102])
@@ -6827,11 +6972,12 @@ class WolfMapViewer(wx.Frame):
6827
6972
 
6828
6973
  elif itemlabel == _('Create cloud points from buildings'):
6829
6974
 
6830
- if self.mylazdata is None:
6831
- self.init_laz_from_numpy()
6975
+ if self.active_laz is None:
6976
+ self.init_laz_from_lazlasnpz()
6832
6977
 
6833
- mybuildings = self.mylazdata[np.where(self.mylazdata[:, 3] == 1)]
6978
+ mybuildings = self.active_laz.get_data_class(1)
6834
6979
  mycloud = cloud_vertices()
6980
+
6835
6981
  mycloud.init_from_nparray(mybuildings)
6836
6982
  mycloud.myprop.style = 2
6837
6983
  mycloud.myprop.color = getIfromRGB([102, 102, 102])
@@ -6843,23 +6989,15 @@ class WolfMapViewer(wx.Frame):
6843
6989
  else:
6844
6990
  self.add_object('cloud', newobj=mycloud, ToCheck=True, id='Buildings')
6845
6991
 
6992
+ elif itemlabel == _('Create cloud points from specified classes'):
6993
+ pass
6994
+
6846
6995
  elif itemlabel == _('Create LAZ viewer'):
6847
6996
 
6848
6997
  laz_source = self._select_laz_source()
6849
6998
  if laz_source is None:
6850
6999
  return
6851
7000
 
6852
- choices, ass_values = choices_laz_colormap()
6853
- dlg = wx.SingleChoiceDialog(None, _("Pick a colormap"), "Choices", choices)
6854
- ret = dlg.ShowModal()
6855
- if ret == wx.ID_CANCEL:
6856
- dlg.Destroy()
6857
- return
6858
-
6859
- colormap = dlg.GetStringSelection()
6860
- idx = choices.index(colormap)
6861
- dlg.Destroy()
6862
-
6863
7001
  if laz_source is self.mylazgrid:
6864
7002
  if self.mylazgrid is None:
6865
7003
  logging.warning(_('No gridded LAZ data loaded !'))
@@ -6867,9 +7005,43 @@ class WolfMapViewer(wx.Frame):
6867
7005
  autoscale=False
6868
7006
  self.clip_laz_gridded()
6869
7007
 
6870
- self.myviewer = myviewer(self.mylazdata, ass_values[idx], palette_classif = self.mylazgrid.colors)
7008
+ self.active_laz.create_viewer(self._choice_laz_colormap(), self.mylazgrid.colors)
7009
+ self.myviewerslaz.append(self.active_laz.viewer)
7010
+ self.active_viewerlaz = self.myviewerslaz[-1]
7011
+
7012
+ # self.myviewer = myviewer(self.active_laz.data, ass_values[idx], palette_classif = self.mylazgrid.colors)
6871
7013
  else:
6872
- self.myviewer = myviewer(laz_source, ass_values[idx]) #, palette_classif = self.mylazdata_colors)
7014
+ self.active_laz.create_viewer(classification= self.mylazgrid.colors)
7015
+ self.myviewerslaz.append(self.active_laz.viewer)
7016
+ self.active_viewerlaz = self.myviewerslaz[-1]
7017
+
7018
+ # self.myviewer = myviewer(laz_source.data, ass_values[idx], palette_classif= laz_source.classification)
7019
+
7020
+ elif itemlabel == _('Filter data based on codes'):
7021
+
7022
+ self.filter_active_laz()
7023
+
7024
+ elif itemlabel == _('Descimate LAZ data'):
7025
+
7026
+ if self.active_laz is None:
7027
+ return
7028
+
7029
+ # Choose a decimation factor - integer
7030
+ dlg = wx.NumberEntryDialog(None, _('Your dataset contains {} points.\nWould you like to descimate?').format(self.active_laz.num_points),
7031
+ _('Decaimate factor'), _('Decimation'), 0, 0, 100)
7032
+
7033
+ ret = dlg.ShowModal()
7034
+
7035
+ if ret == wx.ID_CANCEL:
7036
+ dlg.Destroy()
7037
+ return
7038
+
7039
+ descimate_fact = dlg.GetValue()
7040
+ dlg.Destroy()
7041
+
7042
+ if descimate_fact > 0:
7043
+ self.active_laz.descimate(descimate_fact)
7044
+ logging.info(_('New count : {}').format(self.active_laz.num_points))
6873
7045
 
6874
7046
  elif itemlabel == _('Clip LAZ grid on current zoom'):
6875
7047
 
@@ -6879,14 +7051,15 @@ class WolfMapViewer(wx.Frame):
6879
7051
 
6880
7052
  self.clip_laz_gridded()
6881
7053
 
6882
- if self.mylazdata is None:
7054
+ if self.active_laz is None:
7055
+ logging.error(_('No data found'))
6883
7056
  return
6884
7057
 
6885
- if self.mylazdata.shape[0] > 100_000_000:
7058
+ if self.active_laz.data.shape[0] > 100_000_000:
6886
7059
 
6887
7060
  # Choose a decimation factor - integer
6888
- dlg = wx.NumberEntryDialog(None, _('Your data selection is very large (>100 M)\nWould you like to decimate?'),
6889
- _('Decaimate factor'), _('Decimation'), 0, 0, 100)
7061
+ dlg = wx.NumberEntryDialog(None, _('Your data selection is very large (>100 M)\nWould you like to descimate?\n\n{} points').format(self.active_laz.data.shape[0]),
7062
+ _('Descimate factor'), _('Decimation'), 0, 0, 100)
6890
7063
 
6891
7064
  ret = dlg.ShowModal()
6892
7065
 
@@ -6894,11 +7067,11 @@ class WolfMapViewer(wx.Frame):
6894
7067
  dlg.Destroy()
6895
7068
  return
6896
7069
 
6897
- decimate_fact = dlg.GetValue()
7070
+ descimate_fact = dlg.GetValue()
6898
7071
  dlg.Destroy()
6899
7072
 
6900
- if decimate_fact > 0:
6901
- self.decimate_laz_data(decimate_fact)
7073
+ if descimate_fact > 0:
7074
+ self.descimate_laz_data(descimate_fact)
6902
7075
 
6903
7076
  elif itemlabel == _('Fill active array from LAZ data'):
6904
7077
 
@@ -7991,7 +8164,7 @@ class WolfMapViewer(wx.Frame):
7991
8164
  'weirs',
7992
8165
  'vector',
7993
8166
  'tiles', 'tilescomp'
7994
- 'cloud',
8167
+ 'cloud', 'laz',
7995
8168
  'triangulation',
7996
8169
  'cross_sections',
7997
8170
  'other',
@@ -8011,12 +8184,13 @@ class WolfMapViewer(wx.Frame):
8011
8184
  Add object to current Frame/Drawing area
8012
8185
  """
8013
8186
 
8014
- filterArray = "All supported formats|*.bin;*.tif;*.tiff;*.top;*.flt;*.npy;*.npz|bin (*.bin)|*.bin|Elevation WOLF2D (*.top)|*.top|Geotif (*.tif)|*.tif|Float ESRI (*.flt)|*.flt|Numpy (*.npy)|*.npy|Numpy named arrays(*.npz)|*.npz|all (*.*)|*.*"
8187
+ filterArray = "All supported formats|*.bin;*.tif;*.tiff;*.top;*.flt;*.npy;*.npz;*.vrt|bin (*.bin)|*.bin|Elevation WOLF2D (*.top)|*.top|Geotif (*.tif)|*.tif|Float ESRI (*.flt)|*.flt|Numpy (*.npy)|*.npy|Numpy named arrays(*.npz)|*.npz|all (*.*)|*.*"
8015
8188
  filterjson = "json (*.json)|*.json|all (*.*)|*.*"
8016
8189
  filterall = "all (*.*)|*.*"
8017
8190
  filterres2d = "all (*.*)|*.*"
8018
8191
  filterVector = "All supported formats|*.vec;*.vecz;*.dxf;*.shp|vec (*.vec)|*.vec|vecz (*.vecz)|*.vecz|dxf (*.dxf)|*.dxf|shp (*.shp)|*.shp|all (*.*)|*.*"
8019
8192
  filterCloud = "xyz (*.xyz)|*.xyz|dxf (*.dxf)|*.dxf|text (*.txt)|*.txt|shp (*.shp)|*.shp|all (*.*)|*.*"
8193
+ filterlaz = "laz (*.laz)|*.laz|las (*.las)|*.las|Numpy (*.npz)|*.npz|all (*.*)|*.*"
8020
8194
  filtertri = "tri (*.tri)|*.tri|text (*.txt)|*.txt|dxf (*.dxf)|*.dxf|gltf (*.gltf)|*.gltf|gltf binary (*.glb)|*.glb|*.*'all (*.*)|*.*"
8021
8195
  filterCs = "vecz WOLF (*.vecz)|*.vecz|txt 2022 (*.txt)|*.txt|WOLF (*.sxy)|*.sxy|text 2000 (*.txt)|*.txt|all (*.*)|*.*"
8022
8196
  filterimage = "Geotif (*.tif)|*.tif|all (*.*)|*.*"
@@ -8043,6 +8217,8 @@ class WolfMapViewer(wx.Frame):
8043
8217
  file = wx.FileDialog(self, "Choose file", wildcard=filterVector)
8044
8218
  elif which.lower() == 'cloud':
8045
8219
  file = wx.FileDialog(self, "Choose file", wildcard=filterCloud)
8220
+ elif which.lower() == 'laz':
8221
+ file = wx.FileDialog(self, "Choose file", wildcard=filterlaz)
8046
8222
  elif which.lower() == 'triangulation':
8047
8223
  file = wx.FileDialog(self, "Choose file", wildcard=filtertri)
8048
8224
  elif which.lower() == 'cross_sections':
@@ -8543,6 +8719,19 @@ class WolfMapViewer(wx.Frame):
8543
8719
  self.myvectors.append(newobj)
8544
8720
  newobj.mapviewer = self
8545
8721
 
8722
+ elif which.lower() =='laz':
8723
+ curdict = self.mylazdata
8724
+ curtree = self.myitemslaz
8725
+
8726
+ if newobj is None:
8727
+ newobj = Wolf_LAZ_Data(mapviewer=self)
8728
+ newobj.from_file(filename)
8729
+
8730
+ self.mylazdata.append(newobj)
8731
+ self.active_laz = newobj
8732
+
8733
+ newobj.set_mapviewer(self)
8734
+
8546
8735
  elif which.lower() == 'cloud':
8547
8736
 
8548
8737
  curdict = self.myclouds
@@ -8784,6 +8973,8 @@ class WolfMapViewer(wx.Frame):
8784
8973
  return self.mywmsfore
8785
8974
  elif drawing_type == draw_type.IMAGESTILES:
8786
8975
  return self.myimagestiles
8976
+ elif drawing_type == draw_type.LAZ:
8977
+ return self.mylazdata
8787
8978
  else:
8788
8979
  logging.error('Unknown drawing type : ' + drawing_type)
8789
8980
  return None
@@ -9214,10 +9405,20 @@ class WolfMapViewer(wx.Frame):
9214
9405
 
9215
9406
  fdlg.Destroy()
9216
9407
 
9408
+ elif isinstance(self.selected_object, Wolf_LAZ_Data):
9409
+ filterArray = "Dump (*.dump)|*.dmp|all (*.*)|*.*"
9410
+ fdlg = wx.FileDialog(self, "Choose file name for LAZ data :" + self.selected_object.idx, wildcard=filterArray,
9411
+ style=wx.FD_SAVE)
9412
+ ret = fdlg.ShowModal()
9413
+ if ret == wx.ID_OK:
9414
+ self.selected_object.saveas(fdlg.GetPath())
9415
+
9416
+ fdlg.Destroy()
9417
+
9217
9418
  elif text == _('Properties'):
9218
9419
 
9219
9420
  myobj = self.selected_object
9220
- if type(myobj) in [WolfArray, WolfArrayMB, WolfArrayMNAP, Zones, Wolfresults_2D, wolfres2DGPU, Particle_system, Picc_data, Cadaster_data, hydrometry_wolfgui, Bridge, Weir]:
9421
+ if type(myobj) in [WolfArray, WolfArrayMB, WolfArrayMNAP, Zones, Wolfresults_2D, wolfres2DGPU, Particle_system, Picc_data, Cadaster_data, hydrometry_wolfgui, Bridge, Weir, Wolf_LAZ_Data]:
9221
9422
  myobj.show_properties()
9222
9423
 
9223
9424
  elif isinstance(myobj, cloud_vertices):
@@ -9365,6 +9566,158 @@ class WolfMapViewer(wx.Frame):
9365
9566
  self.selected_object.export_active_zone_to_shapefile(fdlg.GetPath())
9366
9567
  fdlg.Destroy()
9367
9568
 
9569
+ elif _('Set colormap') in text:
9570
+
9571
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9572
+ self.selected_object.associated_color = self._choice_laz_colormap()
9573
+
9574
+ elif _('Edit colormap') in text:
9575
+
9576
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9577
+ self.selected_object.interactive_update_colors()
9578
+
9579
+ elif _('Set classification') in text:
9580
+
9581
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9582
+ self.selected_object.set_classification(self._choice_laz_classification())
9583
+
9584
+ elif _('Edit selection') in text:
9585
+
9586
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9587
+ self.selected_object._edit_selection()
9588
+
9589
+ elif _('All to cloud') in text:
9590
+
9591
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9592
+
9593
+ if self.selected_object.num_points > 100000:
9594
+ dlg = wx.MessageDialog(None, _('The number of points is high, it could take some time to convert to cloud.\nDo you want to continue ?'), _('Warning'), wx.YES_NO | wx.NO_DEFAULT)
9595
+ ret = dlg.ShowModal()
9596
+
9597
+ if ret != wx.ID_YES:
9598
+ dlg.Destroy()
9599
+
9600
+ return
9601
+
9602
+ newcloud = cloud_vertices()
9603
+ newcloud.init_from_nparray(self.selected_object.xyz)
9604
+ self.add_object('cloud', newobj=newcloud, id=self.selected_object.idx + '_cloud')
9605
+
9606
+ elif _('Selection to cloud') in text:
9607
+
9608
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9609
+
9610
+ xyz = self.selected_object.xyz_selected
9611
+ if xyz.shape[0] ==0:
9612
+ logging.warning('No points selected')
9613
+ return
9614
+
9615
+ if xyz.shape[0] > 100000:
9616
+ dlg = wx.MessageDialog(None, _('The number of points is high, it could take some time to convert to cloud.\nDo you want to continue ?'), _('Warning'), wx.YES_NO | wx.NO_DEFAULT)
9617
+ ret = dlg.ShowModal()
9618
+
9619
+ if ret != wx.ID_YES:
9620
+ dlg.Destroy()
9621
+
9622
+ return
9623
+
9624
+ newcloud = cloud_vertices()
9625
+ newcloud.init_from_nparray(xyz)
9626
+ self.add_object('cloud', newobj=newcloud, id=self.selected_object.idx + '_cloud_sel')
9627
+
9628
+ elif _('Selection to vector') in text:
9629
+
9630
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9631
+
9632
+ if self.active_zone is None:
9633
+ logging.warning(_('No active zone selected'))
9634
+ return
9635
+
9636
+ xyz = self.selected_object.xyz_selected
9637
+ if xyz.shape[0] ==0:
9638
+ logging.warning('No points selected')
9639
+ return
9640
+
9641
+ if xyz.shape[0] > 100000:
9642
+ dlg = wx.MessageDialog(None, _('The number of points is high, it could take some time to convert to cloud.\nDo you want to continue ?'), _('Warning'), wx.YES_NO | wx.NO_DEFAULT)
9643
+ ret = dlg.ShowModal()
9644
+
9645
+ if ret != wx.ID_YES:
9646
+ dlg.Destroy()
9647
+
9648
+ return
9649
+
9650
+ def approximate_vector(xyz):
9651
+ """ Get a cloud of points and return a vector
9652
+ based on the best approximated segment
9653
+ and points projected on its trace
9654
+ """
9655
+
9656
+ # best approximation of the segment
9657
+ # based on the RANSAC algorithm from scikit-learn
9658
+ model = linear_model.RANSACRegressor()
9659
+ model.fit(xyz[:,0].reshape(-1,1), xyz[:,1])
9660
+
9661
+ # get the points projected on the segment
9662
+ proj = model.predict(xyz[:,0].reshape(-1,1))
9663
+
9664
+ # get the coordinates of the projected points
9665
+ xyz_proj = np.zeros((xyz.shape[0],3))
9666
+ xyz_proj[:,0] = xyz[:,0]
9667
+ xyz_proj[:,1] = proj
9668
+ xyz_proj[:,2] = xyz[:,2]
9669
+
9670
+ #Sort the points
9671
+ idx = np.argsort(xyz_proj[:,0])
9672
+ xyz_proj = xyz_proj[idx]
9673
+
9674
+ return xyz_proj
9675
+
9676
+ newvector = vector(name = self.selected_object.idx + '_vector_sel', fromnumpy= approximate_vector(xyz))
9677
+ self.active_zone.add_vector(newvector, forceparent=True)
9678
+ self.active_zone.parent.find_minmax(True)
9679
+ self.active_zone.parent.reset_listogl()
9680
+
9681
+ self.active_zone.parent.fill_structure()
9682
+ self.Refresh()
9683
+
9684
+ elif _('Play') in text:
9685
+
9686
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9687
+ self.selected_object.play_flight()
9688
+
9689
+ elif _('Add point') in text:
9690
+
9691
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9692
+ self.selected_object.add_pose_in_memory()
9693
+
9694
+ elif _('Record') in text:
9695
+
9696
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9697
+
9698
+ dlg = wx.DirDialog(self, _('Choose a directory to save the video'), style=wx.DD_DEFAULT_STYLE)
9699
+ if dlg.ShowModal() == wx.ID_OK:
9700
+ self.selected_object.record_flight(dlg.GetPath())
9701
+
9702
+ dlg.Destroy()
9703
+
9704
+ elif _('Load flight') in text:
9705
+
9706
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9707
+ dlg = wx.FileDialog(self, _('Choose a file to load the flight'), wildcard='JSON (*.json)|*.json|All (*.*)|*.*', style=wx.FD_OPEN)
9708
+ if dlg.ShowModal() == wx.ID_OK:
9709
+ self.selected_object.load_flight(dlg.GetPath())
9710
+
9711
+ dlg.Destroy()
9712
+
9713
+ elif _('Save flight') in text:
9714
+
9715
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
9716
+ dlg = wx.FileDialog(self, _('Choose a file to save the flight'), wildcard='JSON (*.json)|*.json|All (*.*)|*.*', style=wx.FD_SAVE)
9717
+ if dlg.ShowModal() == wx.ID_OK:
9718
+ self.selected_object.save_flight(dlg.GetPath())
9719
+
9720
+ dlg.Destroy()
9368
9721
 
9369
9722
  def OnClose(self, event):
9370
9723
  """ Close the application """
@@ -10078,14 +10431,27 @@ class WolfMapViewer(wx.Frame):
10078
10431
 
10079
10432
  self.mousex = self.mousedown[0]
10080
10433
  self.mousey = self.mousedown[1]
10081
- self.mousedown = (0., 0.)
10434
+ # self.mousedown = (0., 0.)
10082
10435
  self.oneclick = False
10083
10436
  self.setbounds()
10084
10437
 
10085
10438
  if ctrldown:
10086
- if self.active_viewer3d is not None:
10087
- self.active_viewer3d.force_view(self.mousex, self.mousey, self.active_array.get_value(self.mousex, self.mousey))
10088
- self.Refresh()
10439
+ if self.active_array is not None:
10440
+ if self.active_viewer3d is not None:
10441
+ self.active_viewer3d.force_view(self.mousex, self.mousey, self.active_array.get_value(self.mousex, self.mousey))
10442
+ self.Refresh()
10443
+
10444
+ if self.active_laz is not None:
10445
+ if self.active_laz.viewer is not None:
10446
+ self.active_laz.force_view(self.mousex, self.mousey, self.active_array.get_value(self.mousex, self.mousey))
10447
+ else:
10448
+ if self.active_viewer3d is not None:
10449
+ self.active_viewer3d.force_view(self.mousex, self.mousey)
10450
+ self.Refresh()
10451
+
10452
+ if self.active_laz is not None:
10453
+ if self.active_laz.viewer is not None:
10454
+ self.active_laz.force_view(self.mousex, self.mousey)
10089
10455
 
10090
10456
  def OnLDown(self, e):
10091
10457
 
@@ -10151,6 +10517,13 @@ class WolfMapViewer(wx.Frame):
10151
10517
  if ctrl:
10152
10518
  myobj.show_properties()
10153
10519
 
10520
+ elif type(myobj) == Wolf_LAZ_Data:
10521
+
10522
+ self.active_laz = myobj
10523
+
10524
+ if ctrl:
10525
+ myobj.show_properties()
10526
+
10154
10527
  elif type(myobj) == Bridge:
10155
10528
  self.active_bridge = myobj
10156
10529
 
@@ -11825,6 +12198,10 @@ class WolfMapViewer(wx.Frame):
11825
12198
  self.mousex = self.mousex + self.width / 10.
11826
12199
  self.setbounds()
11827
12200
 
12201
+ elif key == ord('A'):
12202
+ if self.active_laz is not None:
12203
+ self.active_laz.add_pose_in_memory()
12204
+
11828
12205
  def paste_values(self,fromarray:WolfArray):
11829
12206
  """ Paste selected values from a WolfArray to the active array """
11830
12207
 
@@ -11875,6 +12252,20 @@ class WolfMapViewer(wx.Frame):
11875
12252
  tracks.append(_('Export active zone to Shape file'))
11876
12253
  tracks.append(_('Rebin'))
11877
12254
  tracks.append(_('Set NullValue'))
12255
+ tracks.append(_('Set colormap'))
12256
+ tracks.append(_('Edit colormap'))
12257
+ tracks.append(_('Set classification'))
12258
+ tracks.append(_('Convert to...'))
12259
+ tracks.append(_('Edit selection'))
12260
+ tracks.append(_('All to cloud'))
12261
+ tracks.append(_('Selection to cloud'))
12262
+
12263
+ tracks.append(_('Colormap'))
12264
+ tracks.append(_('Movie'))
12265
+ tracks.append(_('Play'))
12266
+ tracks.append(_('Record'))
12267
+ tracks.append(_('Load flight'))
12268
+ tracks.append(_('Save flight'))
11878
12269
 
11879
12270
  # Récupération des items du menu contextuel
11880
12271
  menuitems = self.popupmenu.GetMenuItems()
@@ -11917,6 +12308,33 @@ class WolfMapViewer(wx.Frame):
11917
12308
  self.popupmenu.Append(wx.ID_ANY, _('Export to Shape file'), _('Export to Shape file'))
11918
12309
  self.popupmenu.Append(wx.ID_ANY, _('Export active zone to Shape file'), _('Export active zone to Shape file'))
11919
12310
 
12311
+ if isinstance(self.selected_object, Wolf_LAZ_Data):
12312
+
12313
+ colrmapmenu = wx.Menu()
12314
+ self.popupmenu.AppendSubMenu(colrmapmenu, _('Colormap'))
12315
+
12316
+ colrmapmenu.Append(wx.ID_ANY, _('Set colormap'), _('Change colormap'))
12317
+ colrmapmenu.Append(wx.ID_ANY, _('Edit colormap'), _('Edit colormap'))
12318
+ colrmapmenu.Append(wx.ID_ANY, _('Set classification'), _('Change classification'))
12319
+
12320
+ converttomenu = wx.Menu()
12321
+ self.popupmenu.AppendSubMenu(converttomenu, _('Convert to...'))
12322
+
12323
+ converttomenu.Append(wx.ID_ANY, _('All to cloud'), _('Convert all to cloud'))
12324
+ converttomenu.Append(wx.ID_ANY, _('Selection to cloud'), _('Convert selection to cloud'))
12325
+ converttomenu.Append(wx.ID_ANY, _('Selection to vector'), _('Convert selection to vector'))
12326
+
12327
+ self.popupmenu.Append(wx.ID_ANY, _('Edit selection'), _('Edit selection'))
12328
+
12329
+ moviemenu = wx.Menu()
12330
+ self.popupmenu.AppendSubMenu(moviemenu, _('Movie'))
12331
+
12332
+ moviemenu.Append(wx.ID_ANY, _('Add point'), _('Add point passage'))
12333
+ moviemenu.Append(wx.ID_ANY, _('Play'), _('Play'))
12334
+ # moviemenu.Append(wx.ID_ANY, _('Record'), _('Record'))
12335
+ moviemenu.Append(wx.ID_ANY, _('Load flight'), _('Load flight'))
12336
+ moviemenu.Append(wx.ID_ANY, _('Save flight'), _('Save flight'))
12337
+
11920
12338
  self.treelist.PopupMenu(self.popupmenu)
11921
12339
 
11922
12340
  def update(self):