wolfhece 2.0.55__py3-none-any.whl → 2.1.1__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
@@ -61,7 +61,7 @@ from .opengl.py3d import Cache_WolfArray_plot3D, WolfArray_plot3D
61
61
  WOLF_ARRAY_HILLSHAPE = -1
62
62
  WOLF_ARRAY_FULL_SINGLE = 1
63
63
  WOLF_ARRAY_FULL_DOUBLE = 2
64
- WOLF_ARRAY_SYM_DOUBLE = 8
64
+ WOLF_ARRAY_SYM_DOUBLE = 12
65
65
  WOLF_ARRAY_FULL_LOGICAL = 4
66
66
  WOLF_ARRAY_CSR_DOUBLE = 5
67
67
  WOLF_ARRAY_FULL_INTEGER = 6
@@ -146,7 +146,7 @@ class header_wolf():
146
146
 
147
147
  self.head_blocks = {}
148
148
 
149
- self.nullvalue = 0.
149
+ self._nullvalue = 0.
150
150
 
151
151
  def __str__(self) -> str:
152
152
  """ Return a string representation of the header """
@@ -168,6 +168,14 @@ class header_wolf():
168
168
 
169
169
  return ret
170
170
 
171
+ @property
172
+ def nullvalue(self):
173
+ return self._nullvalue
174
+
175
+ @nullvalue.setter
176
+ def nullvalue(self, value:float):
177
+ self._nullvalue = value
178
+
171
179
  @property
172
180
  def nbdims(self):
173
181
  if self.nbz == 0:
@@ -527,7 +535,7 @@ class header_wolf():
527
535
  return None
528
536
  elif otherbounds[0][1] < mybounds[0][0]:
529
537
  return None
530
- elif otherbounds[1][1] < mybounds[0][1]:
538
+ elif otherbounds[1][1] < mybounds[1][0]:
531
539
  return None
532
540
  else:
533
541
  ox = max(mybounds[0][0], otherbounds[0][0])
@@ -545,20 +553,37 @@ class header_wolf():
545
553
  else:
546
554
  return ([ox, ex], [oy, ey])
547
555
 
548
- def find_union(self, other:"header_wolf") -> tuple[list[float],list[float]]:
556
+ def find_union(self, other:Union["header_wolf", list["header_wolf"]]) -> tuple[list[float],list[float]]:
549
557
  """
550
558
  Find the union of two header
551
559
 
552
560
  :return: tuple of two lists of two floats - ([xmin, xmax],[ymin, ymax])
553
561
  """
554
562
 
555
- mybounds = self.get_bounds()
556
- otherbounds = other.get_bounds()
563
+ if isinstance(other, list):
564
+
565
+ for cur in other:
566
+ assert isinstance(cur, header_wolf), _('All elements in the list must be header_wolf instances')
567
+
568
+ [ox,ex], [oy,ey] = self.get_bounds()
569
+
570
+ for cur in other:
571
+ otherbounds = cur.get_bounds()
557
572
 
558
- ox = min(mybounds[0][0], otherbounds[0][0])
559
- oy = min(mybounds[1][0], otherbounds[1][0])
560
- ex = max(mybounds[0][1], otherbounds[0][1])
561
- ey = max(mybounds[1][1], otherbounds[1][1])
573
+ ox = min(ox, otherbounds[0][0])
574
+ oy = min(oy, otherbounds[1][0])
575
+ ex = max(ex, otherbounds[0][1])
576
+ ey = max(ey, otherbounds[1][1])
577
+
578
+ else:
579
+
580
+ mybounds = self.get_bounds()
581
+ otherbounds = other.get_bounds()
582
+
583
+ ox = min(mybounds[0][0], otherbounds[0][0])
584
+ oy = min(mybounds[1][0], otherbounds[1][0])
585
+ ex = max(mybounds[0][1], otherbounds[0][1])
586
+ ey = max(mybounds[1][1], otherbounds[1][1])
562
587
 
563
588
  return ([ox, ex], [oy, ey])
564
589
 
@@ -773,7 +798,11 @@ class header_wolf():
773
798
  return test
774
799
 
775
800
  def align2grid(self, x1:float, y1:float, eps:float=0.0001) -> tuple[float,float]:
776
- """ Align coordinates to nearest grid point """
801
+ """
802
+ Align coordinates to nearest grid point
803
+ where the grid is defined by the borders of the array.
804
+
805
+ """
777
806
 
778
807
  if x1-self.origx < 0:
779
808
  x2 = np.round((x1 - self.origx + eps) / self.dx) * self.dx + self.origx
@@ -793,6 +822,7 @@ class header_wolf():
793
822
  xstart:float=None, ystart:float=None) -> list[list[float]]:
794
823
  """
795
824
  Rasterize a segment according to the grid
825
+ where the grid is defined by the borders of the array.
796
826
 
797
827
  :param x1: x coordinate of the first point
798
828
  :param y1: y coordinate of the first point
@@ -870,47 +900,65 @@ class header_wolf():
870
900
 
871
901
  return newvector
872
902
 
873
- def get_xy_infootprint_vect(self, myvect: vector) -> np.ndarray:
903
+ def get_xy_infootprint_vect(self, myvect: vector, eps:float = 0.) -> tuple[np.ndarray,np.ndarray]:
874
904
  """
875
905
  Return the coordinates of the cells in the footprint of a vector
876
906
 
877
907
  :param myvect = target vector
908
+ :return: tuple of two numpy arrays - (coordinates, indices)
909
+
878
910
  """
879
911
 
880
- myptsij = self.get_ij_infootprint_vect(myvect)
912
+ myptsij = self.get_ij_infootprint_vect(myvect, eps=eps)
881
913
  mypts=np.asarray(myptsij.copy(),dtype=np.float64)
914
+
882
915
  mypts[:,0] = (mypts[:,0]+.5)*self.dx +self.origx +self.translx
883
916
  mypts[:,1] = (mypts[:,1]+.5)*self.dy +self.origy +self.transly
884
917
 
885
918
  return mypts,myptsij
886
919
 
887
- def get_ij_infootprint_vect(self, myvect: vector) -> np.ndarray:
920
+ def get_ij_infootprint_vect(self, myvect: vector, eps:float = 0.) -> np.ndarray:
888
921
  """
889
922
  Return the indices of the cells in the footprint of a vector
890
923
 
891
924
  :param myvect = target vector
925
+ :return : numpy array of indices
892
926
  """
893
927
 
894
- i1, j1 = self.get_ij_from_xy(myvect.xmin, myvect.ymin)
895
- i2, j2 = self.get_ij_from_xy(myvect.xmax, myvect.ymax)
928
+ i1, j1 = self.get_ij_from_xy(myvect.xmin+eps, myvect.ymin+eps)
929
+ i2, j2 = self.get_ij_from_xy(myvect.xmax-eps, myvect.ymax-eps)
930
+
896
931
  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)
897
932
  j1 = max(j1,0)
898
933
  i2 = min(i2,self.nbx-1)
899
934
  j2 = min(j2,self.nby-1)
935
+
900
936
  xv,yv = np.meshgrid(np.arange(i1,i2+1),np.arange(j1,j2+1))
901
937
  mypts = np.hstack((xv.flatten()[:,np.newaxis],yv.flatten()[:,np.newaxis]))
902
938
 
903
939
  return mypts
904
940
 
905
941
  def convert_xy2ij_np(self,xy):
906
- """ Convert XY coordinates to IJ indices with Numpy without any check/options """
942
+ """
943
+ Convert XY coordinates to IJ indices **(0-based)** with Numpy without any check/options
944
+
945
+ :param xy = numpy array of shape (n,2) with XY coordinates
946
+
947
+ """
948
+
907
949
  return np.asarray((xy[:,0]-self.origx -self.translx)/self.dx-.5,dtype=np.int32), \
908
950
  np.asarray((xy[:,1]-self.origy -self.transly)/self.dy-.5,dtype=np.int32)
909
951
 
910
- def convert_ij2xy_np(self,xy):
911
- """ Convert IJ indices to XY coordinates with Numpy without any check/options """
912
- return np.asarray((xy[:,0]+.5)*self.dx+self.origx +self.translx ,dtype=np.float64), \
913
- np.asarray((xy[:,1]+.5)*self.dy+self.origy +self.transly ,dtype=np.float64)
952
+ def convert_ij2xy_np(self,ij):
953
+ """
954
+ Convert IJ indices **(0-based)** to XY coordinates with Numpy without any check/options
955
+
956
+ :param ij = numpy array of shape (n,2) with IJ indices
957
+
958
+ """
959
+
960
+ return np.asarray((ij[:,0]+.5)*self.dx+self.origx +self.translx ,dtype=np.float64), \
961
+ np.asarray((ij[:,1]+.5)*self.dy+self.origy +self.transly ,dtype=np.float64)
914
962
 
915
963
  class NewArray(wx.Dialog):
916
964
  """
@@ -1149,26 +1197,41 @@ class Ops_Array(wx.Frame):
1149
1197
  self.array_ops = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize)
1150
1198
 
1151
1199
  # panel Selection
1200
+ # -----------------
1201
+
1152
1202
  self.selection = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1153
1203
  self.array_ops.AddPage(self.selection, _("Selection"), True)
1154
1204
 
1155
1205
  # panel Operations
1206
+ # -----------------
1207
+
1156
1208
  self.operation = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1157
1209
  self.array_ops.AddPage(self.operation, _("Operators"), False)
1158
1210
 
1159
1211
  # panel Mask
1212
+ # -----------------
1213
+
1160
1214
  self.mask = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1161
1215
  self.array_ops.AddPage(self.mask, _("Mask"), False)
1162
1216
 
1163
1217
  # panel Interpolation
1218
+ # ---------------------
1219
+
1220
+ # if self.parentarray.nb_blocks>0:
1221
+ # self.Interpolation = None
1222
+ # else:
1164
1223
  self.Interpolation = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1165
1224
  self.array_ops.AddPage(self.Interpolation, _("Interpolation"), False)
1166
1225
 
1167
1226
  # panel Tools/Misc
1227
+ # -----------------
1228
+
1168
1229
  self.tools = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1169
1230
  self.array_ops.AddPage(self.tools, _("Miscellaneous"), False)
1170
1231
 
1171
- # panel PALETTE de couleurs
1232
+ # panel PALETTE de couleurs
1233
+ # -------------------------
1234
+
1172
1235
  self.Palette = PlotPanel(self.array_ops, wx.ID_ANY, toolbar=False)
1173
1236
  self.palgrid = CpGrid(self.Palette, wx.ID_ANY, style=wx.WANTS_CHARS | wx.TE_CENTER)
1174
1237
  self.palapply = wx.Button(self.Palette, wx.ID_ANY, _("Apply"), wx.DefaultPosition, wx.DefaultSize, 0)
@@ -1205,8 +1268,18 @@ class Ops_Array(wx.Frame):
1205
1268
 
1206
1269
  self.palsave = wx.Button(self.Palette, wx.ID_ANY, _("Save to file"), wx.DefaultPosition, wx.DefaultSize, 0)
1207
1270
  self.palsave.SetToolTip(_('Save colormap on .pal file'))
1271
+
1272
+ sizer_loadpal = wx.BoxSizer(wx.HORIZONTAL)
1273
+
1208
1274
  self.palload = wx.Button(self.Palette, wx.ID_ANY, _("Load from file"), wx.DefaultPosition, wx.DefaultSize, 0)
1209
1275
  self.palload.SetToolTip(_('Load colormap from .pal file'))
1276
+
1277
+ self._default_pal = wx.Button(self.Palette, wx.ID_ANY, _("Load precomputed"), wx.DefaultPosition, wx.DefaultSize, 0)
1278
+ self._default_pal.SetToolTip(_('Load a default colormap available in the software'))
1279
+
1280
+ sizer_loadpal.Add(self.palload, 1, wx.EXPAND)
1281
+ sizer_loadpal.Add(self._default_pal, 1, wx.EXPAND)
1282
+
1210
1283
  self.palimage = wx.Button(self.Palette, wx.ID_ANY, _("Create image"), wx.DefaultPosition, wx.DefaultSize, 0)
1211
1284
  self.palimage.SetToolTip(_('Generate colormap image (horizontal, vertical or both) and save to disk'))
1212
1285
  self.paldistribute = wx.Button(self.Palette, wx.ID_ANY, _("Distribute"), wx.DefaultPosition, wx.DefaultSize, 0)
@@ -1240,7 +1313,7 @@ class Ops_Array(wx.Frame):
1240
1313
 
1241
1314
  self.Palette.sizer.Add(self.palchoosecolor, 1, wx.EXPAND)
1242
1315
  self.Palette.sizer.Add(self.palapply, 1, wx.EXPAND)
1243
- self.Palette.sizer.Add(self.palload, 1, wx.EXPAND)
1316
+ self.Palette.sizer.Add(sizer_loadpal, 1, wx.EXPAND)
1244
1317
  self.Palette.sizer.Add(self.palsave, 1, wx.EXPAND)
1245
1318
  self.Palette.sizer.Add(self.palimage, 1, wx.EXPAND)
1246
1319
  self.Palette.sizer.Add(self.paldistribute, 1 , wx.EXPAND)
@@ -1248,6 +1321,8 @@ class Ops_Array(wx.Frame):
1248
1321
  self.array_ops.AddPage(self.Palette, _("Palette"), False)
1249
1322
 
1250
1323
  # HISTOGRAMMES
1324
+ # ----------------
1325
+
1251
1326
  self.histo = PlotPanel(self.array_ops, wx.ID_ANY, toolbar=True)
1252
1327
  self.histoupdate = wx.Button(self.histo, wx.ID_ANY, _("All data..."), wx.DefaultPosition, wx.DefaultSize, 0)
1253
1328
  self.histoupdatezoom = wx.Button(self.histo, wx.ID_ANY, _("On zoom..."), wx.DefaultPosition, wx.DefaultSize, 0)
@@ -1260,58 +1335,70 @@ class Ops_Array(wx.Frame):
1260
1335
  self.array_ops.AddPage(self.histo, _("Histogram"), False)
1261
1336
 
1262
1337
  # LINKS
1338
+ # ----------------
1339
+
1263
1340
  self.links = wx.Panel(self.array_ops, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
1264
1341
  self.array_ops.AddPage(self.links, _("Links"), False)
1265
1342
 
1266
1343
  # Interpolation
1267
- gSizer1 = wx.GridSizer(0, 2, 0, 0)
1268
-
1269
- self.interp2D = wx.Button(self.Interpolation, wx.ID_ANY, _("2D Interpolation on selection"), wx.DefaultPosition,
1270
- wx.DefaultSize, 0)
1271
- self.interp2D.SetToolTip(_('Spatial interpolation based on nodes stored in named groups. \n The interpolation apply only on the current selection.'))
1272
- gSizer1.Add(self.interp2D, 0, wx.EXPAND)
1273
- self.interp2D.Bind(wx.EVT_BUTTON, self.interpolation2D)
1344
+ # ----------------
1274
1345
 
1275
- self.m_button7 = wx.Button(self.Interpolation, wx.ID_ANY, _("Stage/Volume/Surface evaluation"), wx.DefaultPosition,
1276
- wx.DefaultSize, 0)
1277
- self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship. \n Results : plots and arrays saved on disk'))
1346
+ if self.Interpolation is not None:
1278
1347
 
1279
- gSizer1.Add(self.m_button7, 0, wx.EXPAND)
1280
- self.m_button7.Bind(wx.EVT_BUTTON, self.volumesurface)
1348
+ gSizer1 = wx.GridSizer(0, 2, 0, 0)
1281
1349
 
1282
- self.m_button8 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active zone \n polygons"),
1283
- wx.DefaultPosition, wx.DefaultSize, 0)
1284
- self.m_button8.SetToolTip(_('Spatial interpolation based on all polygons in active zone'))
1350
+ self.interp2D = wx.Button(self.Interpolation, wx.ID_ANY, _("2D Interpolation on selection"), wx.DefaultPosition,
1351
+ wx.DefaultSize, 0)
1352
+ self.interp2D.SetToolTip(_('Spatial interpolation based on nodes stored in named groups. \n The interpolation apply only on the current selection.'))
1353
+ gSizer1.Add(self.interp2D, 0, wx.EXPAND)
1354
+ self.interp2D.Bind(wx.EVT_BUTTON, self.interpolation2D)
1285
1355
 
