wolfhece 2.2.28__py3-none-any.whl → 2.2.30__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.
@@ -637,6 +637,8 @@ class vectorproperties:
637
637
 
638
638
  self.used=True
639
639
 
640
+ self.plot_indices = False
641
+
640
642
  self._values = {}
641
643
 
642
644
  # FIXME : to be changed
@@ -699,6 +701,8 @@ class vectorproperties:
699
701
  self.imagevisible = False
700
702
  self.textureimage:genericImagetexture = None
701
703
 
704
+ self.plot_indices = False
705
+
702
706
  def get_extra(self) -> list[float,float,int,float,str,bool]:
703
707
  """ Return extra properties """
704
708
  return [self.legendlength,
@@ -706,7 +710,8 @@ class vectorproperties:
706
710
  self.legendpriority,
707
711
  self.legendorientation,
708
712
  str(self.attachedimage),
709
- self.imagevisible]
713
+ self.imagevisible,
714
+ self.plot_indices]
710
715
 
711
716
  def set_extra(self, linesextra:list[float,float,int,float,str,bool] = None):
712
717
  """ Set extra properties """
@@ -725,6 +730,9 @@ class vectorproperties:
725
730
  self.attachedimage = Path(linesextra[4])
726
731
  self.imagevisible = linesextra[5].lower() == 'true'
727
732
 
733
+ if len(linesextra)>6:
734
+ self.plot_indices = linesextra[6].lower() == 'true'
735
+
728
736
  def load_extra(self, lines:list[str]) -> int:
729
737
  """ Load extra properties from lines """
730
738
 
@@ -817,7 +825,7 @@ class vectorproperties:
817
825
 
818
826
  self.color = getIfromRGB(props[('Draw','Color')])
819
827
  self.width = props[('Draw','Width')]
820
- self.style = props[('Draw','Style')]
828
+ # self.style = props[('Draw','Style')]
821
829
 
822
830
  old_closed = self.closed
823
831
  self.closed = props[('Draw','Closed')]
@@ -828,7 +836,8 @@ class vectorproperties:
828
836
  self.filled = props[('Draw','Filled')]
829
837
  self.transparent = props[('Draw','Transparent')]
830
838
  self.alpha = props[('Draw','Alpha')]
831
- self.flash = props[('Draw','Flash')]
839
+ # self.flash = props[('Draw','Flash')]
840
+ self.plot_indices = props[('Draw','Plot indices if active')]
832
841
 
833
842
  self.legendunderlined = props[('Legend','Underlined')]
834
843
  self.legendbold = props[('Legend','Bold')]
@@ -928,14 +937,18 @@ class vectorproperties:
928
937
 
929
938
  self.myprops.hide_selected_buttons() # only 'Apply' button
930
939
 
940
+ self.myprops.addparam('Geometry','Length 2D',99999.,Type_Param.Float,'',whichdict='Default')
941
+ self.myprops.addparam('Geometry','Length 3D',99999.,Type_Param.Float,'',whichdict='Default')
942
+ self.myprops.addparam('Geometry','Surface',99999.,Type_Param.Float,'',whichdict='Default')
943
+
931
944
  self.myprops.addparam('Draw','Color',(0,0,0),'Color','Drawing color',whichdict='Default')
932
945
  self.myprops.addparam('Draw','Width',1,'Integer','Drawing width',whichdict='Default')
933
- self.myprops.addparam('Draw','Style',1,'Integer','Drawing style',whichdict='Default')
946
+ # self.myprops.addparam('Draw','Style',1,'Integer','Drawing style',whichdict='Default')
934
947
  self.myprops.addparam('Draw','Closed',False,'Logical','',whichdict='Default')
935
948
  self.myprops.addparam('Draw','Filled',False,'Logical','',whichdict='Default')
936
949
  self.myprops.addparam('Draw','Transparent',False,'Logical','',whichdict='Default')
937
950
  self.myprops.addparam('Draw','Alpha',0,'Integer','Transparency intensity (255 is opaque)',whichdict='Default')
938
- self.myprops.addparam('Draw','Flash',False,'Logical','',whichdict='Default')
951
+ # self.myprops.addparam('Draw','Flash',False,'Logical','',whichdict='Default')
939
952
 
940
953
  self.myprops.addparam('Legend','Visible',False,'Logical','',whichdict='Default')
941
954
 
@@ -991,10 +1004,6 @@ if :\n \
991
1004
  self.myprops.addparam('Image','Attached image','',Type_Param.File, '', whichdict='Default')
992
1005
  self.myprops.addparam('Image','To show',False,Type_Param.Logical,'',whichdict='Default')
993
1006
 
994
- self.myprops.addparam('Geometry','Length 2D',99999.,Type_Param.Float,'',whichdict='Default')
995
- self.myprops.addparam('Geometry','Length 3D',99999.,Type_Param.Float,'',whichdict='Default')
996
- self.myprops.addparam('Geometry','Surface',99999.,Type_Param.Float,'',whichdict='Default')
997
-
998
1007
  def destroyprop(self):
