wolfhece 2.0.18__py3-none-any.whl → 2.0.19__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
@@ -1002,10 +1002,20 @@ class WolfMapViewer(wx.Frame):
1002
1002
  self.active_array.interpolate_on_triangulation(self.active_tri.pts, self.active_tri.tri, )
1003
1003
 
1004
1004
  def compare_cloud2array(self):
1005
+ """
1006
+ Compare the active cloud points to the active array
1007
+
1008
+ """
1009
+
1010
+ if self.active_array is None :
1011
+ logging.warning(_('No active array -- Please activate an array first'))
1012
+ return
1005
1013
 
1006
- if self.active_array is not None and self.active_cloud is not None:
1014
+ if self.active_cloud is None:
1015
+ logging.warning(_('No active cloud -- Please activate a cloud first'))
1016
+ return
1007
1017
 
1008
- self.active_array.compare_cloud(self.active_cloud)
1018
+ self.active_array.compare_cloud(self.active_cloud)
1009
1019
 
1010
1020
  def compare_tri2array(self):
1011
1021
 
@@ -1748,7 +1758,8 @@ class WolfMapViewer(wx.Frame):
1748
1758
  '2012-2013': 'ORTHO_2012_2013',
1749
1759
  '2015': 'ORTHO_2015', '2016': 'ORTHO_2016', '2017': 'ORTHO_2017',
1750
1760
  '2018': 'ORTHO_2018', '2019': 'ORTHO_2019', '2020': 'ORTHO_2020',
1751
- '2021': 'ORTHO_2021'}}
1761
+ '2021': 'ORTHO_2021', '2022 printemps': 'ORTHO_2022_PRINTEMPS', '2022 été': 'ORTHO_2022_ETE',
1762
+ '2023 été': 'ORTHO_2023_ETE'}}
1752
1763
  for idx, (k, item) in enumerate(orthos.items()):
1753
1764
  for kdx, (m, subitem) in enumerate(item.items()):