1286
- gSizer1.Add(self.m_button8, 0, wx.EXPAND)
1287
- self.m_button8.Bind(wx.EVT_BUTTON, self.interp2Dpolygons)
1356
+ self.m_button7 = wx.Button(self.Interpolation, wx.ID_ANY, _("Stage/Volume/Surface evaluation"), wx.DefaultPosition,
1357
+ wx.DefaultSize, 0)
1358
+ self.m_button7.SetToolTip(_('Evaluate stage-volume-surface relationship. \n Results : plots and arrays saved on disk'))
1288
1359
 
1289
- self.m_button9 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active zone \n 3D polylines"),
1290
- wx.DefaultPosition, wx.DefaultSize, 0)
1291
- self.m_button9.SetToolTip(_('Spatial interpolation based on all polylines in active zone'))
1360
+ if self.parentarray.nb_blocks>0:
1361
+ self.m_button7.Disable()
1362
+ 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.'))
1292
1363
 
1293
- gSizer1.Add(self.m_button9, 0, wx.EXPAND)
1294
- self.m_button9.Bind(wx.EVT_BUTTON, self.interp2Dpolylines)
1364
+ gSizer1.Add(self.m_button7, 0, wx.EXPAND)
1365
+ self.m_button7.Bind(wx.EVT_BUTTON, self.volumesurface)
1295
1366
 
1296
- self.m_button10 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active vector \n polygon"),
1367
+ self.m_button8 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active zone \n polygons"),
1297
1368
  wx.DefaultPosition, wx.DefaultSize, 0)
1298
- self.m_button10.SetToolTip(_('Spatial interpolation based on active polygon'))
1369
+ self.m_button8.SetToolTip(_('Spatial interpolation based on all polygons in active zone'))
1299
1370
 
1300
- gSizer1.Add(self.m_button10, 0, wx.EXPAND)
1301
- self.m_button10.Bind(wx.EVT_BUTTON, self.interp2Dpolygon)
1371
+ gSizer1.Add(self.m_button8, 0, wx.EXPAND)
1372
+ self.m_button8.Bind(wx.EVT_BUTTON, self.interp2Dpolygons)
1302
1373
 
1303
- self.m_button11 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active vector \n 3D polyline"),
1374
+ self.m_button9 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active zone \n 3D polylines"),
1304
1375
  wx.DefaultPosition, wx.DefaultSize, 0)
1305
- self.m_button11.SetToolTip(_('Spatial interpolation based on active polyline'))
1376
+ self.m_button9.SetToolTip(_('Spatial interpolation based on all polylines in active zone'))
1377
+
1378
+ gSizer1.Add(self.m_button9, 0, wx.EXPAND)
1379
+ self.m_button9.Bind(wx.EVT_BUTTON, self.interp2Dpolylines)
1380
+
1381
+ self.m_button10 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active vector \n polygon"),
1382
+ wx.DefaultPosition, wx.DefaultSize, 0)
1383
+ self.m_button10.SetToolTip(_('Spatial interpolation based on active polygon'))
1306
1384
 
1307
- gSizer1.Add(self.m_button11, 0, wx.EXPAND)
1308
- self.m_button11.Bind(wx.EVT_BUTTON, self.interp2Dpolyline)
1385
+ gSizer1.Add(self.m_button10, 0, wx.EXPAND)
1386
+ self.m_button10.Bind(wx.EVT_BUTTON, self.interp2Dpolygon)
1309
1387
 
1310
- self.Interpolation.SetSizer(gSizer1)
1311
- self.Interpolation.Layout()
1312
- gSizer1.Fit(self.Interpolation)
1388
+ self.m_button11 = wx.Button(self.Interpolation, wx.ID_ANY, _("Interpolation on active vector \n 3D polyline"),
1389
+ wx.DefaultPosition, wx.DefaultSize, 0)
1390
+ self.m_button11.SetToolTip(_('Spatial interpolation based on active polyline'))
1391
+
1392
+ gSizer1.Add(self.m_button11, 0, wx.EXPAND)
1393
+ self.m_button11.Bind(wx.EVT_BUTTON, self.interp2Dpolyline)
1394
+
1395
+ self.Interpolation.SetSizer(gSizer1)
1396
+ self.Interpolation.Layout()
1397
+ gSizer1.Fit(self.Interpolation)
1313
1398
 
1314
1399
  # Tools
1400
+ # ----------------
1401
+
1315
1402
  Toolssizer = wx.BoxSizer(wx.VERTICAL)
1316
1403
 
1317
1404
  hbox = wx.BoxSizer(wx.HORIZONTAL)
@@ -1322,30 +1409,36 @@ class Ops_Array(wx.Frame):
1322
1409
  hbox.Add(self.lbl_nullval, 0, wx.EXPAND|wx.ALL)
1323
1410
  hbox.Add(self.txt_nullval, 1, wx.EXPAND|wx.ALL)
1324
1411
 
1325
- self.ApplyTools = wx.Button(self.tools, wx.ID_ANY, _("Apply null value"), wx.DefaultPosition,
1326
- wx.DefaultSize, 0)
1412
+ self.ApplyTools = wx.Button(self.tools, wx.ID_ANY, _("Apply null value"), wx.DefaultPosition,wx.DefaultSize, 0)
1327
1413
 
1328
1414
 
1329
- self.nullborder = wx.Button(self.tools, wx.ID_ANY, _("Null border"), wx.DefaultPosition,
1330
- wx.DefaultSize, 0)
1415
+ self.nullborder = wx.Button(self.tools, wx.ID_ANY, _("Null border"), wx.DefaultPosition,wx.DefaultSize, 0)
1331
1416
 
1332
- self.filter_zone = wx.Button(self.tools, wx.ID_ANY, _("Filter zone"), wx.DefaultPosition,
1333
- wx.DefaultSize, 0)
1417
+ self.filter_zone = wx.Button(self.tools, wx.ID_ANY, _("Filter zone"), wx.DefaultPosition,wx.DefaultSize, 0)
1418
+
1419
+ self.labelling = wx.Button(self.tools, wx.ID_ANY, _("Labelling"), wx.DefaultPosition,wx.DefaultSize, 0)
1420
+
1421
+ self.extract_selection = wx.Button(self.tools, wx.ID_ANY, _("Extract selection"), wx.DefaultPosition,wx.DefaultSize, 0)
1334
1422
 
1335
1423
  Toolssizer.Add(hbox, 0, wx.EXPAND)
1336
1424
  Toolssizer.Add(self.ApplyTools, 1, wx.EXPAND)
1337
1425
  Toolssizer.Add(self.nullborder, 1, wx.EXPAND)
1338
1426
  Toolssizer.Add(self.filter_zone, 1, wx.EXPAND)
1427
+ Toolssizer.Add(self.labelling, 1, wx.EXPAND)
1428
+ Toolssizer.Add(self.extract_selection, 1, wx.EXPAND)
1339
1429
 
1340
- self.ApplyTools.SetToolTip(_("Save modifications into memmory/object"))
1341
- self.nullborder.SetToolTip(_("Set null value on the border of the array"))
1342
- self.filter_zone.SetToolTip(_("Filter the array based on cotiiguous zones"))
1430
+ self.ApplyTools.SetToolTip(_("Apply Nullvalue into memmory/object"))
1431
+ self.nullborder.SetToolTip(_("Set null value on the border of the array\n\nYou will be asked for the width of the border (in cells)"))
1432
+ self.filter_zone.SetToolTip(_("Filter the array based on contiguous zones\n\nConservation of the ones which contain selected nodes"))
1433
+ self.labelling.SetToolTip(_("Labelling of contiguous zones using Scipy.label function\n\nReplacing the current values by the labels"))
1434
+ self.extract_selection.SetToolTip(_("Extract the current selection"))
1343
1435
 
1344
1436
  self.tools.SetSizer(Toolssizer)
1345
1437
  self.tools.Layout()
1346
1438
  Toolssizer.Fit(self.tools)
1347
1439
 
1348
1440
  # Selection
1441
+ # ----------------
1349
1442
 
1350
1443
  bSizer15 = wx.BoxSizer(wx.VERTICAL)
1351
1444
 
@@ -1372,7 +1465,7 @@ class Ops_Array(wx.Frame):
1372
1465
  self.LaunchSelection = wx.Button(self.selection, wx.ID_ANY,
1373
1466
  _("Action !"), wx.DefaultPosition,
1374
1467
  wx.DefaultSize, 0)
1375
- self.LaunchSelection.SetBackgroundColour((0,128,64,255))
1468
+ # self.LaunchSelection.SetBackgroundColour((0,128,64,255))
1376
1469
  self.LaunchSelection.SetDefault()
1377
1470
  # self.LaunchSelection.SetForegroundColour((255,255,255,255))
1378
1471
  font = wx.Font(12, wx.FONTFAMILY_DECORATIVE, 0, 90, underline = False,faceName ="")
@@ -1413,9 +1506,35 @@ class Ops_Array(wx.Frame):
1413
1506
  bSizer16.Add(self.to_clipboard_str, 0, wx.EXPAND)
1414
1507
  bSizer16.Add(self.to_clipboard_script, 0, wx.EXPAND)
1415
1508
 