999
1008
  """
1000
1009
  Nullify the properties UI
@@ -1063,14 +1072,20 @@ if :\n \
1063
1072
  """ Update the properties """
1064
1073
 
1065
1074
  if self.myprops is not None:
1075
+ self.parent.update_lengths()
1076
+ self.myprops[( 'Geometry','Length 2D')] = self.parent.length2D if self.parent.length2D is not None else 0.
1077
+ self.myprops[( 'Geometry','Length 3D')] = self.parent.length3D if self.parent.length3D is not None else 0.
1078
+ self.myprops[( 'Geometry','Surface')] = self.parent.area if self.parent.area is not None else 0.
1079
+
1066
1080
  self.myprops[('Draw','Color')] = getRGBfromI(self.color)
1067
1081
  self.myprops[('Draw','Width')] = self.width
1068
- self.myprops[('Draw','Style')] = self.style
1082
+ # self.myprops[('Draw','Style')] = self.style
1069
1083
  self.myprops[('Draw','Closed')] = self.closed
1070
1084
  self.myprops[('Draw','Filled')] = self.filled
1071
1085
  self.myprops[('Draw','Transparent')]= self.transparent
1072
1086
  self.myprops[('Draw','Alpha')] = self.alpha
1073
- self.myprops[('Draw','Flash')] = self.flash
1087
+ # self.myprops[('Draw','Flash')] = self.flash
1088
+ self.myprops[('Draw','Plot indices if active')] = self.plot_indices
1074
1089
 
1075
1090
  self.myprops[('Legend','Visible')] = self.legendvisible
1076
1091
  self.myprops[('Legend','Text')] = self.legendtext
@@ -1123,11 +1138,6 @@ if :\n \
1123
1138
  self.myprops[('Move','Delta X')] = 0.
1124
1139
  self.myprops[('Move','Delta Y')] = 0.
1125
1140
 
1126
- self.parent.update_lengths()
1127
- self.myprops[( 'Geometry','Length 2D')] = self.parent.length2D if self.parent.length2D is not None else 0.
1128
- self.myprops[( 'Geometry','Length 3D')] = self.parent.length3D if self.parent.length3D is not None else 0.
1129
- self.myprops[( 'Geometry','Surface')] = self.parent.area if self.parent.area is not None else 0.
1130
-
1131
1141
  self.myprops.Populate()
1132
1142
  class vector:
1133
1143
  """
@@ -2124,6 +2134,99 @@ class vector:
2124
2134
  else:
2125
2135
  return [self.myvertices]
2126
2136
 
