wolfhece 1.8.12__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. wolfhece/GraphNotebook.py +0 -1
  2. wolfhece/PyCrosssections.py +591 -5
  3. wolfhece/PyDraw.py +1151 -413
  4. wolfhece/PyGui.py +2 -4
  5. wolfhece/PyParams.py +1515 -852
  6. wolfhece/PyVertex.py +73 -73
  7. wolfhece/PyVertexvectors.py +226 -808
  8. wolfhece/RatingCurve.py +19 -6
  9. wolfhece/apps/wolf2D.py +11 -0
  10. wolfhece/apps/wolfcompare2Darrays.py +51 -22
  11. wolfhece/bernoulli/NetworkOpenGL.py +337 -341
  12. wolfhece/drawing_obj.py +25 -0
  13. wolfhece/hydrology/Catchment.py +77 -77
  14. wolfhece/hydrology/Optimisation.py +206 -53
  15. wolfhece/hydrology/PostProcessHydrology.py +22 -22
  16. wolfhece/hydrology/SubBasin.py +17 -17
  17. wolfhece/hydrology/constant.py +4 -0
  18. wolfhece/hydrology/cst_exchanges.py +2 -1
  19. wolfhece/lazviewer/processing/estimate_normals/estimate_normals.cp310-win_amd64.pyd +0 -0
  20. wolfhece/lazviewer/vfuncs/vfuncs.cp310-win_amd64.pyd +0 -0
  21. wolfhece/libs/WolfDll.dll +0 -0
  22. wolfhece/libs/wolfogl.cp310-win_amd64.pyd +0 -0
  23. wolfhece/libs/wolfpy.cp310-win_amd64.pyd +0 -0
  24. wolfhece/mesh2d/wolf2dprev.py +4 -4
  25. wolfhece/multiprojects.py +13 -13
  26. wolfhece/pylogging.py +1 -1
  27. wolfhece/pyshields.py +213 -136
  28. wolfhece/pyviews.py +23 -23
  29. wolfhece/wolf_array.py +69 -152
  30. wolfhece/wolf_texture.py +39 -16
  31. wolfhece/wolfresults_2D.py +4 -4
  32. {wolfhece-1.8.12.dist-info → wolfhece-2.0.0.dist-info}/METADATA +3 -2
  33. {wolfhece-1.8.12.dist-info → wolfhece-2.0.0.dist-info}/RECORD +38 -34
  34. wolfhece/apps/wolfgpu.py +0 -19
  35. /wolfhece/lazviewer/processing/estimate_normals/{estimate_normals.pyd → estimate_normals.cp39-win_amd64.pyd} +0 -0
  36. /wolfhece/lazviewer/vfuncs/{vfuncs.pyd → vfuncs.cp39-win_amd64.pyd} +0 -0
  37. {wolfhece-1.8.12.dist-info → wolfhece-2.0.0.dist-info}/LICENCE +0 -0
  38. {wolfhece-1.8.12.dist-info → wolfhece-2.0.0.dist-info}/WHEEL +0 -0
  39. {wolfhece-1.8.12.dist-info → wolfhece-2.0.0.dist-info}/top_level.txt +0 -0
@@ -18,12 +18,14 @@ from typing import Union, Literal
18
18
  import logging
19
19
  from tqdm import tqdm
20
20
  import geopandas as gpd
21
+ import io
22
+ from typing import Union, Literal
21
23
 
22
24
  from .textpillow import Font_Priority
23
25
  from .PyTranslate import _
24
26
  from .CpGrid import CpGrid
25
27
  from .PyVertex import wolfvertex,getIfromRGB,getRGBfromI
26
- from .PyParams import Wolf_Param
28
+ from .PyParams import Wolf_Param, key_Param, Type_Param
27
29
  from .lazviewer.laz_viewer import myviewer
28
30
  from .wolf_texture import Text_Image_Texture,Text_Infos
29
31
  from .drawing_obj import Element_To_Draw
@@ -309,7 +311,7 @@ class Triangulation(Element_To_Draw):
309
311
 
310
312
  self.id_list = -99999
311
313
 