1416
- bSizer21.Add(bSizer16, 1, wx.EXPAND, 5)
1509
+ # MultiBlocks
1510
+ # ----------------
1511
+ # Add a listbox to define the active blocks
1512
+
1513
+ if self.parentarray.nb_blocks>0:
1514
+ self._list = wx.ListBox(self.selection,
1515
+ wx.ID_ANY,
1516
+ wx.DefaultPosition,
1517
+ wx.DefaultSize,
1518
+ [_('All')] + [str(i) for i in range(1, self.parentarray.nb_blocks+1)],
1519
+ style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
1520
+ self._list.SetToolTip(_("Active block"))
1521
+ bSizer16.Add(self._list, 1, wx.EXPAND)
1522
+
1523
+ self._list.Bind(wx.EVT_LISTBOX, self.OnBlockSelect)
1524
+
1525
+ # self._open_block = wx.Button(self.selection, wx.ID_ANY, _("Open block"), wx.DefaultPosition,
1526
+ # wx.DefaultSize, 0)
1417
1527
 
1528
+ # self._open_block.SetToolTip(_("Open the Operation manager for the selected block"))
1529
+ # self._open_block.Bind(wx.EVT_BUTTON, self.OnOpenBlock)
1530
+
1531
+ # bSizer16.Add(self._open_block, 0, wx.EXPAND)
1532
+
1533
+
1534
+ bSizer21.Add(bSizer16, 1, wx.EXPAND, 5)
1418
1535
 
1536
+ # VECTORS Manager
1537
+ # ----------------
1419
1538
 
1420
1539
  bSizer17 = wx.BoxSizer(wx.VERTICAL)
1421
1540
 
@@ -1594,11 +1713,14 @@ class Ops_Array(wx.Frame):
1594
1713
  self.ApplyTools.Bind(wx.EVT_BUTTON, self.OnApplyNullvalue)
1595
1714
  self.nullborder.Bind(wx.EVT_BUTTON, self.OnNullBorder)
1596
1715
  self.filter_zone.Bind(wx.EVT_BUTTON, self.OnFilterZone)
1716
+ self.labelling.Bind(wx.EVT_BUTTON, self.OnLabelling)
1717
+ self.extract_selection.Bind(wx.EVT_BUTTON, self.OnExtractSelection)
1597
1718
 
1598
1719
  self.SelectOp.Bind(wx.EVT_BUTTON, self.OnApplyOpSelect)
1599
1720
  self.palapply.Bind(wx.EVT_BUTTON, self.Onupdatepal)
1600
1721
  self.palsave.Bind(wx.EVT_BUTTON, self.Onsavepal)
1601
1722
  self.palload.Bind(wx.EVT_BUTTON, self.Onloadpal)
1723
+ self._default_pal.Bind(wx.EVT_BUTTON, self.Onloaddefaultpal)
1602
1724
  self.palimage.Bind(wx.EVT_BUTTON, self.Onpalimage)
1603
1725
  self.paldistribute.Bind(wx.EVT_BUTTON, self.Onpaldistribute)
1604
1726
  self.palchoosecolor.Bind(wx.EVT_BUTTON, self.OnClickColorPal)
@@ -1606,8 +1728,36 @@ class Ops_Array(wx.Frame):
1606
1728
  self.histoupdatezoom.Bind(wx.EVT_BUTTON, self.OnClickHistoUpdate)
1607
1729
  self.histoupdateerase.Bind(wx.EVT_BUTTON, self.OnClickHistoUpdate)
1608
1730
 
1731
+ def OnBlockSelect(self, event):
1732
+ """ Select block """
1733
+
1734
+ self.parentarray.active_blocks = self._list.GetSelections()
1735
+
1736
+ # def OnOpenBlock(self, event):
1737
+ # """ Open block """
1738
+
1739
+ # sel = self._list.GetSelections()
1740
+
1741
+ # if len(sel)==0:
1742
+ # logging.info('No block selected')
1743
+ # return
1744
+ # elif len(sel)>1:
1745
+ # logging.info('Only one block can be selected')
1746
+ # return
1747
+ # elif sel[0]==0:
1748
+ # logging.info('All blocks selected -- Choose only one specific block')
1749
+ # return
1750
+ # else:
1751
+ # keyblock = getkeyblock(sel[0], addone=False)
1752
+
1753
+ # ops = self.parentarray.myblocks[keyblock].myops
1754
+
1755
+ # if ops is not None:
1756
+ # ops.Show()
1757
+
1609
1758
  def interpolation2D(self, event: wx.MouseEvent):
1610
1759
  """ calling Interpolation 2D """
1760
+
1611
1761
  self.parentarray.interpolation2D()
1612
1762
 
1613
1763
  def Unmaskall(self, event: wx.MouseEvent):
@@ -1615,6 +1765,7 @@ class Ops_Array(wx.Frame):
1615
1765
  Unmask all values in the current array
1616
1766
  @author Pierre Archambeau
1617
1767
  """
1768
+
1618
1769
  self.parentarray.mask_reset()
1619
1770
  self.refresh_array()
1620
1771
 
@@ -1623,201 +1774,109 @@ class Ops_Array(wx.Frame):
1623
1774
  Enlève le masque des éléments sélectionnés
1624
1775
  @author Pierre Archambeau
1625
1776
  """
1626
- curarray: WolfArray
1627
- curarray = self.parentarray
1628
-
1629
- if len(curarray.mngselection.myselection) == 0:
1630
- return
1631
- else:
1632
- destxy = curarray.mngselection.myselection
1633
-
1634
- destij = np.asarray([list(curarray.get_ij_from_xy(x, y)) for x, y in destxy])
1635
1777
 
1636
- curarray.array.mask[destij[:, 0], destij[:, 1]] = False
1778
+ self.parentarray.SelectionData.Unmasksel()
1637
1779
 
1638
- self.refresh_array()
1639
1780
 
1640
1781
  def InvertMask(self, event: wx.MouseEvent):
1641
1782
  """ Invert mask """
1783
+
1642
1784
  self.parentarray.mask_invert()
1643
1785
  self.refresh_array()
1644
1786
 
1645
1787
  def interp2Dpolygons(self, event: wx.MouseEvent):
1646
1788
  """
1647
1789
  Bouton d'interpolation sous tous les polygones d'une zone
1648
- cf _interp2Dpolygon
1790
+ cf WolfArray.interp2Dpolygon
1649
1791
  """
1650
- choices = ["nearest", "linear", "cubic"]
1651
- dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
1652
- ret = dlg.ShowModal()
1653
- if ret == wx.ID_CANCEL:
1654
- dlg.Destroy()
1655
- return
1656
-
1657
- method = dlg.GetStringSelection()
1658
- dlg.Destroy()
1659
-
1660
- actzone = self.active_zone
1661
1792
 
1662
- for curvec in actzone.myvectors:
1663
- curvec: vector
1664
- self._interp2Dpolygon(curvec, method)
1665
-
1666
- self.refresh_array()
1793
+ self.parentarray.SelectionData.interp2Dpolygons(self.active_zone)
1667
1794
 
1668
1795
  def interp2Dpolygon(self, event: wx.MouseEvent):
1669
1796
  """
1670
1797
  Bouton d'interpolation sous un polygone
1671
- cf _interp2Dpolygon
1672
- """
1673
- choices = ["nearest", "linear", "cubic"]
1674
- dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
1675
- ret = dlg.ShowModal()
1676
- if ret == wx.ID_CANCEL:
1677
- dlg.Destroy()
1678
- return
1679
-
1680
- method = dlg.GetStringSelection()
1681
- dlg.Destroy()
1682
-
1683
- self._interp2Dpolygon(self.active_vector, method)
1684
-
1685
- self.refresh_array()
1686
-
1687
- def _interp2Dpolygon(self, vect: vector, method):
1688
- """
1689
- Interpolation sous un polygone
1690
-
1691
- L'interpolation a lieu :
1692
- - uniquement dans les mailles sélectionnées si elles existent
1693
- - dans les mailles contenues dans le polygone sinon
1694
-
1695
- On utilise ensuite "griddata" pour interpoler les altitudes des mailles
1696
- depuis les vertices 3D du polygone
1798
+ cf WolfArray.interp2Dpolygon
1697
1799
  """
1698
- curarray: WolfArray
1699
- curarray = self.parentarray
1700
-
1701
- if len(curarray.mngselection.myselection) == 0:
1702
- destxy = curarray.get_xy_inside_polygon(vect)
1703
- else:
1704
- destxy = curarray.mngselection.myselection
1705
-
1706
- if len(destxy)==0:
1707
- return
1708
-
1709
- destij = np.asarray([list(curarray.get_ij_from_xy(x, y)) for x, y in destxy])
1710
-
1711
- xyz = vect.asnparray3d()
1712
-
1713
- newvalues = griddata(xyz[:, :2], xyz[:, 2], destxy, method=method, fill_value=-99999.)
1714
1800
 
1715
- locmask = np.where(newvalues != -99999.)
1716
- curarray.array.data[destij[locmask][:, 0], destij[locmask][:, 1]] = newvalues[locmask]
1801
+ self.parentarray.SelectionData.interp2Dpolygon(self.active_vector)
1717
1802
 
1718
1803
  def interp2Dpolylines(self, event: wx.MouseEvent):
1719
1804
  """
1720
1805
  Bouton d'interpolation sous toutes les polylignes de la zone
1721
- cf _interp2Dpolyline
1806
+ cf parent.interp2Dpolyline
1722
1807
  """
1723
- actzone = self.active_zone
1724
1808
 
1725
- for curvec in actzone.myvectors:
1726
- curvec: vector
1727
- self._interp2Dpolyline(curvec)
1809
+ self.parentarray.SelectionData.interp2Dpolylines(self.active_zone)
1728
1810
 
1729
- self.refresh_array()
1730
1811
 
1731
1812
  def interp2Dpolyline(self, event: wx.MouseEvent):
1732
1813
  """
1733
1814
  Bouton d'interpolation sous la polyligne active
1734
- cf _interp2Dpolyline
1735
- """
1736
- self._interp2Dpolyline(self.active_vector)
1737
-
1738
- self.refresh_array()
1739
-
1740
- def _interp2Dpolyline(self, vect: vector, usemask=True):
1741
- """
1742
- Interpolation sous une polyligne
1743
-
1744
- L'interpolation a lieu :
1745
- - uniquement dans les mailles sélectionnées si elles existent
1746
- - dans les mailles sous la polyligne sinon
1747
-
1748
- On utilise ensuite "interpolate" de shapely pour interpoler les altitudes des mailles
1749
- depuis les vertices 3D de la polyligne
1815
+ cf parent.interp2Dpolyline
1750
1816
  """
1751
- curarray: WolfArray
1752
- curarray = self.parentarray
1753
-
1754
- vecls = vect.asshapely_ls()
1755
- if len(curarray.mngselection.myselection) == 0:
1756
- allij = curarray.get_ij_under_polyline(vect, usemask)
1757
- allxy = [curarray.get_xy_from_ij(cur[0], cur[1]) for cur in allij]
1758
- else:
1759
- allxy = curarray.mngselection.myselection
1760
- allij = np.asarray([curarray.get_ij_from_xy(x,y) for x,y in allxy])
1761
1817
 
1762
- newz = np.asarray([vecls.interpolate(vecls.project(Point(x, y))).z for x, y in allxy])
1763
- curarray.array.data[allij[:, 0], allij[:, 1]] = newz
1818
+ self.parentarray.SelectionData.interp2Dpolyline(self.active_vector)
1764
1819
 
1765
1820
  def volumesurface(self, event):
1766
1821
  """
1767
1822
  Click on evaluation of stage-storage-surface relation
1768
1823
  """
1769
- self._volumesurface()
1770
-
1771
- def _volumesurface(self, show=True):
1772
- """
1773
- Evaluation of stage-storage-surface relation
1774
- """
1775
- if self.mapviewer is not None:
1776
- if self.mapviewer.linked:
1777
- array1 = self.mapviewer.linkedList[0].active_array
1778
- array2 = self.mapviewer.linkedList[1].active_array
1779
-
1780
- # transfert des mailles sélectionnées dans l'autre matrice
1781
- if array1 is self.parentarray:
1782
- array2.mngselection.myselection = array1.mngselection.myselection.copy()
1783
- if array2 is self.parentarray:
1784
- array1.mngselection.myselection = array2.mngselection.myselection.copy()
1785
-
1786
- if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1787
- myarray = array1
1788
- axs = myarray.volume_estimation()
1789
- myarray = array2
1790
- axs = myarray.volume_estimation(axs)
1791
- else:
1792
- myarray = array1.mngselection.get_newarray()
1793
- axs = myarray.volume_estimation()
1794
- myarray = array2.mngselection.get_newarray()
1795
- axs = myarray.volume_estimation(axs)
1796
- else:
1797
- if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1798
- myarray = self.parentarray
1799
- else:
1800
- myarray = self.parentarray.mngselection.get_newarray()
1801
- myarray.volume_estimation()
1802
- else:
1803
- if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1804
- myarray = self.parentarray
1805
- else:
1806
- myarray = self.parentarray.mngselection.get_newarray()
1807
- myarray.volume_estimation()
1808
1824
 
1809
- if show:
1810
- plt.show()
1825
+ self.parentarray.SelectionData.volumesurface()
1826
+
1827
+ # def _volumesurface(self, show=True):
1828
+ # """
1829
+ # Evaluation of stage-storage-surface relation
1830
+ # """
1831
+
1832
+ # if self.mapviewer is not None:
1833
+ # if self.mapviewer.linked:
1834
+ # array1 = self.mapviewer.linkedList[0].active_array
1835
+ # array2 = self.mapviewer.linkedList[1].active_array
1836
+
1837
+ # # transfert des mailles sélectionnées dans l'autre matrice
1838
+ # if array1 is self.parentarray:
1839
+ # array2.mngselection.myselection = array1.mngselection.myselection.copy()
1840
+ # if array2 is self.parentarray:
1841
+ # array1.mngselection.myselection = array2.mngselection.myselection.copy()
1842
+
1843
+ # if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1844
+ # myarray = array1
1845
+ # axs = myarray.volume_estimation()
1846
+ # myarray = array2
1847
+ # axs = myarray.volume_estimation(axs)
1848
+ # else:
1849
+ # myarray = array1.mngselection.get_newarray()
1850
+ # axs = myarray.volume_estimation()
1851
+ # myarray = array2.mngselection.get_newarray()
1852
+ # axs = myarray.volume_estimation(axs)
1853
+ # else:
1854
+ # if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1855
+ # myarray = self.parentarray
1856
+ # else:
1857
+ # myarray = self.parentarray.mngselection.get_newarray()
1858
+ # myarray.volume_estimation()
1859
+ # else:
1860
+ # if len(self.parentarray.mngselection.myselection) == 0 or self.parentarray.mngselection.myselection == 'all':
1861
+ # myarray = self.parentarray
1862
+ # else:
1863
+ # myarray = self.parentarray.mngselection.get_newarray()
1864
+ # myarray.volume_estimation()
1865
+
1866
+ # if show:
1867
+ # plt.show()
1811
1868
 
1812
1869
  def OnAllSelect(self, event):
1813
1870
  """
1814
1871
  Select all --> just put "all" in "myselection"
1815
1872
  """
1816
- self.parentarray.mngselection.myselection = 'all'
1873
+
1874
+ self.parentarray.SelectionData.select_all()
1817
1875
  self.parentarray.myops.nbselect.SetLabelText('All')
1818
1876
 
1819
1877
  def OnMoveSelect(self, event):
1820
1878
  """Transfert de la sélection courante dans un dictionnaire"""
1879
+
1821
1880
  dlg = wx.TextEntryDialog(self, 'Choose id', 'id?')
1822
1881
  ret = dlg.ShowModal()
1823
1882
  idtxt = dlg.GetValue()
@@ -1826,13 +1885,15 @@ class Ops_Array(wx.Frame):
1826
1885
  ret = dlg.ShowModal()
1827
1886
  color = dlg.GetColourData()
1828
1887
 
1829
- self.parentarray.mngselection.move_selectionto(idtxt, color.GetColour())
1888
+ self.parentarray.SelectionData.move_selectionto(idtxt, color.GetColour())
1830
1889
 
1831
1890
  def reset_selection(self):
1832
1891
  """
1833
1892
  Reset of current selection
1834
1893
  """
1835
- self.parentarray.mngselection.myselection = []
1894
+
1895
+ self.parentarray.SelectionData.reset()
1896
+
1836
1897
  self.nbselect.SetLabelText('0')
1837
1898
  self.minx.SetLabelText('0')
1838
1899
  self.miny.SetLabelText('0')
@@ -1843,13 +1904,15 @@ class Ops_Array(wx.Frame):
1843
1904
  """
1844
1905
  Reset of current selection and stored ones
1845
1906
  """
1907
+
1846
1908
  self.reset_selection()
1847
- self.parentarray.mngselection.selections = {}
1909
+ self.parentarray.SelectionData.reset_all()
1848
1910
 
1849
1911
  def OnResetSelect(self, event):
1850
1912
  """
1851
1913
  Click on Reset of current selection
1852
1914
  """
1915
+
1853
1916
  self.reset_selection()
1854
1917
  self.refresh_array()
1855
1918
 
@@ -1857,6 +1920,7 @@ class Ops_Array(wx.Frame):
1857
1920
  """
1858
1921
  Click on reset all
1859
1922
  """
1923
+
1860
1924
  self.reset_all_selection()
1861
1925
  self.refresh_array()
1862
1926
 
@@ -1874,7 +1938,7 @@ class Ops_Array(wx.Frame):
1874
1938
 
1875
1939
  selectobj = self.parentarray.mngselection
1876
1940
 
1877
- if len(selectobj.selections) > 0:
1941
+ if selectobj.nb > 0:
1878
1942
  choices = [_("Current selection")]
1879
1943
  for cur in selectobj.selections.items():
1880
1944
  choices.append(cur[0])
@@ -1934,10 +1998,11 @@ class Ops_Array(wx.Frame):
1934
1998
  # condition value
1935
1999
  curcondvalue = float(self.condvalue.GetValue())
1936
2000
 
1937
- self.parentarray.mngselection.condition_select(curcond, curcondvalue)
2001
+ self.parentarray.SelectionData.condition_select(curcond, curcondvalue)
1938
2002
 
1939
2003
  def OnApplyNullvalue(self, event:wx.MouseEvent):
1940
2004
  """ Apply null value to the array """
2005
+
1941
2006
  newnull = self.txt_nullval.Value
1942
2007
  if newnull.lower() == 'nan':
1943
2008
  newnull = np.nan
@@ -1945,12 +2010,14 @@ class Ops_Array(wx.Frame):
1945
2010
  newnull = float(newnull)
1946
2011
 
1947
2012
  if self.parentarray.nullvalue!= newnull:
2013
+
1948
2014
  self.parentarray.nullvalue = newnull
1949
2015
  self.parentarray.mask_data(newnull)
1950
2016
  self.refresh_array()
1951
2017
 
1952
2018
  def refresh_array(self):
1953
2019
  """ Force refresh of the parent array """
2020
+
1954
2021
  if self.parentarray is not None:
1955
2022
  self.parentarray.reset_plot()
1956
2023
 
@@ -1971,8 +2038,19 @@ class Ops_Array(wx.Frame):
1971
2038
  def OnFilterZone(self, event:wx.MouseEvent):
1972
2039
  """ Filter the array based on contiguous zones """
1973
2040
 
2041
+ pass
1974
2042
  self.parentarray.filter_zone()
1975
2043
 
2044
+ def OnLabelling(self, event:wx.MouseEvent):
2045
+ """ Labelling of contiguous zones """
2046
+
2047
+ self.parentarray.labelling()
2048
+
2049
+ def OnExtractSelection(self, event:wx.MouseEvent):
2050
+ """ Extract the current selection """
2051
+
2052
+ self.parentarray.extract_selection()
2053
+
1976
2054
  def OnApplyOpMath(self, event:wx.MouseEvent):
1977
2055
  """ Apply math operator to the array """
1978
2056
 
@@ -1995,7 +2073,7 @@ class Ops_Array(wx.Frame):
1995
2073
  else:
1996
2074
  curcondvalue = float(curcondvalue)
1997
2075
 
1998
- self.parentarray.mngselection.treat_select(curop, curcond, curopvalue, curcondvalue)
2076
+ self.parentarray.SelectionData.treat_select(curop, curcond, curopvalue, curcondvalue)
1999
2077
 
2000
2078
  def Onmask(self, event:wx.MouseEvent):
2001
2079
  """ Mask nodes based on condition """
@@ -2006,7 +2084,7 @@ class Ops_Array(wx.Frame):
2006
2084
  curopvalue = float(self.opvalue.GetValue())
2007
2085
  curcondvalue = float(self.condvalue.GetValue())
2008
2086
 
2009
- self.parentarray.mngselection.mask_condition(curop, curcond, curopvalue, curcondvalue)
2087
+ self.parentarray.SelectionData.mask_condition(curop, curcond, curopvalue, curcondvalue)
2010
2088
  self.refresh_array()
2011
2089
 
2012
2090
  def OnManageVectors(self, event:wx.MouseEvent):
@@ -2122,7 +2200,7 @@ class Ops_Array(wx.Frame):
2122
2200
  """ Select nodes inside a vector or set action to add vertices to a vector by clicks"""
2123
2201
 
2124
2202
  if vect.nbvertices > 2:
2125
- self.parentarray.mngselection.select_insidepoly(vect)
2203
+ self.parentarray.SelectionData.select_insidepoly(vect)
2126
2204
 
2127
2205
  elif self.mapviewer is not None:
2128
2206
  if vect.nbvertices < 3:
@@ -2160,7 +2238,7 @@ class Ops_Array(wx.Frame):
2160
2238
  """ Select nodes along a vector or set action to add vertices to a vector by clicks """
2161
2239
 
2162
2240
  if vect.nbvertices > 1:
2163
- self.parentarray.mngselection.select_underpoly(vect)
2241
+ self.parentarray.SelectionData.select_underpoly(vect)
2164
2242
 
2165
2243
  elif self.mapviewer is not None:
2166
2244
  if vect.nbvertices < 2:
@@ -2239,6 +2317,7 @@ class Ops_Array(wx.Frame):
2239
2317
 
2240
2318
  def onclose(self, event:wx.MouseEvent):
2241
2319
  """ Hide the window """
2320
+
2242
2321
  self.Hide()
2243
2322
 
2244
2323
  def onshow(self, event:wx.MouseEvent):
@@ -2291,6 +2370,7 @@ class Ops_Array(wx.Frame):
2291
2370
 
2292
2371
  def Onloadpal(self, event:wx.MouseEvent):
2293
2372
  """ Load palette from file """
2373
+
2294
2374
  myarray: WolfArray
2295
2375
  myarray = self.parentarray
2296
2376
  myarray.mypal.readfile()
@@ -2300,6 +2380,36 @@ class Ops_Array(wx.Frame):
2300
2380
 
2301
2381
  self.refresh_array()
2302
2382
 
2383
+ def Onloaddefaultpal(self, event:wx.MouseEvent):
2384
+ """ Load default palette """
2385
+
2386
+ import glob
2387
+
2388
+ # list of all .pal file in model directory
2389
+
2390
+ dirpal = os.path.join(os.path.dirname(__file__), 'models')
2391
+
2392
+ listpal = glob.glob(dirpal + '/*.pal')
2393
+
2394
+ if len(listpal) == 0:
2395
+ logging.info('No default palette found')
2396
+ return
2397
+
2398
+ listpal = [os.path.basename(i) for i in listpal]
2399
+
2400
+ dlg = wx.SingleChoiceDialog(None, 'Choose the default palette', 'Default palette', listpal)
2401
+ ret = dlg.ShowModal()
2402
+
2403
+ if ret == wx.ID_CANCEL:
2404
+ dlg.Destroy()
2405
+
2406
+ self.parentarray.mypal.readfile(dirpal + '/' + dlg.GetStringSelection())
2407
+
2408
+ self.parentarray.mypal.automatic = False
2409
+ self.palauto.SetValue(0)
2410
+
2411
+ self.refresh_array()
2412
+
2303
2413
  def Onpalimage(self, event:wx.MouseEvent):
2304
2414
  """ Create image from palette """
2305
2415
  myarray: WolfArray
@@ -2432,19 +2542,17 @@ class SelectionData():
2432
2542
 
2433
2543
  The selected nodes are stored using their "world" spatial coordinates so that they can be easily transferred to other objects.
2434
2544
  """
2545
+
2435
2546
  myselection:list[tuple[float, float]]
2436
2547
  selections: dict[str:dict['select':list[tuple[float, float]], 'idgllist':int, 'color':list[float]]]
2437
2548
 
2438
2549
  def __init__(self, parent:"WolfArray") -> None:
2550
+
2439
2551
  self.parent: WolfArray
2440
2552
  self.parent = parent
2441
2553
 
2442
2554
  self.wx_exists = wx.GetApp() is not None
2443
2555
 
2444
- #copy of the resolution
2445
- self.dx = parent.dx
2446
- self.dy = parent.dy
2447
-
2448
2556
  self.myselection = []
2449
2557
  self.selections = {}
2450
2558
 
@@ -2452,6 +2560,59 @@ class SelectionData():
2452
2560
  self.hideselection = False
2453
2561
  self.numlist_select = 0 # OpenGL list index
2454
2562
 
2563
+ @property
2564
+ def dx(self) -> float:
2565
+ """ Resolution in x """
2566
+
2567
+ if self.parent is None:
2568
+ return 0.
2569
+ else:
2570
+ return self.parent.dx
2571
+
2572
+ @property
2573
+ def dy(self) -> float:
2574
+ """ Resolution in y """
2575
+
2576
+ if self.parent is None:
2577
+ return 0.
2578
+ else:
2579
+ return self.parent.dy
2580
+
2581
+ @property
2582
+ def nb(self) -> int:
2583
+ """ Number of selected nodes """
2584
+
2585
+ return len(self.myselection)
2586
+
2587
+ def Unmasksel(self, resetplot:bool=True):
2588
+ """ Unmask selection """
2589
+
2590
+ curarray: WolfArray
2591
+ curarray = self.parent
2592
+
2593
+ if self.nb == 0:
2594
+ return
2595
+ else:
2596
+ destxy = self.myselection
2597
+
2598
+ destij = np.asarray([list(curarray.get_ij_from_xy(x, y)) for x, y in destxy])
2599
+
2600
+ curarray.array.mask[destij[:, 0], destij[:, 1]] = False
2601
+
2602
+ if resetplot:
2603
+ curarray.reset_plot()
2604
+
2605
+ def reset(self):
2606
+ """ Reset the selection """
2607
+
2608
+ self.myselection = []
2609
+
2610
+ def reset_all(self):
2611
+ """ Reset the selection """
2612
+
2613
+ self.myselection = []
2614
+ self.selections = {}
2615
+
2455
2616
  def get_string(self, which:str = None) -> str:
2456
2617
  """ Get string of the current selection or of a stored one """
2457
2618
 
@@ -2536,7 +2697,7 @@ class SelectionData():
2536
2697
  logging.warning(_('Cannot open the clipboard'))
2537
2698
 
2538
2699
 
2539
- def move_selectionto(self, idx:str, color:list[float]):
2700
+ def move_selectionto(self, idx:str, color:list[float], resetplot:bool=True):
2540
2701
  """
2541
2702
  Transfer current selection to dictionary
2542
2703
 
@@ -2556,7 +2717,10 @@ class SelectionData():
2556
2717
  curdict['color'] = color
2557
2718
 
2558
2719
  self.myselection = [] # reset current selection
2559
- self.update_nb_nodes_sections()
2720
+ self.update_nb_nodes_selection()
2721
+
2722
+ if resetplot:
2723
+ self.parent.reset_plot()
2560
2724
 
2561
2725
  def plot_selection(self):
2562
2726
  """ Plot current selection and stored selections """
@@ -2594,6 +2758,10 @@ class SelectionData():
2594
2758
 
2595
2759
  #FIXME : Is it a good idea to use SHADER rather than list ?
2596
2760
  if self.update_plot_selection:
2761
+
2762
+ dx = self.dx
2763
+ dy = self.dy
2764
+
2597
2765
  if loclist != 0:
2598
2766
  glDeleteLists(loclist, 1)
2599
2767
 
@@ -2603,10 +2771,10 @@ class SelectionData():
2603
2771
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
2604
2772
  glBegin(GL_QUADS)
2605
2773
  for cursel in curlist:
2606
- x1 = cursel[0] - self.dx / 2.
2607
- x2 = cursel[0] + self.dx / 2.
2608
- y1 = cursel[1] - self.dy / 2.
2609
- y2 = cursel[1] + self.dy / 2.
2774
+ x1 = cursel[0] - dx / 2.
2775
+ x2 = cursel[0] + dx / 2.
2776
+ y1 = cursel[1] - dy / 2.
2777
+ y2 = cursel[1] + dy / 2.
2610
2778
  glColor3f(color[0], color[1], color[2])
2611
2779
  glVertex2f(x1, y1)
2612
2780
  glVertex2f(x2, y1)
@@ -2617,10 +2785,10 @@ class SelectionData():
2617
2785
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
2618
2786
  for cursel in curlist:
2619
2787
  glBegin(GL_LINE_STRIP)
2620
- x1 = cursel[0] - self.dx / 2.
2621
- x2 = cursel[0] + self.dx / 2.
2622
- y1 = cursel[1] - self.dy / 2.
2623
- y2 = cursel[1] + self.dy / 2.
2788
+ x1 = cursel[0] - dx / 2.
2789
+ x2 = cursel[0] + dx / 2.
2790
+ y1 = cursel[1] - dy / 2.
2791
+ y2 = cursel[1] + dy / 2.
2624
2792
  glColor3f(0., 1., 0.)
2625
2793
  glVertex2f(x1, y1)
2626
2794
  glVertex2f(x2, y1)
@@ -2653,7 +2821,10 @@ class SelectionData():
2653
2821
 
2654
2822
  if self.parent.check_bounds_ij(i, j):
2655
2823
  # if i>=0 and j>=0 and i<self.parent.nbx and j<self.parent.nby:
2656
- self.add_node_to_selectionij(i, j, verif)
2824
+ self._add_node_to_selectionij(i, j, verif)
2825
+ return 0 # useful for MB
2826
+ else:
2827
+ return -1 # useful for MB
2657
2828
 
2658
2829
  def add_nodes_to_selection(self, xy:list[float], verif:bool=True):
2659
2830
  """
@@ -2666,9 +2837,9 @@ class SelectionData():
2666
2837
  # on repasse par les i,j car les coordonnées transférées peuvent venir d'un click souris
2667
2838
  # le but est de ne conserver que les coordonnées des CG de mailles
2668
2839
  ij = [self.parent.get_ij_from_xy(x, y) for x, y in xy]
2669
- self.add_nodes_to_selectionij(ij, verif)
2840
+ self._add_nodes_to_selectionij(ij, verif)
2670
2841
 
2671
- def add_node_to_selectionij(self, i:int, j:int, verif=True):
2842
+ def _add_node_to_selectionij(self, i:int, j:int, verif=True):
2672
2843
  """
2673
2844
  Add one ij coordinate to the selection
2674
2845
 
@@ -2676,6 +2847,7 @@ class SelectionData():
2676
2847
  :param j: j coordinate
2677
2848
  :param verif: if True, the coordinates are checked to avoid duplicates
2678
2849
  """
2850
+
2679
2851
  x1, y1 = self.parent.get_xy_from_ij(i, j)
2680
2852
 
2681
2853
  if isinstance(self.myselection, str):
@@ -2688,12 +2860,16 @@ class SelectionData():
2688
2860
  ret = -1
2689
2861
  if ret >= 0:
2690
2862
  self.myselection.pop(ret)
2863
+
2864
+ return 0
2691
2865
  else:
2692
2866
  self.myselection.append((x1, y1))
2867
+ return 0
2693
2868
  else:
2694
2869
  self.myselection.append((x1, y1))
2870
+ return 0
2695
2871
 
2696
- def add_nodes_to_selectionij(self, ij:list[tuple[float, float]], verif:bool=True):
2872
+ def _add_nodes_to_selectionij(self, ij:list[tuple[float, float]], verif:bool=True):
2697
2873
  """
2698
2874
  Add multiple ij coordinates to the selection
2699
2875
 
@@ -2742,7 +2918,7 @@ class SelectionData():
2742
2918
  nbini = len(self.myselection)
2743
2919
 
2744
2920
  myvect.find_minmax()
2745
- mypoints,_ = self.parent.get_xy_infootprint_vect(myvect)
2921
+ mypoints, _tmpij = self.parent.get_xy_infootprint_vect(myvect)
2746
2922
  path = mpltPath.Path(myvect.asnparray())
2747
2923
  inside = path.contains_points(mypoints)
2748
2924
 
@@ -2759,7 +2935,7 @@ class SelectionData():
2759
2935
  self.condition_select('Mask',0)
2760
2936
 
2761
2937
  self.hideselection=False
2762
- self.update_nb_nodes_sections()
2938
+ self.update_nb_nodes_selection()
2763
2939
 
2764
2940
  def select_underpoly(self, myvect: vector):
2765
2941
  """ Select nodes along a polyline """
@@ -2769,16 +2945,17 @@ class SelectionData():
2769
2945
  myvect.find_minmax()
2770
2946
  mypoints = self.parent.get_ij_under_polyline(myvect)
2771
2947
 
2772
- self.add_nodes_to_selectionij(mypoints, verif=nbini != 0)
2948
+ self._add_nodes_to_selectionij(mypoints, verif=nbini != 0)
2773
2949
 
2774
2950
  if self.parent.myops is not None:
2775
2951
  if self.parent.myops.selectrestricttomask.IsChecked():
2776
2952
  self.condition_select('Mask',0)
2777
2953
 
2778
- self.update_nb_nodes_sections()
2954
+ self.update_nb_nodes_selection()
2779
2955
 
2780
- def update_nb_nodes_sections(self):
2956
+ def update_nb_nodes_selection(self):
2781
2957
  """ Update the number of selected nodes """
2958
+
2782
2959
  if self.myselection=='all':
2783
2960
  nb = self.parent.nbnotnull
2784
2961
  else:
@@ -2800,13 +2977,31 @@ class SelectionData():
2800
2977
  else:
2801
2978
  self.update_plot_selection = True
2802
2979
 
2980
+ if nb>0:
2981
+ if self.myselection=='all':
2982
+ [xmin, xmax], [ymin, ymax] = self.parent.get_bounds()
2983
+ else:
2984
+ xmin = np.min(np.asarray(self.myselection)[:, 0])
2985
+ ymin = np.min(np.asarray(self.myselection)[:, 1])
2986
+ xmax = np.max(np.asarray(self.myselection)[:, 0])
2987
+ ymax = np.max(np.asarray(self.myselection)[:, 1])
2988
+ else:
2989
+ xmin = -99999.
2990
+ ymin = -99999.
2991
+ xmax = -99999.
2992
+ ymax = -99999.
2993
+
2803
2994
  if self.parent.myops is not None:
2995
+
2804
2996
  self.parent.myops.nbselect.SetLabelText(str(nb))
2805
2997
  if nb>0:
2806
- self.parent.myops.minx.SetLabelText(str(np.min(np.asarray(self.myselection)[:, 0])))
2807
- self.parent.myops.miny.SetLabelText(str(np.min(np.asarray(self.myselection)[:, 1])))
2808
- self.parent.myops.maxx.SetLabelText(str(np.max(np.asarray(self.myselection)[:, 0])))
2809
- self.parent.myops.maxy.SetLabelText(str(np.max(np.asarray(self.myselection)[:, 1])))
2998
+
2999
+ self.parent.myops.minx.SetLabelText('{:.3f}'.format(xmin))
3000
+ self.parent.myops.miny.SetLabelText('{:.3f}'.format(ymin))
3001
+ self.parent.myops.maxx.SetLabelText('{:.3f}'.format(xmax))
3002
+ self.parent.myops.maxy.SetLabelText('{:.3f}'.format(ymax))
3003
+
3004
+ return nb, xmin, xmax, ymin, ymax
2810
3005
 
2811
3006
  def condition_select(self, cond, condval, condval2=0, usemask=False):
2812
3007
  array = self.parent.array
@@ -2867,7 +3062,7 @@ class SelectionData():
2867
3062
  # interval without equality
2868
3063
  ij = np.argwhere(((array<condval) | (array>condval2)) & mask)
2869
3064
 
2870
- self.add_nodes_to_selectionij(ij, nbini != 0)
3065
+ self._add_nodes_to_selectionij(ij, nbini != 0)
2871
3066
  except:
2872
3067
  logging.error(_('Error in condition_select -- nbini == 0 ! -- Please report this bug, specifying the context'))
2873
3068
  return
@@ -2904,7 +3099,7 @@ class SelectionData():
2904
3099
  ij = np.argwhere(((array[ijall[:, 0], ijall[:, 1]]<condval) | (array[ijall[:, 0], ijall[:, 1]]>condval2)) & (mask[ijall[:, 0], ijall[:, 1]]))
2905
3100
 
2906
3101
  ij = ij.flatten()
2907
- self.add_nodes_to_selectionij(ijall[ij], nbini != 0)
3102
+ self._add_nodes_to_selectionij(ijall[ij], nbini != 0)
2908
3103
  except:
2909
3104
  logging.error(_('Error in condition_select ! -- Please report this bug, specifying the context'))
2910
3105
  return
@@ -2945,7 +3140,7 @@ class SelectionData():
2945
3140
  # Mask
2946
3141
  ij = np.argwhere(np.logical_not(array.mask))
2947
3142
 
2948
- self.add_nodes_to_selectionij(ij, nbini != 0)
3143
+ self._add_nodes_to_selectionij(ij, nbini != 0)
2949
3144
  except:
2950
3145
  logging.error(_('Error in condition_select -- nbini == 0 ! -- Please report this bug, specifying the context'))
2951
3146
  return
@@ -2989,12 +3184,12 @@ class SelectionData():
2989
3184
  ij = np.argwhere(np.logical_not(array.mask[ijall[:, 0], ijall[:, 1]]))
2990
3185
 
2991
3186
  ij = ij.flatten()
2992
- self.add_nodes_to_selectionij(ijall[ij], nbini != 0)
3187
+ self._add_nodes_to_selectionij(ijall[ij], nbini != 0)
2993
3188
  except:
2994
3189
  logging.error(_('Error in condition_select ! -- Please report this bug, specifying the context'))
2995
3190
  return
2996
3191
 
2997
- self.update_nb_nodes_sections()
3192
+ self.update_nb_nodes_selection()
2998
3193
 
2999
3194
  def treat_select(self, op, cond, opval, condval):
3000
3195
  # operationChoices = [ u"+", u"-", u"*", u"/", u"replace'" ]
@@ -3289,34 +3484,48 @@ class SelectionData():
3289
3484
 
3290
3485
  return z
3291
3486
 
3292
- def get_header(self):
3293
- array: WolfArray
3487
+ def _get_header(self):
3488
+ """ Header corresponding to the selection """
3294
3489
 
3295
3490
  array = self.parent
3296
3491
  sel = np.asarray(self.myselection)
3297
3492
 
3298
3493
  myhead = header_wolf()
3299
3494
 
3300
- myhead.dx = array.dx
3301
- myhead.dy = array.dy
3302
- myhead.translx = 0. # array.translx
3303
- myhead.transly = 0. # array.transly
3495
+ if self.dx == 0. or self.dy == 0.:
3496
+ logging.error(_('dx or dy is null in get_header - Abort !'))
3497
+ return None
3498
+
3499
+ myhead.dx = self.dx
3500
+ myhead.dy = self.dy
3501
+ myhead.translx = 0.
3502
+ myhead.transly = 0.
3304
3503
 
3305
- myhead.origx = np.amin(sel[:, 0]) - array.dx / 2.
3306
- myhead.origy = np.amin(sel[:, 1]) - array.dy / 2.
3504
+ myhead.origx = np.amin(sel[:, 0]) - self.dx / 2.
3505
+ myhead.origy = np.amin(sel[:, 1]) - self.dy / 2.
3307
3506
 
3308
- ex = np.amax(sel[:, 0]) + array.dx / 2.
3309
- ey = np.amax(sel[:, 1]) + array.dy / 2.
3507
+ ex = np.amax(sel[:, 0]) + self.dx / 2.
3508
+ ey = np.amax(sel[:, 1]) + self.dy / 2.
3310
3509
 
3311
- myhead.nbx = int((ex - myhead.origx) / array.dx)
3312
- myhead.nby = int((ey - myhead.origy) / array.dy)
3510
+ myhead.nbx = int((ex - myhead.origx) / self.dx)
3511
+ myhead.nby = int((ey - myhead.origy) / self.dy)
3313
3512
 
3314
3513
  return myhead
3315
3514
 
3316
3515
  def get_newarray(self):
3516
+ """ Create a new array from the selection """
3517
+
3518
+ if self.nb == 0:
3519
+ return None
3317
3520
 
3318
3521
  newarray = WolfArray()
3319
- newarray.init_from_header(self.get_header())
3522
+
3523
+ lochead = self._get_header()
3524
+ if lochead is None:
3525
+ logging.error(_('Error in get_newarray !'))
3526
+ return
3527
+
3528
+ newarray.init_from_header(self._get_header())
3320
3529
 
3321
3530
  sel = np.asarray(self.myselection)
3322
3531
  if len(sel) == 1:
@@ -3333,6 +3542,325 @@ class SelectionData():
3333
3542
 
3334
3543
  return newarray
3335
3544
 
3545
+ def select_all(self):
3546
+ """ Select all nodes """
3547
+
3548
+ self.myselection = 'all'
3549
+ self.update_nb_nodes_selection()
3550
+
3551
+ def interp2Dpolygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"] = None, resetplot:bool = True):
3552
+ """
3553
+ Interpolation sous tous les polygones d'une zone
3554
+ cf parent.interp2Dpolygon
3555
+ """
3556
+
3557
+ if method is None:
3558
+ choices = ["nearest", "linear", "cubic"]
3559
+ dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
3560
+ ret = dlg.ShowModal()
3561
+ if ret == wx.ID_CANCEL:
3562
+ dlg.Destroy()
3563
+ return
3564
+
3565
+ method = dlg.GetStringSelection()
3566
+ dlg.Destroy()
3567
+
3568
+ self.parent.interpolate_on_polygons(working_zone, method)
3569
+
3570
+ if resetplot:
3571
+ self.parent.reset_plot()
3572
+
3573
+ def interp2Dpolygon(self, working_vector:vector, method:Literal["nearest", "linear", "cubic"] = None, resetplot:bool = True):
3574
+ """
3575
+ Interpolation sous un polygone
3576
+ cf parent.interp2Dpolygon
3577
+ """
3578
+
3579
+ if method is None:
3580
+ choices = ["nearest", "linear", "cubic"]
3581
+ dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
3582
+ ret = dlg.ShowModal()
3583
+ if ret == wx.ID_CANCEL:
3584
+ dlg.Destroy()
3585
+ return
3586
+
3587
+ method = dlg.GetStringSelection()
3588
+ dlg.Destroy()
3589
+
3590
+ self.parent.interpolate_on_polygon(working_vector, method)
3591
+
3592
+ if resetplot:
3593
+ self.parent.reset_plot()
3594
+
3595
+ def interp2Dpolylines(self, working_zone:zone, resetplot:bool = True):
3596
+ """
3597
+ Interpolation sous toutes les polylignes de la zone
3598
+ cf parent.interp2Dpolyline
3599
+ """
3600
+
3601
+ self.parent.interpolate_on_polylines(working_zone)
3602
+
3603
+ if resetplot:
3604
+ self.parent.reset_plot()
3605
+
3606
+ def interp2Dpolyline(self, working_vector:vector, resetplot:bool = True):
3607
+ """
3608
+ Interpolation sous la polyligne active
3609
+ cf parent.interp2Dpolyline
3610
+ """
3611
+
3612
+ self.parent.interpolate_on_polyline(working_vector)
3613
+
3614
+ if resetplot:
3615
+ self.parent.reset_plot()
3616
+
3617
+
3618
+ def copy(self, source:"SelectionData"):
3619
+
3620
+ self.myselection = source.myselection.copy()
3621
+
3622
+ def volumesurface(self, show=True):
3623
+ """
3624
+ Evaluation of stage-storage-surface relation
3625
+ """
3626
+
3627
+ if self.parent.get_mapviewer() is not None:
3628
+
3629
+ mapviewer = self.parent.get_mapviewer()
3630
+
3631
+ if mapviewer.linked:
3632
+
3633
+ array1:WolfArray = mapviewer.linkedList[0].active_array
3634
+ array2:WolfArray = mapviewer.linkedList[1].active_array
3635
+
3636
+ # transfert des mailles sélectionnées dans l'autre matrice
3637
+ if array1 is self.parent:
3638
+ array2.SelectionData.copy(array1.SelectionData)
3639
+
3640
+ if array2 is self.parent:
3641
+ array1.SelectionData.copy(array2.SelectionData)
3642
+
3643
+ if self.nb == 0 or self.myselection == 'all':
3644
+ myarray = array1
3645
+ axs = myarray.volume_estimation()
3646
+
3647
+ myarray = array2
3648
+ axs = myarray.volume_estimation(axs)
3649
+ else:
3650
+ myarray = array1.mngselection.get_newarray()
3651
+ axs = myarray.volume_estimation()
3652
+
3653
+ myarray = array2.mngselection.get_newarray()
3654
+ axs = myarray.volume_estimation(axs)
3655
+ else:
3656
+ if len(self.parent.mngselection.myselection) == 0 or self.parent.mngselection.myselection == 'all':
3657
+ myarray = self.parent
3658
+ else:
3659
+ myarray = self.parent.mngselection.get_newarray()
3660
+
3661
+ myarray.volume_estimation()
3662
+ else:
3663
+ if self.nb == 0 or self.myselection == 'all':
3664
+ myarray = self.parent
3665
+ else:
3666
+ myarray = self.get_newarray()
3667
+
3668
+ myarray.volume_estimation()
3669
+
3670
+ if show:
3671
+ plt.show()
3672
+
3673
+ class SelectionDataMB(SelectionData):
3674
+ """ Extension of SelectionData to manage multiple blocks """
3675
+
3676
+ def __init__(self, parent:"WolfArrayMB"):
3677
+ SelectionData.__init__(self, parent)
3678
+
3679
+ self.parent:"WolfArrayMB" = parent
3680
+
3681
+ @property
3682
+ def nb(self):
3683
+
3684
+ return np.sum([cur.SelectionData.nb for cur in self.parent.active_blocks])
3685
+
3686
+ def Unmasksel(self):
3687
+
3688
+ for curblock in self.parent.active_blocks:
3689
+ curblock.SelectionData.Unmasksel(resetplot=False)
3690
+
3691
+ self.parent.reset_plot()
3692
+
3693
+ def reset(self):
3694
+
3695
+ for curblock in self.parent.active_blocks:
3696
+ curblock.SelectionData.reset()
3697
+
3698
+ def select_all(self):
3699
+
3700
+ for curblock in self.parent.active_blocks:
3701
+ curblock.SelectionData.select_all()
3702
+
3703
+ def reset_all(self):
3704
+ """ Reset the selection """
3705
+
3706
+ for curblock in self.parent.active_blocks:
3707
+ curblock.SelectionData.reset_all()
3708
+
3709
+ def get_string(self, which:str = None) -> str:
3710
+
3711
+ logging.error(_('Not yet implemented for Multi-Blocks'))
3712
+
3713
+ def get_script(self, which:int = None) -> str:
3714
+
3715
+ logging.error(_('Not yet implemented for Multi-Blocks'))
3716
+
3717
+ def get_newarray(self):
3718
+
3719
+ logging.error(_('Not yet implemented for Multi-Blocks'))
3720
+
3721
+ def add_node_to_selection(self, x:float, y:float, verif:bool=True):
3722
+ """ Add a node to the selection """
3723
+
3724
+ for curblock in self.parent.active_blocks:
3725
+ ret = curblock.SelectionData.add_node_to_selection(x, y, verif)
3726
+
3727
+ def add_nodes_to_selection(self, xy:list[float], verif:bool=True):
3728
+ """ Add nodes to the selection """
3729
+
3730
+ for curblock in self.parent.active_blocks:
3731
+ curblock.SelectionData.add_nodes_to_selection(xy, verif)
3732
+
3733
+ def select_insidepoly(self, myvect: vector):
3734
+
3735
+ for curblock in self.parent.active_blocks:
3736
+ curblock.SelectionData.select_insidepoly(myvect)
3737
+
3738
+ def select_underpoly(self, myvect: vector):
3739
+
3740
+ for curblock in self.parent.active_blocks:
3741
+ curblock.SelectionData.select_underpoly(myvect)
3742
+
3743
+ def update_nb_nodes_selection(self):
3744
+
3745
+ ret = []
3746
+ for curblock in self.parent.active_blocks:
3747
+ ret.append(curblock.SelectionData.update_nb_nodes_selection())
3748
+
3749
+ nb = np.sum([cur[0] for cur in ret])
3750
+ xmin = np.min([cur[1] for cur in ret if cur[1] != -99999.])
3751
+ ymin = np.min([cur[3] for cur in ret if cur[3] != -99999.])
3752
+ xmax = np.max([cur[2] for cur in ret if cur[2] != -99999.])
3753
+ ymax = np.max([cur[4] for cur in ret if cur[4] != -99999.])
3754
+
3755
+ if self.parent.myops is not None:
3756
+
3757
+ self.parent.myops.nbselect.SetLabelText(str(nb))
3758
+ if nb>0:
3759
+ self.parent.myops.minx.SetLabelText('{:.3f}'.format(xmin))
3760
+ self.parent.myops.miny.SetLabelText('{:.3f}'.format(ymin))
3761
+ self.parent.myops.maxx.SetLabelText('{:.3f}'.format(xmax))
3762
+ self.parent.myops.maxy.SetLabelText('{:.3f}'.format(ymax))
3763
+
3764
+
3765
+ def condition_select(self, cond, condval, condval2=0, usemask=False):
3766
+
3767
+ for curblock in self.parent.active_blocks:
3768
+ curblock.SelectionData.condition_select(cond, condval, condval2, usemask)
3769
+
3770
+ def treat_select(self, op, cond, opval, condval):
3771
+
3772
+ for curblock in self.parent.active_blocks:
3773
+ curblock.SelectionData.treat_select(op, cond, opval, condval)
3774
+
3775
+ def mask_condition(self, op, cond, opval, condval):
3776
+
3777
+ for curblock in self.parent.active_blocks:
3778
+ curblock.SelectionData.mask_condition(op, cond, opval, condval)
3779
+
3780
+ def plot_selection(self):
3781
+
3782
+ for curblock in self.parent.active_blocks:
3783
+ curblock.SelectionData.plot_selection()
3784
+
3785
+ def move_selectionto(self, idx:str, color:list[float]):
3786
+
3787
+ for curblock in self.parent.active_blocks:
3788
+ curblock.SelectionData.move_selectionto(idx, color, resetplot=False)
3789
+
3790
+ self.parent.reset_plot()
3791
+
3792
+ def copy_to_clipboard(self, which:int = None, typestr:Literal['string', 'script'] = 'string'):
3793
+
3794
+ logging.error(_('Not yet implemented for Multi-Blocks'))
3795
+
3796
+ def interp2Dpolygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"] = None):
3797
+ """
3798
+ Interpolation sous tous les polygones d'une zone
3799
+ cf parent.interp2Dpolygon
3800
+ """
3801
+
3802
+ if method is None:
3803
+ choices = ["nearest", "linear", "cubic"]
3804
+ dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
3805
+ ret = dlg.ShowModal()
3806
+ if ret == wx.ID_CANCEL:
3807
+ dlg.Destroy()
3808
+ return
3809
+
3810
+ method = dlg.GetStringSelection()
3811
+ dlg.Destroy()
3812
+
3813
+ self.parent.interpolate_on_polygons(working_zone, method)
3814
+
3815
+ self.parent.reset_plot()
3816
+
3817
+ def interp2Dpolygon(self, working_vector:vector, method:Literal["nearest", "linear", "cubic"] = None):
3818
+ """
3819
+ Interpolation sous un polygone
3820
+ cf parent.interp2Dpolygon
3821
+ """
3822
+
3823
+ if method is None:
3824
+ choices = ["nearest", "linear", "cubic"]
3825
+ dlg = wx.SingleChoiceDialog(None, "Pick an interpolate method", "Choices", choices)
3826
+ ret = dlg.ShowModal()
3827
+ if ret == wx.ID_CANCEL:
3828
+ dlg.Destroy()
3829
+ return
3830
+
3831
+ method = dlg.GetStringSelection()
3832
+ dlg.Destroy()
3833
+
3834
+ self.parent.interpolate_on_polygon(working_vector, method)
3835
+
3836
+ self.parent.reset_plot()
3837
+
3838
+ def interp2Dpolylines(self, working_zone:zone, resetplot:bool = True):
3839
+ """
3840
+ Interpolation sous toutes les polylignes de la zone
3841
+ cf parent.interp2Dpolyline
3842
+ """
3843
+
3844
+ self.parent.interpolate_on_polylines(working_zone)
3845
+
3846
+ self.parent.reset_plot()
3847
+
3848
+ def interp2Dpolyline(self, working_vector:vector, resetplot:bool = True):
3849
+ """
3850
+ Interpolation sous la polyligne active
3851
+ cf parent.interp2Dpolyline
3852
+ """
3853
+
3854
+ self.parent.interpolate_on_polyline(working_vector)
3855
+
3856
+ self.parent.reset_plot()
3857
+
3858
+ def volumesurface(self, show=True):
3859
+ """
3860
+ Evaluation of stage-storage-surface relation
3861
+ """
3862
+
3863
+ logging.error(_('Not yet implemented for Multi-Blocks'))
3336
3864
 
3337
3865
  class WolfArray(Element_To_Draw, header_wolf):
3338
3866
  """
@@ -3398,6 +3926,9 @@ class WolfArray(Element_To_Draw, header_wolf):
3398
3926
 
3399
3927
  self.mngselection = None
3400
3928
 
3929
+ self.myblocks = None
3930
+ self._active_blocks = None
3931
+
3401
3932
  self.flipupd=False
3402
3933
  self.array:ma.masked_array = None # numpy masked array to stored numerical data
3403
3934
 
@@ -3425,7 +3956,7 @@ class WolfArray(Element_To_Draw, header_wolf):
3425
3956
  self.shaded.mypal.defaultgray()
3426
3957
  self.shaded.mypal.automatic = False
3427
3958
 
3428
- self.nullvalue = nullvalue
3959
+ self._nullvalue = nullvalue
3429
3960
  self.nbnotnull = 99999 # number of non-null values in the entire aray
3430
3961
  self.nbnotnullzoom = 99999 # number of non-null values in the current visible part in mapviwer
3431
3962
  self.nbtoplot = 0
@@ -3464,6 +3995,9 @@ class WolfArray(Element_To_Draw, header_wolf):
3464
3995
 
3465
3996
  self.head_blocks = header.head_blocks.copy()
3466
3997
 
3998
+ if self.nb_blocks>0:
3999
+ self.myblocks = {}
4000
+
3467
4001
  self.allocate_ressources()
3468
4002
 
3469
4003
  # # FIXME Why not initialize with nullvalue ?
@@ -3532,6 +4066,16 @@ class WolfArray(Element_To_Draw, header_wolf):
3532
4066
 
3533
4067
  self.add_ops_sel() # Ajout d'un gestionnaire de sélection et d'opérations
3534
4068
 
4069
+ def extract_selection(self):
4070
+ """ Extract the current selection """
4071
+
4072
+ newarray = self.SelectionData.get_newarray()
4073
+
4074
+ mapviewer = self.get_mapviewer()
4075
+
4076
+ if mapviewer is not None:
4077
+ mapviewer.add_object('array', newobj = newarray, ToCheck = True, id = self.idx + '_extracted')
4078
+
3535
4079
  def crop_array(self, bbox:list[list[float],list[float]]) -> "WolfArray":
3536
4080
  """ Crop the data based on the bounding box """
3537
4081
  imin, jmin = self.get_ij_from_xy(bbox[0][0], bbox[1][0])
@@ -3605,6 +4149,93 @@ class WolfArray(Element_To_Draw, header_wolf):
3605
4149
  self.myops.SetTitle(_('Operations on array: ') + self.idx)
3606
4150
  self.myops.Show()
3607
4151
 
4152
+ @property
4153
+ def nullvalue(self) -> float:
4154
+ """ Return the null value """
4155
+
4156
+ return self._nullvalue
4157
+
4158
+ @nullvalue.setter
4159
+ def nullvalue(self, value:float):
4160
+ """ Set the null value """
4161
+
4162
+ self._nullvalue = value
4163
+
4164
+ @property
4165
+ def SelectionData(self) -> SelectionData:
4166
+ """ Return the data of the selection """
4167
+
4168
+ return self.mngselection
4169
+
4170
+ @property
4171
+ def active_blocks(self) -> list["WolfArray"]:
4172
+ """ Return the active blocks """
4173
+
4174
+ if self.nb_blocks>0 and self._active_blocks is not None:
4175
+
4176
+ if isinstance(self._active_blocks, list):
4177
+ return [self.myblocks[cur] for cur in self._active_blocks]
4178
+ elif self._active_blocks == 0:
4179
+ return [k for k in self.myblocks.values()]
4180
+ elif self._active_blocks in self.myblocks:
4181
+ return [self.myblocks[self._active_blocks]]
4182
+ else:
4183
+ return None
4184
+
4185
+ else:
4186
+ return [self]
4187
+
4188
+ @active_blocks.setter
4189
+ def active_blocks(self, value:Union[str, int, list[int]]):
4190
+ """
4191
+ Set the active blocks
4192
+
4193
+ :param value: name of the block or index 1-based or list of index 1-based
4194
+
4195
+ """
4196
+
4197
+ if isinstance(value, str):
4198
+ if value in self.myblocks:
4199
+ self._active_blocks = value
4200
+ logging.info(_(f'Block found - {value}'))
4201
+ else:
4202
+ self._active_blocks = None
4203
+ logging.info(_('Block not found'))
4204
+
4205
+ elif isinstance(value, int):
4206
+
4207
+ if value == 0:
4208
+ self._active_blocks = 0
4209
+ logging.info(_('All blocks selected'))
4210
+ else:
4211
+ value = getkeyblock(value, addone=False)
4212
+
4213
+ if value in self.myblocks:
4214
+ self._active_blocks = value
4215
+ logging.info(_(f'Block found - {value}'))
4216
+ else:
4217
+ self._active_blocks = None
4218
+ logging.info(_('Block not found'))
4219
+
4220
+ elif isinstance(value, list):
4221
+
4222
+ if 0 in value:
4223
+ self._active_blocks = 0
4224
+ logging.info(_('All blocks selected'))
4225
+ else:
4226
+ value = [getkeyblock(cur, addone=False) for cur in value]
4227
+ value = [cur for cur in value if cur in self.myblocks]
4228
+
4229
+ if len(value)>0:
4230
+ self._active_blocks = value
4231
+ logging.info(_('List of blocks selected'))
4232
+ else:
4233
+ self._active_blocks = None
4234
+ logging.info(_('No block found'))
4235
+
4236
+ else:
4237
+ logging.error(_('Unknown type for active_blocks'))
4238
+
3608
4239
  @property
3609
4240
  def dtype(self):
3610
4241
  """
@@ -3707,7 +4338,7 @@ class WolfArray(Element_To_Draw, header_wolf):
3707
4338
 
3708
4339
  self.reset_plot()
3709
4340
 
3710
- def filter_independent_zones(self, n_largest:int = 1):
4341
+ def filter_independent_zones(self, n_largest:int = 1, reset_plot:bool = True):
3711
4342
  """
3712
4343
  Filtre des zones indépendantes et conservation des n plus grandes
3713
4344
 
@@ -3721,7 +4352,7 @@ class WolfArray(Element_To_Draw, header_wolf):
3721
4352
  # convertion en masked array
3722
4353
  labeled_array = ma.asarray(labeled_array)
3723
4354
  # application du masque
3724
- labeled_array.mask = self.array.mask
4355
+ labeled_array.mask[:,:] = self.array.mask[:,:]
3725
4356
 
3726
4357
  longueur = []
3727
4358
  labeled_array[labeled_array.mask] = 0
@@ -3737,8 +4368,61 @@ class WolfArray(Element_To_Draw, header_wolf):
3737
4368
 
3738
4369
  self.set_nullvalue_in_mask()
3739
4370
 
3740
- self.reset_plot()
4371
+ if reset_plot:
4372
+ self.reset_plot()
3741
4373
 
4374
+ def filter_zone(self, set_null:bool = False, reset_plot:bool = True):
4375
+ """
4376
+ Filtre des zones et conservation de celles pour lesquelles des
4377
+ mailles sont sélectionnées
4378
+
4379
+ """
4380
+
4381
+ if self.SelectionData.nb == 0:
4382
+ logging.info(_('No selection -- no filtering'))
4383
+ return
4384
+
4385
+ if self.SelectionData.myselection == 'all':
4386
+ logging.info(_('All nodes selected -- no filtering'))
4387
+ return
4388
+
4389
+ # labellisation
4390
+ labeled_array = self.array.data.copy()
4391
+ labeled_array[np.where(self.array.mask)] = 0
4392
+
4393
+ labeled_array, num_features = label(labeled_array)
4394
+
4395
+ # récupération des zones utiles
4396
+ vals_ij = [self.get_ij_from_xy(cur[0], cur[1]) for cur in self.SelectionData.myselection]
4397
+ vals = list(set([labeled_array[int(cur[0]), int(cur[1])] for cur in vals_ij]))
4398
+
4399
+ self.array.mask[:,:] = True
4400
+
4401
+ for j in vals:
4402
+ self.array.mask[labeled_array == j] = False
4403
+
4404
+ if set_null:
4405
+ self.set_nullvalue_in_mask()
4406
+
4407
+ if reset_plot:
4408
+ self.reset_plot()
4409
+
4410
+ def labelling(self, reset_plot:bool = True):
4411
+ """
4412
+ Labelling of the array using Scipy
4413
+
4414
+ """
4415
+
4416
+ # labellisation
4417
+ labeled_array = self.array.data.copy()
4418
+ labeled_array[np.where(self.array.mask)] = 0
4419
+
4420
+ labeled_array, num_features = label(labeled_array)
4421
+
4422
+ self.array.data[:,:] = labeled_array[:,:].astype(self.dtype)
4423
+
4424
+ if reset_plot:
4425
+ self.reset_plot()
3742
4426
 
3743
4427
  def export_geotif(self, outdir='', extent = ''):
3744
4428
  """
@@ -3902,10 +4586,12 @@ class WolfArray(Element_To_Draw, header_wolf):
3902
4586
 
3903
4587
  def add_ops_sel(self):
3904
4588
  """
3905
- Add :
3906
- - Ops_Array (GUI) if mapviewer is not None
3907
- - create SelectionData (Selection manager) if None
4589
+ Adding selection manager and operations array
4590
+
4591
+ - Ops_Array (GUI) if mapviewer is not None
4592
+ - create SelectionData (Selection manager) if None
3908
4593
  """
4594
+
3909
4595
  if self.wx_exists and self.mapviewer is not None:
3910
4596
  self.myops = Ops_Array(self, self.mapviewer)
3911
4597
  self.myops.Hide()
@@ -3913,7 +4599,11 @@ class WolfArray(Element_To_Draw, header_wolf):
3913
4599
  self.myops = None
3914
4600
 
3915
4601
  if self.mngselection is None:
3916
- self.mngselection = SelectionData(self)
4602
+
4603
+ if self.nb_blocks>0:
4604
+ self.mngselection = SelectionDataMB(self)
4605
+ else:
4606
+ self.mngselection = SelectionData(self)
3917
4607
 
3918
4608
  def change_gui(self, newparentgui):
3919
4609
  """
@@ -4039,6 +4729,82 @@ class WolfArray(Element_To_Draw, header_wolf):
4039
4729
 
4040
4730
  plt.show()
4041
4731
 
4732
+ def interpolate_on_polygon(self, working_vector: vector, method:Literal["nearest", "linear", "cubic"]="linear"):
4733
+ """
4734
+ Interpolation sous un polygone
4735
+
4736
+ L'interpolation a lieu :
4737
+ - uniquement dans les mailles sélectionnées si elles existent
4738
+ - dans les mailles contenues dans le polygone sinon
4739
+
4740
+ On utilise ensuite "griddata" pour interpoler les altitudes des mailles
4741
+ depuis les vertices 3D du polygone
4742
+ """
4743
+
4744
+ if self.mngselection is None:
4745
+ destxy = self.get_xy_inside_polygon(working_vector)
4746
+ else:
4747
+ if self.SelectionData.nb == 0:
4748
+ destxy = self.get_xy_inside_polygon(working_vector)
4749
+ else:
4750
+ destxy = self.SelectionData.myselection
4751
+
4752
+ if len(destxy)==0:
4753
+ logging.debug(_('No points to interpolate'))
4754
+ return
4755
+
4756
+ destij = np.asarray([list(self.get_ij_from_xy(x, y)) for x, y in destxy])
4757
+
4758
+ xyz = working_vector.asnparray3d()
4759
+
4760
+ newvalues = griddata(xyz[:, :2], xyz[:, 2], destxy, method=method, fill_value=-99999.)
4761
+
4762
+ locmask = np.where(newvalues != -99999.)
4763
+ self.array.data[destij[locmask][:, 0], destij[locmask][:, 1]] = newvalues[locmask]
4764
+
4765
+ def interpolate_on_polygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"]="linear"):
4766
+ """
4767
+ Interpolation sous plusieurs polygones d'une même zone
4768
+
4769
+ """
4770
+
4771
+ for curvec in working_zone.myvectors:
4772
+ self.interpolate_on_polygon(curvec, method)
4773
+
4774
+ def interpolate_on_polyline(self, working_vector:vector, usemask=True):
4775
+ """
4776
+ Interpolation sous une polyligne
4777
+
4778
+ L'interpolation a lieu :
4779
+ - uniquement dans les mailles sélectionnées si elles existent
4780
+ - dans les mailles sous la polyligne sinon
4781
+
4782
+ On utilise ensuite "interpolate" de shapely pour interpoler les altitudes des mailles
4783
+ depuis les vertices 3D de la polyligne
4784
+ """
4785
+
4786
+ vecls = working_vector.asshapely_ls()
4787
+
4788
+ if self.SelectionData is None:
4789
+ allij = self.get_ij_under_polyline(working_vector, usemask)
4790
+ allxy = [self.get_xy_from_ij(cur[0], cur[1]) for cur in allij]
4791
+ else:
4792
+ if self.SelectionData.nb == 0:
4793
+ allij = self.get_ij_under_polyline(working_vector, usemask)
4794
+ allxy = [self.get_xy_from_ij(cur[0], cur[1]) for cur in allij]
4795
+ else:
4796
+ allxy = self.SelectionData.myselection
4797
+ allij = np.asarray([self.get_ij_from_xy(x,y) for x,y in allxy])
4798
+
4799
+ newz = np.asarray([vecls.interpolate(vecls.project(Point(x, y))).z for x, y in allxy])
4800
+ self.array.data[allij[:, 0], allij[:, 1]] = newz
4801
+
4802
+ def interpolate_on_polylines(self, working_zone:zone, usemask=True):
4803
+
4804
+ for curvec in working_zone.myvectors:
4805
+ self.interpolate_on_polyline(curvec, usemask)
4806
+
4807
+
4042
4808
  def interpolate_on_cloud(self, xy:np.ndarray, z:np.ndarray, method='linear'):
4043
4809
  """
4044
4810
  See : https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
@@ -4195,7 +4961,7 @@ class WolfArray(Element_To_Draw, header_wolf):
4195
4961
  curvec.add_vertex(wolfvertex(coords[curpt,0],coords[curpt,1], coords[curpt,2]))
4196
4962
  curvec.close_force()
4197
4963
 
4198
- self.myops._interp2Dpolygon(curvec, "linear")
4964
+ self.interpolate_on_polygon(curvec, "linear")
4199
4965
 
4200
4966
  self.reset_plot()
4201
4967
  return
@@ -4546,7 +5312,7 @@ class WolfArray(Element_To_Draw, header_wolf):
4546
5312
 
4547
5313
  return axs
4548
5314
 
4549
- def paste_all(self, fromarray:"WolfArray"):
5315
+ def paste_all(self, fromarray:"WolfArray", mask_after:bool=True):
4550
5316
  """ Paste all the values from another WolfArray """
4551
5317
 
4552
5318
  fromarray: WolfArray
@@ -4583,8 +5349,9 @@ class WolfArray(Element_To_Draw, header_wolf):
4583
5349
 
4584
5350
  self.array.data[usefulij_dest] = fromarray.array.data[usefulij]
4585
5351
 
4586
- self.mask_data(self.nullvalue)
4587
- self.reset_plot()
5352
+ if mask_after:
5353
+ self.mask_data(self.nullvalue)
5354
+ self.reset_plot()
4588
5355
 
4589
5356
  def set_values_sel(self, xy:list[float], z:list[float], update:bool=True):
4590
5357
  """
@@ -4594,6 +5361,7 @@ class WolfArray(Element_To_Draw, header_wolf):
4594
5361
  :param z: [z1,z2,...]
4595
5362
  :param update: update the plot
4596
5363
  """
5364
+
4597
5365
  sel = np.asarray(xy)
4598
5366
 
4599
5367
  if len(sel) == 1:
@@ -4779,6 +5547,10 @@ class WolfArray(Element_To_Draw, header_wolf):
4779
5547
  """
4780
5548
  assert self.shape == mask.shape, _('Bad shape')
4781
5549
 
5550
+ if self.array is None:
5551
+ logging.debug(_('No array !!'))
5552
+ return
5553
+
4782
5554
  if link:
4783
5555
  self.array.mask = mask
4784
5556
  else:
@@ -5024,7 +5796,60 @@ class WolfArray(Element_To_Draw, header_wolf):
5024
5796
 
5025
5797
  return newArray
5026
5798
 
5027
- def mask_outsidepoly(self, myvect: vector):
5799
+ def concatenate(self, list_arr:list["WolfArray"], nullvalue:float = 0.):
5800
+ """
5801
+ Concatenate the values from another WolfArrays into a new one
5802
+
5803
+ :param list_arr: list of WolfArray objects
5804
+ :return: a new WolfArray
5805
+ :return_type: WolfArray
5806
+ """
5807
+
5808
+ list_arr:list[WolfArray]
5809
+
5810
+ for curarray in list_arr:
5811
+ assert isinstance(curarray, WolfArray), "The list must contain WolfArray objects"
5812
+ assert curarray.nbdims == self.nbdims, "The arrays must have the same number of dimensions"
5813
+ assert curarray.dx == self.dx and curarray.dy == self.dy, "The arrays must have the same dx and dy"
5814
+ assert curarray.translx == 0 and curarray.transly == 0, "The translations must be zero"
5815
+ assert (np.abs(curarray.origx-self.origx)%int(self.dx) == 0)and(np.abs(curarray.origy-self.origy)%int(self.dy) == 0), "The origins are not compatible! You need to do some interpolation stuff"
5816
+ assert self.translx == 0 and self.transly == 0, "The translations must be zero"
5817
+ assert self.wolftype == curarray.wolftype, "The arrays must have the same wolftype"
5818
+
5819
+ # create an array
5820
+ newArray = WolfArray(nullvalue=nullvalue, whichtype=self.wolftype)
5821
+
5822
+ Xlim,Ylim = self.find_union(list_arr)
5823
+
5824
+ newArray.origx = Xlim[0]
5825
+ newArray.origy = Ylim[0]
5826
+ newArray.dx = self.dx
5827
+ newArray.dy = self.dy
5828
+
5829
+ newArray.nbx = int(np.diff(Xlim)[0]/newArray.dx)
5830
+ newArray.nby = int(np.diff(Ylim)[0]/newArray.dy)
5831
+
5832
+ newArray.translx = 0.
5833
+ newArray.transly = 0.
5834
+
5835
+ newArray.array = np.ma.masked_array(np.ones((newArray.nbx, newArray.nby), dtype=self.dtype) * nullvalue, mask=True, dtype=self.dtype)
5836
+
5837
+ newArray.paste_all(self, mask_after=False)
5838
+
5839
+ for curarray in list_arr:
5840
+ Array_intersect = curarray.find_intersection(self, ij=True)
5841
+
5842
+ if Array_intersect is not None:
5843
+ logging.info(_("There is intersection. By default, the array {} overlaps the first one.".format(curarray.filename)))
5844
+
5845
+ newArray.paste_all(curarray, mask_after=False)
5846
+
5847
+ newArray.mask_data(nullvalue)
5848
+
5849
+
5850
+ return newArray
5851
+
5852
+ def mask_outsidepoly(self, myvect: vector, eps:float = 0.):
5028
5853
  """
5029
5854
  Mask nodes outside a polygon and set values to nullvalue
5030
5855
 
@@ -5038,27 +5863,51 @@ class WolfArray(Element_To_Draw, header_wolf):
5038
5863
  mask[:,:] = True # Mask everything
5039
5864
 
5040
5865
  # trouve les indices dans le polygone
5041
- myij = self.get_ij_inside_polygon(myvect, False)
5866
+ myij = self.get_ij_inside_polygon(myvect, usemask=False, eps=eps)
5867
+
5042
5868
  # démasquage des mailles contenues
5043
5869
  mask[myij[:,0],myij[:,1]] = False
5870
+
5044
5871
  # annulation des valeurs en dehors du polygone
5045
5872
  self.array.data[np.where(mask)] = self.nullvalue
5046
5873
 
5047
- # recherche du nouveau masque, sinon les valeurs no_data à
5048
- # l'intérieur du polygone vont pollluer la matrice
5874
+ # recherche du nouveau masque, sinon les valeurs no_data à
5875
+ # l'intérieur du polygone vont pollluer la matrice
5876
+
5877
+ # Now we have masked everything outside the polygon,
5878
+ # we still have to keep into account values that were
5879
+ # already masked inside the polygon before this operation.
5880
+ # FIXME Why simply not use the previous mask value ?
5881
+ # FIXME This operation seems to contradict mask[:,:] = True
5882
+ self.mask_data(self.nullvalue)
5883
+
5884
+ self.count()
5885
+
5886
+ def mask_insidepoly(self, myvect: vector, eps:float = 0.):
5887
+ """
5888
+ Mask nodes inside a polygon and set values to nullvalue
5889
+
5890
+ :param myvect: target vector in global coordinates
5891
+ """
5892
+ # The polygon here is in world coordinates
5893
+ # (coord will be converted back with translation, origin and dx/dy)
5894
+ # (mesh coord, 0-based)
5895
+
5896
+ # trouve les indices dans le polygone
5897
+ myij = self.get_ij_inside_polygon(myvect, usemask=False, eps=eps)
5898
+
5899
+ # annulation des valeurs en dehors du polygone
5900
+ self.array.data[myij[:,0],myij[:,1]] = self.nullvalue
5049
5901
 
5050
- # Now we have masked everything outside the polygon,
5051
- # we still have to keep into account values that were
5052
- # already masked inside the polygon before this operation.
5053
- # FIXME Why simply not use the previous mask value ?
5054
- # FIXME This operation seems to contradict mask[:,:] = True
5055
- self.mask_data(self.nullvalue)
5902
+ # masquage des mailles contenues
5903
+ self.array.mask[myij[:,0],myij[:,1]] = True
5056
5904
 
5905
+ self.count()
5057
5906
 
5058
5907
  # *************************************************************************************************************************
5059
5908
  # POSITION and VALUES associated to a vector/polygon/polyline
5060
5909
  # These functions can not be stored in header_wolf, because wa can use the mask of the array to limit the search
5061
- # These functions are also present in WolfResults_2D, but they are not exactly the same dur to the structure of the results
5910
+ # These functions are also present in WolfResults_2D, but they are not exactly the same due to the structure of the results
5062
5911
  # *************************************************************************************************************************
5063
5912
  def get_xy_inside_polygon(self, myvect: vector, usemask:bool=True):
5064
5913
  """
@@ -5069,7 +5918,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5069
5918
  """
5070
5919
 
5071
5920
  myvect.find_minmax()
5072
- mypointsxy,mypointsij = self.get_xy_infootprint_vect(myvect)
5921
+ mypointsxy, mypointsij = self.get_xy_infootprint_vect(myvect)
5073
5922
  myvert = myvect.asnparray()
5074
5923
  path = mpltPath.Path(myvert)
5075
5924
  inside = path.contains_points(mypointsxy)
@@ -5096,7 +5945,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5096
5945
 
5097
5946
  return mypoints
5098
5947
 
5099
- def get_ij_inside_polygon(self, myvect: vector, usemask:bool=True):
5948
+ def get_ij_inside_polygon(self, myvect: vector, usemask:bool=True, eps:float = 0.):
5100
5949
  """
5101
5950
  Return the indices inside a polygon
5102
5951
 
@@ -5104,12 +5953,16 @@ class WolfArray(Element_To_Draw, header_wolf):
5104
5953
  :param usemask : limit potential nodes to unmaksed nodes
5105
5954
  """
5106
5955
 
5956
+ # force la mise à jour des min/max
5107
5957
  myvect.find_minmax()
5108
- mypointsij = self.get_ij_infootprint_vect(myvect)
5958
+
5959
+ mypointsxy, mypointsij = self.get_xy_infootprint_vect(myvect, eps=eps)
5960
+
5961
+ # Conversion des coordonnées en numpy pour plus d'efficacité (du moins on espère)
5109
5962
  myvert = myvect.asnparray()
5110
- i,j =self.convert_xy2ij_np(myvert)
5111
- path = mpltPath.Path(np.column_stack([i,j]))
5112
- inside = path.contains_points(mypointsij)
5963
+
5964
+ path = mpltPath.Path(myvert)
5965
+ inside = path.contains_points(mypointsxy)
5113
5966
 
5114
5967
  mypointsij = mypointsij[np.where(inside)]
5115
5968
 
@@ -5287,6 +6140,11 @@ class WolfArray(Element_To_Draw, header_wolf):
5287
6140
 
5288
6141
  else:
5289
6142
  self.read_txt_header()
6143
+
6144
+ if self.nb_blocks > 0:
6145
+ # At this point, we have the header, we know the number of blocks, if exists
6146
+ self.myblocks = {}
6147
+
5290
6148
  if self.preload:
5291
6149
  self.read_data()
5292
6150
  self.loaded = True
@@ -5296,7 +6154,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5296
6154
  """
5297
6155
  Ecriture de tous les fichiers d'un Wolf array
5298
6156
 
5299
- :param newpath: path and filename with extension
6157
+ :param newpath: new path and filename with extension -- if None, use the current filename
5300
6158
  """
5301
6159
 
5302
6160
  if isinstance(newpath, Path):
@@ -5308,7 +6166,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5308
6166
  if self.filename.endswith('.tif'):
5309
6167
  self.export_geotif()
5310
6168
  elif self.filename.endswith('.npy'):
5311
-
6169
+
5312
6170
  writing_header = True
5313
6171
  if self.dtype != self.array.data.dtype:
5314
6172
  logging.warning(_('Data type changed -- Force conversion to internal numpy array'))
@@ -5510,6 +6368,9 @@ class WolfArray(Element_To_Draw, header_wolf):
5510
6368
  elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER16, WOLF_ARRAY_FULL_INTEGER16_2]:
5511
6369
  locarray = np.frombuffer(f.read(self.nbx * self.nby * 2), dtype=np.int16)
5512
6370
  self.array = ma.masked_array(locarray.copy(), dtype=np.int16)
6371
+ elif self.wolftype in [WOLF_ARRAY_FULL_INTEGER8]:
6372
+ locarray = np.frombuffer(f.read(self.nbx * self.nby * 2), dtype=np.int8)
6373
+ self.array = ma.masked_array(locarray.copy(), dtype=np.int8)
5513
6374
 
5514
6375
  if self.nbdims == 2:
5515
6376
  self.array = self.array.reshape(self.nbx, self.nby, order='F')
@@ -5606,7 +6467,7 @@ class WolfArray(Element_To_Draw, header_wolf):
5606
6467
  """
5607
6468
 
5608
6469
  if self.nbdims == 2:
5609
- # FIXME if WolfArray_Sim2D mask linking should work
6470
+ # FIXME if mask linking should work
5610
6471
  # as expected, then we do: self.array.mask.fill(0.0)
5611
6472
  # to avoid replacing the linked mask by a (non linked) one.
5612
6473
 
@@ -5677,6 +6538,25 @@ class WolfArray(Element_To_Draw, header_wolf):
5677
6538
  np.copyto(self.array.mask, self.array.data <= value)
5678
6539
  self.count()
5679
6540
 
6541
+ def mask_greater(self, value):
6542
+ """ Mask cell where values are strictly greater than `value` """
6543
+ if self.array is None:
6544
+ return
6545
+
6546
+ # Copy to prevent unlinking the mask (see `mask_reset`)
6547
+ np.copyto(self.array.mask, self.array.data > value)
6548
+ self.count()
6549
+
6550
+ def mask_greaterequal(self, value):
6551
+ """ Mask cell where values are greater or equal than `value`"""
6552
+ if self.array is None:
6553
+ return
6554
+
6555
+ # Copy to prevent unlinking the mask (see `mask_reset`)
6556
+ np.copyto(self.array.mask, self.array.data >= value)
6557
+ self.count()
6558
+
6559
+
5680
6560
  def set_nullvalue_in_mask(self):
5681
6561
  """ Set nullvalue in masked cells """
5682
6562
  if self.array is None:
@@ -5736,6 +6616,29 @@ class WolfArray(Element_To_Draw, header_wolf):
5736
6616
  y, x = np.meshgrid(y_discr, x_discr)
5737
6617
  return x, y
5738
6618
 
6619
+ def crop_masked_at_edges(self):
6620
+
6621
+ """
6622
+ Crop the array to remove masked cells at the edges of the array
6623
+ :return: cropped array, WolfArray instance
6624
+
6625
+ """
6626
+
6627
+ # Get max indexes
6628
+ Existing_indexes = np.argwhere(self.array.mask!=True)
6629
+ Max_index = np.max(Existing_indexes, 0)
6630
+ Min_index = np.min(Existing_indexes, 0)
6631
+
6632
+ # convert index in location
6633
+ xMax, yMax = self.convert_ij2xy_np(Max_index.reshape((1,2)))
6634
+ xMin, yMin = self.convert_ij2xy_np(Min_index.reshape((1,2)))
6635
+
6636
+ # crop
6637
+ nbx=np.ceil((xMax[0]-xMin[0])/self.dx).astype(int)+1 #+1 otherwise you remove one line
6638
+ nby=np.ceil((yMax[0]-yMin[0])/self.dy).astype(int)+1 #+1 otherwise you remove one column
6639
+ return self.crop(int(Min_index[0]),int(Min_index[1]),int(nbx),int(nby))
6640
+
6641
+
5739
6642
  def crop(self, i_start:int, j_start:int, nbx:int, nby:int, k_start:int=1, nbz:int=1):
5740
6643
  """