2137
+ def _plot_square_at_vertices(self, size=5):
2138
+ """
2139
+ Plot small squares at each vertex, in OpenGL
2140
+ """
2141
+
2142
+ if self.nbvertices == 0:
2143
+ return
2144
+
2145
+ curvert: wolfvertex
2146
+ ongoing = True
2147
+
2148
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
2149
+ # if filled:
2150
+ # glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
2151
+
2152
+ glPointSize(size)
2153
+ rgb = getRGBfromI(self.myprop.color)
2154
+ glBegin(GL_POINTS)
2155
+ for curvert in self.myvertices:
2156
+ glColor3ub(int(rgb[0]), int(rgb[1]), int(rgb[2]))
2157
+ glVertex2f(curvert.x, curvert.y)
2158
+ glEnd()
2159
+
2160
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
2161
+
2162
+ ongoing = False
2163
+
2164
+ def _plot_index_vertex(self, idx:int = None, xy:tuple[float,float] = None,
2165
+ sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
2166
+ """
2167
+ Plot OpenGL
2168
+
2169
+ :param idx: index of the vertex to plot
2170
+ :param xy: coordinates (x,y) of the vertex to plot
2171
+ :param sx: scale x
2172
+ :param sy: scale y
2173
+ :param xmin: minimum x
2174
+ :param ymin: minimum y
2175
+ :param xmax: maximum x
2176
+ :param ymax: maximum y
2177
+ :param size: size of the text
2178
+ """
2179
+ if self.get_mapviewer() is None:
2180
+ logging.warning(_('No mapviewer available for legend plot'))
2181
+ return
2182
+
2183
+ if xy is not None:
2184
+ x, y = xy
2185
+ curvert = self.find_nearest_vert(x, y)
2186
+ idx = self.myvertices.index(curvert)
2187
+ elif idx is not None:
2188
+ if idx < 0 or idx >= self.nbvertices:
2189
+ logging.warning(_('Index {} out of range for vector {}').format(idx, self.myname))
2190
+ return
2191
+ curvert = self.myvertices[idx]
2192
+ else:
2193
+ logging.warning(_('No index or coordinates provided for plotting index vertex'))
2194
+ return
2195
+
2196
+ if not (xmin is None or ymin is None or xmax is None or ymax is None):
2197
+ if curvert.x < xmin or curvert.x > xmax or curvert.y < ymin or curvert.y > ymax:
2198
+ logging.debug(_('Vertex {} at ({},{}) is out of bounds ({},{},{},{}))'.format(idx, curvert.x, curvert.y, xmin, ymin, xmax, ymax)))
2199
+ return
2200
+
2201
+ self._textimage = Text_Image_Texture(str(idx+1),
2202
+ self.get_mapviewer(), # mapviewer de l'instance Zones qui contient le vecteur
2203
+ self._get_textfont_idx(),
2204
+ self,
2205
+ curvert.x,
2206
+ curvert.y)
2207
+ self._textimage.paint()
2208
+
2209
+ def _plot_all_indices(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
2210
+ """
2211
+ Plot all indices of the vertices in OpenGL
2212
+ :param sx: scale x
2213
+ :param sy: scale y
2214
+ :param xmin: minimum x
2215
+ :param ymin: minimum y
2216
+ :param xmax: maximum x
2217
+ :param ymax: maximum y
2218
+ :param size: size of the text
2219
+ """
2220
+ if self.get_mapviewer() is None:
2221
+ logging.warning(_('No mapviewer available for legend plot'))
2222
+ return
2223
+ if self.nbvertices == 0:
2224
+ logging.warning(_('No vertices to plot indices for vector {}').format(self.myname))
2225
+ return
2226
+ if self.myprop.used:
2227
+ for idx in range(self.nbvertices):
2228
+ self._plot_index_vertex(idx=idx, sx=sx, sy=sy, xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax, size=size)
2229
+
2127
2230
  def plot(self, sx=None, sy=None, xmin=None, ymin=None, xmax=None, ymax=None, size=None):
2128
2231
  """
2129
2232
  Plot OpenGL
@@ -2279,10 +2382,12 @@ class vector:
2279
2382
  ax.fill([curvert.x for curvert in self.myvertices], [curvert.y for curvert in self.myvertices], color=(rgb[0]/255.,rgb[1]/255.,rgb[2]/255.))
2280
2383
  else:
2281
2384
  rgb=getRGBfromI(self.myprop.color)
2282
- if self.myprop.transparent:
2283
- ax.plot([curvert.x for curvert in self.myvertices], [curvert.y for curvert in self.myvertices], color=(rgb[0]/255.,rgb[1]/255.,rgb[2]/255.,self.myprop.alpha), linewidth=self.myprop.width)
2284
- else:
2285
- ax.plot([curvert.x for curvert in self.myvertices], [curvert.y for curvert in self.myvertices], color=(rgb[0]/255.,rgb[1]/255.,rgb[2]/255.), linewidth=self.myprop.width)
2385
+ subpoly = self.get_subpolygons()
2386
+ for curpoly in subpoly:
2387
+ if self.myprop.transparent:
2388
+ ax.plot([curvert.x for curvert in curpoly], [curvert.y for curvert in curpoly], color=(rgb[0]/255.,rgb[1]/255.,rgb[2]/255.,self.myprop.alpha), linewidth=self.myprop.width)
2389
+ else:
2390
+ ax.plot([curvert.x for curvert in curpoly], [curvert.y for curvert in curpoly], color=(rgb[0]/255.,rgb[1]/255.,rgb[2]/255.), linewidth=self.myprop.width)
2286
2391
 
2287
2392
  self.plot_legend_mpl(ax)
2288
2393
 
@@ -2302,6 +2407,21 @@ class vector:
2302
2407
 
2303
2408
  return tinfos
2304
2409
 
2410
+ def _get_textfont_idx(self):
2411
+ """ Retunr a 'Text_Infos' instance for the legend """
2412
+
2413
+ r,g,b = getRGBfromI(self.myprop.color)
2414
+ tinfos = Text_Infos(3,
2415
+ (1., 0.),
2416
+ self.myprop.legendfontname,
2417
+ 12,
2418
+ colour=(r,g,b,255),
2419
+ dimsreal=(self.myprop.legendlength,
2420
+ self.myprop.legendheight),
2421
+ relative_position=7)
2422
+
2423
+ return tinfos
2424
+
2305
2425
  def add2tree(self, tree:TreeListCtrl, root):
2306
2426
  """
2307
2427
  Ajout de l'objte à un TreeListCtrl wx
@@ -2474,6 +2594,13 @@ class vector:
2474
2594
  """
2475
2595
  Retrouve le segment associé aux paramètres passés
2476
2596
  """
2597
+
2598
+ if self.length2D is None or self.length3D is None:
2599
+ self.update_lengths()
2600
+ else:
2601
+ if len(self._lengthparts2D) != self.nbvertices-1 or len(self._lengthparts3D) != self.nbvertices-1:
2602
+ self.update_lengths()
2603
+
2477
2604
  if is3D:
2478
2605
  length = self.length3D
2479
2606
  lengthparts = self._lengthparts3D
@@ -2481,15 +2608,6 @@ class vector:
2481
2608
  length = self.length2D
2482
2609
  lengthparts = self._lengthparts2D
2483
2610
 
2484
- if length is None:
2485
- self.update_lengths()
2486
- if is3D:
2487
- length = self.length3D
2488
- lengthparts = self._lengthparts3D
2489
- else:
2490
- length = self.length2D
2491
- lengthparts = self._lengthparts2D
2492
-
2493
2611
  cums = np.cumsum(lengthparts)
2494
2612
 
2495
2613
  if adim:
@@ -2508,7 +2626,7 @@ class vector:
2508
2626
 
2509
2627
  if frombegin:
2510
2628
  k=0
2511
- while s>cums[k]:
2629
+ while s>cums[k] and k < self.nbvertices-2:
2512
2630
  k+=1
2513
2631
  else:
2514
2632
  k=self.nbvertices-2
@@ -4748,19 +4866,23 @@ class zone:
4748
4866
  veccenter = self.myvectors[0]
4749
4867
  veccenter.update_lengths()
4750
4868
 
4869
+ logging.info(_('Length of the center vector: {}').format(veccenter.length2D))
4870
+
4751
4871
  # Returned zone
4752
4872
  myparallels = zone()
4753
4873
 
4754
4874
  if interval_parallel is None :
4875
+ logging.warning(_('Interval between parallels is not defined --> set to farthest_parallel'))
4755
4876
  interval_parallel : farthest_parallel
4756
4877
 
4757
4878
  if interval_parallel > farthest_parallel:
4758
- logging.warning(_('dspar is greater than dpar --> dspar is set to dpar'))
4879
+ logging.warning(_('Interval between parallels is greater than farthest_parallel --> set to farthest_parallel'))
4759
4880
  interval_parallel = farthest_parallel
4760
4881
 
4761
4882
  # All parallel distances
4762
4883
  all_par = np.arange(0, farthest_parallel, interval_parallel)[1:]
4763
4884
  all_par = np.concatenate((all_par,[farthest_parallel]))
4885
+ logging.info(_('All parallel distances: {}').format(all_par))
4764
4886
 
4765
4887
  for curpar in tqdm(all_par):
4766
4888
  # add current parallel to the dicts
@@ -4775,22 +4897,28 @@ class zone:
4775
4897
  #
4776
4898
  # gestion de vecteurs d'intersection
4777
4899
  for curint in intersect.myvectors:
4900
+ if not curint.used:
4901
+ continue
4902
+
4778
4903
  # bouclage sur les vecteurs
4779
- curint2 = curint.parallel_offset(eps_offset, side='right')
4904
+ curint1 = curint.parallel_offset(-eps_offset/2., side='left')
4905
+ curint2 = curint.parallel_offset( eps_offset/2., side='right')
4780
4906
 
4781
4907
  # recherche si une intersection existe
4782
- pt, dist = vecleft[curpar].intersection(curint, eval_dist=True, force_single=True)
4908
+ pt, dist = vecleft[curpar].intersection(curint1, eval_dist=True, force_single=True)
4783
4909
  if pt is not None:
4910
+ logging.debug(_('Intersection found on left parallel at distance {}').format(dist))
4784
4911
  #Une intersection existe --> on ajoute la portion de vecteur
4785
4912
 
4786
4913
  # Projection du point d'intersection sur le vecteur à suivre
4787
- curls = curint.asshapely_ls()
4788
- dist2 = curls.project(pt)
4914
+ dist2 = curint1.linestring.project(pt)
4915
+
4789
4916
  # recherche de la portion de vecteur
4790
4917
  # subs = extrêmité -> intersection
4791
4918
  # subs_inv = intersection -> extrêmité
4792
- subs = curint.substring(0. , dist2, is3D=False, adim=False)
4919
+ subs = curint1.substring(0. , dist2, is3D=False, adim=False)
4793
4920
  subs.reverse()
4921
+
4794
4922
  subs2 = curint2.substring(0., dist2, is3D=False, adim=False)
4795
4923
 
4796
4924
  vec1 = vecleft[curpar].substring(0., dist, is3D=False, adim=False)
@@ -4805,13 +4933,19 @@ class zone:
4805
4933
  # mise à jour des caractéristiques
4806
4934
  vecleft[curpar].find_minmax()
4807
4935
  vecleft[curpar].update_lengths()
4936
+ vecleft[curpar].reset_linestring()
4937
+ curint1.reset_linestring()
4938
+ curint2.reset_linestring()
4808
4939
 
4809
- pt, dist = vecright[curpar].intersection(curint, eval_dist=True, force_single=True)
4940
+ pt, dist = vecright[curpar].intersection(curint1, eval_dist=True, force_single=True)
4810
4941
  if pt is not None:
4811
- curls = curint.asshapely_ls()
4812
- dist2 = curls.project(pt)
4942
+ logging.debug(_('Intersection found on right parallel at distance {}').format(dist))
4943
+
4944
+ dist2 = curint1.linestring.project(pt)
4945
+
4813
4946
  #Une intersection existe --> on ajoute la portion de vecteur
4814
- subs = curint.substring(0., dist2, is3D=False, adim=False)
4947
+ subs = curint1.substring(0., dist2, is3D=False, adim=False)
4948
+
4815
4949
  subs2 = curint2.substring(0., dist2, is3D=False, adim=False)
4816
4950
  subs2.reverse()
4817
4951
 
@@ -4820,8 +4954,11 @@ class zone:
4820
4954
 
4821
4955
  vecright[curpar].myvertices = vec1.myvertices.copy() + subs2.myvertices.copy() + subs.myvertices.copy() + vec2.myvertices.copy()
4822
4956
 
4823
- vecright[curpar].update_lengths()
4824
4957
  vecright[curpar].find_minmax()
4958
+ vecright[curpar].update_lengths()
4959
+ vecright[curpar].reset_linestring()
4960
+ curint1.reset_linestring()
4961
+ curint2.reset_linestring()
4825
4962
 
4826
4963
  #Shapely LineString
4827
4964
  lsl:dict[str,LineString] = {key:vec.asshapely_ls() for key,vec in vecleft.items()}
@@ -4840,7 +4977,7 @@ class zone:
4840
4977
  ptsc = [veccenter.interpolate(curs, is3D=False, adim=False) for curs in sloc]
4841
4978
  ptsc2 = [veccenter.interpolate(curs, is3D=False, adim=False) for curs in sloc2]
4842
4979
 
4843
- sc = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc]
4980
+ sc = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc]
4844
4981
  sc2 = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc2]