1754
1765
  self.add_object(which='wmsback',
@@ -2429,6 +2440,13 @@ class WolfMapViewer(wx.Frame):
2429
2440
  else:
2430
2441
  logging.info(_('Bad parameter in project file - array : ')+ curname[key_Param.VALUE])
2431
2442
 
2443
+ if 'cloud' in myproject.myparams.keys():
2444
+ for curid, curname in zip(myproject.myparams['cloud'].keys(), myproject.myparams['cloud'].values()):
2445
+ if exists(curname[key_Param.VALUE]):
2446
+ mycloud = cloud_vertices(curname[key_Param.VALUE])
2447
+ self.add_object('cloud', newobj=mycloud, id=curid)
2448
+ else:
2449
+ logging.info(_('Bad parameter in project file - cloud : ')+ curname[key_Param.VALUE])
2432
2450
 
2433
2451
  if 'wolf2d' in myproject.myparams.keys():
2434
2452
  for curid, curname in zip(myproject.myparams['wolf2d'].keys(), myproject.myparams['wolf2d'].values()):
@@ -3005,15 +3023,66 @@ class WolfMapViewer(wx.Frame):
3005
3023
 
3006
3024
  elif itemlabel == _("Plot active vector..."):
3007
3025
 
3026
+
3008
3027
  if self.active_vector is None:
3028
+ logging.warning(_('No active vector !'))
3009
3029
  return
3010
3030
 
3031
+ add_cloud = False
3032
+ if self.active_cloud is not None:
3033
+ dlg = wx.MessageDialog(self, _('Do you want to plot the cloud ?'), style=wx.YES_NO)
3034
+
3035
+ if dlg.ShowModal() == wx.ID_YES:
3036
+ add_cloud = True
3037
+
3038
+ prox = wx.TextEntryDialog(None,_('Proximity [m] ?'), value = '5.0')
3039
+ ret = prox.ShowModal()
3040
+ if ret == wx.ID_CANCEL:
3041
+ prox.Destroy()
3042
+ return
3043
+ try:
3044
+ proxval = float(prox.GetValue())
3045
+ except:
3046
+ prox.Destroy()
3047
+ logging.warning(_('Bad value -- Rety'))
3048
+ return
3049
+
3050
+ tol = wx.TextEntryDialog(None,_('Tolerance [m] ?'), value = '0.5')
3051
+ ret = tol.ShowModal()
3052
+ if ret == wx.ID_CANCEL:
3053
+ tol.Destroy()
3054
+ return
3055
+ try:
3056
+ tolval = float(tol.GetValue())
3057
+ except:
3058
+ tol.Destroy()
3059
+ logging.warning(_('Bad value -- Rety'))
3060
+ return
3061
+
3062
+ else:
3063
+ add_cloud = False
3064
+
3065
+ dlg.Destroy()
3066
+
3011
3067
  fig, ax = self.active_vector.plot_mpl(True, False)
3012
3068
 
3013
3069
  linkedarrays = self.get_linked_arrays()
3014
3070
 
3015
3071
  self.active_vector.plot_linked(fig, ax, linkedarrays)
3016
3072
 
3073
+ if add_cloud:
3074
+ s, z = self.active_cloud.projectontrace(self.active_vector, return_cloud=False, proximity= proxval)
3075
+
3076
+ ax.scatter( s, z, c='black', s=1.0)
3077
+
3078
+ for curs, curz in zip(s,z):
3079
+ ax.plot([curs, curs], [curz-tolval, curz+tolval], 'k--', linewidth=0.5)
3080
+ ax.plot([curs-.1, curs+.1], [curz+tolval, curz+tolval], c='black', linewidth=0.5)
3081
+ ax.plot([curs-.1, curs+.1], [curz-tolval, curz-tolval], c='black', linewidth=0.5)
3082
+
3083
+ fig.canvas.draw()
3084
+ fig.canvas.flush_events()
3085
+
3017
3086
  elif itemlabel == _("Export arrays as Geotif..."):
3018
3087
 
3019
3088
  self.export_results_as('geotiff')
@@ -4268,9 +4337,10 @@ class WolfMapViewer(wx.Frame):
4268
4337
  filterall = "all (*.*)|*.*"
4269
4338
  filterres2d = "all (*.*)|*.*"
4270
4339
  filterVector = "vec (*.vec)|*.vec|vecz (*.vecz)|*.vecz|dxf (*.dxf)|*.dxf|shp (*.shp)|*.shp|all (*.*)|*.*"
4271
- filterCloud = "xyz (*.xyz)|*.xyz|dxf (*.dxf)|*.dxf|text (*.txt)|*.txt|all (*.*)|*.*"
4340
+ filterCloud = "xyz (*.xyz)|*.xyz|dxf (*.dxf)|*.dxf|text (*.txt)|*.txt|shp (*.shp)|*.shp|all (*.*)|*.*"
4272
4341
  filtertri = "tri (*.tri)|*.tri|text (*.txt)|*.txt|dxf (*.dxf)|*.dxf|gltf (*.gltf)|*.gltf|gltf binary (*.glb)|*.glb|*.*'all (*.*)|*.*"
4273
4342
  filterCs = "vecz WOLF (*.vecz)|*.vecz|txt 2022 (*.txt)|*.txt|WOLF (*.sxy)|*.sxy|text 2000 (*.txt)|*.txt|all (*.*)|*.*"
4343
+ filterimage = "Geotif (*.tif)|*.tif|all (*.*)|*.*"
4274
4344
 
4275
4345
  if filename == '' and newobj is None:
4276
4346
  # ouverture d'une boîte de dialogue
@@ -4303,9 +4373,9 @@ class WolfMapViewer(wx.Frame):
4303
4373
 
4304
4374
  # FIXME : particularize filters for wmsback and wmsfore
4305
4375
  elif which.lower() == 'wmsback':
4306
- file = wx.FileDialog(self, "Choose file", wildcard=filterCloud)
4376
+ file = wx.FileDialog(self, "Choose file", wildcard=filterimage)
4307
4377
  elif which.lower() == 'wmsfore':
4308
- file = wx.FileDialog(self, "Choose file", wildcard=filterCloud)
4378
+ file = wx.FileDialog(self, "Choose file", wildcard=filterimage)
4309
4379
 
4310
4380
  if file.ShowModal() == wx.ID_CANCEL:
4311
4381
  file.Destroy()
@@ -4718,12 +4788,13 @@ class WolfMapViewer(wx.Frame):
4718
4788
  newobj.mapviewer = self
4719
4789
 
4720
4790
  elif which.lower() == 'cloud':
4791
+
4721
4792
  curdict = self.myclouds
4722
4793
  curtree = self.myitemscloud
4723
4794
  if newobj is None:
4724
4795
 
4725
4796
  loadhead = False
4726
- if not filename.endswith('.dxf'):
4797
+ if not filename.endswith('.dxf') and not filename.endswith('.shp'):
4727
4798
  with open(filename,'r') as f:
4728
4799
  text=f.read().splitlines()
4729
4800
  tmphead=''
@@ -4738,7 +4809,7 @@ class WolfMapViewer(wx.Frame):
4738
4809
 
4739
4810
  with wx.lib.busy.BusyInfo(_('Importing cloud points')):
4740
4811
  wait = wx.BusyCursor()
4741
- newobj = cloud_vertices(filename,header=loadhead)
4812
+ newobj = cloud_vertices(filename, header=loadhead)
4742
4813
  del wait
4743
4814
 
4744
4815
  self.myclouds.append(newobj)
@@ -6681,6 +6752,7 @@ class WolfMapViewer(wx.Frame):
6681
6752
  self.active_tile = None
6682
6753
  self.active_particle_system = None
6683
6754
  self.active_vertex = None
6755
+ self.active_cloud = None
6684
6756
 
6685
6757
  elif key == ord('C'):
6686
6758
 
wolfhece/PyParams.py CHANGED
@@ -271,7 +271,8 @@ class Wolf_Param(wx.Frame):
271
271
  withbuttons: bool = True,
272
272
  DestroyAtClosing:bool = True,
273
273
  toShow:bool = True,
274
- init_GUI:bool = True):
274
+ init_GUI:bool = True,
275
+ force_even_if_same_default:bool = False):
275
276
  """
276
277
  Initialisation
277
278
 
@@ -285,7 +286,7 @@ class Wolf_Param(wx.Frame):
285
286
  :param withbuttons : if True, buttons will be displayed
286
287
  :param DestroyAtClosing : if True, the frame will be destroyed when closed
287
288
  :param toShow : if True, the frame will be displayed
288
-
289
+ :param force_even_if_same_default : if True, the parameter will be displayed even if the default and active parameters are the same
289
290
 
290
291
  Callbacks (see 'set_callbacks'):
291
292
  - callback : callback function when 'apply' is pressed
@@ -305,7 +306,7 @@ class Wolf_Param(wx.Frame):
305
306
  self._callbackdestroy:function = None
306
307
 
307
308
  self.wx_exists = wx.App.Get() is not None # test if wx App is running
308
- self.show_in_active_if_default = False
309
+ self.show_in_active_if_default = force_even_if_same_default
309
310
 
310
311
  if to_read:
311
312
  self.ReadFile(filename)
@@ -457,6 +458,8 @@ class Wolf_Param(wx.Frame):
457
458
  self.SetAutoLayout(1)
458
459
  self.sizer.Fit(self)
459
460
 
461
+ self.SetSize(0,0,w,h)
462
+
460
463
  #affichage de la page
461
464
  self.Show(toShow)
462
465
 
@@ -518,9 +521,13 @@ class Wolf_Param(wx.Frame):
518
521
  page_active.Append(pg.PropertyCategory(groupname))
519
522
 
520
523
  #teste si param existe
521
- if not self.is_in_active(groupname, paramname):
524
+ activeprop = self.prop.GetPropertyByName(groupname + paramname)
525
+ if activeprop is None:
522
526
  #si non existant --> on ajoute, si existant --> rien à faire
523
- self._add_elem_to_page(page_active, groupname, param_def)
527
+ self._insert_elem_to_page(page_active, groupname, param_def)
528
+ # if not self.is_in_active(groupname, paramname):
529
+ # #si non existant --> on ajoute, si existant --> rien à faire
530
+ # self._add_elem_to_page(page_active, groupname, param_def)
524
531
 
525
532
  else:
526
533
  #recopiage de la valeur par défaut
@@ -571,6 +578,16 @@ class Wolf_Param(wx.Frame):
571
578
  # populate the property grid
572
579
  self.Populate()
573
580
 
581
+ def _get_prop_names(self, page:pg.PropertyGridPage) -> list[str]:
582
+ """ Return the names of the properties in a page """
583
+
584
+ return [prop.GetName() for prop in page.GetPyIterator(pg.PG_ITERATE_ALL)]
585
+
586
+ def _is_in_propperty_page(self, page:pg.PropertyGridPage, group:str, param:str="") -> bool:
587
+ """ Test if a parameter is in a page """
588
+
589
+ return (group + param) in self._get_prop_names(page)
590
+
574
591
  def ApplytoMemory(self, event:wx.MouseEvent):
575
592
  """ Transfert des données en mémoire --> remplissage des dictionnaires """
576
593
 
@@ -585,7 +602,19 @@ class Wolf_Param(wx.Frame):
585
602
  if not self._callback is None:
586
603
  self._callback()
587
604
  else:
588
- wx.MessageDialog(self,'Nothing to do!')
605
+ if self.wx_exists:
606
+ dlg = wx.MessageDialog(self,'Nothing to do!')
607
+ dlg.ShowModal()
608
+
609
+ @property
610
+ def page_active(self) -> pg.PropertyGridPage:
611
+ """ Return the active page """
612
+ return self.prop.GetPage(0)
613
+
614
+ @property
615
+ def page_default(self) -> pg.PropertyGridPage:
616
+ """ Return the default page """
617
+ return self.prop.GetPage(1)
589
618
 
590
619
  def _Apply1ParamtoMemory(self,
591
620
  group:str,
@@ -625,7 +654,8 @@ class Wolf_Param(wx.Frame):
625
654
  val_default = self.prop.GetPropertyByName(PREFIX_DEFAULT + group + param_name).m_value
626
655
 
627
656
  # on tente de rcupérer la valeur active mais il ets possible qu'elle n'existe pas si sa valeur est identique à la valeur par défaut
628
- if self.is_in_active(group, param_name):
657
+ if self._is_in_propperty_page(self.page_active, group, param_name):
658
+ # if self.is_in_active(group, param_name):
629
659
  val_active = self.prop.GetPropertyByName(group + param_name).m_value
630
660
  else:
631
661
  val_active = val_default
@@ -641,7 +671,8 @@ class Wolf_Param(wx.Frame):
641
671
  else:
642
672
  # La valeur par défaut n'existe pas --> on prend la valeur active car c'est certainement une valeur incrémentable ou d'un groupe incrémentable
643
673
  # Si la valeur n'est pas présente, on ne fait rien
644
- if self.is_in_active(group, param_name):
674
+ if self._is_in_propperty_page(self.page_active, group, param_name):
675
+ # if self.is_in_active(group, param_name):
645
676
  val_active = self.prop.GetPropertyByName(group + param_name).m_value
646
677
  val_active = self.value_as_type(val_active, dict_param_def[key_Param.TYPE])
647
678
 
@@ -675,7 +706,9 @@ class Wolf_Param(wx.Frame):
675
706
 
676
707
  #gestion des paramètres actifs
677
708
  for group, params in self.myparams.items():
709
+
678
710
  page_active.Append(pg.PropertyCategory(group))
711
+
679
712
  for param_name, param in params.items():
680
713
  param:dict
681
714
  if self.is_in_default(group, param_name):
@@ -701,6 +734,63 @@ class Wolf_Param(wx.Frame):
701
734
  self.prop.ShowHeader()
702
735
  self.prop.Refresh()
703
736
 
737
+ def _insert_elem_to_page(self, page:pg.PropertyGridPage, group:str, param:dict, param_def:dict = None, prefix:str=''):
738
+ """ Insert an element to a page """
739
+
740
+ param_name = param[key_Param.NAME]
741
+ locname = prefix + group + param_name
742
+
743
+ # Get parent item based on group name
744
+ parent = page.GetPropertyByName(group)
745
+ assert parent is not None, "Group {} not found in page".format(group)
746
+ assert isinstance(parent, pg.PropertyCategory), "Parent is not a PropertyCategory"
747
+
748
+ if param_def is not None:
749
+ # priority to default parameters
750
+ if key_Param.ADDED_JSON in param_def.keys():
751
+ param[key_Param.ADDED_JSON] = param_def[key_Param.ADDED_JSON]
752
+ param[key_Param.COMMENT] = param_def[key_Param.COMMENT]
753
+ param[key_Param.TYPE] = param_def[key_Param.TYPE]
754
+
755
+ if key_Param.ADDED_JSON in param.keys() and param[key_Param.ADDED_JSON] is not None:
756
+ # Ajout des choix via chaîne JSON
757
+ list_keys = [ k for k in param[key_Param.ADDED_JSON]['Values'].keys()]
758
+ list_values = [ k for k in param[key_Param.ADDED_JSON]['Values'].values()]
759
+
760
+ page.AppendIn(parent, pg.EnumProperty(param_name, name=locname, labels=list_keys, values=list_values, value=int(param[key_Param.VALUE])))
761
+
762
+ self.prop.SetPropertyHelpString(locname , param[key_Param.ADDED_JSON]['Full_Comment'])
763
+ else:
764
+
765
+ locvalue = self[(group, param_name)]
766
+
767
+ if isinstance(locvalue, float):
768
+ page.AppendIn(parent, pg.FloatProperty(label = param_name, name = locname, value = locvalue))
769
+
770
+ elif isinstance(locvalue, int):
771
+ # bool is also an int
772
+ if isinstance(locvalue, bool):
773
+ page.AppendIn(parent, pg.BoolProperty(label=param_name, name = locname, value = locvalue))
774
+ else:
775
+ page.AppendIn(parent, pg.IntProperty(label = param_name, name = locname, value = locvalue))
776
+
777
+ elif param[key_Param.TYPE]==Type_Param.File:
778
+ page.AppendIn(parent, pg.FileProperty(label=param_name, name = locname, value = param[key_Param.VALUE]))
779
+
780
+ elif param[key_Param.TYPE]==Type_Param.Directory:
781
+ page.AppendIn(parent, pg.DirProperty(label = param_name, name = locname, value = locvalue))
782
+
783
+ elif param[key_Param.TYPE]==Type_Param.Color:
784
+ page.AppendIn(parent, pg.ColourProperty(label = param_name, name = locname, value = locvalue))
785
+
786
+ elif param[key_Param.TYPE]==Type_Param.Fontname:
787
+ page.AppendIn(parent, pg.FontProperty(label = param_name, name = locname, value = locvalue))
788
+
789
+ else:
790
+ page.AppendIn(parent, pg.StringProperty(label = param_name, name = locname, value = locvalue))
791
+
792
+ self.prop.SetPropertyHelpString(locname, param[key_Param.COMMENT])
793
+
704
794
  def _add_elem_to_page(self, page:pg.PropertyGridPage, group:str, param:dict, param_def:dict = None, prefix:str=''):
705
795
  """ Add an element to a page """
706
796
 
wolfhece/PyVertex.py CHANGED
@@ -9,12 +9,13 @@ except:
9
9
  raise Exception(msg)
10
10
 
11
11
  import math
12
- from shapely.geometry import Point, LineString
12
+ from shapely.geometry import Point, LineString, MultiPoint
13
13
  from os.path import exists
14
14
  import wx
15
15
  import re
16
16
  import logging
17
17
  from scipy.spatial import KDTree
18
+ from pathlib import Path
18
19
 
19
20
  from .PyParams import Wolf_Param, key_Param, Type_Param
20
21
  from .PyTranslate import _
@@ -121,6 +122,10 @@ class wolfvertex:
121
122
  self.y = min(self.y, bounds[1][1])
122
123
 
123
124
  class cloudproperties:
125
+ """
126
+ Properties of a cloud of vertices
127
+
128
+ """
124
129
  used: bool
125
130
 
126
131
  color: int
@@ -148,7 +153,7 @@ class cloudproperties:
148
153
 
149
154
  myprops: Wolf_Param = None
150
155
 
151
- def __init__(self, lines=[], parent=None) -> None:
156
+ def __init__(self, lines=[], parent:"cloud_vertices"=None) -> None:
152
157
 
153
158
  self.parent = parent
154
159
 
@@ -251,8 +256,10 @@ class cloudproperties:
251
256
  if 'Draw' in curdict.keys():
252
257
  keysactive = curdict['Draw'].keys()
253
258
  if 'Color' in keysactive:
254
- self.color = getIfromRGB(
255
- curdict['Draw']['Color'][key_Param.VALUE].replace('(', '').replace(')', '').split(', '))
259
+ if isinstance(curdict['Draw']['Color'][key_Param.VALUE], str):
260
+ self.color = getIfromRGB(curdict['Draw']['Color'][key_Param.VALUE].replace('(', '').replace(')', '').split(', '))
261
+ elif isinstance(curdict['Draw']['Color'][key_Param.VALUE], tuple):
262
+ self.color = getIfromRGB(curdict['Draw']['Color'][key_Param.VALUE])
256
263
  if 'Width' in keysactive:
257
264
  self.width = int(curdict['Draw']['Width'][key_Param.VALUE])
258
265
  if 'Style' in keysactive:
@@ -277,8 +284,10 @@ class cloudproperties:
277
284
  if 'Font size' in keysactive:
278
285
  self.legendfontsize = int(curdict['Legend']['Font size'][key_Param.VALUE])
279
286
  if 'Color' in keysactive:
280
- self.legendcolor = getIfromRGB(
281
- curdict['Legend']['Color'][key_Param.VALUE].replace('(', '').replace(')', '').split(', '))
287
+ if isinstance(curdict['Legend']['Color'][key_Param.VALUE], str):
288
+ self.legendcolor = getIfromRGB(curdict['Draw']['Color'][key_Param.VALUE].replace('(', '').replace(')', '').split(', '))
289
+ elif isinstance(curdict['Legend']['Color'][key_Param.VALUE], tuple):
290
+ self.v = getIfromRGB(curdict['Draw']['Color'][key_Param.VALUE])
282
291
  if 'Italic' in keysactive:
283
292
  self.legenditalic = bool(curdict['Legend']['Italic'][key_Param.VALUE])
284
293
  if 'relative Position' in keysactive:
@@ -294,9 +303,17 @@ class cloudproperties:
294
303
 
295
304
  self.parent.forceupdategl = True
296
305
 
306
+ if self.parent.mapviewer is not None:
307
+ self.parent.mapviewer.Refresh()
308
+
297
309
  def defaultprop(self):
310
+ """
311
+ Default properties
312
+
313
+ """
298
314
  if self.myprops is None:
299
- self.myprops = Wolf_Param(title='Cloud Properties', to_read=False)
315
+ self.myprops = Wolf_Param(title='Cloud Properties', to_read=False, force_even_if_same_default=True)
316
+ self.myprops.hide_selected_buttons()
300
317
  self.myprops._callbackdestroy = self.destroyprop
301
318
  self.myprops._callback = self.fill_property
302
319
  self.myprops.saveme.Disable()
@@ -383,7 +400,7 @@ class cloud_vertices(Element_To_Draw):
383
400
 
384
401
  """
