wolfhece 2.1.116__py3-none-any.whl → 2.1.118__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.
@@ -5,7 +5,7 @@ from PIL import Image
5
5
  from os.path import exists,join
6
6
  import matplotlib.pyplot as plt
7
7
  from os import stat,remove,listdir,scandir, makedirs
8
- import pathlib
8
+ from pathlib import Path
9
9
  import math
10
10
  from time import sleep
11
11
  from typing import Literal, Union
@@ -22,8 +22,10 @@ from . import viewer
22
22
  from ..PyWMS import getWalonmap
23
23
  from ..PyTranslate import _
24
24
  from ..color_constants import Colors
25
- from ..PyParams import Wolf_Param
25
+ from ..PyParams import Wolf_Param, Type_Param
26
26
  from ..matplotlib_fig import Matplotlib_Figure as mplfig
27
+ from ..drawing_obj import Element_To_Draw
28
+ from ..CpGrid import CpGrid
27
29
 
28
30
  """
29
31
  Importation et visualisation de données LAS et LAZ
@@ -43,16 +45,20 @@ class Colors_Lazviewer(Enum):
43
45
  class Classification_LAZ():
44
46
 
45
47
  def __init__(self) -> None:
48
+
49
+ self.class_name = 'SPW-Geofit 2023'
46
50
  self.classification:dict[str,str,list[float,float,float,float]] = {}
47
51
  self.test_wx()
48
52
 
49
53
  self._choose_colors = None
54
+ self._viewer = None
50
55
 
51
56
  def test_wx(self):
52
57
  self.wx_exists = wx.App.Get() is not None
53
58
 
54
59
  def init_2013(self):
55
60
 
61
+ self.class_name = 'SPW 2013-2014'
56
62
  self.classification={
57
63
  0 : ['0', 'Pas de classification', Colors.rgb_withalpha_float('black',.2),],
58
64
  1 : ['Hors-sol', 'building, toits et autres', Colors.rgb_withalpha_float('white',.2),],
@@ -63,6 +69,7 @@ class Classification_LAZ():
63
69
 
64
70
  def init_2023(self):
65
71
 
72
+ self.class_name = 'SPW-Geofit 2023'
66
73
  self.classification={
67
74
  0 : ['0', 'Pas de classification', Colors.rgb_withalpha_float('black',.2),],
68
75
  1 : ['Défaut', 'Voiture, câbles électrique, points de végétation diffus, Sursol non utile', Colors.rgb_withalpha_float('white',.2),],
@@ -72,6 +79,7 @@ class Classification_LAZ():
72
79
  9 : ['Eau', 'Points de la surface d\’eau brute mesurés par le scanner 2',Colors.rgb_withalpha_float('royalblue',.3)],
73
80
  10 : ['Ponts', 'Les ponts ont été classés à part pour améliorer la définition du MNT. Ils ont été ouverts grâce',Colors.rgb_withalpha_float('lightyellow1',1.)],
74
81
  11 : ['Mur de berges', 'Mur et muret en berge de la Vesdre dépassant le sol à des vocation de réaliser une modélisation 3D hydraulique avec ces obstacles.',Colors.rgb_withalpha_float('red1',1.)],
82
+ 13 : ['Inconnu', 'A vérifier auSPW', Colors.rgb_withalpha_float('lightslategray',.2)],
75
83
  15 : ['Tranche d\'eau', 'Echo intermédiaire dans l\’eau n\’appartenant ni à la surface d\’eau ni au fond du lit', Colors.rgb_withalpha_float('lightblue',.2)],
76
84
  16 : ['Surface bathymétrique', 'Fond du lit de la Vesdre et de ses affluents et des autres surfaces d\’eau mesurées à partir du scanner 3 FWF discrétisé',Colors.rgb_withalpha_float('sandybrown',1.)],
77
85
  17 : ['Surface bathymétrique incertaine', 'Surface bathymétrique sur les zones peu profondes principalement sous végétation où les intensités des échos sont parfois trop faibles pour avoir la certitude qu\’ils représentent le fond de rivière. La classe 17 est néanmoins plus certaine que la classe 18. Elle est utilisée dans la génération des MNT par défaut.',Colors.rgb_withalpha_float('rosybrown',.5)],
@@ -142,7 +150,7 @@ class xyz_laz():
142
150
  self.data = []
143
151
  return
144
152
 
145
- last_part = pathlib.Path(fn).name
153
+ last_part = Path(fn).name
146
154
  parts = last_part.split('_')
147
155
 
148
156
  # L'origine est codée dans le nom de fichier
@@ -153,7 +161,7 @@ class xyz_laz():
153
161
  dy = 3500.
154
162
 
155
163
  # Récupération du lien vers le fichier GridInfo.txt
156
- gridinfo=join(pathlib.Path(fn).parent,'gridinfo.txt')
164
+ gridinfo=join(Path(fn).parent,'gridinfo.txt')
157
165
 
158
166
  if exists(gridinfo):
159
167
  with open(gridinfo,'r') as f:
@@ -240,8 +248,8 @@ class xyz_laz():
240
248
  if exists(fn+'.zip'):
241
249
  with zipfile.ZipFile(fn+'.zip','r') as zip_file:
242
250
  fn = zip_file.namelist()[0]
243
- zip_file.extract(fn, path=pathlib.Path(fn).parent)
244
- fn = join(pathlib.Path(fn).parent, fn)
251
+ zip_file.extract(fn, path=Path(fn).parent)
252
+ fn = join(Path(fn).parent, fn)
245
253
  elif not exists(fn):
246
254
  return
247
255
 
@@ -391,7 +399,7 @@ class xyz_laz_grid():
391
399
  xloc = np.linspace(xbounds[0], xbounds[1], gridsize[0]+1)
392
400
  yloc = np.linspace(ybounds[0], ybounds[1], gridsize[1]+1)
393
401
 
394
- dirout = pathlib.Path(fn_out).parent
402
+ dirout = Path(fn_out).parent
395
403
  fn=join(dirout,'gridinfo.txt')
396
404
 
397
405
  if exists(fn):
@@ -401,7 +409,7 @@ class xyz_laz_grid():
401
409
  f.write(str(int(xbounds[0]))+','+str(int(xbounds[1]))+'\n')
402
410
  f.write(str(int(ybounds[0]))+','+str(int(ybounds[1]))+'\n')
403
411
  f.write(str(int(gridsize[0]))+','+str(int(gridsize[1]))+'\n')
404
- f.write(pathlib.Path(fn_out).name+'_'+'x1'+'_'+'y1'+'_xyz.bin'+'\n')
412
+ f.write(Path(fn_out).name+'_'+'x1'+'_'+'y1'+'_xyz.bin'+'\n')
405
413
  if force_format == np.float64:
406
414
  f.write('xy_float64')
407
415
  else:
@@ -477,7 +485,7 @@ class xyz_laz_grid():
477
485
  if force_format == np.float64:
478
486
  fnzip = fn + '.zip'
479
487
  with zipfile.ZipFile(fnzip,'w',zipfile.ZIP_DEFLATED) as zip_file:
480
- zip_file.write(fn, pathlib.Path(fn).name)
488
+ zip_file.write(fn, Path(fn).name)
481
489
  remove(fn)
482
490
 
483
491
 
@@ -678,6 +686,639 @@ class xyz_laz_grids():
678
686
  gridsize=[max(int(dx/ds),1), max(int(dy/ds),1)],
679
687
  force_format=force_format))
680
688
 
689
+
690
+ class Base_LAZ_Data(Element_To_Draw):
691
+
692
+ def __init__(self, idx:str = '', plotted:bool = False, mapviewer = None, need_for_wx:bool = False) -> None:
693
+
694
+ self._bounds = [[0.,0.],[0.,0.]] # [[xmin,xmax],[ymin,ymax]]
695
+ super().__init__(idx, plotted, mapviewer, need_for_wx)
696
+
697
+ self.lazfile:Path = None
698
+ self._data:np.ndarray = None
699
+ self.classification = Classification_LAZ()
700
+
701
+ self.associated_color:int = Colors_Lazviewer.CODE_2023.value
702
+
703
+ self.viewer:viewer = None
704
+ self._colors:np.ndarray = None
705
+
706
+ self._point_size = .05
707
+
708
+ self._memory = []
709
+
710
+ self._myprops = None
711
+
712
+ self._bg_color = [0,0,0,255]
713
+ self._bg_color_top = [0,0,0,255]
714
+ self._bg_color_bottom = [0,0,0,255]
715
+
716
+ self._floor_level = 0.
717
+ self._floor_color = [0,0,0,255]
718
+
719
+ self._show_grid = True
720
+ self._show_axis = True
721
+ self._show_info = True
722
+
723
+ self._select_only_codes = []
724
+
725
+ self._xls:CpGrid = None
726
+ self._xlsFrame:wx.Frame = None
727
+
728
+ # self._auto_update_properties = False
729
+ # self._auto_update_interval = 100 # ms
730
+ # self._timer = None
731
+
732
+ def filter_data(self, codes:list[int]):
733
+ self._data = self._data[np.isin(self._data[:,3],codes)]
734
+
735
+ def bg_color(self, value):
736
+ if self.viewer is not None:
737
+ return self.viewer.set(bg_color = value)
738
+
739
+ def bg_color_top(self, value):
740
+ if self.viewer is not None:
741
+ return self.viewer.set(bg_color_top = value)
742
+
743
+ def bg_color_bottom(self, value):
744
+ if self.viewer is not None:
745
+ return self.viewer.set(bg_color_bottom = value)
746
+
747
+ def floor_level(self, value):
748
+ if self.viewer is not None:
749
+ return self.viewer.set(floor_level = value)
750
+
751
+ def floor_color(self, value):
752
+ if self.viewer is not None:
753
+ return self.viewer.set(floor_color = value)
754
+
755
+ def show_grid(self, value:bool):
756
+ if self.viewer is not None:
757
+ return self.viewer.set(show_grid = value)
758
+
759
+ def show_axis(self, value:bool):
760
+ if self.viewer is not None:
761
+ return self.viewer.set(show_axis = value)
762
+
763
+ def show_info(self, value:bool):
764
+ if self.viewer is not None:
765
+ return self.viewer.set(show_info = value)
766
+
767
+ @property
768
+ def selected(self):
769
+ if self.viewer is None:
770
+ return None
771
+ return self.viewer.get('selected')
772
+
773
+ @property
774
+ def xyz_selected(self) -> np.ndarray:
775
+ if self.viewer is None:
776
+ return None
777
+
778
+ if self.selected.shape[0] == 0:
779
+ return np.ndarray((0,3))
780
+
781
+ if len(self._select_only_codes)>0:
782
+ return self.data[self.selected,:3][np.isin(self.data[self.selected,3],self._select_only_codes)]
783
+ else:
784
+ return self.data[self.selected,:3]
785
+
786
+ @property
787
+ def code_selected(self) -> np.ndarray:
788
+ if self.viewer is None:
789
+ return None
790
+
791
+ if self.selected.shape[0] == 0:
792
+ return np.ndarray((0,1))
793
+
794
+ if len(self._select_only_codes)>0:
795
+ return self.data[self.selected,3][np.isin(self.data[self.selected,3],self._select_only_codes)]
796
+ else:
797
+ return self.data[self.selected,3]
798
+
799
+ @property
800
+ def num_points(self):
801
+ """ Number of points """
802
+ nb1 = self.data.shape[0]
803
+ if self.viewer is not None:
804
+ nb2 = self.viewer.get('num_points')[0]
805
+ assert nb1 == nb2, _('Incoherent number of points')
806
+
807
+ return nb1
808
+
809
+ @property
810
+ def nb_points(self):
811
+ """ Number of points """
812
+ return self.num_points
813
+
814
+ @property
815
+ def nb(self):
816
+ """ Number of points """
817
+ return self.num_points
818
+
819
+ @property
820
+ def right(self):
821
+ """Camera Right vector """
822
+ return self.viewer.get('right')
823
+
824
+ @property
825
+ def mvp(self):
826
+ if self.viewer is None:
827
+ return None
828
+ return self.viewer.get('mvp')
829
+
830
+ @property
831
+ def eye(self):
832
+ if self.viewer is None:
833
+ return None
834
+ return self.viewer.get('eye')
835
+
836
+ @property
837
+ def lookat(self):
838
+ if self.viewer is None:
839
+ return None
840
+ return self.viewer.get('lookat')
841
+
842
+ @property
843
+ def phi(self):
844
+ if self.viewer is None:
845
+ return None
846
+ return self.viewer.get('phi')[0]
847
+
848
+ @property
849
+ def theta(self):
850
+ if self.viewer is None:
851
+ return None
852
+ return self.viewer.get('theta')[0]
853
+
854
+ @property
855
+ def r(self):
856
+ if self.viewer is None:
857
+ return None
858
+ return self.viewer.get('r')[0]
859
+
860
+ @phi.setter
861
+ def phi(self, value):
862
+ if self.viewer is None:
863
+ return None
864
+ self.viewer.set(phi=value)
865
+
866
+ @theta.setter
867
+ def theta(self, value):
868
+ if self.viewer is None:
869
+ return None
870
+ self.viewer.set(theta=value)
871
+
872
+ @r.setter
873
+ def r(self, value):
874
+ if self.viewer is None:
875
+ return None
876
+ self.viewer.set(r=value)
877
+
878
+ @lookat.setter
879
+ def lookat(self, value):
880
+ if self.viewer is None:
881
+ return None
882
+ self.viewer.set(lookat=value)
883
+
884
+ @eye.setter
885
+ def eye(self, value):
886
+ if self.viewer is None:
887
+ return None
888
+ x,y,z = value
889
+ lx, ly, lz = self.lookat
890
+ right = self.right
891
+
892
+ # Compute phi, theta, r based on eye and lookat and right vector
893
+ r = np.sqrt((x-lx)**2 + (y-ly)**2 + (z-lz)**2)
894
+ self.r =r
895
+ self.phi = np.arccos((z-lz)/r)
896
+ self.theta = np.arctan2((y-ly),(x-lx))
897
+
898
+ @property
899
+ def point_size(self):
900
+ return self._point_size
901
+
902
+ @point_size.setter
903
+ def point_size(self, value):
904
+ self._point_size = value
905
+ if self.viewer is not None:
906
+ self.viewer.set(point_size=value)
907
+
908
+ @property
909
+ def xyz(self):
910
+ return self.data[:,:3]
911
+
912
+ @property
913
+ def codes(self):
914
+ return self.data[:,3]
915
+
916
+ def codes_unique(self):
917
+ return list(np.unique(self.codes).astype(int))
918
+
919
+ def create_viewer(self, color_code:Colors_Lazviewer = None, classification:Classification_LAZ = None):
920
+ """ Create a viewer for las data """
921
+
922
+ if color_code is not None:
923
+ self.associated_color = color_code
924
+
925
+ if classification is not None:
926
+ self.classification = classification
927
+
928
+ self._colors = get_colors(self.data, self.associated_color, palette_classif= self.classification)
929
+
930
+ self.viewer = viewer(self.xyz, self._colors)
931
+ self.viewer.set(point_size= self._point_size)
932
+
933
+ return self.viewer
934
+
935
+ def interactive_update_colors(self):
936
+
937
+ self.classification.interactive_update_colors()
938
+
939
+ self.classification._choose_colors.SetTitle(_('Colors of ') + self.idx)
940
+
941
+ def new_callback_colors():
942
+ self.classification.callback_colors()
943
+ self.set_colors()
944
+
945
+ self.classification._choose_colors.callback = new_callback_colors
946
+
947
+ def set_colors(self):
948
+ if self.viewer is not None:
949
+ self._colors = get_colors(self.data, self.associated_color, palette_classif= self.classification)
950
+ self.viewer.attributes(self._colors)
951
+
952
+ def set_classification(self, classification:str = None):
953
+
954
+ if classification is None:
955
+ logging.warning(_('No classification chosen - Abort !'))
956
+ elif classification == 'SPW 2013-2014':
957
+ self.classification.init_2013()
958
+ else:
959
+ self.classification.init_2023()
960
+
961
+ def find_minmax(self, update=False):
962
+ if self.data is not None:
963
+ self.bounds = [[np.min(self.data[:,0]), np.max(self.data[:,0])],[np.min(self.data[:,1]), np.max(self.data[:,1])]]
964
+
965
+ @property
966
+ def xmin(self):
967
+ return self.bounds[0][0]
968
+
969
+ @xmin.setter
970
+ def xmin(self, value):
971
+ self._bounds[0][0] = value
972
+
973
+ @property
974
+ def xmax(self):
975
+ return self.bounds[0][1]
976
+
977
+ @xmax.setter
978
+ def xmax(self, value):
979
+ self._bounds[0][1] = value
980
+
981
+ @property
982
+ def ymin(self):
983
+ return self.bounds[1][0]
984
+
985
+ @ymin.setter
986
+ def ymin(self, value):
987
+ self._bounds[1][0] = value
988
+
989
+ @property
990
+ def ymax(self):
991
+ return self.bounds[1][1]
992
+
993
+ @ymax.setter
994
+ def ymax(self, value):
995
+ self._bounds[1][1] = value
996
+
997
+ @property
998
+ def data(self):
999
+ return self._data
1000
+
1001
+ @data.setter
1002
+ def data(self, value):
1003
+ self._data = value
1004
+
1005
+ @property
1006
+ def bounds(self):
1007
+ return self._bounds
1008
+
1009
+ @bounds.setter
1010
+ def bounds(self, value):
1011
+ self._bounds = value
1012
+
1013
+ def from_grid(self, grid:xyz_laz_grid, bounds:Union[tuple[tuple[float,float],tuple[float,float]], list[list[float, float],list[float, float]]]):
1014
+
1015
+ self.bounds = bounds
1016
+ self.data = grid.scan(bounds)
1017
+
1018
+ def from_file(self, fn:str):
1019
+
1020
+ self.data = read_laz(fn)
1021
+ self.bounds = [[np.min(self.data[:,0]), np.max(self.data[:,0])],[np.min(self.data[:,1]), np.max(self.data[:,1])]]
1022
+
1023
+ def decimate(self, step:int):
1024
+ self.data = self.data[::step]
1025
+
1026
+ def get_data_class(self, key:int):
1027
+ return self.data[self.data[:,3] == key]
1028
+
1029
+ def add_pose_in_memory(self, key_time:float = 1.):
1030
+ if self.viewer is not None:
1031
+ lookat = self.lookat
1032
+ new_pose = (lookat[0], lookat[1], lookat[2], self.phi, self.theta, self.r)
1033
+ self._memory.append((new_pose, key_time))
1034
+
1035
+ def play_flight(self, tlim=[-np.inf, np.inf], repeat=False, interp='cubic_natural'):
1036
+
1037
+ if self.viewer is not None:
1038
+ if len(self._memory)>0:
1039
+ poses = [cur[0] for cur in self._memory]
1040
+ times = [0.]
1041
+ for i in range(1,len(self._memory)):
1042
+ times.append(times[-1]+self._memory[i][1])
1043
+ self.viewer.play(poses, times, tlim, repeat, interp)
1044
+
1045
+ def set_times(self, times:np.ndarray):
1046
+ if len(self._memory)>0:
1047
+ self._memory = [(self._memory[i][0], times[i]) for i in range(len(self._memory))]
1048
+
1049
+ def set_times_increment(self, increment:float):
1050
+ if len(self._memory)>0:
1051
+ self._memory = [(self._memory[i][0], increment*i) for i in range(len(self._memory))]
1052
+
1053
+ def get_times(self):
1054
+ return np.asarray([cur[1] for cur in self._memory])
1055
+
1056
+ def record_flight(self, dirout:str, tlim=[-np.inf, np.inf], interp='cubic_natural', fps=24, prefix:str = 'laz_', ext:str = '.png'):
1057
+ if self.viewer is not None:
1058
+ if len(self._memory)>0:
1059
+ poses = [cur[0] for cur in self._memory]
1060
+ times = [0.]
1061
+ for i in range(1,len(self._memory)):
1062
+ times.append(times[-1]+self._memory[i][1])
1063
+ self.viewer.record(dirout, poses, times, tlim, interp, fps=fps, prefix=prefix, ext=ext)
1064
+
1065
+ def save_flight(self, fn:str):
1066
+ """ Write memory to file JSON """
1067
+ import json
1068
+
1069
+ if len(self._memory)>0:
1070
+ with open(fn,'w') as f:
1071
+ json.dump(self._memory, f, indent=2)
1072
+
1073
+ def load_flight(self, fn:str):
1074
+ """ Load memory from file JSON """
1075
+ import json
1076
+
1077
+ if exists(fn):
1078
+ with open(fn,'r') as f:
1079
+ self._memory = json.load(f)
1080
+
1081
+
1082
+ def _callback_props(self):
1083
+
1084
+ self._update_props()
1085
+
1086
+ def _callback_destroy_props(self):
1087
+
1088
+ if self._myprops is not None:
1089
+ self._callback_props()
1090
+ self._myprops.Destroy()
1091
+ self._myprops = None
1092
+
1093
+ def _create_props(self):
1094
+
1095
+ if self._myprops is not None:
1096
+ return
1097
+
1098
+ self._myprops = Wolf_Param(None, title=_('Properties of ') + self.idx,
1099
+ to_read=False, force_even_if_same_default= True)
1100
+
1101
+ props = self._myprops
1102
+
1103
+ props.set_callbacks(self._callback_props, self._callback_destroy_props)
1104
+ props.hide_selected_buttons()
1105
+
1106
+
1107
+ ret = props.addparam('Camera', 'X', self.eye[0], Type_Param.Float, 'eye_x')
1108
+ ret = props.addparam('Camera', 'Y', self.eye[1], Type_Param.Float, 'eye_y')
1109
+ ret = props.addparam('Camera', 'Z', self.eye[2], Type_Param.Float, 'eye_z')
1110
+
1111
+ ret = props.addparam('Look at', 'X', self.lookat[0], Type_Param.Float, 'lookat_x')
1112
+ ret = props.addparam('Look at', 'Y', self.lookat[1], Type_Param.Float, 'lookat_y')
1113
+ ret = props.addparam('Look at', 'Z', self.lookat[2], Type_Param.Float, 'lookat_z')
1114
+
1115
+ ret = props.addparam('Relative Position', 'Phi', self.phi, Type_Param.Float, 'azimuthal angle (radians) - (phi, theta, r) are spherical coordinates specifying camera position relative to the look at position.')
1116
+ ret = props.addparam('Relative Position', 'Theta', self.theta, Type_Param.Float, 'elevation angle (radians) - (phi, theta, r) are spherical coordinates specifying camera position relative to the look at position.')
1117
+ ret = props.addparam('Relative Position', 'R', self.r, Type_Param.Float, 'distance to look-at point - (phi, theta, r) are spherical coordinates specifying camera position relative to the look at position.')
1118
+
1119
+ ret = props.addparam('Background', 'Color', self._bg_color, Type_Param.Color, 'Background color')
1120
+ ret = props.addparam('Background', 'Top Color', self._bg_color_top, Type_Param.Color, 'Top Background color')
1121
+ ret = props.addparam('Background', 'Bottom Color', self._bg_color_bottom, Type_Param.Color, 'Bottom Background color')
1122
+
1123
+ ret = props.addparam('Floor', 'Level', self._floor_level, Type_Param.Float, 'Floor level')
1124
+ ret = props.addparam('Floor', 'Color', self._floor_color, Type_Param.Color, 'Floor color')
1125
+
1126
+ ret = props.addparam('Infos', 'Grid', self._show_grid, Type_Param.Logical, 'Show grid')
1127
+ ret = props.addparam('Infos', 'Axis', self._show_axis, Type_Param.Logical, 'Show axis')
1128
+ ret = props.addparam('Infos', 'values', self._show_info, Type_Param.Logical, 'Show info')
1129
+
1130
+ ret = props.addparam('Points', 'Size', self._point_size, Type_Param.Float, 'Point size')
1131
+
1132
+ codes_sel = ''
1133
+ for curcode in self._select_only_codes:
1134
+ codes_sel += str(curcode) + ','
1135
+ ret = props.addparam('Selection', 'Codes', codes_sel, Type_Param.String, 'Codes to select')
1136
+
1137
+ # ret = props.addparam('Auto Update', 'Active', self._auto_update_properties, Type_Param.Logical, 'Auto update properties')
1138
+ # ret = props.addparam('Auto Update', 'Interval', self._auto_update_interval, Type_Param.Integer, 'Auto update interval (ms)')
1139
+
1140
+ props.Populate()
1141
+
1142
+ updatebutton = wx.Button(props, label=_('Update from viewer'))
1143
+ props.sizerbut.Add(updatebutton,1,wx.EXPAND)
1144
+ props.Bind(wx.EVT_BUTTON, self._fill_props, updatebutton)
1145
+
1146
+ getselection = wx.Button(props, label=_('Get selection'))
1147
+ props.sizerbut.Add(getselection,1,wx.EXPAND)
1148
+ props.Bind(wx.EVT_BUTTON, self._get_selection, getselection)
1149
+
1150
+ props.Layout()
1151
+
1152
+ def _get_selection(self, event):
1153
+
1154
+ if self.viewer is None:
1155
+ logging.warning(_('No viewer'))
1156
+ return
1157
+
1158
+ xyz = self.xyz_selected
1159
+
1160
+ if xyz.shape[0]==0:
1161
+ logging.warning(_('No points selected'))
1162
+ return
1163
+
1164
+ if self._xls is None:
1165
+ self._xlsFrame = wx.Frame(None, wx.ID_ANY, _('Selected points - ') + self.idx)
1166
+ self._xls = CpGrid(self._xlsFrame, wx.ID_ANY, style = wx.WANTS_CHARS)
1167
+
1168
+ sizer = wx.BoxSizer(wx.VERTICAL)
1169
+ sizer.Add(self._xls, 1, wx.EXPAND)
1170
+
1171
+ nbclass = len(self.classification.classification)
1172
+ self._xls.CreateGrid(xyz.shape[0] + nbclass +1, 4)
1173
+
1174
+ self._xlsFrame.SetSizer(sizer)
1175
+ self._xlsFrame.Layout()
1176
+ self._xlsFrame.Show()
1177
+
1178
+ else:
1179
+ self._xls.ClearGrid()
1180
+ if self._xls.NumberRows < xyz.shape[0]:
1181
+ self._xls.AppendRows(xyz.shape[0]-self._xls.NumberRows)
1182
+
1183
+ self._xls.SetColLabelValue(0, 'X')
1184
+ self._xls.SetColLabelValue(1, 'Y')
1185
+ self._xls.SetColLabelValue(2, 'Z')
1186
+ self._xls.SetColLabelValue(3, 'Code')
1187
+
1188
+ codes = self.code_selected
1189
+
1190
+ for i in range(xyz.shape[0]):
1191
+ self._xls.SetCellValue(i,0,str(xyz[i,0]))
1192
+ self._xls.SetCellValue(i,1,str(xyz[i,1]))
1193
+ self._xls.SetCellValue(i,2,str(xyz[i,2]))
1194
+ self._xls.SetCellValue(i,3,str(codes[i]))
1195
+
1196
+ # Copy classification under the values
1197
+ for i, (key, val) in enumerate(self.classification.classification.items()):
1198
+ self._xls.SetCellValue(xyz.shape[0]+i+1,0,str(key))
1199
+ self._xls.SetCellValue(xyz.shape[0]+i+1,1,val[0])
1200
+ self._xls.SetCellValue(xyz.shape[0]+i+1,2,val[1])
1201
+ self._xls.SetCellValue(xyz.shape[0]+i+1,3,str(key))
1202
+
1203
+ self._xlsFrame.Show()
1204
+
1205
+ # Mettre la fenêtre au premier plan et centrée
1206
+ self._xlsFrame.Raise()
1207
+ self._xlsFrame.Center()
1208
+
1209
+ def _update_props(self):
1210
+
1211
+ if self._myprops is None:
1212
+ return
1213
+
1214
+ if self.viewer is None:
1215
+ return
1216
+
1217
+ props = self._myprops
1218
+
1219
+ self.lookat = (props[('Look at', 'X')], props[('Look at', 'Y')], props[('Look at', 'Z')])
1220
+ self.eye = (props[('Camera', 'X')], props[('Camera', 'Y')], props[('Camera', 'Z')])
1221
+
1222
+ color = np.asarray(props[('Background', 'Color')])
1223
+ self.bg_color(color / 255.)
1224
+ color = np.asarray(props[('Background', 'Top Color')])
1225
+ self.bg_color_top(color / 255.)
1226
+ color = np.asarray(props[('Background', 'Bottom Color')])
1227
+ self.bg_color_bottom(color / 255.)
1228
+
1229
+ self.floor_level(props[('Floor', 'Level')])
1230
+ color = np.asarray(props[('Floor', 'Color')])
1231
+ self.floor_color(color / 255.)
1232
+
1233
+ self.show_grid(props[('Infos', 'Grid')])
1234
+ self.show_axis(props[('Infos', 'Axis')])
1235
+ self.show_info(props[('Infos', 'values')])
1236
+
1237
+ self.point_size = props[('Points', 'Size')]
1238
+
1239
+ codes_sel = props[('Selection', 'Codes')]
1240
+ codes_sel = codes_sel.split(',')
1241
+ try:
1242
+ self._select_only_codes = list(set([int(curcode) for curcode in codes_sel]))
1243
+ except Exception as e:
1244
+ logging.error(e)
1245
+ logging.warning(_('Nullify selection filter - Check your input'))
1246
+ self._select_only_codes = []
1247
+
1248
+ # self._auto_update_interval = props[('Auto Update', 'Interval')]
1249
+ # self._auto_update_properties = props[('Auto Update', 'Active')]
1250
+
1251
+ # if self._auto_update_properties:
1252
+ # self.SetTimer(self._auto_update_interval)
1253
+ # else:
1254
+ # if self._timer is not None:
1255
+ # self._timer.Stop()
1256
+
1257
+ def _fill_props(self, full:bool = False):
1258
+
1259
+ if self._myprops is None:
1260
+ return
1261
+
1262
+ props = self._myprops
1263
+
1264
+ props[('Look at', 'X')] = self.lookat[0]
1265
+ props[('Look at', 'Y')] = self.lookat[1]
1266
+ props[('Look at', 'Z')] = self.lookat[2]
1267
+
1268
+ props[('Camera', 'X')] = self.eye[0]
1269
+ props[('Camera', 'Y')] = self.eye[1]
1270
+ props[('Camera', 'Z')] = self.eye[2]
1271
+
1272
+ props[('Relative Position', 'Phi')] = self.phi
1273
+ props[('Relative Position', 'Theta')] = self.theta
1274
+ props[('Relative Position', 'R')] = self.r
1275
+
1276
+ if full:
1277
+
1278
+ props[('Background', 'Color')] = self._bg_color
1279
+ props[('Background', 'Top Color')] = self._bg_color_top
1280
+ props[('Background', 'Bottom Color')] = self._bg_color_bottom
1281
+
1282
+ props[('Floor', 'Level')] = self._floor_level
1283
+ props[('Floor', 'Color')] = self._floor_color
1284
+
1285
+ props[('Infos', 'Grid')] = self._show_grid
1286
+ props[('Infos', 'Axis')] = self._show_axis
1287
+ props[('Infos', 'values')] = self._show_info
1288
+
1289
+ props[('Points', 'Size')] = self._point_size
1290
+
1291
+ # props[('Auto Update', 'Interval')] = self._auto_update_interval
1292
+ # props[('Auto Update', 'Active')] = self._auto_update_properties
1293
+
1294
+ props.Populate()
1295
+
1296
+ # def _fill_handler(self, event):
1297
+
1298
+ # if self.viewer is None:
1299
+ # return
1300
+
1301
+ # self._fill_props(full = False)
1302
+
1303
+ # def SetTimer(self, interval:int):
1304
+
1305
+ # if self.viewer is None:
1306
+ # return
1307
+
1308
+ # if self._timer is None:
1309
+ # self._timer = wx.Timer(self._myprops)
1310
+ # self._myprops.Bind(wx.EVT_TIMER, self._fill_handler, self._timer)
1311
+
1312
+ # self._timer.Start(interval)
1313
+
1314
+ def show_properties(self):
1315
+
1316
+ if self.viewer is None:
1317
+ return
1318
+
1319
+ self._create_props()
1320
+ self._myprops.Show()
1321
+
681
1322
  def find_pointsXYZ(xyz:np.ndarray, bounds:Union[tuple[tuple[float,float],tuple[float,float]], list[list[float, float],list[float, float]]]) -> np.ndarray:
682
1323
 
683
1324
  xb=bounds[0]
@@ -1092,7 +1733,7 @@ def myviewer(las:Union[np.ndarray, list[laspy.LasData], laspy.LasData], which_co
1092
1733
 
1093
1734
  colors = get_colors(las, which_colors, fname=fname, palette_classif= palette_classif)
1094
1735
 
1095
- v=viewer(xyz,colors)
1736
+ v = viewer(xyz,colors)
1096
1737
  v.set(point_size=.05)
1097
1738
  return v
1098
1739