4845
4982
 
4846
4983
  #Real distances along left, right and center vector
@@ -4881,9 +5018,9 @@ class zone:
4881
5018
 
4882
5019
  if howmanypoly==1:
4883
5020
  #un seul polygone sur base des // gauche et droite
4884
- zonepoly = zone(name='polygons_'+self.myname,parent=self.parent)
5021
+ zonepoly = zone(name='polygons_'+self.myname, parent=self.parent)
4885
5022
 
4886
- self.parent.add_zone(zonepoly)
5023
+ self.parent.add_zone(zonepoly, forceparent=True)
4887
5024
 
4888
5025
  for i in range(nb):
4889
5026
  ptc1 = sc[i]
@@ -4917,16 +5054,16 @@ class zone:
4917
5054
  #force to close the polygon
4918
5055
  curvec.close_force()
4919
5056
  #add vector to zone
4920
- zonepoly.add_vector(curvec)
5057
+ zonepoly.add_vector(curvec, forceparent=True)
4921
5058
 
4922
5059
  #force to update minmax in the zone --> mandatory to plot
4923
5060
  zonepoly.find_minmax(True)
4924
5061
  else:
4925
5062
  #deux polygones sur base des // gauche et droite
4926
- zonepolyleft = zone(name='polygons_left_'+self.myname,parent=self.parent)
4927
- zonepolyright = zone(name='polygons_right_'+self.myname,parent=self.parent)
4928
- self.parent.add_zone(zonepolyleft)
4929
- self.parent.add_zone(zonepolyright)
5063
+ zonepolyleft = zone(name='polygons_left_'+self.myname, parent=self.parent)
5064
+ zonepolyright = zone(name='polygons_right_'+self.myname, parent=self.parent)
5065
+ self.parent.add_zone(zonepolyleft, forceparent=True)
5066
+ self.parent.add_zone(zonepolyright, forceparent=True)
4930
5067
 