385
402
  filename: str
386
- myvertices: dict
403
+ myvertices: dict[int, dict['vertex':wolfvertex, str:float]]
387
404
 
388
405
  xbounds: tuple
389
406
  ybounds: tuple
@@ -392,7 +409,28 @@ class cloud_vertices(Element_To_Draw):
392
409
  myprop: cloudproperties
393
410
  mytree : KDTree
394
411
 
395
- def __init__(self, fname: str = '', fromxls: str = '', header: bool = False, toload=True, idx: str = '', plotted: bool = True, mapviewer=None, need_for_wx: bool = False) -> None:
412
+ def __init__(self,
413
+ fname: str = '',
414
+ fromxls: str = '',
415
+ header: bool = False,
416
+ toload=True,
417
+ idx: str = '',
418
+ plotted: bool = True,
419
+ mapviewer=None,
420
+ need_for_wx: bool = False) -> None:
421
+ """
422
+ Init cloud of vertices
423
+
424
+ :param fname: file name
425
+ :param fromxls: string read from xls file and to be parsed
426
+ :param header: header in file (first line with column names)
427
+ :param toload: load file at init
428
+ :param idx: identifier -- see Element_To_Draw
429
+ :param plotted: plot at init -- see Element_To_Draw
430
+ :param mapviewer: mapviewer -- see Element_To_Draw
431
+ :param need_for_wx: see Element_To_Draw
432
+ """
433
+
396
434
  super().__init__(idx, plotted, mapviewer, need_for_wx)