5741
6644
  Crop the array
@@ -5779,6 +6682,44 @@ class WolfArray(Element_To_Draw, header_wolf):
5779
6682
 
5780
6683
  return newWolfArray
5781
6684
 
6685
+ def extend(self, x_ext:int, y_ext:int):
6686
+
6687
+ # crop is the opposite
6688
+
6689
+ assert x_ext >= 0 and y_ext >= 0
6690
+ assert self.nbdims == 2, "Only 2D arrays are supported"
6691
+
6692
+ # Remember WolfArrays are masked. Therefore
6693
+ # we need to extend mask. In this case, not specifying
6694
+ # anything will expand the mask with "dont mask"
6695
+ # values.
6696
+
6697
+ # extend vertically
6698
+ ex = self.array
6699
+
6700
+ if x_ext > 0:
6701
+ # dtype is important: it allows to keep a Fortran friendly
6702
+ # type I think.
6703
+ ex = ma.append(
6704
+ ex,
6705
+ np.array([0] * ex.shape[1] * x_ext, dtype=ex.dtype).reshape((x_ext, -1)),
6706
+ axis=0,
6707
+ )
6708
+ self.nbx += x_ext
6709
+
6710
+ # extend horizontally
6711
+ if y_ext > 0:
6712
+ ex = ma.append(
6713
+ ex,
6714
+ np.array([0] * ex.shape[0] * y_ext, dtype=ex.dtype).reshape((-1, y_ext)),
6715
+ axis=1,
6716
+ )
6717
+ self.nby += y_ext
6718
+
6719
+ self.array = ex
6720
+
6721
+ self.mask_data(self.nullvalue)
6722
+
5782
6723
  def extremum(self, which:Literal['min','max']='min'):
