wolfhece 2.1.99__py3-none-any.whl → 2.1.101__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.
Files changed (35) hide show
  1. wolfhece/PyDraw.py +220 -29
  2. wolfhece/PyGui.py +1039 -53
  3. wolfhece/PyVertexvectors.py +2 -2
  4. wolfhece/Results2DGPU.py +37 -13
  5. wolfhece/acceptability/Parallels.py +2 -2
  6. wolfhece/acceptability/_add_path.py +23 -0
  7. wolfhece/acceptability/acceptability.py +594 -563
  8. wolfhece/acceptability/acceptability_gui.py +564 -331
  9. wolfhece/acceptability/cli.py +307 -120
  10. wolfhece/acceptability/func.py +1754 -1597
  11. wolfhece/apps/version.py +1 -1
  12. wolfhece/bernoulli/losses.py +76 -23
  13. wolfhece/bernoulli/losses_jax.py +143 -0
  14. wolfhece/bernoulli/pipe.py +7 -2
  15. wolfhece/gpuview.py +4 -1
  16. wolfhece/libs/__init__.py +11 -10
  17. wolfhece/libs/wolfogl.cp310-win_amd64.pyd +0 -0
  18. wolfhece/math_parser/__init__.py +4 -4
  19. wolfhece/math_parser/calculator.py +51 -9
  20. wolfhece/mesh2d/bc_manager.py +25 -2
  21. wolfhece/mesh2d/gpu_2d.py +644 -0
  22. wolfhece/mesh2d/simple_2d.py +2817 -0
  23. wolfhece/mesh2d/wolf2dprev.py +5 -2
  24. wolfhece/pidcontroller.py +131 -0
  25. wolfhece/pywalous.py +7 -7
  26. wolfhece/scenario/config_manager.py +98 -21
  27. wolfhece/wolf_array.py +391 -176
  28. wolfhece/wolf_vrt.py +108 -7
  29. wolfhece/wolfresults_2D.py +113 -6
  30. wolfhece/xyz_file.py +91 -51
  31. {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/METADATA +3 -1
  32. {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/RECORD +35 -30
  33. {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/WHEEL +1 -1
  34. {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/entry_points.txt +0 -0
  35. {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/top_level.txt +0 -0
wolfhece/wolf_array.py CHANGED
@@ -22,6 +22,7 @@ import logging
22
22
  import json
23
23
  import tempfile
24
24
  from pathlib import Path
25
+ from tqdm import tqdm
25
26
 
26
27
  try:
27
28
  from OpenGL.GL import *
@@ -115,6 +116,7 @@ WOLF_ARRAY_CSR_DOUBLE = 5
115
116
  WOLF_ARRAY_FULL_INTEGER = 6
116
117
  WOLF_ARRAY_FULL_SINGLE_3D = 7
117
118
  WOLF_ARRAY_FULL_INTEGER8 = 8
119
+ WOLF_ARRAY_FULL_UINTEGER8 = 88
118
120
 
119
121
  WOLF_ARRAY_MB_SINGLE = 3
120
122
  WOLF_ARRAY_MB_INTEGER = 9
@@ -277,7 +279,7 @@ class header_wolf():
277
279
  ret += _('Spatial extent : \n')
278
280
  ret += _(' - Origin : ({} ; {}) \n').format(self.origx, self.origy)
279
281
  ret += _(' - End : ({} ; {}) \n').format(self.origx + self.nbx * self.dx, self.origy +self.nby * self.dy)
280
- ret += _(' - Widht x Height : {} x {} \n').format(self.nbx * self.dx, self.nby * self.dy)
282
+ ret += _(' - Width x Height : {} x {} \n').format(self.nbx * self.dx, self.nby * self.dy)
281
283
  ret += _(' - Translation : ({} ; {})\n').format(self.translx, self.transly)
282
284
  ret += _('Null value : {}\n\n'.format(self.nullvalue))
283
285
 
@@ -344,8 +346,8 @@ class header_wolf():
344
346
  """
345
347
  Return block header
346
348
 
347
- :param key:int = block's index (0-based) or key (str)
348
- :return : header_wolf instance if key is found, None otherwise
349
+ :param key: block's index (0-based) or key (str)
350
+ :return: header_wolf instance if key is found, None otherwise
349
351
  """
350
352
  if key is None:
351
353
  return self
@@ -364,7 +366,7 @@ class header_wolf():
364
366
  """
365
367
  Set block header
366
368
 
367
- :param value = tuple (key, header_wolf)
369
+ :param value: tuple (key, header_wolf)
368
370
 
369
371
  'key' can be an int (0-based) or a str
370
372
  If str, please use getkeyblock function to generate the key
@@ -381,9 +383,9 @@ class header_wolf():
381
383
  """
382
384
  Set origin
383
385
 
384
- :param x = origin along X
385
- :param y = origin along Y
386
- :param z = origin along Z
386
+ :param x: origin along X
387
+ :param y: origin along Y
388
+ :param z: origin along Z
387
389
  """
388
390
  self.origx = x
389
391
  self.origy = y
@@ -405,8 +407,8 @@ class header_wolf():
405
407
  """
406
408
  Return bounds in coordinates
407
409
 
408
- :param abs = if True, add translation to (x, y) (coordinate to global space)
409
- :return : tuple of two lists of two floats - ([xmin, xmax],[ymin, ymax])
410
+ :param abs: if True, add translation to (x, y) (coordinate to global space)
411
+ :return: tuple of two lists of two floats - ([xmin, xmax],[ymin, ymax])
410
412
  """
411
413
  if abs:
412
414
  return ([self.origx + self.translx, self.origx + self.translx + float(self.nbx) * self.dx],
@@ -421,7 +423,7 @@ class header_wolf():
421
423
 
422
424
  Firstly, get_bounds is called to get bounds in coordinates and then get_ij_from_xy is called to get bounds in indices.
423
425
 
424
- :param abs = if True, add translation to (x, y) (coordinate to global space)
426
+ :param abs: if True, add translation to (x, y) (coordinate to global space)
425
427
  """
426
428
  mybounds = self.get_bounds(abs)
427
429
 
@@ -433,13 +435,13 @@ class header_wolf():
433
435
  """
434
436
  Get indices from coordinates
435
437
 
436
- :param x = X coordinate
437
- :param y = Y coordinate
438
- :param z = Z coordinate (optional)
439
- :param scale = scaling of the spatial resolution (dx,dy,[dz])
440
- :param aswolf = if True, return if one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
441
- :param abs = if True, remove translation from (x, y, [z]) (coordinate from global space)
442
- :param forcedims2 = if True, force to return only 2 indices even if z is supplied
438
+ :param x: X coordinate
439
+ :param y: Y coordinate
440
+ :param z: Z coordinate (optional)
441
+ :param scale: scaling of the spatial resolution (dx,dy,[dz])
442
+ :param aswolf: if True, return if one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
443
+ :param abs: if True, remove translation from (x, y, [z]) (coordinate from global space)
444
+ :param forcedims2: if True, force to return only 2 indices even if z is supplied
443
445
  """
444
446
 
445
447
  locx = np.float64(x) - self.origx
@@ -475,7 +477,7 @@ class header_wolf():
475
477
  :param abs = if True, remove translation from (x, y, [z]) (coordinate from global space)
476
478
  :param forcedims2 = if True, force to return only 2 indices even if z is supplied
477
479
 
478
- :return : numpy array containing (i, j, [k]) indices - shape (n, 2) or (n, 3)
480
+ :return: numpy array containing (i, j, [k]) indices - shape (n, 2) or (n, 3)
479
481
  """
480
482
 
481
483
  if isinstance(xy,tuple):
@@ -642,17 +644,17 @@ class header_wolf():
642
644
  def ij2xy_np(self, ij:np.ndarray, scale:float=1., aswolf:bool=False, abs:bool=True) -> np.ndarray:
643
645
  """ alias for get_xy_from_ij_array
644
646
 
645
- :param ij = numpy array containing (i, j, [k]) indices
646
- :param scale = scaling of the spatial resolution (dx,dy,[dz])
647
- :param aswolf = if True, input is one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
648
- :param abs = if True, add translation to results (x, y, [z]) (coordinate to global space)
647
+ :param ij: numpy array containing (i, j, [k]) indices
648
+ :param scale: scaling of the spatial resolution (dx,dy,[dz])
649
+ :param aswolf: if True, input is one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
650
+ :param abs: if True, add translation to results (x, y, [z]) (coordinate to global space)
649
651
 
650
652
  ..warning: 'ij' is not the result of np.where() but if you want to use np.where() you can use the following code:
651
653
  ```
652
654
  np.vstack((ij[0], ij[1])).T
653
655
  ```
654
656
 
655
- :return : numpy array containing (x, y, [z]) coordinates - shape (n, 2) or (n, 3)
657
+ :return: numpy array containing (x, y, [z]) coordinates - shape (n, 2) or (n, 3)
656
658
  """
657
659
  return self.get_xy_from_ij_array(ij, scale, aswolf, abs)
658
660
 
@@ -664,11 +666,11 @@ class header_wolf():
664
666
  """
665
667
  alias for get_ij_from_xy_array
666
668
 
667
- :param xy = numpy array containing (x, y, [z]) coordinates - shape (n, 2) or (n, 3)
668
- :param scale = scaling of the spatial resolution (dx,dy,[dz])
669
- :param aswolf = if True, return if one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
670
- :param abs = if True, remove translation from (x, y, [z]) (coordinate from global space)
671
- :param forcedims2 = if True, force to return only 2 indices even if z is supplied
669
+ :param xy: numpy array containing (x, y, [z]) coordinates - shape (n, 2) or (n, 3)
670
+ :param scale: scaling of the spatial resolution (dx,dy,[dz])
671
+ :param aswolf: if True, return if one-based (as Wolf VB6 or Fortran), otherwise 0-based (default Python standard)
672
+ :param abs: if True, remove translation from (x, y, [z]) (coordinate from global space)
673
+ :param forcedims2: if True, force to return only 2 indices even if z is supplied
672
674
 
673
675
  :return : numpy array containing (i, j, [k]) indices - shape (n, 2) or (n, 3)
674
676
  """
@@ -689,8 +691,8 @@ class header_wolf():
689
691
  """
690
692
  Find the intersection of two header
691
693
 
692
- @arg other: other header
693
- @arg ij: if True, return indices instead of coordinates
694
+ :param other: other header
695
+ :param ij: if True, return indices instead of coordinates
694
696
 
695
697
  :return: None or tuple of two lists of two floats - ([xmin, xmax],[ymin, ymax]) or indices in each header (if ij=True) [[imin1, imax1], [jmin1, jmax1]], [[imin2, imax2], [jmin2, jmax2]]
696
698
  """
@@ -759,7 +761,7 @@ class header_wolf():
759
761
  """
760
762
  Read informations from header .txt
761
763
 
762
- :param filename : path and filename of the basefile
764
+ :param filename: path and filename of the basefile
763
765
 
764
766
  If filename is a Path object, it is converted to a string
765
767
  If filename ends with '.tif', nothing is done because infos are in the .tif file
@@ -866,7 +868,7 @@ class header_wolf():
866
868
  elif dtype == np.int16:
867
869
  self.wolftype = WOLF_ARRAY_FULL_INTEGER16
868
870
  elif dtype == np.uint8:
869
- self.wolftype = WOLF_ARRAY_FULL_INTEGER8
871
+ self.wolftype = WOLF_ARRAY_FULL_UINTEGER8
870
872
  elif dtype == np.int8:
871
873
  self.wolftype = WOLF_ARRAY_FULL_INTEGER8
872
874
  else:
@@ -994,12 +996,14 @@ class header_wolf():
994
996
 
995
997
  Nullvalue is not written
996
998
 
997
- :param filename : path and filename with '.txt' extension, which will NOT be automatically added
998
- :param wolftype : type of the WOLF_ARRAY_* array
999
- :param forceupdate : if True, the file is rewritten even if it already exists
999
+ :param filename: path and filename with '.txt' extension, which will NOT be automatically added
1000
+ :param wolftype: type of the WOLF_ARRAY_* array
1001
+ :param forceupdate: if True, the file is rewritten even if it already exists
1000
1002
  """
1001
1003
 
1002
- assert wolftype in [WOLF_ARRAY_CSR_DOUBLE, WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_DOUBLE, WOLF_ARRAY_SYM_DOUBLE, WOLF_ARRAY_FULL_LOGICAL, WOLF_ARRAY_CSR_DOUBLE, WOLF_ARRAY_FULL_INTEGER, WOLF_ARRAY_FULL_SINGLE_3D, WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_MB_SINGLE, WOLF_ARRAY_MB_INTEGER, WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_MNAP_INTEGER, WOLF_ARRAY_FULL_INTEGER16_2], _('The type of array is not correct')
1004
+ assert wolftype in [WOLF_ARRAY_CSR_DOUBLE, WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_DOUBLE, WOLF_ARRAY_SYM_DOUBLE, WOLF_ARRAY_FULL_LOGICAL,
1005
+ WOLF_ARRAY_CSR_DOUBLE, WOLF_ARRAY_FULL_INTEGER, WOLF_ARRAY_FULL_SINGLE_3D, WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_FULL_UINTEGER8,
1006
+ WOLF_ARRAY_MB_SINGLE, WOLF_ARRAY_MB_INTEGER, WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_MNAP_INTEGER, WOLF_ARRAY_FULL_INTEGER16_2], _('The type of array is not correct')
1003
1007
 
1004
1008
  if not os.path.exists(filename) or forceupdate:
1005
1009
  with open(filename,'w') as f:
@@ -1035,8 +1039,8 @@ class header_wolf():
1035
1039
  """
1036
1040
  Comparison of two headers
1037
1041
 
1038
- :param other : other header to compare
1039
- :param check_mb : if True, the comparison is done on the blocks too
1042
+ :param other: other header to compare
1043
+ :param check_mb: if True, the comparison is done on the blocks too
1040
1044
 
1041
1045
  The nullvalue is not taken into account
1042
1046
  """
@@ -1173,8 +1177,9 @@ class header_wolf():
1173
1177
  """
1174
1178
  Return the coordinates of the cells in the footprint of a vector
1175
1179
 
1176
- :param myvect = target vector
1180
+ :param myvect: target vector
1177
1181
  :return: tuple of two numpy arrays - (coordinates, indices)
1182
+ :param eps: epsilon to avoid rounding errors
1178
1183
 
1179
1184
  """
1180
1185
 
@@ -1190,8 +1195,9 @@ class header_wolf():
1190
1195
  """
1191
1196
  Return the indices of the cells in the footprint of a vector
1192
1197
 
1193
- :param myvect = target vector
1194
- :return : numpy array of indices
1198
+ :param myvect: target vector
1199
+ :return: numpy array of indices
1200
+ :param eps: epsilon to avoid rounding errors
1195
1201
  """
1196
1202
 
1197
1203
  if isinstance(myvect, Polygon):
@@ -1219,7 +1225,7 @@ class header_wolf():
1219
1225
  """
1220
1226
  Convert XY coordinates to IJ indices **(0-based)** with Numpy without any check/options
1221
1227
 
1222
- :param xy = numpy array of shape (n,2) with XY coordinates
1228
+ :param xy: = numpy array of shape (n,2) with XY coordinates
1223
1229
 
1224
1230
  """
1225
1231
 
@@ -1230,7 +1236,7 @@ class header_wolf():
1230
1236
  """
1231
1237
  Convert IJ indices **(0-based)** to XY coordinates with Numpy without any check/options
1232
1238
 
1233
- :param ij = numpy array of shape (n,2) with IJ indices
1239
+ :param ij: = numpy array of shape (n,2) with IJ indices
1234
1240
 
1235
1241
  """
1236
1242
 
@@ -1683,11 +1689,11 @@ class Ops_Array(wx.Frame):
1683
1689
 
1684
1690
  self.m_button7 = wx.Button(self.Interpolation, wx.ID_ANY, _("Stage/Volume/Surface evaluation"), wx.DefaultPosition,
1685
1691
  wx.DefaultSize, 0)
1686
- self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship. \n Results : plots and arrays saved on disk'))
1692
+ self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship.\nResults : csv and array saved on disk\n\n CAUTION : This function will be applied only on the selected area except if you select "all".\nIn the latter case, the computation time could be long if the array are very large.'))
1687
1693
 
1688
1694
  if self.parentarray.nb_blocks>0:
1689
1695
  self.m_button7.Disable()
1690
- self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship. \n Results : plots and arrays saved on disk\n\nThis function is not available for multi-block arrays.'))
1696
+ self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship.\nResults : arrays and csv file saved on disk\n\nThis function is not available for multi-block arrays.'))
1691
1697
 
1692
1698
  gSizer1.Add(self.m_button7, 0, wx.EXPAND)
1693
1699
  self.m_button7.Bind(wx.EVT_BUTTON, self.volumesurface)
@@ -4462,8 +4468,10 @@ class SelectionData():
4462
4468
  if self.nb == 0:
4463
4469
  return None
4464
4470
 
4465
- newarray = WolfArray()
4471
+ if self.myselection == 'all':
4472
+ return WolfArray(mold=self.parent)
4466
4473
 
4474
+ newarray = WolfArray()
4467
4475
  lochead = self._get_header()
4468
4476
  if lochead is None:
4469
4477
  logging.error(_('Error in get_newarray !'))
@@ -4586,33 +4594,35 @@ class SelectionData():
4586
4594
 
4587
4595
  if self.nb == 0 or self.myselection == 'all':
4588
4596
  myarray = array1
4589
- axs = myarray.volume_estimation()
4597
+ fig, axs = myarray.volume_estimation()
4590
4598
 
4591
4599
  myarray = array2
4592
- axs = myarray.volume_estimation(axs)
4600
+ fig, axs = myarray.volume_estimation(axs)
4593
4601
  else:
4594
4602
  myarray = array1.mngselection.get_newarray()
4595
- axs = myarray.volume_estimation()
4603
+ fig, axs = myarray.volume_estimation()
4596
4604
 
4597
4605
  myarray = array2.mngselection.get_newarray()
4598
- axs = myarray.volume_estimation(axs)
4606
+ fig, axs = myarray.volume_estimation(axs)
4599
4607
  else:
4600
4608
  if len(self.parent.mngselection.myselection) == 0 or self.parent.mngselection.myselection == 'all':
4601
4609
  myarray = self.parent
4602
4610
  else:
4603
4611
  myarray = self.parent.mngselection.get_newarray()
4612
+ myarray.SelectionData.selections = self.parent.mngselection.selections.copy()
4604
4613
 
4605
- myarray.volume_estimation()
4614
+ fig, axs = myarray.volume_estimation()
4606
4615
  else:
4607
4616
  if self.nb == 0 or self.myselection == 'all':
4608
4617
  myarray = self.parent
4609
4618
  else:
4610
4619
  myarray = self.get_newarray()
4620
+ myarray.SelectionData.selections = self.selections.copy()
4611
4621
 
4612
- myarray.volume_estimation()
4622
+ fig, axs = myarray.volume_estimation()
4613
4623
 
4614
4624
  if show:
4615
- plt.show()
4625
+ fig.show()
4616
4626
 
4617
4627
  class SelectionDataMB(SelectionData):
4618
4628
  """ Extension of SelectionData to manage multiple blocks """
@@ -4875,6 +4885,7 @@ class WolfArray(Element_To_Draw, header_wolf):
4875
4885
  plotted:bool = False,
4876
4886
  need_for_wx:bool = False,
4877
4887
  mask_source:np.ndarray = None,
4888
+ np_source:np.ndarray = None,
4878
4889
  ) -> None:
4879
4890
  """
4880
4891
  Constructor of the WolfArray class
@@ -4893,6 +4904,7 @@ class WolfArray(Element_To_Draw, header_wolf):
4893
4904
  :param plotted: True = will be plotted if required by the mapviewer
4894
4905
  :param need_for_wx: True = a wxApp is required (if no application is underway --> Error)
4895
4906
  :param mask_source: mask to link to the data
4907
+ :param np_source: numpy array to link to the data
4896
4908
 
4897
4909
  """
4898
4910
  try:
@@ -4980,7 +4992,16 @@ class WolfArray(Element_To_Draw, header_wolf):
4980
4992
  if self.nb_blocks>0:
4981
4993
  self.myblocks = {}
4982
4994
 
4983
- self.allocate_ressources()
4995
+ if np_source is None:
4996
+ self.allocate_ressources()
4997
+ else:
4998
+ assert np_source.shape == (self.nbx, self.nby), _('Shape of np_source is not compatible with header')
4999
+
5000
+ if self.dtype != np_source.dtype:
5001
+ logging.warning(_('dtype of np_source is not compatible with header -- Conversion will be done'))
5002
+ np_source = np_source.astype(self.dtype)
5003
+
5004
+ self.array = ma.MaskedArray(np_source, mask= np_source[:,:] == self.nullvalue, copy=False, order='C')
4984
5005
 
4985
5006
  # # FIXME Why not initialize with nullvalue ?
4986
5007
  # self.array = ma.MaskedArray(np.ones((self.nbx, self.nby), order='F', dtype=self.dtype))
@@ -5052,6 +5073,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5052
5073
  else:
5053
5074
  self.init_from_new(new)
5054
5075
 
5076
+
5055
5077
  self.add_ops_sel() # Ajout d'un gestionnaire de sélection et d'opérations
5056
5078
 
5057
5079
  def set_opacity(self, alpha:float):
@@ -5092,7 +5114,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5092
5114
  return size * 4
5093
5115
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_FULL_INTEGER16_2]:
5094
5116
  return size * 2
5095
- elif self.wolftype == WOLF_ARRAY_FULL_INTEGER8:
5117
+ elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_FULL_UINTEGER8]:
5096
5118
  return size
5097
5119
  else:
5098
5120
  return size * 4
@@ -5353,6 +5375,8 @@ class WolfArray(Element_To_Draw, header_wolf):
5353
5375
  dtype = np.int16
5354
5376
  elif self.wolftype == WOLF_ARRAY_FULL_INTEGER8:
5355
5377
  dtype = np.int8
5378
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
5379
+ dtype = np.uint8
5356
5380
  elif self.wolftype == WOLF_ARRAY_FULL_LOGICAL:
5357
5381
  dtype = np.int16
5358
5382
 
@@ -5372,6 +5396,8 @@ class WolfArray(Element_To_Draw, header_wolf):
5372
5396
  dtype = gdal.GDT_Int16
5373
5397
  elif self.wolftype == WOLF_ARRAY_FULL_INTEGER8:
5374
5398
  dtype = gdal.GDT_Byte
5399
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
5400
+ dtype = gdal.GDT_Byte
5375
5401
  elif self.wolftype == WOLF_ARRAY_FULL_LOGICAL:
5376
5402
  dtype = gdal.GDT_Int16
5377
5403
 
@@ -5402,6 +5428,8 @@ class WolfArray(Element_To_Draw, header_wolf):
5402
5428
  dtype = _('int16 - 2 bytes per values')
5403
5429
  elif self.wolftype == WOLF_ARRAY_FULL_INTEGER8:
5404
5430
  dtype = _('int8 - 1 byte per values')
5431
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
5432
+ dtype = _('uint8 - 1 byte per values')
5405
5433
  elif self.wolftype == WOLF_ARRAY_FULL_LOGICAL:
5406
5434
  dtype = _('int16 - 2 bytes per values')
5407
5435
 
@@ -6060,7 +6088,7 @@ class WolfArray(Element_To_Draw, header_wolf):
6060
6088
  - uniquement dans les mailles sélectionnées si elles existent
6061
6089
  - dans les mailles contenues dans le polygone sinon
6062
6090
 
6063
- On utilise ensuite "griddata" pour interpoler les altitudes des mailles
6091
+ On utilise ensuite "griddata" de Scipy pour interpoler les altitudes des mailles
6064
6092
  depuis les vertices 3D du polygone
6065
6093
  """
6066
6094
 
@@ -6123,17 +6151,27 @@ class WolfArray(Element_To_Draw, header_wolf):
6123
6151
  self.array.data[allij[:, 0], allij[:, 1]] = newz
6124
6152
 
6125
6153
  def interpolate_on_polylines(self, working_zone:zone, usemask=True):
6154
+ """ Interpolation sous toutes les polylignes d'une même zone """
6126
6155
 
6127
6156
  for curvec in working_zone.myvectors:
6128
6157
  self.interpolate_on_polyline(curvec, usemask)
6129
6158
 
6130
6159
 
6131
- def interpolate_on_cloud(self, xy:np.ndarray, z:np.ndarray, method='linear'):
6160
+ def interpolate_on_cloud(self, xy:np.ndarray, z:np.ndarray, method:Literal['linear', 'nearest', 'cubic']= 'linear'):
6132
6161
  """
6133
- See : https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
6162
+ Interpolation sur un nuage de points.
6134
6163
 
6135
- method == nearest, linear or cubic
6164
+ L'interpolation a lieu :
6165
+ - uniquement dans les mailles sélectionnées si elles existent
6166
+ - dans les mailles contenues dans le polygone convexe contenant les points sinon
6136
6167
 
6168
+ Using griddata from Scipy.
6169
+
6170
+ :param xy: numpy.array of vertices - shape (n,2)
6171
+ :param z: numpy.array of values - shape (n,)
6172
+ :param method: method for the interpolation -- 'nearest', 'linear' or 'cubic'
6173
+
6174
+ See : https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
6137
6175
  """
6138
6176
 
6139
6177
  if self.mngselection.myselection == [] or self.mngselection.myselection == 'all':
@@ -6157,18 +6195,36 @@ class WolfArray(Element_To_Draw, header_wolf):
6157
6195
 
6158
6196
  self.reset_plot()
6159
6197
 
6160
- def interpolate_on_triangulation(self, coords, triangles, grid_x=None, grid_y = None, mask_tri=None, interp_method = 'matplotlib'):
6161
- import matplotlib.tri as mtri
6198
+ def interpolate_on_triangulation(self, coords, triangles,
6199
+ grid_x=None, grid_y = None,
6200
+ mask_tri=None, interp_method:Literal['matplotlib','scipy'] = 'matplotlib'):
6162
6201
  """
6163
- See : https://matplotlib.org/stable/gallery/images_contours_and_fields/triinterp_demo.html
6202
+ Interpolation sur une triangulation.
6164
6203
 
6165
- method == linear
6204
+ L'interpolation a lieu :
6205
+ - uniquement dans les mailles sélectionnées si elles existent
6206
+ - dans les mailles contenues dans la triangulation sinon
6207
+
6208
+ Matplotlib is used by default, but Scipy(griddata) can be used as well. If Matplotlib crashes, try with Scipy.
6209
+ Matplotlib is more strict on the quality of the triangulation.
6210
+
6211
+ :param coords: numpy.array of vertices - shape (n,3)
6212
+ :param triangles: numpy.array of triangles - shape (m,3)
6213
+ :param grid_x: numpy.array of x values where the interpolation will be done -- if None, the grid is created from the array
6214
+ :param grid_y: numpy.array of y values where the interpolation will be done -- if None, the grid is created from the array
6215
+ :param mask_tri: numpy.array of mask for the triangles
6216
+ :param interp_method: method for the interpolation -- 'matplotlib' or 'scipy'
6217
+
6218
+ For matplotlib algo, see : https://matplotlib.org/stable/gallery/images_contours_and_fields/triinterp_demo.html
6219
+ For scipy algo, see : https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
6166
6220
 
6167
6221
  """
6168
6222
 
6169
6223
 
6170
6224
  if interp_method =='matplotlib':
6171
6225
 
6226
+ import matplotlib.tri as mtri
6227
+
6172
6228
  use_scipy=False
6173
6229
 
6174
6230
  try:
@@ -6289,10 +6345,16 @@ class WolfArray(Element_To_Draw, header_wolf):
6289
6345
  self.reset_plot()
6290
6346
  return
6291
6347
 
6292
- def import_from_gltf(self, fn:str='', fnpos:str='', interp_method:Literal['matplotlib','numpy'] = 'matplotlib'):
6348
+ def import_from_gltf(self, fn:str='', fnpos:str='', interp_method:Literal['matplotlib','scipy'] = 'matplotlib'):
6293
6349
  """
6294
- interp_method == 'matplotlib' or 'griddata'
6350
+ Import from GLTF/GLB format
6351
+
6352
+ :param fn: filename
6353
+ :param fnpos: filename for the position's information
6354
+ :param interp_method: method for the interpolation -- 'matplotlib' or 'scipy'
6355
+
6295
6356
  """
6357
+ #FIXME : add the possibility to use PyVista
6296
6358
 
6297
6359
  if fn == '' or fnpos == '':
6298
6360
  logging.info(_('Retry !! -- Bad files'))
@@ -6457,7 +6519,6 @@ class WolfArray(Element_To_Draw, header_wolf):
6457
6519
  triangles.append([[i + decal, i + decal + 1, i + decal + nby] for i in range(nby - 1)])
6458
6520
  triangles.append([[i + decal + nby, i + decal + 1, i + decal + nby + 1] for i in range(nby - 1)])
6459
6521
 
6460
- from tqdm import tqdm
6461
6522
  for k in tqdm(range(1, nbx - 1)):
6462
6523
  decal = k * nby
6463
6524
  triangles.append([[i + decal, i + decal + 1, i + decal + nby] for i in range(nby - 1)])
@@ -6497,7 +6558,7 @@ class WolfArray(Element_To_Draw, header_wolf):
6497
6558
 
6498
6559
  return mylap
6499
6560
 
6500
- def volume_estimation(self, axs=None):
6561
+ def volume_estimation(self, axs:plt.Axes= None):
6501
6562
  """ Estimation of the volume of the selected zone """
6502
6563
 
6503
6564
  vect = self.array[np.logical_not(self.array.mask)].flatten()
@@ -6527,58 +6588,125 @@ class WolfArray(Element_To_Draw, header_wolf):
6527
6588
  deltaz = (zmax - zmin) / nb
6528
6589
  curz = zmin
6529
6590
  nbgroupement = []
6530
- longueur = []
6591
+ labeled_areas = []
6531
6592
  stockage = []
6532
6593
  z = []
6533
6594
 
6534
- dlg = wx.MessageDialog(None, _("Would you like to calculate relationships on the basis of the largest area ? \n if Yes, no guarantee on the volume increase"), style = wx.YES_NO|wx.YES_DEFAULT)
6595
+ methods = [_("All cells below the elevation (even if cells are disconnected)"),
6596
+ _("Only the largest connected area below the elevation (not necessarily the same for each elevation)"),
6597
+ _("Only the area below the elevation (if containing the cells stored in memory selection)")]
6598
+
6599
+ keys_select = list(self.SelectionData.selections.keys())
6600
+ if len(keys_select) == 0:
6601
+ methods = methods[:2]
6602
+ use_memory = False
6603
+
6604
+ dlg = wx.SingleChoiceDialog(None, _("Choose a method for selecting the area to integrate"), _("Labeling?"), methods)
6535
6605
  ret = dlg.ShowModal()
6536
- if ret == wx.ID_YES:
6537
- labeled= True
6538
- dlg.Destroy()
6606
+
6607
+ if ret == wx.ID_CANCEL:
6608
+ dlg.Destroy()
6609
+ return
6610
+
6611
+ if dlg.GetSelection() == 0:
6612
+ labeled = False
6613
+ else:
6614
+ labeled = True
6615
+ if dlg.GetSelection() == 1:
6616
+ use_memory = False
6617
+ else:
6618
+ if len(keys_select) >1:
6619
+ dlg = wx.SingleChoiceDialog(None, _("Choose a memory selection"), _("Memory selection?"), keys_select)
6620
+ ret = dlg.ShowModal()
6621
+
6622
+ if ret == wx.ID_CANCEL:
6623
+ dlg.Destroy()
6624
+ return
6625
+
6626
+ key = keys_select[dlg.GetSelection()]
6627
+ else:
6628
+ key = keys_select[0]
6629
+
6630
+ xy_key = self.SelectionData.selections[key]['select']
6631
+ if len(xy_key) == 0:
6632
+ logging.error(_('Empty selection'))
6633
+ return
6634
+
6635
+ ij_key = self.xy2ij_np(xy_key)
6636
+
6637
+ use_memory = True
6539
6638
 
6540
6639
  extensionmax = WolfArray(mold=self)
6541
6640
  extensionmax.array[:, :] = 0.
6542
6641
 
6543
6642
  if labeled:
6544
- for i in range(nb + 1):
6545
- logging.info(_(' Step ') +str(i))
6643
+ for i in tqdm(range(nb + 1)):
6546
6644
  z.append(curz)
6547
6645
 
6646
+ # Compute difference between the array and the current elevation
6548
6647
  if i == 0:
6549
6648
  diff = self.array - (curz + 1.e-3)
6550
6649
  else:
6551
6650
  diff = self.array - curz
6552
6651
 
6652
+ # Keep only the negative values
6553
6653
  diff[diff > 0] = 0.
6554
6654
  diff.data[diff.mask] = 0.
6555
- labeled_array, num_features = label(diff.data)
6556
- labeled_array = ma.asarray(labeled_array)
6557
- labeled_array.mask = self.array.mask
6558
-
6559
- # groupement = labeled_array
6560
- # groupement[labeled_array.mask] = 0
6561
- # nbgroupement.append(num_features)
6562
- # for j in range(1, nbgroupement[i] + 1):
6563
- # taille = (np.sum(groupement[groupement == j]) // j)
6564
- # longueur.append([taille, j])
6565
-
6566
6655
 
6567
- longueur = list(sum_labels(np.ones(labeled_array.shape, dtype=np.int32), labeled_array, range(1, num_features+1)))
6656
+ if np.count_nonzero(diff < 0.) > 1:
6657
+ # More than one cell below the elevation
6658
+
6659
+ # Labeling of the cells below the elevation
6660
+ labeled_array, num_features = label(diff.data)
6661
+ # Applying the same mask as the original array
6662
+ labeled_array = ma.asarray(labeled_array)
6663
+ labeled_array.mask = self.array.mask
6664
+
6665
+ if use_memory:
6666
+ # Use only the labeled areas containing the cells stored in memory selection
6667
+ labeled_areas = []
6668
+ for curij in ij_key:
6669
+ labeled_areas.append(labeled_array[curij[0], curij[1]])
6670
+
6671
+ # Remove masked value
6672
+ labeled_areas = [x for x in labeled_areas if x is not ma.masked]
6673
+ # Remove duplicates
6674
+ labeled_areas = list(set(labeled_areas))
6675
+
6676
+ for curarea in labeled_areas:
6677
+ if curarea ==0:
6678
+ volume = 0.
6679
+ surface = 0.
6680
+ continue
6681
+
6682
+ # Search
6683
+ mask = labeled_array == curarea
6684
+ area = np.where(mask)
6685
+ volume = -self.dx * self.dy * np.sum(diff[area])
6686
+ surface = self.dx * self.dy * len(area[0])
6687
+ extensionmax.array[np.logical_and(mask, extensionmax.array[:, :] == 0.)] = float(i + 1)
6568
6688
 
6569
- longueur.sort(key=lambda x: x[0], reverse=True)
6689
+ else:
6690
+ labeled_areas = list(sum_labels(np.ones(labeled_array.shape, dtype=np.int32), labeled_array, range(1, num_features+1)))
6691
+ labeled_areas = [[x, y] for x, y in zip(labeled_areas, range(1, num_features+1))]
6692
+ labeled_areas.sort(key=lambda x: x[0], reverse=True)
6693
+ jmax = labeled_areas[0][1]
6694
+ nbmax = labeled_areas[0][0]
6695
+
6696
+ volume = -self.dx * self.dy * np.sum(diff[labeled_array == jmax])
6697
+ surface = self.dx * self.dy * nbmax
6698
+ extensionmax.array[np.logical_and(labeled_array == jmax, extensionmax.array[:, :] == 0.)] = float(i + 1)
6699
+ else:
6700
+ # Only one cell below the elevation
6701
+ volume = -self.dx * self.dy * np.sum(diff)
6702
+ surface = self.dx * self.dy * np.count_nonzero(diff<0.)
6703
+ extensionmax.array[np.logical_and(diff[:,:]<0., extensionmax.array[:, :] == 0.)] = float(i + 1)
6570
6704
 
6571
- jmax = longueur[0][1]
6572
- nbmax = longueur[0][0]
6573
- volume = -self.dx * self.dy * np.sum(diff[labeled_array == jmax])
6574
- surface = self.dx * self.dy * nbmax
6575
6705
  stockage.append([volume, surface])
6576
6706
  curz += deltaz
6577
6707
 
6578
- extensionmax.array[np.logical_and(labeled_array == jmax, extensionmax.array[:, :] == 0.)] = float(i + 1)
6579
6708
  else:
6580
- for i in range(nb + 1):
6581
- logging.info(_(' Step ') +str(i))
6709
+ for i in tqdm(range(nb + 1)):
6582
6710
  z.append(curz)
6583
6711
 
6584
6712
  if i == 0:
@@ -6595,7 +6723,7 @@ class WolfArray(Element_To_Draw, header_wolf):
6595
6723
 
6596
6724
  extensionmax.array[np.logical_and(diff[:,:]<0., extensionmax.array[:, :] == 0.)] = float(i + 1)
6597
6725
 
6598
- dlg = wx.FileDialog(None, _('Choose filename'), wildcard='bin (*.bin)|*.bin|All (*.*)|*.*', style=wx.FD_SAVE)
6726
+ dlg = wx.FileDialog(None, _('Choose filename for zoning result'), wildcard='bin (*.bin)|*.bin|tif (*.tif)|*.tif|All (*.*)|*.*', style=wx.FD_SAVE)
6599
6727
  ret = dlg.ShowModal()
6600
6728
  if ret == wx.ID_CANCEL:
6601
6729
  dlg.Destroy()
@@ -6609,22 +6737,25 @@ class WolfArray(Element_To_Draw, header_wolf):
6609
6737
 
6610
6738
  if axs is None:
6611
6739
  fig, axs = plt.subplots(1, 2, tight_layout=True)
6740
+ else:
6741
+ fig = axs[0].get_figure()
6742
+
6612
6743
  axs[0].plot(z, [x[0] for x in stockage])
6613
6744
  axs[0].scatter(z, [x[0] for x in stockage])
6614
6745
  axs[0].set_xlabel(_("Elevation [m]"), size=15)
6615
- axs[0].set_ylabel(_("Volume [m^3]"), size=15)
6746
+ axs[0].set_ylabel(_("Volume [$m^3$]"), size=15)
6616
6747
  axs[1].step(z, [x[1] for x in stockage], where='post')
6617
6748
  axs[1].scatter(z, [x[1] for x in stockage])
6618
6749
  axs[1].set_xlabel(_("Elevation [m]"), size=15)
6619
- axs[1].set_ylabel(_("Surface [m^2]"), size=15)
6620
- plt.suptitle(_("Retention capacity of the selected zone"), fontsize=20)
6750
+ axs[1].set_ylabel(_("Surface [$m^2$]"), size=15)
6751
+ fig.suptitle(_("Retention capacity of the selected zone"), fontsize=20)
6621
6752
 
6622
6753
  with open(fn[:-4] + '_hvs.txt', 'w') as f:
6623
- f.write('H [m]\tZ [m DNG]\tVolume [m^3]\tSurface [m^2]\n')
6754
+ f.write('H [m]\tZ [m DNG]\tVolume [$m^3$]\tSurface [$m^2$]\n')
6624
6755
  for curz, (curv, curs) in zip(z, stockage):
6625
6756
  f.write('{}\t{}\t{}\t{}\n'.format(curz - zmin, curz, curv, curs))
6626
6757
 
6627
- return axs
6758
+ return fig, axs
6628
6759
 
6629
6760
  def paste_all(self, fromarray:"WolfArray", mask_after:bool=True):
6630
6761
  """ Paste all the values from another WolfArray """
@@ -6735,6 +6866,8 @@ class WolfArray(Element_To_Draw, header_wolf):
6735
6866
  dtype = np.int16
6736
6867
  elif self.wolftype == WOLF_ARRAY_FULL_INTEGER8:
6737
6868
  dtype = np.int8
6869
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
6870
+ dtype = np.uint8
6738
6871
 
6739
6872
  self.dx = myhead.dx
6740
6873
  self.dy = myhead.dy
@@ -6905,20 +7038,24 @@ class WolfArray(Element_To_Draw, header_wolf):
6905
7038
  self.plotted = False
6906
7039
 
6907
7040
  if unload and self.filename != '':
6908
- if askquestion and self.wx_exists:
6909
- dlg = wx.MessageDialog(None,
6910
- _('Do you want to unload data? \n If YES, the data will be reloaded from file once checekd \n If not saved, modifications will be lost !!'),
6911
- style=wx.YES_NO)
6912
- ret = dlg.ShowModal()
6913
- if ret == wx.ID_YES:
6914
- unload=True
7041
+ if Path(self.filename).exists():
7042
+ # An array can exists with a filename but no written data on disk
7043
+ # In this case, we don't want to delete the data in memory
6915
7044
 
6916
- if unload:
6917
- self.delete_lists()
6918
- self.array = np.zeros([1])
6919
- if VERSION_RGB==1 : self.rgb = None
6920
- self.loaded = False
6921
- return
7045
+ if askquestion and self.wx_exists:
7046
+ dlg = wx.MessageDialog(None,
7047
+ _('Do you want to unload data? \n If YES, the data will be reloaded from file once checekd \n If not saved, modifications will be lost !!'),
7048
+ style=wx.YES_NO)
7049
+ ret = dlg.ShowModal()
7050
+ if ret == wx.ID_YES:
7051
+ unload=True
7052
+
7053
+ if unload:
7054
+ self.delete_lists()
7055
+ self.array = np.zeros([1])
7056
+ if VERSION_RGB==1 : self.rgb = None
7057
+ self.loaded = False
7058
+ return
6922
7059
 
6923
7060
  if not forceresetOGL:
6924
7061
  if askquestion and self.wx_exists:
@@ -7186,7 +7323,7 @@ class WolfArray(Element_To_Draw, header_wolf):
7186
7323
 
7187
7324
  return newArray
7188
7325
 
7189
- def mask_outsidepoly(self, myvect: vector, eps:float = 0.):
7326
+ def mask_outsidepoly(self, myvect: vector, eps:float = 0., set_nullvalue:bool=True):
7190
7327
  """
7191
7328
  Mask nodes outside a polygon and set values to nullvalue
7192
7329
 
@@ -7196,31 +7333,21 @@ class WolfArray(Element_To_Draw, header_wolf):
7196
7333
  # (coord will be converted back with translation, origin and dx/dy)
7197
7334
  # (mesh coord, 0-based)
7198
7335
 
7199
- mask = self.array.mask
7200
- mask[:,:] = True # Mask everything
7201
-
7202
7336
  # trouve les indices dans le polygone
7203
- myij = self.get_ij_inside_polygon(myvect, usemask=False, eps=eps)
7337
+ myij = self.get_ij_inside_polygon(myvect, usemask=True, eps=eps)
7204
7338
 
7205
- # démasquage des mailles contenues
7206
- mask[myij[:,0],myij[:,1]] = False
7339
+ self.array.mask.fill(True) # Mask everything
7207
7340
 
7208
- # annulation des valeurs en dehors du polygone
7209
- self.array.data[np.where(mask)] = self.nullvalue
7210
-
7211
- # recherche du nouveau masque, sinon les valeurs no_data à
7212
- # l'intérieur du polygone vont pollluer la matrice
7341
+ # démasquage des mailles contenues
7342
+ self.array.mask[myij[:,0],myij[:,1]] = False
7213
7343
 
7214
- # Now we have masked everything outside the polygon,
7215
- # we still have to keep into account values that were
7216
- # already masked inside the polygon before this operation.
7217
- # FIXME Why simply not use the previous mask value ?
7218
- # FIXME This operation seems to contradict mask[:,:] = True
7219
- self.mask_data(self.nullvalue)
7344
+ if set_nullvalue:
7345
+ # annulation des valeurs en dehors du polygone
7346
+ self.set_nullvalue_in_mask()
7220
7347
 
7221
7348
  self.count()
7222
7349
 
7223
- def mask_insidepoly(self, myvect: vector, eps:float = 0.):
7350
+ def mask_insidepoly(self, myvect: vector, eps:float = 0., set_nullvalue:bool=True):
7224
7351
  """
7225
7352
  Mask nodes inside a polygon and set values to nullvalue
7226
7353
 
@@ -7233,8 +7360,9 @@ class WolfArray(Element_To_Draw, header_wolf):
7233
7360
  # trouve les indices dans le polygone
7234
7361
  myij = self.get_ij_inside_polygon(myvect, usemask=False, eps=eps)
7235
7362
 
7236
- # annulation des valeurs en dehors du polygone
7237
- self.array.data[myij[:,0],myij[:,1]] = self.nullvalue
7363
+ if set_nullvalue:
7364
+ # annulation des valeurs en dehors du polygone
7365
+ self.array.data[myij[:,0],myij[:,1]] = self.nullvalue
7238
7366
 
7239
7367
  # masquage des mailles contenues
7240
7368
  self.array.mask[myij[:,0],myij[:,1]] = True
@@ -7250,8 +7378,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7250
7378
  """
7251
7379
  Return the coordinates inside a polygon
7252
7380
 
7253
- :param myvect : target vector
7254
- :param usemask : limit potential nodes to unmaksed nodes
7381
+ :param myvect: target vector
7382
+ :param usemask: limit potential nodes to unmaksed nodes
7255
7383
  """
7256
7384
 
7257
7385
  if isinstance(myvect, vector):
@@ -7279,8 +7407,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7279
7407
  """
7280
7408
  Return the coordinates inside a polygon
7281
7409
 
7282
- :param myvect : target vector
7283
- :param usemask : limit potential nodes to unmaksed nodes
7410
+ :param myvect: target vector
7411
+ :param usemask: limit potential nodes to unmaksed nodes
7284
7412
  """
7285
7413
 
7286
7414
  if isinstance(myvect, vector):
@@ -7307,8 +7435,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7307
7435
  """
7308
7436
  Return the coordinates along a polyline
7309
7437
 
7310
- :param myvect : target vector
7311
- :param usemask : limit potential nodes to unmaksed nodes
7438
+ :param myvect: target vector
7439
+ :param usemask: limit potential nodes to unmaksed nodes
7312
7440
  """
7313
7441
 
7314
7442
  allij = self.get_ij_under_polyline(myvect, usemask)
@@ -7320,8 +7448,9 @@ class WolfArray(Element_To_Draw, header_wolf):
7320
7448
  """
7321
7449
  Return the indices inside a polygon
7322
7450
 
7323
- :param myvect : target vector
7324
- :param usemask : limit potential nodes to unmaksed nodes
7451
+ :param myvect: target vector
7452
+ :param usemask: limit potential nodes to unmaksed nodes
7453
+ :param eps: epsilon for the intersection
7325
7454
  """
7326
7455
 
7327
7456
  # force la mise à jour des min/max
@@ -7346,8 +7475,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7346
7475
  def intersects_polygon(self, myvect: vector | Polygon, usemask:bool=True):
7347
7476
  """ Return True if the array intersects the polygon
7348
7477
 
7349
- :param myvect : target vector
7350
- :param usemask : limit potential nodes to unmaksed nodes
7478
+ :param myvect: target vector
7479
+ :param usemask: limit potential nodes to unmaksed nodes
7351
7480
  """
7352
7481
 
7353
7482
  return self.get_xy_inside_polygon(myvect, usemask).shape[0] > 0
@@ -7355,8 +7484,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7355
7484
  def intersects_polygon_shapely(self, myvect: vector | Polygon, eps:float = 0., usemask:bool=True):
7356
7485
  """ Return True if the array intersects the polygon
7357
7486
 
7358
- :param myvect : target vector
7359
- :param usemask : limit potential nodes to unmaksed nodes
7487
+ :param myvect: target vector
7488
+ :param usemask: limit potential nodes to unmaksed nodes
7360
7489
  """
7361
7490
  return self.get_xy_inside_polygon_shapely(myvect, usemask).shape[0] > 0
7362
7491
 
@@ -7364,8 +7493,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7364
7493
  """
7365
7494
  Return the indices along a polyline
7366
7495
 
7367
- :param myvect = target vector
7368
- :param usedmask = limit potential nodes to unmaksed nodes
7496
+ :param myvect: target vector
7497
+ :param usedmask: limit potential nodes to unmaksed nodes
7369
7498
  """
7370
7499
 
7371
7500
  ds = min(self.dx, self.dy)
@@ -7388,8 +7517,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7388
7517
  """
7389
7518
  Récupération des valeurs contenues dans un polygone
7390
7519
 
7391
- :param usemask : (optional) restreint les éléments aux éléments non masqués de la matrice
7392
- :param getxy : (optional) retourne en plus les coordonnées des points
7520
+ :param usemask: (optional) restreint les éléments aux éléments non masqués de la matrice
7521
+ :param getxy: (optional) retourne en plus les coordonnées des points
7393
7522
  """
7394
7523
  mypoints = self.get_xy_inside_polygon(myvect, usemask)
7395
7524
  myvalues = np.asarray([self.get_value(cur[0], cur[1]) for cur in mypoints])
@@ -7403,8 +7532,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7403
7532
  """
7404
7533
  Récupération des valeurs contenues sous une polyligne
7405
7534
 
7406
- :param usemask : (optional) restreint les éléments aux éléments non masqués de la matrice
7407
- :param getxy : (optional) retourne en plus les coordonnées des points
7535
+ :param usemask: (optional) restreint les éléments aux éléments non masqués de la matrice
7536
+ :param getxy: (optional) retourne en plus les coordonnées des points
7408
7537
  """
7409
7538
  mypoints = self.get_xy_under_polyline(myvect, usemask)
7410
7539
 
@@ -7419,8 +7548,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7419
7548
  """
7420
7549
  Récupération de toutes les valeurs contenues dans un polygone
7421
7550
 
7422
- :param usemask : (optional) restreint les éléments aux éléments non masqués de la matrice
7423
- :param getxy : (optional) retourne en plus les coordonnées des points
7551
+ :param usemask: (optional) restreint les éléments aux éléments non masqués de la matrice
7552
+ :param getxy: (optional) retourne en plus les coordonnées des points
7424
7553
 
7425
7554
  ICI on retourne le résultat de get_values_insidepoly, car une seule matrice, mais une autre classe pourrait vouloir faure autre chose
7426
7555
  C'est le cas notamment de Wolfresults_2D
@@ -7432,8 +7561,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7432
7561
  """
7433
7562
  Récupération de toutes les valeurs sous la polyligne
7434
7563
 
7435
- :param usemask : (optional) restreint les éléments aux éléments non masqués de la matrice
7436
- :param getxy : (optional) retourne en plus les coordonnées des points
7564
+ :param usemask: (optional) restreint les éléments aux éléments non masqués de la matrice
7565
+ :param getxy: (optional) retourne en plus les coordonnées des points
7437
7566
 
7438
7567
  ICI on retourne le résultat de get_values_underpoly, car une seule matrice, mais une autre classe pourrait vouloir faure autre chose
7439
7568
  C'est le cas notamment de Wolfresults_2D
@@ -7562,6 +7691,9 @@ class WolfArray(Element_To_Draw, header_wolf):
7562
7691
  elif locarray.dtype == np.int8:
7563
7692
  self.wolftype = WOLF_ARRAY_FULL_INTEGER8
7564
7693
  logging.warning(_('Data type changed to int8'))
7694
+ elif locarray.dtype == np.uint8:
7695
+ self.wolftype = WOLF_ARRAY_FULL_UINTEGER8
7696
+ logging.warning(_('Data type changed to uint8'))
7565
7697
  else:
7566
7698
  logging.error(_('Unsupported type in numpy file -- Abort wrting header file'))
7567
7699
  writing_header = False
@@ -7586,7 +7718,7 @@ class WolfArray(Element_To_Draw, header_wolf):
7586
7718
  :param factor: factor of resolution change -- > 1.0 : decrease resolution, < 1.0 : increase resolution
7587
7719
  :type factor: float
7588
7720
  :return: new shape
7589
- :rtype: Tuple[int, int]
7721
+ :rtype: Tuple[int, int], Tuple[float, float]
7590
7722
  """
7591
7723
 
7592
7724
  newdx = self.dx * float(factor)
@@ -7869,6 +8001,9 @@ class WolfArray(Element_To_Draw, header_wolf):
7869
8001
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER8]:
7870
8002
  locarray = np.frombuffer(f.read(self.nbx * self.nby * 2), dtype=np.int8)
7871
8003
  self.array = ma.masked_array(locarray.copy(), dtype=np.int8)
8004
+ elif self.wolftype in [WOLF_ARRAY_FULL_UINTEGER8]:
8005
+ locarray = np.frombuffer(f.read(self.nbx * self.nby * 2), dtype=np.uint8)
8006
+ self.array = ma.masked_array(locarray.copy(), dtype=np.uint8)
7872
8007
 
7873
8008
  if self.nbdims == 2:
7874
8009
  self.array = self.array.reshape(self.nbx, self.nby, order='F')
@@ -7903,7 +8038,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7903
8038
 
7904
8039
  return xyz[filter]
7905
8040
 
7906
- def set_general_frame_from_xyz(self, fname:str, dx:float, dy:float, border_size:int=5):
8041
+ @classmethod
8042
+ def set_general_frame_from_xyz(cls, fname:str, dx:float, dy:float, border_size:int=5, delimiter:str=',', fillin:bool=False):
7907
8043
  """
7908
8044
  Lecture d'un fichier texte xyz et initialisation des données de base
7909
8045
 
@@ -7913,19 +8049,72 @@ class WolfArray(Element_To_Draw, header_wolf):
7913
8049
  :param border_size: nombre de mailles de bordure en plus de l'extension spatiale du fichier
7914
8050
  """
7915
8051
 
7916
- my_file = XYZFile(fname)
8052
+ my_file = XYZFile(fname, delimiter=delimiter)
7917
8053
  my_file.read_from_file()
7918
8054
  (xlim, ylim) = my_file.get_extent()
7919
8055
 
7920
- self.dx = dx
7921
- self.dy = dy
7922
- self.origx = m.floor(xlim[0]) - float(border_size) * self.dx
7923
- self.origy = m.floor(ylim[0]) - float(border_size) * self.dy
7924
- self.nbx = int((m.floor(xlim[1]) - m.ceil(xlim[0])) / self.dx) + 2*border_size
7925
- self.nby = int((m.floor(ylim[1]) - m.ceil(ylim[0])) / self.dy) + 2*border_size
8056
+ Array = WolfArray()
8057
+ Array.dx = dx
8058
+ Array.dy = dy
8059
+ Array.origx = m.floor(xlim[0]) - dx/2. - float(border_size) * Array.dx
8060
+ Array.origy = m.floor(ylim[0]) - dy/2. - float(border_size) * Array.dy
8061
+ Array.nbx = int((m.floor(xlim[1]) - m.ceil(xlim[0])) / Array.dx) + 1 + 2*border_size
8062
+ Array.nby = int((m.floor(ylim[1]) - m.ceil(ylim[0])) / Array.dy) + 1 + 2*border_size
8063
+
8064
+ Array.array = np.ma.zeros((Array.nbx, Array.nby), dtype=np.float32)
7926
8065
 
7927
- self.array = np.ma.zeros((self.nbx, self.nby))
7928
- return my_file
8066
+ if fillin:
8067
+ Array.fillin_from_xyz(my_file.xyz)
8068
+
8069
+ return Array
8070
+
8071
+ @classmethod
8072
+ def set_general_frame_from_xyz_dir(cls, path:str, bounds:list, delimiter:str=',', dxdy:tuple[float, float]= None, border_size:int=5, fillin:bool=True):
8073
+ """
8074
+ Lecture d'un dossier contenant des fichiers texte xyz, initialisation des données de base et chargement de la matrice
8075
+ Renvoie un WolfArray or False si le fichier n'est pas dans les limites
8076
+
8077
+ :param path: chemin du dossier avec les fichier xyz
8078
+ :dtype path: str
8079
+ :param bounds: limites de l'extension spatiale
8080
+ :dtype bounds: list
8081
+ :param delimiter: délimiteur des fichiers xyz
8082
+ :dtype delimiter: str
8083
+ :param border_size: nombre de mailles de bordure en plus de l'extension spatiale du fichier
8084
+ :dtype border_size: int
8085
+ """
8086
+
8087
+ Data_xyz = XYZFile('nothing.xyz', folder=path, bounds=bounds, delimiter=delimiter)
8088
+
8089
+ if Data_xyz.nblines == 0:
8090
+ logging.info(f"File not in the boundaries for {path.split(os.sep)[-1]}")
8091
+ return False
8092
+
8093
+ xlim, ylim = Data_xyz.get_extent()
8094
+
8095
+ if dxdy is None:
8096
+ # We assume dx and dy are equals within xyz file
8097
+ dx = np.diff(Data_xyz.xyz[0:2,0])[0]
8098
+ logging.info(f"dx = {dx} ; dy = {dx}")
8099
+ dy = dx
8100
+ else:
8101
+ dx,dy = dxdy
8102
+ assert dx is not None and dy is not None, _('dx and dy must be defined')
8103
+
8104
+ Array = WolfArray()
8105
+ Array.dx = dx
8106
+ Array.dy = dy
8107
+ Array.origx = m.floor(xlim[0]) -dx/2. - float(border_size) * Array.dx
8108
+ Array.origy = m.floor(ylim[0]) -dy/2. - float(border_size) * Array.dy
8109
+ Array.nbx = int((m.floor(xlim[1]) - m.ceil(xlim[0])) / Array.dx) +1 + 2*border_size
8110
+ Array.nby = int((m.floor(ylim[1]) - m.ceil(ylim[0])) / Array.dy) +1 + 2*border_size
8111
+
8112
+ Array.array = np.ma.zeros((Array.nbx, Array.nby))
8113
+
8114
+ if fillin:
8115
+ Array.fillin_from_xyz(Data_xyz.xyz)
8116
+
8117
+ return Array
7929
8118
 
7930
8119
  def fillin_from_xyz(self, xyz:np.ndarray):
7931
8120
  """ Remplissage du tableau à partir d'un tableau xyz """
@@ -8027,6 +8216,8 @@ class WolfArray(Element_To_Draw, header_wolf):
8027
8216
  value=np.int16(value)
8028
8217
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER8]:
8029
8218
  value=np.int8(value)
8219
+ elif self.wolftype in [WOLF_ARRAY_FULL_UINTEGER8]:
8220
+ value=np.uint8(value)
8030
8221
  except:
8031
8222
  logging.error(_('Type not supported : {} - {}'.format(value, type(value))))
8032
8223
  logging.warning(_('Masking operation compromised'))
@@ -8190,7 +8381,7 @@ class WolfArray(Element_To_Draw, header_wolf):
8190
8381
  assert type(k_start) == int, "k_start must be an integer"
8191
8382
  assert type(nbz) == int, "nbz must be an integer"
8192
8383
 
8193
- newWolfArray = WolfArray()
8384
+ newWolfArray = WolfArray(nullvalue=self.nullvalue)
8194
8385
  newWolfArray.nbx = nbx
8195
8386
  newWolfArray.nby = nby
8196
8387
  newWolfArray.dx = self.dx
@@ -8383,7 +8574,7 @@ class WolfArray(Element_To_Draw, header_wolf):
8383
8574
 
8384
8575
  if VERSION_RGB==1 :
8385
8576
  if self.nbx * self.nby > 1_000_000 : logging.info(_('Computing colors'))
8386
- if self.wolftype not in [WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_INTEGER8]:
8577
+ if self.wolftype not in [WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_FULL_UINTEGER8]:
8387
8578
  # FIXME: Currently, only some types are supported in Cython/OpenGL library
8388
8579
  self._tmp_float32 = self.array.astype(dtype=np.float32)
8389
8580
  self.rgb = self.mypal.get_rgba(self._tmp_float32)
@@ -8394,6 +8585,7 @@ class WolfArray(Element_To_Draw, header_wolf):
8394
8585
  elif VERSION_RGB in [2 ,3]:
8395
8586
  if self.wolftype not in [WOLF_ARRAY_FULL_SINGLE,
8396
8587
  WOLF_ARRAY_FULL_INTEGER8,
8588
+ WOLF_ARRAY_FULL_UINTEGER8,
8397
8589
  WOLF_ARRAY_FULL_INTEGER16,
8398
8590
  WOLF_ARRAY_FULL_INTEGER16_2,
8399
8591
  WOLF_ARRAY_FULL_INTEGER,
@@ -8561,7 +8753,7 @@ class WolfArray(Element_To_Draw, header_wolf):
8561
8753
  self.mygrid = {}
8562
8754
  self.gridmaxscales = -1
8563
8755
 
8564
- def plot_matplotlib(self):
8756
+ def plot_matplotlib(self, figax:tuple=None, getdata_im:bool=False):
8565
8757
  """
8566
8758
  Plot the array - Matplotlib version
8567
8759
 
@@ -8570,14 +8762,19 @@ class WolfArray(Element_To_Draw, header_wolf):
8570
8762
 
8571
8763
  self.mask_data(self.nullvalue)
8572
8764
  self.updatepalette(0)
8765
+ if figax is None:
8766
+ fig, ax = plt.subplots()
8767
+ else:
8768
+ fig, ax = figax
8573
8769
 
8574
- fig, ax = plt.subplots()
8575
-
8576
- ax.imshow(self.array.transpose(), origin='lower', cmap=self.mypal,
8770
+ im = ax.imshow(self.array.transpose(), origin='lower', cmap=self.mypal,
8577
8771
  extent=(self.origx, self.origx + self.dx * self.nbx, self.origy, self.origy + self.dy * self.nby))
8578
8772
  ax.set_aspect('equal')
8579
8773
 
8580
- return fig, ax
8774
+ if getdata_im:
8775
+ return fig, ax, im
8776
+ else:
8777
+ return fig, ax
8581
8778
 
8582
8779
  def fillonecellgrid(self, curscale, loci, locj, force=False):
8583
8780
  """ Fill one cell of the plotted grid """
@@ -8638,6 +8835,14 @@ class WolfArray(Element_To_Draw, header_wolf):
8638
8835
  elif self.nbnotnull > 0:
8639
8836
  wolfogl.addmeall_int8_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8640
8837
  jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8838
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
8839
+ if self.nbnotnull != self.nbx * self.nby:
8840
+ if self.nbnotnull > 0:
8841
+ wolfogl.addme_uint8_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8842
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8843
+ elif self.nbnotnull > 0:
8844
+ wolfogl.addmeall_uint8_pal(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8845
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst))
8641
8846
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_FULL_INTEGER16_2]:
8642
8847
  if self.nbnotnull != self.nbx * self.nby:
8643
8848
  if self.nbnotnull > 0:
@@ -8694,6 +8899,14 @@ class WolfArray(Element_To_Draw, header_wolf):
8694
8899
  elif self.nbnotnull > 0:
8695
8900
  wolfogl.addmeall_int8_pal_mask(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8696
8901
  jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst), self.array.mask)
8902
+ elif self.wolftype == WOLF_ARRAY_FULL_UINTEGER8:
8903
+ if self.nbnotnull != self.nbx * self.nby:
8904
+ if self.nbnotnull > 0:
8905
+ wolfogl.addme_uint8_pal_mask(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8906
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst), self.array.mask)
8907
+ elif self.nbnotnull > 0:
8908
+ wolfogl.addmeall_uint8_pal_mask(self.array, self.mypal.colorsflt, self.mypal.values, ox, oy, dx, dy, jstart,
8909
+ jend, istart, iend, cursize, self.nullvalue, self.alpha, int(self.mypal.interval_cst), self.array.mask)
8697
8910
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_FULL_INTEGER16_2]:
8698
8911
  if self.nbnotnull != self.nbx * self.nby:
8699
8912
  if self.nbnotnull > 0:
@@ -8764,8 +8977,8 @@ class WolfArray(Element_To_Draw, header_wolf):
8764
8977
  """
8765
8978
  The borders are computed on basis of the current *mask*
8766
8979
 
8767
- :param filename : if provided, write 'sux', 'sux' and 'xy' files
8768
- :param abs : add translation coordinates (Global World Coordinates)
8980
+ :param filename: if provided, write 'sux', 'sux' and 'xy' files
8981
+ :param abs: add translation coordinates (Global World Coordinates)
8769
8982
 
8770
8983
  :return indicesX, indicesY, contourgen, interior
8771
8984
 
@@ -8961,6 +9174,8 @@ class WolfArray(Element_To_Draw, header_wolf):
8961
9174
  return WOLF_ARRAY_FULL_INTEGER
8962
9175
  elif curarray.dtype == np.int8:
8963
9176
  return WOLF_ARRAY_FULL_INTEGER8
9177
+ elif curarray.dtype == np.uint8:
9178
+ return WOLF_ARRAY_FULL_UINTEGER8
8964
9179
 
8965
9180
  self.array = np.ma.array(array.copy())
8966
9181
  self.wolftype = wolftype_from_npz(array)