397
435
 
398
436
  self.myvertices = {}
@@ -416,8 +454,11 @@ class cloud_vertices(Element_To_Draw):
416
454
 
417
455
  if fname != '':
418
456
  if toload:
419
- if fname[-4:].lower()=='.dxf':
457
+ if Path(fname).suffix.lower() == '.dxf':
458
+ # if fname[-4:].lower()=='.dxf':
420
459
  self.import_from_dxf(fname)
460
+ elif Path(fname).suffix.lower() == '.shp':
461
+ self.import_shapefile(fname)
421
462
  else:
422
463
  self.readfile(fname, header)
423
464
 
@@ -592,7 +633,14 @@ class cloud_vertices(Element_To_Draw):
592
633
  self.loaded = True
593
634
 
594
635
  def import_from_dxf(self,fn=''):
636
+ """
637
+ Importing DXF file using ezdxf library
638
+
639
+ :param fn: file name
640
+
641
+ """
595
642
  if fn == '' or not exists(fn):
643
+ logging.error(_('File not found : ')+fn)
596
644
  return
597
645
 
598
646
  import ezdxf
@@ -622,6 +670,57 @@ class cloud_vertices(Element_To_Draw):
622
670
 
623
671
  return k
624
672
 
673
+ def import_shapefile(self, fn='', targetcolumn:str = 'X1_Y1_Z1'):
674
+ """
675
+ Importing Shapefile using geopandas library
676
+
677
+ :param fn: file name
678
+ :param targetcolumn: column name to be used for XYZ coordinates -- 'X1_Y1_Z1' is used by SPW-ARNE-DCENN
679
+
680
+ """
681
+
682
+ if fn == '' or not exists(fn):
683
+ logging.error(_('File not found : ')+fn)
684
+ return
685
+
686
+ import geopandas as gpd
687
+
688
+ # read data
689
+ gdf = gpd.read_file(fn)
690
+
691
+ # Bouclage sur les éléments du Shapefile
692
+ if not targetcolumn in gdf.columns:
693
+
694
+ if self.wx_exists:
695
+
696
+ dlg = wx.SingleChoiceDialog(None, _('Choose the column to be used for XYZ coordinates'), _('Column choice'), gdf.columns)
697
+ if dlg.ShowModal() == wx.ID_OK:
698
+ targetcolumn = dlg.GetStringSelection()
699
+ dlg.Destroy()
700
+ else:
701
+ dlg.Destroy()
702
+ return
703
+
704
+ k=0
705
+ for index, row in gdf.iterrows():
706
+ x, y, z = row[targetcolumn].split(',')
707
+ x = float(x)
708
+ y = float(y)
709
+ z = float(z)
710
+
711
+ curvert = wolfvertex(x, y, z)
712
+ curdict = self.myvertices[k] = {}
713
+ curdict['vertex'] = curvert
714
+ k += 1
715
+
716
+ self.find_minmax(True)
717
+ self.loaded = True
718
+
719
+ logging.info(_('Number of imported points : ')+str(k))
720
+
721
+ return k
722
+
723
+
625
724
  def add_vertex(self, vertextoadd: wolfvertex = None, id=None, cloud: dict = None):