5783
6724
  """ Return the extremum value """
5784
6725
 
@@ -6354,6 +7295,55 @@ class WolfArray(Element_To_Draw, header_wolf):
6354
7295
  self.array.mask[:,:width] = True
6355
7296
  self.array.mask[:,-width:] = True
6356
7297
 
7298
+ def as_WolfArray(self, abs:bool=True) -> "WolfArray":
7299
+ """
7300
+ Return a WolfArray object from this WolfArray
7301
+ """
7302
+
7303
+ NewArray = WolfArray(mold=self)
7304
+
7305
+ if abs:
7306
+ NewArray.origx += self.translx
7307
+ NewArray.origy += self.transly
7308
+ NewArray.translx = 0.
7309
+ NewArray.transly = 0.
7310
+
7311
+ return NewArray
7312
+
7313
+ def get_unique_values(self):
7314
+ """
7315
+ Return unique values in the array
7316
+ """
7317
+
7318
+ unique = np.ma.unique(self.array)
7319
+
7320
+ while unique[-1] is np.ma.masked and len(unique) > 1:
7321
+ unique = unique[:-1]
7322
+
7323
+ return unique
7324
+
7325
+ def map_values(self, keys_vals:dict, default:float=None):
7326
+ """
7327
+ Apply a mapping to the array
7328
+ """
7329
+
7330
+ vals = self.get_unique_values()
7331
+
7332
+ if default is not None:
7333
+ self.array.data[:,:] = default
7334
+
7335
+ for val in vals:
7336
+ if val not in keys_vals:
7337
+ logging.warning(f"Value {val} not in keys_vals")
7338
+ continue
7339
+
7340
+ for key, val in keys_vals.items():
7341
+ self.array.data[self.array.data == key] = val
7342
+
7343
+ self.mask_data(self.nullvalue)
7344
+
7345
+ self.reset_plot()
7346
+
6357
7347
  class WolfArrayMB(WolfArray):
