geobox 2.1.0__py3-none-any.whl → 2.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. geobox/__init__.py +61 -63
  2. geobox/aio/__init__.py +61 -63
  3. geobox/aio/api.py +491 -574
  4. geobox/aio/apikey.py +263 -263
  5. geobox/aio/attachment.py +341 -339
  6. geobox/aio/base.py +261 -262
  7. geobox/aio/basemap.py +196 -196
  8. geobox/aio/dashboard.py +340 -342
  9. geobox/aio/feature.py +35 -35
  10. geobox/aio/field.py +315 -321
  11. geobox/aio/file.py +72 -72
  12. geobox/aio/layout.py +340 -341
  13. geobox/aio/log.py +23 -23
  14. geobox/aio/map.py +1033 -1034
  15. geobox/aio/model3d.py +415 -415
  16. geobox/aio/mosaic.py +696 -696
  17. geobox/aio/plan.py +314 -314
  18. geobox/aio/query.py +693 -693
  19. geobox/aio/raster.py +88 -454
  20. geobox/aio/{analysis.py → raster_analysis.py} +153 -170
  21. geobox/aio/route.py +4 -4
  22. geobox/aio/scene.py +340 -342
  23. geobox/aio/settings.py +18 -18
  24. geobox/aio/task.py +404 -402
  25. geobox/aio/tile3d.py +337 -339
  26. geobox/aio/tileset.py +102 -103
  27. geobox/aio/usage.py +52 -51
  28. geobox/aio/user.py +506 -507
  29. geobox/aio/vector_tool.py +1968 -0
  30. geobox/aio/vectorlayer.py +316 -414
  31. geobox/aio/version.py +272 -273
  32. geobox/aio/view.py +1019 -983
  33. geobox/aio/workflow.py +340 -341
  34. geobox/api.py +14 -98
  35. geobox/apikey.py +262 -262
  36. geobox/attachment.py +336 -337
  37. geobox/base.py +384 -384
  38. geobox/basemap.py +194 -194
  39. geobox/dashboard.py +339 -341
  40. geobox/enums.py +31 -1
  41. geobox/feature.py +31 -10
  42. geobox/field.py +320 -320
  43. geobox/file.py +4 -4
  44. geobox/layout.py +339 -340
  45. geobox/log.py +4 -4
  46. geobox/map.py +1031 -1032
  47. geobox/model3d.py +410 -410
  48. geobox/mosaic.py +696 -696
  49. geobox/plan.py +313 -313
  50. geobox/query.py +691 -691
  51. geobox/raster.py +5 -368
  52. geobox/{analysis.py → raster_analysis.py} +108 -128
  53. geobox/scene.py +341 -342
  54. geobox/settings.py +194 -194
  55. geobox/task.py +399 -400
  56. geobox/tile3d.py +337 -338
  57. geobox/tileset.py +4 -4
  58. geobox/usage.py +3 -3
  59. geobox/user.py +503 -503
  60. geobox/vector_tool.py +1968 -0
  61. geobox/vectorlayer.py +5 -110
  62. geobox/version.py +272 -272
  63. geobox/view.py +981 -981
  64. geobox/workflow.py +338 -339
  65. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/METADATA +15 -1
  66. geobox-2.2.1.dist-info/RECORD +72 -0
  67. geobox-2.1.0.dist-info/RECORD +0 -70
  68. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/WHEEL +0 -0
  69. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/licenses/LICENSE +0 -0
  70. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/top_level.txt +0 -0