626
725
  if vertextoadd is not None:
627
726
  curid = id
@@ -639,6 +738,7 @@ class cloud_vertices(Element_To_Draw):
639
738
  pass
640
739
 
641
740
  def plot(self, update=False, *args, **kwargs):
741
+ """ OpenGL plot of the cloud of vertices """
642
742
 
643
743
  if update or self.gllist == 0 or self.forceupdategl and not self.ongoing:
644
744
  curvert: wolfvertex
@@ -790,21 +890,48 @@ class cloud_vertices(Element_To_Draw):
790
890
  xyz = self.get_xyz(key)
791
891
  myarray.interpolate_on_cloud(xyz[:,:2],xyz[:,2],method)
792
892
 
793
- def projectontrace(self, trace):
893
+ def iter_on_vertices(self):
894
+ """ Iteration on vertices """
895
+ for cur in self.myvertices.values():
896
+ yield cur['vertex']
897
+
898
+ def get_multipoint(self):
899
+ return MultiPoint([cur.as_shapelypoint() for cur in self.iter_on_vertices()])
900
+
901
+ def projectontrace(self, trace, return_cloud:bool = True, proximity:float = 99999.):
794
902
  """
795
903
  Projection du nuage sur une trace (type 'vector')
796
904
 
905
+ :param trace: classe vector
906
+ :param proximity: distance de recherche pour la projection
907
+
797
908
  Return :
798
- Nouveau nuage contenant les infos de position sur la trace et d'altitude (s,z)
909
+ if return_cloud:
910
+ Nouveau nuage contenant les infos de position sur la trace et d'altitude (s,z)
911
+ else:
912
+ s,z : list[float], list[float]
799
913
  """
914
+
800
915
  # trace:vector
801
916
  tracels:LineString
802
917
  tracels = trace.asshapely_ls() # conversion en linestring Shapely
803
918
 
804
- all_s = [tracels.project(Point(cur['vertex'].x,cur['vertex'].y)) for cur in self.myvertices.values()] # Projection des points sur la trace et récupération de la coordonnées curviligne
805
- all_z = [cur['vertex'].z for cur in self.myvertices.values()]
806
- # création d'un nouveau nuage
807
- newcloud = cloud_vertices(idx=_('Projection on ')+trace.myname)
919
+ if proximity == 99999.:
920
+ # on garde tous les points
921
+
922
+ all_s = [tracels.project(Point(cur['vertex'].x,cur['vertex'].y)) for cur in self.myvertices.values()] # Projection des points sur la trace et récupération de la coordonnées curviligne
923
+ all_z = [cur['vertex'].z for cur in self.myvertices.values()]
924
+
925
+ else:
926
+
927
+ buffer = tracels.buffer(proximity) # buffer de la trace
928
+
929
+ multipoints = self.get_multipoint() # conversion en multipoint Shapely
930
+
931
+ mp = multipoints.intersection(buffer) # intersection avec le buffer
932
+
933
+ all_s = [tracels.project(Point(cur.x,cur.y)) for cur in mp.geoms] # Projection des points sur la trace et récupération de la coordonnées curviligne
934
+ all_z = [cur.z for cur in mp.geoms] # récupération de l'altitude
808
935
 
809
936
  new_dict = {}
810
937
  k=0
@@ -812,6 +939,10 @@ class cloud_vertices(Element_To_Draw):
812
939
  new_dict[k] = {'vertex':wolfvertex(s,z)}
813
940
  k+=1
814
941
 
815
- newcloud.add_vertex(cloud=new_dict)
942
+ if return_cloud:
943
+ newcloud = cloud_vertices(idx=_('Projection on ')+trace.myname)
944
+ newcloud.add_vertex(cloud=new_dict)
816
945
 
817
- return newcloud
946
+ return newcloud
947
+ else:
948
+ return all_s, all_z
@@ -311,7 +311,7 @@ class Triangulation(Element_To_Draw):
311
311
 
312
312
  self.id_list = -99999
313
313
 