6358
7348
  """
6359
7349
  Matrice multiblocks
@@ -6366,12 +7356,133 @@ class WolfArrayMB(WolfArray):
6366
7356
 
6367
7357
  def __init__(self, fname=None, mold=None, masknull=True, crop=None, whichtype=WOLF_ARRAY_MB_SINGLE, preload=True,
6368
7358
  create=False, mapviewer=None, nullvalue=0, srcheader=None):
6369
- self.myblocks = {}
7359
+
6370
7360
  super().__init__(fname, mold, masknull, crop, whichtype, preload, create, mapviewer, nullvalue, srcheader)
6371
- # self.wolftype = whichtype
7361
+
7362
+ self._active_blocks = 0
7363
+
7364
+ if self.myblocks is None:
7365
+ self.myblocks = {}
7366
+
7367
+ def extract_selection(self):
7368
+ """ Extract the current selection """
7369
+
7370
+ newarrays = []
7371
+
7372
+ for curblock in self.myblocks.values():
7373
+ newblock = curblock.SelectionData.get_newarray()
7374
+
7375
+ if newblock is not None:
7376
+ newarrays.append(newblock)
7377
+
7378
+ if len(newarrays) == 0:
7379
+ logging.warning(_('No selection to extract'))
7380
+ return None
7381
+
7382
+ newMBarray = WolfArrayMB()
7383
+ for newarray in newarrays:
7384
+ newMBarray.add_block(newarray, force_idx=True)
7385
+
7386
+ mapviewer = self.get_mapviewer()
7387
+
7388
+ if mapviewer is not None:
7389
+ mapviewer.add_object('array', newobj = newarray, ToCheck = True, id = self.idx + '_extracted')
7390
+
7391
+
7392
+ @property
7393
+ def nullvalue(self) -> float:
7394
+ """ Return the null value """
7395
+
7396
+ return self._nullvalue
7397
+
7398
+ @nullvalue.setter
7399
+ def nullvalue(self, value:float):
7400
+ """ Set the null value """
7401
+
7402
+ self._nullvalue = value
7403
+
7404
+ if self.myblocks is not None:
7405
+ for curblock in self.myblocks.values():
7406
+ curblock.nullvalue = value
7407
+
7408
+ def add_ops_sel(self):
7409
+ """ Add operations and selection manager to all blocks """
7410
+
7411
+ super().add_ops_sel()
7412
+
7413
+ if self.myblocks is None:
7414
+ self.myblocks = {}
7415
+
7416
+ for curblock in self.myblocks.values():
7417
+ curblock.add_ops_sel()
7418
+
7419
+ def filter_zone(self, set_null:bool = False):
7420
+ """
7421
+ Filtre des zones et conservation de celles pour lesquelles des
7422
+ mailles sont sélectionnées
7423
+
7424
+ """
7425
+
7426
+ for curblock in self.myblocks.values():
7427
+ curblock.filter_zone(set_null, reset_plot=False)
7428
+
7429
+ self.reset_plot()
7430
+
7431
+ def labelling(self):
7432
+ """
7433
+ Labelling of the array using Scipy
7434
+
7435
+ """
7436
+
7437
+ for curblock in self.myblocks.values():
7438
+ curblock.labelling(reset_plot=False)
7439
+
7440
+ self.reset_plot()
7441
+
7442
+ def interpolate_on_polygon(self, working_vector: vector, method:Literal["nearest", "linear", "cubic"]="linear"):
7443
+ """
7444
+ Interpolation sous un polygone
7445
+
7446
+ L'interpolation a lieu :
7447
+ - uniquement dans les mailles sélectionnées si elles existent
7448
+ - dans les mailles contenues dans le polygone sinon
7449
+
7450
+ On utilise ensuite "griddata" pour interpoler les altitudes des mailles
7451
+ depuis les vertices 3D du polygone
7452
+ """
7453
+
7454
+ for curblock in self.myblocks.values():
7455
+ curblock.interpolate_on_polygon(working_vector, method)
7456
+
7457
+ def interpolate_on_polygons(self, working_zone: zone, method:Literal["nearest", "linear", "cubic"]="linear"):
7458
+
7459
+ for curvector in working_zone.myvectors:
7460
+ self.interpolate_on_polygon(curvector, method)
7461
+
7462
+ def interpolate_on_polyline(self, working_vector:vector, usemask=True):
7463
+ """
7464
+ Interpolation sous une polyligne
7465
+
7466
+ L'interpolation a lieu :
7467
+ - uniquement dans les mailles sélectionnées si elles existent
7468
+ - dans les mailles sous la polyligne sinon
7469
+
7470
+ On utilise ensuite "interpolate" de shapely pour interpoler les altitudes des mailles
7471
+ depuis les vertices 3D de la polyligne
7472
+ """
7473
+
7474
+ for curblock in self.myblocks.values():
7475
+ curblock.interpolate_on_polyline(working_vector, usemask)
7476
+
7477
+ def interpolate_on_polylines(self, working_zone:zone, usemask=True):
7478
+ """ Interpolation sous les polylignes d'une même zone """
7479
+
7480
+ for curvec in working_zone.myvectors:
7481
+ self.interpolate_on_polyline(curvec, usemask)
6372
7482
 