4931
5068
  for i in range(nb):
4932
5069
  ptc1 = sc[i]
@@ -4938,8 +5075,8 @@ class zone:
4938
5075
 
4939
5076
  #mean distance along center will be stored as Z value of each vertex
4940
5077
  smean =(ptc1+ptc2)/2.
4941
- curvecleft=vector(name='poly'+str(i+1),parentzone=zonepolyleft)
4942
- curvecright=vector(name='poly'+str(i+1),parentzone=zonepolyright)
5078
+ curvecleft=vector(name='poly'+str(i+1), parentzone=zonepolyleft)
5079
+ curvecright=vector(name='poly'+str(i+1), parentzone=zonepolyright)
4943
5080
 
4944
5081
  #Substring for Left and Right
4945
5082
  sublsl=vecleft[farthest_parallel].substring(pt1[-1], pt2[-1], is3D=False, adim=False)
@@ -4957,8 +5094,8 @@ class zone:
4957
5094
  downl.reverse()
4958
5095
  downr = [wolfvertex(pt[i].x, pt[i].y) for pt in ptr2.values()]
4959
5096
 
4960
- curvecleft.myvertices = sublsl.myvertices.copy() + downl[1:-1].copy() + [sublscr.myvertices.copy()] + upl[1:-1].copy()
4961
- curvecright.myvertices = sublsc.myvertices.copy() + downr[1:-1].copy() + [sublsr.myvertices.copy()] + upr[1:-1].copy()
5097
+ curvecleft.myvertices = sublsl.myvertices.copy() + downl[1:-1].copy() + sublscr.myvertices.copy() + upl[1:-1].copy()
5098
+ curvecright.myvertices = sublsc.myvertices.copy() + downr[1:-1].copy() + sublsr.myvertices.copy() + upr[1:-1].copy()
4962
5099
 
4963
5100
  for curvert in curvecleft.myvertices:
4964
5101
  curvert.z = smean
@@ -4976,6 +5113,9 @@ class zone:
4976
5113
 
4977
5114
  self._fill_structure()
4978
5115
 
5116
+ if self.get_mapviewer() is not None:
5117
+ self.get_mapviewer().Paint()
5118
+
4979
5119
  return myparallels
4980
5120
 
4981
5121
  def get_values_linked_polygons(self, linked_arrays, stats=True) -> dict:
@@ -6929,7 +7069,11 @@ class Zones(wx.Frame, Element_To_Draw):
6929
7069
  box_s.Add(self.update_from_s,1,wx.EXPAND)
6930
7070
  box_s.Add(self.getxyfromsz,1,wx.EXPAND) # Added
6931
7071
 
6932
- boxright.Add(self.interpxyz,0,wx.EXPAND)
7072
+ box_interp_indices = wx.BoxSizer(wx.HORIZONTAL)
7073
+ box_interp_indices.Add(self.interpxyz,1,wx.EXPAND)
7074
+
7075
+ boxright.Add(box_interp_indices,0,wx.EXPAND)
7076
+
6933
7077
 
6934
7078
  _sizer_ascbuffer = wx.BoxSizer(wx.HORIZONTAL)
6935
7079
  _sizer_ascbuffer.Add(self.sascending,1,wx.EXPAND)
@@ -7553,6 +7697,16 @@ class Zones(wx.Frame, Element_To_Draw):
7553
7697
  self.mapviewer.mimicme()
7554
7698
  self.active_zone.reset_listogl()
7555
7699
 
7700
+ def OnPlotIndices(self, event:wx.MouseEvent):
7701
+ """
7702
+ Plot the indices of the active vector in the mapviewer
7703
+ """
7704
+
7705
+ if self.wx_exists:
7706
+ if self.verify_activevec():
7707
+ return
7708
+ self.mapviewer._force_to_plot_indices = True
7709
+
7556
7710
  def Onzoom(self, event:wx.MouseEvent):
7557
7711
  """
7558
7712
  Zoom sur le vecteur actif dans le mapviewer
@@ -7670,6 +7824,7 @@ class Zones(wx.Frame, Element_To_Draw):
7670
7824
  """
7671
7825
 
7672
7826
  if self.active_zone is None:
7827
+ logging.warning(_('No active zone - Nothing to do !'))
7673
7828
  return
7674
7829
 
7675
7830
  if self.wx_exists:
@@ -7679,25 +7834,81 @@ class Zones(wx.Frame, Element_To_Draw):
7679
7834
  logging.warning(_('The active zone must contain 3 vectors and only 3'))
7680
7835
  return
7681
7836
 
7682
- dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',500,1,10000)
7683
- ret=dlg.ShowModal()
7684
- if ret==wx.ID_CANCEL:
7685
- dlg.Destroy()
7686
- return
7837
+ self.active_zone.myvectors[1].update_lengths()
7687
7838
 