314
- def plot(self):
314
+ def plot(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None ):
315
315
 
316
316
  if self.id_list == -99999:
317
317
  self.id_list = glGenLists(1)
@@ -341,10 +341,10 @@ class Triangulation(Element_To_Draw):
341
341
  def find_minmax(self,force):
342
342
  if force:
343
343
  if self.nb_pts>0:
344
- self.minx=np.min(self.pts[:,0])
345
- self.miny=np.min(self.pts[:,1])
346
- self.maxx=np.max(self.pts[:,0])
347
- self.maxy=np.max(self.pts[:,1])
344
+ self.xmin=np.min(self.pts[:,0])
345
+ self.ymin=np.min(self.pts[:,1])
346
+ self.xmax=np.max(self.pts[:,0])
347
+ self.ymax=np.max(self.pts[:,1])
348
348
 
349
349
  def import_dxf(self,fn):
350
350
  import ezdxf
@@ -2268,8 +2268,8 @@ class zone:
2268
2268
  Création d'une triangulation sur base des vecteurs
2269
2269
  Tient compte de l'ordre
2270
2270
 
2271
- nb : nombre de points de découpe des vecteurs
2272
- nb2 : nombre de points en perpendiculaire
2271
+ :param nb : nombre de points de découpe des vecteurs
2272
+ :param nb2 : nombre de points en perpendiculaire
2273
2273
 
2274
2274
  return :
2275
2275
  - instance de 'Triangulation'
@@ -2284,8 +2284,14 @@ class zone:
2284
2284
  myls.append(curv.asshapely_ls())
2285
2285
 
2286
2286
  if nb is None and wx_exists:
2287
- dlg=wx.NumberEntryDialog(None,_('How many points along polylines ?')+'\n'+
2288
- _('Length size is {} meters').format(myls[0].length),'nb','dl size',100,1,10000.)
2287
+ dlg=wx.NumberEntryDialog(None,
2288
+ _('How many points along polylines ?')+'\n'+
2289
+ _('Length size is {} meters').format(myls[0].length),
2290
+ 'nb',
2291
+ 'dl size',
2292
+ 100,
2293
+ 1,
2294
+ 10000)
2289
2295
  ret=dlg.ShowModal()
2290
2296
  if ret==wx.ID_CANCEL:
2291
2297
  dlg.Destroy()
@@ -2304,7 +2310,13 @@ class zone:
2304
2310
  newls.append(LineString([curls.interpolate(curs,True) for curs in s]))
2305
2311
 
2306
2312
  if nb2==0 and wx_exists:
2307
- dlg=wx.NumberEntryDialog(None,_('How many points between two polylines ?'), 'nb2','perpendicular',0,1,10000.)
2313
+ dlg=wx.NumberEntryDialog(None,
2314
+ _('How many points between two polylines ?'),
2315
+ 'nb2',
2316
+ 'perpendicular',
2317
+ 0,
2318
+ 1,
2319
+ 10000)
2308
2320
  ret=dlg.ShowModal()
2309
2321
  if ret==wx.ID_CANCEL:
2310
2322
  dlg.Destroy()
@@ -2370,8 +2382,8 @@ class zone:
2370
2382
  Création d'une triangulation sur base des vecteurs par projection au plus proche du veteur central
2371
2383
  Tient compte de l'ordre
2372
2384
 
2373
- nb : nombre de points de découpe des vecteurs
2374
- nb2 : nombre de points en perpendiculaire
2385
+ :param nb : nombre de points de découpe des vecteurs
2386
+ :param nb2 : nombre de points en perpendiculaire
2375
2387
 
2376
2388
  return :
2377
2389
  - instance de 'Triangulation'
@@ -2387,7 +2399,7 @@ class zone:
2387
2399
 
2388
2400
  if nb is None and wx_exists:
2389
2401
  dlg=wx.NumberEntryDialog(None,_('How many points along polylines ?')+'\n'+
2390
- _('Length size is {} meters').format(myls[0].length),'nb','dl size',100,1,10000.)
2402
+ _('Length size is {} meters').format(myls[0].length),'nb','dl size',100,1,10000)
2391
2403
  ret=dlg.ShowModal()
2392
2404
  if ret==wx.ID_CANCEL:
2393
2405
  dlg.Destroy()
@@ -2411,7 +2423,7 @@ class zone:
2411
2423
  newls.append(LineString([curls.interpolate(curs) for curs in news]))
2412
2424
 
2413
2425
  if nb2==0 and wx_exists:
2414
- dlg=wx.NumberEntryDialog(None,_('How many points between two polylines ?'), 'nb2','perpendicular',0,0,10000.)
2426
+ dlg=wx.NumberEntryDialog(None,_('How many points between two polylines ?'), 'nb2','perpendicular',0,0,10000)
2415
2427
  ret=dlg.ShowModal()
2416
2428
  if ret==wx.ID_CANCEL:
2417
2429
  dlg.Destroy()
@@ -33,6 +33,7 @@ class Colors_Lazviewer(Enum):
33
33
  ORTHO_2012_2013 = 2013
34
34
  ORTHO_2015 = 2015
35
35
  ORTHO_2021 = 2021
36
+ ORTHO_2023 = 2023
36
37
  ORTHO_2006_2007 = 2006
37
38
  CODE_2013 = 0
38
39
  CODE_2023 = 2
@@ -93,7 +94,7 @@ class Classification_LAZ():
93
94
  self.test_wx()
94
95
 
95
96
  if self._choose_colors is None and self.wx_exists:
96
- self._choose_colors = Wolf_Param(None, _('Colors of classification LAZ 2023'), w=600, h=800, to_read=False, withbuttons=True, toShow=False)
97
+ self._choose_colors = Wolf_Param(None, _('Colors of classification LAZ 2023'), w=600, h=800, to_read=False, withbuttons=True, toShow=False, force_even_if_same_default=True)
97
98
  self._choose_colors.callback = self.callback_colors
98
99
  self._choose_colors.callbackdestroy = self.callback_destroy
99
100
  self._choose_colors.hide_selected_buttons()