6373
7483
  def check_bounds_ij(self, i:int, j:int):
6374
7484
  """Check if i and j are inside the array bounds"""
7485
+
6375
7486
  x,y = self.get_xy_from_ij(i,j)
6376
7487
  return self.check_bounds_xy(x,y)
6377
7488
 
@@ -6468,6 +7579,8 @@ class WolfArrayMB(WolfArray):
6468
7579
  self.loaded = True
6469
7580
  else:
6470
7581
  raise Exception(_(f"Trying to load an array that doesn't exist ({self.filename})"))
7582
+ else:
7583
+ logging.info(_('Array already loaded'))
6471
7584
 
6472
7585
  def uncheck_plot(self, unload:bool=True, forceresetOGL:bool=False, askquestion:bool=True):
6473
7586
  """ Uncheck plot and apply to each block """
@@ -6491,6 +7604,8 @@ class WolfArrayMB(WolfArray):
6491
7604
 
6492
7605
  self.myblocks = {}
6493
7606
  self.loaded = False
7607
+ else:
7608
+ logging.info(_('Array not unloaded'))
6494
7609
 
6495
7610
  def mask_data(self, value):
6496
7611
  """ Mask cells where values are equal to `value`"""
@@ -6759,6 +7874,15 @@ class WolfArrayMB(WolfArray):
6759
7874
  self.plotting = False
6760
7875
  self.mimic_plotdata()
6761
7876
 
7877
+ # Plot selected nodes
7878
+ if self.mngselection is not None:
7879
+ self.mngselection.plot_selection()
7880
+
7881
+ # Plot zones attached to array
7882
+ if self.myops is not None:
7883
+ self.myops.myzones.plot()
7884
+
7885
+
6762
7886
  def fillonecellgrid(self, curscale, loci, locj, force=False):
6763
7887
  for curblock in self.myblocks.values():
6764
7888
  curblock.fillonecellgrid(curscale, loci, locj, force)
@@ -7067,16 +8191,20 @@ class WolfArrayMB(WolfArray):
7067
8191
  def allocate_ressources(self):
7068
8192
  """ Allocate memory ressources """
7069
8193
 
7070
- if len(self.myblocks)==0:
7071
- for id, (key, curhead) in enumerate(self.head_blocks.items()):
7072
- if self.wolftype == WOLF_ARRAY_MB_SINGLE:
7073
- self.myblocks[key] = WolfArray(srcheader=curhead, whichtype=WOLF_ARRAY_FULL_SINGLE)
7074
- elif self.wolftype == WOLF_ARRAY_MB_INTEGER:
7075
- self.myblocks[key] = WolfArray(srcheader=curhead, whichtype=WOLF_ARRAY_FULL_INTEGER)
8194
+ if self.myblocks is None:
8195
+ logging.warning("No blocks to allocate")
8196
+ else:
7076
8197
 
7077
- self.myblocks[key].isblock = True
7078
- self.myblocks[key].blockindex = id
7079
- self.myblocks[key].idx = key
8198
+ if len(self.myblocks)==0:
8199
+ for id, (key, curhead) in enumerate(self.head_blocks.items()):
8200
+ if self.wolftype == WOLF_ARRAY_MB_SINGLE:
8201
+ self.myblocks[key] = WolfArray(srcheader=curhead, whichtype=WOLF_ARRAY_FULL_SINGLE)
8202
+ elif self.wolftype == WOLF_ARRAY_MB_INTEGER:
8203
+ self.myblocks[key] = WolfArray(srcheader=curhead, whichtype=WOLF_ARRAY_FULL_INTEGER)
8204
+
8205
+ self.myblocks[key].isblock = True
8206
+ self.myblocks[key].blockindex = id
8207
+ self.myblocks[key].idx = key
7080
8208
 
7081
8209
  def set_header_from_added_blocks(self):
7082
8210
  """ Set header from blocks """
@@ -7213,18 +8341,26 @@ class WolfArrayMB(WolfArray):
7213
8341
  logging.debug(f"Block {curblock.idx} is empty or totally masked.")
7214
8342
 
7215
8343
  return newArray
8344
+
8345
+
7216
8346
  class WolfArrayMNAP(WolfArrayMB):
7217
8347
  """
7218
8348
  Matrice MNAP d'une modélisation WOLF2D
7219
8349
 
7220
- Elle contient toutes les informations de maillage
8350
+ Elle contient toutes les informations de maillage en Multi-blocks
8351
+ ainsi que les relations de voisinage de blocs.
8352
+
8353
+ Surcharge de WolfArrayMB avec modification des opérations de lecture/écriture
8354
+ car le fichier est au format TEXTE/ASCII et d'une structure spécifique.
8355
+
7221
8356
  """
8357
+
7222
8358
  # Each zone will have the contour of one block.
7223
8359
  contour: Zones
7224
8360
 
7225
8361
  def __init__(self, fname=None, mold=None, masknull=True, crop=None):
7226
8362
  super().__init__(fname, mold, masknull, crop)
7227
- self.contour = Zones()
8363
+
7228
8364
 
7229
8365
  def write_all(self):
7230
8366
 
@@ -7259,23 +8395,38 @@ class WolfArrayMNAP(WolfArrayMB):
7259
8395
  f.write(padf(v.x) + padf(v.y) + "\n")
7260
8396
 
7261
8397
  def read_data(self):
7262
- if os.path.exists(self.filename + '.mnap'):
8398
+
8399
+ # Vérification de l'existence de certains attributs
8400
+ if self.myblocks is None:
8401
+ self.myblocks = {}
8402
+
8403
+ # une matrice WolfArrayMB n'a pas de contour -> ajout d'un attribut spécifique
8404
+ self.contour = Zones()
8405
+
8406
+ if Path(self.filename + '.mnap').exists():
8407
+
7263
8408
  with open(self.filename + '.mnap') as f:
8409
+
8410
+ # Lecture au format texte
7264
8411
  lines = f.read().splitlines()
7265
8412
 
8413
+ # nombre de blocks dans la première ligne
7266
8414
  nb_blocks = abs(int(lines[0]))
7267
- self.contour = Zones()
7268
8415
 
7269
8416
  decal = 1
7270
8417
  for i in range(nb_blocks):
8418
+ # bouclage sur chque block
7271
8419
  curkey = getkeyblock(i)
7272
- curarray = WolfArray()
8420
+
8421
+ curarray = WolfArray(whichtype=WOLF_ARRAY_FULL_INTEGER8)
7273
8422
  self.myblocks[curkey] = curarray
7274
8423
 
7275
- curarray.wolftype = WOLF_ARRAY_FULL_INTEGER8
8424
+ assert curarray.wolftype == WOLF_ARRAY_FULL_INTEGER8, "Type de block incorrect"
8425
+
7276
8426
  curarray.isblock = True
7277
8427
  curarray.blockindex = i
7278
8428
 
8429
+ # Recherche des informations de maillage - dx, dy, origx, origy, nbx, nby
7279
8430
  tmp = re.sub('\\s+', ' ', lines[decal].strip()).split(' ')
7280
8431
  curarray.dx = float(tmp[0])
7281
8432
  curarray.dy = float(tmp[1])
@@ -7291,6 +8442,8 @@ class WolfArrayMNAP(WolfArrayMB):
7291
8442
  curarray.nby = int(tmp[1])
7292
8443
 
7293
8444
  decal += 4
8445
+
8446
+ #Lecture de la matrice de maillage pour le block en cours
7294
8447
  myarray = []
7295
8448
 
7296
8449
  for j in range(curarray.nby):
@@ -7304,6 +8457,7 @@ class WolfArrayMNAP(WolfArrayMB):
7304
8457
 
7305
8458
  curarray.array = np.flipud(np.ma.asarray(myarray, order='F')).transpose()
7306
8459
 
8460
+ #Lecture du contour de block
7307
8461
  curzone = zone(name=curkey)
7308
8462
  contourblock = vector(name='contour')
7309
8463
 
@@ -7320,6 +8474,9 @@ class WolfArrayMNAP(WolfArrayMB):
7320
8474
  curarray.translx = self.translx + self.origx
7321
8475
  curarray.transly = self.transly + self.origy
7322
8476
 
8477
+ # Remplissagze du header
8478
+ # --> la matrice MNAP est la référence d'une simulation 2D
8479
+ # pour obtenir les informations de maillage
7323
8480
  curhead = self.head_blocks[getkeyblock(i)] = header_wolf()
7324
8481
 
7325
8482
  curhead.nbx = curarray.nbx
@@ -7332,6 +8489,17 @@ class WolfArrayMNAP(WolfArrayMB):
7332
8489
  curhead.transly = curarray.transly
7333
8490
 
7334
8491
  def read_txt_header(self):
8492
+ """
8493
+ Surcharge de la lecture du header
8494
+
8495
+ Il n'y a pas en tant que tel de header d'un fichier MNAP.
8496
+
8497
+ Les informations de translation sont dans le fichier ".trl".
8498
+
8499
+ Les informations de tailles de maille 'fines',
8500
+ Nbx, Nby et coordonnées d'origine sont dans le fichier ".par"
8501
+
8502
+ """
7335
8503
 
7336
8504
  if os.path.exists(self.filename + '.trl'):
7337
8505
  with open(self.filename + '.trl') as f:
@@ -7349,144 +8517,5 @@ class WolfArrayMNAP(WolfArrayMB):
7349
8517
  self.origx = float(lines[11])
7350
8518
  self.origy = float(lines[12])
7351
8519
 
8520
+ # Imposition du type de stockage
7352
8521
  self.wolftype = WOLF_ARRAY_MNAP_INTEGER
7353
-
7354
-
7355
- class WolfArray_Sim2D(WolfArray):
7356
- """
7357
- Surcharge de WolfArray pour les matrices fines de simulation
7358
-
7359
- Objectif : lier la matrice de mask à une source commune
7360
-
7361
- """
7362
- def __init__(self,
7363
- fname:str=None,
7364
- mold:"WolfArray"=None,
7365
- masknull:bool=True,
7366
- crop:list[float]=None,
7367
- whichtype=WOLF_ARRAY_FULL_SINGLE,
7368
- preload:bool=True,
7369
- create:bool=False,
7370
- mapviewer=None,
7371
- nullvalue:float=0,
7372
- srcheader:header_wolf=None,
7373
- masksrc:np.ndarray=None):
7374
-
7375
- # link to mask source
7376
- self.masksrc = masksrc
7377
-
7378
- # FIXME __init__ will initialize a mask of its own and so self.masksrc
7379
- # will be ignored at this point. That's misleading, I'd thought
7380
- # that passing a mask would wire it to this array, forever.
7381
- super().__init__(fname, mold, masknull, crop, whichtype, preload, create, mapviewer, nullvalue, srcheader, mask_source=masksrc)
7382
-
7383
- def check_plot(self):
7384
- """
7385
- Surcharge de la fonction de vérification du plot
7386
-
7387
- Utile notamment pour lier le masque
7388
- """
7389
- self.plotted = True
7390
-
7391
- if not self.loaded and self.filename != '':
7392
- self.read_data()
7393
-
7394
- if self.array is None:
7395
- #problème à la lecture
7396
- self.plotted=False
7397
- return
7398
-
7399
- if self.masksrc is not None:
7400
- self.array.mask = self.masksrc
7401
-
7402
- self.loaded = True
7403
-
7404
- if self.rgb is None:
7405
- self.updatepalette(0)
7406
-
7407
- def read_all(self):
7408
- """
7409
- Surcharge de la fonction de lecture de la matrice
7410
-
7411
- Utile notamment puor le fichier zbin
7412
- """
7413
-
7414
- if self.filename[-4:]=='zbin':
7415
- fileold = self.filename
7416
-
7417
- self.filename = fileold[:-4]+'top'
7418
-
7419
- if not os.path.exists(self.filename):
7420
- return
7421
-
7422
- self.read_txt_header()
7423
- self.filename = fileold
7424
- self.read_data()
7425
- else:
7426
- return super().read_all()
7427
-
7428
- def read_data(self):
7429
- """
7430
- Surcharge de la fonction de lecture de la matrice
7431
-
7432
- Utile notamment puor le fichier zbin
7433
- """
7434
-
7435
- if self.filename[-4:]=='zbin':
7436
- fileold = self.filename
7437
-
7438
- self.filename = fileold[:-4]+'top'
7439
-
7440
- if not os.path.exists(self.filename):
7441
- self.filename = fileold
7442
- return
7443
-
7444
- self.read_data()
7445
- toparray = self.array.copy()
7446
-
7447
- self.filename = fileold[:-4]+'hbin'
7448
- if not os.path.exists(self.filename):
7449
- self.filename = fileold
7450
- return
7451
-
7452
- self.read_data()
7453
- harray = self.array.copy()
7454
-
7455
- self.array = toparray+harray
7456
- self.array.mask = self.masksrc
7457
-
7458
- self.filename = fileold
7459
- else:
7460
- return super().read_data()
7461
-
7462
- def write_all(self):
7463
- return super().write_all()
7464
-
7465
- def write_array(self):
7466
- """
7467
- Surcharge de la fonction d'écriture de la matrice
7468
-
7469
- Utile notamment puor le fichier zbin
7470
- """
7471
- if self.filename[-4:]=='zbin':
7472
- fileold = self.filename
7473
-
7474
- self.filename = fileold[:-4]+'top'
7475
- if not os.path.exists(self.filename):
7476
- self.filename = fileold
7477
- return
7478
-
7479
- zarray = self.array.copy()
7480
- self.read_data()
7481
- toparray = self.array.copy()
7482
-
7483
- self.array = zarray-toparray
7484
- self.array[np.where(self.array<0.)]=0.
7485
-
7486
- self.filename = fileold[:-4]+'hbin'
7487
- self.write_array()
7488
-
7489
- self.filename = fileold
7490
-
7491
- else:
7492
- return super().write_array()