7688
- ds=float(dlg.GetValue())/100.
7689
- dlg.Destroy()
7839
+ poly_dlg = wx.Dialog(None, title=_('Polygons from parallels options'), size=(400, 350))
7840
+ poly_dlg.SetBackgroundColour(wx.Colour(240, 240, 240))
7841
+ poly_sizer = wx.BoxSizer(wx.VERTICAL)
7842
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Polygons from parallels options')), 0, wx.ALL | wx.CENTER, 5)
7843
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('This will create polygons from the parallels in the active zone')), 0, wx.ALL | wx.CENTER, 5)
7844
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Please enter the parameters below:')), 0, wx.ALL | wx.CENTER, 5)
7845
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Longitudinal size [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7846
+ ds_text = wx.TextCtrl(poly_dlg, value='5000') # Default
7847
+ poly_sizer.Add(ds_text, 0, wx.ALL | wx.EXPAND, 5)
7848
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('How many polygons? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right')), 0, wx.ALL | wx.LEFT, 5)
7849
+ nb_text = wx.TextCtrl(poly_dlg, value='1') # Default
7850
+ poly_sizer.Add(nb_text, 0, wx.ALL | wx.EXPAND, 5)
7851
+ ok_button = wx.Button(poly_dlg, label=_('OK'))
7852
+ ok_button.Bind(wx.EVT_BUTTON, lambda evt: self._OnCreatePolygons(evt, ds_text, nb_text, poly_dlg))
7853
+ poly_sizer.Add(ok_button, 0, wx.ALL | wx.CENTER, 5)
7854
+ poly_dlg.SetSizer(poly_sizer)
7855
+ poly_dlg.Layout()
7856
+ poly_dlg.CentreOnParent()
7857
+ poly_dlg.ShowModal()
7690
7858
 
