aceti 0.0.1__tar.gz

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.
aceti-0.0.1/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ dist/
2
+ __pycache__/
aceti-0.0.1/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025 Alejandro Casado Pérez
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ graft maps
aceti-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: aceti
3
+ Version: 0.0.1
4
+ Summary: A simple package to store and create maps for an experiment
5
+ Project-URL: Homepage, https://github.com/aceti-pub/common_maps
6
+ Project-URL: Issues, https://github.com/aceti-pub/common_maps/issues
7
+ Author-email: Alejandro Casado <acasado4@us.es>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Education
12
+ Classifier: Operating System :: MacOS :: MacOS X
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Programming Language :: Python :: 2
15
+ Classifier: Programming Language :: Python :: 3
16
+ Requires-Dist: numpy
17
+ Description-Content-Type: text/markdown
18
+
19
+ aceti_maps
20
+ ===========
21
+
22
+ * Python library to make an efficient use of data
23
+ * License: MIT
24
+ * Compatible With: python 3.0+
25
+
26
+ Develop API Usage
27
+ -----------------
28
+
29
+ available maps
30
+ - Alamillo
31
+ - Alamillo11x15
32
+ - Alamillo30x49
33
+
34
+ <pre>
35
+ <code>
36
+ >>>from aceti_maps import import_map
37
+ >>>base_matrix, lat_lon_map = import_map("alamillo11x15")
38
+
39
+ </code>
40
+ </pre>
aceti-0.0.1/README.md ADDED
@@ -0,0 +1,29 @@
1
+ La forma de hacer upload de este paquete se realiza mediante Hatchling siguiendo el [tutorial de python](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
2
+
3
+ esta librería recibe el nombre de aceti_maps
4
+
5
+ asegurarse de tener pip actualizado a la última versión
6
+ ```bash
7
+ $ python3 -m pip install --upgrade pip
8
+ ```
9
+ construir el repositorio
10
+ ```bash
11
+ $ python3 -m build
12
+ ```
13
+
14
+ subirlo al repositorio deseado
15
+ ```bash
16
+ $ python3 -m twine upload --repository testpypi dist/*
17
+ $ python3 -m twine upload dist/*
18
+ ```
19
+ el token lo tiene acasado4@us.es
20
+
21
+
22
+
23
+ instalar mediante
24
+ ```bash
25
+ $ python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps aceti_maps
26
+ $ pip install aceti_maps
27
+ ```
28
+
29
+ la guía de uso está disponible en [README_LEG](./README_LEG.md)
@@ -0,0 +1,22 @@
1
+ aceti_maps
2
+ ===========
3
+
4
+ * Python library to make an efficient use of data
5
+ * License: MIT
6
+ * Compatible With: python 3.0+
7
+
8
+ Develop API Usage
9
+ -----------------
10
+
11
+ available maps
12
+ - Alamillo
13
+ - Alamillo11x15
14
+ - Alamillo30x49
15
+
16
+ <pre>
17
+ <code>
18
+ >>>from aceti_maps import import_map
19
+ >>>base_matrix, lat_lon_map = import_map("alamillo11x15")
20
+
21
+ </code>
22
+ </pre>
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling >= 1.26"]
3
+ build-backend = "hatchling.build"
4
+ [project]
5
+ name = "aceti"
6
+ version = "0.0.1"
7
+ authors = [
8
+ { name="Alejandro Casado", email="acasado4@us.es" },
9
+ ]
10
+ description = "A simple package to store and create maps for an experiment"
11
+ readme = "README_LEG.md"
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Education",
15
+ "Programming Language :: Python :: 2",
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: MacOS :: MacOS X",
18
+ "Operating System :: Microsoft :: Windows",
19
+ ]
20
+ license = "MIT"
21
+ license-files = ["LICEN[CS]E*"]
22
+ dependencies = [
23
+ "numpy",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/aceti-pub/common_maps"
28
+ Issues = "https://github.com/aceti-pub/common_maps/issues"
@@ -0,0 +1,2 @@
1
+ # from .maps_utils import png_to_csv, csv_to_png, csv_to_npy, invert_map, get_output_name, csv_shrink, csv_downsize
2
+ from .map_importer import import_map
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+ import os
3
+ import sys
4
+ if sys.version_info < (3, 9):
5
+ # importlib.resources either doesn't exist or lacks the files() function, so use the PyPI version:
6
+ import importlib_resources
7
+ else:
8
+ # importlib.resources has files(), so use that:
9
+ import importlib.resources as importlib_resources
10
+
11
+ def import_map(map_name: str):
12
+ """
13
+ Import a map from a file and return the base matrix and lat/lon map.
14
+ Args:
15
+ map_name (str): The name of the map to import.
16
+ Returns:
17
+ tuple: A tuple containing the base matrix and lat/lon map.
18
+ """
19
+ map_name = map_name.lower()
20
+ pkg = importlib_resources.files("aceti_maps")
21
+ if os.path.exists(pkg.joinpath("maps", f"{map_name}mask.npy")):
22
+ print(f"Loading map {map_name} from repo directory")
23
+
24
+ base_matrix = np.load(pkg.joinpath("maps", f"{map_name}mask.npy"))
25
+
26
+ # Load the lat/lon map
27
+ lat_lon_map = np.load(pkg.joinpath("maps", f"{map_name}latlon.npy"))
28
+
29
+ return base_matrix, lat_lon_map
@@ -0,0 +1,573 @@
1
+
2
+ # modified from the scripts created by Hayden Eskriett [http://eskriett.com] and jbndlr
3
+ # Find the associated blog post at: http://blog.eskriett.com/2013/07/19/downloading-google-maps/
4
+ # but it has been done in a better way using the data in https://developers.google.com/maps/documentation/javascript/coordinates
5
+ # and https://stackoverflow.com/questions/40342355/how-can-i-generate-a-regular-geographic-grid-using-python
6
+
7
+
8
+
9
+
10
+
11
+ ###################################IMPORTANT##################################
12
+ #Google maps works with [Latitude Longitude] variables however
13
+ #Dronekit and other programs (such as gridder) work with [Longitude Latitude] variables
14
+ ##############################################################################
15
+
16
+ import urllib.request
17
+ from PIL import Image
18
+ import os
19
+ import math
20
+ import pyproj
21
+ import matplotlib.pyplot as plt
22
+ import numpy as np
23
+ # from KMLMissionGeneration import KMLMissionGenerator
24
+ class CustomError(Exception):
25
+ pass
26
+
27
+ class GoogleMapDownloader:
28
+ """
29
+ A class which generates high resolution google maps image given
30
+ Northwest and Southeast points in [Lat Lon] and zoom level
31
+ You can change the quality of the image by changing the zoom and layer values
32
+
33
+ 19 is a valid zoom value knowing the size of our drone
34
+
35
+ for the maps you have available
36
+ ROADMAP = "v"
37
+ TERRAIN = "p"
38
+ ALTERED_ROADMAP = "r"
39
+ SATELLITE = "s"
40
+ TERRAIN_ONLY = "t"
41
+ HYBRID = "y"
42
+
43
+
44
+ """
45
+
46
+ def __init__(self, Northwest, Southeast, zoom=19, layer="s"):
47
+ """
48
+ GoogleMapDownloader Constructor
49
+ Args:
50
+ lat: The latitude of the location required
51
+ lng: The longitude of the location required
52
+ zoom: The zoom level of the location required, ranges from 0 - 23
53
+ """
54
+ self.Northwest = Northwest
55
+ self.Southeast = Southeast
56
+ self._zoom = zoom
57
+ self._layer = layer
58
+
59
+ if Northwest[0]<=Southeast[0] or Northwest[1]>=Southeast[1]:
60
+ raise CustomError("You must use Northwest(top-left) and Southeast(bottom-right) coordinates")
61
+ self.get_nw_coordinates()
62
+ self.get_se_coordinates()
63
+
64
+ if (abs(self.nw_tile[0]-self.se_tile[0]) == 0) or (abs(self.nw_tile[1]-self.se_tile[1]) == 0):
65
+ raise CustomError("Insuficient zoom, points are too close, i am lazy to program this, increase zoom")
66
+
67
+
68
+
69
+ def get_nw_coordinates(self):
70
+ """
71
+ Generates an X,Y tile and pixel coordinate based on the latitude, longitude
72
+ and zoom level
73
+ Returns: An X,Y pixel coordinate
74
+ """
75
+
76
+ tile_size = 256 #each tile has 256 pixels
77
+
78
+ # Use a left shift to get the power of 2, zoom 0 is a world map, zoom 1 is wold map divided in 4 tiles, zoom 2 is world map divided in 16 tiles
79
+ # i.e. a zoom level of 2 will have 2^2 = 4 tiles as coordinate sistem divides axis in 4 (x+y+,x-y+,x-y-,x+y-)
80
+ numTiles = 1 << self._zoom
81
+
82
+ # Find the x_pixel given the longitude
83
+ x_pixel = (tile_size / 2 + self.Northwest[1] * tile_size / 360.0) * numTiles
84
+
85
+ # Convert the latitude to radians and take the sine
86
+ sin_y = math.sin(self.Northwest[0] * (math.pi / 180.0))
87
+
88
+ # Calulate the y_pixel
89
+ y_pixel = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
90
+ tile_size / (2 * math.pi))) * numTiles
91
+
92
+ self.nw_pixel=[x_pixel, y_pixel]
93
+ self.nw_tile=[int(x_pixel // tile_size), int(y_pixel // tile_size)]
94
+
95
+ def get_se_coordinates(self):
96
+ """
97
+ Generates an X,Y tile and pixel coordinate based on the latitude, longitude
98
+ and zoom level
99
+ Returns: An X,Y pixel coordinate
100
+ """
101
+
102
+ tile_size = 256 #each tile has 256 pixels
103
+
104
+ # Use a left shift to get the power of 2, zoom 0 is a world map, zoom 1 is wold map divided in 4 tiles, zoom 2 is world map divided in 16 tiles
105
+ # i.e. a zoom level of 2 will have 2^2 = 4 tiles as coordinate sistem divides axis in 4 (x+y+,x-y+,x-y-,x+y-)
106
+ numTiles = 1 << self._zoom
107
+
108
+ # Find the x_pixel given the longitude
109
+ x_pixel = (tile_size / 2 + self.Southeast[1] * tile_size / 360.0) * numTiles
110
+
111
+ # Convert the latitude to radians and take the sine
112
+ sin_y = math.sin(self.Southeast[0] * (math.pi / 180.0))
113
+
114
+ # Calulate the y_pixel
115
+ y_pixel = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
116
+ tile_size / (2 * math.pi))) * numTiles
117
+
118
+ self.se_pixel=[x_pixel, y_pixel]
119
+ self.se_tile=[math.ceil(x_pixel // tile_size)+1, math.ceil(y_pixel // tile_size)+1]
120
+
121
+ def generateImage(self, ):
122
+ """
123
+ Generates an image by stitching a number of google map tiles together.
124
+
125
+ Args:
126
+ start_x: The top-left x-tile coordinate
127
+ start_y: The top-left y-tile coordinate
128
+ tile_width: The number of tiles wide the image should be -
129
+ defaults to 5
130
+ tile_height: The number of tiles high the image should be -
131
+ defaults to 5
132
+ Returns:
133
+ A high-resolution Goole Map image.
134
+ """
135
+ tile_width = abs(self.nw_tile[0]-self.se_tile[0])
136
+ tile_height = abs(self.nw_tile[1]-self.se_tile[1])
137
+
138
+
139
+
140
+ # Determine the size of the image, for simplicity, we will print the whole image and later crop it
141
+ width, height = 256 * tile_width, 256 * tile_height
142
+
143
+ # Create a new image of the size required
144
+ map_img = Image.new('RGB', (width, height))
145
+
146
+
147
+ # calculate northwest pixel of the tile
148
+ start_x=self.nw_tile[0]
149
+ start_y=self.nw_tile[1]
150
+
151
+ # print the map
152
+ for x in range(0, tile_width):
153
+ for y in range(0, tile_height):
154
+
155
+ url = f'https://mt0.google.com/vt?lyrs={self._layer}&x=' + str(start_x + x) + '&y=' + str(start_y + y) + '&z=' + str(
156
+ self._zoom)
157
+
158
+ current_tile = str(x) + '-' + str(y)
159
+ urllib.request.urlretrieve(url, current_tile)
160
+
161
+ im = Image.open(current_tile)
162
+ map_img.paste(im, (x * 256, y * 256))
163
+
164
+ os.remove(current_tile)
165
+
166
+
167
+ # cut corners
168
+ left=abs(self.nw_tile[0] * 256 - self.nw_pixel[0])
169
+ top=abs(self.nw_tile[1] * 256 - self.nw_pixel[1])
170
+ right=left + abs(self.se_pixel[0] - self.nw_pixel[0])
171
+ bottom=top + abs(self.nw_pixel[1] - self.se_pixel[1])
172
+
173
+
174
+ map_img = map_img.crop((left, top, right, bottom))
175
+ return map_img
176
+
177
+ class gridder:
178
+
179
+ def __init__(self, NW_corner, SE_corner, grid_size, zoom =19):
180
+ """
181
+ Args:
182
+ NW_corner:
183
+ SE_corner:
184
+ grid_size:
185
+ """
186
+
187
+
188
+
189
+ # Set up transformers, EPSG:3857 is metric, same as EPSG:900913
190
+ self.to_proxy_transformer = pyproj.Transformer.from_crs('epsg:4326', 'epsg:3857')
191
+ self.to_original_transformer = pyproj.Transformer.from_crs('epsg:3857', 'epsg:4326')
192
+
193
+ # Project corners to target projection
194
+ self.NW_corner=[NW_corner[1],NW_corner[0]]
195
+ self.SE_corner=[SE_corner[1],SE_corner[0]]
196
+
197
+ #this transformation works in [Longitude Latitude]
198
+ self.transformed_nw = self.to_proxy_transformer.transform(self.NW_corner[1], self.NW_corner[0]) # Transform NW point to 3857
199
+ self.transformed_se = self.to_proxy_transformer.transform(self.SE_corner[1], self.SE_corner[0]) # .. same for SE
200
+
201
+ self.pole=["E","N"]
202
+ self.grid_size=grid_size
203
+ self.zoom = zoom
204
+ print(f"map size is {int(abs(self.transformed_nw[1]-self.transformed_se[1]))}x{int(abs(self.transformed_nw[0]-self.transformed_se[0]))}m")
205
+ self.create_grid()
206
+ print(f"grid size is {self.width}x{self.heigth} cells")
207
+ self.calculate_pixels_per_grid()
208
+
209
+
210
+
211
+
212
+
213
+ def save_to_file(self, name):
214
+ with open(name, 'w') as of:
215
+ for j in range(self.heigth):
216
+ for i in range(self.width):
217
+ of.write('{:f},{:f};'.format(self.gridpoints[j][i][0], self.gridpoints[j][i][1]))
218
+ of.write('\n')
219
+
220
+
221
+ def create_grid(self):
222
+ # Iterate over 2D area
223
+ self.gridpoints = []
224
+ countx=0
225
+ county=0
226
+ x = self.transformed_nw[0]
227
+ if self.transformed_nw[0] >self.transformed_se[0]:
228
+ self.pole[0]="N"
229
+ else:
230
+ self.pole[0]="S"
231
+ while abs(x) > abs(self.transformed_se[0]):
232
+ county+=1
233
+ countx=0
234
+ column=[]
235
+ y = self.transformed_nw[1]
236
+ if self.transformed_nw[1] <self.transformed_se[1]:
237
+ self.pole[1]="E"
238
+ else:
239
+ self.pole[1]="W"
240
+ while abs(y) > abs(self.transformed_se[1]):
241
+ p = self.to_original_transformer.transform(x, y)
242
+ column.append([p[0],p[1]])
243
+ if self.pole[1]=="E":
244
+ y += self.grid_size
245
+ else:
246
+ y -= self.grid_size
247
+ countx+=1
248
+ column.pop() #cut corners
249
+ self.gridpoints.append(column)
250
+ if self.pole[0]=="N":
251
+ x -=self.grid_size
252
+ else:
253
+ x +=self.grid_size
254
+ self.gridpoints.pop() #cut corners
255
+ self.width=len(self.gridpoints[0])
256
+ self.heigth=len(self.gridpoints)
257
+
258
+
259
+ def to_pixel(self, GPS_point, zoom=19):
260
+ """
261
+ Generates an X,Y pixel coordinate based on the latitude, longitude
262
+ and zoom level
263
+ Returns: An X,Y pixel coordinate
264
+ """
265
+ #check if we are inside the map
266
+ if self.pole[1]=="W":
267
+ if ((self.SE_corner[1])>(GPS_point[1])>(self.NW_corner[1])):
268
+ raise CustomError(f"point {GPS_point} 1W is outside the map {[self.NW_corner,self.SE_corner]}")
269
+ else:
270
+ if ((self.SE_corner[1])<(GPS_point[1])<(self.NW_corner[1])):
271
+ raise CustomError(f"point {GPS_point} 1E is outside the map {[self.NW_corner,self.SE_corner]}")
272
+ if self.pole[0]=="N":
273
+ if ((self.SE_corner[0])>(GPS_point[0])>(self.NW_corner[0])):
274
+ raise CustomError(f"point {GPS_point} 0N is outside the map {[self.NW_corner,self.SE_corner]}")
275
+ else:
276
+ if ((self.SE_corner[0])<(GPS_point[0])<(self.NW_corner[0])):
277
+ raise CustomError(f"point {GPS_point} 0S is outside the map {[self.NW_corner,self.SE_corner]}")
278
+
279
+
280
+
281
+ tile_size = 256 #each tile has 256 pixels
282
+
283
+ # Use a left shift to get the power of 2, zoom 0 is a world map, zoom 1 is wold map divided in 4 tiles, zoom 2 is world map divided in 16 tiles
284
+ # i.e. a zoom level of 2 will have 2^2 = 4 tiles as coordinate sistem divides axis in 4 (x+y+,x-y+,x-y-,x+y-)
285
+ numTiles = 1 << self.zoom
286
+
287
+ # Find the x_pixel given the longitude
288
+ x_pixel = (tile_size / 2 + GPS_point[1] * tile_size / 360.0) * numTiles
289
+
290
+ # Convert the latitude to radians and take the sine
291
+ sin_y = math.sin(GPS_point[0] * (math.pi / 180.0))
292
+
293
+ # Calulate the y_pixel
294
+ y_pixel = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
295
+ tile_size / (2 * math.pi))) * numTiles
296
+
297
+ return [x_pixel-self.corner_pixel[0], y_pixel-self.corner_pixel[1]]
298
+
299
+ def calculate_pixels_per_grid(self):
300
+
301
+ self.calculate_corner_pixel()
302
+ p=self.to_pixel(self.gridpoints[self.heigth-1][self.width-1])
303
+ x=p[0]
304
+ y=p[1]
305
+ self.pixel_width=x/(self.width-1)
306
+ self.pixel_heigth=y/(self.heigth-1)
307
+ print(f"pixel size is {x}x{y} with corner {self.corner_pixel}")
308
+
309
+ def calculate_corner_pixel(self):
310
+ """
311
+ Generates an X,Y pixel coordinate based on the latitude, longitude
312
+ and zoom level
313
+ Returns: An X,Y pixel coordinate
314
+ """
315
+
316
+ tile_size = 256 #each tile has 256 pixels
317
+
318
+ # Use a left shift to get the power of 2, zoom 0 is a world map, zoom 1 is wold map divided in 4 tiles, zoom 2 is world map divided in 16 tiles
319
+ # i.e. a zoom level of 2 will have 2^2 = 4 tiles as coordinate sistem divides axis in 4 (x+y+,x-y+,x-y-,x+y-)
320
+ numTiles = 1 << self.zoom
321
+
322
+ # Find the x_pixel given the longitude
323
+ x_pixel = (tile_size / 2 + self.NW_corner[0] * tile_size / 360.0) * numTiles
324
+
325
+ # Convert the latitude to radians and take the sine
326
+ sin_y = math.sin(self.NW_corner[1] * (math.pi / 180.0))
327
+
328
+ # Calulate the y_pixel
329
+ y_pixel = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
330
+ tile_size / (2 * math.pi))) * numTiles
331
+
332
+ self.corner_pixel=[x_pixel, y_pixel]
333
+
334
+ def show_grid(self, img):
335
+
336
+ #show grid
337
+ x=[]
338
+ y=[]
339
+ plt.figure()
340
+ plt.imshow(img, cmap=plt.get_cmap('binary'))
341
+
342
+ #horizontal lines
343
+ for j in range(self.heigth):
344
+ for i in range(self.width):
345
+ p=self.to_pixel(self.gridpoints[j][i])
346
+ x.append(p[0])
347
+ y.append(p[1])
348
+ plt.plot(x,y,'b-', linewidth=0.2)
349
+ x=[]
350
+ y=[]
351
+ #vertical lines
352
+
353
+ for i in range(self.width):
354
+ for j in range(self.heigth):
355
+ p=self.to_pixel(self.gridpoints[j][i])
356
+ x.append(p[0])
357
+ y.append(p[1])
358
+ plt.plot(x,y,'b-', linewidth=0.2)
359
+ x=[]
360
+ y=[]
361
+ plt.savefig('grid.png', dpi=400)
362
+
363
+ img=Image.open('grid.png')
364
+ img.show()
365
+
366
+
367
+ def show_point(self, img, point):
368
+
369
+ #print a point in the map
370
+ pixel=self.to_pixel(point)
371
+
372
+ plt.figure()
373
+ plt.imshow(img, cmap=plt.get_cmap('binary'))
374
+ plt.plot(pixel[0],pixel[1],'ro', markersize=5)
375
+ plt.show()
376
+
377
+ def save_empty_mask(self, file):
378
+ with open(file, 'w') as of:
379
+ for j in range(self.heigth-1):
380
+ for i in range(self.width-1):
381
+ of.write('0;')
382
+ of.write('\n')
383
+
384
+ def save_mask(self, file):
385
+ with open(file, 'w') as of:
386
+ for j in range(self.heigth-1):
387
+ for i in range(self.width-2):
388
+ of.write('{:d};'.format(self.mask[j][i]))
389
+ of.write('{:d}\n'.format(self.mask[j][i]))
390
+
391
+ def create_mask(self, img):
392
+ grayImage=img.convert(mode="L")
393
+ array = np.array(grayImage)
394
+ self.mask=[]
395
+ for j in range(self.heigth-1):
396
+ column=[]
397
+ for i in range(self.width-1):
398
+ p1=self.to_pixel(self.gridpoints[j][i])
399
+ p2=self.to_pixel(self.gridpoints[j+1][i])
400
+ p3=self.to_pixel(self.gridpoints[j][i+1])
401
+ p4=self.to_pixel(self.gridpoints[j+1][i+1])
402
+ p1=array[int(p1[1])][int(p1[0])]
403
+ p2=array[int(p2[1])][int(p2[0])]
404
+ p3=array[int(p3[1])][int(p3[0])]
405
+ p4=array[int(p4[1])][int(p4[0])]
406
+ white=0
407
+ if p1:
408
+ white+=1
409
+ if p2:
410
+ white+=1
411
+ if p3:
412
+ white+=1
413
+ if p4:
414
+ white+=1
415
+ if white>2:
416
+ column.append(0)
417
+ else:
418
+ column.append(1)
419
+ self.mask.append(column)
420
+ def show_mask(self, img):
421
+ #show grid
422
+
423
+ plt.figure()
424
+ plt.imshow(img, cmap=plt.get_cmap('binary'))
425
+
426
+ for j in range(self.heigth-1):
427
+ for i in range(self.width-1):
428
+ if not self.mask[j][i]:
429
+ x=[]
430
+ y=[]
431
+ p1=self.to_pixel(self.gridpoints[j][i])
432
+ p2=self.to_pixel(self.gridpoints[j+1][i])
433
+ p3=self.to_pixel(self.gridpoints[j][i+1])
434
+ p4=self.to_pixel(self.gridpoints[j+1][i+1])
435
+ x.append(p1[0])
436
+ y.append(p1[1])
437
+ x.append(p2[0])
438
+ y.append(p2[1])
439
+ x.append(p4[0])
440
+ y.append(p4[1])
441
+ x.append(p3[0])
442
+ y.append(p3[1])
443
+ x.append(p1[0])
444
+ y.append(p1[1])
445
+ plt.plot(x,y,'b-', linewidth=0.2)
446
+
447
+
448
+ plt.savefig('mask.png', dpi=400)
449
+
450
+ img=Image.open('mask.png')
451
+ img.show()
452
+
453
+ # def show_mission(self, img):
454
+ # plt.figure()
455
+ # plt.imshow(img, cmap=plt.get_cmap('binary'))
456
+ # point=0
457
+ # KML=KMLMissionGenerator("MisionesLoyola_dron_3.kml")
458
+ # mission=KML.get_mission_list()[0]
459
+
460
+ # for j in range(self.heigth-1):
461
+ # for i in range(self.width-1):
462
+ # if not self.mask[j][i]:
463
+ # x=[]
464
+ # y=[]
465
+ # p1=self.to_pixel(self.gridpoints[j][i])
466
+ # p2=self.to_pixel(self.gridpoints[j+1][i])
467
+ # p3=self.to_pixel(self.gridpoints[j][i+1])
468
+ # p4=self.to_pixel(self.gridpoints[j+1][i+1])
469
+ # x.append(p1[0])
470
+ # y.append(p1[1])
471
+ # x.append(p2[0])
472
+ # y.append(p2[1])
473
+ # x.append(p4[0])
474
+ # y.append(p4[1])
475
+ # x.append(p3[0])
476
+ # y.append(p3[1])
477
+ # x.append(p1[0])
478
+ # y.append(p1[1])
479
+ # plt.plot(x,y,'b-', linewidth=0.2)
480
+ # for i in mission:
481
+ # point=[i[1], i[0]]
482
+ # pixel=self.to_pixel(point)
483
+ # plt.plot(pixel[0],pixel[1],'ro', markersize=0.5)
484
+
485
+
486
+ # plt.savefig('mission.png', dpi=400)
487
+
488
+ # img=Image.open('mission.png')
489
+ # img.show()
490
+
491
+
492
+ def main():
493
+ # Create a new instance of GoogleMap Downloader
494
+ """
495
+ Loyola
496
+ NW_corner=[37.30877610927852, -5.940516378146266] #northwest point of the map [latitude longitude]
497
+ SE_corner=[37.30661986681041, -5.939422309058239] #southeast point of the map [latitude longitude]
498
+
499
+
500
+ NW_corner=[36.123388953996404, -5.443591065870082] #northwest point of the map [latitude longitude]
501
+ SE_corner=[36.11595558243919, -5.430975637057081] #southeast point of the map [latitude longitude]
502
+ #alamillo
503
+
504
+ NW_corner=[36.227154628215054, -6.188738765767977] #northwest point of the map [latitude longitude]
505
+ SE_corner=[35.67592758704647, -5.13798693812742] #southeast point of the map [latitude longitude]
506
+ #Estrecho
507
+ """
508
+ # NW_corner=[30.719200,-86.115300] #northwest point of the map [latitude longitude]
509
+ # SE_corner=[30.7148,-86.110014] #southeast point of the map [latitude longitude]
510
+ # #Lake DeFuniak
511
+
512
+ NW_corner=[37.420088017565696, -6.001345595400041] #northwest point of the map [latitude longitude]
513
+ SE_corner=[37.41837443521307, -5.997484063063451] #southeast point of the map [latitude longitude]
514
+ #alamillo
515
+
516
+ #SE_corner=[37.29989089621092, -5.9274044593699236]
517
+ grid_size= 2.5 #size of the grid in meters
518
+ zoom=19
519
+
520
+ #create class of the map downloader
521
+ gmd = GoogleMapDownloader(NW_corner ,SE_corner, zoom =zoom) #zoom 19, aproximadamente tiles de 50m^2, más zoom no se aprecian obstaculos nuevos
522
+
523
+ try:
524
+ # Get the high resolution image
525
+ img = gmd.generateImage()
526
+ except IOError:
527
+ print("Could not generate the image - try adjusting the zoom level and checking your coordinates")
528
+ else:
529
+ # Save the image to disk
530
+ img.rotate(17)
531
+ img.save("high_resolution_image2.png")
532
+ print("The map has successfully been created")
533
+
534
+
535
+ #Show the image
536
+ plt.figure()
537
+ plt.imshow(img, cmap=plt.get_cmap('binary'))
538
+ plt.show()
539
+
540
+ #create grid
541
+ print(f"generating map for {NW_corner}, {SE_corner}")
542
+ grid= gridder(NW_corner,SE_corner,grid_size, zoom =zoom)
543
+
544
+
545
+
546
+ #show the grid on the image
547
+ aux=0
548
+ while aux!="y" and aux!="n":
549
+ aux=input("is there already an existing mask (y/n)").lower()
550
+ if aux=='n':
551
+ grid.show_grid(img)
552
+ grid.save_to_file("grid.csv")
553
+ grid.save_empty_mask("empty_mask.csv")
554
+ return
555
+
556
+ while not os.path.exists(str("./"+aux)) or aux[-1]!="g":
557
+ aux=input("insert mask name: ").lower()
558
+ imgn=Image.open(aux)
559
+ grid.show_grid(imgn)
560
+ name=aux[0:-4]
561
+ grid.create_mask(imgn)
562
+ grid.save_mask(str(name+".csv"))
563
+ grid.show_mask(img)
564
+
565
+
566
+ #show a point
567
+ #grid.show_point(img, [37.307659405593995, -5.940044140455814])
568
+
569
+ #grid.show_mission(img)
570
+
571
+
572
+
573
+ if __name__ == '__main__': main()
@@ -0,0 +1,38 @@
1
+ import sys
2
+ sys.path.append('.')
3
+
4
+ from Environment.generate_map import img2pixels
5
+
6
+ import numpy as np
7
+
8
+ # Esquina inferior izquierda
9
+ lat = np.float64(37.41856004857407)
10
+ lon = np.float64(-6.001322282719345)
11
+
12
+ # Esquina superior derecha
13
+ lat2 = np.float64(37.41953493274117)
14
+ lon2 = np.float64(-5.9987915127912)
15
+
16
+ path = 'Environment/maps/alamillo.png'
17
+
18
+ pixels = img2pixels(path, threshold=128, height=40)
19
+
20
+ pixels = 1 - pixels
21
+
22
+ # Sabiendo que lat,lon hace referencia a la esquina inferior izquierda y lat2,lon2 a la esquina superior derecha,
23
+ # calculamos, para cada pixel, su latitud y longitud
24
+ latitudes = np.linspace(lat2, lat, pixels.shape[0], dtype=np.float64)
25
+ longitudes = np.linspace(lon, lon2, pixels.shape[1], dtype=np.float64)
26
+
27
+ # Creamos un array de MxNx2 dimensiones con las latitudes y longitudes
28
+ lat_lon_map = np.zeros((pixels.shape[0], pixels.shape[1], 2), dtype=np.float64)
29
+
30
+ for i in range(pixels.shape[0]):
31
+ for j in range(pixels.shape[1]):
32
+ lat_lon_map[i,j] = [latitudes[i], longitudes[j]]
33
+
34
+ np.save('Environment/maps/lat_lon_alamillo_big.npy', lat_lon_map)
35
+ np.save('Environment/maps/alamillo_big.npy', pixels)
36
+
37
+
38
+
@@ -0,0 +1,40 @@
1
+ # Programa para pasar de una imagen a una matriz de pixeles 0,1 con un umbral y un alto en pixeles
2
+ import sys
3
+ from PIL import Image
4
+ import numpy as np
5
+ import matplotlib.pyplot as plt
6
+ import argparse
7
+
8
+
9
+
10
+ def img2pixels(img_path, threshold=128, height=100):
11
+
12
+ img = Image.open(img_path)
13
+ img = img.convert('L') # Convert to grayscale
14
+ img = img.resize((int(img.width * height / img.height), height), Image.LANCZOS)
15
+ img = np.array(img)
16
+
17
+ # Threshold
18
+ img = (img > threshold).astype(int)
19
+
20
+ return img
21
+
22
+
23
+
24
+ if __name__ == "__main__":
25
+
26
+ argparser = argparse.ArgumentParser(description='Convert image to pixel matrix')
27
+ argparser.add_argument('--path', type=str, help='Path to image')
28
+ argparser.add_argument('--threshold', type=int, default=128, help='Threshold for binarization')
29
+ argparser.add_argument('--height', type=int, default=100, help='Height of the output image')
30
+ argparser.add_argument('--output', type=str, help='Output file')
31
+
32
+ args = argparser.parse_args()
33
+
34
+ # Example
35
+ pixels = img2pixels(args.path, threshold=args.threshold, height=args.height)
36
+
37
+
38
+ # To numpy and save to file
39
+
40
+ np.save(args.output + '.npy', pixels)
@@ -0,0 +1,180 @@
1
+ import sys
2
+ sys.path.append('.')
3
+
4
+ import pandas as pd
5
+ import numpy as np
6
+ import os
7
+ from typing import Union
8
+ import lzma
9
+ import pickle
10
+ import yaml
11
+ from collections import defaultdict
12
+
13
+ class Legendarium:
14
+
15
+ def __init__(self, experiment_name : str, experiment_description : str, path : str):
16
+
17
+ self._exp_name = experiment_name
18
+ self._exp_desc = experiment_description
19
+ self._path = path
20
+
21
+ # Check if directory exists
22
+ if path is not None:
23
+ if not os.path.exists(self._path):
24
+ os.makedirs(self._path)
25
+ else:
26
+ # Check if the there is a file with the same experiment name
27
+ if os.path.exists(os.path.join(self._path, f"{self._exp_name}.metrics.xz")):
28
+ raise Exception("Experiment already exists!")
29
+
30
+
31
+ self.metrics_meta = {}
32
+ self.metrics = []
33
+ self.parameters = {}
34
+ self.n_metrics = 0
35
+ self.data_names = []
36
+
37
+ def create_parameter(self, parameter_name : str, parameter_value):
38
+ """
39
+ Create a parameter for the experiment
40
+ """
41
+ self.parameters.update({parameter_name : parameter_value})
42
+
43
+ def create_metric(self, metric_name : str, data_type : type, description : str, unit : str):
44
+
45
+ self.metrics_meta.update({metric_name : {"type" : data_type, "description" : description, "unit" : unit, "order": self.n_metrics}})
46
+ self.n_metrics += 1
47
+
48
+ def write(self, run : int, step : int, **kwargs):
49
+ """
50
+ Write data to the metric
51
+ """
52
+
53
+ # Check if metric exists
54
+ for metric_name, new_data in kwargs.items():
55
+
56
+ if metric_name not in self.metrics_meta:
57
+ raise Exception(f"Metric {metric_name} not found!")
58
+
59
+ # Check if the data type is correct
60
+ if not isinstance(run, int):
61
+ raise Exception("Run should be an integer!")
62
+
63
+ if not isinstance(step, int):
64
+ raise Exception("Step should be an integer!")
65
+
66
+ # Check if the data type is correct
67
+ if not issubclass(type(kwargs[metric_name]), self.metrics_meta[metric_name]["type"]):
68
+ raise Exception(f"Data type mismatch for metric {metric_name}!")
69
+
70
+ # Check if all the metrics are present
71
+ if len(kwargs) != self.n_metrics:
72
+ raise Exception("Not all metrics are present in the data!")
73
+
74
+ new_data = [run, step] + [None] * self.n_metrics
75
+
76
+
77
+ for key, value in kwargs.items():
78
+
79
+ # Comprobamos si la clave es una metrica registrada
80
+ if key not in self.metrics_meta:
81
+ raise Exception(f"Metric {key} not found!")
82
+
83
+ # Comprobamos si el tipo de dato es correcto
84
+ if not isinstance(value, self.metrics_meta[key]["type"]):
85
+ raise Exception(f"Data type mismatch for metric {key}!")
86
+
87
+ # Obtenemos la posición en la lista
88
+ pos = self.metrics_meta[key]["order"]
89
+ new_data[pos + 2] = value
90
+
91
+ # Añadimos la información de los parámetros
92
+ for key, value in self.parameters.items():
93
+ new_data.append(value)
94
+
95
+ self.metrics.append(new_data)
96
+
97
+
98
+ def save(self):
99
+ """
100
+ Save the experiment
101
+ """
102
+
103
+ data_names = ["run", "step"] + list(self.metrics_meta.keys()) + list(self.parameters.keys())
104
+
105
+
106
+ # Save the metrics
107
+ with lzma.open(os.path.join(self._path, f"{self._exp_name}.metrics.xz"), "wb") as f:
108
+ pickle.dump(self.metrics, f)
109
+
110
+ # Save the metrics meta
111
+ with open(os.path.join(self._path, f"{self._exp_name}.meta.yaml"), "w") as f:
112
+ yaml.dump(data_names, f)
113
+
114
+
115
+ def load_experiment_pd(experiment_name : str, path : str):
116
+ # Load the metrics as a pandas dataframe
117
+
118
+ # Load the metrics
119
+ with lzma.open(os.path.join(path, f"{experiment_name}.metrics.xz"), "rb") as f:
120
+ metrics = pickle.load(f)
121
+
122
+ # Load the metrics meta
123
+ with open(os.path.join(path, f"{experiment_name}.meta.yaml"), "r") as f:
124
+ data_names = yaml.load(f, Loader=yaml.FullLoader)
125
+
126
+ # Create the dataframe
127
+ df = pd.DataFrame(metrics, columns = data_names)
128
+
129
+ return df
130
+
131
+ def load_experiments(path : str):
132
+ # Load all the experiments in a directory and return a pandas dataframe
133
+
134
+ pds = []
135
+
136
+ for file in os.listdir(path):
137
+ if file.endswith(".metrics.xz"):
138
+ experiment_name = file.split(".")[0]
139
+ try:
140
+ df = load_experiment_pd(experiment_name, path)
141
+ pds.append(df)
142
+ except Exception as e:
143
+ print(f"Error loading experiment {experiment_name}: {e}")
144
+
145
+
146
+ return pd.concat(pds)
147
+
148
+
149
+ if __name__ == "__main__":
150
+
151
+
152
+ # Create an instance of the class
153
+ exp = Legendarium(f"test", "Test experiment", "experiments")
154
+
155
+ # Create a parameter
156
+ exp.create_parameter("algorithm", "Greedy")
157
+ exp.create_parameter("max_distance", 100.0)
158
+
159
+ # Create a metric
160
+ exp.create_metric("reward", float, "Reward function", "points")
161
+ exp.create_metric("map", np.ndarray, "Mean map", "%")
162
+
163
+ for run in range(3):
164
+
165
+ # Write data
166
+ for i in range(100):
167
+ exp.write(run = run, step = i, reward = np.random.rand(), map = np.random.rand(100,100))
168
+
169
+ # Save the data
170
+ exp.save()
171
+
172
+ # Load the data
173
+ df = load_experiments("experiments")
174
+ print(df.head())
175
+
176
+ import seaborn as sns
177
+ import matplotlib.pyplot as plt
178
+
179
+ sns.lineplot(data = df, x = "step", y = "reward", hue = "run")
180
+ plt.show()
@@ -0,0 +1,128 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ def png_to_csv(name, delim=' '):
5
+ ''' Convert a binary image to a CSV file. '''
6
+ # Load the image
7
+ image = cv2.imread(f'Environment/maps/{name}.png', 0)
8
+
9
+ # Binarize the image
10
+ _, binary_image = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
11
+
12
+ # Convert the binary image to 0s and 1s
13
+ binary_image = np.where(binary_image > 0, 1, 0)
14
+
15
+ # Save the binary image as a CSV file
16
+ np.savetxt(f'Environment/maps/{name}.csv', binary_image, delimiter=delim, fmt='%d')
17
+
18
+ def csv_to_png(name, delim=' '):
19
+ ''' Convert a CSV file to a binary image. '''
20
+ # Load the CSV file
21
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim)
22
+
23
+ # Convert the binary image to 0s and 255s
24
+ binary_image = np.where(binary_image > 0, 255, 0)
25
+
26
+ # Save the binary image as a PNG file
27
+ cv2.imwrite(f'Environment/maps/{name}.png', binary_image)
28
+
29
+ def csv_to_npy(name, delim=' '):
30
+ ''' Convert a CSV file to a NumPy file. '''
31
+ if 'mask' in name or 'plantilla' in name or 'nodes' in name:
32
+ # Load the CSV file
33
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim)
34
+
35
+ # Save the binary image as a NumPy file
36
+ np.save(f'Environment/maps/{name}.npy', binary_image)
37
+ elif 'latlon' in name or 'grid' in name:
38
+ # There is a two component array in each cell #
39
+
40
+ # Load the CSV file
41
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim, dtype=str)
42
+ lat_lon_map = np.zeros((binary_image.shape[0], binary_image.shape[1], 2), dtype=np.float64)
43
+
44
+ # Convert the strings to tuples
45
+ for i in range(binary_image.shape[0]):
46
+ for j in range(binary_image.shape[1]):
47
+ lat = binary_image[i, j].split(',')[0]
48
+ lon = binary_image[i, j].split(',')[1]
49
+ lat_lon_map[i, j] = [float(lat), float(lon)]
50
+
51
+ # Save the binary image as a NumPy file
52
+ np.save(f'Environment/maps/{name}.npy', lat_lon_map)
53
+
54
+ def csv_downsize(name, delim=' ', factor=2, output_name=None):
55
+ ''' Downsize a CSV file. '''
56
+ # Load the CSV file
57
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim, dtype=str)
58
+
59
+ # Downsize the binary image
60
+ binary_image = binary_image[::factor, ::factor]
61
+
62
+ output_name1 = output_name.split('_')[0]
63
+ output_name2 = output_name.split('_')[1]
64
+
65
+ # Save the binary image as a CSV file
66
+ np.savetxt(f'Environment/maps/{output_name1}{binary_image.shape[0]}x{binary_image.shape[1]}{output_name2}.csv', binary_image, delimiter=delim, fmt='%s')
67
+
68
+ def csv_shrink(name, delim=' ', init_column=0, final_column=None, init_row=0, final_row=None, output_name=None):
69
+ ''' Shrink a CSV file. '''
70
+ # Load the CSV file
71
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim, dtype=str)
72
+
73
+ # Set the final column and row if they are None
74
+ if final_column is None:
75
+ final_column = binary_image.shape[1]
76
+ if final_row is None:
77
+ final_row = binary_image.shape[0]
78
+
79
+ # Shrink the binary image
80
+ binary_image = binary_image[init_row:final_row, init_column:final_column]
81
+
82
+ output_name1 = output_name.split('_')[0]
83
+ output_name2 = output_name.split('_')[1]
84
+
85
+ # Save the binary image as a CSV file
86
+ np.savetxt(f'Environment/maps/{output_name1}{binary_image.shape[0]}x{binary_image.shape[1]}{output_name2}.csv', binary_image, delimiter=delim, fmt='%s')
87
+
88
+ def get_output_name(name):
89
+ ''' Get the output name if the format is correct. '''
90
+ output_name = name
91
+ first_number_pos = None
92
+ last_number_pos = None
93
+ for i, c in enumerate(name):
94
+ if c.isdigit():
95
+ if first_number_pos is None:
96
+ first_number_pos = i
97
+ last_number_pos = i
98
+ if first_number_pos is not None and last_number_pos is not None:
99
+ output_name = name[:first_number_pos] + '_' + name[last_number_pos+1:]
100
+ else:
101
+ output_name = 'output_map'
102
+ return output_name
103
+
104
+ def invert_map(name, delim=' '):
105
+ ''' Invert a map. '''
106
+ # Load the CSV file
107
+ binary_image = np.loadtxt(f'Environment/maps/{name}.csv', delimiter=delim)
108
+
109
+ # Invert the binary image
110
+ binary_image = np.where(binary_image == 1, 0, 1)
111
+
112
+ # Save the binary image as a CSV file
113
+ np.savetxt(f'Environment/maps/{name}.csv', binary_image, delimiter=delim, fmt='%d')
114
+
115
+ if __name__ == '__main__':
116
+
117
+ # name = 'rawfiles/Alamillo95x216grid'
118
+ # delim = ';'
119
+
120
+ name = 'rawfiles/Alamillo95x216plantilla'
121
+ delim = ' '
122
+
123
+ # invert_map(name, delim)
124
+ # png_to_csv(name, delim)
125
+ # csv_to_png(name, delim)
126
+ # csv_to_npy(name, delim)
127
+ # csv_downsize(name, delim, factor=3, output_name=get_output_name(name))
128
+ # csv_shrink(name, delim, init_column=0, final_column=145, init_row=0, final_row=90, output_name=get_output_name(name))
@@ -0,0 +1,65 @@
1
+ import numpy as np
2
+ from scipy.ndimage import binary_dilation
3
+ import matplotlib.pyplot as plt
4
+
5
+ # NODOS
6
+ nodos_mask = np.load('Environment/maps/AlamilloAccess11x15mask.npy')
7
+ nodos_lat_lon = np.load('Environment/maps/AlamilloAccess11x15latlon.npy')
8
+
9
+ # "REALES"
10
+ real_mask = np.genfromtxt('Environment/maps/rawfiles/Alamillo95x216plantilla.csv', dtype=int, delimiter=' ')
11
+ raw_grid_csv = np.genfromtxt('Environment/maps/rawfiles/Alamillo95x216grid.csv', delimiter=';', dtype=str)
12
+ real_lat_long = np.zeros((*real_mask.shape, 2))
13
+ # Transform the map to a float for long and lat
14
+ for i in range(real_mask.shape[0]):
15
+ for j in range(real_mask.shape[1]):
16
+ real_lat_long[i, j, 0] = float(raw_grid_csv[i, j].split(',')[0])
17
+ real_lat_long[i, j, 1] = float(raw_grid_csv[i, j].split(',')[1])
18
+
19
+ latitudes = real_lat_long[:,:, 0]
20
+ longitudes = real_lat_long[:,:, 1]
21
+
22
+ navigables_latitudes = latitudes[real_mask == 1]
23
+ navigables_longitudes = longitudes[real_mask == 1]
24
+
25
+ # Comprobar si los puntos de navegación en el mapa real están en el mapa de nodos
26
+ # Para cada punto navegable (1) en base_matrix, obtener su latitud y longitud. Y comprobar si todos son alcanzables.
27
+ cont_unreach = 0
28
+ cont_reach = 0
29
+ non_reachable_points = []
30
+ reachable_points = []
31
+ for i in range(nodos_mask.shape[0]):
32
+ for j in range(nodos_mask.shape[1]):
33
+ if nodos_mask[i, j] == 1:
34
+ # Comprobar si está como navegable en el mapa de navegación
35
+ if nodos_lat_lon[i, j, 0] in navigables_latitudes and nodos_lat_lon[i, j, 1] in navigables_longitudes:
36
+ # Obtener los índices de la latitud y longitud en el mapa de navegación
37
+ lat_indexs = np.where(navigables_latitudes == nodos_lat_lon[i, j, 0])[0]
38
+ lon_indexs = np.where(navigables_longitudes == nodos_lat_lon[i, j, 1])[0]
39
+
40
+ # Comprobar si hay algún índice en común
41
+ if len(set(lat_indexs).intersection(set(lon_indexs))) == 0:
42
+ print(f'No alcanzable (no común): {nodos_lat_lon[i, j, 0]}, {nodos_lat_lon[i, j, 1]}')
43
+ cont_unreach += 1
44
+ non_reachable_points.append((i, j))
45
+ else:
46
+ cont_reach += 1
47
+ reachable_points.append((i, j))
48
+ else:
49
+ print(f'No alcanzable: {nodos_lat_lon[i, j, 0]}, {nodos_lat_lon[i, j, 1]}')
50
+ cont_unreach += 1
51
+ non_reachable_points.append((i, j))
52
+
53
+
54
+ if cont_unreach == 0:
55
+ print(f'Todos los puntos son alcanzables: {cont_reach}')
56
+ else:
57
+ print(f'{cont_unreach} puntos no son alcanzables de un total de {np.sum(nodos_mask)}')
58
+
59
+ # Pintar los puntos no alcanzables
60
+ plt.imshow(nodos_mask)
61
+ for point in non_reachable_points:
62
+ plt.scatter(point[1], point[0], c='r', s=10)
63
+ for point in reachable_points:
64
+ plt.scatter(point[1], point[0], c='g', s=10)
65
+ plt.show()
@@ -0,0 +1,3 @@
1
+ from aceti_maps import import_map
2
+
3
+ base_matrix, lat_lon_map = import_map("alamillo11x15")