geobox/map.py CHANGED
@@ -1,1033 +1,1032 @@
1
- from typing import Dict, List, Optional, Union, TYPE_CHECKING
2
- from urllib.parse import urljoin, urlencode
3
-
4
- from .base import Base
5
- from .utils import clean_data, join_url_params
6
- from .model3d import Model
7
- from .file import File
8
- from .feature import Feature
9
-
10
- if TYPE_CHECKING:
11
- from . import GeoboxClient
12
- from .user import User
13
- from .task import Task
14
- from .attachment import Attachment
15
- from .aio import AsyncGeoboxClient
16
- from .aio.map import Map as AsyncMap
17
-
18
-
19
- class Map(Base):
20
-
21
- BASE_ENDPOINT = 'maps/'
22
-
23
- def __init__(self,
24
- api: 'GeoboxClient',
25
- uuid: str,
26
- data: Optional[Dict] = {}):
27
- """
28
- Initialize a Map instance.
29
-
30
- Args:
31
- api (GeoboxClient): The GeoboxClient instance for making requests.
32
- name (str): The name of the map.
33
- uuid (str): The unique identifier for the map.
34
- data (Dict, optional): The data of the map.
35
- """
36
- self.map_layers = {
37
- 'layers': []
38
- }
39
- super().__init__(api, uuid=uuid, data=data)
40
-
41
-
42
- @classmethod
43
- def get_maps(cls, api: 'GeoboxClient', **kwargs) -> Union[List['Map'], int]:
44
- """
45
- Get list of maps with optional filtering and pagination.
46
-
47
- Args:
48
- api (GeoboxClient): The GeoboxClient instance for making requests.
49
-
50
- Keyword Args:
51
- q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
52
- search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
53
- search_fields (str): comma separated list of fields for searching.
54
- order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
55
- return_count (bool): Whether to return total count. default is False.
56
- skip (int): Number of items to skip. default is 0.
57
- limit (int): Number of items to return. default is 10.
58
- user_id (int): Specific user. privileges required.
59
- shared (bool): Whether to return shared maps. default is False.
60
-
61
- Returns:
62
- List[Map] | int: A list of Map instances or the total number of maps.
63
-
64
- Example:
65
- >>> from geobox import GeoboxClient
66
- >>> from geobox.map import Map
67
- >>> client = GeoboxClient()
68
- >>> maps = Map.get_maps(client, q="name LIKE '%My Map%'")
69
- or
70
- >>> maps = client.get_maps(q="name LIKE '%My Map%'")
71
- """
72
- params = {
73
- 'f': 'json',
74
- 'q': kwargs.get('q'),
75
- 'search': kwargs.get('search'),
76
- 'search_fields': kwargs.get('search_fields'),
77
- 'order_by': kwargs.get('order_by'),
78
- 'return_count': kwargs.get('return_count', False),
79
- 'skip': kwargs.get('skip', 0),
80
- 'limit': kwargs.get('limit', 10),
81
- 'user_id': kwargs.get('user_id'),
82
- 'shared': kwargs.get('shared', False)
83
- }
84
- return super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: Map(api, item['uuid'], item))
85
-
86
-
87
- @classmethod
88
- def create_map(cls,
89
- api: 'GeoboxClient',
90
- name: str,
91
- display_name: str = None,
92
- description: str = None,
93
- extent: List[float] = None,
94
- thumbnail: str = None,
95
- style: Dict = None,
96
- user_id: int = None) -> 'Map':
97
- """
98
- Create a new map.
99
-
100
- Args:
101
- api (GeoboxClient): The GeoboxClient instance for making requests.
102
- name (str): The name of the map.
103
- display_name (str, optional): The display name of the map.
104
- description (str, optional): The description of the map.
105
- extent (List[float], optional): The extent of the map.
106
- thumbnail (str, optional): The thumbnail of the map.
107
- style (Dict, optional): The style of the map.
108
- user_id (int, optional): Specific user. privileges required.
109
-
110
- Returns:
111
- Map: The newly created map instance.
112
-
113
- Raises:
114
- ValidationError: If the map data is invalid.
115
-
116
- Example:
117
- >>> from geobox import GeoboxClient
118
- >>> from geobox.map import Map
119
- >>> client = GeoboxClient()
120
- >>> map = Map.create_map(client, name="my_map", display_name="My Map", description="This is a description of my map", extent=[10, 20, 30, 40], thumbnail="https://example.com/thumbnail.png", style={"type": "style"})
121
- or
122
- >>> map = client.create_map(name="my_map", display_name="My Map", description="This is a description of my map", extent=[10, 20, 30, 40], thumbnail="https://example.com/thumbnail.png", style={"type": "style"})
123
- """
124
- data = {
125
- "name": name,
126
- "display_name": display_name,
127
- "description": description,
128
- "extent": extent,
129
- "thumbnail": thumbnail,
130
- "style": style,
131
- "user_id": user_id,
132
- }
133
- return super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: Map(api, item['uuid'], item))
134
-
135
-
136
- @classmethod
137
- def get_map(cls, api: 'GeoboxClient', uuid: str, user_id: int = None) -> 'Map':
138
- """
139
- Get a map by its UUID.
140
-
141
- Args:
142
- api (GeoboxClient): The GeoboxClient instance for making requests.
143
- uuid (str): The UUID of the map to get.
144
- user_id (int, optional): Specific user. privileges required.
145
-
146
- Returns:
147
- Map: The map object.
148
-
149
- Raises:
150
- NotFoundError: If the map with the specified UUID is not found.
151
-
152
- Example:
153
- >>> from geobox import GeoboxClient
154
- >>> from geobox.map import Map
155
- >>> client = GeoboxClient()
156
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
157
- or
158
- >>> map = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
159
- """
160
- params = {
161
- 'f': 'json',
162
- 'user_id': user_id,
163
- }
164
- return super()._get_detail(api, cls.BASE_ENDPOINT, uuid, params, factory_func=lambda api, item: Map(api, item['uuid'], item))
165
-
166
-
167
- @classmethod
168
- def get_map_by_name(cls, api: 'GeoboxClient', name: str, user_id: int = None) -> Union['Map', None]:
169
- """
170
- Get a map by name
171
-
172
- Args:
173
- api (GeoboxClient): The GeoboxClient instance for making requests.
174
- name (str): the name of the map to get
175
- user_id (int, optional): specific user. privileges required.
176
-
177
- Returns:
178
- Map | None: returns the map if a map matches the given name, else None
179
-
180
- Example:
181
- >>> from geobox import GeoboxClient
182
- >>> from geobox.map import Map
183
- >>> client = GeoboxClient()
184
- >>> map = Map.get_map_by_name(client, name='test')
185
- or
186
- >>> map = client.get_map_by_name(name='test')
187
- """
188
- maps = cls.get_maps(api, q=f"name = '{name}'", user_id=user_id)
189
- if maps and maps[0].name == name:
190
- return maps[0]
191
- else:
192
- return None
193
-
194
-
195
- def update(self, **kwargs) -> Dict:
196
- """
197
- Update the map.
198
-
199
- Keyword Args:
200
- name (str): The name of the map.
201
- display_name (str): The display name of the map.
202
- description (str): The description of the map.
203
- extent (List[float]): The extent of the map.
204
- thumbnail (str): The thumbnail of the map.
205
- style (Dict): The style of the map.
206
-
207
- Returns:
208
- Dict: The updated map data.
209
-
210
- Raises:
211
- ValidationError: If the map data is invalid.
212
-
213
- Example:
214
- >>> from geobox import GeoboxClient
215
- >>> from geobox.map import Map
216
- >>> client = GeoboxClient()
217
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
218
- >>> map.update(display_name="New Display Name")
219
- """
220
- data = {
221
- "name": kwargs.get('name'),
222
- "display_name": kwargs.get('display_name'),
223
- "description": kwargs.get('description'),
224
- "extent": kwargs.get('extent'),
225
- "thumbnail": kwargs.get('thumbnail'),
226
- "style": kwargs.get('style'),
227
- }
228
- return super()._update(self.endpoint, data)
229
-
230
-
231
- def delete(self) -> None:
232
- """
233
- Delete the map.
234
-
235
- Returns:
236
- None
237
-
238
- Example:
239
- >>> from geobox import GeoboxClient
240
- >>> from geobox.map import Map
241
- >>> client = GeoboxClient()
242
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
243
- >>> map.delete()
244
- """
245
- super().delete(self.endpoint)
246
-
247
-
248
- @property
249
- def style(self) -> Dict:
250
- """
251
- Get the style of the map.
252
-
253
- Returns:
254
- Dict: The style of the map.
255
-
256
- Example:
257
- >>> from geobox import GeoboxClient
258
- >>> from geobox.map import Map
259
- >>> client = GeoboxClient()
260
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
261
- >>> map.style
262
- """
263
- endpoint = urljoin(self.endpoint, 'style/')
264
- response = self.api.get(endpoint)
265
- return response
266
-
267
-
268
- @property
269
- def thumbnail(self) -> str:
270
- """
271
- Get the thumbnail URL of the map.
272
-
273
- Returns:
274
- str: The thumbnail of the map.
275
-
276
- Example:
277
- >>> from geobox import GeoboxClient
278
- >>> from geobox.map import Map
279
- >>> client = GeoboxClient()
280
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
281
- >>> map.thumbnail
282
- 'https://example.com/thumbnail.png'
283
- """
284
- return super().thumbnail()
285
-
286
-
287
- def set_readonly(self, readonly: bool) -> None:
288
- """
289
- Set the readonly status of the map.
290
-
291
- Args:
292
- readonly (bool): The readonly status of the map.
293
-
294
- Returns:
295
- None
296
-
297
- Example:
298
- >>> from geobox import GeoboxClient
299
- >>> from geobox.map import Map
300
- >>> client = GeoboxClient()
301
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
302
- >>> map.set_readonly(True)
303
- """
304
- data = clean_data({
305
- 'readonly': readonly
306
- })
307
- endpoint = urljoin(self.endpoint, 'setReadonly/')
308
- response = self.api.post(endpoint, data, is_json=False)
309
- self._update_properties(response)
310
-
311
-
312
- def set_multiuser(self, multiuser: bool) -> None:
313
- """
314
- Set the multiuser status of the map.
315
-
316
- Args:
317
- multiuser (bool): The multiuser status of the map.
318
-
319
- Returns:
320
- None
321
-
322
- Example:
323
- >>> from geobox import GeoboxClient
324
- >>> from geobox.map import Map
325
- >>> client = GeoboxClient()
326
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
327
- >>> map.set_multiuser(True)
328
- """
329
- data = clean_data({
330
- 'multiuser': multiuser
331
- })
332
- endpoint = urljoin(self.endpoint, 'setMultiuser/')
333
- response = self.api.post(endpoint, data, is_json=False)
334
- self._update_properties(response)
335
-
336
-
337
-
338
- def wmts(self, scale: int = None) -> str:
339
- """
340
- Get the WMTS URL of the map.
341
-
342
- Args:
343
- scale (int): The scale of the map. value are: 1, 2
344
-
345
- Returns:
346
- str: The WMTS URL of the map.
347
-
348
- Example:
349
- >>> from geobox import GeoboxClient
350
- >>> from geobox.map import Map
351
- >>> client = GeoboxClient()
352
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
353
- >>> map.wmts(scale=1)
354
- """
355
- endpoint = urljoin(self.api.base_url, f'{self.endpoint}wmts/')
356
- if scale:
357
- endpoint = f"{endpoint}?scale={scale}"
358
-
359
- if not self.api.access_token and self.api.apikey:
360
- endpoint = join_url_params(endpoint, {"apikey": self.api.apikey})
361
-
362
- return endpoint
363
-
364
-
365
- def share(self, users: List['User']) -> None:
366
- """
367
- Shares the map with specified users.
368
-
369
- Args:
370
- users (List[User]): The list of user objects to share the map with.
371
-
372
- Returns:
373
- None
374
-
375
- Example:
376
- >>> from geobox import GeoboxClient
377
- >>> from geobox.map import Map
378
- >>> client = GeoboxClient()
379
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
380
- >>> users = client.search_users(search='John')
381
- >>> map.share(users=users)
382
- """
383
- super()._share(self.endpoint, users)
384
-
385
-
386
- def unshare(self, users: List['User']) -> None:
387
- """
388
- Unshares the map with specified users.
389
-
390
- Args:
391
- users (List[User]): The list of user objects to unshare the map with.
392
-
393
- Returns:
394
- None
395
-
396
- Example:
397
- >>> from geobox import GeoboxClient
398
- >>> from geobox.map import Map
399
- >>> client = GeoboxClient()
400
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
401
- >>> users = client.search_users(search='John')
402
- >>> map.unshare(users=users)
403
- """
404
- super()._unshare(self.endpoint, users)
405
-
406
-
407
- def get_shared_users(self, search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
408
- """
409
- Retrieves the list of users the map is shared with.
410
-
411
- Args:
412
- search (str, optional): The search query.
413
- skip (int, optional): The number of users to skip.
414
- limit (int, optional): The maximum number of users to retrieve.
415
-
416
- Returns:
417
- List[User]: The list of shared users.
418
-
419
- Example:
420
- >>> from geobox import GeoboxClient
421
- >>> from geobox.map import Map
422
- >>> client = GeoboxClient()
423
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
424
- >>> map.get_shared_users(search='John', skip=0, limit=10)
425
- """
426
- params = {
427
- 'search': search,
428
- 'skip': skip,
429
- 'limit': limit
430
- }
431
- return super()._get_shared_users(self.endpoint, params)
432
-
433
-
434
- def seed_cache(self,
435
- from_zoom: int = None,
436
- to_zoom: int = None,
437
- extent: List[float] = None,
438
- workers: int = 1,
439
- user_id: int = None,
440
- scale: int = None) -> List['Task']:
441
- """
442
- Seed the cache of the map.
443
-
444
- Args:
445
- from_zoom (int, optional): The zoom level to start caching from.
446
- to_zoom (int, optional): The zoom level to stop caching at.
447
- extent (List[float], optional): The extent of the map.
448
- workers (int, optional): The number of workers to use. default is 1.
449
- user_id (int, optional): Specific user. privileges required.
450
- scale (int, optional): The scale of the map.
451
-
452
- Returns:
453
- List[Task]: The task instance of the cache seeding operation.
454
-
455
- Raises:
456
- ValueError: If the workers is not in [1, 2, 4, 8, 12, 16, 20, 24].
457
- ValueError: If the cache seeding fails.
458
-
459
- Example:
460
- >>> from geobox import GeoboxClient
461
- >>> from geobox.map import Map
462
- >>> client = GeoboxClient()
463
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
464
- >>> task = map.seed_cache(from_zoom=0, to_zoom=10, extent=[10, 20, 30, 40], workers=1, scale=1)
465
- """
466
- data = {
467
- 'from_zoom': from_zoom,
468
- 'to_zoom': to_zoom,
469
- 'extent': extent,
470
- 'workers': workers,
471
- 'user_id': user_id,
472
- 'scale': scale
473
- }
474
- return super()._seed_cache(self.endpoint, data)
475
-
476
-
477
- def update_cache(self,
478
- from_zoom: int = None,
479
- to_zoom: int = None,
480
- extent: List[float] = None,
481
- user_id: int = None,
482
- scale: int = None) -> List['Task']:
483
- """
484
- Update the cache of the map.
485
-
486
- Args:
487
- from_zoom (int, optional): The zoom level to start caching from.
488
- to_zoom (int, optional): The zoom level to stop caching at.
489
- extent (List[float], optional): The extent of the map.
490
- user_id (int, optional): Specific user. privileges required.
491
- scale (int, optional): The scale of the map.
492
-
493
- Returns:
494
- List[Task]: The task instance of the cache updating operation.
495
-
496
- Raises:
497
- ValueError: If the cache updating fails.
498
-
499
- Example:
500
- >>> from geobox import GeoboxClient
501
- >>> from geobox.map import Map
502
- >>> client = GeoboxClient()
503
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
504
- >>> map.update_cache(from_zoom=0, to_zoom=10, extent=[10, 20, 30, 40], scale=1)
505
- """
506
- data = {
507
- 'from_zoom': from_zoom,
508
- 'to_zoom': to_zoom,
509
- 'extent': extent,
510
- 'user_id': user_id,
511
- 'scale': scale
512
- }
513
- return super()._update_cache(self.endpoint, data)
514
-
515
-
516
- def clear_cache(self) -> None:
517
- """
518
- Clear the cache of the map.
519
-
520
- Returns:
521
- None
522
-
523
- Example:
524
- >>> from geobox import GeoboxClient
525
- >>> from geobox.map import Map
526
- >>> client = GeoboxClient()
527
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
528
- >>> map.clear_cache()
529
- """
530
- return super()._clear_cache(self.endpoint)
531
-
532
-
533
- @property
534
- def cache_size(self) -> int:
535
- """
536
- Get the size of the cache of the map.
537
-
538
- Returns:
539
- int: The size of the cache of the map.
540
-
541
- Example:
542
- >>> from geobox import GeoboxClient
543
- >>> from geobox.map import Map
544
- >>> client = GeoboxClient()
545
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
546
- >>> map.cache_size
547
- """
548
- return super()._cache_size(self.endpoint)
549
-
550
-
551
- @property
552
- def settings(self) -> Dict:
553
- """
554
- Get the settings of the map
555
-
556
- Returns:
557
- Dict: the settings of the map.
558
-
559
- Example:
560
- >>> from geobox import GeoboxClient
561
- >>> from geobox.map import Map
562
- >>> client = GeoboxClient()
563
- >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
564
- >>> map.settings
565
- """
566
- return self.json.get('settings', {
567
- 'general_settings': {},
568
- 'edit_settings': {},
569
- 'snap_settings': {},
570
- 'controls': [],
571
- 'search_settings': {},
572
- 'marker_settings': {},
573
- 'terrain_settings': {},
574
- 'grid_settings': {},
575
- 'view_settings': {},
576
- 'toc_settings': []
577
- })
578
-
579
-
580
- def update_settings(self, settings: Dict) -> Dict:
581
- """
582
- Update the settings
583
-
584
- settings (Dict): settings dictionary
585
-
586
- Returns:
587
- Dict: updated settings
588
-
589
- Example:
590
- >>> from geobox import GeoboxClient
591
- >>> client = GeoboxClient()
592
- >>> map1 = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
593
- >>> map2 = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
594
- >>> map1.update_settings(map2.settings)
595
- """
596
- return super()._set_settings(self.endpoint, settings)
597
-
598
-
599
- def set_settings(self, **kwargs) -> Dict:
600
- """
601
- Set the settings of the map using keywords
602
-
603
- Keyword Args:
604
- map_unit (str): 'latlng' | 'utm'.
605
- base_map (str): 'OSM' | 'google' | 'blank'.
606
- flash_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
607
- highlight_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
608
- selection_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
609
- selectable_layers (str): 'ALL' | null | Comma separated list of layers.
610
- calendar_type (str): The type of the calendar.
611
- edit_settings (dict): The settings of the edit.
612
- snap_tolerance (int): number of pixels for snap tolerance.
613
- snap_unit (str): pixels.
614
- snap_mode (str): 'both' | 'edge' | 'vertex'.
615
- snap_cache (int): number of total features for snap cache.
616
- controls (List[str]): The controls of the map.
617
- search_mode (str): 'both' | 'markers' | 'layers'.
618
- search_layers (str): 'ALL' | null | Comma separated list of layers.
619
- geosearch (bool): The geosearch of the map.
620
- remove_unused_tags (bool): The remove unused tags of the map.
621
- terrain_layer (str): The terrain layer of the map.
622
- exaggeration (int): The exaggeration of the terrain.
623
- enable_grid (bool): The enable grid of the map.
624
- grid_unit (str): The unit of the grid.
625
- grid_width (int): The width of the grid.
626
- grid_height (int): The height of the grid.
627
- grid_minzoom (int): The minzoom of the grid.
628
- grid_maxzoom (int): The maxzoom of the grid.
629
- bearing (int): The bearing of the map.
630
- pitch (int): The pitch of the map.
631
- center (List[float]): The center of the map.
632
- zoom (int): The zoom of the map.
633
- toc_settings (List): The settings of the toc.
634
- custom_basemaps (List[str]): The custom basemaps of the map.
635
- show_maptip_on (str): 'ALL' | null | Comma separated list of layers.
636
- snappable_layers (str): 'ALL' | null | Comma separated list of layers.
637
-
638
- Returns:
639
- Dict: The response of the API.
640
-
641
- Example:
642
- >>> from geobox import GeoboxClient
643
- >>> from geobox.map import Map
644
- >>> client = GeoboxClient()
645
- >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
646
- >>> map.set_settings(zoom=10)
647
- """
648
- general_settings = {'map_unit', 'base_map', 'flash_color', 'highlight_color',
649
- 'selection_color', 'selectable_layers', 'calendar_type', 'custom_basemaps', 'show_maptip_on'}
650
- edit_settings = {'editable_layers', 'target_layer'}
651
- snap_settings = {'snap_tolerance', 'snap_unit', 'snap_mode', 'snap_cache', 'snappable_layers'}
652
- search_settings = {'search_mode', 'search_layers', 'geosearch'}
653
- marker_settings = {'remove_unused_tags'}
654
- terrain_settings = {'terrain_layer', 'exaggeration'}
655
- grid_settings = {'enable_grid', 'grid_unit', 'grid_width', 'grid_height', 'grid_minzoom', 'grid_maxzoom'}
656
- view_settings = {'bearing', 'pitch', 'center', 'zoom'}
657
-
658
- settings = self.settings
659
-
660
- for key, value in kwargs.items():
661
- if key in general_settings:
662
- settings['general_settings'][key] = value
663
- elif key in edit_settings:
664
- settings['edit_settings'][key] = value
665
- elif key in snap_settings:
666
- settings['snap_settings'][key] = value
667
- elif key == 'controls':
668
- settings['controls'] = value
669
- elif key in search_settings:
670
- settings['search_settings'][key] = value
671
- elif key in marker_settings:
672
- settings['marker_settings'][key] = value
673
- elif key in terrain_settings:
674
- settings['terrain_settings'][key] = value
675
- elif key in grid_settings:
676
- settings['grid_settings'][key] = value
677
- elif key in view_settings:
678
- settings['view_settings'][key] = value
679
- elif key == 'toc_settings':
680
- settings['toc_settings'] = value
681
-
682
- return super()._set_settings(self.endpoint, settings)
683
-
684
-
685
- def get_markers(self) -> Dict:
686
- """
687
- Get the markers of the map.
688
-
689
- Returns:
690
- Dict: The markers of the map.
691
-
692
- Example:
693
- >>> from geobox import GeoboxClient
694
- >>> from geobox.map import Map
695
- >>> client = GeoboxClient()
696
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
697
- >>> map.get_markers()
698
- """
699
- endpoint = urljoin(self.endpoint, 'markers/')
700
- return self.api.get(endpoint)
701
-
702
-
703
- def set_markers(self, data: Dict) -> Dict:
704
- """
705
- Set the markers of the map.
706
-
707
- Args:
708
- data (dict): The data of the markers.
709
-
710
- Returns:
711
- Dict: The response of the API.
712
-
713
- Example:
714
- >>> from geobox import GeoboxClient
715
- >>> from geobox.map import Map
716
- >>> client = GeoboxClient()
717
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
718
- >>> data = {
719
- ... 'tags': {
720
- ... '#general': {
721
- ... 'color': '#ff0000',
722
- ... }
723
- ... },
724
- ... 'locations': [
725
- ... {
726
- ... 'id': 1,
727
- ... 'tag': '#general',
728
- ... 'name': 'test',
729
- ... 'geometry': [
730
- ... 51.13162784422988,
731
- ... 35.766603814763045
732
- ... ],
733
- ... 'description': 'string'
734
- ... }
735
- ... ]
736
- ... }
737
- >>> map.set_markers(data)
738
- """
739
- endpoint = urljoin(self.endpoint, 'markers/')
740
- response = self.api.put(endpoint, data)
741
- return response
742
-
743
-
744
- def get_models(self, json=False) -> Union[List['Model'], Dict]:
745
- """
746
- Get the map models.
747
-
748
- Args:
749
- json (bool, optional): If True, return the response as a dictionary.
750
-
751
- Returns:
752
- List[Model] | Dict: map models objects or the response.
753
-
754
- Example:
755
- >>> from geobox import GeoboxClient
756
- >>> from geobox.map import Map
757
- >>> client = GeoboxClient()
758
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
759
- >>> map.get_models(json=True)
760
- """
761
- endpoint = urljoin(self.endpoint, 'models/')
762
- response = self.api.get(endpoint)
763
- if not response or json:
764
- return response
765
- else:
766
- return [Model(self.api, model['obj'], model) for model in response['objects'] if response.get('objects')]
767
-
768
-
769
- def set_models(self, data: Dict) -> List['Model']:
770
- """
771
- Set multiple models on the map.
772
-
773
- Args:
774
- data (Dict): the data of the models and their location on the map. check the example for the data structure.
775
-
776
- Returns:
777
- List[Model]: the map models objects
778
-
779
- Example:
780
- >>> from geobox import GeoboxClient
781
- >>> from geobox.map inport Map
782
- >>> client = GeoboxClient()
783
- >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
784
- >>> data = {'objects': [
785
- ... {
786
- ... "name": "transmission_tower",
787
- ... "alias": None,
788
- ... "desc": None,
789
- ... "obj": "12345678-1234-5678-1234-567812345678",
790
- ... "loc": [53.1859045261684, 33.37762747390032, 0.0],
791
- ... "rotation": [0.0, 0.0, 0.0],
792
- ... "scale": 1.0,
793
- ... "min_zoom": 0,
794
- ... "max_zoom": 22
795
- ... }
796
- ... ]}
797
- >>> map.set_models(data)
798
- """
799
- endpoint = urljoin(self.endpoint, 'models/')
800
- response = self.api.put(endpoint, data)
801
- return [Model(self.api, model['obj'], model) for model in response['objects'] if response.get('objects')]
802
-
803
-
804
- def add_model(self,
805
- model: 'Model',
806
- location: List[float],
807
- rotation: List[float] = [0.0, 0.0, 0.0],
808
- scale: float = 1.0,
809
- min_zoom: int = 0,
810
- max_zoom: int = 22,
811
- alias: str = None,
812
- description: str = None) -> List['Model']:
813
- """
814
- Add a model the map.
815
-
816
- Args:
817
- model (Model): The model object.
818
- location (List[float]): location of the model on the map. a list with three float values.
819
- rotation (List[float], optional): rotation of the model on the map. a list with three float vlaues. default is [0.0, 0.0, 0.0].
820
- scale (float, optional): the scale of the model on the map.
821
- min_zoom (int, optional): minimum zoom level.
822
- max_zoom (int, optional): maximum zoom level.
823
- alias (str, optional): alias of the model on the map.
824
- description (str, optional): the description of the model on the map.
825
-
826
- Returns:
827
- List['Model']: The map model objects
828
-
829
- Example:
830
- >>> from geobox import GeoboxClient
831
- >>> from geobox.map import Map
832
- >>> client = GeoboxClient()
833
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
834
- >>> model = client.get_model(uuid="12345678-1234-5678-1234-567812345678")
835
- >>> map.add_model(model=model,
836
- ... location=[53.53, 33.33, 0.0],
837
- ... rotation=[0.0, 0.0, 0.0],
838
- ... scale=1.0,
839
- ... min_zoom=0,
840
- ... max_zoom=22,
841
- ... alias=None,
842
- ... description=None)
843
- """
844
- data = self.get_models(json=True)
845
- if data and data.get('objects') and isinstance(data['objects'], list):
846
- data.get('objects').append({
847
- 'name': model.name,
848
- 'alias': alias,
849
- 'desc': description,
850
- 'obj': model.uuid,
851
- 'loc': location,
852
- 'rotation': rotation,
853
- 'scale': scale,
854
- 'min_zoom': min_zoom,
855
- 'max_zoom': max_zoom
856
- })
857
- else:
858
- data = {'objects':[
859
- {
860
- 'name': model.name,
861
- 'alias': alias,
862
- 'desc': description,
863
- 'obj': model.uuid,
864
- 'loc': location,
865
- 'rotation': rotation,
866
- 'scale': scale,
867
- 'min_zoom': min_zoom,
868
- 'max_zoom': max_zoom
869
- }
870
- ]
871
- }
872
-
873
- endpoint = urljoin(self.endpoint, 'models/')
874
- response = self.api.put(endpoint, data)
875
- return [Model(self.api, model['obj'], model) for model in response['objects']]
876
-
877
-
878
- def image_tile_url(self, x: str = '{x}', y: str = '{y}', z: str = '{z}', format='.png') -> str:
879
- """
880
- Get map image tile url
881
-
882
- Returns:
883
- str: the image tile url
884
-
885
- Example:
886
- >>> from geobox import GeoboxClient
887
- >>> from geobox.map import Map
888
- >>> client = GeoboxClient()
889
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
890
- >>> map.image_tile_url()
891
- >>> map.image_tile_url(x=1, y=2, z=3, format='.pbf')
892
- """
893
- endpoint = f"{self.api.base_url}{self.endpoint}tiles/{z}/{x}/{y}{format}"
894
-
895
- if not self.api.access_token and self.api.apikey:
896
- endpoint = f'{endpoint}?apikey={self.api.apikey}'
897
-
898
- return endpoint
899
-
900
-
901
- def export_map_to_image(self, bbox: List, width: int, height: int) -> 'Task':
902
- """
903
- Export the map to image
904
-
905
- Args:
906
- bbox (List): e.g. [50.275, 35.1195, 51.4459, 36.0416]
907
- width (int): minimum: 10, maximum: 10000
908
- height (int): minimum: 10, maximum: 10000
909
-
910
- Returns:
911
- Task: the task object
912
-
913
- Example:
914
- >>> from geobox import GeoboxClient
915
- >>> from geobox.map import Map
916
- >>> client = GeoboxClient()
917
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
918
- >>> task = map.export_map_to_image(bbox=[50.275, 35.1195, 51.4459, 36.0416],
919
- ... width=1024,
920
- ... height=1024)
921
- """
922
- data = clean_data({
923
- 'uuid': self.uuid,
924
- 'bbox': bbox,
925
- 'width': width,
926
- 'height': height
927
- })
928
- query_string = urlencode(data)
929
- endpoint = urljoin(self.endpoint, 'export/')
930
- endpoint = f"{endpoint}?{query_string}"
931
- response = self.api.post(endpoint)
932
- return self.api.get_task(response['task_id'])
933
-
934
-
935
- def get_attachments(self, **kwargs) -> List['Attachment']:
936
- """
937
- Get the resouces attachments
938
-
939
- Keyword Args:
940
- element_id (str): the id of the element with attachment.
941
- search (str): search term for keyword-based searching among all textual fields.
942
- order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
943
- skip (int): Number of items to skip. default is 0.
944
- limit (int): Number of items to return. default is 10.
945
- return_count (bool): Whether to return total count. default is False.
946
-
947
- Returns:
948
- List[Attachment] | int: A list of attachments instances or the total number of attachments.
949
-
950
- Raises:
951
- TypeError: if the resource type is not supported
952
-
953
- Example:
954
- >>> from geobox import GeoboxClient
955
- >>> from geobox.map import Map
956
- >>> client = GeoboxClient()
957
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
958
- >>> map.get_attachments()
959
- """
960
- from .attachment import Attachment
961
-
962
- return Attachment.get_attachments(self.api, resource=self, **kwargs)
963
-
964
-
965
- def create_attachment(self,
966
- name: str,
967
- loc_x: int,
968
- loc_y: int,
969
- file: 'File',
970
- feature: 'Feature' = None,
971
- display_name: str = None,
972
- description: str = None) -> 'Attachment':
973
- """
974
- Create a new Attachment.
975
-
976
- Args:
977
- name (str): The name of the scene.
978
- loc_x (int): x parameter of the attachment location.
979
- loc_y (int): y parameter of the attachment location.
980
- file (File): the file object.
981
- feature (Feature, optional): the feature object.
982
- display_name (str, optional): The display name of the scene.
983
- description (str, optional): The description of the scene.
984
-
985
- Returns:
986
- Attachment: The newly created Attachment instance.
987
-
988
- Raises:
989
- ValidationError: If the Attachment data is invalid.
990
-
991
- Example:
992
- >>> from geobox import GeoboxClient
993
- >>> from geobox.map import Map
994
- >>> client = GeoboxClient()
995
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
996
- >>> file = client.get_files()[0]
997
- >>> map.create_attachment(name='test', loc_x=10, loc_y=10, file=file)
998
- """
999
- from .attachment import Attachment
1000
-
1001
- return Attachment.create_attachment(self.api,
1002
- name=name,
1003
- loc_x=loc_x,
1004
- loc_y=loc_y,
1005
- resource=self,
1006
- file=file,
1007
- feature=feature,
1008
- display_name=display_name,
1009
- description=description)
1010
-
1011
-
1012
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncMap':
1013
- """
1014
- Switch to async version of the map instance to have access to the async methods
1015
-
1016
- Args:
1017
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
1018
-
1019
- Returns:
1020
- geobox.aio.map.Map: the async instance of the map.
1021
-
1022
- Example:
1023
- >>> from geobox import Geoboxclient
1024
- >>> from geobox.aio import AsyncGeoboxClient
1025
- >>> from geobox.map import Map
1026
- >>> client = GeoboxClient()
1027
- >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
1028
- >>> async with AsyncGeoboxClient() as async_client:
1029
- >>> async_map = map.to_async(async_client)
1030
- """
1031
- from .aio.map import Map as AsyncMap
1032
-
1
+ from typing import Dict, List, Optional, Union, TYPE_CHECKING
2
+ from urllib.parse import urljoin, urlencode
3
+
4
+ from .base import Base
5
+ from .utils import clean_data, join_url_params
6
+ from .model3d import Model
7
+ from .file import File
8
+ from .feature import Feature
9
+
10
+ if TYPE_CHECKING:
11
+ from . import GeoboxClient
12
+ from .user import User
13
+ from .task import Task
14
+ from .attachment import Attachment
15
+ from .aio import AsyncGeoboxClient
16
+ from .aio.map import Map as AsyncMap
17
+
18
+
19
+ class Map(Base):
20
+
21
+ BASE_ENDPOINT = 'maps/'
22
+
23
+ def __init__(self,
24
+ api: 'GeoboxClient',
25
+ uuid: str,
26
+ data: Optional[Dict] = {}):
27
+ """
28
+ Initialize a Map instance.
29
+
30
+ Args:
31
+ api (GeoboxClient): The GeoboxClient instance for making requests.
32
+ name (str): The name of the map.
33
+ uuid (str): The unique identifier for the map.
34
+ data (Dict, optional): The data of the map.
35
+ """
36
+ self.map_layers = {
37
+ 'layers': []
38
+ }
39
+ super().__init__(api, uuid=uuid, data=data)
40
+
41
+
42
+ @classmethod
43
+ def get_maps(cls, api: 'GeoboxClient', **kwargs) -> Union[List['Map'], int]:
44
+ """
45
+ Get list of maps with optional filtering and pagination.
46
+
47
+ Args:
48
+ api (GeoboxClient): The GeoboxClient instance for making requests.
49
+
50
+ Keyword Args:
51
+ q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
52
+ search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
53
+ search_fields (str): comma separated list of fields for searching.
54
+ order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
55
+ return_count (bool): Whether to return total count. default is False.
56
+ skip (int): Number of items to skip. default is 0.
57
+ limit (int): Number of items to return. default is 10.
58
+ user_id (int): Specific user. privileges required.
59
+ shared (bool): Whether to return shared maps. default is False.
60
+
61
+ Returns:
62
+ List[Map] | int: A list of Map instances or the total number of maps.
63
+
64
+ Example:
65
+ >>> from geobox import GeoboxClient
66
+ >>> from geobox.map import Map
67
+ >>> client = GeoboxClient()
68
+ >>> maps = Map.get_maps(client, q="name LIKE '%My Map%'")
69
+ or
70
+ >>> maps = client.get_maps(q="name LIKE '%My Map%'")
71
+ """
72
+ params = {
73
+ 'f': 'json',
74
+ 'q': kwargs.get('q'),
75
+ 'search': kwargs.get('search'),
76
+ 'search_fields': kwargs.get('search_fields'),
77
+ 'order_by': kwargs.get('order_by'),
78
+ 'return_count': kwargs.get('return_count', False),
79
+ 'skip': kwargs.get('skip', 0),
80
+ 'limit': kwargs.get('limit', 10),
81
+ 'user_id': kwargs.get('user_id'),
82
+ 'shared': kwargs.get('shared', False)
83
+ }
84
+ return super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: Map(api, item['uuid'], item))
85
+
86
+
87
+ @classmethod
88
+ def create_map(cls,
89
+ api: 'GeoboxClient',
90
+ name: str,
91
+ display_name: str = None,
92
+ description: str = None,
93
+ extent: List[float] = None,
94
+ thumbnail: str = None,
95
+ style: Dict = None,
96
+ user_id: int = None) -> 'Map':
97
+ """
98
+ Create a new map.
99
+
100
+ Args:
101
+ api (GeoboxClient): The GeoboxClient instance for making requests.
102
+ name (str): The name of the map.
103
+ display_name (str, optional): The display name of the map.
104
+ description (str, optional): The description of the map.
105
+ extent (List[float], optional): The extent of the map.
106
+ thumbnail (str, optional): The thumbnail of the map.
107
+ style (Dict, optional): The style of the map.
108
+ user_id (int, optional): Specific user. privileges required.
109
+
110
+ Returns:
111
+ Map: The newly created map instance.
112
+
113
+ Raises:
114
+ ValidationError: If the map data is invalid.
115
+
116
+ Example:
117
+ >>> from geobox import GeoboxClient
118
+ >>> from geobox.map import Map
119
+ >>> client = GeoboxClient()
120
+ >>> map = Map.create_map(client, name="my_map", display_name="My Map", description="This is a description of my map", extent=[10, 20, 30, 40], thumbnail="https://example.com/thumbnail.png", style={"type": "style"})
121
+ or
122
+ >>> map = client.create_map(name="my_map", display_name="My Map", description="This is a description of my map", extent=[10, 20, 30, 40], thumbnail="https://example.com/thumbnail.png", style={"type": "style"})
123
+ """
124
+ data = {
125
+ "name": name,
126
+ "display_name": display_name,
127
+ "description": description,
128
+ "extent": extent,
129
+ "thumbnail": thumbnail,
130
+ "style": style,
131
+ "user_id": user_id,
132
+ }
133
+ return super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: Map(api, item['uuid'], item))
134
+
135
+
136
+ @classmethod
137
+ def get_map(cls, api: 'GeoboxClient', uuid: str, user_id: int = None) -> 'Map':
138
+ """
139
+ Get a map by its UUID.
140
+
141
+ Args:
142
+ api (GeoboxClient): The GeoboxClient instance for making requests.
143
+ uuid (str): The UUID of the map to get.
144
+ user_id (int, optional): Specific user. privileges required.
145
+
146
+ Returns:
147
+ Map: The map object.
148
+
149
+ Raises:
150
+ NotFoundError: If the map with the specified UUID is not found.
151
+
152
+ Example:
153
+ >>> from geobox import GeoboxClient
154
+ >>> from geobox.map import Map
155
+ >>> client = GeoboxClient()
156
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
157
+ or
158
+ >>> map = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
159
+ """
160
+ params = {
161
+ 'f': 'json',
162
+ 'user_id': user_id,
163
+ }
164
+ return super()._get_detail(api, cls.BASE_ENDPOINT, uuid, params, factory_func=lambda api, item: Map(api, item['uuid'], item))
165
+
166
+
167
+ @classmethod
168
+ def get_map_by_name(cls, api: 'GeoboxClient', name: str, user_id: int = None) -> Union['Map', None]:
169
+ """
170
+ Get a map by name
171
+
172
+ Args:
173
+ api (GeoboxClient): The GeoboxClient instance for making requests.
174
+ name (str): the name of the map to get
175
+ user_id (int, optional): specific user. privileges required.
176
+
177
+ Returns:
178
+ Map | None: returns the map if a map matches the given name, else None
179
+
180
+ Example:
181
+ >>> from geobox import GeoboxClient
182
+ >>> from geobox.map import Map
183
+ >>> client = GeoboxClient()
184
+ >>> map = Map.get_map_by_name(client, name='test')
185
+ or
186
+ >>> map = client.get_map_by_name(name='test')
187
+ """
188
+ maps = cls.get_maps(api, q=f"name = '{name}'", user_id=user_id)
189
+ if maps and maps[0].name == name:
190
+ return maps[0]
191
+ else:
192
+ return None
193
+
194
+
195
+ def update(self, **kwargs) -> Dict:
196
+ """
197
+ Update the map.
198
+
199
+ Keyword Args:
200
+ name (str): The name of the map.
201
+ display_name (str): The display name of the map.
202
+ description (str): The description of the map.
203
+ extent (List[float]): The extent of the map.
204
+ thumbnail (str): The thumbnail of the map.
205
+ style (Dict): The style of the map.
206
+
207
+ Returns:
208
+ Dict: The updated map data.
209
+
210
+ Raises:
211
+ ValidationError: If the map data is invalid.
212
+
213
+ Example:
214
+ >>> from geobox import GeoboxClient
215
+ >>> from geobox.map import Map
216
+ >>> client = GeoboxClient()
217
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
218
+ >>> map.update(display_name="New Display Name")
219
+ """
220
+ data = {
221
+ "name": kwargs.get('name'),
222
+ "display_name": kwargs.get('display_name'),
223
+ "description": kwargs.get('description'),
224
+ "extent": kwargs.get('extent'),
225
+ "thumbnail": kwargs.get('thumbnail'),
226
+ "style": kwargs.get('style'),
227
+ }
228
+ return super()._update(self.endpoint, data)
229
+
230
+
231
+ def delete(self) -> None:
232
+ """
233
+ Delete the map.
234
+
235
+ Returns:
236
+ None
237
+
238
+ Example:
239
+ >>> from geobox import GeoboxClient
240
+ >>> from geobox.map import Map
241
+ >>> client = GeoboxClient()
242
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
243
+ >>> map.delete()
244
+ """
245
+ super()._delete(self.endpoint)
246
+
247
+
248
+ @property
249
+ def style(self) -> Dict:
250
+ """
251
+ Get the style of the map.
252
+
253
+ Returns:
254
+ Dict: The style of the map.
255
+
256
+ Example:
257
+ >>> from geobox import GeoboxClient
258
+ >>> from geobox.map import Map
259
+ >>> client = GeoboxClient()
260
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
261
+ >>> map.style
262
+ """
263
+ endpoint = urljoin(self.endpoint, 'style/')
264
+ response = self.api.get(endpoint)
265
+ return response
266
+
267
+
268
+ @property
269
+ def thumbnail(self) -> str:
270
+ """
271
+ Get the thumbnail URL of the map.
272
+
273
+ Returns:
274
+ str: The thumbnail of the map.
275
+
276
+ Example:
277
+ >>> from geobox import GeoboxClient
278
+ >>> from geobox.map import Map
279
+ >>> client = GeoboxClient()
280
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
281
+ >>> map.thumbnail
282
+ """
283
+ return super()._thumbnail()
284
+
285
+
286
+ def set_readonly(self, readonly: bool) -> None:
287
+ """
288
+ Set the readonly status of the map.
289
+
290
+ Args:
291
+ readonly (bool): The readonly status of the map.
292
+
293
+ Returns:
294
+ None
295
+
296
+ Example:
297
+ >>> from geobox import GeoboxClient
298
+ >>> from geobox.map import Map
299
+ >>> client = GeoboxClient()
300
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
301
+ >>> map.set_readonly(True)
302
+ """
303
+ data = clean_data({
304
+ 'readonly': readonly
305
+ })
306
+ endpoint = urljoin(self.endpoint, 'setReadonly/')
307
+ response = self.api.post(endpoint, data, is_json=False)
308
+ self._update_properties(response)
309
+
310
+
311
+ def set_multiuser(self, multiuser: bool) -> None:
312
+ """
313
+ Set the multiuser status of the map.
314
+
315
+ Args:
316
+ multiuser (bool): The multiuser status of the map.
317
+
318
+ Returns:
319
+ None
320
+
321
+ Example:
322
+ >>> from geobox import GeoboxClient
323
+ >>> from geobox.map import Map
324
+ >>> client = GeoboxClient()
325
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
326
+ >>> map.set_multiuser(True)
327
+ """
328
+ data = clean_data({
329
+ 'multiuser': multiuser
330
+ })
331
+ endpoint = urljoin(self.endpoint, 'setMultiuser/')
332
+ response = self.api.post(endpoint, data, is_json=False)
333
+ self._update_properties(response)
334
+
335
+
336
+
337
+ def wmts(self, scale: int = None) -> str:
338
+ """
339
+ Get the WMTS URL of the map.
340
+
341
+ Args:
342
+ scale (int): The scale of the map. value are: 1, 2
343
+
344
+ Returns:
345
+ str: The WMTS URL of the map.
346
+
347
+ Example:
348
+ >>> from geobox import GeoboxClient
349
+ >>> from geobox.map import Map
350
+ >>> client = GeoboxClient()
351
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
352
+ >>> map.wmts(scale=1)
353
+ """
354
+ endpoint = urljoin(self.api.base_url, f'{self.endpoint}wmts/')
355
+ if scale:
356
+ endpoint = f"{endpoint}?scale={scale}"
357
+
358
+ if not self.api.access_token and self.api.apikey:
359
+ endpoint = join_url_params(endpoint, {"apikey": self.api.apikey})
360
+
361
+ return endpoint
362
+
363
+
364
+ def share(self, users: List['User']) -> None:
365
+ """
366
+ Shares the map with specified users.
367
+
368
+ Args:
369
+ users (List[User]): The list of user objects to share the map with.
370
+
371
+ Returns:
372
+ None
373
+
374
+ Example:
375
+ >>> from geobox import GeoboxClient
376
+ >>> from geobox.map import Map
377
+ >>> client = GeoboxClient()
378
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
379
+ >>> users = client.search_users(search='John')
380
+ >>> map.share(users=users)
381
+ """
382
+ super()._share(self.endpoint, users)
383
+
384
+
385
+ def unshare(self, users: List['User']) -> None:
386
+ """
387
+ Unshares the map with specified users.
388
+
389
+ Args:
390
+ users (List[User]): The list of user objects to unshare the map with.
391
+
392
+ Returns:
393
+ None
394
+
395
+ Example:
396
+ >>> from geobox import GeoboxClient
397
+ >>> from geobox.map import Map
398
+ >>> client = GeoboxClient()
399
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
400
+ >>> users = client.search_users(search='John')
401
+ >>> map.unshare(users=users)
402
+ """
403
+ super()._unshare(self.endpoint, users)
404
+
405
+
406
+ def get_shared_users(self, search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
407
+ """
408
+ Retrieves the list of users the map is shared with.
409
+
410
+ Args:
411
+ search (str, optional): The search query.
412
+ skip (int, optional): The number of users to skip.
413
+ limit (int, optional): The maximum number of users to retrieve.
414
+
415
+ Returns:
416
+ List[User]: The list of shared users.
417
+
418
+ Example:
419
+ >>> from geobox import GeoboxClient
420
+ >>> from geobox.map import Map
421
+ >>> client = GeoboxClient()
422
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
423
+ >>> map.get_shared_users(search='John', skip=0, limit=10)
424
+ """
425
+ params = {
426
+ 'search': search,
427
+ 'skip': skip,
428
+ 'limit': limit
429
+ }
430
+ return super()._get_shared_users(self.endpoint, params)
431
+
432
+
433
+ def seed_cache(self,
434
+ from_zoom: int = None,
435
+ to_zoom: int = None,
436
+ extent: List[float] = None,
437
+ workers: int = 1,
438
+ user_id: int = None,
439
+ scale: int = None) -> List['Task']:
440
+ """
441
+ Seed the cache of the map.
442
+
443
+ Args:
444
+ from_zoom (int, optional): The zoom level to start caching from.
445
+ to_zoom (int, optional): The zoom level to stop caching at.
446
+ extent (List[float], optional): The extent of the map.
447
+ workers (int, optional): The number of workers to use. default is 1.
448
+ user_id (int, optional): Specific user. privileges required.
449
+ scale (int, optional): The scale of the map.
450
+
451
+ Returns:
452
+ List[Task]: The task instance of the cache seeding operation.
453
+
454
+ Raises:
455
+ ValueError: If the workers is not in [1, 2, 4, 8, 12, 16, 20, 24].
456
+ ValueError: If the cache seeding fails.
457
+
458
+ Example:
459
+ >>> from geobox import GeoboxClient
460
+ >>> from geobox.map import Map
461
+ >>> client = GeoboxClient()
462
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
463
+ >>> task = map.seed_cache(from_zoom=0, to_zoom=10, extent=[10, 20, 30, 40], workers=1, scale=1)
464
+ """
465
+ data = {
466
+ 'from_zoom': from_zoom,
467
+ 'to_zoom': to_zoom,
468
+ 'extent': extent,
469
+ 'workers': workers,
470
+ 'user_id': user_id,
471
+ 'scale': scale
472
+ }
473
+ return super()._seed_cache(self.endpoint, data)
474
+
475
+
476
+ def update_cache(self,
477
+ from_zoom: int = None,
478
+ to_zoom: int = None,
479
+ extent: List[float] = None,
480
+ user_id: int = None,
481
+ scale: int = None) -> List['Task']:
482
+ """
483
+ Update the cache of the map.
484
+
485
+ Args:
486
+ from_zoom (int, optional): The zoom level to start caching from.
487
+ to_zoom (int, optional): The zoom level to stop caching at.
488
+ extent (List[float], optional): The extent of the map.
489
+ user_id (int, optional): Specific user. privileges required.
490
+ scale (int, optional): The scale of the map.
491
+
492
+ Returns:
493
+ List[Task]: The task instance of the cache updating operation.
494
+
495
+ Raises:
496
+ ValueError: If the cache updating fails.
497
+
498
+ Example:
499
+ >>> from geobox import GeoboxClient
500
+ >>> from geobox.map import Map
501
+ >>> client = GeoboxClient()
502
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
503
+ >>> map.update_cache(from_zoom=0, to_zoom=10, extent=[10, 20, 30, 40], scale=1)
504
+ """
505
+ data = {
506
+ 'from_zoom': from_zoom,
507
+ 'to_zoom': to_zoom,
508
+ 'extent': extent,
509
+ 'user_id': user_id,
510
+ 'scale': scale
511
+ }
512
+ return super()._update_cache(self.endpoint, data)
513
+
514
+
515
+ def clear_cache(self) -> None:
516
+ """
517
+ Clear the cache of the map.
518
+
519
+ Returns:
520
+ None
521
+
522
+ Example:
523
+ >>> from geobox import GeoboxClient
524
+ >>> from geobox.map import Map
525
+ >>> client = GeoboxClient()
526
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
527
+ >>> map.clear_cache()
528
+ """
529
+ return super()._clear_cache(self.endpoint)
530
+
531
+
532
+ @property
533
+ def cache_size(self) -> int:
534
+ """
535
+ Get the size of the cache of the map.
536
+
537
+ Returns:
538
+ int: The size of the cache of the map.
539
+
540
+ Example:
541
+ >>> from geobox import GeoboxClient
542
+ >>> from geobox.map import Map
543
+ >>> client = GeoboxClient()
544
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
545
+ >>> map.cache_size
546
+ """
547
+ return super()._cache_size(self.endpoint)
548
+
549
+
550
+ @property
551
+ def settings(self) -> Dict:
552
+ """
553
+ Get the settings of the map
554
+
555
+ Returns:
556
+ Dict: the settings of the map.
557
+
558
+ Example:
559
+ >>> from geobox import GeoboxClient
560
+ >>> from geobox.map import Map
561
+ >>> client = GeoboxClient()
562
+ >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
563
+ >>> map.settings
564
+ """
565
+ return self.json.get('settings', {
566
+ 'general_settings': {},
567
+ 'edit_settings': {},
568
+ 'snap_settings': {},
569
+ 'controls': [],
570
+ 'search_settings': {},
571
+ 'marker_settings': {},
572
+ 'terrain_settings': {},
573
+ 'grid_settings': {},
574
+ 'view_settings': {},
575
+ 'toc_settings': []
576
+ })
577
+
578
+
579
+ def update_settings(self, settings: Dict) -> Dict:
580
+ """
581
+ Update the settings
582
+
583
+ settings (Dict): settings dictionary
584
+
585
+ Returns:
586
+ Dict: updated settings
587
+
588
+ Example:
589
+ >>> from geobox import GeoboxClient
590
+ >>> client = GeoboxClient()
591
+ >>> map1 = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
592
+ >>> map2 = client.get_map(uuid="12345678-1234-5678-1234-567812345678")
593
+ >>> map1.update_settings(map2.settings)
594
+ """
595
+ return super()._set_settings(self.endpoint, settings)
596
+
597
+
598
+ def set_settings(self, **kwargs) -> Dict:
599
+ """
600
+ Set the settings of the map using keywords
601
+
602
+ Keyword Args:
603
+ map_unit (str): 'latlng' | 'utm'.
604
+ base_map (str): 'OSM' | 'google' | 'blank'.
605
+ flash_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
606
+ highlight_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
607
+ selection_color (str): 'rgb(255,0,0)' (rgb color or rgba color or hex color ).
608
+ selectable_layers (str): 'ALL' | null | Comma separated list of layers.
609
+ calendar_type (str): The type of the calendar.
610
+ edit_settings (dict): The settings of the edit.
611
+ snap_tolerance (int): number of pixels for snap tolerance.
612
+ snap_unit (str): pixels.
613
+ snap_mode (str): 'both' | 'edge' | 'vertex'.
614
+ snap_cache (int): number of total features for snap cache.
615
+ controls (List[str]): The controls of the map.
616
+ search_mode (str): 'both' | 'markers' | 'layers'.
617
+ search_layers (str): 'ALL' | null | Comma separated list of layers.
618
+ geosearch (bool): The geosearch of the map.
619
+ remove_unused_tags (bool): The remove unused tags of the map.
620
+ terrain_layer (str): The terrain layer of the map.
621
+ exaggeration (int): The exaggeration of the terrain.
622
+ enable_grid (bool): The enable grid of the map.
623
+ grid_unit (str): The unit of the grid.
624
+ grid_width (int): The width of the grid.
625
+ grid_height (int): The height of the grid.
626
+ grid_minzoom (int): The minzoom of the grid.
627
+ grid_maxzoom (int): The maxzoom of the grid.
628
+ bearing (int): The bearing of the map.
629
+ pitch (int): The pitch of the map.
630
+ center (List[float]): The center of the map.
631
+ zoom (int): The zoom of the map.
632
+ toc_settings (List): The settings of the toc.
633
+ custom_basemaps (List[str]): The custom basemaps of the map.
634
+ show_maptip_on (str): 'ALL' | null | Comma separated list of layers.
635
+ snappable_layers (str): 'ALL' | null | Comma separated list of layers.
636
+
637
+ Returns:
638
+ Dict: The response of the API.
639
+
640
+ Example:
641
+ >>> from geobox import GeoboxClient
642
+ >>> from geobox.map import Map
643
+ >>> client = GeoboxClient()
644
+ >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
645
+ >>> map.set_settings(zoom=10)
646
+ """
647
+ general_settings = {'map_unit', 'base_map', 'flash_color', 'highlight_color',
648
+ 'selection_color', 'selectable_layers', 'calendar_type', 'custom_basemaps', 'show_maptip_on'}
649
+ edit_settings = {'editable_layers', 'target_layer'}
650
+ snap_settings = {'snap_tolerance', 'snap_unit', 'snap_mode', 'snap_cache', 'snappable_layers'}
651
+ search_settings = {'search_mode', 'search_layers', 'geosearch'}
652
+ marker_settings = {'remove_unused_tags'}
653
+ terrain_settings = {'terrain_layer', 'exaggeration'}
654
+ grid_settings = {'enable_grid', 'grid_unit', 'grid_width', 'grid_height', 'grid_minzoom', 'grid_maxzoom'}
655
+ view_settings = {'bearing', 'pitch', 'center', 'zoom'}
656
+
657
+ settings = self.settings
658
+
659
+ for key, value in kwargs.items():
660
+ if key in general_settings:
661
+ settings['general_settings'][key] = value
662
+ elif key in edit_settings:
663
+ settings['edit_settings'][key] = value
664
+ elif key in snap_settings:
665
+ settings['snap_settings'][key] = value
666
+ elif key == 'controls':
667
+ settings['controls'] = value
668
+ elif key in search_settings:
669
+ settings['search_settings'][key] = value
670
+ elif key in marker_settings:
671
+ settings['marker_settings'][key] = value
672
+ elif key in terrain_settings:
673
+ settings['terrain_settings'][key] = value
674
+ elif key in grid_settings:
675
+ settings['grid_settings'][key] = value
676
+ elif key in view_settings:
677
+ settings['view_settings'][key] = value
678
+ elif key == 'toc_settings':
679
+ settings['toc_settings'] = value
680
+
681
+ return super()._set_settings(self.endpoint, settings)
682
+
683
+
684
+ def get_markers(self) -> Dict:
685
+ """
686
+ Get the markers of the map.
687
+
688
+ Returns:
689
+ Dict: The markers of the map.
690
+
691
+ Example:
692
+ >>> from geobox import GeoboxClient
693
+ >>> from geobox.map import Map
694
+ >>> client = GeoboxClient()
695
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
696
+ >>> map.get_markers()
697
+ """
698
+ endpoint = urljoin(self.endpoint, 'markers/')
699
+ return self.api.get(endpoint)
700
+
701
+
702
+ def set_markers(self, data: Dict) -> Dict:
703
+ """
704
+ Set the markers of the map.
705
+
706
+ Args:
707
+ data (dict): The data of the markers.
708
+
709
+ Returns:
710
+ Dict: The response of the API.
711
+
712
+ Example:
713
+ >>> from geobox import GeoboxClient
714
+ >>> from geobox.map import Map
715
+ >>> client = GeoboxClient()
716
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
717
+ >>> data = {
718
+ ... 'tags': {
719
+ ... '#general': {
720
+ ... 'color': '#ff0000',
721
+ ... }
722
+ ... },
723
+ ... 'locations': [
724
+ ... {
725
+ ... 'id': 1,
726
+ ... 'tag': '#general',
727
+ ... 'name': 'test',
728
+ ... 'geometry': [
729
+ ... 51.13162784422988,
730
+ ... 35.766603814763045
731
+ ... ],
732
+ ... 'description': 'string'
733
+ ... }
734
+ ... ]
735
+ ... }
736
+ >>> map.set_markers(data)
737
+ """
738
+ endpoint = urljoin(self.endpoint, 'markers/')
739
+ response = self.api.put(endpoint, data)
740
+ return response
741
+
742
+
743
+ def get_models(self, json=False) -> Union[List['Model'], Dict]:
744
+ """
745
+ Get the map models.
746
+
747
+ Args:
748
+ json (bool, optional): If True, return the response as a dictionary.
749
+
750
+ Returns:
751
+ List[Model] | Dict: map models objects or the response.
752
+
753
+ Example:
754
+ >>> from geobox import GeoboxClient
755
+ >>> from geobox.map import Map
756
+ >>> client = GeoboxClient()
757
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
758
+ >>> map.get_models(json=True)
759
+ """
760
+ endpoint = urljoin(self.endpoint, 'models/')
761
+ response = self.api.get(endpoint)
762
+ if not response or json:
763
+ return response
764
+ else:
765
+ return [Model(self.api, model['obj'], model) for model in response['objects'] if response.get('objects')]
766
+
767
+
768
+ def set_models(self, data: Dict) -> List['Model']:
769
+ """
770
+ Set multiple models on the map.
771
+
772
+ Args:
773
+ data (Dict): the data of the models and their location on the map. check the example for the data structure.
774
+
775
+ Returns:
776
+ List[Model]: the map models objects
777
+
778
+ Example:
779
+ >>> from geobox import GeoboxClient
780
+ >>> from geobox.map inport Map
781
+ >>> client = GeoboxClient()
782
+ >>> map = Map.get_map(uuid="12345678-1234-5678-1234-567812345678")
783
+ >>> data = {'objects': [
784
+ ... {
785
+ ... "name": "transmission_tower",
786
+ ... "alias": None,
787
+ ... "desc": None,
788
+ ... "obj": "12345678-1234-5678-1234-567812345678",
789
+ ... "loc": [53.1859045261684, 33.37762747390032, 0.0],
790
+ ... "rotation": [0.0, 0.0, 0.0],
791
+ ... "scale": 1.0,
792
+ ... "min_zoom": 0,
793
+ ... "max_zoom": 22
794
+ ... }
795
+ ... ]}
796
+ >>> map.set_models(data)
797
+ """
798
+ endpoint = urljoin(self.endpoint, 'models/')
799
+ response = self.api.put(endpoint, data)
800
+ return [Model(self.api, model['obj'], model) for model in response['objects'] if response.get('objects')]
801
+
802
+
803
+ def add_model(self,
804
+ model: 'Model',
805
+ location: List[float],
806
+ rotation: List[float] = [0.0, 0.0, 0.0],
807
+ scale: float = 1.0,
808
+ min_zoom: int = 0,
809
+ max_zoom: int = 22,
810
+ alias: str = None,
811
+ description: str = None) -> List['Model']:
812
+ """
813
+ Add a model the map.
814
+
815
+ Args:
816
+ model (Model): The model object.
817
+ location (List[float]): location of the model on the map. a list with three float values.
818
+ rotation (List[float], optional): rotation of the model on the map. a list with three float vlaues. default is [0.0, 0.0, 0.0].
819
+ scale (float, optional): the scale of the model on the map.
820
+ min_zoom (int, optional): minimum zoom level.
821
+ max_zoom (int, optional): maximum zoom level.
822
+ alias (str, optional): alias of the model on the map.
823
+ description (str, optional): the description of the model on the map.
824
+
825
+ Returns:
826
+ List['Model']: The map model objects
827
+
828
+ Example:
829
+ >>> from geobox import GeoboxClient
830
+ >>> from geobox.map import Map
831
+ >>> client = GeoboxClient()
832
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
833
+ >>> model = client.get_model(uuid="12345678-1234-5678-1234-567812345678")
834
+ >>> map.add_model(model=model,
835
+ ... location=[53.53, 33.33, 0.0],
836
+ ... rotation=[0.0, 0.0, 0.0],
837
+ ... scale=1.0,
838
+ ... min_zoom=0,
839
+ ... max_zoom=22,
840
+ ... alias=None,
841
+ ... description=None)
842
+ """
843
+ data = self.get_models(json=True)
844
+ if data and data.get('objects') and isinstance(data['objects'], list):
845
+ data.get('objects').append({
846
+ 'name': model.name,
847
+ 'alias': alias,
848
+ 'desc': description,
849
+ 'obj': model.uuid,
850
+ 'loc': location,
851
+ 'rotation': rotation,
852
+ 'scale': scale,
853
+ 'min_zoom': min_zoom,
854
+ 'max_zoom': max_zoom
855
+ })
856
+ else:
857
+ data = {'objects':[
858
+ {
859
+ 'name': model.name,
860
+ 'alias': alias,
861
+ 'desc': description,
862
+ 'obj': model.uuid,
863
+ 'loc': location,
864
+ 'rotation': rotation,
865
+ 'scale': scale,
866
+ 'min_zoom': min_zoom,
867
+ 'max_zoom': max_zoom
868
+ }
869
+ ]
870
+ }
871
+
872
+ endpoint = urljoin(self.endpoint, 'models/')
873
+ response = self.api.put(endpoint, data)
874
+ return [Model(self.api, model['obj'], model) for model in response['objects']]
875
+
876
+
877
+ def image_tile_url(self, x: str = '{x}', y: str = '{y}', z: str = '{z}', format='.png') -> str:
878
+ """
879
+ Get map image tile url
880
+
881
+ Returns:
882
+ str: the image tile url
883
+
884
+ Example:
885
+ >>> from geobox import GeoboxClient
886
+ >>> from geobox.map import Map
887
+ >>> client = GeoboxClient()
888
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
889
+ >>> map.image_tile_url()
890
+ >>> map.image_tile_url(x=1, y=2, z=3, format='.pbf')
891
+ """
892
+ endpoint = f"{self.api.base_url}{self.endpoint}tiles/{z}/{x}/{y}{format}"
893
+
894
+ if not self.api.access_token and self.api.apikey:
895
+ endpoint = f'{endpoint}?apikey={self.api.apikey}'
896
+
897
+ return endpoint
898
+
899
+
900
+ def export_map_to_image(self, bbox: List, width: int, height: int) -> 'Task':
901
+ """
902
+ Export the map to image
903
+
904
+ Args:
905
+ bbox (List): e.g. [50.275, 35.1195, 51.4459, 36.0416]
906
+ width (int): minimum: 10, maximum: 10000
907
+ height (int): minimum: 10, maximum: 10000
908
+
909
+ Returns:
910
+ Task: the task object
911
+
912
+ Example:
913
+ >>> from geobox import GeoboxClient
914
+ >>> from geobox.map import Map
915
+ >>> client = GeoboxClient()
916
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
917
+ >>> task = map.export_map_to_image(bbox=[50.275, 35.1195, 51.4459, 36.0416],
918
+ ... width=1024,
919
+ ... height=1024)
920
+ """
921
+ data = clean_data({
922
+ 'uuid': self.uuid,
923
+ 'bbox': bbox,
924
+ 'width': width,
925
+ 'height': height
926
+ })
927
+ query_string = urlencode(data)
928
+ endpoint = urljoin(self.endpoint, 'export/')
929
+ endpoint = f"{endpoint}?{query_string}"
930
+ response = self.api.post(endpoint)
931
+ return self.api.get_task(response['task_id'])
932
+
933
+
934
+ def get_attachments(self, **kwargs) -> List['Attachment']:
935
+ """
936
+ Get the resouces attachments
937
+
938
+ Keyword Args:
939
+ element_id (str): the id of the element with attachment.
940
+ search (str): search term for keyword-based searching among all textual fields.
941
+ order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
942
+ skip (int): Number of items to skip. default is 0.
943
+ limit (int): Number of items to return. default is 10.
944
+ return_count (bool): Whether to return total count. default is False.
945
+
946
+ Returns:
947
+ List[Attachment] | int: A list of attachments instances or the total number of attachments.
948
+
949
+ Raises:
950
+ TypeError: if the resource type is not supported
951
+
952
+ Example:
953
+ >>> from geobox import GeoboxClient
954
+ >>> from geobox.map import Map
955
+ >>> client = GeoboxClient()
956
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
957
+ >>> map.get_attachments()
958
+ """
959
+ from .attachment import Attachment
960
+
961
+ return Attachment.get_attachments(self.api, resource=self, **kwargs)
962
+
963
+
964
+ def create_attachment(self,
965
+ name: str,
966
+ loc_x: int,
967
+ loc_y: int,
968
+ file: 'File',
969
+ feature: 'Feature' = None,
970
+ display_name: str = None,
971
+ description: str = None) -> 'Attachment':
972
+ """
973
+ Create a new Attachment.
974
+
975
+ Args:
976
+ name (str): The name of the scene.
977
+ loc_x (int): x parameter of the attachment location.
978
+ loc_y (int): y parameter of the attachment location.
979
+ file (File): the file object.
980
+ feature (Feature, optional): the feature object.
981
+ display_name (str, optional): The display name of the scene.
982
+ description (str, optional): The description of the scene.
983
+
984
+ Returns:
985
+ Attachment: The newly created Attachment instance.
986
+
987
+ Raises:
988
+ ValidationError: If the Attachment data is invalid.
989
+
990
+ Example:
991
+ >>> from geobox import GeoboxClient
992
+ >>> from geobox.map import Map
993
+ >>> client = GeoboxClient()
994
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
995
+ >>> file = client.get_files()[0]
996
+ >>> map.create_attachment(name='test', loc_x=10, loc_y=10, file=file)
997
+ """
998
+ from .attachment import Attachment
999
+
1000
+ return Attachment.create_attachment(self.api,
1001
+ name=name,
1002
+ loc_x=loc_x,
1003
+ loc_y=loc_y,
1004
+ resource=self,
1005
+ file=file,
1006
+ feature=feature,
1007
+ display_name=display_name,
1008
+ description=description)
1009
+
1010
+
1011
+ def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncMap':
1012
+ """
1013
+ Switch to async version of the map instance to have access to the async methods
1014
+
1015
+ Args:
1016
+ async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
1017
+
1018
+ Returns:
1019
+ AsyncMap: the async instance of the map.
1020
+
1021
+ Example:
1022
+ >>> from geobox import Geoboxclient
1023
+ >>> from geobox.aio import AsyncGeoboxClient
1024
+ >>> from geobox.map import Map
1025
+ >>> client = GeoboxClient()
1026
+ >>> map = Map.get_map(client, uuid="12345678-1234-5678-1234-567812345678")
1027
+ >>> async with AsyncGeoboxClient() as async_client:
1028
+ >>> async_map = map.to_async(async_client)
1029
+ """
1030
+ from .aio.map import AsyncMap
1031
+
1033
1032
  return AsyncMap(api=async_client, uuid=self.uuid, data=self.data)