7691
- dlg=wx.NumberEntryDialog(None,_('How many polygons ? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right'),'Number','Polygons',1,1,2)
7692
- ret=dlg.ShowModal()
7693
- if ret==wx.ID_CANCEL:
7694
- dlg.Destroy()
7859
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',500,1,10000)
7860
+ # ret=dlg.ShowModal()
7861
+ # if ret==wx.ID_CANCEL:
7862
+ # dlg.Destroy()
7863
+ # return
7864
+
7865
+ # ds=float(dlg.GetValue())/100.
7866
+ # dlg.Destroy()
7867
+
7868
+ # dlg=wx.NumberEntryDialog(None,_('How many polygons ? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right'),'Number','Polygons',1,1,2)
7869
+ # ret=dlg.ShowModal()
7870
+ # if ret==wx.ID_CANCEL:
7871
+ # dlg.Destroy()
7872
+ # return
7873
+
7874
+ # nb=int(dlg.GetValue())
7875
+ # dlg.Destroy()
7876
+
7877
+
7878
+ def _OnCreatePolygons(self, event:wx.MouseEvent, ds_text:wx.TextCtrl, nb_text:wx.TextCtrl, option_dialog:wx.Dialog):
7879
+ """
7880
+ Handle the creation of polygons based on user input from the dialog.
7881
+ """
7882
+
7883
+ try:
7884
+ ds = float(ds_text.GetValue()) / 100.0 # Convert cm to
7885
+ nb = int(nb_text.GetValue()) # Number of polygons
7886
+
7887
+ if ds <= 0:
7888
+ wx.MessageBox(_('Please enter a valid distance greater than 0.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7695
7889
  return
7696
7890
 
7697
- nb=int(dlg.GetValue())
7698
- dlg.Destroy()
7891
+ if ds > self.active_zone.myvectors[1].length2D:
7892
+ wx.MessageBox(_('The distance must be less than the length of the center vector in the active zone.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7893
+ return
7699
7894
 
7895
+ if nb < 1 or nb > 2:
7896
+ wx.MessageBox(_('Please enter a valid number of polygons (1 or 2).'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7897
+ return
7898
+ except ValueError:
7899
+ wx.MessageBox(_('Please enter valid numeric values for all fields.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7900
+ return
7901
+
7902
+ try:
7700
7903
  self.active_zone.create_polygon_from_parallel(ds,nb)
7904
+ except Exception as e:
7905
+ logging.error(_('Error during polygon creation: {}').format(str(e)))
7906
+
7907
+ if self.get_mapviewer() is not None:
7908
+ self.get_mapviewer().Paint()
7909
+
7910
+ option_dialog.Destroy()
7911
+
7701
7912
 
7702
7913
  def Oncreateslidingpoly(self, event:wx.MouseEvent):
7703
7914
  """
@@ -7715,71 +7926,145 @@ class Zones(wx.Frame, Element_To_Draw):
7715
7926
  dlg.Destroy()
7716
7927
  return
7717
7928
 
7718
- #dialog box for length, sliding length, farthest parallel and parallel interval
7719
- dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',5000,1,100000)
7720
- ret=dlg.ShowModal()
7721
- if ret==wx.ID_CANCEL:
7722
- dlg.Destroy()
7723
- return
7929
+ option_dialog = wx.Dialog(None, title=_('Sliding polygons options'), size=(450, 520))
7930
+ option_dialog.SetBackgroundColour(wx.Colour(240, 240, 240))
7931
+ option_sizer = wx.BoxSizer(wx.VERTICAL)
7932
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Sliding polygons options')), 0, wx.ALL | wx.CENTER, 5)
7933
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('This will create sliding polygons from the active vector in the active zone')), 0, wx.ALL | wx.CENTER, 5)
7934
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Please enter the parameters below:')), 0, wx.ALL | wx.CENTER, 5)
7935
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Longitudinal size [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7936
+ ds_text = wx.TextCtrl(option_dialog, value='5000') # Default value in cm
7937
+ option_sizer.Add(ds_text, 0, wx.ALL | wx.EXPAND, 5)
7938
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Sliding length [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7939
+ sliding_text = wx.TextCtrl(option_dialog, value='5000') # Default value
7940
+ option_sizer.Add(sliding_text, 0, wx.ALL | wx.EXPAND, 5)
7941
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Farthest parallel [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7942
+ farthest_text = wx.TextCtrl(option_dialog, value='10000') # Default
7943
+ option_sizer.Add(farthest_text, 0, wx.ALL | wx.EXPAND, 5)
7944
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Parallel interval [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7945
+ interval_text = wx.TextCtrl(option_dialog, value='1000') # Default
7946
+ option_sizer.Add(interval_text, 0, wx.ALL | wx.EXPAND, 5)
7947
+
7948
+ intersect_sizer = wx.BoxSizer(wx.HORIZONTAL)
7949
+ inter_checkbox = wx.CheckBox(option_dialog, label=_('Use intersect zone if available'))
7950
+ inter_checkbox.SetValue(True) # Default to True
7951
+ offset_text = wx.TextCtrl(option_dialog, value='10') # Default offset value
7952
+ intersect_sizer.Add(inter_checkbox, 0, wx.ALL | wx.LEFT, 5)
7953
+ intersect_sizer.Add(wx.StaticText(option_dialog, label=_('Offset [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7954
+ intersect_sizer.Add(offset_text, 0, wx.ALL | wx.EXPAND, 5)
7955
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('If you have a zone named "intersect", you can use it to constrain the polygons.\nWhen constraint vectors are present, they cannot intersect the central vector.\nLikewise, they must be drawn moving away from the central vector.')), 0, wx.ALL | wx.CENTER, 5)
7956
+
7957
+ option_sizer.Add(intersect_sizer, 0, wx.ALL | wx.LEFT, 5)
7958
+ separate_checkbox = wx.CheckBox(option_dialog, label=_('Separate left and right polygons'))
7959
+ separate_checkbox.SetValue(False) # Default to False
7960
+ option_sizer.Add(separate_checkbox, 0, wx.ALL | wx.LEFT, 5)
7961
+ ok_button = wx.Button(option_dialog, label=_('OK'))
7962
+ ok_button.Bind(wx.EVT_BUTTON, lambda evt: self._OnCreateSlidingPolygon(evt, ds_text, sliding_text, farthest_text, interval_text, inter_checkbox, offset_text, separate_checkbox, option_dialog))
7963
+ option_sizer.Add(ok_button, 0, wx.ALL | wx.CENTER, 5)
7964
+ option_dialog.SetSizer(option_sizer)
7965
+ option_dialog.Layout()
7966
+ option_dialog.Centre()
7724
7967
 
7725
- ds=float(dlg.GetValue())/100.
7968
+ try:
7969
+ option_dialog.ShowModal()
7970
+ except:
7971
+ logging.error(_('Error during sliding polygons calculation.'))
7726
7972
 
7727
- dlg.Destroy()
7973
+ option_dialog.Destroy()
7728
7974
 
7729
- dlg=wx.NumberEntryDialog(None,_('What is the desired sliding length [cm] ?'),'sliding','sliding size',5000,1,100000)
7730
- ret=dlg.ShowModal()
7731
- if ret==wx.ID_CANCEL:
7732
- dlg.Destroy()
7975
+ def _OnCreateSlidingPolygon(self, event, ds_text, sliding_text, farthest_text, interval_text, inter_checkbox, offset_text, separate_checkbox, option_dialog:wx.Dialog):
7976
+ """
7977
+ Handle the creation of sliding polygons based on user input from the dialog.
7978
+ """
7979
+
7980
+ try:
7981
+ ds = float(ds_text.GetValue()) / 100.0 # Convert cm to m
7982
+ sliding = float(sliding_text.GetValue()) / 100.0 # Convert cm
7983
+ farthest = float(farthest_text.GetValue()) / 100.0 # Convert cm to m
7984
+ interval = float(interval_text.GetValue()) / 100.0 # Convert cm to
7985
+ intersect = inter_checkbox.GetValue() # Boolean value
7986
+ separate = separate_checkbox.GetValue() # Boolean value
7987
+ offset = float(offset_text.GetValue())/100.0 # Offset value in m
7988
+ except ValueError:
7989
+ wx.MessageBox(_('Please enter valid numeric values for all fields.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7733
7990
  return
7734
7991
 
7735
- sliding=float(dlg.GetValue())/100.
7992
+ if separate:
7993
+ howmany = 2 # Separate left and right polygons
7994
+ else:
7995
+ howmany = 1 # Single polygon
7736
7996
 
7737
- dlg.Destroy()
7997
+ # #dialog box for length, sliding length, farthest parallel and parallel interval
7998
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',5000,1,100000)
7999
+ # ret=dlg.ShowModal()
8000
+ # if ret==wx.ID_CANCEL:
8001
+ # dlg.Destroy()
8002
+ # return
7738
8003
 
7739
- dlg=wx.NumberEntryDialog(None,_('What is the desired farthest parallel [cm] ?'),'farthest','farthest size',10000,1,100000)
7740
- ret=dlg.ShowModal()
7741
- if ret==wx.ID_CANCEL:
7742
- dlg.Destroy()
7743
- return
8004
+ # ds=float(dlg.GetValue())/100.
7744
8005
 
7745
- farthest=float(dlg.GetValue())/100.
8006
+ # dlg.Destroy()
7746
8007
 
7747
- dlg.Destroy()
8008
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired sliding length [cm] ?'),'sliding','sliding size',5000,1,100000)
8009
+ # ret=dlg.ShowModal()
8010
+ # if ret==wx.ID_CANCEL:
8011
+ # dlg.Destroy()
8012
+ # return
7748
8013
 
7749
- dlg=wx.NumberEntryDialog(None,_('What is the desired parallel interval [cm] ?'),'interval','interval size',int(farthest*10.),1,int(farthest*100.))
7750
- ret=dlg.ShowModal()
7751
- if ret==wx.ID_CANCEL:
7752
- dlg.Destroy()
7753
- return
8014
+ # sliding=float(dlg.GetValue())/100.
7754
8015
 
7755
- interval=float(dlg.GetValue())/100.
8016
+ # dlg.Destroy()
7756
8017
 
7757
- dlg.Destroy()
8018
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired farthest parallel [cm] ?'),'farthest','farthest size',10000,1,100000)
8019
+ # ret=dlg.ShowModal()
8020
+ # if ret==wx.ID_CANCEL:
8021
+ # dlg.Destroy()
8022
+ # return
7758
8023
 
7759
- zones_names=[curz.myname for curz in self.myzones]
7760
- if "intersect" in zones_names:
7761
- dlg = wx.MessageDialog(None,_('Do you want to use the intersect zone ?'),style=wx.YES_NO)
7762
- ret=dlg.ShowModal()
7763
- if ret==wx.ID_YES:
7764
- inter = True
7765
- else:
7766
- inter = False
7767
- dlg.Destroy()
7768
- else:
7769
- inter = False
8024
+ # farthest=float(dlg.GetValue())/100.
8025
+
8026
+ # dlg.Destroy()
8027
+
8028
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired parallel interval [cm] ?'),'interval','interval size',int(farthest*10.),1,int(farthest*100.))
8029
+ # ret=dlg.ShowModal()
8030
+ # if ret==wx.ID_CANCEL:
8031
+ # dlg.Destroy()
8032
+ # return
8033
+
8034
+ # interval=float(dlg.GetValue())/100.
8035
+
8036
+ # dlg.Destroy()
8037
+
8038
+ zones_names=[curz.myname.lower() for curz in self.myzones]
8039
+ # if "intersect" in zones_names:
8040
+ # dlg = wx.MessageDialog(None,_('Do you want to use the intersect zone ?'),style=wx.YES_NO)
8041
+ # ret=dlg.ShowModal()
8042
+ # if ret==wx.ID_YES:
8043
+ # inter = True
8044
+ # else:
8045
+ # inter = False
8046
+ # dlg.Destroy()
8047
+ # else:
8048
+ # inter = False
7770
8049
 
7771
8050
  inter_zone = None
7772
- if inter:
7773
- inter_zone = self.myzones[zones_names.index("intersect")]
8051
+ if intersect:
8052
+ if "intersect" in zones_names:
8053
+ inter_zone = self.myzones[zones_names.index("intersect")]
8054
+
8055
+ # dlg = wx.MessageDialog(None,_('Do you want to separate left and right polygons ?'),style=wx.YES_NO)
8056
+ # ret=dlg.ShowModal()
8057
+ # if ret==wx.ID_YES:
8058
+ # howmany = 2
8059
+ # else:
8060
+ # howmany = 1
7774
8061
 
7775
- dlg = wx.MessageDialog(None,_('Do you want to separate left and right polygons ?'),style=wx.YES_NO)
7776
- ret=dlg.ShowModal()
7777
- if ret==wx.ID_YES:
7778
- howmany = 2
7779
- else:
7780
- howmany = 1
8062
+ try:
8063
+ self.active_zone.create_sliding_polygon_from_parallel(ds, sliding, farthest, interval, inter_zone, howmany, eps_offset=offset)
8064
+ except:
8065
+ logging.error(_('Error during sliding polygons calculation.'))
7781
8066
 
7782
- self.active_zone.create_sliding_polygon_from_parallel(ds, sliding, farthest, interval, inter_zone, howmany)
8067
+ option_dialog.Close()
7783
8068
 
7784
8069
 
7785
8070
  def Oncreatebin(self,event:wx.MouseEvent):
@@ -8471,9 +8756,15 @@ class Zones(wx.Frame, Element_To_Draw):
8471
8756
 
8472
8757
  self.active_zone.reset_listogl()
8473
8758
  self.myzones.pop(int(self.myzones.index(self.active_zone)))
8759
+ self.Activate_vector(None)
8760
+ self.Activate_zone(None)
8761
+
8474
8762
  self.fill_structure()
8475
8763
  self.find_minmax(True)
8476
8764
 
8765
+ if self.get_mapviewer() is not None:
8766
+ self.get_mapviewer().Paint()
8767
+
8477
8768
  def OnClickfindactivate_vector(self, event:wx.MouseEvent):
8478
8769
  """
8479
8770
  Recherche et activation d'un vecteur dans toutes les zones
@@ -8580,11 +8871,7 @@ class Zones(wx.Frame, Element_To_Draw):
8580
8871
  return
8581
8872
 
8582
8873
  curname=self.active_vector.myname
8583
- r = wx.MessageDialog(
8584
- None,
8585
- _('The vector {n} will be deleted. Continue?').format(n=curname),
8586
- style=wx.YES_NO | wx.ICON_QUESTION
8587
- ).ShowModal()
8874
+ r = wx.MessageDialog(None, _('The vector {n} will be deleted. Continue?').format(n=curname), style=wx.YES_NO | wx.ICON_QUESTION).ShowModal()
8588
8875
 
8589
8876
  if r != wx.ID_YES:
8590
8877
  return
@@ -8596,14 +8883,23 @@ class Zones(wx.Frame, Element_To_Draw):
8596
8883
 
8597
8884
  idx = int(actzone.myvectors.index(self.active_vector))
8598
8885
  if idx >= 0 and idx < actzone.nbvectors:
8886
+ actzone.reset_listogl()
8599
8887
  actzone.myvectors.pop(idx)
8600
8888
 
8601
- if actzone.nbvectors==0:
8889
+ if actzone.nbvectors == 0:
8602
8890
  self.Activate_vector(None)
8891
+ elif idx < actzone.nbvectors:
8892
+ self.Activate_vector(actzone.myvectors[idx])
8893
+ else:
8894
+ self.Activate_vector(actzone.myvectors[-1])
8603
8895
 
8604
8896
  self.fill_structure()
8605
8897
  self.find_minmax(True)
8606
8898
 
8899
+ if self.get_mapviewer() is not None:
8900
+ self.get_mapviewer().Paint()
8901
+
8902
+
8607
8903
  def OnClickup_vector(self, event:wx.MouseEvent):
8608
8904
  """Remonte le vecteur actif dans la liste de la zone"""
8609
8905
  if self.verify_activevec():