312
- def plot(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
314
+ def plot(self):
313
315
 
314
316
  if self.id_list == -99999:
315
317
  self.id_list = glGenLists(1)
@@ -382,7 +384,7 @@ class Triangulation(Element_To_Draw):
382
384
  self.nb_tri = len(self.tri)
383
385
  self.valid_format()
384
386
  class vectorproperties:
385
-
387
+ """ Vector properties """
386
388
  used:bool
387
389
 
388
390
  color:int
@@ -411,7 +413,14 @@ class vectorproperties:
411
413
 
412
414
  myprops:Wolf_Param = None
413
415
 
414
- def __init__(self,lines=[],parent=None) -> None:
416
+ def __init__(self, lines:list[str]=[], parent:"vector"=None) -> None:
417
+ """
418
+ Init the vector properties -- Compatibility with VB6, Fortran codes --> Modify with care
419
+
420
+ @param lines: list of lines from a file
421
+ @param parent: parent vector
422
+ """
423
+
415
424
  self.parent:vector
416
425
  self.parent=parent
417
426
 
@@ -442,6 +451,7 @@ class vectorproperties:
442
451
 
443
452
  self.used=lines[2]=='#TRUE#'
444
453
  else:
454
+ # default values in case of new vector
445
455
  self.color=0
446
456
  self.width=1
447
457
  self.style=1
@@ -468,31 +478,39 @@ class vectorproperties:
468
478
  self.init_extra()
469
479
 
470
480
  def init_extra(self):
481
+ """
482
+ Init extra properties --> not compatible with VB6, Fortran codes
471
483
 
472
- self.legendlength = 100
473
- self.legendheight = 100
484
+ Useful for Python UI, OpenGL legend, etc.
485
+ """
486
+ self.legendlength = 100.
487
+ self.legendheight = 100.
474
488
  self.legendpriority = 2
475
- self.legendorientation = 0
489
+ self.legendorientation = 0.
476
490
 
477
- def get_extra(self):
491
+ def get_extra(self) -> list[float,float,int,float]:
492
+ """ Return extra properties """
493
+ return [self.legendlength,
494
+ self.legendheight,
495
+ self.legendpriority,
496
+ self.legendorientation]
478
497
 
479
- extras = [self.legendlength,
480
- self.legendheight,
481
- self.legendpriority,
482
- self.legendorientation]
498
+ def set_extra(self, linesextra:list[float,float,int,float] = None):
499
+ """ Set extra properties """
483
500
 
484
- return extras
501
+ if linesextra is None:
502
+ return
485
503
 
486
- def set_extra(self,linesextra:list):
504
+ assert len(linesextra)==4, 'Extra properties must be a list of [float, float, int, float]'
487
505
 
488
- if len(linesextra)>0:
489
- self.legendlength = float(linesextra[0])
490
- self.legendheight = float(linesextra[1])
491
- self.legendpriority = float(linesextra[2])
492
- self.legendorientation = float(linesextra[3])
506
+ self.legendlength = float(linesextra[0])
507
+ self.legendheight = float(linesextra[1])
508
+ self.legendpriority = float(linesextra[2])
509
+ self.legendorientation = float(linesextra[3])
493
510
 
494
511
 
495
- def saveextra(self,f):
512
+ def save_extra(self, f:io.TextIOWrapper):
513
+ """ Save extra properties to opened file """
496
514
 
497
515
  extras = self.get_extra()
498
516
 
@@ -501,7 +519,12 @@ class vectorproperties:
501
519
  for curextra in extras:
502
520
  f.write('{}'.format(curextra)+'\n')
503
521
 
504
- def save(self,f):
522
+ def save(self, f:io.TextIOWrapper):
523
+ """
524
+ Save properties to opened file
525
+
526
+ Pay attention to the order of the lines and the format to be compatible with VB6, Fortran codes
527
+ """
505
528
  line1 = str(self.color) + ',' + str(self.width)+','+ str(self.style)
506
529
 
507
530
  added = ',#TRUE#' if self.closed else ',#FALSE#'
@@ -532,120 +555,39 @@ class vectorproperties:
532
555
  added = '#TRUE#' if self.used else '#FALSE#'
533
556
  f.write(added+'\n')
534
557
 
535
- def fill_property_default(self):
536
-
537
- curdict=self.myprops.myparams_default
538
-
539
- if 'Draw' in curdict.keys():
540
- keysactive = curdict['Draw'].keys()
541
- if 'Color' in keysactive:
542
- self.color = getIfromRGB(curdict['Draw']['Color']['value'])
543
- if 'Width' in keysactive:
544
- self.width = int(curdict['Draw']['Width']['value'])
545
- if 'Style' in keysactive:
546
- self.style = int(curdict['Draw']['Style']['value'])
547
- if 'Closed' in keysactive:
548
- self.closed = bool(curdict['Draw']['Closed']['value'])
549
- if 'Filled' in keysactive:
550
- self.filled = bool(curdict['Draw']['Filled']['value'])
551
- if 'Transparent' in keysactive:
552
- self.transparent = bool(curdict['Draw']['Transparent']['value'])
553
- if 'Alpha' in keysactive:
554
- self.alpha = int(curdict['Draw']['Alpha']['value'])
555
- if 'Flash' in keysactive:
556
- self.flash = bool(curdict['Draw']['Flash']['value'])
557
-
558
- if 'Legend' in curdict.keys():
559
- keysactive = curdict['Legend'].keys()
560
- if 'Underlined' in keysactive:
561
- self.legendunderlined = bool(curdict['Legend']['Underlined']['value'])
562
- if 'Bold' in keysactive:
563
- self.legendbold = bool(curdict['Legend']['Bold']['value'])
564
- if 'Font name' in keysactive:
565
- self.legendfontname = str(curdict['Legend']['Font name']['value'])
566
- if 'Font size' in keysactive:
567
- self.legendfontsize = int(curdict['Legend']['Font size']['value'])
568
- if 'Color' in keysactive:
569
- self.legendcolor = getIfromRGB(curdict['Legend']['Color']['value'])
570
- if 'Italic' in keysactive:
571
- self.legenditalic = bool(curdict['Legend']['Italic']['value'])
572
- if 'relative Position' in keysactive:
573
- self.legendrelpos = int(curdict['Legend']['relative Position']['value'])
574
- if 'Text' in keysactive:
575
- self.legendtext = str(curdict['Legend']['Text']['value'])
576
- if 'Visible' in keysactive:
577
- self.legendvisible = bool(curdict['Legend']['Visible']['value'])
578
- if 'X' in keysactive:
579
- self.legendx = float(curdict['Legend']['X']['value'])
580
- if 'Y' in keysactive:
581
- self.legendy = float(curdict['Legend']['Y']['value'])
582
-
583
- if 'Length' in keysactive:
584
- self.legendlength = float(curdict['Legend']['Length']['value'])
585
- if 'Height' in keysactive:
586
- self.legendheight = float(curdict['Legend']['Height']['value'])
587
- if 'Priority' in keysactive:
588
- self.legendpriority = int(curdict['Legend']['Priority']['value'])
589
- if 'Orientation' in keysactive:
590
- self.legendorientation = float(curdict['Legend']['Orientation']['value'])
591
-
592
558
  def fill_property(self):
593
-
594
- curdict=self.myprops.myparams
595
- self.fill_property_default()
596
-
597
- if 'Draw' in curdict.keys():
598
- keysactive = curdict['Draw'].keys()
599
- if 'Color' in keysactive:
600
- self.color = getIfromRGB(curdict['Draw']['Color']['value'].replace('(','').replace(')','').split(', '))
601
- if 'Width' in keysactive:
602
- self.width = int(curdict['Draw']['Width']['value'])
603
- if 'Style' in keysactive:
604
- self.style = int(curdict['Draw']['Style']['value'])
605
- if 'Closed' in keysactive:
606
- self.closed = bool(curdict['Draw']['Closed']['value'])
607
- if 'Filled' in keysactive:
608
- self.filled = bool(curdict['Draw']['Filled']['value'])
609
- if 'Transparent' in keysactive:
610
- self.transparent = bool(curdict['Draw']['Transparent']['value'])
611
- if 'Alpha' in keysactive:
612
- self.alpha = int(curdict['Draw']['Alpha']['value'])
613
- if 'Flash' in keysactive:
614
- self.flash = bool(curdict['Draw']['Flash']['value'])
615
-
616
- if 'Legend' in curdict.keys():
617
- keysactive = curdict['Legend'].keys()
618
- if 'Underlined' in keysactive:
619
- self.legendunderlined = bool(curdict['Legend']['Underlined']['value'])
620
- if 'Bold' in keysactive:
621
- self.legendbold = bool(curdict['Legend']['Bold']['value'])
622
- if 'Font name' in keysactive:
623
- self.legendfontname = str(curdict['Legend']['Font name']['value'])
624
- if 'Font size' in keysactive:
625
- self.legendfontsize = int(curdict['Legend']['Font size']['value'])
626
- if 'Color' in keysactive:
627
- self.legendcolor = getIfromRGB(curdict['Legend']['Color']['value'].replace('(','').replace(')','').split(', '))
628
- if 'Italic' in keysactive:
629
- self.legenditalic = bool(curdict['Legend']['Italic']['value'])
630
- if 'relative Position' in keysactive:
631
- self.legendrelpos = int(curdict['Legend']['relative Position']['value'])
632
- if 'Text' in keysactive:
633
- self.legendtext = str(curdict['Legend']['Text']['value'])
634
- if 'Visible' in keysactive:
635
- self.legendvisible = bool(curdict['Legend']['Visible']['value'])
636
- if 'X' in keysactive:
637
- self.legendx = float(curdict['Legend']['X']['value'])
638
- if 'Y' in keysactive:
639
- self.legendy = float(curdict['Legend']['Y']['value'])
640
-
641
- if 'Length' in keysactive:
642
- self.legendlength = float(curdict['Legend']['Length']['value'])
643
- if 'Height' in keysactive:
644
- self.legendheight = float(curdict['Legend']['Height']['value'])
645
- if 'Priority' in keysactive:
646
- self.legendpriority = int(curdict['Legend']['Priority']['value'])
647
- if 'Orientation' in keysactive:
648
- self.legendorientation = float(curdict['Legend']['Orientation']['value'])
559
+ """
560
+ Callback for the properties UI
561
+
562
+ When the 'Apply' button is pressed, this function is called
563
+ """
564
+ props = self.myprops
565
+
566
+ self.color = getIfromRGB(props[('Draw','Color')])
567
+ self.width = props[('Draw','Width')]
568
+ self.style = props[('Draw','Style')]
569
+ self.closed = props[('Draw','Closed')]
570
+ self.filled = props[('Draw','Filled')]
571
+ self.transparent = props[('Draw','Transparent')]
572
+ self.alpha = props[('Draw','Alpha')]
573
+ self.flash = props[('Draw','Flash')]
574
+
575
+ self.legendunderlined = props[('Legend','Underlined')]
576
+ self.legendbold = props[('Legend','Bold')]
577
+ self.legendfontname = props[('Legend','Font name')]
578
+ self.legendfontsize = props[('Legend','Font size')]
579
+ self.legendcolor = getIfromRGB(self.myprops[('Legend','Color')])
580
+ self.legenditalic = props[('Legend','Italic')]
581
+ self.legendrelpos = props[('Legend','relative Position')]
582
+ self.legendtext = props[('Legend','Text')]
583
+ self.legendvisible = props[('Legend','Visible')]
584
+ self.legendx = props[('Legend','X')]
585
+ self.legendy = props[('Legend','Y')]
586
+
587
+ self.legendlength = props[('Legend','Length')]
588
+ self.legendheight = props[('Legend','Height')]
589
+ self.legendpriority = props[('Legend','Priority')]
590
+ self.legendorientation = props[('Legend','Orientation')]
649
591
 
650
592
  if self.legendvisible:
651
593
  self.parent.textimage = Text_Image_Texture(self.legendtext,
@@ -657,24 +599,37 @@ class vectorproperties:
657
599
  else:
658
600
  self.parent.textimage=None
659
601
 
602
+ try:
603
+ self.parent.parentzone.parent.mapviewer.Refresh()
604
+ except:
605
+ pass
606
+
660
607
  def get_textfont(self):
608
+ """ Retunr a 'Text_Infos' instance for the legend """
661
609
 
662
610
  r,g,b = getRGBfromI(self.legendcolor)
663
611
  return Text_Infos(self.legendpriority,
664
612
  (np.cos(self.legendorientation/180*np.pi),np.sin(self.legendorientation/180*np.pi)),
665
- self.legendfontname.lower()+'.ttf',
613
+ self.legendfontname.lower().endswith('.ttf'),
666
614
  self.legendfontsize,
667
615
  colour=(r,g,b,255),
668
616
  dimsreal=(self.legendlength,self.legendheight))
669
617
 
670
- def defaultprop(self):
618
+ def _defaultprop(self):
619
+ """
620
+ Create the default properties for the vector and the associated UI
621
+ """
622
+
671
623
  if self.myprops is None:
672
- self.myprops=Wolf_Param(title='Vector Properties',to_read=False)
624
+ self.myprops=Wolf_Param(title='Vector Properties', w=500, h=800, to_read=False)
625
+ self.myprops.show_in_active_if_default = True
673
626
  self.myprops._callbackdestroy = self.destroyprop
674
627
  self.myprops._callback=self.fill_property
675
- self.myprops.saveme.Disable()
676
- self.myprops.loadme.Disable()
677
- self.myprops.reloadme.Disable()
628
+
629
+ self.myprops.hide_selected_buttons() # only 'Apply' button
630
+ # self.myprops.saveme.Disable()
631
+ # self.myprops.loadme.Disable()
632
+ # self.myprops.reloadme.Disable()
678
633
 
679
634
  self.myprops.addparam('Draw','Color',(0,0,0),'Color','Drawing color',whichdict='Default')
680
635
  self.myprops.addparam('Draw','Width',1,'Integer','Drawing width',whichdict='Default')
@@ -692,7 +647,7 @@ class vectorproperties:
692
647
  self.myprops.addparam('Legend','Y',0,'Float','',whichdict='Default')
693
648
  self.myprops.addparam('Legend','Bold',False,'Logical','',whichdict='Default')
694
649
  self.myprops.addparam('Legend','Italic',False,'Logical','',whichdict='Default')
695
- self.myprops.addparam('Legend','Font name','Arial','String','',whichdict='Default')
650
+ self.myprops.addparam('Legend','Font name','Arial', 'String','',whichdict='Default')
696
651
  self.myprops.addparam('Legend','Font size',10,'Integer','',whichdict='Default')
697
652
  self.myprops.addparam('Legend','Color',(0,0,0),'Color','',whichdict='Default')
698
653
  self.myprops.addparam('Legend','Underlined',False,'Logical','',whichdict='Default')
@@ -702,10 +657,21 @@ class vectorproperties:
702
657
  self.myprops.addparam('Legend','Orientation',0,'Float','',whichdict='Default')
703
658
 
704
659
  def destroyprop(self):
660
+ """
661
+ Nullify the properties UI
662
+
663
+ Destroy has been called, so the UI is not visible anymore
664
+ """
705
665
  self.myprops=None
706
666
 
707
667
  def show(self):
708
- self.defaultprop()
668
+ """
669
+ Show the properties
670
+
671
+ Firstly, set default values
672
+ Then, add the current properties to the UI
673
+ """
674
+ self._defaultprop()
709
675
 
710
676
  self.myprops.addparam('Draw','Color',getRGBfromI(self.color),'Color','Drawing color')
711
677
  self.myprops.addparam('Draw','Width',self.width,'Integer','Drawing width')
@@ -734,6 +700,8 @@ class vectorproperties:
734
700
  self.myprops.addparam('Legend','Orientation',self.legendorientation,'Float','')
735
701
 
736
702
  self.myprops.Populate()
703
+ self.myprops.Layout()
704
+ self.myprops.SetSizeHints(500,800)
737
705
  self.myprops.Show()
738
706
 
739
707
  class vector:
@@ -790,11 +758,11 @@ class vector:
790
758
  if type(lines)==list:
791
759
  if len(lines)>0:
792
760
  self.myname=lines[0]
793
- self.nbvertices=int(lines[1])
761
+ tmp_nbvertices=int(lines[1])
794
762
  self.myvertices=[]
795
763
 
796
764
  if is2D:
797
- for i in range(self.nbvertices):
765
+ for i in range(tmp_nbvertices):
798
766
  try:
799
767
  curx,cury=lines[2+i].split()
800
768
  except:
@@ -802,7 +770,7 @@ class vector:
802
770
  curvert = wolfvertex(float(curx),float(cury))
803
771
  self.myvertices.append(curvert)
804
772
  else:
805
- for i in range(self.nbvertices):
773
+ for i in range(tmp_nbvertices):
806
774
  try:
807
775
  curx,cury,curz=lines[2+i].split()
808
776
  except:
@@ -810,11 +778,10 @@ class vector:
810
778
  curvert = wolfvertex(float(curx),float(cury),float(curz))
811
779
  self.myvertices.append(curvert)
812
780
 
813
- self.myprop=vectorproperties(lines[self.nbvertices+2:],parent=self)
781
+ self.myprop=vectorproperties(lines[tmp_nbvertices+2:],parent=self)
814
782
 
815
783
  if name!='' and self.myname=='':
816
784
  self.myname=name
817
- self.nbvertices=0
818
785
  self.myvertices=[]
819
786
  self.myprop=vectorproperties(parent=self)
820
787
 
@@ -829,6 +796,18 @@ class vector:
829
796
  if fromshapely is not None:
830
797
  self.import_shapelyobj(fromshapely)
831
798
 
799
+ @property
800
+ def nbvertices(self) -> int:
801
+ return len(self.myvertices)
802
+
803
+ @property
804
+ def used(self) -> bool:
805
+ return self.myprop.used
806
+
807
+ @used.setter
808
+ def used(self, value:bool):
809
+ self.myprop.used = value
810
+
832
811
  def import_shapelyobj(self, obj):
833
812
  """ Importation d'un objet shapely """
834
813
 
@@ -875,7 +854,10 @@ class vector:
875
854
  return ((xmin, xmax), (ymin, ymax))
876
855
 
877
856
  def get_mean_vertex(self, asshapelyPoint = False):
857
+ """ Return the mean vertex """
858
+
878
859
  if self.closed or (self.myvertices[0].x == self.myvertices[-1].x and self.myvertices[0].y == self.myvertices[-1].y):
860
+ # if closed, we don't take the last vertex otherwise we have a double vertex
879
861
  x_mean = np.mean([curvert.x for curvert in self.myvertices[:-1]])
880
862
  y_mean = np.mean([curvert.y for curvert in self.myvertices[:-1]])
881
863
  z_mean = np.mean([curvert.z for curvert in self.myvertices[:-1]])
@@ -1045,37 +1027,6 @@ class vector:
1045
1027
  else:
1046
1028
  return None
1047
1029
 
1048
- # def offset_curve(self, distance=5.):
1049
- # """
1050
- # The distance parameter must be a signed float value.
1051
- # """
1052
-
1053
- # if self.nbvertices<2:
1054
- # return None
1055
-
1056
- # myls = self.asshapely_ls()
1057
-
1058
- # mypar = myls.offset_curve(distance=abs(distance),join_style=JOIN_STYLE.round)
1059
-
1060
- # if mypar.geom_type=='MultiLineString':
1061
- # return None
1062
-
1063
- # if len(mypar.coords) >0:
1064
-
1065
- # newvec = vector(name='par'+str(distance), parentzone=self.parentzone)
1066
-
1067
- # for x,y in mypar.coords:
1068
- # xy = Point(x,y)
1069
- # curs = mypar.project(xy,True)
1070
- # curz = myls.interpolate(curs,True).z
1071
-
1072
- # newvert = wolfvertex(x,y,curz)
1073
- # newvec.add_vertex(newvert)
1074
-
1075
- # return newvec
1076
- # else:
1077
- # return None
1078
-
1079
1030
  def intersection(self, vec2 = None, eval_dist=False,norm=False, force_single=False):
1080
1031
  """
1081
1032
  Calcul de l'intersection avec un autre vecteur
@@ -1112,7 +1063,6 @@ class vector:
1112
1063
 
1113
1064
  def reset(self):
1114
1065
  """Remise à zéro"""
1115
- self.nbvertices=0
1116
1066
  self.myvertices=[]
1117
1067
  self.linestring=None
1118
1068
 
@@ -1128,7 +1078,6 @@ class vector:
1128
1078
  assert(addedvert is not None)
1129
1079
  assert isinstance(addedvert, wolfvertex)
1130
1080
  self.myvertices.append(addedvert)
1131
- self.nbvertices += 1
1132
1081
 
1133
1082
  def add_vertices_from_array(self, xyz:np.ndarray):
1134
1083
  """
@@ -1144,8 +1093,13 @@ class vector:
1144
1093
  def count(self):
1145
1094
  """
1146
1095
  Retroune le nombre de vertices
1096
+
1097
+ For compatibility with older version of the code --> use 'nbvertices' property instead
1098
+ Must be removed in the future
1147
1099
  """
1148
- self.nbvertices=len(self.myvertices)
1100
+ # Nothing to do because nbvertices is a property
1101
+ # self.nbvertices=len(self.myvertices)
1102
+ return
1149
1103
 
1150
1104
  def close_force(self):
1151
1105
  """
@@ -1263,7 +1217,6 @@ class vector:
1263
1217
 
1264
1218
  myvert=wolfvertex(x,y)
1265
1219
  self.myvertices.insert(indexmp,myvert)
1266
- self.nbvertices+=1
1267
1220
 
1268
1221
  return self.myvertices[indexmp]
1269
1222
 
@@ -1277,7 +1230,7 @@ class vector:
1277
1230
  self.xmax=max(vert.x for vert in self.myvertices)
1278
1231
  self.ymax=max(vert.y for vert in self.myvertices)
1279
1232
 
1280
- def plot(self):
1233
+ def plot(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
1281
1234
  """
1282
1235
  Plot OpenGL
1283
1236
  """
@@ -1399,7 +1352,6 @@ class vector:
1399
1352
 
1400
1353
  while k<self.nbvertices:
1401
1354
  self.myvertices.pop(k)
1402
- self.nbvertices-=1
1403
1355
 
1404
1356
  if self.linestring is not None:
1405
1357
  self.prepare_shapely()
@@ -1582,7 +1534,6 @@ class vector:
1582
1534
  except:
1583
1535
  pass
1584
1536
  else:
1585
- self.nbvertices = newvec.nbvertices
1586
1537
  self.myvertices = newvec.myvertices
1587
1538
  self.update_lengths()
1588
1539
 
@@ -1905,40 +1856,48 @@ class zone:
1905
1856
  mytree:TreeListCtrl
1906
1857
  myitem:TreeItemId
1907
1858
 
1908
- def __getitem__(self, ndx) -> vector:
1909
- return self.myvectors[ndx]
1859
+ def __init__(self,
1860
+ lines:list[str]=[],
1861
+ name:str='NoName',
1862
+ parent:"Zones"=None,
1863
+ is2D:bool=True,
1864
+ fromshapely:Union[LineString,Polygon,MultiLineString, MultiPolygon]=None) -> None:
1910
1865
 
1911
- def __init__(self, lines=[], name='NoName', parent=None, is2D=True, fromshapely=None) -> None:
1912
-
1913
- self.myname = ''
1914
- self.idgllist = -99999
1915
- self.active_vector=None
1916
- self.parent=parent
1866
+ self.myname = '' # name of the zone
1867
+ self.idgllist = -99999 # id of the zone in the gllist
1868
+ self.active_vector=None # current active vector
1869
+ self.parent=parent # parent object - type(Zones)
1917
1870
 
1918
1871
  if len(lines)>0:
1872
+ # Decoding from lines -- lines is a list of strings provided by the parent during reading
1873
+ # The order of the lines is important to ensure compatibility with the WOLF2D format
1919
1874
  self.myname=lines[0]
1920
- self.nbvectors=int(lines[1])
1875
+ tmp_nbvectors=int(lines[1])
1921
1876
  self.myvectors=[]
1922
1877
  curstart=2
1923
- for i in range(self.nbvectors):
1878
+ for i in range(tmp_nbvectors):
1924
1879
  curvec=vector(lines[curstart:],parentzone=self,is2D=is2D)
1925
1880
  curstart+=curvec._nblines()
1926
1881
  self.myvectors.append(curvec)
1927
1882
 
1928
1883
  if name!='' and self.myname=='':
1929
1884
  self.myname=name
1930
- self.nbvectors=0
1931
1885
  self.myvectors=[]
1932
1886
 
1933
- self.selected_vectors=[]
1934
- self.multils = None
1935
- self.used = True
1887
+ self.selected_vectors=[] # list of selected vectors
1888
+ self.multils:MultiLineString = None # MultiLineString shapely
1889
+ self.used = True # indicate if the zone must used or not --> corresponding to checkbox in the tree
1936
1890
 
1937
- self.mytree=None
1891
+ self.mytree=None # TreeListCtrl wx
1938
1892
 
1939
1893
  if fromshapely is not None:
1894
+ # Object can be created from a shapely object
1940
1895
  self.import_shapelyobj(fromshapely)
1941
1896
 
1897
+ @property
1898
+ def nbvectors(self):
1899
+ return len(self.myvectors)
1900
+
1942
1901
  def import_shapelyobj(self, obj):
1943
1902
  """ Importation d'un objet shapely """
1944
1903
 
@@ -1965,7 +1924,7 @@ class zone:
1965
1924
  Si plusieurs vecteurs portent le même nom, seule le premier est retourné
1966
1925
  """
1967
1926
  if isinstance(keyvector,int):
1968
- if keyvector<self.nbvectors:
1927
+ if keyvector < self.nbvectors:
1969
1928
  return self.myvectors[keyvector]
1970
1929
  return None
1971
1930
  if isinstance(keyvector,str):
@@ -1974,7 +1933,12 @@ class zone:
1974
1933
  return self.myvectors[zone_names.index(keyvector)]
1975
1934
  return None
1976
1935
 
1936
+ def __getitem__(self, ndx:Union[int,str]) -> vector:
1937
+ """ Permet de retrouver un vecteur sur base de son index """
1938
+ return self.get_vector(ndx)
1939
+
1977
1940
  def export_shape(self, fn:str = ''):
1941
+ """ Export to shapefile using GDAL/OGR """
1978
1942
 
1979
1943
  from osgeo import gdal, osr, gdalconst,ogr
1980
1944
 
@@ -2023,7 +1987,7 @@ class zone:
2023
1987
  # Save and close DataSource
2024
1988
  ds = None
2025
1989
 
2026
- def save(self,f):
1990
+ def save(self, f:io.TextIOWrapper):
2027
1991
  """
2028
1992
  Ecriture sur disque
2029
1993
  """
@@ -2032,14 +1996,14 @@ class zone:
2032
1996
  for curvect in self.myvectors:
2033
1997
  curvect.save(f)
2034
1998
 
2035
- def saveextra(self,f):
1999
+ def save_extra(self, f:io.TextIOWrapper):
2036
2000
  """
2037
2001
  Ecriture des options EXTRA
2038
2002
  """
2039
2003
  f.write(self.myname+'\n')
2040
2004
  curvect:vector
2041
2005
  for curvect in self.myvectors:
2042
- curvect.myprop.saveextra(f)
2006
+ curvect.myprop.save_extra(f)
2043
2007
 
2044
2008
  def add_vector(self, addedvect:vector, index=-99999, forceparent=False):
2045
2009
  """
@@ -2050,21 +2014,28 @@ class zone:
2050
2014
  self.myvectors.append(addedvect)
2051
2015
  else:
2052
2016
  self.myvectors.insert(index,addedvect)
2053
- self.nbvectors+=1
2017
+
2054
2018
  # FIXME set vector's parent to self ?
2019
+ # NOT necessary because, in some situation, we can add a vector
2020
+ # to a temporary zone without forcing its parent to be this zone
2021
+ if forceparent:
2022
+ addedvect.parentzone = self
2055
2023
 
2056
2024
  if self.nbvectors==1:
2057
2025
  self.active_vector = addedvect
2058
2026
  # FIXME else ?
2059
-
2060
- if forceparent:
2061
- addedvect.parentzone = self
2027
+ # NOTHING because the active vector is normally choosen by the UI or during special operations
2028
+ # Here, we select the first added vector
2062
2029
 
2063
2030
  def count(self):
2064
2031
  """
2065
- Nombre de vecteurs
2032
+ Compte le nombre de vecteurs
2033
+
2034
+ For compatibility with older versions --> Must be removed in future version
2066
2035
  """
2067
- self.nbvectors=len(self.myvectors)
2036
+ # self.nbvectors=len(self.myvectors)
2037
+ # Nothing to do because the number of vectors is a property
2038
+ return
2068
2039
 
2069
2040
  def _nblines(self):
2070
2041
  """
@@ -2227,8 +2198,6 @@ class zone:
2227
2198
  mypl = self.active_vector.parallel_offset(distance,'right')
2228
2199
  elif distance<0.:
2229
2200
  mypl = self.active_vector.parallel_offset(distance,'left')
2230
- # if abs(distance)>0.:
2231
- # mypl = self.active_vector.offset_curve(distance)
2232
2201
  else:
2233
2202
  mypl = vector(name=self.active_vector.myname+"_duplicate")
2234
2203
  mypl.myvertices = [wolfvertex(cur.x,cur.y,cur.z) for cur in self.active_vector.myvertices]
@@ -3188,15 +3157,12 @@ class Zones(wx.Frame, Element_To_Draw):
3188
3157
  tx:float
3189
3158
  ty:float
3190
3159
 
3191
- nbzones:int
3160
+ # nbzones:int
3192
3161
 
3193
3162
  myzones:list[zone]
3194
3163
  treelist:TreeListCtrl
3195
3164
  xls:CpGrid
3196
3165
 
3197
- def __getitem__(self, ndx) -> zone:
3198
- return self.myzones[ndx]
3199
-
3200
3166
  def __init__(self, filename='', ox:float=0., oy:float=0., tx:float=0., ty:float=0., parent=None, is2D=True, idx: str = '', plotted: bool = True, mapviewer=None, need_for_wx: bool = False) -> None:
3201
3167
  """
3202
3168
  parent : soit une instance 'WolfMapViewer', soit une instance 'Ops_Array'
@@ -3252,7 +3218,6 @@ class Zones(wx.Frame, Element_To_Draw):
3252
3218
  self.tx=tx
3253
3219
  self.ty=ty
3254
3220
  self.myzones=[]
3255
- self.nbzones=0
3256
3221
 
3257
3222
  if filename!='':
3258
3223
  # lecture du fichier
@@ -3278,17 +3243,22 @@ class Zones(wx.Frame, Element_To_Draw):
3278
3243
 
3279
3244
  self.tx=float(tx)
3280
3245
  self.ty=float(ty)
3281
- self.nbzones=int(lines[1])
3246
+ tmp_nbzones=int(lines[1])
3282
3247
 
3283
3248
  curstart=2
3284
- for i in range(self.nbzones):
3249
+ for i in range(tmp_nbzones):
3285
3250
  curzone=zone(lines[curstart:],parent=self,is2D=self.is2D)
3286
3251
  self.myzones.append(curzone)
3287
3252
  curstart+=curzone._nblines()
3288
3253
 
3289
3254
  self.find_minmax(True)
3290
3255
 
3256
+ @property
3257
+ def nbzones(self):
3258
+ return len(self.myzones)
3259
+
3291
3260
  def import_shapefile(self, fn:str, bbox:Polygon = None):
3261
+ """ Import shapefile by using geopandas """
3292
3262
 
3293
3263
  content = gpd.read_file(fn, bbox=bbox)
3294
3264
 
@@ -3333,6 +3303,11 @@ class Zones(wx.Frame, Element_To_Draw):
3333
3303
  return self.myzones[zone_names.index(keyzone)]
3334
3304
  return None
3335
3305
 
3306
+ def __getitem__(self, ndx:Union[int,str]) -> zone:
3307
+ """ Retourne la zone sur base de son nom ou de sa position """
3308
+
3309
+ return self.get_zone(ndx)
3310
+
3336
3311
  def import_dxf(self, fn, imported_elts=['POLYLINE','LWPOLYLINE','LINE']):
3337
3312
  """
3338
3313
  Import d'un fichier DXF en tant qu'objets WOLF
@@ -3508,7 +3483,7 @@ class Zones(wx.Frame, Element_To_Draw):
3508
3483
 
3509
3484
  with open(self.filename + '.extra', 'w') as f:
3510
3485
  for curzone in self.myzones:
3511
- curzone.saveextra(f)
3486
+ curzone.save_extra(f)
3512
3487
 
3513
3488
  def OnClose(self, e):
3514
3489
  """
@@ -3522,7 +3497,6 @@ class Zones(wx.Frame, Element_To_Draw):
3522
3497
  Ajout d'une zone à la liste
3523
3498
  """
3524
3499
  self.myzones.append(addedzone)
3525
- self.nbzones+=1
3526
3500
 
3527
3501
  if forceparent:
3528
3502
  addedzone.parent = self
@@ -3560,7 +3534,7 @@ class Zones(wx.Frame, Element_To_Draw):
3560
3534
  self.xmax=1.
3561
3535
  self.ymax=1.
3562
3536
 
3563
- def plot(self):
3537
+ def plot(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
3564
3538
  """
3565
3539
  Dessine les zones
3566
3540
  """
@@ -4680,7 +4654,6 @@ class Zones(wx.Frame, Element_To_Draw):
4680
4654
 
4681
4655
  self.active_zone.reset_listogl()
4682
4656
  self.myzones.pop(int(self.myzones.index(self.active_zone)))
4683
- self.nbzones-=1
4684
4657
  self.fill_structure()
4685
4658
  self.find_minmax(True)
4686
4659
 
@@ -4781,7 +4754,6 @@ class Zones(wx.Frame, Element_To_Draw):
4781
4754
 
4782
4755
  actzone =self.active_zone
4783
4756
  actzone.myvectors.pop(int(actzone.myvectors.index(self.active_vector)))
4784
- actzone.nbvectors-=1
4785
4757
  self.fill_structure()
4786
4758
  self.find_minmax(True)
4787
4759
 
@@ -4974,56 +4946,49 @@ class Zones(wx.Frame, Element_To_Draw):
4974
4946
  dlg.Destroy()
4975
4947
  return
4976
4948
 
4977
- def add_interpolators(self, myinterpolators):
4978
- """
4979
- Ajout d'objets 'Interpolators' pour affichage/stockage
4980
- """
4981
- myinterpolators:Interpolators
4982
- curinterp:Interpolator
4983
-
4984
- zonesinterp=Zones(parent=self.parent)
4985
-
4986
- id=0
4987
- points=[]
4988
- triangles=[]
4989
- decal=0
4990
- for curinterp in myinterpolators.myinterp:
4991
- id+=1
4992
-
4993
- myzone = zone(name='Interpolator'+str(id), parent=zonesinterp, is2D=False)
4994
- myzone.used=False
4995
- zonesinterp.add_zone(myzone)
4996
- curinterp.add_triangles_to_zone(myzone)
4949
+ class Grid(Zones):
4950
+ """
4951
+ Grid to draw on the mapviewer.
4997
4952
 
4998
- nbpts,pts,tr=curinterp.get_triangles()
4953
+ Contains one zone and 3 vectors (gridx, gridy, contour).
4999
4954
 
5000
- points.append(pts)
5001
- triangles.append(tr+decal)
5002
- decal+=nbpts
4955
+ Each gridx and gridy vector contains vertices forming a continuous line.
4956
+ Contour vector contains 4 vertices forming a closed polyline.
5003
4957
 
5004
- curinterp.export_gltf(np.concatenate(points),np.concatenate(triangles))
4958
+ Drawing all the elements on the mapviewer allows to draw a grid.
5005
4959
 
5006
- # if self.wx_exists:
5007
- # self.fill_structure()
4960
+ Based on spatial extent and resolution.
4961
+ """
5008
4962
 
5009
- return zonesinterp
4963
+ def __init__(self,
4964
+ size:float=1000.,
4965
+ ox:float=0.,
4966
+ oy:float=0.,
4967
+ ex:float=1000.,
4968
+ ey:float=1000.,
4969
+ parent=None):
5010
4970
 
5011
- class Grid(Zones):
5012
-
5013
- def __init__(self, size:float=1000.,ox:float=0.,oy:float=0.,ex:float=1000.,ey:float=1000., parent=None):
5014
4971
  super().__init__(ox=ox, oy=oy, parent=parent)
5015
4972
 
5016
- mygrid=zone(name='mygrid',parent=self)
4973
+ mygrid=zone(name='grid',parent=self)
5017
4974
  self.add_zone(mygrid)
5018
- mygridx=vector(name='mygridx')
5019
- mygridy=vector(name='mygridy')
4975
+
4976
+ gridx=vector(name='gridx')
4977
+ gridy=vector(name='gridy')
5020
4978
  contour=vector(name='contour')
5021
- mygrid.add_vector(mygridx)
5022
- mygrid.add_vector(mygridy)
4979
+
4980
+ mygrid.add_vector(gridx)
4981
+ mygrid.add_vector(gridy)
5023
4982
  mygrid.add_vector(contour)
4983
+
5024
4984
  self.creategrid(size,ox,oy,ex,ey)
5025
4985
 
5026
- def creategrid(self,size:float=100.,ox:float=0.,oy:float=0.,ex:float=1000.,ey:float=1000.):
4986
+ def creategrid(self,
4987
+ size:float=100.,
4988
+ ox:float=0.,
4989
+ oy:float=0.,
4990
+ ex:float=1000.,
4991
+ ey:float=1000.):
5027
4992
 
5028
4993
  mygridx=self.myzones[0].myvectors[0]
5029
4994
  mygridy=self.myzones[0].myvectors[1]
@@ -5081,550 +5046,3 @@ class Grid(Zones):
5081
5046
  contour.add_vertex(newvert)
5082
5047
 
5083
5048
  self.find_minmax(True)
5084
-
5085
- class Interpolator():
5086
- """
5087
- Objet d'interpolation sur sections en travers
5088
-
5089
- - self.interpolants est une liste de listes
5090
- - chaque élément de self.interpolants est également une liste de listes
5091
- - chaque liste de self.interpolants[k] contient les wolfvertex de la section discrétisée
5092
-
5093
- """
5094
-
5095
- def __init__(self,vec1:vector,vec2:vector,supports:list,ds=1.) -> None:
5096
-
5097
- self.interpolants=[]
5098
-
5099
- sect1={}
5100
- sect2={}
5101
-
5102
- #Linestrings shapely des sections 1 et 2
5103
- #ATTENTION, SHAPELY est une librairie géométrique 2D --> des outils spécifiques ont été programmés pour faire l'interpolation 3D
5104
- s1=sect1['ls']=vec1.asshapely_ls()
5105
- s2=sect2['ls']=vec2.asshapely_ls()
5106
-
5107
- nb = 0
5108
- supls={}
5109
-
5110
- eps=5.e-2
5111
-
5112
- for curvec in supports:
5113
- #linestring du support courant
5114
- #distances des intersections des sections sur le support
5115
- myls:LineString
5116
- myls=curvec.asshapely_ls()
5117
-
5118
- #intersections du vecteur support avec les sections
5119
- i1=myls.intersects(s1)
5120
- if not i1:
5121
- pt=Point(s1.xy[0][0],s1.xy[1][0])
5122
- pt1=myls.interpolate(myls.project(pt))
5123
- length = pt1.distance(pt)
5124
- i1 = length<eps
5125
-
5126
- if i1:
5127
- vec1.myvertices[0].x=pt1.xy[0][0]
5128
- vec1.myvertices[0].y=pt1.xy[1][0]
5129
- s1=vec1.asshapely_ls()
5130
-
5131
- if not i1:
5132
- pt=Point(s1.xy[0][-1],s1.xy[1][-1])
5133
- pt1=myls.interpolate(myls.project(pt))
5134
- length = pt1.distance(pt)
5135
- i1 = length<eps
5136
- if i1:
5137
- vec1.myvertices[-1].x=pt1.xy[0][-1]
5138
- vec1.myvertices[-1].y=pt1.xy[1][-1]
5139
- s1=vec1.asshapely_ls()
5140
-
5141
- i2=myls.intersects(s2)
5142
- if not i2:
5143
- pt=Point(s2.xy[0][0],s2.xy[1][0])
5144
- pt2=myls.interpolate(myls.project(pt))
5145
- length = pt2.distance(Point(s2.xy[0][0],s2.xy[1][0]))
5146
- i2 = length<eps
5147
-
5148
- if i2:
5149
- vec2.myvertices[0].x=pt2.xy[0][0]
5150
- vec2.myvertices[0].y=pt2.xy[1][0]
5151
- s2=vec2.asshapely_ls()
5152
-
5153
- if not i2:
5154
- pt=Point(s2.xy[0][-1],s2.xy[1][-1])
5155
- pt2=myls.interpolate(myls.project(pt))
5156
- length = pt2.distance(pt)
5157
- i2 = length<eps
5158
- if i2:
5159
- vec2.myvertices[-1].x=pt2.xy[0][-1]
5160
- vec2.myvertices[-1].y=pt2.xy[1][-1]
5161
- s2=vec2.asshapely_ls()
5162
-
5163
- if i1 and i2:
5164
- supls[nb]={}
5165
- supls[nb]['ls']=myls
5166
- supls[nb]['vec']=curvec
5167
- nb+=1
5168
-
5169
- #bouclage sur les vecteurs supports pour trouver les intersections avec les sections
5170
- # - trouver la portion utile entre intersections des supports
5171
- # - trouver les distances sur les sections de ces intersections
5172
- for k in range(nb):
5173
- #linestring du support courant
5174
- #distances des intersections des sections sur le support
5175
- myls:LineString
5176
- myls=supls[k]['ls']
5177
-
5178
- #intersections du vecteur support avec les sections
5179
-
5180
- #section amont
5181
- i1=myls.intersection(s1)
5182
- if i1.geom_type=='MultiPoint':
5183
- i1=i1.geoms[0]
5184
-
5185
- #section aval
5186
- i2=myls.intersection(s2)
5187
- if i2.geom_type=='MultiPoint':
5188
- i2=i2.geoms[0]
5189
-
5190
- #Les distances, sur les sections, sont calculées en projetant l'intersection du vecteur support et des sections
5191
- sect1[k]=s1.project(i1)
5192
- sect2[k]=s2.project(i2)
5193
-
5194
- #Les distances, sur le support, sont calculées en projetant l'intersection du vecteur support et des sections
5195
- supls[k][1]=myls.project(i1)
5196
- if supls[k][1]==-1.:
5197
- #problème de précision de calcul
5198
- if myls.distance(Point(s1.xy[0][0],s1.xy[1][0]))<eps:
5199
- supls[k][1]=myls.project(Point(s1.xy[0][0],s1.xy[1][0]))
5200
- sect1[k]=s1.project(Point(s1.xy[0][0],s1.xy[1][0]))
5201
- elif myls.distance(Point(s1.xy[0][-1],s1.xy[1][-1]))<eps:
5202
- supls[k][1]=myls.project(Point(s1.xy[0][-1],s1.xy[1][-1]))
5203
- sect1[k]=s1.project(Point(s1.xy[0][-1],s1.xy[1][-1]))
5204
-
5205
- supls[k][2]=myls.project(i2)
5206
- if supls[k][2]==-1.:
5207
- #problème de précision de calcul
5208
- if myls.distance(Point(s2.xy[0][0],s2.xy[1][0]))<eps:
5209
- supls[k][2]=myls.project(Point(s2.xy[0][0],s2.xy[1][0]))
5210
- sect2[k]=s2.project(Point(s2.xy[0][0],s2.xy[1][0]))
5211
- elif myls.distance(Point(s2.xy[0][-1],s2.xy[1][-1]))<eps:
5212
- supls[k][2]=myls.project(Point(s2.xy[0][-1],s2.xy[1][-1]))
5213
- sect2[k]=s2.project(Point(s2.xy[0][-1],s2.xy[1][-1]))
5214
-
5215
- #on ne conserve que la fraction utile entre intersections
5216
- supls[k]['vec']=supls[k]['vec'].substring(supls[k][1],supls[k][2],False,False)
5217
-
5218
- #bouclage sur les intervalles --> nb_supports-1
5219
- for k in range(nb-1):
5220
- interpolant=[]
5221
- self.interpolants.append(interpolant)
5222
-
5223
- cursupl:vector
5224
- cursupr:vector
5225
- curvec1:vector
5226
- curvec2:vector
5227
-
5228
- #morceaux de sections entre intersections avec le support
5229
- curvec1=sect1['sub'+str(k)]=vec1.substring(sect1[k],sect1[k+1],is3D=False,adim=False)
5230
- curvec2=sect2['sub'+str(k)]=vec2.substring(sect2[k],sect2[k+1],is3D=False,adim=False)
5231
-
5232
- #pointeurrs vers les morceaux des supports
5233
- cursupl = supls[k]['vec']
5234
- cursupr = supls[k+1]['vec']
5235
-
5236
- #MAJ des longueurs 2D et 3D
5237
- cursupl.update_lengths()
5238
- cursupr.update_lengths()
5239
- curvec1.update_lengths()
5240
- curvec2.update_lengths()
5241
-
5242
- #Trouve la liste des distances à traiter pour le maillage
5243
- nbi = np.ceil(max(curvec1.length3D,curvec2.length3D)/ds)
5244
- locds = 1./float(nbi)
5245
- dist3d = np.concatenate([np.arange(0.,1.,locds),np.cumsum(curvec1._lengthparts3D)/curvec1.length3D,np.cumsum(curvec2._lengthparts3D)/curvec2.length3D])
5246
- dist3d = np.unique(dist3d)
5247
-
5248
- #nombre de points à traiter sur les supports
5249
- # on divise la longueur 3D des supports par la taille souhaitée et on arrondi à l'entier supérieur
5250
- nbi = int(np.ceil(max(cursupl.length3D,cursupr.length3D)/ds))
5251
- # nouvelle distance de calcul
5252
- locds = 1./float(nbi)
5253
-
5254
- sloc=0.
5255
- pt1l = curvec1.interpolate(0.,True,True)
5256
- pt2l = curvec2.interpolate(0.,True,True)
5257
- pt1r = curvec1.interpolate(1.,True,True)
5258
- pt2r = curvec2.interpolate(1.,True,True)
5259
-
5260
- s1dr = vector(name='sectiondroite1')
5261
- s2dr = vector(name='sectiondroite2')
5262
- s1dr.add_vertex([pt1l,pt1r])
5263
- s2dr.add_vertex([pt2l,pt2r])
5264
-
5265
- s1dr = s1dr.asshapely_ls()
5266
- s2dr = s2dr.asshapely_ls()
5267
-
5268
- # if np.isnan(pt1l.x):
5269
- # a=1
5270
- # if np.isnan(pt2l.x):
5271
- # a=1
5272
- # if np.isnan(pt1r.x):
5273
- # a=1
5274
- # if np.isnan(pt2r.x):
5275
- # a=1
5276
-
5277
- for curalong in range(nbi+1):
5278
- print(str(curalong))
5279
-
5280
- #interpolation 3D sur les 2 supports
5281
- l1 = cursupl.interpolate(sloc,True,True)
5282
- l2 = cursupr.interpolate(sloc,True,True)
5283
-
5284
- curvec=vector(name='loc')
5285
- curvec.add_vertex([l1,l2])
5286
- val = []
5287
-
5288
- if l1.z!=0.:
5289
- if pt1l.z==0.:
5290
- alpha1l=0.
5291
- else:
5292
- alpha1l = l1.z/pt1l.z
5293
- if pt2l.z==0.:
5294
- alpha2l=0.
5295
- else:
5296
- alpha2l = l1.z/pt2l.z
5297
- else:
5298
- alpha1l = 0.
5299
- alpha2l = 0.
5300
- if l2.z!=0.:
5301
- if pt1r.z==0.:
5302
- alpha1r = 0.
5303
- else:
5304
- alpha1r = l2.z/pt1r.z
5305
-
5306
- if pt2r.z==0.:
5307
- alpha2r = 0.
5308
- else:
5309
- alpha2r = l2.z/pt2r.z
5310
- else:
5311
- alpha1r=0.
5312
- alpha2r=0.
5313
-
5314
- for curdist in dist3d:
5315
-
5316
- #interpolation 3D dans les 2 sections
5317
- cur1 = curvec1.interpolate(curdist,True,True)
5318
- cur2 = curvec2.interpolate(curdist,True,True)
5319
-
5320
- alpha1 = alpha1l*(1.-curdist)+alpha1r*curdist
5321
- alpha2 = alpha2l*(1.-curdist)+alpha2r*curdist
5322
-
5323
- sr1 = s1dr.project(Point(cur1.x,cur1.y))
5324
- sr2 = s2dr.project(Point(cur2.x,cur2.y))
5325
- pr1 = s1dr.interpolate(sr1)
5326
- pr2 = s2dr.interpolate(sr2)
5327
- sr1/=s1dr.length
5328
- sr2/=s2dr.length
5329
-
5330
- dx1 = cur1.x-pr1.x
5331
- dy1 = cur1.y-pr1.y
5332
- dx2 = cur2.x-pr2.x
5333
- dy2 = cur2.y-pr2.y
5334
- dx = dx1*(1.-sloc)+dx2*sloc
5335
- dy = dy1*(1.-sloc)+dy2*sloc
5336
- s = sr1*(1.-sloc)+sr2*sloc
5337
-
5338
- # dist2d1 = cur1.dist2D(curvec1.myvertices[0])/curvec1.myvertices[0].dist2D(curvec1.myvertices[-1]) #curvec1.length2D
5339
- # dist2d2 = cur2.dist2D(curvec2.myvertices[0])/curvec2.myvertices[0].dist2D(curvec2.myvertices[-1]) #curvec2.length2D
5340
- # dist2d = dist2d1*(1.-sloc) + dist2d2*sloc
5341
- # pt = curvec.interpolate(dist2d,False,True)
5342
- pt = curvec.interpolate(s,False,True)
5343
-
5344
- # xloc = cur1.x + sloc * (cur2.x-cur1.x)
5345
- # yloc = cur1.y + sloc * (cur2.y-cur1.y)
5346
- zloc = cur1.z*alpha1 + sloc * (cur2.z*alpha2-cur1.z*alpha1)
5347
-
5348
- val.append(wolfvertex(pt.x+dx,pt.y+dy,zloc))
5349
- # val.append(wolfvertex(xloc,yloc,zloc))
5350
-
5351
- interpolant.append(val)
5352
-
5353
- sloc+=locds
5354
- sloc=min(sloc,1.)
5355
-
5356
- def get_xyz_for_viewer(self,nbsub=10):
5357
-
5358
- pts=self.interpolants
5359
-
5360
- nb=0
5361
- for curpt in pts:
5362
- for curl in curpt:
5363
- nb+=(len(curpt)-1)*(len(curl)-1)*3+(len(curl)-1)+(len(curpt))
5364
-
5365
- pond=np.arange(0.,1.,1./float(nbsub))
5366
- xyz=np.ones([(nb-1)*nbsub,4],order='F')
5367
- start=0
5368
- for curpt in pts:
5369
- for k in range(len(curpt)-1):
5370
- curl=curpt[k]
5371
- nextl=curpt[k+1]
5372
- for i in range(len(curl)-1):
5373
- v1=curl[i].getcoords()
5374
- v2=curl[i+1].getcoords()
5375
- v3=nextl[i].getcoords()
5376
-
5377
- xyz[start:start+nbsub,:3]=[v1+(v2-v1)*curpond for curpond in pond]
5378
- start+=nbsub
5379
- xyz[start:start+nbsub,:3]= [v2+(v3-v2)*curpond for curpond in pond]
5380
- start+=nbsub
5381
- xyz[start:start+nbsub,:3]= [v3+(v1-v3)*curpond for curpond in pond]
5382
- start+=nbsub
5383
-
5384
- curl=curpt[-1]
5385
- for i in range(len(curl)-1):
5386
- v1=curl[i].getcoords()
5387
- v2=curl[i+1].getcoords()
5388
- xyz[start:start+nbsub,:3]=[v1+(v2-v1)*curpond for curpond in pond]
5389
- start+=nbsub
5390
- for k in range(len(curpt)-1):
5391
- curl=curpt[k]
5392
- nextl=curpt[k+1]
5393
- v1=curl[-1].getcoords()
5394
- v3=nextl[-1].getcoords()
5395
- xyz[start:start+nbsub,:3]=[v1+(v3-v1)*curpond for curpond in pond]
5396
- start+=nbsub
5397
-
5398
- return xyz
5399
-
5400
- def add_triangles_to_zone(self,myzone:zone):
5401
-
5402
- nb=0
5403
- npt=1
5404
- for curpt in self.interpolants:
5405
- for k in range(len(curpt)-1):
5406
- curl=curpt[k]
5407
- nextl=curpt[k+1]
5408
- for i in range(len(curl)-1):
5409
- curvec = vector(name='tr'+'_'+str(npt)+'_'+str(k)+'_'+str(i),parentzone=myzone)
5410
- curvec.add_vertex([curl[i],curl[i+1],nextl[i]])
5411
- curvec.close_force()
5412
- curvec.myprop.used=False
5413
- myzone.add_vector(curvec)
5414
-
5415
- curvec = vector(name='tr'+'_'+str(npt)+'_'+str(k+1)+'_'+str(i),parentzone=myzone)
5416
- curvec.add_vertex([nextl[i],curl[i+1],nextl[i+1]])
5417
- curvec.close_force()
5418
- curvec.myprop.used=False
5419
- myzone.add_vector(curvec)
5420
-
5421
- npt+=1
5422
- nb+=(len(curpt)-1)*(len(curl)-1)*3+(len(curl)-1)+(len(curpt))
5423
-
5424
- def get_triangles(self,forgltf=True):
5425
-
5426
- points=[]
5427
- triangles=[]
5428
- nbpts=0
5429
- nbtr=0
5430
- for curpt in self.interpolants:
5431
-
5432
- nb_points_perline = len(curpt[0])
5433
- nbsect=len(curpt)
5434
- if forgltf:
5435
- pointsloc=[[pt.x,pt.z,-pt.y] for curl in curpt for pt in curl]
5436
- else:
5437
- pointsloc=[[pt.x,pt.y,pt.z] for curl in curpt for pt in curl]
5438
-
5439
- trianglesloc=[[[k+decal*nb_points_perline+nbpts,
5440
- k+1+decal*nb_points_perline+nbpts,
5441
- nb_points_perline+k+decal*nb_points_perline+nbpts],
5442
-
5443
- [nb_points_perline+k+decal*nb_points_perline+nbpts,
5444
- k+1+decal*nb_points_perline+nbpts,
5445
- nb_points_perline+k+decal*nb_points_perline+1+nbpts]]
5446
- for decal in range(len(curpt)-1) for k in range(nb_points_perline-1)]
5447
-
5448
- nbpts+=nb_points_perline*nbsect
5449
- nbloc=(nb_points_perline-1)*(nbsect-1)*2
5450
- nbtr+=nbloc
5451
-
5452
- points.append(pointsloc)
5453
- triangles.append(np.asarray(trianglesloc).reshape([nbloc,3]))
5454
-
5455
-
5456
- points=np.asarray(np.concatenate(points),dtype=np.float32)
5457
- triangles=np.asarray(np.concatenate(triangles),dtype=np.uint32)
5458
-
5459
-
5460
- if len(np.argwhere(np.isnan(points)==True))>0:
5461
- a=1
5462
-
5463
- return nbpts,points,triangles
5464
-
5465
- def get_points(self,forgltf=False):
5466
-
5467
- points=[]
5468
- nbpts=0
5469
- for curpt in self.interpolants:
5470
-
5471
- nb_points_perline = len(curpt[0])
5472
- nbsect=len(curpt)
5473
- if forgltf:
5474
- pointsloc=[[pt.x,pt.z,-pt.y] for curl in curpt for pt in curl]
5475
- else:
5476
- pointsloc=[[pt.x,pt.y,pt.z] for curl in curpt for pt in curl]
5477
-
5478
- nbpts+=nb_points_perline*nbsect
5479
- points.append(pointsloc)
5480
-
5481
- if forgltf:
5482
- points=np.asarray(np.concatenate(points),dtype=np.float32)
5483
- else:
5484
- points=np.asarray(np.concatenate(points))
5485
-
5486
- return nbpts,points
5487
-
5488
- def export_gltf(self,points=None,triangles=None):
5489
-
5490
- if points is None and triangles is None:
5491
- points,triangles= self.get_triangles()
5492
-
5493
- triangles_binary_blob = triangles.flatten().tobytes()
5494
- points_binary_blob = points.tobytes()
5495
-
5496
- gltf = pygltflib.GLTF2(
5497
- scene=0,
5498
- scenes=[pygltflib.Scene(nodes=[0])],
5499
- nodes=[pygltflib.Node(mesh=0)],
5500
- meshes=[
5501
- pygltflib.Mesh(
5502
- primitives=[
5503
- pygltflib.Primitive(
5504
- attributes=pygltflib.Attributes(POSITION=1), indices=0
5505
- )
5506
- ]
5507
- )
5508
- ],
5509
- accessors=[
5510
- pygltflib.Accessor(
5511
- bufferView=0,
5512
- componentType=pygltflib.UNSIGNED_INT,
5513
- count=triangles.size,
5514
- type=pygltflib.SCALAR,
5515
- max=[int(triangles.max())],
5516
- min=[int(triangles.min())],
5517
- ),
5518
- pygltflib.Accessor(
5519
- bufferView=1,
5520
- componentType=pygltflib.FLOAT,
5521
- count=len(points),
5522
- type=pygltflib.VEC3,
5523
- max=points.max(axis=0).tolist(),
5524
- min=points.min(axis=0).tolist(),
5525
- ),
5526
- ],
5527
- bufferViews=[
5528
- pygltflib.BufferView(
5529
- buffer=0,
5530
- byteLength=len(triangles_binary_blob),
5531
- target=pygltflib.ELEMENT_ARRAY_BUFFER,
5532
- ),
5533
- pygltflib.BufferView(
5534
- buffer=0,
5535
- byteOffset=len(triangles_binary_blob),
5536
- byteLength=len(points_binary_blob),
5537
- target=pygltflib.ARRAY_BUFFER,
5538
- ),
5539
- ],
5540
- buffers=[
5541
- pygltflib.Buffer(
5542
- byteLength=len(triangles_binary_blob) + len(points_binary_blob)
5543
- )
5544
- ],
5545
- )
5546
- gltf.set_binary_blob(triangles_binary_blob + points_binary_blob)
5547
-
5548
- dlg=wx.FileDialog(None,_('Choose filename'),wildcard='binary gltf2 (*.glb)|*.glb|gltf2 (*.gltf)|*.gltf|All (*.*)|*.*',style=wx.FD_SAVE)
5549
- ret=dlg.ShowModal()
5550
- if ret==wx.ID_CANCEL:
5551
- dlg.Destroy()
5552
- return
5553
-
5554
- fn=dlg.GetPath()
5555
- dlg.Destroy()
5556
-
5557
- gltf.save(fn)
5558
-
5559
- def get_xy_z_for_griddata(self):
5560
-
5561
- xy = np.asarray([[curvertex.x,curvertex.y] for curpt in self.interpolants for curl in curpt for curvertex in curl])
5562
- z = np.asarray([curvertex.z for curpt in self.interpolants for curl in curpt for curvertex in curl])
5563
-
5564
- # if len(np.argwhere(np.isnan(z)))>0:
5565
- # test=1
5566
- # if len(np.argwhere(np.isneginf(z)))>0:
5567
- # test=1
5568
- # if len(np.argwhere(np.isposinf(z)))>0:
5569
- # test=1
5570
- return xy,z
5571
-
5572
- class Interpolators():
5573
-
5574
- def __init__(self, banks:Zones, cs, ds=1.) -> None:
5575
-
5576
- self.mybanks = [curv for curzone in banks.myzones for curv in curzone.myvectors]
5577
- cs.set_zones()
5578
- self.mycs = cs.myzones
5579
-
5580
- self.myinterp=[]
5581
-
5582
- zonecs:zone
5583
- zonecs = self.mycs.myzones[0]
5584
-
5585
- if zonecs.myvectors[0].up is not None:
5586
-
5587
- cs1=cs.get_upstream()['cs']
5588
-
5589
- while cs1.down is not cs1:
5590
- cs2=cs1.down
5591
-
5592
- print('{} - {}'.format(cs1.myname,cs2.myname))
5593
-
5594
- myinterp=Interpolator(cs1,cs2,self.mybanks,ds)
5595
- self.myinterp.append(myinterp)
5596
- cs1=cs2
5597
- else:
5598
- for i in range(zonecs.nbvectors-1):
5599
- cs1=zonecs.myvectors[i]
5600
- cs2=zonecs.myvectors[i+1]
5601
-
5602
- print('{} - {}'.format(cs1.myname,cs2.myname))
5603
- myinterp=Interpolator(cs1,cs2,self.mybanks,ds)
5604
- self.myinterp.append(myinterp)
5605
-
5606
- self.myzones= self.mycs.add_interpolators(self)
5607
-
5608
- def viewer_interpolator(self):
5609
-
5610
- xyz=[]
5611
- for curinterp in self.myinterp:
5612
- xyz.append(curinterp.get_xyz_for_viewer())
5613
-
5614
- xyz=np.concatenate(xyz)
5615
-
5616
- myviewer(xyz,0)
5617
-
5618
- def interp_on_array(self,myarray,method):
5619
-
5620
- xy=[]
5621
- z=[]
5622
- for curint in self.myinterp:
5623
- tmpxy,tmpz = curint.get_xy_z_for_griddata()
5624
- xy.append(tmpxy)
5625
- z.append(tmpz)
5626
-
5627
- xy = np.concatenate(xy)
5628
- z = np.concatenate(z)
5629
-
5630
- myarray.interpolate_on_cloud(xy,z,method)