wolfhece 2.1.50__py3-none-any.whl → 2.1.56__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/wolf_array.py CHANGED
@@ -40,7 +40,7 @@ import wx
40
40
  from scipy.interpolate import interp2d, griddata
41
41
  from scipy.ndimage import laplace, label, sum_labels
42
42
  import pygltflib
43
- from shapely.geometry import Point, LineString, MultiLineString
43
+ from shapely.geometry import Point, LineString, MultiLineString, Polygon, MultiPolygon, MultiPoint
44
44
  from shapely.ops import linemerge, substring, polygonize_full
45
45
  from os.path import dirname,basename,join
46
46
  import logging
@@ -95,6 +95,39 @@ WOLF_ARRAY_MB = [WOLF_ARRAY_MB_SINGLE, WOLF_ARRAY_MB_INTEGER, WOLF_ARRAY_MNAP_IN
95
95
 
96
96
  VERSION_RGB = 2
97
97
 
98
+ from numba import jit
99
+
100
+ @jit(nopython=True)
101
+ def custom_gradient(array: np.ndarray):
102
+ """ Calculate the gradient manually """
103
+ grad_x = np.zeros_like(array)
104
+ grad_y = np.zeros_like(array)
105
+
106
+ for i in range(1, array.shape[0] - 1):
107
+ for j in range(1, array.shape[1] - 1):
108
+ grad_x[i, j] = (array[i + 1, j] - array[i - 1, j]) / 2.0
109
+ grad_y[i, j] = (array[i, j + 1] - array[i, j - 1]) / 2.0
110
+
111
+ return grad_x, grad_y
112
+
113
+ @jit(nopython=True)
114
+ def hillshade(array:np.ndarray, azimuth:float, angle_altitude:float) -> np.ndarray:
115
+ """ Create a hillshade array """
116
+
117
+ azimuth = 360.0 - azimuth
118
+
119
+ x, y = custom_gradient(array)
120
+ slope = np.pi / 2. - np.arctan(np.sqrt(x * x + y * y))
121
+ aspect = np.arctan2(-x, y)
122
+ azimuthrad = azimuth * np.pi / 180.
123
+ altituderad = angle_altitude * np.pi / 180.
124
+
125
+ shaded = np.sin(altituderad) * np.sin(slope) + np.cos(altituderad) * \
126
+ np.cos(slope) * np.cos((azimuthrad - np.pi / 2.) - aspect)
127
+ shaded += 1.
128
+ shaded *= .5
129
+
130
+ return shaded.astype(np.float32)
98
131
  class Rebin_Ops(Enum):
99
132
  MIN = 0
100
133
  MEAN = 1
@@ -1104,7 +1137,7 @@ class header_wolf():
1104
1137
 
1105
1138
  return newvector
1106
1139
 
1107
- def get_xy_infootprint_vect(self, myvect: vector, eps:float = 0.) -> tuple[np.ndarray,np.ndarray]:
1140
+ def get_xy_infootprint_vect(self, myvect: vector | Polygon, eps:float = 0.) -> tuple[np.ndarray,np.ndarray]:
1108
1141
  """
1109
1142
  Return the coordinates of the cells in the footprint of a vector
1110
1143
 
@@ -1121,7 +1154,7 @@ class header_wolf():
1121
1154
 
1122
1155
  return mypts,myptsij
1123
1156
 
1124
- def get_ij_infootprint_vect(self, myvect: vector, eps:float = 0.) -> np.ndarray:
1157
+ def get_ij_infootprint_vect(self, myvect: vector | Polygon, eps:float = 0.) -> np.ndarray:
1125
1158
  """
1126
1159
  Return the indices of the cells in the footprint of a vector
1127
1160
 
@@ -1129,8 +1162,16 @@ class header_wolf():
1129
1162
  :return : numpy array of indices
1130
1163
  """
1131
1164
 
1132
- i1, j1 = self.get_ij_from_xy(myvect.xmin+eps, myvect.ymin+eps)
1133
- i2, j2 = self.get_ij_from_xy(myvect.xmax-eps, myvect.ymax-eps)
1165
+ if isinstance(myvect, Polygon):
1166
+ xmin, ymin, xmax, ymax = myvect.bounds
1167
+ elif isinstance(myvect, vector):
1168
+ xmin, ymin, xmax, ymax = myvect.xmin, myvect.ymin, myvect.xmax, myvect.ymax
1169
+ else:
1170
+ logging.error(_('The object must be a vector or a Polygon'))
1171
+ return np.array([])
1172
+
1173
+ i1, j1 = self.get_ij_from_xy(xmin+eps, ymin+eps)
1174
+ i2, j2 = self.get_ij_from_xy(xmax-eps, ymax-eps)
1134
1175
 
1135
1176
  i1 = max(i1,0) # FIXME Why ??? How could i,j be negative ? --> because this fucntion can be called with a vector that is not in the array (e.g. a vector defined by clicks in the UI)
1136
1177
  j1 = max(j1,0)
@@ -1379,6 +1420,11 @@ class Ops_Array(wx.Frame):
1379
1420
  if self.wx_exists:
1380
1421
  self.set_GUI()
1381
1422
 
1423
+ @property
1424
+ def idx(self):
1425
+ """ Return the idx of the parentarray """
1426
+ return self.parentarray.idx
1427
+
1382
1428
  def get_mapviewer(self):
1383
1429
  """ Retourne l'instance WolfMapViewer """
1384
1430
  return self.mapviewer
@@ -1488,7 +1534,7 @@ class Ops_Array(wx.Frame):
1488
1534
 
1489
1535
  self.palimage = wx.Button(self.Palette, wx.ID_ANY, _("Create image"), wx.DefaultPosition, wx.DefaultSize, 0)
1490
1536
  self.palimage.SetToolTip(_('Generate colormap image (horizontal, vertical or both) and save to disk'))
1491
- self.paldistribute = wx.Button(self.Palette, wx.ID_ANY, _("Distribute"), wx.DefaultPosition, wx.DefaultSize, 0)
1537
+ self.paldistribute = wx.Button(self.Palette, wx.ID_ANY, _("Evenly spaced"), wx.DefaultPosition, wx.DefaultSize, 0)
1492
1538
  self.paldistribute.SetToolTip(_('Set colormap values based on minimum+maximum or minimum+step'))
1493
1539
  if self.parentarray.mypal.automatic:
1494
1540
  self.palauto.SetValue(1)
@@ -2397,6 +2443,7 @@ class Ops_Array(wx.Frame):
2397
2443
  if self.mapviewer is not None:
2398
2444
  self.mapviewer.start_action('select node by node', _('Please click on the desired nodes...'))
2399
2445
  self.mapviewer.active_array = self.parentarray
2446
+ self.mapviewer.set_label_selecteditem(self.parentarray.idx)
2400
2447
 
2401
2448
  def select_zone_inside_manager(self):
2402
2449
  """
@@ -2439,6 +2486,7 @@ class Ops_Array(wx.Frame):
2439
2486
 
2440
2487
  self.mapviewer.start_action('select by vector inside', _('Please draw a polygon...'))
2441
2488
  self.mapviewer.active_array = self.parentarray
2489
+ self.mapviewer.set_label_selecteditem(self.parentarray.idx)
2442
2490
  self.Active_vector(vect)
2443
2491
 
2444
2492
  firstvert = wolfvertex(0., 0.)
@@ -2477,6 +2525,7 @@ class Ops_Array(wx.Frame):
2477
2525
 
2478
2526
  self.mapviewer.start_action('select by vector along', _('Please draw a polyline...'))
2479
2527
  self.mapviewer.active_array = self.parentarray
2528
+ self.mapviewer.set_label_selecteditem(self.parentarray.idx)
2480
2529
  self.Active_vector(vect)
2481
2530
 
2482
2531
  firstvert = wolfvertex(0., 0.)
@@ -2492,6 +2541,7 @@ class Ops_Array(wx.Frame):
2492
2541
  self.vectmp.reset()
2493
2542
  self.Active_vector(self.vectmp)
2494
2543
  self.mapviewer.active_array = self.parentarray
2544
+ self.mapviewer.set_label_selecteditem(self.parentarray.idx)
2495
2545
 
2496
2546
  firstvert = wolfvertex(0., 0.)
2497
2547
  self.vectmp.add_vertex(firstvert)
@@ -2506,6 +2556,7 @@ class Ops_Array(wx.Frame):
2506
2556
  self.vectmp.reset()
2507
2557
  self.Active_vector(self.vectmp)
2508
2558
  self.mapviewer.active_array = self.parentarray
2559
+ self.mapviewer.set_label_selecteditem(self.parentarray.idx)
2509
2560
 
2510
2561
  firstvert = wolfvertex(0., 0.)
2511
2562
  self.vectmp.add_vertex(firstvert)
@@ -2648,7 +2699,8 @@ class Ops_Array(wx.Frame):
2648
2699
  myarray.mypal.export_image()
2649
2700
 
2650
2701
  def Onpaldistribute(self, event:wx.MouseEvent):
2651
- """ Distribute values in palette """
2702
+ """ Evenly spaced values in palette """
2703
+
2652
2704
  myarray: WolfArray
2653
2705
  myarray = self.parentarray
2654
2706
  myarray.mypal.distribute_values()
@@ -2698,9 +2750,13 @@ class Ops_Array(wx.Frame):
2698
2750
  curarray.shading = True
2699
2751
 
2700
2752
  alpha = float(self.palalphahillshade.GetValue()) / 100.
2701
- if curarray.shaded.alpha != alpha:
2702
- curarray.shaded.alpha = alpha
2703
- curarray.shading = True
2753
+
2754
+ if curarray.shaded is None:
2755
+ logging.error('No shaded array')
2756
+ else:
2757
+ if curarray.shaded.alpha != alpha:
2758
+ curarray.shaded.alpha = alpha
2759
+ curarray.shading = True
2704
2760
 
2705
2761
  if dellists:
2706
2762
  self.refresh_array()
@@ -4410,6 +4466,25 @@ class WolfArray(Element_To_Draw, header_wolf):
4410
4466
 
4411
4467
  self.add_ops_sel() # Ajout d'un gestionnaire de sélection et d'opérations
4412
4468
 
4469
+ def set_opacity(self, alpha:float):
4470
+ """ Set the transparency of the array """
4471
+
4472
+ if alpha <0.:
4473
+ alpha = 0.
4474
+
4475
+ if alpha > 1.:
4476
+ alpha = 1.
4477
+
4478
+ self.alpha = alpha
4479
+
4480
+ if self.myops is not None:
4481
+ self.myops.palalpha.SetValue(0)
4482
+ self.myops.palalphaslider.SetValue(int(alpha*100))
4483
+
4484
+ self.reset_plot()
4485
+
4486
+ return self.alpha
4487
+
4413
4488
  @property
4414
4489
  def memory_usage(self):
4415
4490
  """
@@ -4552,6 +4627,10 @@ class WolfArray(Element_To_Draw, header_wolf):
4552
4627
  """ Affichage des propriétés de la matrice dans une fenêtre wxPython """
4553
4628
  if self.wx_exists and self.myops is not None:
4554
4629
  self.myops.SetTitle(_('Operations on array: ') + self.idx)
4630
+
4631
+ if self.mapviewer is not None:
4632
+ self.myops.SetIcon(self.mapviewer.GetIcon())
4633
+
4555
4634
  self.myops.Show()
4556
4635
 
4557
4636
  self.myops.Center()
@@ -4566,7 +4645,6 @@ class WolfArray(Element_To_Draw, header_wolf):
4566
4645
  @property
4567
4646
  def nullvalue(self) -> float:
4568
4647
  """ Return the null value """
4569
-
4570
4648
  return self._nullvalue
4571
4649
 
4572
4650
  @nullvalue.setter
@@ -4575,6 +4653,16 @@ class WolfArray(Element_To_Draw, header_wolf):
4575
4653
 
4576
4654
  self._nullvalue = value
4577
4655
 
4656
+ @property
4657
+ def nodata(self) -> float:
4658
+ """ alias for nullvalue """
4659
+ return self._nullvalue
4660
+
4661
+ @nodata.setter
4662
+ def nodata(self, value:float):
4663
+ """ alias for nullvalue """
4664
+ self._nullvalue = value
4665
+
4578
4666
  @property
4579
4667
  def SelectionData(self) -> SelectionData:
4580
4668
  """ Return the data of the selection """
@@ -5757,23 +5845,14 @@ class WolfArray(Element_To_Draw, header_wolf):
5757
5845
  return mytri, znull
5758
5846
 
5759
5847
  def hillshade(self, azimuth:float, angle_altitude:float):
5760
- """ Create a hillshade array """
5848
+ """ Create a hillshade array -- see "hillshade" function accelerated by JIT"""
5761
5849
 
5762
- azimuth = 360.0 - azimuth
5763
-
5764
- x, y = np.gradient(self.array)
5765
- slope = np.pi / 2. - np.arctan(np.sqrt(x * x + y * y))
5766
- aspect = np.arctan2(-x, y)
5767
- azimuthrad = azimuth * np.pi / 180.
5768
- altituderad = angle_altitude * np.pi / 180.
5769
-
5770
- shaded = np.sin(altituderad) * np.sin(slope) + np.cos(altituderad) * np.cos(slope) * np.cos(
5771
- (azimuthrad - np.pi / 2.) - aspect)
5772
- shaded += 1.
5773
- shaded *= .5
5850
+ if self.shaded is None:
5851
+ logging.error(_('No shaded array'))
5852
+ return
5774
5853
 
5775
5854
  self.shaded.set_header(self.get_header())
5776
- self.shaded.array = shaded
5855
+ self.shaded.array = hillshade(self.array.data, azimuth, angle_altitude)
5777
5856
  self.shaded.delete_lists()
5778
5857
 
5779
5858
  def get_gradient_norm(self):
@@ -6544,7 +6623,7 @@ class WolfArray(Element_To_Draw, header_wolf):
6544
6623
  # These functions can not be stored in header_wolf, because wa can use the mask of the array to limit the search
6545
6624
  # These functions are also present in WolfResults_2D, but they are not exactly the same due to the structure of the results
6546
6625
  # *************************************************************************************************************************
6547
- def get_xy_inside_polygon(self, myvect: vector, usemask:bool=True):
6626
+ def get_xy_inside_polygon(self, myvect: vector | Polygon, usemask:bool=True):
6548
6627
  """
6549
6628
  Return the coordinates inside a polygon
6550
6629
 
@@ -6552,9 +6631,15 @@ class WolfArray(Element_To_Draw, header_wolf):
6552
6631
  :param usemask : limit potential nodes to unmaksed nodes
6553
6632
  """
6554
6633
 
6555
- myvect.find_minmax()
6634
+ if isinstance(myvect, vector):
6635
+ # force la mise à jour des min/max
6636
+ myvect.find_minmax()
6637
+ # Conversion des coordonnées en numpy pour plus d'efficacité (du moins on espère)
6638
+ myvert = myvect.asnparray()
6639
+ elif isinstance(myvect, Polygon):
6640
+ myvert = myvect.exterior.coords[:-1]
6641
+
6556
6642
  mypointsxy, mypointsij = self.get_xy_infootprint_vect(myvect)
6557
- myvert = myvect.asnparray()
6558
6643
  path = mpltPath.Path(myvert)
6559
6644
  inside = path.contains_points(mypointsxy)
6560
6645
 
@@ -6567,6 +6652,34 @@ class WolfArray(Element_To_Draw, header_wolf):
6567
6652
 
6568
6653
  return mypointsxy
6569
6654
 
6655
+ def get_xy_inside_polygon_shapely(self, myvect: vector | Polygon, usemask:bool=True):
6656
+ """
6657
+ Return the coordinates inside a polygon
6658
+
6659
+ :param myvect : target vector
6660
+ :param usemask : limit potential nodes to unmaksed nodes
6661
+ """
6662
+
6663
+ if isinstance(myvect, vector):
6664
+ # force la mise à jour des min/max
6665
+ myvect.find_minmax()
6666
+ polygon = myvect.asshapely_pol()
6667
+ elif isinstance(myvect, Polygon):
6668
+ polygon = myvect
6669
+
6670
+ mypointsxy, mypointsij = self.get_xy_infootprint_vect(myvect)
6671
+
6672
+ inside = np.asarray([polygon.contains(Point(x,y)) for x,y in mypointsxy])
6673
+
6674
+ mypointsxy = mypointsxy[np.where(inside)]
6675
+
6676
+ if usemask:
6677
+ mypointsij = mypointsij[np.where(inside)]
6678
+ mymask = np.logical_not(self.array.mask[mypointsij[:, 0], mypointsij[:, 1]])
6679
+ mypointsxy = mypointsxy[np.where(mymask)]
6680
+
6681
+ return mypointsxy
6682
+
6570
6683
  def get_xy_under_polyline(self, myvect: vector, usemask:bool=True):
6571
6684
  """
6572
6685
  Return the coordinates along a polyline
@@ -6607,6 +6720,23 @@ class WolfArray(Element_To_Draw, header_wolf):
6607
6720
 
6608
6721
  return mypointsij
6609
6722
 
6723
+ def intersects_polygon(self, myvect: vector | Polygon, usemask:bool=True):
6724
+ """ Return True if the array intersects the polygon
6725
+
6726
+ :param myvect : target vector
6727
+ :param usemask : limit potential nodes to unmaksed nodes
6728
+ """
6729
+
6730
+ return self.get_xy_inside_polygon(myvect, usemask).shape[0] > 0
6731
+
6732
+ def intersects_polygon_shapely(self, myvect: vector | Polygon, eps:float = 0., usemask:bool=True):
6733
+ """ Return True if the array intersects the polygon
6734
+
6735
+ :param myvect : target vector
6736
+ :param usemask : limit potential nodes to unmaksed nodes
6737
+ """
6738
+ return self.get_xy_inside_polygon_shapely(myvect, usemask).shape[0] > 0
6739
+
6610
6740
  def get_ij_under_polyline(self, myvect: vector, usemask:bool=True):
6611
6741
  """
6612
6742
  Return the indices along a polyline
@@ -6968,6 +7098,8 @@ class WolfArray(Element_To_Draw, header_wolf):
6968
7098
  else:
6969
7099
  self.array = np.kron(self.array, np.ones((int(1/factor), int(1/factor)), dtype=self.array.dtype))
6970
7100
 
7101
+ self.mask_data(self.nullvalue)
7102
+
6971
7103
  self.count()
6972
7104
 
6973
7105
  # rebin must not change the type of the array
@@ -7185,6 +7317,29 @@ class WolfArray(Element_To_Draw, header_wolf):
7185
7317
  else:
7186
7318
  logging.warning(_('Type not supported : ')+str(self.dtype))
7187
7319
 
7320
+ def fillin_from_ijz(self, ijz:np.ndarray):
7321
+ """ Remplissage du tableau à partir d'un tableau ijz """
7322
+
7323
+ try:
7324
+ i = ijz[:, 0].astype(int)
7325
+ j = ijz[:, 1].astype(int)
7326
+ except Exception as e:
7327
+ logging.error(_('Error in conversion of ijz to int : ')+str(e))
7328
+ return
7329
+
7330
+ if self.dtype == np.float32:
7331
+ self.array.data[i, j] = np.float32(ijz[:, 2])
7332
+ elif self.dtype == np.float64:
7333
+ self.array.data[i, j] = np.float64(ijz[:, 2])
7334
+ elif self.dtype == np.int32:
7335
+ self.array.data[i, j] = np.int32(ijz[:, 2])
7336
+ elif self.dtype == np.int16:
7337
+ self.array.data[i, j] = np.int16(ijz[:, 2])
7338
+ elif self.dtype == np.int8:
7339
+ self.array.data[i, j] = np.int8(ijz[:, 2])
7340
+ else:
7341
+ logging.warning(_('Type not supported : ')+str(self.dtype))
7342
+
7188
7343
  def mask_force_null(self):
7189
7344
  """
7190
7345
  Force to unmask all and mask null value
@@ -7616,20 +7771,22 @@ class WolfArray(Element_To_Draw, header_wolf):
7616
7771
  WOLF_ARRAY_FULL_INTEGER16,
7617
7772
  WOLF_ARRAY_FULL_INTEGER16_2,
7618
7773
  WOLF_ARRAY_FULL_INTEGER,
7619
- WOLF_ARRAY_FULL_DOUBLE]:
7774
+ WOLF_ARRAY_FULL_DOUBLE,
7775
+ WOLF_ARRAY_HILLSHAPE]:
7620
7776
  # FIXME: Currently, only some types are supported in Cython/OpenGL library
7621
7777
  self._tmp_float32 = self.array.astype(dtype=np.float32)
7622
7778
  else:
7623
7779
  self._tmp_float32 = None
7624
7780
 
7625
7781
 
7626
- # if self.shading:
7627
- # pond = (self.shaded.array-.5)*2.
7628
- # pmin = (1. - self.shaded.alpha) * self.rgb
7629
- # pmax = self.shaded.alpha * np.ones(self.rgb.shape) + (1. - self.shaded.alpha) * self.rgb
7630
- # for i in range(4):
7631
- # self.rgb[pond<0,i] = self.rgb[pond<0,i] * (1.+pond[pond<0]) - pmin[pond<0,i] * pond[pond<0]
7632
- # self.rgb[pond>0,i] = self.rgb[pond>0,i] * (1.-pond[pond>0]) + pmax[pond>0,i] * pond[pond>0]
7782
+ if VERSION_RGB==1 :
7783
+ if self.shading:
7784
+ pond = (self.shaded.array-.5)*2.
7785
+ pmin = (1. - self.shaded.alpha) * self.rgb
7786
+ pmax = self.shaded.alpha * np.ones(self.rgb.shape) + (1. - self.shaded.alpha) * self.rgb
7787
+ for i in range(4):
7788
+ self.rgb[pond<0,i] = self.rgb[pond<0,i] * (1.+pond[pond<0]) - pmin[pond<0,i] * pond[pond<0]
7789
+ self.rgb[pond>0,i] = self.rgb[pond>0,i] * (1.-pond[pond>0]) + pmax[pond>0,i] * pond[pond>0]
7633
7790
 
7634
7791
  if VERSION_RGB==1 : self.rgb[self.array.mask] = [1., 1., 1., 0.]
7635
7792
 
@@ -7719,11 +7876,15 @@ class WolfArray(Element_To_Draw, header_wolf):
7719
7876
 
7720
7877
  if self.wolftype != WOLF_ARRAY_HILLSHAPE and self.shading:
7721
7878
  self.hillshade(self.azimuthhill, self.altitudehill)
7722
- self.updatepalette(0)
7723
- self.shaded.updatepalette(0)
7879
+
7880
+ if VERSION_RGB==1 :
7881
+ self.updatepalette(0)
7882
+ self.shaded.updatepalette(0)
7883
+
7724
7884
  self.shading=False
7725
7885
  if self.mapviewer is not None:
7726
- if not self.idx + '_hillshade' in self.mapviewer.get_list_keys(self.mapviewer.ARRAYS, False) :# .added['arrays'].keys():
7886
+ from .PyDraw import draw_type
7887
+ if not self.idx + '_hillshade' in self.mapviewer.get_list_keys(drawing_type=draw_type.ARRAYS, checked_state= None) :# .added['arrays'].keys():
7727
7888
  self.mapviewer.add_object('array', newobj=self.shaded, ToCheck=True, id=self.idx + '_hillshade')
7728
7889
 
7729
7890
  try:
@@ -7739,12 +7900,14 @@ class WolfArray(Element_To_Draw, header_wolf):
7739
7900
  mylist = self.mygrid[cursize]['mylists'][i, j]
7740
7901
  if mylist > 0:
7741
7902
  glCallList(self.mygrid[cursize]['mylists'][i, j])
7742
- except:
7743
- pass
7903
+ except Exception as e:
7904
+ logging.error(_('OpenGL error in WolfArray.plot 1 -- Please report this case with the data file and the context in which the error occured'))
7905
+ logging.error(e)
7744
7906
 
7745
7907
  glDisable(GL_BLEND)
7746
- except:
7747
- logging.error(_('OpenGL error in WolfArray.plot -- Please report this case with the data file and the context in which the error occured'))
7908
+ except Exception as e:
7909
+ logging.error(_('OpenGL error in WolfArray.plot 2 -- Please report this case with the data file and the context in which the error occured'))
7910
+ logging.error(e)
7748
7911
 
7749
7912
  self.plotting = False
7750
7913
 
@@ -7793,9 +7956,7 @@ class WolfArray(Element_To_Draw, header_wolf):
7793
7956
  def fillonecellgrid(self, curscale, loci, locj, force=False):
7794
7957
  """ Fill one cell of the plotted grid """
7795
7958
 
7796
-
7797
-
7798
- cursize = curscale # 2**curscale
7959
+ cursize = curscale
7799
7960
 
7800
7961
  if not cursize in self.mygrid.keys():
7801
7962
  return
@@ -7875,22 +8036,28 @@ class WolfArray(Element_To_Draw, header_wolf):
7875
8036
  elif self.nbnotnull > 0:
7876
8037
  wolfogl.addmeall_double_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
7877
8038
  jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
7878
- elif self.wolftype != WOLF_ARRAY_FULL_SINGLE:
8039
+ elif self.wolftype not in [WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_HILLSHAPE]:
7879
8040
  if self.nbnotnull != self.nbx * self.nby:
7880
8041
  if self.nbnotnull > 0:
7881
8042
  wolfogl.addme_pal(self._tmp_float32, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
7882
- jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8043
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst), -1.)
7883
8044
  elif self.nbnotnull > 0:
7884
8045
  wolfogl.addmeall_pal(self._tmp_float32, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
7885
- jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8046
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst), -1.)
7886
8047
  else:
8048
+ clr_float = self.mypal.colorsflt.copy()
8049
+ clr_float[:,3] = self.alpha
8050
+ if '_hillshade' in self.idx:
8051
+ clr_float[1,3] = 0.
8052
+
7887
8053
  if self.nbnotnull != self.nbx * self.nby:
7888
8054
  if self.nbnotnull > 0:
7889
- wolfogl.addme_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart, jend, istart, iend, cursize,
7890
- self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8055
+
8056
+ wolfogl.addme_pal(self.array, clr_float, self.mypal.values, ox, oy, dx, dy, jstart, jend, istart, iend, cursize,
8057
+ self.nullvalue, self.alpha, int(self.mypal.interval_cst), -1.)
7891
8058
  elif self.nbnotnull > 0:
7892
- wolfogl.addmeall_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart, jend, istart, iend, cursize,
7893
- self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8059
+ wolfogl.addmeall_pal(self.array, clr_float, self.mypal.values, ox, oy, dx, dy, jstart, jend, istart, iend, cursize,
8060
+ self.nullvalue, self.alpha, int(self.mypal.interval_cst), -1.)
7894
8061
 
7895
8062
  except Exception as e:
7896
8063
  logging.error(repr(e))
@@ -243,8 +243,13 @@ class Props_Res_2D(wx.Frame):
243
243
 
244
244
  self._cm_save = wx.Button(self._panel_colormap, wx.ID_ANY, _("Save to file"), wx.DefaultPosition, wx.DefaultSize, 0)
245
245
  self._cm_save.SetToolTip(_('Save colormap on .pal file'))
246
+
246
247
  self._cm_load = wx.Button(self._panel_colormap, wx.ID_ANY, _("Load from file"), wx.DefaultPosition, wx.DefaultSize, 0)
247
248
  self._cm_load.SetToolTip(_('Load colormap from .pal file'))
249
+
250
+ self._cm_default_pal = wx.Button(self._panel_colormap, wx.ID_ANY, _("Load precomputed"), wx.DefaultPosition, wx.DefaultSize, 0)
251
+ self._cm_default_pal.SetToolTip(_('Load a default colormap available in the software'))
252
+
248
253
  self._cm_toimage = wx.Button(self._panel_colormap, wx.ID_ANY, _("Create image"), wx.DefaultPosition, wx.DefaultSize, 0)
249
254
  self._cm_toimage.SetToolTip(_('Generate colormap image (horizontal, vertical or both) and save to disk'))
250
255
  self._cm_distribute = wx.Button(self._panel_colormap, wx.ID_ANY, _("Distribute"), wx.DefaultPosition, wx.DefaultSize, 0)
@@ -296,7 +301,14 @@ class Props_Res_2D(wx.Frame):
296
301
 
297
302
  self._panel_colormap.sizer.Add(self._cm_choose_color, 1, wx.EXPAND)
298
303
  self._panel_colormap.sizer.Add(self._cm_apply, 1, wx.EXPAND)
299
- self._panel_colormap.sizer.Add(self._cm_load, 1, wx.EXPAND)
304
+
305
+ sizer_loadpal = wx.BoxSizer(wx.HORIZONTAL)
306
+
307
+ self._panel_colormap.sizer.Add(sizer_loadpal, 1, wx.EXPAND)
308
+
309
+ sizer_loadpal.Add(self._cm_load, 1, wx.EXPAND)
310
+ sizer_loadpal.Add(self._cm_default_pal, 1, wx.EXPAND)
311
+
300
312
  self._panel_colormap.sizer.Add(self._cm_save, 1, wx.EXPAND)
301
313
  self._panel_colormap.sizer.Add(self._cm_toimage, 1, wx.EXPAND)
302
314
  self._panel_colormap.sizer.Add(self._cm_distribute, 1 , wx.EXPAND)
@@ -636,7 +648,10 @@ class Props_Res_2D(wx.Frame):
636
648
  self._Apply_Tools.Bind(wx.EVT_BUTTON, self.OnApplyTools)
637
649
  self._cm_apply.Bind(wx.EVT_BUTTON, self.Onupdatepal)
638
650
  self._cm_save.Bind(wx.EVT_BUTTON, self.Onsavepal)
651
+
639
652
  self._cm_load.Bind(wx.EVT_BUTTON, self.Onloadpal)
653
+ self._cm_default_pal.Bind(wx.EVT_BUTTON, self.Onloaddefaultpal)
654
+
640
655
  self._cm_toimage.Bind(wx.EVT_BUTTON, self.Onpalimage)
641
656
  self._cm_distribute.Bind(wx.EVT_BUTTON, self.Onpaldistribute)
642
657
  self._cm_choose_color.Bind(wx.EVT_BUTTON, self.OnClickColorPal)
@@ -712,7 +727,7 @@ class Props_Res_2D(wx.Frame):
712
727
  # Fill the grid
713
728
  self._parent.mypal.fillgrid(self._cm_grid)
714
729
 
715
- def Onsavepal(self, event):
730
+ def Onsavepal(self, event:wx.MouseEvent):
716
731
  """ Save the colormap to a file """
717
732
 
718
733
  self._parent.mypal.savefile()
@@ -728,6 +743,38 @@ class Props_Res_2D(wx.Frame):
728
743
  self._parent.set_currentview()
729
744
  self.update_palette()
730
745
 
746
+ def Onloaddefaultpal(self, event:wx.MouseEvent):
747
+ """ Load default palette """
748
+
749
+ import glob
750
+ from pathlib import Path
751
+
752
+ # list of all .pal file in model directory
753
+
754
+ dirpal = Path(__file__).parent / 'models'
755
+
756
+ listpal = glob.glob(str(dirpal) + '/*.pal')
757
+
758
+ if len(listpal) == 0:
759
+ logging.info('No default palette found')
760
+ return
761
+
762
+ listpal = [Path(i).name for i in listpal]
763
+
764
+ dlg = wx.SingleChoiceDialog(None, 'Choose the default palette', 'Default palette', listpal)
765
+ ret = dlg.ShowModal()
766
+
767
+ if ret == wx.ID_CANCEL:
768
+ dlg.Destroy()
769
+
770
+ self._parent.mypal.readfile(str(dirpal / dlg.GetStringSelection()))
771
+
772
+ self._parent.mypal.automatic = False
773
+ self._cm_auto.SetValue(0)
774
+ self.update_palette()
775
+
776
+ self._parent.set_currentview()
777
+
731
778
  def Onpalimage(self, event):
732
779
  """ Export the colormap to an image """
733
780
 
@@ -1722,6 +1769,18 @@ class OneWolfResult:
1722
1769
 
1723
1770
  self.mngselection = SelectionData(self._current)
1724
1771
 
1772
+ def set_opacity(self, alpha:float):
1773
+ """ Set the transparency of the array """
1774
+
1775
+ if alpha <0.:
1776
+ alpha = 0.
1777
+
1778
+ if alpha > 1.:
1779
+ alpha = 1.
1780
+
1781
+ self.alpha = alpha
1782
+
1783
+ return self.alpha
1725
1784
 
1726
1785
  @property
1727
1786
  def min_field_size(self):
@@ -2185,6 +2244,16 @@ class Wolfresults_2D(Element_To_Draw):
2185
2244
  self.myops = None
2186
2245
  self._active_blocks = 0
2187
2246
 
2247
+
2248
+ def set_opacity(self, alpha:float):
2249
+ """ Set the transparency of the array """
2250
+
2251
+ self.alpha = alpha
2252
+
2253
+ self.reset_plot()
2254
+
2255
+ return self.alpha
2256
+
2188
2257
  @property
2189
2258
  def SelectionData(self) -> SelectionDataMB:
2190
2259
  """ Return the data of the selection """
@@ -2352,6 +2421,13 @@ class Wolfresults_2D(Element_To_Draw):
2352
2421
 
2353
2422
  @alpha.setter
2354
2423
  def alpha(self, value:float):
2424
+
2425
+ if value <0.:
2426
+ value = 0.
2427
+
2428
+ if value > 1.:
2429
+ value = 1.
2430
+
2355
2431
  for i in range(self.nb_blocks):
2356
2432
  self[i].alpha = value
2357
2433
 
@@ -4137,6 +4213,7 @@ class Wolfresults_2D(Element_To_Draw):
4137
4213
 
4138
4214
  def reset_plot(self,whichpal=0):
4139
4215
  """Reset du dessin"""
4216
+
4140
4217
  self.delete_lists()
4141
4218
  self.get_working_array()
4142
4219
  self.updatepalette(whichpal)