@@ -987,6 +988,8 @@ def get_colors(las:laspy.LasData, which_colors:Colors_Lazviewer, imsize=2000, fn
987
988
  mycat='IMAGERIE/ORTHO_2021'
988
989
  elif which_colors==Colors_Lazviewer.ORTHO_2006_2007.value:
989
990
  mycat='IMAGERIE/ORTHO_2006_2007'
991
+ elif which_colors==Colors_Lazviewer.ORTHO_2023.value:
992
+ mycat='IMAGERIE/ORTHO_2023_ETE'
990
993
 
991
994
  if type(las) is laspy.LasData:
992
995
  x = las.x
wolfhece/wolf_array.py CHANGED
@@ -3773,28 +3773,47 @@ class WolfArray(Element_To_Draw, header_wolf):
3773
3773
  else:
3774
3774
  self.add_ops_sel()
3775
3775
 
3776
- def compare_cloud(self,mycloud:cloud_vertices):
3776
+ def compare_cloud(self, mycloud:cloud_vertices, delta:list[float] = [.15, .5, 1.]):
3777
3777
  """
3778
3778
  Graphique de comparaison des valeurs d'un nuage de points et des valeurs de la matrice sous les mêmes positions
3779
+
3780
+ :param mycloud: cloud_vertices
3781
+ :param delta: list of tolerance for the comparison
3782
+
3779
3783
  """
3784
+
3785
+ # Get the values of the cloud
3780
3786
  xyz_cloud = mycloud.get_xyz()
3787
+ # Get values of the array at the same positions
3781
3788
  zarray = np.array([self.get_value(curxy[0],curxy[1]) for curxy in xyz_cloud])
3782
3789
 
3790
+ # count the number of points outside the array
3783
3791
  nbout = np.count_nonzero(zarray==-99999)
3784
3792
 
3793
+ # Get the values of the cloud that are not outside the array
3794
+ # Separate XY and Z values (cloud and array)
3795
+ # - z values
3785
3796
  z_cloud = xyz_cloud[zarray!=-99999][:,2]
3797
+ # - xy values
3786
3798
  xy_cloud = xyz_cloud[zarray!=-99999][:,:2]
3799
+
3800
+ # - array values
3787
3801
  zarray = zarray[zarray!=-99999]
3788
3802
 
3803
+ # concatenate all z values
3789
3804
  zall = np.concatenate([z_cloud,zarray])
3805
+ # find the min and max values
3790
3806
  zmin = np.min(zall)
3791
3807
  zmax = np.max(zall)
3792
3808
 
3809
+ # compute differences
3793
3810
  diffz = zarray-z_cloud
3811
+ # choose a colormap
3794
3812
  cmap = plt.cm.get_cmap('RdYlBu')
3795
3813
  mindiff = np.min(diffz)
3796
3814
  maxdiff = np.max(diffz)
3797
3815
 
3816
+ # Plot the differences [0] and the position [1]
3798
3817
  fig,ax = plt.subplots(2,1)
3799
3818
  ax[0].set_title(_('Comparison Z - ') + str(nbout) + _(' outside points on ') + str(len(xyz_cloud)))
3800
3819
  sc0 = ax[0].scatter(z_cloud,zarray,s=10,c=diffz,cmap = cmap, vmin=mindiff, vmax=maxdiff)
@@ -3802,7 +3821,16 @@ class WolfArray(Element_To_Draw, header_wolf):
3802
3821
  ax[0].set_ylabel(_('Array values'))
3803
3822
  ax[0].set_xlim([zmin,zmax])
3804
3823
  ax[0].set_ylim([zmin,zmax])
3805
- ax[0].plot([zmin,zmax],[zmin,zmax])
3824
+
3825
+ ax[0].plot([zmin,zmax],[zmin,zmax], color='black')
3826
+
3827
+ if delta is not None:
3828
+ if isinstance(delta, list):
3829
+ for idx, curdelta in enumerate(delta):
3830
+ curdelta = abs(float(curdelta))
3831
+ ax[0].plot([zmin,zmax],[zmin+delta,zmax+delta], 'k--', alpha=1.-1./(idx+1))
3832
+ ax[0].plot([zmin,zmax],[zmin-delta,zmax-delta], 'k--', alpha=1.-1./(idx+1))
3833
+
3806
3834
  ax[0].axis('equal')
3807
3835
 
3808
3836
  sc1 = ax[1].scatter(xy_cloud[:,0],xy_cloud[:,1],s=10,c=diffz,cmap = cmap, vmin=mindiff, vmax=maxdiff)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.0.18
3
+ Version: 2.0.19
4
4
  Author-email: Stéphane Champailler <stephane.champailler@uliege.be>, Pierre Archambeau <pierre.archambeau@uliege.be>
5
5
  Project-URL: Homepage, https://uee.uliege.be/hece
6
6
  Project-URL: Issues, https://uee.uliege.be/hece
@@ -5,16 +5,16 @@ wolfhece/Lidar2002.py,sha256=sXZ6p8_EKI5l8fJswIMAABT6dqHKVexU52Tjl1uuisU,5770
5
5
  wolfhece/ManageParams.py,sha256=Wgt5Zh7QBtyiwTAltPHunSLqt4XuVuRH76GTUrXabS4,219
6
6
  wolfhece/PyConfig.py,sha256=oGSL1WsLM9uinlNP4zGBLK3uHPmBfduUi7R-VtWuRFA,8034
7
7
  wolfhece/PyCrosssections.py,sha256=wdq-KYaLDBAa-gu3plWFBJN0Stx-oZX2dxs-iKjGBHo,111109
8
- wolfhece/PyDraw.py,sha256=DYiV9eUq6bXPpqQEl8w-WH45pAqLY5U2Hl0XZW9T7Zk,300264
8
+ wolfhece/PyDraw.py,sha256=wXOtnYNVBRoaD8kkbcq1DRUEVqwY74akdPcL-eIUHn0,303430
9
9
  wolfhece/PyGui.py,sha256=mzJCRjMHtebFrxmPnwUK6YpQgMf5iiiCTm0hCOuRsOY,52722
10
10
  wolfhece/PyGuiHydrology.py,sha256=t7EqOMyA1mkVg_aATMaduR-aqs04V-uRCifyHVmPqRs,7133
11
11
  wolfhece/PyHydrographs.py,sha256=h2OfgmRkKc5XZn0iPFOVy60pGTSa5EFoUOEya0SeG7o,3411
12
12
  wolfhece/PyPalette.py,sha256=nb9oPLZF-xx-yvOWvw2XVVmis6XTmYT2i7hvH3qPwAg,21932
13
- wolfhece/PyParams.py,sha256=RqeIWvvKZ6LK5q6QK4k6SIRci4qVgLejnVR45sDS9iw,77211
13
+ wolfhece/PyParams.py,sha256=TN7xDdhBGwq9dypVXuIfOUZ9Y6OxwcemfMhrJr1Y89U,81691
14
14
  wolfhece/PyPictures.py,sha256=-mJB0JL2YYiEK3D7_ssDkvYiMWK4ve9kXhozQXNeSx8,2216
15
15
  wolfhece/PyTranslate.py,sha256=4appkmNeHHZLFmUtaA_k5_5QL-5ymxnbVN4R2OblmtE,622
16
- wolfhece/PyVertex.py,sha256=nqQhfg4RFn4iGenJf6BMsnPB-fNFjnXqVeUi39BhEWc,30512
17
- wolfhece/PyVertexvectors.py,sha256=T5or2zgEy1Z6-DsrwJmRvsHo_fmcCiqNHAtrBBaV0wk,189557
16
+ wolfhece/PyVertex.py,sha256=slmNcecB54jmqGHC4bozemLRUASSW6uJzypxWZ9kh7g,35071
17
+ wolfhece/PyVertexvectors.py,sha256=n5Xfb-AlJfwV-RVOrV15Uo3STR-PYdxDY1Tb_MJkeV0,190119
18
18
  wolfhece/PyWMS.py,sha256=t6jVZpTxTNSLJxABk8A79cEMWTKoRM_S_SXRipsHLzw,4493
19
19
  wolfhece/RatingCurve.py,sha256=Psw4OknvqVXOjIomJxCW4hGd_q2HZ4DmcwV-wJXehds,21420
20
20
  wolfhece/RatingCurveData.py,sha256=5UvnIm89BwqjnEbLCcY3CA8WoFd_xHJbooNy62fX5iY,57660
@@ -44,7 +44,7 @@ wolfhece/pywalous.py,sha256=jwp251AzGBc0VmMzOqA0IJiRRa6yQIfccRM8lVGszIY,4474
44
44
  wolfhece/rain_SPWMI.py,sha256=YqsF-yFro3y_a6MfVRFfr-Rxi7NR1gl_i8VX7scmzes,13548
45
45
  wolfhece/textpillow.py,sha256=YJxF4JzPv3G1oqenJgWVYq3OPZx9iFtrmeIfvBwbJVU,8735
46
46
  wolfhece/tools_mpl.py,sha256=q8Yc4aukPPiUcEzREvZRM_em67XqXaahdoaNt0DETfE,266
47
- wolfhece/wolf_array.py,sha256=BAdO9j_ilDbzJ_Awrqnxz0kKL3zML0Z8eCSkY_M8IQM,280195
47
+ wolfhece/wolf_array.py,sha256=gFHA0xTTQpgwneXUNwbSvvbMRp6nJaXyDKU5EQuKBR0,281277
48
48
  wolfhece/wolf_hist.py,sha256=JpRXvzJLUP-RkSkvth3DQWglgTMFI2ZEUDb4RYOfeeI,3284
49
49
  wolfhece/wolf_texture.py,sha256=quflEvi32lWSvOPa0aDCDl-8Jv-jGtLHbR2rdx67LsI,14883
50
50
  wolfhece/wolf_tiles.py,sha256=F2JsJHdAP8fIffNJdG_J26bonCIRtIwMmxKFqdSCRDA,10088
@@ -118,7 +118,7 @@ wolfhece/lagrangian/particles.py,sha256=TOr02FFIz98i0eFe8HAq-tpnJH0zgyCu1mDPeBxs
118
118
  wolfhece/lagrangian/velocity_field.py,sha256=vwGq7fEazib4Or7afVIFMfY_rRemQgKuSZ_4lHHx3wM,10276
119
119
  wolfhece/lazviewer/__init__.py,sha256=0SNDEKGad6e2AwxjalcPqb2bdW6crmXQFxWUY13PiVU,223
120
120
  wolfhece/lazviewer/_add_path.py,sha256=GDwPnzHuGRXGriDNcu1SQ6HetFDGIApeAQZEzYArGvI,605
121
- wolfhece/lazviewer/laz_viewer.py,sha256=7_IrV4smPxmIbhpq9zlX1Lorv-dyf5lwjRVhiSThqzc,42041
121
+ wolfhece/lazviewer/laz_viewer.py,sha256=EHg-7MGRASevT3tmOwIGWdZZqo8cvEbTt8J2Ei9v1X8,42205
122
122
  wolfhece/lazviewer/libs/Qt5Core.dll,sha256=sTJ_ctYFY9KHMNytF-lzH_078zIvnKTjN-71FDkOWPw,4924928
123
123
  wolfhece/lazviewer/libs/Qt5Gui.dll,sha256=07BeaOeYByraGkKYeDiSDYLawHM8tyd55pVJlKbZ4Y0,5436416
124
124
  wolfhece/lazviewer/libs/Qt5Network.dll,sha256=U-9FiLE9LUKru8r8EQxTnwwlMpwS8JzUtenhkKTCox0,1038336
@@ -243,8 +243,8 @@ wolfhece/sounds/sonsw1.wav,sha256=HhuGeZ3iIyJdDALmM-jvGZDkKw3IZ3JXCuQZkN3Zjtc,21
243
243
  wolfhece/sounds/sonsw2.wav,sha256=pFLVt6By0_EPQNt_3KfEZ9a1uSuYTgQSX1I_Zurv9Rc,110636
244
244
  wolfhece/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
245
245
  wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=yGbU_JsF56jsmms0gh7mxa7tbNQ_SxqhpAZxhm-mTy4,14860
246
- wolfhece-2.0.18.dist-info/METADATA,sha256=_Qnbh7lus3Ln44kYSd_UjvnovEnBd38bWRq4nIHSMPw,2239
247
- wolfhece-2.0.18.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
248
- wolfhece-2.0.18.dist-info/entry_points.txt,sha256=IHhq-i2W9QpyXFHKe2Ld8j1R4hW5DmYqrZsuSsXkdEE,245
249
- wolfhece-2.0.18.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
250
- wolfhece-2.0.18.dist-info/RECORD,,
246
+ wolfhece-2.0.19.dist-info/METADATA,sha256=CMs_atGwoXeru4C1K50WGzLgM73dEJw7iAgE53id5-M,2239
247
+ wolfhece-2.0.19.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
248
+ wolfhece-2.0.19.dist-info/entry_points.txt,sha256=IHhq-i2W9QpyXFHKe2Ld8j1R4hW5DmYqrZsuSsXkdEE,245
249
+ wolfhece-2.0.19.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
250
+ wolfhece-2.0.19.dist-info/RECORD,,