From 16d378989065dbd4bc73c37ef8566f74ab93ab2a Mon Sep 17 00:00:00 2001 From: Nik Date: Sat, 4 Oct 2025 11:54:16 +0200 Subject: [PATCH 01/98] [IMP] geoengine_base: pre-commit auto fixes --- base_geoengine/README.rst | 368 +++++ base_geoengine/__init__.py | 6 + base_geoengine/__manifest__.py | 42 + base_geoengine/expressions.py | 156 ++ base_geoengine/fields.py | 341 ++++ base_geoengine/geo_convertion_helper.py | 42 + base_geoengine/geo_db.py | 90 ++ base_geoengine/geo_operators.py | 75 + base_geoengine/i18n/base_geoengine.pot | 946 +++++++++++ base_geoengine/i18n/es.po | 1044 ++++++++++++ base_geoengine/i18n/fr_BE.po | 1046 ++++++++++++ base_geoengine/i18n/it.po | 1049 ++++++++++++ base_geoengine/i18n/sv.po | 1038 ++++++++++++ base_geoengine/i18n/zh_CN.po | 1005 ++++++++++++ base_geoengine/images/map-hover.png | Bin 0 -> 113834 bytes base_geoengine/images/map.png | Bin 0 -> 71907 bytes base_geoengine/models/__init__.py | 26 + base_geoengine/models/base.py | 173 ++ base_geoengine/models/geo_raster_layer.py | 90 ++ base_geoengine/models/geo_vector_layer.py | 157 ++ base_geoengine/models/ir_model.py | 51 + base_geoengine/models/ir_view.py | 39 + base_geoengine/pyproject.toml | 3 + base_geoengine/readme/CONTRIBUTORS.md | 25 + base_geoengine/readme/DESCRIPTION.md | 16 + base_geoengine/readme/HISTORY.md | 123 ++ base_geoengine/readme/INSTALL.md | 19 + base_geoengine/readme/ROADMAP.md | 1 + base_geoengine/readme/USAGE.md | 80 + base_geoengine/security/data.xml | 20 + base_geoengine/security/ir.model.access.csv | 9 + base_geoengine/static/description/icon.png | Bin 0 -> 130328 bytes base_geoengine/static/description/index.html | 723 +++++++++ base_geoengine/static/img/map-marker.png | Bin 0 -> 356 bytes .../static/lib/chromajs-3.1.2/LICENSE | 28 + .../static/lib/chromajs-3.1.2/chroma.js | 72 + .../static/lib/geostats-2.1.0/geostats.css | 24 + .../static/lib/geostats-2.1.0/geostats.js | 1435 +++++++++++++++++ base_geoengine/static/lib/ol-10.5.0/ol.js | 2 + base_geoengine/static/lib/ol-10.5.0/ol.js.map | 1 + base_geoengine/static/src/css/style.css | 408 +++++ .../static/src/images/editing_tool_bar.png | Bin 0 -> 2222 bytes base_geoengine/static/src/js/.eslintrc | 9 + .../static/src/js/raster_layers_store.esm.js | 42 + .../static/src/js/vector_layers_store.esm.js | 36 + .../geoengine/geoengine_arch_parser.esm.js | 90 ++ .../views/geoengine/geoengine_compiler.esm.js | 16 + .../geoengine_controller.esm.js | 214 +++ .../geoengine_controller.xml | 45 + .../geoengine_record/geoengine_record.esm.js | 70 + .../geoengine_record/geoengine_record.xml | 14 + .../geoengine_renderer.esm.js | 1317 +++++++++++++++ .../geoengine_renderer.scss | 67 + .../geoengine_renderer/geoengine_renderer.xml | 35 + .../js/views/geoengine/geoengine_view.esm.js | 40 + .../layers_panel/layers_panel.esm.js | 292 ++++ .../geoengine/layers_panel/layers_panel.scss | 37 + .../geoengine/layers_panel/layers_panel.xml | 117 ++ .../records_panel/records_panel.esm.js | 85 + .../records_panel/records_panel.scss | 21 + .../geoengine/records_panel/records_panel.xml | 76 + .../search_bar_records.esm.js | 28 + .../search_bar_records/search_bar_records.xml | 27 + .../domain_field.esm.js | 34 + .../domain_selector_field_input.esm.js | 22 + .../domain_selector_field_input.xml | 13 + ...selector_field_input_for_active_ids.esm.js | 22 + ...in_selector_field_input_for_active_ids.xml | 12 + ...main_selector_field_input_with_tags.esm.js | 26 + .../domain_selector_field_input_with_tags.xml | 37 + .../domain_selector_geo_field.esm.js | 104 ++ .../domain_selector_geo_field.xml | 8 + .../domain_selector_geo_field_dialog.esm.js | 40 + .../domain_selector_geo_field_dialog.xml | 8 + .../domain_selector_geo_field_input.esm.js | 118 ++ .../domain_selector_geo_field_input.xml | 23 + .../domain_selector_number_field.esm.js | 73 + .../domain_selector_number_field.xml | 20 + .../domain_selector_operators.esm.js | 15 + .../field.geoengine_edit_map.scss | 13 + .../field_geoengine_edit_map.esm.js | 350 ++++ .../field_geoengine_edit_map.xml | 6 + base_geoengine/tests/__init__.py | 2 + base_geoengine/tests/models.py | 41 + base_geoengine/tests/test_model.py | 705 ++++++++ base_geoengine/views/base_geoengine_view.xml | 9 + .../views/geo_raster_layer_view.xml | 94 ++ .../views/geo_vector_layer_view.xml | 184 +++ base_geoengine/views/ir_model_view.xml | 32 + base_geoengine/views/ir_view_view.xml | 47 + requirements.txt | 3 + 91 files changed, 15512 insertions(+) create mode 100644 base_geoengine/README.rst create mode 100644 base_geoengine/__init__.py create mode 100644 base_geoengine/__manifest__.py create mode 100644 base_geoengine/expressions.py create mode 100644 base_geoengine/fields.py create mode 100644 base_geoengine/geo_convertion_helper.py create mode 100644 base_geoengine/geo_db.py create mode 100644 base_geoengine/geo_operators.py create mode 100644 base_geoengine/i18n/base_geoengine.pot create mode 100644 base_geoengine/i18n/es.po create mode 100644 base_geoengine/i18n/fr_BE.po create mode 100644 base_geoengine/i18n/it.po create mode 100644 base_geoengine/i18n/sv.po create mode 100644 base_geoengine/i18n/zh_CN.po create mode 100644 base_geoengine/images/map-hover.png create mode 100644 base_geoengine/images/map.png create mode 100644 base_geoengine/models/__init__.py create mode 100644 base_geoengine/models/base.py create mode 100644 base_geoengine/models/geo_raster_layer.py create mode 100644 base_geoengine/models/geo_vector_layer.py create mode 100644 base_geoengine/models/ir_model.py create mode 100644 base_geoengine/models/ir_view.py create mode 100644 base_geoengine/pyproject.toml create mode 100644 base_geoengine/readme/CONTRIBUTORS.md create mode 100644 base_geoengine/readme/DESCRIPTION.md create mode 100644 base_geoengine/readme/HISTORY.md create mode 100644 base_geoengine/readme/INSTALL.md create mode 100644 base_geoengine/readme/ROADMAP.md create mode 100644 base_geoengine/readme/USAGE.md create mode 100644 base_geoengine/security/data.xml create mode 100644 base_geoengine/security/ir.model.access.csv create mode 100644 base_geoengine/static/description/icon.png create mode 100644 base_geoengine/static/description/index.html create mode 100644 base_geoengine/static/img/map-marker.png create mode 100644 base_geoengine/static/lib/chromajs-3.1.2/LICENSE create mode 100644 base_geoengine/static/lib/chromajs-3.1.2/chroma.js create mode 100644 base_geoengine/static/lib/geostats-2.1.0/geostats.css create mode 100755 base_geoengine/static/lib/geostats-2.1.0/geostats.js create mode 100644 base_geoengine/static/lib/ol-10.5.0/ol.js create mode 100644 base_geoengine/static/lib/ol-10.5.0/ol.js.map create mode 100644 base_geoengine/static/src/css/style.css create mode 100644 base_geoengine/static/src/images/editing_tool_bar.png create mode 100644 base_geoengine/static/src/js/.eslintrc create mode 100644 base_geoengine/static/src/js/raster_layers_store.esm.js create mode 100644 base_geoengine/static/src/js/vector_layers_store.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_compiler.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.scss create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.scss create mode 100644 base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.scss create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_field.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input/domain_selector_field_input.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input/domain_selector_field_input.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_operators.esm.js create mode 100644 base_geoengine/static/src/js/widgets/geoengine_edit_map/field.geoengine_edit_map.scss create mode 100644 base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js create mode 100644 base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.xml create mode 100644 base_geoengine/tests/__init__.py create mode 100644 base_geoengine/tests/models.py create mode 100644 base_geoengine/tests/test_model.py create mode 100644 base_geoengine/views/base_geoengine_view.xml create mode 100644 base_geoengine/views/geo_raster_layer_view.xml create mode 100644 base_geoengine/views/geo_vector_layer_view.xml create mode 100644 base_geoengine/views/ir_model_view.xml create mode 100644 base_geoengine/views/ir_view_view.xml create mode 100644 requirements.txt diff --git a/base_geoengine/README.rst b/base_geoengine/README.rst new file mode 100644 index 000000000..0c3a30ad2 --- /dev/null +++ b/base_geoengine/README.rst @@ -0,0 +1,368 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +=========================== +Geospatial support for Odoo +=========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:a22713167bb39e1995e9bc618b29382cd03bba76a910d58cf62993288b0a385b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fgeospatial-lightgray.png?logo=github + :target: https://github.com/OCA/geospatial/tree/18.0/base_geoengine + :alt: OCA/geospatial +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/geospatial-18-0/geospatial-18-0-base_geoengine + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/geospatial&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. +It will allow you to : + +- Visualize and query your business information on map +- Perform GeoBI and spatial query +- Configure your spatial layers and spatial datasources +- Extend Odoo models with spatial columns + +GeoEngine relies on `OpenLayers `__ and +`PostgGIS `__ technologies. + +Postgis is used to store spatial information in databases. OpenLayer is +used to represent spatial data in other words to show maps and the +different spatial layers. The GeoEngine module acts as a data provider +and as an OpenLayers configurator. It also provides a complete extension +to Odoo ORM. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +To install this module, you need to have +`PostGIS `__ installed. + +On Ubuntu: + +:: + + .. code-block:: bash + +.. + + sudo apt-get install postgis + +The module also requires two additional python libs: + +- `Shapely `__ +- `geojson `__ + +When you will install the module this two additional libs will be +installed. + +For a complete documentation please refer to the `public +documenation `__ + +Usage +===== + +Geoengine Demo +-------------- + +1. As a user/admin, when I am in the Geoengine Demo module and I go to + the ZIP menu. When I click on an item in the list view, I get to the + form view showing me the different information about the ZIP. We can + see its ZIP, city, priority, total sales and his spatial + representation. +2. As a user, I can't modify the information in the form view. +3. As an admin, I can modify the information in the form view. I can + click on the bin button to clear the map and I can draw a new shape. +4. As a user, when I go the "Retail machines" tab and there are no + items to display, it does not show me anything. +5. As an admin, when I go the "Retail machines" tab and there are no + items to display, the list view of the retail machines suggests to + me to add a new line. +6. As a user/admin, if there are items to be displayed in the "Retail + machines" tab then I can click on an item and the retail machines + form view will be displayed. We can see its spatial representation + by going to "The point" tab and its attributes in "Attributes" tab. +7. As a user/admin, when I go to the geoengine zip view by clicking on + the map button at the top right of the screen. The geoengine view + appears with the first 80 results displayed on the map. The vector + layers selected are those defined as "active on startup" by the + admin. The selected raster layer is the first one that is not an + overlay layer. +8. As a user/admin, when I hover over an area on the map, the area + changes its style. +9. As a user/admin, when I click on an area, a popup appears an I can + see the different information about the area. If I click on the + cross, the popup will disappear. If I click somewhere else on the + map, the popup will also disappear. If I click on the about button, + then the form view will be displayed. +10. As a user/admin, when I use the paging system, then the results + displayed on the map are different (corresponding to the request). +11. As a user/admin, if we use the search bar, we can search results by + his zip or his city. +12. As an admin, if I change the sequence of layers with the handle + button then the change are persisted in database. +13. As a user, if I change the sequence of layers with the handle button + then the change are not persisted in database. There are just the + changes in the display. +14. As an admin, if I change the domain of a layer with the filter + button then the change are persisted in database. +15. As a user, if I change the domain of a layer with the filter button + then the change are not persisted in database. There are just the + changes in the display. +16. As an admin, I have the possibility to edit the layer with its + corresponding button. +17. As a user/admin, I can open/close LayerPanel with its button. +18. As a user/admin, I can open/close RecordsPanel with its button. +19. As a user/admin, when I click on a record in RecordsPanel, a move is + made on the map to the selected record. +20. As a user/admin, when I click on a record in RecordsPanel, I can + also click on the left magnifying glass to zoom on the record. +21. As a user/admin, when I click on a record in RecordsPanel, I can + also click on the right magnifying glass to get the original zoom. +22. As a user/admin, I can use the search bar to search in the + RecordsPanel. +23. As an admin,If the geoengine view is in edit mode, I can create new + records by drawing them in the view. +24. As an admin, If the geoengine view is in edit mode, I can modify its + spatial representation. + +Geoengine Backend +----------------- + +1. As an admin, if I go into the configuration of the raster layers and + it has elements, I can click on one and see its information. +2. As an admin, if I want to create a new raster layer, I can click on + "NEW" and fill out the form. The required fields for OpenStreetMap + type are "Layer Name" and "Related View". If we want to have a WMTS + (Web Map Tile Service) raster type. The required fields in addition + to the precedents are "Service URL", "Matrix set","Format", + "Projection" and "Resolutions". If we take WMS (Web Map Service) + raster type, then the required fields are "Layer Name", "Related + View", "Service URL", "Params", "Server Type". +3. As an admin,if I go into the configuration of the vector layers and + it has elements, I can click on one and see its information. +4. As an admin, if I want to create a new vector layer, I can click on + "NEW" and fill out the form. The required fields are "Layer Name", + "Related View", "Geo field" and "Representation mode". + +Known issues / Roadmap +====================== + + + +Changelog +========= + +16.0.1.0.0 (2023-03-20) +----------------------- + +- LayerSwitcher has been removed as it was not really practical. A + LayerPanel is now active. +- The geo_search method is now deprecated and replaced by the standard + odoo search method. +- The widget "geo_edit_map" attribute is no longer necessary as the + field is automatically detected by his type. We can also provide an + option attribute that allows us to pass an opacity and a color as + parameters. + +.. code:: xml + +
+ + + + + +
+ +- The method geo_search is now deprecated. We now need to use the + standard odoo search method. + +.. code:: python + + obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) + +- We can now pass to the geoengine view a template to display the + information we want to see when clicking on a feature. + +.. code:: xml + + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+ +- We can now pass a model to use to a layer to display other information + on the map. + +.. code:: xml + + + + [('state', '=', 'hs')] + + HS retail machines + + basic + + #FF0000 + + 0.8 + + +- There is some new features in the LayerPanel. + +1. If you are logged in as an admin, you have the possibility to edit + the layer by clicking on the edit button. This will open a dialog + box. Changes will appear in real time on the view. +2. If you are logged in as an admin, you can also change the domain of + the layer. If you are logged in as a user, changes will not be + persisted in the database. Changes will appear in real time on the + view. +3. If you are logged in as an admin, you can also change the sequence of + the layers by sliding them over each other. If you are logged in as a + user, changes will not be persisted in the database. + +- Widget domain is now implemented for geo field This means that the + geo-operators are also implemented and that there is the possibility + to add a sub-domain. If we want to add a domain that includes all the + records that are displayed in the geoengine view (active_ids). We can + use the two new operators : "in active_ids" and "not in active_ids". + These will automatically replace the marker with ids. Note that the + widget will indicate that the domain is invalid because of the marker. +- Creation of the RecordsPanel. This panel allows you to retrieve all + active records. You can click on record to get the movement to the + selected record. Two magnifying glass are also available. You can + click on the left one to zoom on the record. You can click on the + right one to get the original zoom. +- A search bar is also available. It allows you to perform a search into + the RecordsPanel. +- A button to open/close the panels is also available. +- The module has been translated in French. +- Now you can now make the geoengine view editable. Simply add editable + attribute in the geoengine view. + +.. code:: xml + + + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+ + Thanks to that, you can create new records by drawing them directly in the geoengine view. You can also edit record in the same view. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp +* ACSONE SA/NV + +Contributors +------------ + +- Nicolas Bessi +- Frederic Junod +- Yannick Payot +- Sandy Carter +- Laurent Mignon +- Jonathan Nemry +- David Lasley +- Daniel Reis +- Matthieu Dietrich +- Alan Ramos +- Damien Crier +- Cyril Gaudin +- Pierre Verkest +- Benjamin Willig +- Devendra Kavthekar +- Emanuel Cino +- Thomas Nowicki +- Alexandre Saunier +- Sandip Mangukiya +- Samuel Kouff +- `APSL-Nagarro `__: + + - Antoni Marroig + - Miquel Alzanillas + +- Red Butay <> +- Sergio Sancho + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/geospatial `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_geoengine/__init__.py b/base_geoengine/__init__.py new file mode 100644 index 000000000..205ee0f38 --- /dev/null +++ b/base_geoengine/__init__.py @@ -0,0 +1,6 @@ +from . import models +from . import expressions +from . import fields +from . import geo_convertion_helper +from . import geo_operators +from .geo_db import init_postgis diff --git a/base_geoengine/__manifest__.py b/base_geoengine/__manifest__.py new file mode 100644 index 000000000..f87a4d562 --- /dev/null +++ b/base_geoengine/__manifest__.py @@ -0,0 +1,42 @@ +# Copyright 2011-2015 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Geospatial support for Odoo", + "version": "18.0.1.0.1", + "category": "GeoBI", + "author": "Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/geospatial", + "depends": ["base", "web"], + "data": [ + "security/data.xml", + "views/base_geoengine_view.xml", + "views/ir_model_view.xml", + "views/ir_view_view.xml", + "views/geo_raster_layer_view.xml", + "views/geo_vector_layer_view.xml", + "security/ir.model.access.csv", + ], + "assets": { + "web.assets_backend": [ + "base_geoengine/static/src/js/**/*", + "base_geoengine/static/src/css/style.css", + "web/static/src/libs/fontawesome/css/font-awesome.css", + ("include", "web._assets_helpers"), + "web/static/src/scss/pre_variables.scss", + "web/static/lib/bootstrap/scss/_variables.scss", + ("include", "web._assets_bootstrap"), + ], + "base_geoengine.assets_jsLibs_geoengine": [ + "/base_geoengine/static/lib/ol-10.5.0/ol.js", + "/base_geoengine/static/lib/chromajs-3.1.2/chroma.js", + "/base_geoengine/static/lib/geostats-2.1.0/geostats.js", + "/base_geoengine/static/lib/geostats-2.1.0/geostats.css", + ], + }, + "external_dependencies": {"python": ["shapely", "geojson"]}, + "installable": True, + "pre_init_hook": "init_postgis", +} diff --git a/base_geoengine/expressions.py b/base_geoengine/expressions.py new file mode 100644 index 000000000..f6ed0f740 --- /dev/null +++ b/base_geoengine/expressions.py @@ -0,0 +1,156 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import random +import string + +from odoo.models import BaseModel +from odoo.osv import expression +from odoo.osv.expression import TERM_OPERATORS +from odoo.tools import SQL, Query + +from .fields import GeoField +from .geo_operators import GeoOperator + +original___condition_to_sql = BaseModel._condition_to_sql + +GEO_OPERATORS = { + "geo_greater": ">", + "geo_lesser": "<", + "geo_equal": "=", + "geo_touch": "ST_Touches", + "geo_within": "ST_Within", + "geo_contains": "ST_Contains", + "geo_intersect": "ST_Intersects", +} +GEO_SQL_OPERATORS = { + "geo_greater": SQL(">"), + "geo_lesser": SQL("<"), + "geo_equal": SQL("="), + "geo_touch": SQL("ST_Touches"), + "geo_within": SQL("ST_Within"), + "geo_contains": SQL("ST_Contains"), + "geo_intersect": SQL("ST_Intersects"), +} +term_operators_list = list(TERM_OPERATORS) +for op in GEO_OPERATORS: + term_operators_list.append(op) + +expression.TERM_OPERATORS = tuple(term_operators_list) +expression.SQL_OPERATORS.update(GEO_SQL_OPERATORS) + + +def _condition_to_sql( + self, alias: str, fname: str, operator: str, value, query: Query +) -> SQL: + """ + This method has been monkey patched in order to be able to include + geo_operators into the Odoo search method. + """ + if operator in GEO_OPERATORS.keys(): + current_field = self._fields.get(fname) + current_operator = GeoOperator(current_field) + if current_field and isinstance(current_field, GeoField): + params = [] + if isinstance(value, dict): + # We are having indirect geo_operator like (‘geom’, ‘geo_...’, + # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + ref_search = value + sub_queries = [] + for key in ref_search: + i = key.rfind(".") + rel_model = key[0:i] + rel_col = key[i + 1 :] + rel_model = self.env[rel_model] + # we compute the attributes search on spatial rel + if ref_search[key]: + rel_alias = ( + rel_model._table + + "_" + + "".join(random.choices(string.ascii_lowercase, k=5)) + ) + rel_query = where_calc( + rel_model, + ref_search[key], + active_test=True, + alias=rel_alias, + ) + self._apply_ir_rules(rel_query, "read") + if operator == "geo_equal": + rel_query.add_where( + f'"{alias}"."{fname}" {GEO_OPERATORS[operator]} ' + f"{rel_alias}.{rel_col}" + ) + elif operator in ("geo_greater", "geo_lesser"): + rel_query.add_where( + f"ST_Area({alias}.{fname}) {GEO_OPERATORS[operator]} " + f"ST_Area({rel_alias}.{rel_col})" + ) + else: + rel_query.add_where( + f'{GEO_OPERATORS[operator]}("{alias}"."{fname}", ' + f"{rel_alias}.{rel_col})" + ) + + subquery, subparams = rel_query.subselect("1") + sub_query_mogrified = ( + self.env.cr.mogrify(subquery, subparams) + .decode("utf-8") + .replace(f"'{rel_model._table}'", f'"{rel_model._table}"') + .replace("%", "%%") + ) + sub_queries.append(f"EXISTS({sub_query_mogrified})") + query = " AND ".join(sub_queries) + else: + query = get_geo_func( + current_operator, operator, fname, value, params, self._table + ) + return SQL(query, *params) + return original___condition_to_sql( + self, alias=alias, fname=fname, operator=operator, value=value, query=query + ) + + +def get_geo_func(current_operator, operator, left, value, params, table): + """ + This method will call the SQL query corresponding to the requested geo operator + """ + match operator: + case "geo_greater": + query = current_operator.get_geo_greater_sql(table, left, value, params) + case "geo_lesser": + query = current_operator.get_geo_lesser_sql(table, left, value, params) + case "geo_equal": + query = current_operator.get_geo_equal_sql(table, left, value, params) + case "geo_touch": + query = current_operator.get_geo_touch_sql(table, left, value, params) + case "geo_within": + query = current_operator.get_geo_within_sql(table, left, value, params) + case "geo_contains": + query = current_operator.get_geo_contains_sql(table, left, value, params) + case "geo_intersect": + query = current_operator.get_geo_intersect_sql(table, left, value, params) + case _: + raise NotImplementedError(f"The operator {operator} is not supported") + return query + + +def where_calc(model, domain, active_test=True, alias=None): + """ + This method is copied from base, we need to create our own query. + """ + # if the object has an active field ('active', 'x_active'), filter out all + # inactive records unless they were explicitly asked for + if model._active_name and active_test and model._context.get("active_test", True): + # the item[0] trick below works for domain items and '&'/'|'/'!' + # operators too + if not any(item[0] == model._active_name for item in domain): + domain = [(model._active_name, "=", 1)] + domain + + query = Query(model.env, alias, model._table) + if domain: + return expression.expression(domain, model, alias=alias, query=query).query + return query + + +BaseModel._condition_to_sql = _condition_to_sql diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py new file mode 100644 index 000000000..300eaeb1d --- /dev/null +++ b/base_geoengine/fields.py @@ -0,0 +1,341 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import json +import logging +from operator import attrgetter + +from odoo import _, fields +from odoo.tools import sql + +from . import geo_convertion_helper as convert +from .geo_db import create_geo_column, create_geo_index + +logger = logging.getLogger(__name__) +try: + import geojson + from shapely.geometry import Point, shape + from shapely.geometry.base import BaseGeometry + from shapely.wkb import loads as wkbloads +except ImportError: + logger.warning("Shapely or geojson are not available in the sys path") + + +class GeoField(fields.Field): + """The field descriptor contains the field definition common to all + specialized fields for geolocalization. Subclasses must define a type + and a geo_type. The type is the name of the corresponding column type, + the geo_type is the name of the corresponding type in the GIS system. + """ + + geo_type = None + dim = "2" + srid = 3857 + gist_index = True + + @property + def column_type(self): + postgis_geom_type = self.geo_type.upper() if self.geo_type else "GEOMETRY" + if self.dim == "3": + postgis_geom_type += "Z" + elif self.dim == "4": + postgis_geom_type += "ZM" + return ("geometry", f"geometry({postgis_geom_type}, {self.srid})") + + def convert_to_column(self, value, record, values=None, validate=True): + """Convert value to database format + + value can be geojson, wkt, shapely geometry object. + If geo_direct_write in context you can pass diretly WKT""" + if not value: + return None + shape_to_write = self.entry_to_shape(value, same_type=True) + if shape_to_write.is_empty: + return None + else: + return f"SRID={self.srid};{shape_to_write.wkt}" + + def convert_to_cache(self, value, record, validate=True): + val = value + if isinstance(val, bytes | str): + try: + int(val, 16) + except Exception: + # not an hex value -> try to load from a sting + # representation of a geometry + value = convert.value_to_shape(value, use_wkb=False) + if isinstance(value, BaseGeometry): + val = value.wkb_hex + return val + + def convert_to_record(self, value, record): + """Value may be: + - a GeoJSON string when field onchange is triggered + - a geometry object hexcode from cache + - a unicode containing dict + """ + if not value: + return False + return convert.value_to_shape(value, use_wkb=True) + + def convert_to_read(self, value, record, use_display_name=True): + if not isinstance(value, BaseGeometry): + # read hexadecimal value from database + shape = self.load_geo(value) + else: + shape = value + if not shape or shape.is_empty: + return False + return geojson.dumps(shape) + + # + # Field description + # + + # properties used by get_description() + _description_dim = property(attrgetter("dim")) + _description_srid = property(attrgetter("srid")) + _description_gist_index = property(attrgetter("gist_index")) + + @classmethod + def load_geo(cls, wkb): + """Load geometry into browse record after read was done""" + if isinstance(wkb, BaseGeometry): + return wkb + return wkbloads(wkb, hex=True) if wkb else False + + def entry_to_shape(self, value, same_type=False): + """Transform input into an object""" + shape = convert.value_to_shape(value) + if same_type and not shape.is_empty: + if shape.geom_type.lower() != self.geo_type.lower(): + msg = _( + "Geo Value %(geom_type)s must be of the same type %(geo_type)s \ + as fields", + geom_type=shape.geom_type.lower(), + geo_type=self.geo_type.lower(), + ) + raise TypeError(msg) + return shape + + def update_geo_db_column(self, model): + """Update the column type in the database.""" + cr = model._cr + query = """SELECT srid, type, coord_dimension + FROM geometry_columns + WHERE f_table_name = %s + AND f_geometry_column = %s""" + cr.execute(query, (model._table, self.name)) + check_data = cr.fetchone() + if not check_data: + raise TypeError( + _( + "geometry_columns table seems to be corrupted." + " SRID check is not possible" + ) + ) + if check_data[0] != self.srid: + raise TypeError( + _( + "Reprojection of column is not implemented." + " We can not change srid %(srid)s to %(data)s", + srid=self.srid, + data=check_data[0], + ) + ) + elif check_data[1] != self.geo_type.upper(): + raise TypeError( + _( + "Geo type modification is not implemented." + " We can not change type %(data)s to %(geo_type)s", + data=check_data[1], + geo_type=self.geo_type.upper(), + ) + ) + elif check_data[2] != self.dim: + raise TypeError( + _( + "Geo dimention modification is not implemented." + " We can not change dimention %(data)s to %(dim)s", + data=check_data[2], + dim=self.dim, + ) + ) + if self.gist_index: + create_geo_index(cr, self.name, model._table) + return True + + def update_db_column(self, model, column): + """Create/update the column corresponding to ``self``. + + For creation of geo column + + :param model: an instance of the field's model + :param column: the column's configuration (dict) + if it exists, or ``None`` + """ + # the column does not exist, create it + + if not column: + create_geo_column( + model._cr, + model._table, + self.name, + self.geo_type.upper(), + self.srid, + self.dim, + self.string, + ) + if self.gist_index: + create_geo_index(model._cr, self.name, model._table) + return + + if column["udt_name"] == self.column_type[0]: + if self.gist_index: + create_geo_index(model._cr, self.name, model._table) + return + + self.update_geo_db_column(model) + + if column["udt_name"] in self.column_cast_from: + sql.convert_column(model._cr, model._table, self.name, self.column_type[1]) + else: + newname = (self.name + "_moved{}").format + i = 0 + while sql.column_exists(model._cr, model._table, newname(i)): + i += 1 + if column["is_nullable"] == "NO": + sql.drop_not_null(model._cr, model._table, self.name) + sql.rename_column(model._cr, model._table, self.name, newname(i)) + sql.create_column( + model._cr, model._table, self.name, self.column_type[1], self.string + ) + + +class GeoLine(GeoField): + """Field for POSTGIS geometry Line type""" + + type = "geo_line" + geo_type = "LineString" + + @classmethod + def from_points(cls, cr, point1, point2, srid=None): + """ + Converts given points in parameter to a line. + :param cr: DB cursor + :param point1: Point (BaseGeometry) + :param point2: Point (BaseGeometry) + :param srid: SRID + :return: LINESTRING Object + """ + sql = """ + SELECT + ST_MakeLine( + ST_GeomFromText(%(wkt1)s, %(srid)s), + ST_GeomFromText(%(wkt2)s, %(srid)s) + ) + """ + cr.execute( + sql, + { + "wkt1": point1.wkt, + "wkt2": point2.wkt, + "srid": srid or cls.srid, + }, + ) + res = cr.fetchone() + return cls.load_geo(res[0]) + + +class GeoPoint(GeoField): + """Field for POSTGIS geometry Point type""" + + type = "geo_point" + geo_type = "Point" + + @classmethod + def from_latlon(cls, cr, latitude, longitude): + """Convert a (latitude, longitude) into an UTM coordinate Point:""" + pt = Point(longitude, latitude) + cr.execute( + """ + SELECT + ST_Transform( + ST_GeomFromText(%(wkt)s, 4326), + %(srid)s) + """, + {"wkt": pt.wkt, "srid": cls.srid}, + ) + res = cr.fetchone() + return cls.load_geo(res[0]) + + @classmethod + def to_latlon(cls, cr, geopoint): + """Convert a UTM coordinate point to \ + (latitude, longitude):""" + # Line to execute to retrieve + # longitude, latitude from UTM in postgres command line: + # SELECT ST_X(geom), ST_Y(geom) FROM (SELECT ST_TRANSFORM(ST_SetSRID( + # ST_MakePoint(601179.61612, 6399375,681364), + # ..............900913), 4326) as geom) g; + if isinstance(geopoint, BaseGeometry): + geo_point_instance = geopoint + else: + geo_point_instance = shape(json.loads(geopoint)) + cr.execute( + """ + SELECT + ST_TRANSFORM( + ST_SetSRID( + ST_MakePoint( + %(coord_x)s, %(coord_y)s + ), + %(srid)s + ), 4326)""", + { + "coord_x": geo_point_instance.x, + "coord_y": geo_point_instance.y, + "srid": cls.srid, + }, + ) + + res = cr.fetchone() + point_latlon = cls.load_geo(res[0]) + return point_latlon.x, point_latlon.y + + +class GeoPolygon(GeoField): + """Field for POSTGIS geometry Polygon type""" + + type = "geo_polygon" + geo_type = "Polygon" + + +class GeoMultiLine(GeoField): + """Field for POSTGIS geometry MultiLine type""" + + type = "geo_multi_line" + geo_type = "MultiLineString" + + +class GeoMultiPoint(GeoField): + """Field for POSTGIS geometry MultiPoint type""" + + type = "geo_multi_point" + geo_type = "MultiPoint" + + +class GeoMultiPolygon(GeoField): + """Field for POSTGIS geometry MultiPolygon type""" + + type = "geo_multi_polygon" + geo_type = "MultiPolygon" + + +fields.GeoLine = GeoLine +fields.GeoPoint = GeoPoint +fields.GeoPolygon = GeoPolygon +fields.GeoMultiLine = GeoMultiLine +fields.GeoMultiPoint = GeoMultiPoint +fields.GeoMultiPolygon = GeoMultiPolygon diff --git a/base_geoengine/geo_convertion_helper.py b/base_geoengine/geo_convertion_helper.py new file mode 100644 index 000000000..faa015c3f --- /dev/null +++ b/base_geoengine/geo_convertion_helper.py @@ -0,0 +1,42 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from odoo import _ + +try: + import geojson + from shapely import wkb, wkt + from shapely.geometry import shape + from shapely.geometry.base import BaseGeometry +except ImportError: + logger = logging.getLogger(__name__) + logger.warning(_("Shapely or geojson are not available in the sys path")) + + +def value_to_shape(value, use_wkb=False): + """Transforms input into a Shapely object""" + if not value: + return wkt.loads("GEOMETRYCOLLECTION EMPTY") + if isinstance(value, str): + # We try to do this before parsing json exception + # exception are ressource costly + if "{" in value: + geo_dict = geojson.loads(value) + return shape(geo_dict) + elif use_wkb: + return wkb.loads(value, hex=True) + else: + return wkt.loads(value) + elif hasattr(value, "wkt"): + if isinstance(value, BaseGeometry): + return value + else: + return wkt.loads(value.wkt) + else: + raise TypeError( + _( + "Write/create/search geo type must be wkt/geojson " + "string or must respond to wkt" + ) + ) diff --git a/base_geoengine/geo_db.py b/base_geoengine/geo_db.py new file mode 100644 index 000000000..9c8e4b633 --- /dev/null +++ b/base_geoengine/geo_db.py @@ -0,0 +1,90 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +"""Helper to setup Postgis""" + +import logging + +from odoo import _ +from odoo.exceptions import MissingError +from odoo.tools import sql + +logger = logging.getLogger("geoengine.sql") +_schema = logging.getLogger("odoo.schema") + + +def init_postgis(env): + """Initialize postgis + Add PostGIS support to the database. PostGIS is a spatial database + extender for PostgreSQL object-relational database. It adds support for + geographic objects allowing location queries to be run in SQL. + """ + cr = env.cr + cr.execute( + """ + SELECT + tablename + FROM + pg_tables + WHERE + tablename='spatial_ref_sys'; + """ + ) + check = cr.fetchone() + if check: + return {} + try: + cr.execute( + """ + CREATE EXTENSION postgis; + CREATE EXTENSION postgis_topology; + """ + ) + except Exception as exc: + raise MissingError( + _( + "Error, can not automatically initialize spatial postgis" + " support. Database user may have to be superuser and" + " postgres/postgis extensions with their devel header have" + " to be installed. If you do not want Odoo to connect with a" + " super user you can manually prepare your database. To do" + " this, open a client to your database using a super user and" + " run:\n" + "CREATE EXTENSION postgis;\n" + "CREATE EXTENSION postgis_topology;\n" + ) + ) from exc + + +def create_geo_column(cr, tablename, columnname, geotype, srid, dim, comment=None): + """Create a geometry column with the given type. + + :params: srid: geometry's projection srid + :params: dim: geometry's dimension (2D or 3D) + """ + cr.execute( + "SELECT AddGeometryColumn( %s, %s, %s, %s, %s)", + (tablename, columnname, srid, geotype, dim), + ) + if comment: + # pylint: disable=E8103 + cr.execute( + f'COMMENT ON COLUMN "{tablename}"."{columnname}" IS %s', + (comment,), + ) + _schema.debug( + "Table %r: added geometry column %r of type %s", tablename, columnname, geotype + ) + + +def _postgis_index_name(table, col_name): + return f"{table}_{col_name}_gist_index" + + +def create_geo_index(cr, columnname, tablename): + """Create the given index unless it exists.""" + indexname = _postgis_index_name(tablename, columnname) + if sql.index_exists(cr, indexname): + return + # pylint: disable=E8103 + cr.execute(f"CREATE INDEX {indexname} ON {tablename} USING GIST ( {columnname} )") + _schema.debug("Table %r: created index %r", tablename, indexname) diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py new file mode 100644 index 000000000..8be01f44e --- /dev/null +++ b/base_geoengine/geo_operators.py @@ -0,0 +1,75 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +class GeoOperator: + def __init__(self, geo_field): + self.geo_field = geo_field + + def _get_direct_como_op_sql(self, table, col, value, params, op=""): + """provide raw sql for geater and lesser operators""" + if isinstance(value, int | float): + return f" ST_Area({table}.{col}) {op} {value}" + else: + base = self.geo_field.entry_to_shape(value, same_type=False) + params.append(base.wkt) + return f" ST_Area({table}.{col}) {op} ST_Area(ST_GeomFromText(%s))" + + def _get_postgis_comp_sql(self, table, col, value, params, op=""): + """return raw sql for all search based on St_**(a, b) posgis operator""" + base = self.geo_field.entry_to_shape(value, same_type=False) + srid = self.geo_field.srid + params.append(base.wkt) + params.append(srid) + return f"{op}({table}.{col}, ST_GeomFromText(%s, %s))" + + def get_geo_greater_sql(self, table, col, value, params): + """Returns raw sql for geo_greater operator + (used for area comparison) + """ + return self._get_direct_como_op_sql(table, col, value, params, op=">") + + def get_geo_lesser_sql(self, table, col, value, params): + """Returns raw sql for geo_lesser operator + (used for area comparison)""" + return self._get_direct_como_op_sql(table, col, value, params, op="<") + + def get_geo_equal_sql( + self, + table, + col, + value, + params, + ): + """Returns raw sql for geo_equal operator + (used for equality comparison) + """ + base = self.geo_field.entry_to_shape(value, same_type=False) + compare_to = "ST_GeomFromText(%s)" + params.append(base.wkt) + return f" {table}.{col} = {compare_to}" + + def get_geo_intersect_sql(self, table, col, value, params): + """Returns raw sql for geo_intersec operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Intersects") + + def get_geo_touch_sql(self, table, col, value, params): + """Returns raw sql for geo_touch operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Touches") + + def get_geo_within_sql(self, table, col, value, params): + """Returns raw sql for geo_within operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Within") + + def get_geo_contains_sql(self, table, col, value, params): + """Returns raw sql for geo_contains operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Contains") diff --git a/base_geoengine/i18n/base_geoengine.pot b/base_geoengine/i18n/base_geoengine.pot new file mode 100644 index 000000000..35bcde7b3 --- /dev/null +++ b/base_geoengine/i18n/base_geoengine.pot @@ -0,0 +1,946 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +msgid "%s column does not exists or is not a geo field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +msgid "Add new value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +msgid "Add tag" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +msgid "Discard" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +msgid "Domain editing" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +msgid "Editing Raster Layer" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +msgid "Editing vector layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +msgid "" +"Error, can not automatically initialize spatial postgis support. Database user may have to be superuser and postgres/postgis extensions with their devel header have to be installed. If you do not want Odoo to connect with a super user you can manually prepare your database. To do this, open a client to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +msgid "" +"Geo Value %(geom_type)s must be of the same type %(geo_type)s" +" as fields" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to" +" %(geo_type)s" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +msgid "Geoengine" +msgstr "" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +msgid "Layers (" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +msgid "New record" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +msgid "No raster layer for view %s" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +msgid "OPEN" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +msgid "Rasters" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +msgid "Records (" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +msgid "Remove tag" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +msgid "Save" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +msgid "Search..." +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +msgid "Shapely or geojson are not available in the sys path" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +msgid "Subdomain" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +msgid "The geo_field_id must be a field in %s model" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +msgid "Vectors" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +msgid "Warning" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +msgid "You must at least provide one of domain or geo_domain" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +msgid "You need to provide an attribute that exists in %s model" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +msgid "You need to select a numeric field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_contains" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_equal" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_greater" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_intersect" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_lesser" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_touch" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +msgid "geo_within" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +msgid "in active_ids" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +msgid "not in active_ids" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "" diff --git a/base_geoengine/i18n/es.po b/base_geoengine/i18n/es.po new file mode 100644 index 000000000..9c09f6137 --- /dev/null +++ b/base_geoengine/i18n/es.po @@ -0,0 +1,1044 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-08-08 11:10+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "La columna %s no existe o no es un campo geográfico" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "Activo en el arranque" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add new value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add tag" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "Campo de atributo" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "Base/Fuente" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "Básico" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "Iniciar clase de color" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "Clasificación" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "Modo de clasificación" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "Código" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "Gama de colores/Chroma.js" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "Colores" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "Configuración" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "Crear un índice gist" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "Personalizar" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "Extensión predeterminada del mapa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "Zoom predeterminado del mapa" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "Diccionario de valores de las dimensiones en formato JSON" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "Dimensiones" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "Mostrar etiquetas en el polígono" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "Mostrar Nombre" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "Sistema de gestión de almacenes (SGA) a distancia" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Domain editing" +msgstr "Editando Dominio" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing Raster Layer" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing vector layer" +msgstr "Edición de capas vectoriales" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "Fin de la clase de color" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database " +"user may have to be superuser and postgres/postgis extensions with their " +"devel header have to be installed. If you do not want Odoo to connect with a " +"super user you can manually prepare your database. To do this, open a client " +"to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" +"Error, no se puede inicializar automáticamente el soporte espacial postgis. " +"El usuario de la base de datos debe ser superusuario y las extensiones " +"postgres/postgis con su cabecera devel deben estar instaladas. Si no quieres " +"que Odoo se conecte con un superusuario puedes preparar manualmente tu base " +"de datos. Para hacer esto, abre un cliente a tu base de datos usando un " +"superusuario y ejecuta\n" +"CREAR EXTENSIÓN postgis;\n" +"CREAR EXTENSIÓN postgis_topología;\n" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "Tipo de campo" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "Campos" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "Formato" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "General" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo Value %(geom_type)s must be of the same type " +"%(geo_type)s as fields" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "" +"La modificación de la dimensión geográfica no está implementada. No podemos " +"cambiar la dimensión %(data)s a %(dim)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "Campo geográfico" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to " +"%(geo_type)s" +msgstr "" +"La modificación del geotipo no está implementada. No podemos cambiar el tipo " +"%(data)s a %(geo_type)s" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "GeoIngeniería" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "Servidor de Geoingeniería" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "Fecha de Geoingeniería" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +#, python-format +msgid "Geoengine" +msgstr "Geoingeniería" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "Administración de Geoingeniería" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "Usuario de Geoingeniería" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "Tiene Tipo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "ID (identificación)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "Intervalo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "Es Wms" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "Es Wmts" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "¿Es una capa de superposición?" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "Última Actualización el" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "Capa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "nombre de Capa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "Opacidad de la capa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "Prioridad de Capa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "Fecha de Capa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "La capa es de sólo lectura" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "Prioridad de Capa" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "La capa se mostrará al inicio si está marcada." + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Layers (" +msgstr "Capas (" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "Secuencia de líneas" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "Lista de dimensiones separadas por ','" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "Conjunto matriz" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "Extensión máxima" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +#, python-format +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "Falta la plantilla ${INFO_BOX_ATTRIBUTE}." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "Modelo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "Dominio del modelo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "Modelo a utilizar" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "Vista del modelo" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "Cadena multilínea" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "Punto Múltiple" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "Multipolígono" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "Nombre" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "Necesidad de proporcionar al menos un parámetro de CAPAS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "New record" +msgstr "Nuevo récord" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "No hay capa ráster para la vista %s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "Número de clase" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +#, python-format +msgid "OPEN" +msgstr "ABRIR" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "Campo de odoo" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "Datos de la capa Odoo (No implementado)" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "Campo de capa de Odoo a utilizar" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "OpenStreetMap" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "Parámetros" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "Punto" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "Polígono" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "Dimensión PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "Tipo PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "Proyección" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "Símbolo proporcional" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "Cuantil" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "Ráster (capas de fondo)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "Capa Ráster" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "Gestión de capas rasterizadas" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "Tipo de capa rasterizada" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "Vista de capa rasterizada" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "Tipo de capa rasterizada" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "Capas Ráster" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Rasters" +msgstr "Rásteres" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +#, python-format +msgid "Records (" +msgstr "Registros (" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "Modelo relacionado" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "Vista relacionada" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Remove tag" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "Representación" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "Modo de representación" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "" +"La reproyección de columna no está implementada. No podemos cambiar srid " +"%(srid)s por %(data)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "Solicitar codificación" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "Resoluciones" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "Extensión de mapa restringida" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Save" +msgstr "Guardar" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#, python-format +msgid "Search..." +msgstr "Buscar..." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "Tipo de servidor" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "Servicio" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "URL de servicio" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "Shapely or geojson are not available in the sys path" +msgstr "Shapely o geojson no están disponibles en la ruta del sistema" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +#, python-format +msgid "Subdomain" +msgstr "Subdominio" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "The geo_field_id must be a field in %s model" +msgstr "El geo_field_id debe ser un campo del modelo %s" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "Valor único" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "Unidades" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "Utilizar para editar" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "Vector" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "Vector (capas activas)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "Capa vectorial" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "Gestión de capas vectoriales" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "Capas vectoriales" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Vectors" +msgstr "Vectores" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "Gestión de visualización" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipo de vista" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "Vistas" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "Opciones WMS" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "WMTS" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "Opciones WMTS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "Warning" +msgstr "Aviso" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "" +"Write/create/search geo type debe ser wkt/geojson string o debe responder a " +"wkt" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "" +"Está a punto de crear un nuevo registro sin haber visualizado todos los " +"demás. Podría producirse un riesgo de solapamiento. ¿Desea continuar?" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "You must at least provide one of domain or geo_domain" +msgstr "Debe proporcionar al menos uno de los dominios o geo_domain" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to provide an attribute that exists in %s model" +msgstr "Necesita proporcionar un atributo que existe en el modelo %s" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to select a numeric field" +msgstr "Debe seleccionar un campo numérico" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "ej. EPSG:21781" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "ej. REST" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "ej. m" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "ej. png" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_contains" +msgstr "geo_contains (geo_contenedores)" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_equal" +msgstr "geo_equal (geo_igual)" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_greater" +msgstr "geo_greater (geo_mayor)" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_intersect" +msgstr "geo_intersect (geo_intersección)" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_lesser" +msgstr "geo_lesser (geo_menor)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "geo_line (geo_línea)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "geo_multi_line (geo_multi_línea)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "geo_multi_point (geo_multi_punto)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "geo_multi_polygon (geo_multi_polígono)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "geo_point (geo_punto)" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "geo_polygon (geo_polígono)" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "" +"geo_search está obsoleto: utiliza el método de búsqueda definido en el " +"modelo base" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_touch" +msgstr "geo_touch (geo_táctil)" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_within" +msgstr "geo_within (geo_interior)" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "" +"La tabla geometry_columns parece estar dañada. No es posible comprobar el " +"SRID" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "valor hexadecimal" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "in active_ids" +msgstr "En active_ids" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "not in active_ids" +msgstr "No en active_ids" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "srid" + +#, python-format +#~ msgid "" +#~ "Geo Value %(geom_type)s must be of the same type %(geo_type)s as fields" +#~ msgstr "" +#~ "Los valores geográficos %(geom_type)s deben ser del mismo tipo " +#~ "%(geo_type)s que los campos" + +#~ msgid "Last Modified on" +#~ msgstr "Última Modificación el" + +#, python-format +#~ msgid "No GeoEngine view defined for the model %s" +#~ msgstr "No se definió una vista de GeoIngeniería para el modelo %s" + +#, python-format +#~ msgid "Please create a view or modify view mode" +#~ msgstr "Por favor, cree una vista o modifique el modo de vista" + +#~ msgid "" +#~ "The type of the remote WMS server: mapserver, geoserver, carmentaserver, " +#~ "or qgis" +#~ msgstr "" +#~ "Tipo de servidor WMS remoto: mapserver, geoserver, carmentaserver o qgis" diff --git a/base_geoengine/i18n/fr_BE.po b/base_geoengine/i18n/fr_BE.po new file mode 100644 index 000000000..34ca132cd --- /dev/null +++ b/base_geoengine/i18n/fr_BE.po @@ -0,0 +1,1046 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-15 06:18+0000\n" +"PO-Revision-Date: 2023-05-15 06:18+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "%s la colonne n'existe pas ou n'est pas un champ géographique" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "Actif au démarrage" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add new value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add tag" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "Attribut" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "Basique" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "Début de la classe de couleur" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "Mode de classification" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "Plage de couleurs/Chroma.js" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "Couleurs" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "Création d'un index gist" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "Personnalisable" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "Étendue de la carte par défaut" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "Zoom par défaut de la carte" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "Liste de valeurs pour les dimensions sous forme de JSON" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Discard" +msgstr "Annuler" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "Afficher les étiquettes sur les polygones" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "Nom d'affichage" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "WMS distant" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Domain editing" +msgstr "Édition du domaine" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing Raster Layer" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing vector layer" +msgstr "Edition de la couche vectorielle" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "Fin de la classe de couleur" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database " +"user may have to be superuser and postgres/postgis extensions with their " +"devel header have to be installed. If you do not want Odoo to connect with a " +"super user you can manually prepare your database. To do this, open a client " +"to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" +"Erreur, impossible d'initialiser automatiquement le support spatial postigs. " +"L'utilisateur de la base de données doit être un super utilisateur et les " +"extensions postgres/postgis doivent être installées avec leurs en-tête " +"devel. Si vous ne voulez pas qu'Odoo se connecte avec un super utilisateur, " +"vous pouvez préparer manuellement votre base de données. Pour ce faire, " +"ouvrez un client à votre base de données en utilisant un super utilisateur " +"et exécutez:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "Type de champ" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "Champs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "Général" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo Value %(geom_type)s must be of the same type " +"%(geo_type)s as fields" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "" +"La modification de la dimension de la géométrie n'est pas implémentée. Nous " +"ne pouvons pas modifier la dimension %(data)s to %(dim)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "Champ géographique" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to " +"%(geo_type)s" +msgstr "" +"La modification du type de la géométrie n'est pas implémentée. Nous ne " +"pouvons pas changer le type %(data)s to %(geo_type)s" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +#, python-format +msgid "Geoengine" +msgstr "" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "Admin Geoengine" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "Utilisateur GeoEngine" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "A le type" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "Intervalle" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "Est un Wms" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "Est un Wmts" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "S'agit-il d'une couche superposée ?" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "Couche" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "Nom de la couche" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "Opacité de la couche" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "Priorité de la couche" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "Données de la couche" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "La couche est en lecture seule" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "Priorité de la couche" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "Si cette case est cochée, la couche sera affichée au démarrage" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Layers (" +msgstr "Couches (" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "Liste des dimensions séparées par ','" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "Ensemble matriciel" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "Étendue maximum" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +#, python-format +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "Template ${INFO_BOX_ATTRIBUTE} manquant." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "Modèle" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "Domaine du modèle" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "Modèle à utiliser" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "Vue du modèle" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "Nom" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "Besoin de fournir au moins un paramètre LAYERS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "New record" +msgstr "Nouvel enregistrement" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "Pas de couche d'arrière-plan pour la vue %s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "Nombre de classe" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +#, python-format +msgid "OPEN" +msgstr "OUVRIR" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "Champ Odoo" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "Données de couche Odoo (non implémenté)" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "Champ de couche Odoo à utiliser" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "Paramètres" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "Dimension PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "Type PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "Symbole proportionnel" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "Raster (Couches d'arrière-plan)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "Couche d'arrière-plan" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "Gestion des couches d'arrière-plan" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "Type de couche d'arrière-plan" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "Vue de la couche d'arrière-plan" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "Type de couche d'arrière-plan" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "Couches d'arrière-plan" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Rasters" +msgstr "Couches d'arrière-plan" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +#, python-format +msgid "Records (" +msgstr "Enregistrements (" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "Modèle associé" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "Vue associé" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Remove tag" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "Représentation" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "Mode de représentation" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "" +"La reprojection de la colonne n'est pas mise en oeuvre. Nous ne pouvons pas " +"modifier le srid %(srid)s to %(data)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "Demande d'encodage" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "Résolutions" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "Limitation de l'étendue de la carte" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Save" +msgstr "Sauvegarder" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#, python-format +msgid "Search..." +msgstr "Rechercher..." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "Type de serveur" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "URL du service" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "Shapely or geojson are not available in the sys path" +msgstr "" +"Shapely ou geojson ne sont pas disponibles dans le chemin d'accès système" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +#, python-format +msgid "Subdomain" +msgstr "Sous domaine" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "The geo_field_id must be a field in %s model" +msgstr "Le geo_field_id doit être un champ dans le modèle %s" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "Valeur unique" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "Unités" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "Autorisation d'édition" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "Vecteur" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "Vecteur (couche actives)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "Couche vectorielle" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "Gestion des couches vectorielles" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "Couches vectorielles" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Vectors" +msgstr "Couches vectorielles" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "Vue" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "Gestion des vues" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "Type de vue" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "Vues" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "Options du WMS" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "Options du WMTS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "Warning" +msgstr "Attention" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "" +"Vous êtes sur le point de créer un nouvel enregistrement sans avoir affiché " +"tous les autres. Un risque de chevauchement pourrait se produire. Voulez-" +"vous continuer ?" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "You must at least provide one of domain or geo_domain" +msgstr "Vous devez fournir au moins un domaine ou un géo-domaine" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to provide an attribute that exists in %s model" +msgstr "Vous devez fournir un attribut qui existe dans le modèle %s" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to select a numeric field" +msgstr "Vous devez sélectionner un champ numérique" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "ex. EPSG:21781" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "ex. REST" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "ex. m" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "ex. png" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_contains" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_equal" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_greater" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_intersect" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_lesser" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "" +"la méthode geo_search est dépréciée : utilisez la méthode search définie " +"dans le modèle de base" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_touch" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_within" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "" +"La table geometry_columns semble être corrompue. La vérification de SRID " +"n'est pas possible" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "valeur hexadécimale" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "in active_ids" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "not in active_ids" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "" + +#, python-format +#~ msgid "" +#~ "Geo Value %(geom_type)s must be of the same type %(geo_type)s as fields" +#~ msgstr "" +#~ "La valeur géographique %(geom_type)s doit être du même type %(geo_type)s " +#~ "queles champs" + +#~ msgid "Last Modified on" +#~ msgstr "Dernière modification le" + +#, python-format +#~ msgid "No GeoEngine view defined for the model %s" +#~ msgstr "Aucune vue GeoEngine n'est définie pour le modèle %s" + +#, python-format +#~ msgid "Please create a view or modify view mode" +#~ msgstr "Veuillez créer une vue ou modifier le mode de vue" + +#~ msgid "" +#~ "The type of the remote WMS server: mapserver, geoserver, carmentaserver, " +#~ "or qgis" +#~ msgstr "" +#~ "Le type du serveur WMS distant: mapserver, geoserver, camentaserver, " +#~ "orqgis" diff --git a/base_geoengine/i18n/it.po b/base_geoengine/i18n/it.po new file mode 100644 index 000000000..b7c259406 --- /dev/null +++ b/base_geoengine/i18n/it.po @@ -0,0 +1,1049 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-09-27 15:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "La colonna %s non esiste, o non è un campo geo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "Attivo all'avvio" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add new value" +msgstr "Aggiungi nuovo valore" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add tag" +msgstr "Aggiungi etichetta" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "Campo attributo" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "Base" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "Base" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "Classe colore inizio" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "Classificazione" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "Modo di classificazione" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "Codice" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "Intervallo colorato/Chroma.js" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "Colori" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "Configurazione" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "Crea indice gist" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "Personalizzato" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "Estensione predefinita della mappa" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "Zoom predefinito della mappa" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "Dizionario JSON di valori delle dimensioni" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "Dimensioni" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Discard" +msgstr "Abbandona" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "Mostra etichette sul poligono" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "WMS remoto" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Domain editing" +msgstr "Modifica dminio" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing Raster Layer" +msgstr "Modifica livello raster" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing vector layer" +msgstr "Modifica livello vettore" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "Classe colore fine" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database " +"user may have to be superuser and postgres/postgis extensions with their " +"devel header have to be installed. If you do not want Odoo to connect with a " +"super user you can manually prepare your database. To do this, open a client " +"to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" +"Errore, impossibile inizializzare automaticamente il supporto spaziale " +"postgis. L'utente database deve essere superutente e le estensioni postgres/" +"postgis con le loro intestazioni devono essere installate. Se non si vuole " +"che Odoo si connetta con un super utente si può preparare manualmente il " +"database. Per questo, aprire un client verso il database utilizzando un " +"super utente ed eseguendo:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "Tipo campo" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "Campi" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "Formato" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "Generale" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo Value %(geom_type)s must be of the same type " +"%(geo_type)s as fields" +msgstr "" +"Il valore geografico %(geom_type)s deve essere dello stesso tipo %(geo_type)" +"s come campo" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "" +"La modifica della dimensione geo non è implementata. Non si possono cambiare " +"le dimensioni %(data)s a %(dim)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "Campo geo" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to " +"%(geo_type)s" +msgstr "" +"La modifica del tipo geo non è implementata. Non si può cambiare il tipo " +"%(data)s a %(geo_type)s" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "GeoEngine" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "Backend GeoEngine" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "Dati GeoEngine" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +#, python-format +msgid "Geoengine" +msgstr "GeoEngine" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "Amministratore Geoengine" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "Utente GeoEngine" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "Ha tipo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "ID" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "Intervallo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "È WMS" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "È WMTS" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "È livello in sovraimpressione?" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "Livello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "Nome livello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "Opacità ivello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "Priorità livello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "Livello trasparente" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "Dati ivello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "Il ivello è in sola lettura" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "Priorità livello" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "Il livello verrà mostrato all'avvio se selezionato." + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Layers (" +msgstr "Livelli (" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "Stringa riga" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "Elenco dimensioni separate da ','" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "Set matrice" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "Estensione massima" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +#, python-format +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "Modello ${INFO_BOX_ATTRIBUTE} non trovato." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "Modello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "Dominio modello" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "Modello da usare" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "Vista modello" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "Stringa multi riga" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "Punto multiplo" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "Poligono multiplo" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "Nome" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "Serve fornire almeno un parametro LAYERS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "New record" +msgstr "Nuovo record" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "" +"Nessuna vista GeoEngine definita per il modello %s. " +"Creare una vista o modificare il modo vista" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "Nessuno livello raster per la vista %s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "Numero di classi" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +#, python-format +msgid "OPEN" +msgstr "OPEN" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "Campo Odoo" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "Livello dati Odoo (non implementato)" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "Livello campo Odoo da usare" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "Opacità" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "OpenStreetMap" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "Parametri" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "Parametri WMS" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "Punto" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "Poligono" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "Dimensione PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "Tipo PostGIs" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "Proiezione" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "Simbolo proporzionale" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "Quantile" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "Raster (livello di sfondo)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "Livello raster" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "Gestione livello raster" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "Tipo livello raster" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "Vista livello raster" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "Tipo livello raster" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "Livelli raster" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Rasters" +msgstr "Raster" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +#, python-format +msgid "Records (" +msgstr "Record (" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "Modello correlato" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "Viste correlata" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Remove tag" +msgstr "Rimuovi etichetta" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "Rappresentazione" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "Modalità di rappresentazione" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "" +"Riproiezione della colonna nn implementata. Non si può modificare srid " +"%(srid)s a %(data)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "Codifica richiesta" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "Risoluzione" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "Estensione ristretta della mappa" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Save" +msgstr "Salva" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#, python-format +msgid "Search..." +msgstr "Cerca..." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "Tipo server" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "Servizio" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "URL servizio" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "Shapely or geojson are not available in the sys path" +msgstr "Shapely o geojson non sono disponibili nel path di sistema" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +#, python-format +msgid "Subdomain" +msgstr "Sottodominio" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "The geo_field_id must be a field in %s model" +msgstr "Il geo_field_id deve essere un campo nel modello %s" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "" +"Il tipo sel server WMS remoto: mapserver, geoserver, " +"carmentaserver, o qgis" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "Valore unico" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "Unità" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "Usa per modificare" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "Vettore" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "Vettore (livelli attivi)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "Livello vettoriale" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "Gestione livello vettoriale" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "Livelli vettoriali" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Vectors" +msgstr "Vettori" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "Vista" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "Gestione vista" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "Tipo vista" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "Viste" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "Opzioni WMS" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "WMTS" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "Opzioni WMTS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "Warning" +msgstr "Attenzione" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "" +"Il tipo geo scrittura/creazione/ricerca deve essere una stringa wkt/geojson " +"odeve rispondere a wkt" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "" +"Si sta per creare un nuovo record senza aver disabilitato tutti gli altri. " +"C'è il rischio di sovrapposizione. Si vuole continuare?" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "You must at least provide one of domain or geo_domain" +msgstr "Bisogna fornire almeno un dominio o un geo_domain" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to provide an attribute that exists in %s model" +msgstr "Bisogna fornire un attributo che esista nel modello %s" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to select a numeric field" +msgstr "Bisogna selezionare un campo numerico" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "es. EPSG:21781" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "es. REST" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "es. m" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "es. png" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_contains" +msgstr "geo_contains" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_equal" +msgstr "geo_equal" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_greater" +msgstr "geo_greater" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_intersect" +msgstr "geo_intersect" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_lesser" +msgstr "geo_lesser" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "geo_line" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "geo_multi_line" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "geo_multi_point" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "geo_multi_polygon" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "geo_point" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "geo_polygon" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "" +"geo_search è deprecat: usare il motodo ricerca definito nel modello base" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_touch" +msgstr "geo_touch" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_within" +msgstr "geo_within" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "" +"la tabella geometry_columns sembra corrotta.Il controllo SRID non è possibile" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "valore esadecimale" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "in active_ids" +msgstr "in active_ids" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "not in active_ids" +msgstr "not in active_ids" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "srid" + +#, python-format +#~ msgid "" +#~ "Geo Value %(geom_type)s must be of the same type %(geo_type)s as fields" +#~ msgstr "" +#~ "Il valore geo %(geom_type)s deve essere dello stesso tipo %(geo_type)s " +#~ "come i campi" + +#~ msgid "Last Modified on" +#~ msgstr "Ultima modifica il" + +#, python-format +#~ msgid "No GeoEngine view defined for the model %s" +#~ msgstr "Nessuna vista GeoEngine definita per il modello %s" + +#, python-format +#~ msgid "Please create a view or modify view mode" +#~ msgstr "Creare una vista o modificare la modalità di visualizzazione" + +#~ msgid "" +#~ "The type of the remote WMS server: mapserver, geoserver, carmentaserver, " +#~ "or qgis" +#~ msgstr "" +#~ "Il tipo sel server WMS remoto: mapserver, geoserver, carmentaserver, o " +#~ "qgis" diff --git a/base_geoengine/i18n/sv.po b/base_geoengine/i18n/sv.po new file mode 100644 index 000000000..b02fbf617 --- /dev/null +++ b/base_geoengine/i18n/sv.po @@ -0,0 +1,1038 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-02 13:38+0000\n" +"Last-Translator: jakobkrabbe \n" +"Language-Team: none\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "%s kolumnen finns inte eller är inte ett geofält" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "Aktiv vid uppstart" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add new value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add tag" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "Attributfält" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "Bas" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "Grundläggande" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "Börja färgklass" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "Klassificering" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "Klassificeringsläge" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "Kod" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "Färgat område/Chroma.js" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "Färger" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "Konfiguration" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "Skapa huvudindex" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "Skapad av" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "Skapad på" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "Anpassad" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "Standard kartomfattning" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "Standard kartzoom" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "Ordbok med värden för dimensioner som JSON" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "Dimensioner" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Discard" +msgstr "Kassera" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "Visa etiketter på polygon" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "Visningsnamn" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "Avlägsen WMS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Domain editing" +msgstr "Domänredigering" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing Raster Layer" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing vector layer" +msgstr "Redigera vektorlager" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "Avsluta färgklass" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database " +"user may have to be superuser and postgres/postgis extensions with their " +"devel header have to be installed. If you do not want Odoo to connect with a " +"super user you can manually prepare your database. To do this, open a client " +"to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" +"Fel, kan inte automatiskt initiera spatial postgis-stöd. Databasanvändare " +"kan behöva vara superanvändare och postgres/postgis-tillägg med deras " +"utvecklingshuvud måste installeras. Om du inte vill att Odoo ska ansluta " +"till en superanvändare kan du manuellt förbereda din databas. För att göra " +"detta, öppna en klient till din databas med en superanvändare och kör:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "Fälttyp" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "Fält" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "Format" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "Generell" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo Value %(geom_type)s must be of the same type " +"%(geo_type)s as fields" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "" +"Modifiering av geografisk dimension är inte implementerad. Vi kan inte ändra " +"dimension %(data)s till %(dim)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "Geofält" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to " +"%(geo_type)s" +msgstr "" +"Ändring av geotyp är inte implementerad. Vi kan inte ändra typ %(data)s till " +"%(geo_type)s" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "GeoMotor" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "GeoMotor Backend" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "GeoMotor data" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +#, python-format +msgid "Geoengine" +msgstr "Geomotor" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "Geomotor Admin" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "Geomotor användare" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "Har typ" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "ID" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "Intervall" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "Är Wms" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "Är Wmts" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "Är överläggslager?" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "Senast uppdaterad av" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "Senast uppdaterad på" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "Lager" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "Lagernamn" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "Lageropacitet" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "Lagerprioritet" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "Lagerdata" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "Layer är skrivskyddad" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "Lagerprioritet" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "Lager kommer att visas vid start om det är markerat." + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Layers (" +msgstr "Lager (" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "Lista över dimensioner avgränsade med ','" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "Matris set" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "Max omfattning" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +#, python-format +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "${INFO_BOX_ATTRIBUTE} mall saknas." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "Modell" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "Modelldomän" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "Modell att använda" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "Modellvy" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "Namn" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "Behöver tillhandahålla minst en LAGER parameter" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "New record" +msgstr "Ny post" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "Inget rasterlager för vyn %s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "Nummer av klass" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +#, python-format +msgid "OPEN" +msgstr "ÖPPNA" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "Odoofält" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "Odoo lagerdata (inte implementerad)" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "Odoo lagerfält att använda" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "Peka" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "PostGIs dimension" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "PostGIs typ" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "Projektion" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "Proportionell symbol" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "Kvantil" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "Raster (bakgrundslager)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "Raster lager" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "Rasterlagerhantering" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "Rasterlagertyp" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "Rasterlagervy" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "Rasterlagertyp" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "Rasterlager" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Rasters" +msgstr "Raster" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +#, python-format +msgid "Records (" +msgstr "Poster (" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "Relaterad modell" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "Relaterad vy" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Remove tag" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "Representationsläge" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "" +"Omprojektering av kolumn är inte implementerad. Vi kan inte ändra srid " +"%(srid)s till %(data)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "Begär kodning" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "Upplösningar" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "Begränsad kartutsträckning" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Save" +msgstr "Spara" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#, python-format +msgid "Search..." +msgstr "Sök..." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "Servertyp" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "Shapely or geojson are not available in the sys path" +msgstr "Shapely eller geojson är inte tillgängliga i sys-sökvägen" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +#, python-format +msgid "Subdomain" +msgstr "Subdomän" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "The geo_field_id must be a field in %s model" +msgstr "Värdet i geo_field_id fältet måste vara i %s modellen" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "Unikt värde" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "Enheter" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "Använd för att redigera" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "Vektor" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "Vektor (aktivt lager)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "Vektor lager" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "Vektor lagerhantering" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "Vektor lager" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Vectors" +msgstr "Vektorer" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "Vy" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "Visningshanterare" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "Vytyp" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "Vyer" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "WMS alternativ" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "WMTS alternativ" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "Warning" +msgstr "Varning" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "" +"Skriv/skapa/sök geotyp måste vara wkt/geojson-sträng eller måste svara på wkt" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "" +"Du är på väg att skapa en ny post utan att ha visat alla de andra. Det kan " +"uppstå risk för överlappning. Vill du fortsätta?" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "You must at least provide one of domain or geo_domain" +msgstr "Du måste åtminstone tillhandahålla en av domän eller geo_domän" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to provide an attribute that exists in %s model" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to select a numeric field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_contains" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_equal" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_greater" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_intersect" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_lesser" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_touch" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_within" +msgstr "" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "in active_ids" +msgstr "" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "not in active_ids" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "" + +#, python-format +#~ msgid "" +#~ "Geo Value %(geom_type)s must be of the same type %(geo_type)s as fields" +#~ msgstr "" +#~ "Geovärde %(geom_type)s måste vara av samma typ %(geo_type)s som fält" + +#~ msgid "Last Modified on" +#~ msgstr "Senast modifierad på" + +#, python-format +#~ msgid "No GeoEngine view defined for the model %s" +#~ msgstr "Ingen GeoMotor-vy definierad för modellen %s" + +#, python-format +#~ msgid "Please create a view or modify view mode" +#~ msgstr "Vänligen skapa en vy eller ändra visningsläge" + +#~ msgid "" +#~ "The type of the remote WMS server: mapserver, geoserver, carmentaserver, " +#~ "or qgis" +#~ msgstr "" +#~ "Typen av fjärr-WMS-servern: mapserver, geoserver, carmentaserver eller " +#~ "qgis" diff --git a/base_geoengine/i18n/zh_CN.po b/base_geoengine/i18n/zh_CN.po new file mode 100644 index 000000000..faaed618a --- /dev/null +++ b/base_geoengine/i18n/zh_CN.po @@ -0,0 +1,1005 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-11-25 09:06+0000\n" +"Last-Translator: xtanuiha \n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "%s 列不存在或不是地理字段" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "启动时激活" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add new value" +msgstr "添加新值" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Add tag" +msgstr "添加标签" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "Attribute field" +msgstr "属性字段" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "基础" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "基本" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "开始颜色类别" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "分类" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "分类模式" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "代码" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "彩色范围/Chroma.js" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "颜色" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "配置" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "创建gist索引" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +msgid "Created by" +msgstr "由...创建" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +msgid "Created on" +msgstr "创建于" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "自定义" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "默认地图范围" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "默认地图缩放" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "维度值的字典作为JSON" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "Dimensions" +msgstr "维度" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Discard" +msgstr "放弃" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "在多边形上显示标签" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +msgid "Display Name" +msgstr "显示名称" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "远程WMS" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Domain editing" +msgstr "域编辑" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing Raster Layer" +msgstr "编辑栅格层" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js:0 +#, python-format +msgid "Editing vector layer" +msgstr "编辑矢量层" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "结束颜色类别" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database user may have to be superuser and postgres/postgis extensions with their devel header have to be installed. If you do not want Odoo to connect with a super user you can manually prepare your database. To do this, open a client to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" +"错误,无法自动初始化空间postgis支持。数据库用户可能需要是超级用户,并且必须安" +"装postgres/postgis扩展及其开发头文件。如果您不希望Odoo与超级用户连接,您可以" +"手动准备数据库。为此,请使用超级用户打开数据库客户端并运行:\\n" +"CREATE EXTENSION postgis;\\n" +"CREATE EXTENSION postgis_topology;\\n" +"\n" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "字段类型" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "字段" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "Format" +msgstr "格式" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "通用" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo Value %(geom_type)s must be of the same type %(geo_type)s" +" as fields" +msgstr "地理值%(geom_type)s必须与字段的类型%(geo_type)s相同" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo dimention modification is not implemented. We can not change dimention " +"%(data)s to %(dim)s" +msgstr "地理维度修改未实现。我们无法将维度%(data)s更改为%(dim)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "地理字段" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Geo type modification is not implemented. We can not change type %(data)s to" +" %(geo_type)s" +msgstr "地理类型修改未实现。我们无法将类型%(data)s更改为%(geo_type)s" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "地理引擎" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "地理引擎后端" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "地理引擎数据" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js:0 +#, python-format +msgid "Geoengine" +msgstr "地理引擎" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "地理引擎管理员" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "地理引擎用户" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "具有类型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +msgid "ID" +msgstr "ID" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "间隔" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wms +msgid "Is Wms" +msgstr "是否为WMS" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "是否为WMTS" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "是否为叠加层?" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +msgid "Last Updated by" +msgstr "最后更新者" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +msgid "Last Updated on" +msgstr "最后更新时间" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "图层" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "图层名称" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "图层不透明度" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "Layer Priority" +msgstr "图层优先级" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_transparent +msgid "Layer Transparent" +msgstr "图层透明度" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "图层数据" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "只读图层" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +msgid "Layer priority" +msgstr "图层优先级" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "如果选中,则图层将在启动时显示。" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Layers (" +msgstr "图层 (" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LineString" +msgstr "线字符串" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "用逗号分隔的维度列表" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "Matrix set" +msgstr "矩阵集" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "Max extent" +msgstr "最大范围" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js:0 +#, python-format +msgid "Missing ${INFO_BOX_ATTRIBUTE} template." +msgstr "缺少 \\${INFO_BOX_ATTRIBUTE} 模板。" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_name +msgid "Model" +msgstr "模型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_domain +msgid "Model Domain" +msgstr "模型域" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_id +msgid "Model to use" +msgstr "要使用的模型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__model_view_id +msgid "Model view" +msgstr "模型视图" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MultiLineString" +msgstr "多线字符串" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MultiPoint" +msgstr "多点" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MultiPolygon" +msgstr "多边形" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "名称" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Need to provide at least a LAYERS param" +msgstr "至少需要提供一个 LAYERS 参数" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "New record" +msgstr "新记录" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "" +"No GeoEngine view defined for the model %s. Please " +"create a view or modify view mode" +msgstr "模型 %s 没有定义 GeoEngine 视图。请创建视图或修改视图模式" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "视图 %s 没有栅格图层" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "类别数量" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml:0 +#, python-format +msgid "OPEN" +msgstr "打开" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "Odoo 字段" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "Odoo 层数据(未实现)" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "要使用的 Odoo 层字段" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__opacity +msgid "Opacity" +msgstr "不透明度" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "开放街图" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Params" +msgstr "参数" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params_wms +msgid "Params Wms" +msgstr "Wms 参数" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "Point" +msgstr "点" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "Polygon" +msgstr "多边形" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "PostGIS 维度" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "PostGIS 类型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "投影" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "比例符号" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "分位数" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "栅格(背景图层)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_form_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "栅格图层" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "栅格图层管理" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "栅格图层类型" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "栅格图层视图" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "栅格图层类型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "栅格图层" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Rasters" +msgstr "栅格数据" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml:0 +#, python-format +msgid "Records (" +msgstr "记录 (" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Related Model" +msgstr "相关模型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "相关视图" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_with_tags/domain_selector_field_input_with_tags.xml:0 +#, python-format +msgid "Remove tag" +msgstr "移除标签" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_geoengine_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "表示" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "表示模式" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"Reprojection of column is not implemented. We can not change srid %(srid)s " +"to %(data)s" +msgstr "列的重投影未实现。我们不能将srid %(srid)s更改为%(data)s" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "Request encoding" +msgstr "请求编码" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "Resolutions" +msgstr "分辨率" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "限制地图范围" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.xml:0 +#, python-format +msgid "Save" +msgstr "保存" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#: code:addons/base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml:0 +#, python-format +msgid "Search..." +msgstr "搜索..." + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__server_type +msgid "Server Type" +msgstr "服务器类型" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "服务" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "服务URL" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "Shapely or geojson are not available in the sys path" +msgstr "sys路径中不可用Shapely或geojson" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js:0 +#, python-format +msgid "Subdomain" +msgstr "子域名" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "The geo_field_id must be a field in %s model" +msgstr "geo_field_id 必须是 %s 模型中的一个字段" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__server_type +msgid "" +"The type of the remote WMS server: mapserver, geoserver, " +"carmentaserver, or qgis" +msgstr "远程 WMS 服务器的类型:mapserver、geoserver、carmentaserver 或 qgis" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "唯一值" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "单位" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "用于编辑" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Vector" +msgstr "矢量" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "矢量(活动图层)" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.actions.act_window,name:base_geoengine.geo_vector_geoengine_view_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +msgid "Vector Layer" +msgstr "矢量图层" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "矢量图层管理" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "矢量图层" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml:0 +#, python-format +msgid "Vectors" +msgstr "矢量数据" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "视图" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "视图管理" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "视图类型" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "视图" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMS options" +msgstr "WMS 选项" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "WMTS" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "WMTS 选项" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "Warning" +msgstr "警告" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/geo_convertion_helper.py:0 +#, python-format +msgid "" +"Write/create/search geo type must be wkt/geojson string or must respond to " +"wkt" +msgstr "写入/创建/搜索地理类型必须是 wkt/geojson 字符串或必须响应 wkt" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js:0 +#, python-format +msgid "" +"You are about to create a new record without having displayed all the " +"others. A risk of overlap could occur. Would you like to continue ?" +msgstr "您即将创建一条新记录,而没有显示所有其他记录。可能会发生重叠的风险。您想要继" +"续吗?" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "You must at least provide one of domain or geo_domain" +msgstr "您至少需要提供一个域名或地理域名" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to provide an attribute that exists in %s model" +msgstr "您需要提供一个存在于 %s 模型中的属性" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/geo_vector_layer.py:0 +#, python-format +msgid "You need to select a numeric field" +msgstr "您需要选择一个数值字段" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "例如 EPSG:21781" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "例如 REST" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "例如 m" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "例如 png" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_contains" +msgstr "地理包含" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_equal" +msgstr "地理相等" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_greater" +msgstr "地理大于" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_intersect" +msgstr "地理相交" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_lesser" +msgstr "地理小于" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "地理线" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "地理多线" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "地理多点" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "地理多边形" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "地理点" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "地理多边形" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/models/base.py:0 +#, python-format +msgid "geo_search is deprecated: uses search method defined on base model" +msgstr "geo_search 已弃用:使用在基础模型上定义的搜索方法" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_touch" +msgstr "地理接触" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js:0 +#, python-format +msgid "geo_within" +msgstr "地理包含" + +#. module: base_geoengine +#. odoo-python +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "" +"geometry_columns table seems to be corrupted. SRID check is not possible" +msgstr "geometry_columns 表似乎已损坏。无法进行 SRID 检查" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "十六进制值" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "in active_ids" +msgstr "在 active_ids 中" + +#. module: base_geoengine +#. odoo-javascript +#: code:addons/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js:0 +#, python-format +msgid "not in active_ids" +msgstr "不在 active_ids 中" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "空间参考系统标识符" diff --git a/base_geoengine/images/map-hover.png b/base_geoengine/images/map-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..14799049f5fdfb8e1c2eb438ae4cac0cae7ae593 GIT binary patch literal 113834 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 S_pBWN>X4OGlBf|k4*FkVS&8@n literal 0 HcmV?d00001 diff --git a/base_geoengine/images/map.png b/base_geoengine/images/map.png new file mode 100644 index 0000000000000000000000000000000000000000..17214344b2bd8d32519c22ef8dff339e1345a9a6 GIT binary patch literal 71907 zcmeFZWl)t-`!7thX{1X!wzPn>bax9#H%LoMNSAbXr_v$~QqtYs-5nyH<@3y$dC&aM z*Z0Fa^X?f(aO39Q>%P`?{c7!S6(wm5R1#De7#Iv$83{EQ7}(Q)e;{z+UuIoBV8LIo zAJwGAU@Aw+4!}1kjxstQVPLR~|NVh26)v#`|A_1&t0;-QjE;=LMYEScA_W6O2_q{Z zs^PJC?4#pIGv|4ONFpHP2+!k4eEQpwmvhr<&Z>r4hi0kv>t^B>vr@08<7MoK4!K(R z*V=cCO6Bo{OHP||bmo#u$FlDa!N{n+uTeI);=*@&G8{Z|$`6BcY>rxAM+ClNYQU|A;kl1O0( zeA%fn`tK)-oxzv?$J42U#Q*oF)%pJYRCDEfW`fAx{Bj$2clS@9 zTGr0SEb7?Wu5oTZ=Xe}dG_3C2sqtqO`}Z2^!F6ZczlY-O(`1YkTa)Nh>d$>GFW(lp zx<~U7;DN8>Q|C*#SKbY^zZ!^(Ib2`=+z8Y9Ss7oFFQjFpDj2)hWWrl;ec$xghCed- zxa*2d{qEI6baZrfHhIUIp`qc~g~#I3Qq9s{j^CQzj1+KX4E~*XMulsRt-!vE zIin$XO-;>9fd)VM)CM!|zlO*kcHD=_jGpBflO8+XO;`kqB7gicY$s?W4A(n8=cka| zx|jWlOHp03{@XX^oH4>k$;jULp&iFzr4scySDC%?axD!F?{#>Ja}Pm6HUsbTPUJO@ zt*8Q|2rYbR7G_^+t=p5Ssn?+wTOajg`OwDcVu_Uw2U+eiWoQ|hnEVv{gFCez^kw>_ zF^V@X*q5aHyoaj2SC^LHv2>XUN~TauvC{_x=yG$8RT9l&r%IG9>vU3v%P()%6vavh)Fg?`iA@87>)7j*pj7f|$2pO(OEaI>+?Ua5g?L zO-)T%yeGe1yja$_#0&c!rn8;Z|Etj-B6L%xd~$YX$w54yL>`0e1=*z<$2gHtO}zQf zLxNgWUteEcos)xuLqOojk=K48&+K?j?XgiY?|{2%%f0>T<*))~Xn{7fS}BU`(}Q<* z|J;Gg?v*DAG`6Z$h>|4|X?e%_pt-W#Mkoi_=Y54%#JksQFKoFpX+hS zIhkyJ4@0aeL-q{~-@lJbOJJ~f%SUi?&xb3_PjjL6~bTpF>-q7C8?nGd7e+eOg=I-up?eFs) zQ-m5b!5hVl?Ci?&^7PcyajuHy=5#Y^61tS3;JF9y)eXnbAI(o9e-WImD=JQH2ljb( zqBC4AAGmb2h|I}oYR<2Re6_C8W-m)jN}|I-d7Sw3=TB`d2bF}Rq@*CZA83ENy1I|Q ze;>GCJqY&3r&l@4)~uehz28yT8NQcdW@DQYhg_=R^&Yqcj9hGg`}S>kWF#so%GJf? z-n$)_L8;#x_W0x^4nsS>K1P=yRru{;9P6vp&AoLscumonk-aOkB(U|Nk`iwB86y@S zoAhe5uf5v9E7aB1`91IXJ@@%N_08|y-`_ht{c`v@F2u`A$>=A2|BI(x^oeejHEXM< zLhAz;iO>B;=*|@J%a>pvfC>}~v*Id0@}k9YYSQEN-529}4rxmEhDRbLb4Jyt45Gq$ zxh3;+&ck1|>k?uigp_<6J7S@nE%-{BsiLA{!$_?xv2P1D)_1o`{mA#xtCqT(gwQ=f0oCnq32Fgd%IB1m}R~0Coivn&h^E`MRBaR zX7?6+68=&v1T9sbNZsIGI`D#wTa6v{RII)h5{GMU~N zbo2eLYFt^lt}0VF%C>vx)12R*6mOaD#jql|M&b{6lu4ieZNLHV?5wP}u7`LpWu>J< zvGYOYKx&$s%a0zPo&-nx1+DHSncp}!k+B%|SN56E<&1U5GLUA{Ydkn(SD2#4A!|La zm~qH9;|9H{Urg%Otl255-?8`oAdK*$EKgz}NV%Z}1LiLHYP=ioYGtWKH2Wo=D z&vB7Xri)DTf)>&5rJE2R-@{SI^HD01TG{mR@o`GW(~h#wq537&+rLj&>sI*|{7Q9$ zdXwAVwV7+QkC&T1=30=A9ZZ#IYQ8~;*?R9UB0|>e=dj$EcjTq7|MEqpG5QXVldVif zKF>}bh&^7Q7@&w%n0tvvYG(VJFAOKWh{c{EyGIwY7PjHiHD|A^3EE zdsxyIk6#(HC#_}CKfH#Mm*pgO;3ta)+aR*{a)-@t!KR*CjV@upDt&f(8V@t{_wU~) zZUVy%S9@cB*O7(y&(4H-d1K#vSRiQ6((Jl8qevLjnLH2ez$AfdgZCkG<8cl~KNM8u z`}Qs{=e(>W+qq?>C#2J;x~%M=m(Y-zi7B#g>%e94=tj3fi~R)@{TicS#=fC@llx;s zEZli#c3@zjHng;ypNFTRrG*q7X)H&$>gaKNJodpEG#3b!?)&!_XTN?)v8J>*@5rgE zCv1e0VImt)dIwJv>2}7R`OlLTm|?bnIt6#uK}@W(P$`auODiN}e8;)0{IO}w=alVv zlg+G2kNZR(hfAGX{h_66vptI?2BqY^t}YyGlV0WDr?J01oYwWa2?K@s(4Czf&{iud z?A+XDE$T4P(J2!pArsTnE`J_xR#y#l^zlPc9;MUf>FRUialeQPzOEA=sKV|2{6pkh zY{o~cHmNpiv6#_5$o*zCGgn6bH3wC+}UD!HK0ZI2hlFuRf{g^t!pe$b4QqNa3mY5FA33GFzFV0^4n0wR zbElwBt%Z|a7hwuJX9P+-=Z#M(_CA`LSxP1OP`1`{G5Ung502`RlEL}VmoHy>NFXC4 zi|386uT$1;xayxB9EA6pY}+J!HJpG)k=1=x)ftD%E^I>9=$)Ko(-8kYZwWtd^$Fd+ zrjh`S{P2*GSuV0Spa_0jS3De=rq(GPEas0sT$1CvXi>*U7JYJJC#f3HN!bHSy)Tyc zdEO@VYY6dXX;RQbfi1THJ39>HG#3jVDp-9HwLZw*%?)3c62gPeUCWx!^@KFIo}(ig zZmvQ~|8Z~=2?z;;vENl0NbW{22#db!*>Uc)VBnV4K*vOpYi=!mote0Hwzj-nC?`(Yr&N+4myS@Y+ML*W?8p+IP6n?uq$%h;=}J zep8dDo7<0uh7^gwyS6hQwvH!f2Zt*5hrVd#EpFr&>9W;@&1!1z;{H~YmiF&Bv!+CH zImJV;DXi-jV$;OHzZBYc*Z$CE&UwBrsnTn@T+bFbumo~(_V@X$yjJPNkOhgv!JXOO-sT(=gy(T!Op1^yP*+!Hx9v5a5OpHz z4*fUacbr9SgrD(bntl5Qg!+T#p zKR*u-ZE}qLOC!6<9dlLkx^E9sMaE{mnPr(ynVt5IpTL;Z)C9lZ$EWSv-XPN4^RrMK zCVAnHA3uVFgP)&$)%-tw`a}~a1I0T8Rq2Z8$H2fK{5TOaXrQ7$2cCMP7`QLU$vHJU z>!!f_z(Qj@Y!mJViR_)6pKok!{ep;$IGI*wE7HgNvL}_s*vHWkdm3O}0E)KUT3q!h zNJ+nzm5Fi`_HFsc`b;O9B1tw;a;vH)rlqCzQTXYRAxY>mCzJBn$C9wBd)8=!PN;E4 zh#rZSIJVc)+#G}*E&=zw@`yjk)j1;F6+etU_RHplhfod{QXn1*YvC8I_+F=={$~b< z3Wc2yA3gxgrfH8}cl_($Ly9qp!|dGjlGld=ZCOzNQF?C;}{a0XQ z#mP{*Ardru9z?B20J5k10uaryk&!ftE9t z-*^bc$h~>&B5XeoSN5g`VBa$%J)N6}CyqFXGu|`Q`D67izUc#e&_=z=c(_R3>(`T_gEisvx$W)kV5{cCi|1i0IAb?Z zCC3%B9^-Zev(FqJ9vt{*QU^hT#XuRI`ThNE{IE&WZRSv~OG-i_V@xPEJUZGX@A+_P z&PQW7nuLfQqOGHYVk|dn49zL6t;J!rB4ZhN(>G6slw&zCLnQnxjJ7@)CQR*=A+NGh zTq}c^215 zOv+I^#|uV5r3&cG?KKIPDgbOOq*lkG;M?{>oaWb~$ExSUs^Y1G^mG!Z{W2OIn7mh) zDzWWYv(KS^_o3jvdtWBxNPNt6;Xk>0Pgo2x1)c^z>RbaWQLV`?g4#G>QxpR;%G-idp_ zDw4(rZg1*cZo}qm415IHj0GU2`lec0~NmOY)uY1vyRp-~xe`D>Qpp=4tVHam;dh;GKZ+VwLRR@_}*14?2X z2>K8jA#0d81&J8FOyu9$hIYi${iCD6Iy8TKJQqPgAvrkUOoemCLc5K1uHFz$=bAQ& z0Cnf@W7Xfsp^m2^(8M!F9{>0@iodeSNTgpZ z24{EecWq*M=i}m7okPe%aMEBnKm74U_<%}fzuagHoiw@CHVFc1i{C+tFN$gOP0xFW zwwb9Zny<37g+?a1I>xT9_y^Bc_U{Y~lzMD1JqtHLeQ;+~eEljvcM~0r38az%v-}Aw zE)tB;Ze_s>gkQ*MavH8^%?ZWUfG7_VB^#EPM@K~sB;dkPnDdfhR?Pv~DmTwGB#?mZ z12cI{A3HIHI${D}7GiRXe|yY9ow?BofXQ5v66GS3!40?uEhaVhgG^N-f_VYz_h?jb zRTr^C!2br>AzkXrYQ|`cm32pI=dppnK=>yUSJ#^o z;XenUZ7X|k;%>4t`FMGG`TCM8hQ7p<7RmvA{uAJNqDR~rEJ<<|-@X~i71Y6(jE#<( zn2R{0zGjv%%Xdb28W|nUe}>h-o1aF4CAlOd`e+p*ca?gg zhbrdgbh8A0k0pMLRYX82V0~0Ql#_J`5^b@p*7TK5-{^z90?TWpLqSFsoAONss^W)q z6_F|!Wbswc;5qQxc!Mz_pfS>s_bCs{2eMpZy$Eoi$$HQLn@zoLjdR0-t>N#*xrkm9 zKR@C4X;n@b0X95TgDOG;X?9;I-r$b&c|A8bw@o?{lK&J=VeHV3bJH>?&JOQmQwpFL z{TpO(0x4ZZ#z}s+bvgKAdTm}e;SAY7Ct=?fgMy3Gme4xc--nVg{%dT0KvWam1pg;n zSpi>MT$~`%+{((z!~_oBM8;`&@9M(ises}SG^A3SS+`=AXU!X|WDp~=N&`K-KvhM> zg6)ru4P%8$j-l=bW;FBNhinDdRwx@=pX>4A;o#mCcmTrjI;C{pykV*1x`^#18QGWU zXt59yV&XXW=q$=iz35|F*V5KjZ&TB5`-YM!YlIB6GUhMFa>cPdO9zX?A$;l&D^fdj z4T%GU6OhDd%vsLH>7FH0A#J+;-Lc0<{u%feViMGG09ZBh*m0A7adAqmBgYKw+@gb5 z+IE*QBNThO^ZV-#7E{Bul*epFObuo$hu>9BbLPWbWm!4DfB-23Ay-U=5;Z6VNS%J- zt4;aPj{C?CXx*@-@NXT7@bwV@&D2Yj7EaulX{h5Mu3@1Fv;w4nGX zt-WmjeM%FD%ozkAi0~CC{Z1nl&6)6UltrpWqCqTg6d)s-1qKqRj-%4Ex8uk30RrD< zP^Bj-l%|k=v^*&L(AWBt|MOtKi@Q4^YVgB@C!XD$>)V6@E-o(6aw{rWG8eDLgmZ>= zPFv1|G&PToj&{%(8*V=T(9+Zl_WWRM3|r5=<7Mm;>k^RIV%C_z=af_SR9SShC9Z=F zwHqf8wX6P3Sxq)W6!y*8RwODMLugWl7VZImk%zj`7$}`?GStpu9jfL6)HL5aIw%P2 z|Jg%<)yuE_MCOV&7u{NXtgK2^pqac*a8V>&ic2di!5EP4%y=wNRcwasPnLeSmi{6} zo}Ld~!Dxq6%mhO{Jv|Q3yAFWVPP0loxup!%|M(Fy)%hhKimJP@zCM;EkRn$E7IE$G zpS6y?w`TxV1N?3^@i{$!y%I31&I6$A?~Y^uDSqkp|ztN;8+K`S16f+~LK ztlD(mK`BHD9-bUOFJ`g_u+n}Mn-3o{a&maM?28C7Ffhu?l@t{>IEY#4Xesqh#qxm6 z1LPurwvy%WQe;uOdv?$H{#rFN)jj;B{w9bZEPAz!oxt#ZnXUs9$G^yWlAw(qTNWDuL`7aZOWv65ZqJSC_gbf%;Frh(e=D$axsV$IV8IuCw zbG4b>T>d>i<95btGp+xmTr{B<(WY8;=Os)1iXDK0iWb_PUTkM;%bPV?3FP6?QJ|TL z{9avNmKcY;vBMV2eEW$zPUiUZ)OQ2T5WKv^hR!gqW6oqNub`m!Mi*l0Hf7bpfwh@F zG06n+F9}sV1*EW|I5f0KiZ|*~&jfBV{!nLsmW$iLw#&rNCRi?4BEkcES511D^07yA zRcKV$(C{iFrv#;v9G_dAz+WcZTE5?dUj+it0c&>jBHQoT6M<5#`&V0Ao3~JmjZS$v zxXP|Z?xjG741al)eV~@rXn$*Kd-)naOc97Rk&%(>K720@lJSQn%ZM!H#$JedAIKZ3 zX}WrNG-@+bC&ImXr>Ut}GL_p8-l&Q)3j4wGG8y%(ap&9T`z?(Z*rFU(Yw!un!2W1) ztH{rX!=T6=+i#8zy4PSVDnI=73rQ8{2ZBmev7}RBXbyY}M zSXnU+^m zS@d){Gowi*AuWyERhd_*vd(8cmDpukd=_saKXB6taMQtb?$Yh`HRZ=P73fc~(9REa z3qXU7#Zw0x9UD(OD^{gnbzyuQ#;X?!MlfY-RegQZa-qg5*7G(H-b<#y(f}2iQ&<=a zZF*T_m@&xI$m&DcvW=K91k|o8( zqfqhV2RCQiV4FxrMn>G%h1FF|n&^DcuvqM?)S7fW-WnKFkdSnJFFbmD*YP+5kWV9m zN-To;r^w#T%}oFo-k4Jj`a}Q$JS$7mdRdRPq}+xU$Mb50=Z~*29{%NX+^C2k80Z^; zz$lP(6A*H3(gVMVHRXf5`#Z>Me*Sc&lB&c&h8sr96W5dBQ(W8Hz zd0f3~CnO0VqkT7t&X!i@@nwNdfO|)4NW{`|4>X!)C!2pVi*%awrC?BXEMQNQ%3zJb zFa^vyHqL54ffATtog&;s(}hc*ZTFjN1By=$%tugqmXyD1glj5Lzw+--?rsO~mjvK;ZgweSLk#=I@!4 zUHJ8#H{*ud;-_xb|2>R8eIji~ZiMaB10d1c`w7U{hx_~0ODEIYzP7gLaBufBxJN0d z$z#;NQbthp9f?q4LlB02Qq1fWx&Owz8yMks1s=M?#yPe?*oO!ak}JJPZB6FivAhui zuw_4Z>zAp<^ZUJtLYAlB|Egh+0dJoUE)u<#6(hd%8xl4R>EiM@H)uTo_~W6rJzWl| zhhjUhp-GyTA08fV=f4Z{DJDj&b+xp#gyQiFaqlK)+OK}$LcX{?79}YHJ=lb9`jhAv z1fi_#>|3w4@$1+2aWXweH(hI=o_I;4De`iFc@0dbRA&|H7j3=-1O((h*Q#=-eH);| zHtMnBFs-LZJ;it%P%4VI7TbQA3g$h8#9%oJ?$Ug*{P2NEtr8vI>lHa(F5SzOP~cpJ zUGx#Yio|zce|qvBSd+91Hzisg*J;^K2HjAAypO0gM7eAsL&r6b;Rl$V@>>A8l$DjK zKxvQ8xM2IQBq*^($ViFL#KOR)P8oXh_N`AV<#TlAyIjeq@0q=fxL)tx5hmS%IVDDl z`lvC*WoDWm&obz{k!oC+fjlb+Z!7{pD^S|>SqU#ZXmJ3tD*YqC&kyEMq*~-S!S3!Z zC~ItwKrjE0I`MjKJa!RcG7lBd8NoI%Lxy)PTml3f5d6hOT|-0Z7euHzJXTtCB~o?U zV*WAC^Ssl3J;NGWT7x@=rN)w=3u_VOsX(zIjVty&t43;~mX1`2i^6xyA44{ZN+o>r zfrN}->oH(w=9l}_o)6XDrv9F0g0X|==%fwz&ezL0-Iz3N>)yIGxtqLS0^HE9l0?IZ zMS42x32cay{D+n5>yRfF3K%6=7B-pJ(r5hNE^0!5pSED(2zU8{1|Y^RkLe)W2F$nL z-tAxn_CPizmhE{=kOMo{{{WlxL&xn0FriYFWQMY{vrqT;f!w?wW2}v^egx6((Lhyg zZ)#c)gxs?RXaa8a?*-viHE=%uI8GBZco!GGnu%fyftC0w_|W2L9Z(CzbeX&WA$$8j zfgC$@6;Vq%U&z<=f-k0Ek!haI3X_&>XBE;fRVzkzByhaGn?<}%T#J;T=FT{od1n}W z0an%e-nBMt!1nC;7(KLmpY&b4$}rWiv@4|hL(W)3L&KhP)9u~e2%4P&)pR;BvWS+a zAi1#5BbSXU)tC?-s^+_Q>SC?No3Fxw+LhRhsNA%2Ix{ol!v9uC=+u!H%qoCK``?N* z&!VxliWrz&+&&Eez>!EVJ;T1~q`hfD-WO@c(bV1!+By>x(~7-2cg9;@UPt~ckUIcd zz`o&qu_}BH`Hb_}-j%WZwRF+_(9MnOATNICpU>=f>me5&f@umC78djbk-%`^TR=`A z_R1!EV`oYt<*qVMwtKM$#|#9}7+K%x4}rMD%f0hIr=5|o%Lt&>w9@9WGqP_{&)IB@ z6crR=mlC)l0OYmeikQtZngPma7*V3Oi-4Evz{9}N4G{EP_@go@&C{yciO1kIO*VhB>5b!&|Pl1g0Vl9pV zH}HH?o^3$%k%JguZS9KL$49T}X~~_kwzjv7(+2Tq^HL<5hM+gRf@KNi-5Z~gwdZbta#-6qAWq3fyrZJQOtKF%I5f1Q zl35^=*{Si&TDu^>SQjGQr6(W5{7SqkT$?#$-cEcl8VxNM+{cSnIRn0gN=fzanUWu@9|u^*+q11~mU7p^yF*{`Q$ zHbc#98Vk&b}5V{(~5jU*sqvU+`vHy{i3@@!P#=5MJFmTn;IIH5h&tIyyQ&K7T-Ks?nAxln~01?m=v? z{r)|upMYq0lYKf!4=xrH=(E6`0iD@eZg+!DKF!P4-rl|oQxk7zvPj;oL3{KvfIrw;6^2dcuZhly0XSbyV#AUb5`WOt3g1 zFw`+)ySv5tP=65^lzfdBckAmgg$_`4TM?n09KbupRnz;8r;nNqbacSQ3^#EjRrbZ0 z@QE$u>cT%Zgm>?HiiLsl0fxpDzHG_VWhZt9VPr4ZUma^$V|B;bqM1y)rcSAUb(~>c zH2fO32C{N|z%W!}B_TZ%>{W?OUbG*f%bipC#cH*d7MHmwTra6+e0wgvhl|c zt+^X;mu!Y$g7sAs!DhLAP9wx+X9UL4+3Bw+Qkm#b4736wyO5tgiA+JtvX~JP)NkLu z4HnDG&ksmugRW`o>qq5L?vZ2GmzSd=(a`bR+uDkJoL^YbF)$EvKV7bR8mt0E4FU_8 z-TPX2ba<$WN=k>#fQf&Bdm{$%CW+~Dk^ztj;I=_3kt`s8$`ls)Mb(a;d;N~F&b%ZnjEk2CER)Pk>=SdBekQJ4AxW9IOJ2M={4zW~9L zizF)}6x@4{ zYGctMmOeAObRtpK^-$#D6Su0Wssc_9#*uXSPL)KUd2`JO^U0A(v%~)}0ni3;^z!lm zozPY}su}0FU^sR--X0y|&yG}YHjIuV9Tm^eFM zK0RFR+r(g#$kl;2nWrM7inl*^dA?}-1H@k>RY^!lVn>yVh}Fw9^!2mG_7aenf9fPk zHZ?Wzy?xu(&|v9EIrR%HTK^A8O|LKTC^Yx_BwX8x0mWrX@EGmI)=DL~QwlZOJxRUs zG6opqf3#FpK`bEYbLa|&gDBYEC!F0U3`d-_uR+&Pm~2F~knBC4w2ZK1?D(YMx=_m8 zlr~}!h;4kzOBG#;Y*d-WBFqkE+VlWr1r*;y^1?%Jt9@sfe4m6Gz7JSMMBS5p%|ivw!y z}X?in2_^C3nfCYgo1RV8r}|*;R9+S6k(=6^m~1M@D@4(9M}mF`2aX( zjQr^6F#JzSEiiviECQn_)d|EZ11X*;!4TyjZdoCRApBGGT2?UMWM1;^Kwl*KgS4gN zr^(pC*IR&?X!yn524b8i*>cNs4t8~QwcV}CZ+#(KjEcfI7bva)ZC!z!SM-aZcPfNO z%u_O*qvoTeYW%?V{{H^V*LN|>#&1{IEy=-(!QVgLKT$rWkjM|h9Q@=J)1~28BKqdR zF*U5DdK@%ucdY|NDUhoJ7{Hl`Y$3+Q2v1i@|5JY=08FVF88lP1-@bi`&Po3WOpMjm z14mv)M#l2;a$D|E zr5l|QbBT7P(TOHaVe#Y^h(;Q~P<``;>ND0O&L|;G$Tzx7fk!%Hg>7u{OlA@$bv35U zUq&DCWT@&u)DJ086eKL_(E?^MnltmELOE3`P`zfCvb;Rlw;Pn6s*1s&j4yeNdPN$v zKuC7`HGZU|M-#@ikAe!{zlfWAVWnEFOs{GKhnzQdXOe;l!&Hlzg())ueA3w1nE2l} zWJvoNHty>Kh0V346M0AcUBnkm*vor+du6h*R8PB)H%Cy7O&9(bqsFiOHz~H+g%-FC zwYB#T4q#0Kguns<<4fDnFy?g`c-xQO)3}&YF03iyJ-tz+JU~HxxY~QcURloQrMmeZ z82hFO5lZ+3cd;iNwYw%^*>oa@VIIbyE0&jG6Hgk=g4{LnT%W&$1_9w5M1 z+l% zgqJl}G9<`OjtG(~^Jjs?v<5w*sd|JU(yp~DcQH;$C72zY@FlH#e`14aQyhaWo%DeMqps4FLm!izqf;Kd1YlA+8D-uBA?PwR$=d|NxaJV&AmqD&=*BwXy`FV$e! zmNJzn=Ku}4_)s@oA^_EN!VLI>SeTf(TEx5XB~v<3ym6Pre4~j>tfpGbQ1}V9y|J7Q zj|=LRd}qEa)BTJSCjc5!%VOAmDR+H8mcUW#Kzw+w_0`qbxYND?Bz&l^;Z!GOLi66L z#8T+2T_%L9g+W*)xc%}}O3TW0w6$~3Ir^6YFaUcgz4+$#R?J!zuc)%p-rKtsOf56m z4|R{sG4OA0B|AX{8hZqMu3ca@S;zME-RwbO{3AC(Qz`(#Vt_-7DL^;ZV-20hcL~Cd4_qXBA2lJRK<+~B!J(;{ z6zs|wJm8s;8VE>VO}ry78MYKPOxfb1EFetmu&&4*GJk2eJCpX#+AEBPhRKSKlJ&yLUR z1I$ztQ<44ZDf6_W(xIqa%F@;EVSKyvRBQCsDxgAn1-@~XR?ey-E)+~azyHq5%WH1t z=S#*j6n#xhg`nGEVgyEiXTPhfYi#v4|NZ6I22H;q)J@8q_dpl-{Jj~^^5n_C0PolR z=X;L4^kNV<%o*Er;Rk^p5YBRU=b^JQA{~q=+2=}=00I!mNevDT24V??xgWa;Om2b~ z2Pmm@xIc~4a{Q??v(36;39upT6h%^yt_coC6j$n?GQ23o{jOU96d+*t0f>m#2$zB9 zQupJ>?97a$Zj&Y)(bR^cUXye0)`j5pxVVdv_F}>b8EWwOGNy*TqY}X3@f`mO$BAYx zf9XVOd_&cEE5wt~b@;_N$UKS6{FGlTNo+P)qOvi4WxAigkx((N9k^^B5h(;YtK~tQ z_7jWWPwZWZVg~5>CK^9Sb4h{7{us6ng}UHZGh74s4=!$Q`6sl3)*jzm4cMC5s4qyy z7>e#ehUryAfD5^{9U$Bw*A`}K4YWX{K&w5Xn7;5qcz+QnUcRQFWSDfpL|z`1#|tXs ztx{}3ApwDY5l+pO&O(Vzv9Po>;`!gsPeQ&{mX>`-H`%;ST_CYLm(zvO zxdi~tc-5<;nc=PJaZH+Ul$jH^p&}EEpP9zzcBdyNc|9~Er@N;FxiVZ6zrKNk1k@?8 zu?~Dq&?mr!$b=Gyb~H34Jq^fM5O0k>ePfKJi|mSs?RY%^P9+T4dp;BwiKMt+f3D5~ z@xZ-TyB3TohC>Z+G`mII5nIEBuKP8?Nb~qbNdZn4Tz7V&>SHpF?Kpe<3M&Z4UU#CB zaCg50R+D79Fz~*r+HQ4$LA7t~=eM?Z^=EnP51EcJ=;QmtFl9cTo}NJ1C5Vihq-ID= z&jHTuQt+cfIc(SvAa2N~u*MB41CPW6bPvf~2wkpvu=_c$ z%LX8T@n$tmP2om1g}*3G4YKvXe|(|ftg(yMhD9#O%L}viQqmIIVJ_27D3;5M9yaOi z&>t91Ow!em4+U}_mRjksTDC$xAUmLc$`p19;N#;v6186ZB6Y?gNY;U1fpk+~1}w5I zI7bsqBTw*tli{@E@AI6YpMJJ2`?`k5XVZ6}Fpy6JfvD=TpLhv(n%sOXT+Xj6coboBH(aSgB zu-DKIYOoj-Z3fW0@IjmUb|A%2{GRWt-T_G*kXASYR~_TMO`{$CdCt+}9Qb^BAV5@J z&iIi8FWT(mN8ABv$7SP+kB*L%9~ITraXDmUZ(l>e!( z;n!RUde?d0w7TLTzzK~^=&N`aw^lMAFaE?gqb3M|TtxSl^vaY6GMcfVOs<1=E@(Os zXBE8OqZ^@%9^8ohOkfy|@T@Tpl%S!ZZ7(GfKA)VNfIb?lS6ot37J`QtZc+mgC%r;$ z$3YDSQ*QSD{58nFfolPfNSj&eD>6K2gAu)(V<7vTFp8!tni?@;@z08h08wjXlOhlN zLS9rVP*Xs21d%nHPpT#A=`3J$OisqHojF)p!N{hOvID)%qiq%FZ7P-k+2S+u)lMDV z(Bq(_UTI7WGpB4!f%wMI&d+S5vBF-HJh+H!dM!?HmCj{d1u`IBPJsM5{9(FG9SH~Q z94_PT5&6g_@IC;*qc%>`coj6O5<$>~x?@D-Wyo3+$y^9rIbP=ha^b_>lC~8!R!b1- ze_P1L!<_uC&zU->*cvz<{nFB3(}9jfgdcspD-+L=YKDG>OObncLo72b zt*oNr&jyyCjIZjs04CP05fl$d>SF71AmDI({B6WS{E|V=5QPd<*+fv-D6m8T`VxFP z?*<5+7YTt+B&hctz?;WzpFs9R!IkJ)KtKQ}D|U%aHWYvF`(!_c(#DVN8GjGy-T-7- zQ}b1Ura>4{&*fZ&Sm|n zX`303_8T9d2_S!ts7S(WIJlUyXPsD;mY&|_0~bN4hWJsB^7};~B8} z%zb6$b8!Cdk2E(ogPh^fz}X!eE34WZxk;1?lnXTT#YNOjsn$LKuWgFDaHN?+yoHpn z5ERybpLI~w&`rZY2y(DZEG&>_-=ZFZq_79`f6mqc57O%Rp$AvFU;osomu3qrpn|fp zG<6)1Bt$43hkD0vZ@H;8MQof;aiXLY6*1rt%sJxG6l~I^_!72ZlLe?Zj%a_VoUq68 zlANag7NJ_l;uC^Mkr5M9A@Nk91WhLf+ALDy_<>LvNRe34in+s$277n|Y0$(Zzo-Zi zO{j@P2!Uylv;QR=o&_dv!-jk3WDolnjj|Irf+~dzVIOTzh%Z9gj)yPbA^j{DM$(rc zY-Qm;-}9kBVs=J*-85jSu092{7V>aFyn^&8)<~#Hq9!wd*8sMh%$!2W6!`lx`Ck}5 zPleK#fggeZhb?8L2%?X(!0N^&7sUinbiW>Hcf^b%w%5|aqWz}AL6SNSfEy6DOq~aT zg1sxMcOc~L*|rMG$(H-~^2ae%In169j?%#BKB=DraB~~UmaY$%EKz~J)4iHCE|}IZ z3wQ%SccZ3nAvHjKX#RN?x)_91RSz^?ueN*CN=$=);dEPD%6sGhA=m8}p>Hg~`2gT2 zAG`f-`nY%6w3i)9;j8_l$NENU5phJEH3bdr%|1JbgWb#-N}IeTKIX6n8PYD?K>N8( zcHIyS!a?<-Z=({_us)faHtcsasxq20(&U~!$MU?zti3U>WH{y-I}(oF#RGc)h6RTP zo5l)Tacz^8N`?jpy@l4EpWF2ig9Anm(qI+GJDgWy0G^t*h2`hx-&SyXkOsaKkYi-2 z=Um&0ip)WH8YBpS^Z?SvxG-Ow%9nWFzKzn*bh$6o)vbnh2KJiNfCQ7>7+`vPySqmF z#-x$GIN=iDih;MJGSus6glD8ggMv#=#iXGZ3wZ~b0KS+C0aa7(j!TKRP>urqYk5@) zq({{n7txvjodr;U(HO(|C?!Zv7^;)PEA#P;A5UI{{?GY&^>VSMjJ32&=Dv;cW20WL z=+t)rSt1G9z~Np_%hB<8xK(+l)G93Us;^%;`!EO7u^wbz|5oeA=pp#RuyC)TZh(2u z7m>SgGN9qhQ`f||d2+l^2SF1p%*vz6d=fOuFk<)k&%tMa7C>iRene|JzSJeRVfK6l zoSxEG)oW)dEr>UFcOBQ0@^}~~{c_+iA+SoZWzV0_&)IJke2$FUsdk)gY|5LP9|09l zjFID_YUq_IQq!iR+~!Ld0C)?O7qC14LHI(nD)=!N<~WU3pJZNy5(eoXDj1^qst!?o z|GuTIEoz{O7PfcGiHw2KnD}s9&66x$Z1aNGAmtlnSav_9)z=w*LBTKQwA~hks{Q8g z&9KT_v4M^Fc-zns_38>7NTn*u804n3Azuvxv8C&RT<6zZd1_}2k4X~L{%XIfYmGY! ze$lR|7OpNUg28AoQShAZ!`vzXH9GsS!I=KE&)rQo$4NkMrgqHIjL$`0dz#&Nb1kvstpwI&T zu7R7NOsuH|EJ0a|&S^wNvPeeA5nj5Oz4HB%bq^@<7w%@!l#ET+X1@Tr$#|2j!H8&2 zonC;4b#dE{YZMAv4X8z-hwTJsnE};{*7apJaE9mK460ECHVT&CeK$xqs%r7reiYmQ zhnm=zc2=e4@%3`$<>kSkb!1T6f*Tiw;^~6W9632XU5^TX#A0&S7KnV$&CJkY4prKu zgS?1=@59dFp-snH%&?|6;tOUvX{<`V2SW%Ua2`TP{O>cAN-*@QtQSFqYU&^}C#R&g zSqy@JDY~D_JuF!>M(zeqPg%X>D2Ig86gKzB zJ=S426-!qk=+cdEi}MEt2EaOkx%>}cPJIXGFC`+?k(f_lQ5qn#Tvb@5%8=~>z!IzG zey5Fj@4EZ$x%ad8>Dk|g)e4P*qmAoMO`k)?_CQR25gdIwJpdZiT&2EvJ|A(Q*x`mJ zp!`jO1fR_)7A8T;rH{sI&F2m@XV971w}4Xi2{5wLdN3btV4EvJ!W$4u-bZxT6c8u@ zWD(fy`>%_eERBtgJw3rDQ#tbLK2SHN=l>x?3!>%$r@4^D_kinxWB&&Sq9+cMStELm z8p*F}qr%F=nyf(1CJ;nrJoymwCH4eSfBT0i+p*VBiXdA)vL2iPV@Tl!EEAVt^A1U6 zAx1Q@m5mK*L@bbRBIt{bw{COKpmWNHxs6W?nm30Q8+K=eIh=lLoyPD^d z`)L|mx4@kKCc{D3ikUlOVhZI6JFLI#f|$v{{%+I+p9?_Mr>Lx4@cSbWCoe9*d5ps_7UW+> zQHW(e;Ea=j4U%dn;yBW@(4@#iQNQNw0<2?F4?~fvn6SkfWyyUbiW5=7r-cndQ1Rv@_6{w zv6KY$nYgP6Ly)xtu#WNRX^9|tW^v&tUMES_pN9L?5{Nyo>QN1s7Z&oGb%VuV<Wk&hVI+m?=#maOyRUsn<9W)5Wt@T}P*>p#fyjmzVW4HD`d{0os9h z>UL>`RMzTxsDH8^fn8ssvLZM+Y1WdW3X+EUc4c-N+)ju{xq#YGS@K3-m(+X)_|Q8o38^b zNcFNrGABKt`TfSo_XMA5@b8rA{hw!Wr@XOD4sI__CGn`aJmqW%Z9@YYk7;+eJ~w6w}Mx@9PcQWI0(`FAu+n zm+{2OAjDCDfL~2n6*7TQ@(y z9I_115aj6-u$N=IQ0M58IU{%1Oe~{fgnJAzs@YKttmebgO3RT-wnbAW2#)9=T55hWjgXIJQP`& z{wNGE({2TyULoO>+9B35$%Ub5*{S9HM^dA;iys~xlN5Zy!K?p8({)F4`M-Ue>>aYR z$xcZ2UfG+>LiS3Mz4zW_?-1FPO-5G8%HAVeqQZ0jx~ZK%(zw1e#N+tok}2e9;mv^zv-KZ(NxqIHtwD+R&G-b_s>N8r zooj2B;Pkn5vzS*ys>Fk*wJr$+s*2j$B_7*uKoUGo9n3|iwyI7bg+4(|(|^fLcucnn zWV_@Fz9)}-Ptbi2(Q7tO(q5-_X!-P&Fv@Amk`&crZzz`OEzrB7^8|qHdGo~m)vIT1 zKA$TpzM1kQ^Y45+7sO^K)|4irB=;j$0s^)b`i_(Rh0I6Q&0yuw4(1Tlg zG7t7h_<`dXi=8k=k?bRQv9^-gb%9a(!q}&_B0VZ`0ll^sHUlwcyuT4|%4!4Vk%Q5OHMQ?w?G@ zFX3+&d~g0i`Cr2#!AypM^08W9t_-Y)&cLz+nsV#u=)heFT1rS|fQHZ6n48DKv~(dw zkfSXbprG_2=x79(w(q$5&9?_RXfcSJQGu1}P8-s%poCv>hMdYxn4D1VG*`TRd^WIt zO?b?weEB=1Wqve&=1?+a7{@^9iN$jQB84Me*y<5cEy4leW>a`SR$& zhJ-0Uz`8I4XXV(~m}KtgXw`(U%FiToxj{#_K9DRm z_z(g>#v#E3yy#*<_@KLKhZ}fmiWEs`&!c5-|JU9ggA_GIEq-20iy`M6J&nNZ;2loZup1En|;vXK$o0GWz|;{mtX)<$@4Bsc?Lq*u;7Axr@HEBWmP!0|HbQ!ZJ-RlI839? z2)jw7W)REa>40s=z~`zeJQ;_h9;lf?K1SD~p-!w9&)6+QnR^|f97JkW5oR(^nC7_?_vtp`mf{J!}{gaHK4`K)CH zZ|U!Z@9Kc?vv-)FD)4hyG3R*8BBP1nZ-X|hOn26rGKa9t9%A&sh=6Pfs+X?~6i|>; zP$cAsV|Rxl$4JvhtgKS{NOcb?Ek;QM}> zv7^O@T%0904fP-`WxZ?l63lL|)5tJ)3EOpWIN+B#T9;eujGI@d;je%yV<1%QuNhr; zsOTx3i%r2Ba30uqe{vH+o;z6xje}6vo|gNE#`_{b5g)nFgVm$t)%w z2ctOvQbf{~&6#qnohfkKlI$HF<-&y5S;%!#LU!1vpZ0URp1Anm-fZo0yVjMOxx0UW zE$;4?26Zm=M{(MZH8qk#yTry0p5trvT(ytJEmPyvOeZg6G50jX0+8pUqUL4L526LRWJbO_ zKRW{%3v&G@7VT^Nag_M@Nn4qIo7V7lTXT=H2OuK=*b~Yeb(xe-LKYoDd@PiK6dmbf`GEmZ|y;J2& zSC-Tc)q859!^_Zd7vb+4pSEoCURM5v(G!a27W@?U*4BQ?{y8=rH*ZC0?r;bq@Qzd` zLVpL9_uQNk&Ovyi62%gHj)=Tg@EzRcG-`i70!|@yVjZa5#MYoUsn*L%OG5}>Y<*4i z-UNddqbZk#N$AJW{2?O6yPpnnBt|o9D0g!DwE!e3_K`e!}>mM8Xv91=|fdiE<19k)zy;0#b)sWsoce@yLW9qh0Db zFe<-Js1bUq!n{T^yRdM6^)JjIJ{JE#O_27BxlskglLSNU?stXy#Y@6EC!BZyw1!a2awjMY?ucuR%!2k#flqFKb zcLI-Ch(<3i1UWk*A>264@&JY{lMMoE}rgfHWGrG50Cc zMPymoM}w~t zUYQHH|IyEi22W2-R}~T$QCe~Z<2~P;$fjA8#A_HDz9cnS`xACbBwZSj7Zn?O_0K1* zYYT}jv}hDjlgl)2ud@@$>yO$mLR2?RgzTB6Jo+Wj*hgHtP*2 zx*F+0m0X6uvR$0*(PY#pO!IdMT|qSArGNhuNjgoxckz`%0s?3%t#x(oaM;tWu?X0t zCEy4@B;~aBlOtgVj~pRV$u)N2C2dyxajuh!IwFB;a6*Oe)-QS+83;X*;wl%+lUMBz zvQ%g5Ps}GwAMmXYyE<37u=r&#^Ev!miS4_}U5IG|+ig)TMPRVcgu|Hn!YGJTg@wFObAbjyn~~x%f><~zlV8s7uWiMza6lb0*QZXu%sf~ zTEAr)aYp$}Gzi{L0@jM@U&6P0>+~LsgB8$R!M_mNn6<;~*T%bzOPt;JXkstwP_J)p zW{YH7Is$Dp*gQao!R}Q)X&W}>#{=mO0Ki`TbHb)rI=PH9SL}n_oM_tz7j!{SzY>h1 z8Srzra9n&f_6L#=R3ZeLPbbxLbUJ+1I7oRG)e_B1l>05mch6+$KGG})GF{ZLP9HBV$ zk4d_@N1q6vN$0C$eAC;{`}?6uFwd+LAvRIbLG4WrGrxdWEY_J#M!6BRM(O?iD8mlv;G-eA(HHDGZ`Yr2lN>TE**h&z_`m!w)T-HK9rNsNu*G+L z-{{rQJQXzees+wqo;>t}`|<>6g6@Vr=c9E5$MT;Qv6Dl295$?3Y+DcmsRF}K=%a&m zxLphoIJ0I>Y{K%br~%Kuk4mauMnrb&-bjyrTsvR*Lp1vUdI6(AHwauhCBo=HtD?Fd z9vTAc2EP&(3ev|u)?Hr0a1KsRsL=~n6B(i@?jKX;vtZIMl$1nX>OWk=!K4Gu?Bk0# zR3Cz)0PrmlW73g_DoQMe!o4Ao8Qeykh)z$zT9=&XWo<0!AL3>QiynN>6%`U?oWz*m zPXN&3;P?GOby7=36LU(xp`U1UC7^Y!=RU`4xpx!~>mAO*V9AcvBU)sHCiysC#ooNp zQh$C{oHS9%@;H#kexks_c-@(ps;2b=QUX9#3}F+Bg=$!ziDG`vk5a@RwV|(C1LJj!qoCS7dfu-M)7ie?=fZF;MJc$5KbV2GyZ7@ ze1JX}8A4$VcNcB}W<$g8|CtFuo_-N#$FHqzQ9TX3f~zZ^hI)xcsFBpXsdIimG836K zE5ja$Yx}KgSpT4&i~76;#+J%;iQ?gp=Lrg+t^>s@d&KzER0vVQv;?&4(#R%>KhD5% z0wkvv7JkKsMyZx)c5(e_2x2jdU01XF+>mUEc&p_!cCF377J~6>BDvJ9KF#xX@ z^TB;fiA8bW5Ry#gEk8i6SxIV7NQ-tj3tnmFi_*LOjr{E2&9go5o8e0gO;6JOpmv*- z(_c%iTjz-ft^>F&Ru`BMxO@37G~dDM<3~FsB#jkw8`fNRSrCYNf@61xcPUKBgFI zX>1Im*y_V3_W07;y5}SaSrNHcMB#x}n8BS8Z^im4ZesPwlRo~dC9mLjI{_fU6=j@z z<}6MYw~w(H5&F^OP#&2RImM6Q?;?%5`&Bp-CX(KTi+JpHS2H*!^ybOO6S6+c{Ct2l z`cvG(F$ZyNt%6DSwJUK0}=YbfW!fF9%n ziQ^Q}kYCJ-k1;ed0!b)IgI1Hav(?pbcQiF^pIm}sBpadysQj$el0Y{$2*q}HS+s26 z^<(MX4>N^##;73yg%)2>R8&WPE8~rI(Av(|_lkuRR~2K{BA$m!>Ows9io@n_-@a>y zM$^mMI*dl6?R6vZ8-@)(L zm>6@5H>A>c`kk;@cwg3K{0zrnulA^1P^e!G#frE8w)rg3$Iku%%gvDZr9~(H=+46DH^6}; zQJuh54XTsV1;&E1AG;7D1GXIaI|QJ)y1F`X9g{<bKy^KR{B2|e ztVEN%_du4F<0JR1!|M?lc3ET6>#vWES?P)N&8)bU`C=WLYvJ4pmo^Q``o3XLDdtmA z-^`q>7(c||64hf4&r?!`{X)Ix!*}K51J7<5Z|rp|Zn7auUcaTEEwAKcWntmpuKL%T zRMW4?86bJ2#UMl&FV!vF<8Hden?Dn~?o0+tbtYA}!7QsmlZp|u-(1`ZV)jS+WwVCw ziD;1_ zJ3nV;AlkJs2aS@3hNjr{o_-BF9yJso-_BW_RPTl8-#swm+!Vh1V8q?@>go#I@j)qy zweN*od&@t65~Riq2D>85Y!K0lTyciVh-9c0REzI)@zhVA)y^2`#*Fb$JuuSb@CCG@ zb4alG0S{z4R{8$hh4hxJdB?>sw{nfK;Ct^R|EC2QlQ2jNR)z4TV95d;<42Ol;>Mcq zI4~jq=unq4RVFh>HkAA>-E*r8fxA0t8@?XeL8zQ}A7p+*THz##2=;N|8&AN)!wcLF z`)(ylhq1Bo<=^?-vy0BV)Ms{&3N^3GR3r=yu?ECsMysmPj{}mm>@7dd0097SZhn3~ zhzme0squ~gGZ>aW#KD2`lgp@)_DNtyVn?BEhXW(N0TxzwaKe-TlyP)k@k%>^=y=vV z%T_|<=ar`OkBtfTkh=wzn`&!OT=(B0Oal&!?B5P4bEwN$FN)=}p1~rl?TLT8luwy~ z!0|!XjkMqLcx%hr&5igOHvG#Xd*<$%Q( z+=BN{-lUk;S5+NsZDB|;THWpI?S+a~41`$ax>aRNhWx<;58s6@dd6vev|LfP(3+nZ!pX=+3dcS$Be!NRc3NLgjJPTK6V@Z(U zEn9M4S51QFf^pNSYqeff4li`scdh}zB#!KX@@iLR7?*&xX0++m0d>)r8U~A5KXkcH zx>wJRX3x7xq+Ne_D&;;Rbc}=2A#oCnzfRxk?U{Q1)c4>mVup4Z#Q4poE6Xw=8hD@n z{{6|?$?AT!orS2sTeMkQsd&BXYiXi^$ylcN_f%hD+K{9MOt^fSHhCOGH z$Ry+f_~C{1g&Qp>FZsSwXUtlOeBs4lAc=hNlszcfuc(z!I|Nw+_}Tb)0+#~%K00l| zJ~+q$@pWE_b!NAO@@UmM+zFs3T*}f@!+z%V51fVqA0SdQQf6uLn42{9@=kgh)(eGbG$h1Iu>uu< zW%%M=B?MCES}Nxlu_Xht(Rc+KD}DzOp^*D=#{U`<^5#KCxXid{0Ndu~*+Ni-oSYmS zyWF>F){xfd19LRMXPgiMnoszT5c~p%zQ6bq9MMznv;#o-FO)JDch6djTE<+Ko?x4J zrVCm~lJ_PXYe$N_`h6Hh@rf^);NIx~u~!oNukgx{o}`oJb8h9)EbKSg0ZKUW+reVkURLZSSGzr)F7cj<8==X@%qOZR-GzzzPfOslOBM z?Fr%1VY^KbV!%KVef*KG=MGxn5PJk0|E(s4GX@;w5*nz1FAKM{GaB-a;ry+Clu-h^ z6gmo+G{8a(j}XWhoMA9bK%fZuQn(IpTpBVmGIlcTn(M<*v2I`F`6lm67em9$B<9$N zcfl0U0NIWqe8Y@+gyU|*CwueGQ{)$B3!Fg2<#~p{4Nj6VtvxN&NSM+iHZd^Bi=sYH z_naTl0w-EW2ckYA7NdOq;CjsmKd_S+DdvwgI+g7b&TO` zeSNmqoJY^yeb~(`I_ReUemx7XDQ+maA0CK@3pEtnFM)E&G7!y(3^)_bokI9~qAf zC#THXc=pX@_RYVxo8S9}%^@n=Nje0+u(c8yuxB|^+sfZxrJ8t!lZoJCVB_L~U>u4} z$en{b3);!HHZfu09kHLI4T3SQH`o6_03apW_`$*V{ys9Od8^09)Jc4WWs|r5MU?4g z7dBA;sAIWoKa^y$TTE`Xis%7h`CC$D`fHA<~_CK--O!V@jgruRGl*a^G=VvqwW zMDVs>8H;c&*L`;8VLMYS1nJoG(oBugpr?UMWJM;b9d$I4=t*ImVuq>rqI5r9l^l&n zd^1$LF74Wlefp6b8`$x1DTOZtxgfg`^E?!1|D#w4e9*@mT(rPf2Mf1GZ{5B1Cm)NF zx%>z^N!-2zEb#l+&#U=O(PHV8iLE+=Xe7#coQl`EPwtW#`cMcpxz4`%>YQcC8;;ve zJp%DZ!1ZVi*?c>1ceaj$(*Yn$w&bsa$%9sn2aq@l0`@D<&jHsTpPD!H5EG@nELz5d z$1C-u{PbD6;k%e%vG!Swxhz4(q`W8vG2ks+;(12K?Us3uAEXWnbI(1P6(VsHrhbzm znd=04ld&;^$evacU5p@pG5_t9-{PGGF9Ma&;{)Po{Jzur8bhY8{Akk9@*OeK35kPNQLmb=<1Sk8vTQUkRd<3 zuVPjcUqDEmRi5jo8~+A$Q=2D+8myGKeXB>Ss}?(H{N!r$mgF9lZC`1S?6*_xLWRmK z&8jC*)vyyb_;ABLMq-$svSU_5lBfBlj>tm5@yOrvlG<1m9G+T0|H&O!7{jNw-@3wG z4A$P@wR(Y(-kybQ*ME0g%YWRWex1*3oeu4)n>ZBk9>lbqcAh7u=*nys-Iy)ta z@)7#V%6E_r3O9PiIwbN!mx?f>#Rib1vN<0`G~jQLaSC`f^nxpAU(d`GrMTr9?SmIm zV(Y0i>qHV7Gan*8E7d74)PQ83+gLwE#!8ZLS;8MEOCRtKeV|H)0JZE9SL|gcy+1N< z7&1N|qJ+LO*OZ*2X4XN;h)`8kh4KfQog>kPUeO@9>!2}lA$##A%HpE8H)Mfu+cBG5 zoo61j=j_koUrYhV%$8iHQ+|ssW1H3fnJB!DmbSwBW~hEy{7zYStf<^_m?E*P=s94j zdK^gF(Xy*MljYDLHbMywuicsP^wJx?w6!kr8{TUYU12;!ZrkM#L7VOEemkP@X<)~J zV{NUu?*b+EEC2Yy@1vKN?>P1_t47~^g7vt}cLldZo5wx{w?wPL@IHh-IXG0BRDqx` zNHW(=7%qs`*4DpkiBCBnJfJI)TkqVkUHQu*B*LsjiNh$#fvuw`$RZmS*J@IQ>}tdk z!3WRWx@Dkkn#Q)2VTL|KezUeNF2y=wi_(h&Ouv=_4l)$%*}@FW1TV z$Q`Ovg0f#@~%o2#pkwD>Vv=Zf}oBdG27 z!D4o1=9`W57j_uB5uGA?)17i~j*Dw+3@Nm@1^j1ggWh^W+-$AU3sY%&)n@@)p z2z3(v_hdyYs3cuo6Ge{-`1NC0FjIDhUy{*cn;UoX)0R75gvv9}v+3)K(^kq-!i$2) zRl;y+UhfZBW)HD*;&E+=O}}V22%P{9?s`fltTaC{CTKgTAG;m6ROw+y!^L=`?VTMj zk(jxgh>YKt-k07!rlx+Pa>SznOM1vNLJBVhMFS6n5Few~evQZqt=o*i&e%yckbVud zOIMo1ofJ@4MB9;#g6R|NrEs@sXR7w#GvzhXS0$<)^pVx zn6ZSGN|zS|)ens`c5D<^EHVscfJ7mNnIalW*a01T{gg_3V8aLUiZVaA)w!x^BSbvA zXY=&k!%cPv<6;Y}`SWXq84JDpPYm|7v1lS=fV2?40{|T@ zTh01{$+TXa4_O+sn}+16n#W6x#?Cr$60_z`Pu+6W8r`FYC|-h_Sz4k3oeLJiE>-s1zc z^vKW<20K8Uva+&qS#Tf#1MKeML0HE1-~kC{FxVUbQ+c%Dxe6WREvm%|x)l&181Q`6 z!LK#{;@>n?-9I_FKK(+yf3mq_ybtuLKFD=6f`i1UB+om(+IH=$YT;PMb_C=rTPY9| z9rT&sLWST@Q_9CK*hOm!aJChs>8iHY`F^I39j{t^)TyOX^WenHWNfB1bPNs&IZtrn zZTf+d%WKn&RJRZJ?h_Rs=aoZ3#1tHPto* zKZk^did`%PItjM6wJlonAC_pinw0Z2;N%D)G!o+%m{hGMa^Ba`?Ni0smLp-TnPC*s z*~_{7`?nP}7?h&mW(O&D$}OT7_bFP|0xH(*k!&H?A}uxmHkOx{A9)^+tLd1@AX5v^^ZRex<=OzrM#y<Gt2E(+ zT<6``h7Y{ADE!+1{|9?5kC(Ct?h6+urzJ9(5BuUPSp)r0fx!?U%zqV;%~R|VgbeCc zT5R~gq0NPoK?@f^I)bfw!ibsQJVvjv`fkhAIci1*U124zltC+D=CE%FChD``CWe7m zX>qr(;7tD?-RG=NMK3Mcl4oaTI!MaLtlQP@KS~NyYkff1^z9Y6CO~Q#c2h>wTGx2u zLF6+e!f@keB5jk8mi!0XUxWq{f>A#}G^A_O{Lm0~l!)vXN(Fuj7<;1O9APj29F_Te zfPKSVrLt09Q-X&^stwH8_V@Ww_-6T>o@UejppX})A7q*B|#&`+|SrR|TZ?<))eQML3KgU_OK7B~u3i_`h0`80`Dq@6D$&J{~K z_`CQv24qV{>gJPy*X7TLvkUUYr0D@ggEW)NTcIlN4&8V06HM)8QBhUL4tcBr-{P@X z-_5fY(@@VSd<~;fSOv{bpb>y3nulju5Z9q3%IvMPsVTw?0>{bhEClywrltACtHnf0 z$QRO#-WgpD^n^CZd7ksqA5+wLiNynz-%?xk>RuVn5zX(bf1r1PvTV=N-5r!s_oR%y zrze+Ie*J6_tRck=&i=Re0+3)p{y}=+_M}LK!acJ9XRkYbWRs@QQamggO!5;I#y9!XmkBFnREgZ8p`r<7_5e;t;CKUqoSQD9)i+P_R{YP1V zZ%_3Wt@g3Q++%zLs5k8dur}!5-%l>9FVt~^lLB|q+`=i|SYSVwUT^T>k6rf~3=DS` z%;ZpdVj^{+&8>*K^t;+os_P5V{D_UPnKbz|IT)FU{De%e=V zZLA`DX-e(DC;}KMXGUKl!?H}+&!4)}HAnRB$!fv{JOg#9?n9;$bOpM_{wIWdP`8cK zMi=@i1({xTDCrIxLis^&IkCVIFYhPkeE~%p;Ic;dt3%SLPVmRml9ryTs3=$?7Uyog zA6I0@KUHNb>q0@|ukzcz^fs}^YA7#B??Jp&@TMVH*b1@J_OP4y)x6-CH-UY zAV-8<{sD+?Rush*eixv9^ea>rikxar{#X(`W=yRepGHJ?vpfhu$klbOM2t?gO&H#N zbaVu%DR#)w!hn~HUxfi*?+B(km@bCjjev4jv3+gjwNp*uPXo?W&FaFli0!Q{Q#|?N z_|WpZRL#T%?zZaPeT{;goF+1tm1J3iJ-FcU;pTQ$&a@%B<79+IQTL%sRAvzCO-xwK z&e@+qt~R@Sr_*zE{`p^IVj0qKh(Y!CF!S5^CIg_6LqpJvTgZl>psKLV9006v@}MCt zfTPIpOg_Ls;)PY$4V>L@ciavyfu#Nh#JKryM#*^s)Q-8gC0^k@QR-nEO%jq-gueP% zT@mUw=m9{9N`dDH_ij+LH6cYb+IzWSn>WvPv3qt$w@laJmdrpG9Vz+Zd-KI!K$=sv z9cMtRTwD5nWj8{p(l=SMPu$WouS>N$gDFiVqq}q?dgvL&&b;2j?GNF(5NciUwi~jx zVHjm;4@5(b_MN|SXS9kNx8{d2hV=2YEGfD)hx=(7*Dg&%$q-3byXB^eqxY3G!E}v} zZ8gbT=7_7soVk+YWub<@s(Kr91qtNGi1#Ah>Wt_A0dsVGh&`7+9nmzIZND#2l&`2H-SkpXs3n)v|$GpLw*_Zz2iOnE8g|RLx zJ&{m;z|~t-#g(osK!Fpru^$fS{Q!G)@GNY@4-O`;p7$z1tX(#cke8deI+eyP=gXlq z@5Ovg1{}h%`rp#kdj9_T3jDaHs`i6C{g{j#+kkQ(9LTLRO-#?v*B%u;5)Ft)--ekD z!tY{kr?*kqnwa0~b0%I07*3k)s+>K~^=5}K+~3{Ys)ZUuArU6w{!`9)Yme$z>16ZI_llSmvt0&jX1{6{E6LaGHndmVCbV+!4ZF-qLu^K zO2jjPP!1~Es-`9Wl2wiAW7R9{mgxshfL2~XWdJvfK-&sELc0EBe%F};)_153$Pt{Y z3LqzI@8IC(IJFHV{25tUtq`OMTMA3`HX|FhDzpHA?9n+T5(A$BUP%vkcZg904+IcY zponA9LgMVZU&>So+8z`dGh>V|)(;Mjl?Xx+IF8+w9l*B=awO2TW1=G{A>MT`qMbNC zu4z8Z5k$L!zyWa6fPz*w3MQCBmJ$2_jtG4%Y=~R+9k~cNIZ`$CqMr%r;bR5^l)d&_ z=>nUq^kGQ~2B)scm%MeXM!f!ZcG5m)`y{J~D9v_rkASAmqaz+&!PLQRW63ihGB{~D zwGy&snY-(LnQd%%+&b3sdP-fDu#hoizWwEzeFe@^PNPQC&}w?Y@o@OMTU%jx!2cL>zy!nYTqIm; z6~9|s2G|Sq7NMMKwce4np`pe2A)(|+i)_vuFW;UAP_#>vx2LDP1m;^3SdYBv#NJqu zce-<~--<4R@9MKjo9ia-7Pp|F{D_bz$sB5)K?OAx)sdngWf8iFCuSPb)Kpd04LyyU zD(ZthL;{8#S$RX5jyz3b1NzKmcQw5UqGhn_*HuPnwd=Bx2#=e&6%JLfr>z%%7IKaH z`OoJj^~)(E2B%MhPWdwXuECQW>#`raV%JBp`n7Z`=SEC!iW-E7Gkz!MKHsIqAJ7rxCIU|dJwl+lYgqs`Aalx>7%?H z@qnw=IaG$S&l#Y+@omumRN30!4ges?YzgqX)|Nq&K7l$Ms{6}o*?h$B=6&~$So0}r zTELLz=!p0F&c(1e zq!yv+nQytpYTrN&Cb&-*vaBW)Vkf{(n4?op*YHYN0XHn9qRGTr700sRp$5aReVzwc z#P{ql8LhBT#n}b8NF%4_2*nF}@MvHlj)kn&n_orC%)U^|g0|FCWcY(x`Q-Hy-Zg^h z`Y&`OL_)$TMcv}w&w$ELxxf6wg4CTRQZY6d(kK9biDsgQvP3AebjhPbM3?v_~kLVU+>I{JP3=#RZ?gCdRycy70J2507Q%b{ zIU*gB>#?q2zm-%}P1=rGyE!{o7Z-yh%oSb*`28qfAb{~k)t|ICG&B_U>%YPP)Tk))Tm;&W26=D=T*FY(jV0A+wWxi zd1WUm*EhZP@WkbtcUI(k7Vy#vfZG~WMqpS@B+7`EZtCCvaD`IB@7 z|Ni?uvbVy>A@Z}M9NZvPNE(Wf&dk^p;Sm5v{ zRlQS}82*I%X^XJc~x#3q27|s^U?zaRB+B45(RFhVp ze}BGZK7u0$xaJNr7-$N!U?8OdgtL_QIRu=fqI&yGjrlvt3&BAQ*OEcjiaQlTXIe)` z2eebT7l(&VFJ7RNNk*ENb3z}@Xl7(=j7ks4EYyFsRmwx!rrW=-plUmeeD*i5sw%dq zi;_EwH!zEcVSWQopwM!iyQ@ZOQff+SayIVH1^2SX_gLFH%(&8f#YIGh&l3ABKm3kt z?p84Ogq#-8@r;cv+XmBJp-i$n*VzpG z)kjHN-V?czl$}x}gHe=~opaYe-!Xn$o8l5mZ{P<`vHMmHKF%_?ZFAe)mS(v>hgo;Cy>?2W>z1ba!&xeT zZ|UZiRG&UvN=}r|NE%5{3dW^)UYS|{Cy!b*PDTJx@9u=n#h^qIX5(MA%FF=M$QyqI zd@9w#R6(^q?&0!rhPX9Sq$g4ki=5x-Tj%8@Q@T{gzQ6IX+J#zREq8R;7!bYjKdLhrU2>a`*#14koLt@w)ZW^G4Y4mpz|R)+5(-nGB|J^PN?qDT7! zUC9(OqsOx^s}vB*UYC?EKZwNko8IuWH&ox$B31Cj`%zqu5PFj z%xvMT8nomU`@4(>W0Fa*){QK!Vhy#gZlM|1t(dXOM)MQdd>%eNWIx5rO}6D0$op$j zdwT?0Yo9h61Im=Yhlgs%Bv-c{OW;^f1}-idR|SDAyH9Ny8o(Cf2I1-;F(^ZHQzH;b zdX)An%VRs3c!SUH2Rty?ikzwW7baVNDSu&(K?RV9+l8qt7;Eg7);z}K&|e3jPTuGF zVs9()+4DPbUgi5~Gxy^p&E(qYJPH)4W&*-bpQeOFM1s2E&?9q%;IGiGWo0Iqtq4OX z0QAHP4yYJMx<)YsFi<&gRd5kTQ}g4M)=c!|P3!NdKR2Tsfry9a75KiZd^S|p`$2bc zLv3Wgl7tLu40MQQtGEa8>Y9b_aDAoz@JnVxa!O*s(0!SIS7q!L+qOY`)s!QMH%Mg6 z{&MgnZ$;0@=&zyguH!axxb(_Yg&}zBUQup>5dDkmrYdYVHnQ@`9pKw7BQfnEyeW=a z^Ei-KIptFn%bs8w8OBl0v#_d}CbzAq+lUfC?b@kfVz+g_WO%Ej3~Hucjyx*M6Tw6O z4@k-U^(d$PS{^afE|_o9L&GRh7ssFH6tD4Bnh<%OIr9*Fvhb<{fh2M0M)tN_vq1$g z9Wck6d`azP#<%BC6hJ1?uuct&lkyvp>%qN?H829qv()#Xi`FlYky!yI z&6lvbAZ9<}W~QUlMScL%%6Y7_v8h0?*nmc`>0*Ju#zF+S+iPZ6hwPK5Oz4)L!Cz0f z<(8eU9t~(^P^3PxGPdK1Nfog2G-~xc`T zv6`iW%*nxV>-zzLV!Cnw!KL?m6js*nfMY1K95uL7qAPDcBO{y}LsACB9TxBD`yv76 zbY&RfgyDeFxI}A*wn44T+}g7fWKOw`P+{5?Ql6#7KRFEY`7kBMU&~>!K1?syDTn&ljWT&Tsfb2_8vc#gCG!o6X`R0qH#2>Y zhU{>cl~rXl)?mlqznfwWP6z9$Msv%{bg!|<3ujn^+yg1nUB+07>RhAt=olZlkar&b z25HwVt=YqVTX8Mx?d9^e0ivfRRZ#)$^};^S-~zz17PhtnNDWlu*l%(_EgrPFZEFa> zGttxY<46Ctk6VZiqokA>2t80gHa23klx5w!=WJfX+F8CxaYY%oZtZzl}%R3Zr3}*0FAm$`EG*;3__q*=q#DcLAq^3i? zwbD_Mhem^%de-`VXLTMbZ?TNI7y*jfGp{Gfiir87-Ka&ChgthD`17Fk1b2WmdIyH4 zW`CXSS+lmbcW?m7s)84`kR_l{;7G_5ly1y(me*&xVN`RcL|2vlSTgVgcR?qs=2l=# zj3X2SGnQgin@p+}o82Q5lqTE!!qxC0{?rTPEqanfg_!AZDmtH31EtM&P?UKuoakMX-aDEb|kZS3^V)W z{hQ|9M@RToc6VI_z=obb@ZQFdx0?+fCN<7(^9a;vELeAnz*M1sm{ zWz_gav3QHumKi~Agww*g^{c;_Q`XNs;aAit*fl`r!LJ3|Gd5bhyTPvO=CUo5(uddk z`W(u9`xVC>Y19D5i?03;` zRV*-*1M)`1411>`JSy?2r~=9hDe75D;5N%jS0N@CfZy6z@@haLXnp76l1-@IW226Z zY&HB)6+KgjPSuC$pP*JN97s1^x# z)(y*_56o$mDf=r>-=2NFon2qqxytkBk*G%*4dPq*?_*hDv@`SaY6fvX6l?l02rQM& zT#Gn=y{SA{MT8m@R413-5SkB(KvPHZ_MN7NdV1}&hKQ-B-U&{JQr*w~6Q=d99zo9z z0pTN?@r%`6%1lxiFuzc*K;$1MWIyN`EHf0A+Xq^wYV^qVdB|#U+}!m&y36UynZ#^B<0Rtc161zxwAvunX6+la zi^_0m73RGOB&F|TV{}e0HWR)~Z`?co2-tbW9t?xA!huru#S1x~f5WBCSv6egE6sXE zq&1+cTSU#ck&VVw`{iY9i@sM6aQDdjCoR?0@ybky>wO1PXCLsev0FihTm&~QLVnF0-QXvG2s(8%0R*hweCeky|JD(T-9HU=KhbXyYnQw@z1EcTGb z&6|FTq@&q}IJq@P&xAc;cRXgkae!010dKRMsHkfOmMIByzTezYwFoF zg9?wUb1*yt-Y878`>Qxc>i1@M`VVB5k#@%i&T+vlwO8RKlS87?*2aMweLb4se!I`jCWk?Xw?u!l@~ zNxoklwqf;S9F31}ly_pH`yy%f08?fz$e=GUINg;Ew%{7i7~0_D3hdMNN2o6!A~>r{ zRm}bafhL+jUK<1k133*cSiQS#i@xW3Gq5srkyP;Qx(bW>VFqhGO!edEXV`Fl{d&fR z=}^s6rixdlZk)B#YLy)+ex(c#g*Qj-jwH}5@1dyx`B0zp#C7yYpng_S7?OMZkJkic zw?mnrzXDK$@fWG@elwE>9ZDb;&Bp2fS$nQB;#dP}w{ z7LGVIdBAku9MW8O-NHS8ow`-O?nMp0jDMGy$D(_;&7k7?_s#WUzkyPFWhf?V*#2-? z-m@R>9@Gv;S^v#gPvg@6U>#11jb@L9^^>ALT(_+C#=Ac5OpRMFh!Vf=+Rl;Fbz4Fi!8JHCo~4~dqfXhT^=|AG!0vcn*<5IOaB zFiw&z)16W!`}n)ER{$0wmg9uc2Dr6ax^Ej1x2_5Xp;Es8fZNTh@JF9Bl`kDTgYv2s zI0I5&BOa1n_PhI85tjVEANO)P!~>D2Q-%k;kJHwjBU0AOOT* zdXhG>2~QJf8x!Au?icjmls(_rc#qEy_rArXUbY09-A4Q9mf@0JgkjfDNpv$`x3+h; zJI!d%Z|$_mQgop$#cVS=u38<50DV{+6cROV>sMlQ)#ozE^Y-!O6&xGOPM#o28ngb} zaC5#0T3Eni#&F+W4nBkFN5WJ;HM>{&b3;~it%@FXl(W%skWqaf`&PMcgw-NVFVP}c z%l@G{tyfUxqhZOuFxL;FP6zM{XnjP>EGC^ci9zjcm5B#fh_9>S(OYFOcL`*|aF!PD zOJ1v8z2_i2g*Oc1U%dv7yP?)Lr{1DsPo7j%e}-`hAZ#TO%&t`sQ$VF|n~kd~eH$D{ z>0t$Kb^E9iC+V3eLrPj@p9!m~cCBCGqG0Z176- zr8-8bNh2*^vIMmgJ;k1&;oCVS6;Y}F>$cQEyju02RN_W7}JS_aQB$UW0kKJ zYZq)K4wnXv848!XMXG2C;yt?O67@$dT(i-=b%C;PImL#KAb{-O?f5NU3xvT_RF~ zqQu>N|J--R8OL$-<(wz>UVDW=ef4dY69+{>2qaWP@hlqac71taP$lOu5lMr2cZ`jj zm4DE|-hLzB+KXrLK%*HT!eKeV2}Gji#0^)E%`aM?!I|iD3N{;7Xi%@O9a4|a8Cp=v zHpbrlV*oM|l()hE43xJ(>Comv>I92@5G?Q8xP+;vsh1G~7lqh9N%JZk&ZO#^+X|c` zbG-aPV_3&93Tol7mJ!LCXcQ1Ke;Dn?N1%lrr8;X&vB*61c&4d|m*w|dowFNr-M9g> zKiMQVJ^g*Gc{MXEEj>&_C06~^z7rZMPxcg75k$IVhV1USvgsMFdPx@$bK`|8Wa&{g zmu#OH*N#mN4`YZ&OaukpzqT@I(5FqTz#$zWy19Qbc3WMpd`5GgCq0BA3xEWGh61hz z>QTGCc^m%0p&_u@&u1PS9E8bo*@kYhbOXCmj3eD{wo#4m*AW9S6L-I$&J_8wbkF4k$K&ZT4#AA5HnD zaW z3-Z7``5ctUgj(j83sI-!e_e5Kao0pPjDNOFuLo&Kv;1o7XLxBL$1JKejejO3Cg)(elfTnadlV=Zc8n3JnskMjA!tq!dLaNWcN9 z)#$>XZVwk4HLto8sS$M^cuyT=kj9pML=+yO8e zUVL4#>^u8|NpO}PPLzEj<6I8fDBh1YqON2ac4~AQG~{MwT3}aM>t61&BomM;s zrM!DzUxwt&Gi}Apx#Se3bUd%%ggBAC5Jo8iA*@!G(x>n{%{^yn7(sQi&hS<6s@>oKR9;@NJ| z;z4m~E>4vcAnb#QEWhG4gFc7$>V&b<^o@o|%1z-mGCZIf=lz&WIJ#uQO4Xzj?wT*% zyBV36lE1e91+`3lWqO*p-c=%3*D-B*=it$nhPFtF25D7l`;TY#_R<$Gn3k{8MJ9`x zn^81Vja_;muE+)wxInA}t-vom`$EX^0=?6_J!Z~CWG;f*m$`p5A{cZ}mx~$fd09O1 zVQa{%fy-MG+2o=W4PmQ6)$NS)HqrxbHW+PU{K{k2b9og!E_vA}$(c6Vb-8sPaBlzW z$s6*=e|ByzbKzWiBr$C#Ks94tONN3P0X%meUfx?noz9Ex%vK{Opo!KoD)AB}8m`N7 z5PC2%tqf;9W-ItDx=S+mcJNGVxBz@yqxz06eBss{2R5vp3x0elC4S0f`x_&SRF ze&_J?0%CHY17%2%7tCZ*Ok{3WV=WCYp?>f&L69N_RuN}?2aDx%nLEm9XtUF%Q~ymF zt+Af3uI&OF02GOz?V<5m?tJ~hpbA`XJ{NzT_546#`Tpwq@J6EMa{X>s>D)e4i#M<6 z4s);S{XMrnl2|b&dmjV!^344df@gBl)1j*Q0PV48w$7aG+@I#>%%KMT0W)^m(CXv^IU;eZI<(N2UqcYvu&CBl6*}Plq2A+RDr@33mg2b4Q2DUCm)38gawP#@l!i z5h%o9c}L(I5k-eY--2pg#;iAg(yv+hd|)}tY6?1Pih;<>%S%{N(*NSbve%98RiIQr z5M$`3;LY}xNZJE5eI0hQALO4`7DTx0(#CCh$R5wJ?j*Uk;xKZ0p<=)d@Nw&8>Z#;y z9RY2MhMi}kGf8EevZVV@|3BgW!%;9)#)qkR*H!b4ATid}zW-IteUo-pk9I}fd!9Kk zo`;8}r|0$W0J!Ff?W>@&Dx{ljO7nU~x`}0)FzLp|*;@H{Ts=Zg?cweVZrl^|ptD{Hte#X7g$c4&02&nz4^I}AAS&Yc0 z?QK>Tgp&a^6X?hg5ygOq0s{#6w_yH2Nxt-I_+K(#(n7xjw%aXs9WhS*^!Efj;G65$ zuI}7%wz`LI-FK0XfzzQ_ZOq5wXBbMT11z+QaLBBkR4%)54QC1=`cy#mKKj_ z*eS1Dd*<-rv&uVcPlahPCcNqdmxkW1%zV~sS0 z?~d5Yh0x9R3UEHINBuAEgUlq%s1CZomoFdjCp7nyGgHLqu#*^&L8sJ~Tu|LPC_K1p zy7?2uujg=SKteFylLkrK*n?Zfd*9Ezg!>XH<2_7GjYze)>v`foCsMx6A+T>_KrYER zdPI7#2u_o(%60nB_WBzSSG8;AY(TymMh)4&BY!FyBR4l} z$7{K!S&vJ-z^1gr`m>NG-WZA05sP*?j@Tjm$!nm}fb$?+bWk%?Rwl62Bkn_u3w1i2 zMnT)Fd(2&$M&&axX>s8A{rl`}k%>ZhreqlHsuPn)(}L7;-wo4UfooN~K4O7k-SVxvqsJTVv>>$*jWPk*)Sw zV3DI8fZ@72FdV)2%~UcO?OvIHP!veaxoNVqj8ek$2z4h zaL0=XL<++B11VdL73R?|+s~cBn$&8lWa2EOVS1~o^ztQf+^ZEr4f*vjkAySHgcpMw zMUB3uzP?$?i=Ykx>CEleu!Xb(kNZ@Q|)Gg{iJ* zn>%HZ)D3APEh{O5E2MbC2(#}__(|t<;NSigQw%>srNMVABHlXkj}SSfrLzDuaMW# zV>~T2!J{|^XtjJPzdznVVxl9!%?3Y!?8glBis+h$fUU%#hm;K)?GTKMIDVY?zSDUe z19XBIsH5QiyO87^rlzF@>}AjWt%f$zbA;EBDqvw@0ZuSqU#_I&Bwj08h`}y{n*^e{ z%d`?1adq})pDd+xA8Fh`0(au)RS&+5WW1U^ly2oRT{sB8eftJ9Jus?;96Phe9PPEs zubGo<+oJ0=L%BKE$uqylr^K}38}#q|{2)xe(_rnuLq)|AibECU zFah$t_wfZpZa=McbtjMnsZp6cxdZ4j)U*L-a4&uPRxNJbVFF6iL^Rqz;PVCFk}zi} zV}7d#Jk?u=LCyvh41BTJ+PuV{hP~3Gkvu|=5^(YG%8^Dbvj^|JRc7uO7wN!{^BYYi zcrN-Pf-cRqnC*iZt!}zYhinPGSdl={YgUQ(FRtLbU2I5Rn~&;@(Di)uFc8S)s=g#r zeI-isPgGaP@IES=<2!rFQfav1%kVY2`T?HGq^i(j|EL4rGPwBoLuR}_M#NFFA0-aR zg2NlfA9RG{9;})f*RDV+neveE9lHTp0&%Mzrwymk7{O4&gL)%w%{#;xD4k$V{+POou)FHK2zH6a(|D!S$)>D5jva_BK7T1Ma2EZ1;E&Pwy2OuiiL%PnRs=WU0z%rnv zCu#Ecoa5_i*m7$%%7EH$1yqs-mcw{k}69w9mK@u;Z!X#rQG4DI~me*c?3E`DRdx&pX| zLP80dZaLASajv!17YnK4Mc3UeR|tw*iexKN%J2QgbpA5hB{DD78}@i~bE(Pp8L-O# zDtIS7Y>FtgM|yR2Hg~{rZ^yRov!YiMM(R^O2kU{VNa+sH4DVKzyo{FgnkvVY_yp|0 zGA$cyg*rSc2#W$uBk-94?9m!hR#DNn(7VMxBr%Ze zI$P4;4?=sug9qwsFt20Kr1r%==R~RZeF?Is6kQW<_~ryV&LLykaQ8uNlbWvcxvP74 zh9+>blqu8T`Fn9!)g=~Qj!%h{c*b@zGyVd`HKjV;Z>#4cHJ9G>l{ax&zuPB|8emOm zCT^N5{{#p1n+DRtD2!A71*Fk=uLxI1z7vuve34l#F*<`0+Y38D=ZNx0JIoWOh&Bm?YaZq8Kl;P?f>IV`vjn~C)2Ju^FOYL#-LLs{1PWIB7Xjl_vm9qLq z;YzM2=j8`$4|Ij}37yRXNQoBcZ?20}A23=LC8rg6vCF^x|*;|vBYR+w_=f%$AP29>= zXO-RRvqBSPH;6)Mcy2$)sj+nt8kPAem>!$P{`mfV{VT9hs&r_@y`;JxVlRthR)4u6 zC2f3n@>CZ~3%_Ey&WNC6zvt`xJdF7-J68TZ?2x}}HOD;Xzj!4adkO_2-8m;WIJzz2i_S#|Qsd6juo#Gq6c?X>+=hhGAmJQlVUS`d&)5 zW(lQ^lwnnv!Tnx@NjHf+ z&&cyzV~|?C9|gD0`UP>s)9}k4kqVox+a-4rT?K`Zja;u{21HZ}7x)}5qip6p2nsUp z5#5g}qwbMb8}vVk@l1JErytH4^*$aS9v94%^*C=MEnp<;ADGD~2HAKhO%sR3ED&)DMR1;E1FLLzdcJbFZm(d*eac#k z*eWhnzZ{P4s;Zb|H1s^J@YDASu|EE8rCMKTsHoIZ7n0F|gLW#YqUGSU0{!yp+09wk zb=q$fT7g&tLk{*ED7-IJe!WNoLn8iCF$ts2t+I>F2JM2`J>0lEJ%(cgTTVIVZLl8 zIWcqY_nG+tlY0U=WKGN7(`6;TRa}893tT~{nhJJ!fF4EBd;*{JU$j>R{tX~nt#5aF76N$>Y)itj7p=9J*~$dKP$=#1RE%k z*6{z^5I1cjZfkN_b58$-z_reLH_=>KoF?4#*wf-1jS41&!2Si2;kJE{twzs;Eu+;T zU$2v^o5RPoc~l(^vKO*jx%0&{9s3?j%iYXq)KBSKu8Xyu3=Js*AE;SAa*Yu(C?=Rg z36_?TBsZJCWX~kjDa~1cyobw6aW)mI86dLqtIcR~WhjHR57rRiA8=+s73;F#nQHb$ zLw0w=zD7IxI^9)sl;YJZMdu#!OGwFv%=uZaKUB8|P<8FS~w_zTz}bHeGz|H2~Nd8Tt#BGM**VQ202c5%(HN)Dul5H9#?k{kp#n11jf`!f6^6nhrk`;wvyvYDRN4l zPdJV?E|<5UyfHAuuXM7k%%{uNod+Q@^bqh+U}#Q2vC`^R0>=Bi(S-|d<3G)a&`9bH zF-p6*Y*jN$aJ%Geh0^=BA|=i`k88&cr;b}KjKuk0ZX5#2()W}Udf6z319 zRUoa5RdhgvOEg>{=%;Q1ixBWbqG?3E;vv}G$5=7M{GUk6EQ8sNEuFQ!ndRA*&p>gq zc4b@+iZ|gG;xr-pW;Ap1>A!8)m9p&Zv)xr!aW~1z#EfgMn@zDzo)IpZ_F-Fh(TK+G(u}tRB zQn#|{YZ^1;xeebje)h~d<1jMKRy+iy<+BYq&w;nI)QZxR(r4&$RcN2zS_m|r%RXM? zA4O1_&PTvq1uM6AE_#OXL#G;|kE4L9KNi*XccunVFs1t)k3)b+`9AltUWEQQ96`FB zCn<0kE;YX(%0gQ3l%}(Lr^edd4!TzW0&M8bJQg@9LNdRM?DFr~sf^Eos?lC?<5cGq z?+!=xOI40uy3V&6V|?A~u^)VdUNIf~v4CcB+f^jM58`z{`~<3Cd67midk(`3Y^k|p zJt2&LJoAH*|6!xptLLQK3)1p)LAP^(`|U?T)HCA!?3K;hd5s2+uU`EFeRxA$pg~4% z?h__Q>mX1arpw?~EXcfk*<69n=#I;7Dy)*`^Ba5sZ)9Vn${jW>3@c_ZYHndam~#Q_ zr^lH(xx;ofM{Ie3_U9oNU+Os_V>-gGQKC{xI!lRXnKW zNKgP*jh1V(rGJBzFD?%NNQGuHFwsFUO5X_@3qb+c|B!SItpHr>Kn#q%OO;Sz|GF>P z?fi$n?!qRVTe>EL$2vg=0=ZD}8W2Ai|6qs@8B&*J+ZH{Tj+{9RpT_@=7WO>NW3kOBh|`D5As4!xQ8`0D=D_~G~g#RQXr11}elp!Z*> zC_SW|VhduK>}368Vr*PBV~4UhJ3bL6J7F7`Ri&LDM1U9&mbxL_P=Dvb=?S(r&-bOW z_KNRZnP^==;a82GD0AY>R;@pUA_N?apg{(C34$LC2ni!XbQ886wGP*xsvF5St;IZS ztk!Le>NtrEwX_U1=aRP@Rql4NuP|fu(Gq>pek{jBb_rM)>SR>OIcOQK(KUhqzA@?Y zy8=AN(h1tNx10+H5D4H%Yd56#)fX3j0)uX#OF`gO0vmepieX^g zhYw;vBMV^Z4lzh*AU}Z|r(Su8O3;t?!B@sM*=hI}z0ZkI09N2I!jLls$FX^Xg$Z8? z|Gh6v^waRu&ZEm#)PKs+9*l|7{Ns*n`KemLH1Tj-=QHZVzj99y-nd15+cEbLv!7ILVZ1TC)YpcoeJNeQ8WAw6o$Fh9!1Oc1y5f-OES?rTuntSl{o5EugX%4h7R6U=z_%| z=-2k5EF`Qz(qObZ0{50^>x;Kh?pfO4$4PGCm0mR`y; z`n5>M2!Kb2!V{O5moONdPWy`V3(^e0flZyOXcMgXwS!$Vg#)mKp^wzWQ>Wwp8WiI% zzCLkxOvPEzDYkOXM_$>?(_VNU<(Fuopto}mpG7U2JO@zWA6 zuJaRnzsL6+S$njWo$QG%-t>urC)1+AmlKeYfu8q{OaA6jI`SI<6rg7XVj$i9dO8rt5LOd)9wy{Fi}=GDS@`X2Yw^ zO;5Z?DfyD*#|Nwq*=r2{8T#4c{)X?aFiwu^8`CLXXiV6vPBvR+fPYEDb@-fIr4RT(!57{d>tm`OyenBt1XK)LjJA4 zK1ke>BEoK9M@nimBYW!i!}k0oa3Ew1zhytZaB#5sJ7QH2QX+syo&b~ZF1G7L!&HH?(wa<3g%z_Kt2=2c<{jok);p;J?kwIV> zlnSk7;;%NyAM9*s=-Z4D# z+fJo%Y%lh%s_*3bL)}DdjMd)l6!cRjKkui#sH)+Rg^KwfEIDj`>8mqvt_25zm-hCf za>ebVUr?kOOye)K8jp_-H?8W|F5O zBMrV(2}dt>6w8fJF*5_A?^q+Zkm63mgDf8f@FD>M^P8oL^|bBBLb|6t%gb3+?jF$< zMcj<9)v`4Us?BO`KJ_ale;;>I0%^;itd_tAu?b;O9NloS-sLlh}In9 zES|u2G!^QpbT;zVeY{)g0eI})_&DB1M%&-p^6H|k%*H>c;Co;CNd}5ob?yF2xY|X` zOJJMKNlVhIn^Rq5{ot^=?)ZCA1}v0s#y_q5AK+^u;l+{14XHodla_?G4{R7glkeI} zh40>KG_mChrFZH>y372#Oj0#P90gw&<28`=%e3DACAxysqoc8L>-WDJqt;#nvY?b1 zZsnjqzk#3xW)$=J9y=4%bBg*tICBgJ7f;vfJij!UmvH=@<;aRcQntC%=2GXp_BLSE zWFQn3b+oi4pc9()=xDFw&;!Ul=xYz<%AI@^AeDv~3j>M&$sBL_j+cHny}dynITLpC z96vSj9iEWHHvYT! zVD9PD0fu8BH0&k=mkHwE$h02|n3G1JpPH%cBY=dLdg#grV<;Q^>m6<0$~{f&^nSwk z&UGN=yL(`<8o!W5HN{MtVv$V#`^H98`LgC%!qMu&3_pXU7^8aQ^lHztZ?@^tmV6mn zRg#po4{Ro;Wgkt005W&-C2%03C&4jYr7pGiPuhnI$XF4P>y{7|Ezc^UA~%jp6+Qn< zhH(~Unbh9Vb%4xPzdm$otU~Egr=uA#`Ju-&{(ZMgmJR<$Sx@y%?gFwyE0^{?!hR38 zTPJCM4w1>BsV#0vMm}-idP3zF>D;yQ^fC(T{bw8BKWpJ?Ytr>lxurA#1yOC{(Hr!0 zws8!*Qr!huop4fgn1GH}QMqjOn+sKtOJ`?W8;HD&DbO-=8&;8C6nwT+dMLsp@0NL# z?1-U-@as)E?J+NUr?KiXXjeeej-<C9L7R%LsRQVnc++|^A zhS`bVd3|n#1LA98KW6%KK~d4gZ{GljdbRhZNR9Qe7v53Pl;tF1*B(r*Y3(jZBP;+`VhrF7~oK1EBsW z7xjE7Q=MFSC2JN7W|?#B<04gNXM)}Kw+5#znYh+8U6q<)9k$)yZ20e-F3=T0H4Wzh zzodvrMrLLbEou7&oG@BB+(#N8lp09$@Q+aF@e0iRv9I{lyW~@B_!Z}|g(J0E{cj`! zdEO~x{{vhZq#RBwowyFINP|y|saCs5C%TisVLZAlFevCfo8qC(+zHaA_7sDzN@_n( z?2y z`toK;^@zYIx+KR3%X#w_6X)9e+#ifxx|=EaL!>PcSH-y5q7@kt$>P<&+Py)S@y{uV zKG0)0uYcFwNx$}fjK&>oshfo5p0ut^>7|95^O&TF}U%l~m2 z@4WQC#2-bFFF*<|86y4*13zVbwnLcPLmDVVgiwd#lAK?5gylli zagq#2g+Z?<-}Ll>W9W=$uW;017p%cZIo9$rR|Q z;UE5Q8g~u@kmL=LJ)I(|i@)H2c8^d*SU5c=$I0Fv;#?c-^V~qe385w6Qe`>O;&&yA z9&6!N@^OT5Qm*H>JOcsPJv1Dbb69 z++tp@dxX*jq1mGMfm?nX0Hbn-#EpKgvor}OwkP6Ol63_S)8IG70)JQM01KLY$W011 z51>Cgp9_?19gd_b3G|t=u>|civ$ctwZzGOzCAPjDqIc4!|h02g-l{Lek*4wD<;^{Q9Q>~4OVUY2VT62k5=8+6FG6ZrU2Y+$nI5VFF1`JFAexz<^;b8u9BWrWrgmn!g9Kb9Amb9|v zCI%nVO2J!|t89hClkZZxf2{6fgyyA|Ym`qZs&G;|y$Z&}Rto@ga}P6(b*)g@ST;LL z7L?a~ufVzU&E129-IA&zyQy#xC0{6|GutN>rPrz@`!T^(q$8(D-OjVEU=fOczx^*6nq0(34 zKEWD*tYA(Bpa(5&Zbn9}RKNSdp)!as@hqJri{quJ(Xy41#gH~oUVLL(fN?5lV&_3#Khd$-{c$NGEBnS5Guv2#_foFK&)s; zVMC$uQO!msZ|aV`j7?sW6r~0$*MnuTY};@)+onY|5lCw*TUR;1+b2bKM1}{E%b3czR4H9&pHrYkmXOhK z)^F^B3VcnCR@fQbYz(>c<=sY!Y;A2J967L)?9}icsis#{$3r%(-KK4qd>u3d&e+?? zfRT>!ax8`iK!2?E4H)eOEnY`_2Djz&d5lnpSCEONQ4e7`K4!`Op~fjl1ILybcJDct zDpgZ{8LjR=XKQm@YJw<&Vf|0EL-p(&e=_V5U!t)M=3$UISllRI@^{L}F%e^_)1lhP zERg!zL;dofBWn;*S`n32&p>LZ%vyIKD72BT`DCA11`3zI6Q|^LGs_d^ItnV^8sy+m zWx)0_yeEtB_Ol830~9C=m_9$3gQxm!75<-}Nc$r2l^nRM|B@sw|#=FCe`skV1 zDjyO`!swe&)Mag7rBp`6iGGYww$T9^a&qZc)KPD(Ut%lc|M0Z9I%^*oezM%+VlJ9Z zLq^u!AB>r({Rg@M;k%Ek)T6ZiQ{#XB$(TC{$imydtAxYAi06l#)JM)4pMP-c?(FQqd2xDiX_;m`3zVF%UvZI8MCg-=f`l9q zX%pq7x){VQW6Y-+*7wJH5W0Ck-_b+cOEltce%^;RcmLdd3ceo{2T~DnL8R(p}FJtB?&jCxBEaLHOwXv9l#6&=$IN|CaXg@Q$@l=0ojwF$_)y0k^4b~!M zx;}1woCHrmX*1;!HfD7{T&m(UPx$Man_qf)k=?w*p^jwOHcHWQ*FoW59eLi!67dyo z7(Gt3FJYfJv4xMLV_IS z?Q^q@y(5OwI>a@j@dTa#boTqOYxMNUC@F*eX5sLB_G|@!3H>OL?HGfqB?3hrQ(4`9 zwh}_c;crq>QNhd%C?LcJ@7H5mP>KDdy#hwQMl-#2DEpS{T{&=74 z`MTU-VJ2gr5#Pz|%8EbuP%!j>OIXdbu1*jjSMxrWg*1kYhp*0u3C8L$gg1{`5 ztCXd806$a)mKPKZfC3seIlx)_{D^e){#c`OEhN}EmT7%IJY>-ha+p|LH1Oq3QB+Y; zsl~$VtXqu^4lJR zyt;+c$d)%$p}1~1+GEsW)atRlrL~qo=n2!<0VCD>BIT-J$|xzSPj*1IgzW&$E2W@= zlva6L8%4Ao@IM%mogE%JXjCf7jNGo^r~yC?HOi7X+ZdBq$Mf^^A-WPMt>8(cbazsQ z7ps}UuoyhemYQqI%Jx3xKax*+5-Q4%W^o}=q+~%yY&|{^UpfizKh-PAgU7uzA+$Hd zUVmm}aCX*_y&iQR{F~o;Dn`>$japEm?H?7>zHyV|B*yyWCNvlw6Z3qJM^qFPCkwN) zAgX1Z3q8*_J)jRBNKFUgpD{c&Sb06c=shkQqEgKoO@gTesNGqwyz&_DpzSUOEJsj9hSBg=i^sctmgN8%uS1c zdA3qNxCA8H_Ap9>kdtMmNX_20BS=Ax4;W@m71PM@2ZpphgeQIa)ZK|PO^#lG6i-b< z1MGSrjW0IXCUIUSkrWPRA!3I-y>+26t8KBHVNZTJJ3XBji1*=W_!LzRnJ9y3y?WO8 zjf-U+GF|#>L49+B2J|zY5?9WErigO?C;E1`4rSJ@F$inAecYH#@ zIkD(f5Gf)I)oiNYuu3v$fz%Z`Kb%l~J!V ziiub>Rk5ff*H1KevHN!jmtNgG-voRgXeKtHNEb5ylO%wqkb0}_z z(ga?L1@g}__g!XDH29Rmy54-{NtF)DLVbX(17;)Zo}apssHKhLC~ZTBse8ZQBgT^U zr3zyr=yS0t>HsHm=*PLu;Pzl=X9xLLEX_mc69Tq{1CEbfHof2xuD&NH>6b@1=HuZ( zV5YwJfq-J2G@r%17ans~oS{7;K_aJt%w2LVJVBwUlyaZW(>Hv=J zSe|%#YAUJc1&;~!DjKm-6}&X?_$n-u zx{p~!R`?!MYB^F!5d*`k;oiK$odk~88CKSz-1%*>RF~hs+xdms$dox%ToXMniiubc8yk6ivz~Ut#A%QVx?~fl2prGAo9*#(kl}samXHBm* zsLlnr1Yyu1XUQiS`p^^X7dpYlPptxIsQM-6stlj(M7<-8XO@H=1BxYZk+?6%wR zW3e%6w~wFXdja!^dpkQ=LXj=}JgOgG07n@a9dGptZXnae2Mj`4){8(JV}S-baNkAqO{s z#l_QnHK`u@Onz{ae~$%n6|nIGef_c5<$SF%&=mZHx_f$dmPXWlx4fd7 zVGxm)fLw48=&O)~W1ZuTCRzLHx6{b>XmP;20$|bbkb%Dmm|;Q)9t-p(c0k&v!h_xy z>~nZtCZ$glFi`(ai1Y0yn*w7~yuT%qS8ToI7BYoPP9cODq4|~nEEj1pT>dhty-EIO zk?S-TTB4d=UQ;uaT1h3SI(XM}^u=-WpOog#vnux`%O$5~j|7GknTwNmZ@2at3C|EJ zUwHLVMt`E0c}b)H^wzJ(X`v34ZPOH#@bbF4b8wsqQ<>CTsetU8SS{Z|Me#Ybrj4FI z4nXaiK!z+@2l=%O+wk5YRtPTp-LZ&EtWAnh8Uk_boSI)lY4?&Z|1gQ4f}vEYZr%If z6zN&jZYS{m%pBLz(XpyufVCPBjG0ab;Z}SZ{Z-Ew8&j0bwY3cXp}&;`px$L z^I_up_eLPIMe=WfBsfUIJj%3Mo%Mb&RiQ+sg-VE{1*P71?r2DRls4Vd54y5`fcy7f z;)W+WW(k&HVq@W^_uW$6=eFP3S=o}GJ+3dWE_x8P-8GmFmv*4Iz`KAdxL#qe4>Jxj zHh76V_i+ z>v^1u4by2zY8q%bF$IB^j`;4~1|Q1H*)x=Z}=d~8@Z4Uj%`jaUOaREED7f!h?i&o3gRH&%S%gb{i;sq|+ zL!Y@1@~xj32OZSeQ{ojy=53)|J2;R%sSwMQIYhlnd+U|YU4*eKHoEkL{JF?Ii#9Gy z(&BD&FI@;@?$QXFI1v6xdX&`I#Imce#?uZ9ddT#rXiH z+HbdD{5~xa0;%ooz#IneB9S^ZP%-x8q$x5@Bj&fzDs8B-hS0IdlSFJFxU|UMTFJwC z2{ix^j}mFS)p-mP^k)eBGq_?umF~Fq6G@e!?p`P}7^1lmYRqx4vzLxRsso+I&B4kw zuG{>pm47Du_ny1d=#TOA*l%{g?KsR>8;e_`KaJe%16>Qc^Y>}CiAJ0_^Hj4tWE+k% z<=U$sHbZcGp1-+TSIxJQ@x(@qGV9?MeZey)`(;Z{Jim%?mX+9I8>g`GAJ*30hd&|$ z<*kyURPeSSYRK65^^CSIkYyB|rG5HMK%vrHrRSXgxiZ7`0*eW|>OZBUy4t4dJ9H(wJk@dpqdnRL`BPOmLiKj*;E1 z*xm}hgRn#Z9A?j*lsp+`+!gv2@zj@r3h$9wyq3f|)th(bJaBr!6&bsTOt>)K8d0V8 z9MbsS49Q#<9~O2B);OTVl)`}}W;9OY-vnYJ7dDw|w_Sdx== zOFQMW6_oIG%SWyfXH#_;Z^qP6RLxk?UIL+9G+V-L8^}Wo?cNXS1mZ&`1oogF8pe8@ z3(P(wBPjRi(sE&114DV3IRL-|fV!o$w-#yM2Lc}K#LC~FgTlRH9_lSuq@b>mdVUP8 zH)KG$(@ZzRwbxK?T$*n88geusUCvrxzc`MaJ_q~D<%MxGU8k~Yn8IB@b<))ukI(T> zFT#Y{pTiJ3kr@(1+X1lck%TbFr+z0%Ez?q-s@;07`TU57jNMVonlul@jqKHf9Eflv z+ocXgF&G)eP|c1%rLv_c3J3^5PXa#_#N`!>&cmzTOQg*2W_s~(MY@>{hlU#)d>$YR z4bCi-qPK7Yg2@pu_eDu_o@VtzJ@qkv8P~(7%@j68;jgfJLJvhnKPozj`~;&)R${2_ z;EHd%JQ?L(UcemYwE6>+&XMpt2M_&WOfoY&dk(zz-@hNE;Hq`rQ`r>N95!p9xN5l; zmaMZAUa-RO*r~&0(Oq%oI=-j*7Fml#xM*+BR{Z?l>;*?ogYY+$JX6AtTdqH@!ZzJ? z97Yn~Wn_@wQ$arx^ed1Nw0iKaFN0G$F<@eDHUyDs$KYP(INa1P7V0d4t}Ofyrcw`& zx{)`_Vt8{e#;o(QIC-i6iY1A!!kHA%G72*qfOJI}_YypgOMg7MIm?di0iK+-r$cPzoOD(N4pH=OjYbZ9N2F#wsQkB8IYGY&iI@>UqUH6xi zbL#7p_(EZY3@Z=fdN0DR^g=CS({l1eWgg1boED?ZQSvv!vER~N&E2I0BpmlHD5!-K zwD+t`4C?7L|5bh0@iv|AIJq}#YuY`m327$*JcyakqY<0HAC27(BXHzjA zA8x*RE`cG@R3ohhPQv_ZGlKVb8>^eF+T> zxYC$FiH$K2WV}txyfBP^=&_Q={X}pp+b~2Hy0%^>A4D@f9dCG`aN^}k&0VcOhIT!G zXW102)yr7sNXpULimvl_D+9<9u+f75*7p0VU$*=>?bpKMKc_?vh9wy=D6h zl{ByTy%MJK8@D&v5VB_o$9nexr@PvqF>)!7kNnwx>H{kx5Mz$H@t4_h?y!^FCxm{` z5e+B`WsCDPGYi_s3EO{2^6<7dQ=Zo(BuJg=vEYpO_ru9SWFxV%I}<9nT||pkkFjaF z`1<_(TbLDc78@J29C|+?C&< zKE=xQ-u@nN4>acB;a560^fKQIxRYd$8}I!Vx3-*gOQt~hWA@_3A<($j@Y@>1YDnDH z)L8?BcyT~tsy;=G6$+r6W5< zP3B9OA1b;NFX9f#?p(ny#Az(24pLwCvg^= z_DD9{2Kvw^p?b9EVSN);^;&u8~?z7C*m|U6%~D`4Nf7+ ztnn5v^VR0-t?{{Up+&$=Z$M_a5iWU2UqgeD1!T6*oXpIMFOV1Bq5NLCxmvLX@a#Z? zVmSLGxM%T!0pnWc27B7*!;8%%z@=WiT3Y(EFK?c5{B$zEqFAj{=5$)Khy*M2mWTGP zobn_w32~tCy+w6tX=z18Qbw<@4HV#k?oh$nJ2}b4(Ju%EC@}sQ$6!w_U&*0L7+Z4N zU#%i^_L>TC2w<$m|624p;?^pScvbMN>=pAEx2d3beXqiFi~dNpNozEUd<3`a7VyQm zLN0r|=5eg2A(l1gWBKDE>A=)ZaZGY&{b679ywg>96r6F1$*9|^#gyRumN!lG4`oo_ z%z_V5j)q?R7`obq9H|Sj?O>2Eo7LxD|0Rkh)86Ns4c#;z3f!_82qHjPkzkGSd17l zl2h_O8ovLQpmD=OwuLvz5!zGT8WTsAz?Y6ajujV)hW($2Oi!0|B}~5PdQukK(hr2W?bpqW4J7;S)hoA*H^&9SA8xp zXLMTj^feZp6RB9Fvjb@S*RLT=;F|D5J_LXh zNMsX8Jpd7K7ySxm52IYo@wDL&@M@Mdzw6{1?pIj zvB$YRf1a<#+Hb~N`5RHr)%XxikP8zrY9)Lq{D-J$=6qt~w)>h(>?i8vl5RDc*bvhL zk%IRvw9D8*@8%!iS5{Z!F}3u!z((f3aHCx8xw77Ia-UAZrE>0CeQcP`dM_fdYpKc6 zTnF<_G8o3mF(iEW*@pc{DU1pnS|K^1iI#$*?PuG5z^ZuK)xX~`5os$b3e_(WX8VZX zOc0EVus&kJmmohjJ`U>=dLtT1Kk?kj6<~&?uD%y19H0t4NfDmjN`E$mc^B!DA!hd6 zJ?kruU`1b)L;HT37;9Qlb;)7Gwkamqx0QYej4{It;fN_>Z9-JpA)dDNDi3*9ic~`> zms)p_u>Oqr#_a|=LFjep6%naW5(dZ`$M~(Mtlg@M$<*+v7lVc(QWks22Oiqr>$-~- z3Zjn4NGvN9gCms-^yDxF0i=p*66J(;;{R*!E8D7EyLRao1(A^M20>Ek?(S|BlvX-K zK)O>JMWjo*rMnD3kS;}}q~jg)dG`MB{)W9-A6y>GW34ssdEMh0;~Zz`oTsJ?emh4x z+fFV?TfGzP1n3~*h%|e;F@v(&`RUW9wM6Br_GJyrst|tH_uBQ(W~abjRe|B)%ugT_ zjEA!_GeNcwsUKh(=YKRQPkS`LFX=T&lm^#Lq@n074r%}RP%Er`%^xzKiFx#oM{AZU z;k#Jh_F9{u4=x~^BJ)swv_3tibc@#rN_jdic2&kmbzh7UWH%K=uHg?pt$R7aR6+Rx`r}}!p zM0Bo@x?qPDMS#}JaYz8VxxkT{F_W#WsmKFjTcB9+;>`T+b7_i9$@_Q4D26;b(b zR$n%v1MT?l2oONiVoX;XIlNIy=aN=XDa>C@MP&qBl~h%m9=*(IeP!cZRx0z=ZS`Gi z^&0O0cm9M|A=R)Sq10_c&G};7%kk4wp>tMxQj4+CMwpppwCE4Cf{Q*`uv(CGxyFN+ zz|$z0X2Iw4^JBNsE<%l;wi|~opK0>mg<}2qZW#PY2czNba>6d~%i6-87ypx)Z{KDL)t0;$Q>e!rIXk!{z+Kw@K>ho+Vg`zEP3wda5ao*FO_ z2<~~f%g!Ix%weOS=IC{PGwt#USg3vdU|xmk*?<;F@vpW!X~h4R3&5N~Tq=p2u_BfK zKtv=L+{Rig$`c`!dIXiJAhlRipe==sRiq1E( zJ42Gj;IaiaJ|N8_E5gw1gLMc53W58fz*+LIxC6allA5>LC zqb=W`hg4|{lA%%euzKmyR##=3y&+sTlswhw>Y~$vrP0CpS^1Q>VzE;)=2Q}pG?i0 z7nT`&_QbWEw7!GZOWS^b9L?!Pt;STP7CHiNfGD6TY#aLA#+Eztj^zTRPEAHs)z`lS z+RIzEP$}AMH3;;8(a9pXD+p@raq9t**t_PU7p`A)^;x*nm|5MIDR4sbG_W9%RD4q0jvmTKju|RpxC9+}A9ZVF{{Co-=xkSD;1v+)BkrqNE&M0_ zafUYvWt~r_js6(dpeIA>-97P`_}9LMQu%j$&Lzy#avGB<;s;lkc7-!6MJ+?B3Me?! z%{7Nni_$rpns}Zvo=GFbHUviTf*t^JPLM#CgMn$q|2kDw40-X)4~TT+jQz9E>OXw2 zgOu^g%5hTn%hP=rvmu5Yt`E0YSa;+LXnlB$Np7|DcGmm3%esUftQ#VAv$HBRsfy*k zu|rS#xW|#-KDogB^S!ce?EPFcJ;lc18XEOL1PBFyd&*MxN4^19j*7GSOPrR%VTdKDK^i3kV~1M3wnPE?uhXJLvLWu8cq0)t5}`WXs+ z%r@7EO0TJ%Ji+RdNfBtcB`m$UV0(Ea%c8wgPw_eY^EQmjkm3P9bdzGa<3OO^I6MR7 z3_>ean1E%pxv^m*J`OL(Fjq_Txf6hhA9Z;9!0zi3_0XUyamh!DJ{M@s@fl~pVC@w4=f_ZBnALMan8U-44u01Z^x!a~P)_vsXJralkBurM)HJ8A z@hNG}cXGH;U*{Ei8^>0)gnrJ!r1!)kka2X@tNNbwqU#8$pNuV$7i)wFABmXoNB&o4 z>|0yt2fM2ZoneweyLPAY)F@W+UAS1K$uoE{T)8>03` zP*2J_23fi?eRqc^urY5|=@O~v8DA$aDPe97c4_SQrY48TGP6azYpSbV0VoF$?BOHR zQ+~&92#{1aM0&2qb{KYu;Ts2L+#DQUZW@uR0CaVtw2H48DJm4ky*%ARJf;zct<^VT zF2QAN@`?nBU+RzTgs&$~Bt}$m0$Z|2Y(hq{7Fc#8uRo+b<2od`nhWts#cv91ny)U= zDMN2p$#s$bkQnXu?_SWxlR=wkMFzr=d#pq_65dO^yc45VQf&-*01DNrzK?qT^y6Th zNFBNGLs#cclLu_+I&0Cx0ReeCWa|~><-H=1uMsP%ocOBaBF5S8we4fQn0wv#-rKI- z3lpOYx!3S)7LtG^qQIUcpNFrc8UV`iEaBHudi8kaA3qw@Ip~6zqmHifD-Z=H58vX_ z=dd=5vF@-Wn_J{&hrBbyTTvFo{54g=SF4jz zN16&Rom8+j(7(r#*`-EDFXEvkA5Ci>@CmMk%ApaTtqP|YeTig$F{~@Bt9SYrS`wZQ zz{05Gw5yIV;=3Pu2ZxKGQauCTf`usY>m{Y~x_`6E+g9fV7_JfhEn_G-__GsnMCCDfhy50U|&xW4cup# znq+Kn>Vct4R~OEvH8tJ0ZJMR0br{r8!F-q4;R**?l;&^ZEW7x)bQSqk@}dbsIA2`keFMGBCFi2hw~d}{b#$D zaBS1abt*Nbkc-9D`9J8S%R>(^@hN6%Y@>>(I?TI@{6rr-2wHji%pFo2sYJZurOl_J zyqI3iDJ+GC5haqboNh{0U3?CYBxTpsqGCv761~7XHMMbE=zO10T+I3a<3NglBfbSC zS05+&LO6fd=Ba~czX19`tQqi|x6Ii7LzPFd&J% zdiAQbqB-)(79lUFtf7d|%LzytR+QOp-M)IOT@1`JsFFZlK%^VjVC=uXEjG~ms)v`| zJ9Z~ztzT5sgY0(IT)~C+2d#!EU+EIEAJUnV_u8)Y3hJ&Dt7HRPUn zoz=M??$~dLBsyyF^6+t*lJ|2ghB#1Be*sAp)eUd|`gc+O@!6&^I z9HP>Ozk&rO4m#01NmTDU`8W_8)_%jgi|sK8`Q4qLmRLWQl-wsHdqwn^tM{wEc}&p~ z5L{p*(?s-V#p22H=h-9F7sj^<(PFd$BkNli@!3?VWy z654^VZbW(CiDa*+(s;Z?T2_@}yuoFixNdO{?of*3C!mj2Qx`BPXhm}s@H#qFob4QN zyIRtHC1tB}Pmu)rRt+h^g3;=)snaMlrTmm}Azbw>yR4hnN}?F*UtAWG2RY^V?!Ukd zEaMz)TDaFq-}01MYaZj0u*S&?xg43kGDX%N0h&FbkhE_tFTcfFwB`57eRB*liDzcQ zoyNkcVc7>12tG`3d;wC>7CKJ8wa3U4Kz3}!nYKyH{Rptk3=Jccl`J`Cm82Yot89>G zuk@_g{ct;W++a6x&u6_Rpr)zGP^?;o8ZC`7LMGsMLxA#2CXZ~V4#OU}5mvJfxQEwG zllMcs*k4~D0;fXqVZe?OXL$EKrvwKg7su^tv!1S5SQO;w8rzIYAj!W!-!~e3 zxSnDuP$YtJhg(a22fjEjo(B)A;1dI+12uq_)e)}f@VM4wU|l>Dcnq(kIxQ0fkK~Tp z!Gy$?0#H5?FObBZfk+VSXu9%4oW<~KvVtE@FD)&>h8|@%{3s#iS#3>SnpD%AFjEo% z=X_5h^(tW-@xqD<_F_$Ee^#mcb6sZ)QVdb@$~>yMyNy>0f!Na$FRfPW#V-t3>O88E z{fKDyc2X^ti&b<#)vV-6J7%3 zU>)}k*oE>gJ#8f-$n(e2l1*JOiiux)o`|aZZOgrZMk|^J1_7+6AEuv9Fd@7uFhl%Q z`Gk?H=(N#;SK+fip+ZxggQ*h92Z)C8Nvj>;f1jc>$&;qR4cEP=@2|i%!aR|e zNze7xx=a^&nZI)Xp>y?hb~(R0>)3CTRotwy(8vTtmE+P8Q5wryEFpDxuh0ec7SH`u`$rK z*x1=&n+bu}s;aj>WW}cu^fx^JVMpvZzbED;fENLDGmS&>i`j9py;rwgK3j98K7Qx8 zrk(HS&BH^M@KB97dtHI zSwCmtV3Op*nr~9|Ioa(RxV-Cds|MTttZ}J0#MbX%OSq6{##mDmnfUYV{%XclbR;FV zXzifrChBkFljB&SQh|qpfvEdPW_{B|>fgV91sE3ubUR?S!kMBZNrGoAg{PcK0C?!qcNYmJSC-IgLp7%O|NKZ~V zo5|7RUPjTEI|fiU!3S~l2T+0s{#wtmfC-1HszwwfFatC7VPBT8JI18K9S&YxF{IH9 zBd*t?cGbbqFvG4Hcyo<}$2qJKkvqVbiS}0Ft8P7@zTSKDz9WGP*ofE1&NuaNAK#CG ztt!yRbd@4~`;^x$UP$|Wdl+4ScecHrX0GNv14P{fdR9h-_LZdE%l9dpdyq|9Q1a1$ zBe)gg%*i!bBpPuN{QSS0dNye)c~5RJub}4%Bn{FWX8Zg;D1mu1>(2L+opAb zyz$CBJU5HZ&d!F0luEzLAjM)jhM)(g6))D5+!Zuc6KLe{LeLt>ACYrcKWIqe*Ej%s z?bl2~;)thFZ6M;h(gR%G7#;<&u7AkkukZGEC}8x~JOy6acW_aGs0JV&&=62z;VZqF z;F#TW5xV>!*oIvR*!VWQ6-{@L8&|(s=e!G969+m5BKvWT?Y#zzmt7kBTlQq`ar%c* z%^sxZT#XhzflvyXS7RTq?4PD}T-x>|KX5TNGE&PC0eS^-y`Djh>)R2>mzg(ol9|mv zE_WmDGFP-7C|QrdO{?n9LWZ;YNz$gDAmEpFF0a(cZ*c5+R&5|dE+QkPX71B-`KA*qs_IQzk?L#bT2JN?K|UH zrghV3wI_z6^OimeVIxzIS_!lGnOT&6wN%K*?5IX6<-tE_#K*jcsl^04j#uZ zXCLaM)lH@h|42WM-UHPUx&~PqmJY7FI$rx3sokeV(V;^oD!;hzTff|y;SmsE(*07* zlDAi`(H_Fd`a-p0I*AOk=bZ%Eav7WzPjF@2_iBYL8(jR@3PE7{0ISev3(a3s-W}TL zta;V(j&n?zUnkq2m*Jhs( zv3ry@VEpBXCn_m9kU}11M8!AgdQ7C}aXVT#R#h*O?n!OJlcuT|ZktQYlN`pOA%Ag*8Dem3{1 zxTpy8dgEg8CP0W1VbyG8Wb~n^=;HjG1%Go^KpS5>!(z;HZ*J&K7YPK?as0-xr5GRG zTNN|R#&RZEXpN;7Z@2D`1=W4;J^d^pS1UmFn@o1u&Ciso4YJbHAN0+8F8cS8ei2=n zO?3>UxLptYgTU*}z??ywk357ia@94G{S>nnDr5GEp7k4QX>XY=S3EDUW&;lSoC-_( zbVabC?a3rJgSxb(gd+guXo6-y9CclvgZSp3 z`OUpQ`Xah`rp#Yz`TBx=@vlH#vOL6I+0!=;R_q^C!LRjm`Bj#fKlo$+fkNGv?(xVU zAS_5&&&tdeaz%NlL6?B^7Mf$gbO7!zclO8arB6_JUtA0pigX6qm+IGR>fx+ji5WgD z?kq713Z6+X8CZ+r61d>qxh$Ag4Om3+!2aeT320dOg2m;$oPu09CPa-vM_*xB3+(i~&-fJ>yp%xv zUM;oRyw~!T-F!~nvo2SJ`l*i`srzk_z0OVXn==)r*OA!G1%4igyE93BI}i+-jqw|Y zFBNzvaZ}89#7+0rQ;ZL?pOUJI?_EhGiJUZHbAsL(BmHVi&tD zx8)NR7{so&)j`f##ibHjAF%TGdiU?%N~*CF@)aFwtzKuR`fc_gw*=J#n?%!2l^Z`cf zWikf778XH|*eskMh{RF|TSYg4hmxejcNq8Yq|rEib-ABVW0k;3(OhAX^*eo7j{WjT zUi^F#@os(V@j2&l_?2?uv+mSHnKJ^rN9cwhKOW`^-5Vl!>;vnZWrtCyGh<_)qt1Gm z#gI=ZF5l@=u8Q3tPT2aaSR?G7T2gL}FVXvcNHchhS*>Ai9+!0l-$wVF+s<>J6rE7{ z`qfFTY0^Cp)&>zX5SSG`_S{7qKC6!NkCs&4`@3uOCeXR%kAMVTT>JxOf8!1ut&?bx ze~)Yi6LSM^S&GkdN1YxMm85*;4#00gSKm8_Rk!UJ-dIC%al{12L!xr`Pk!F>p+E+5 z4miw&^Od0@XSW3sL+V!IbMtp*(UNM-xWHye@v1l#}Q0^%8VIM zmCdidn)hY`Z;0WSvT0j@1F1_52zJd44AOIR5gY>^YudXVpv+EQL(W~@(`g2}; zx7&2BCW9k#1^USZ&wb$Gd?j@U=^e2Cf`a6x&BV>t;hibH{MSz%IByi9bf?-Ol;Hz{ zotbQBGchHUF*ha6ENA@&D8L=Rfb$CXU+1HG@E&Ld8$X1dP)_12@y0DB5jvV^XE` z&P2hD5d5xLUpIaS zk|;vGgKz}Fe~77(cye?*6g>p8(<>f6X?q|e*_&U*Hu zc*Hs=Yb7@u{fc8x&Lt@u9(&_ODBv{DqTe39+VxJ7j5((n@kO2aUBeX>^o1zfL*!$C zTQRi5&z*fUd+HFhOJof?W$6TKn!2{=_!mdfm`l}VU@A~F&0B~#KNdgWjGCV`e0}*ZfDs*pK|KfG`AuutK3OZ0rPT@+G;`8KWl3O%{f;Ohg6)AJ=val{#u z%106=LGl6oV7iYn!zsGyPyLVJhghalxpam(*EQyZxZ-Zx2NnhM+$Zx^`d+iIGN)GM z@UdB(*A54`vRhNA&nMoL+0FxpULs0z8A*Jf`{sZfBs!3P4o673S3HcX_8;s6fQARE z4-qOLwnfX(P4t|ssjofm(%8kGxby@;PXLWmwcn}m`(vYKP&%Ucd@Ny2=BB*CJ8tR( zOhDOC=Yv-MDP87hm{dNPvHUh+S_D$iL}B;C2#jAu(RI!8MrP46Kdh=xj~hA`vVJ)J z8AzaySC=}7P=2(!2aP8-i+tbb$#?R|>w8_a)eIf!YDEBK2fw}lfYWB?VMg@(@1-Rr zRRMxgO7#l%2o+Kc0O$%hZ$Zb+?F_1Y#9A~E0rg`w*%8IKMUe0Bgbsxf#MV{IS!Mj+-mk%x&>#gyL`r-{XU0BQuyl ztXRl4ZpK0!?(4G{Ky&@OzK6Et6nRHbkc}1#ZEM7yQA0(hppz15dlDgW17!sE1O93@x4{ zVi}7HP%?N(u#O0-&R~qMVQ^`opO~`%`tZC3co8Y)Vk6IdZ{6TGcqc*b5BtY1^}SP2 ziagP=332H7+#q!(oY0BHlAE0kGVM2*Hj=^`+i=k(Bp)~AI0WI}o#G_xZEtS}M(&W2 zyx)1(?SMOOED|s6^x_Y~93rX1y#!=ZZ?w?v(V6U(MfI)>CNWpGpF7|b?P)+UR*1{= z6#~UDjJ11qrlyp6$eP-os)r!$zi(ZYbeCBT6ehTm=r*6{{ZAIW!f0a_e*7Sh--+vh zjHAHIM9C)RSYKWUS3fg8a!Ck!<$!9k-14`*Wkgq&Hv@!1TCCQ1zw8G27XojtD4u>1 zuw$(WK&_CAWh&>$xVwI*B=l7bv7`qc)PKTq1_ujo&_1=N@+MY{2H zapqP5A@ydI_ojGQ#FYfdR*n#P7 z>0u+z*^ge}bO{n&)h2hewPjaaEqA{ueC$j-O}2kGU21?8@ljYTAU**h@ZwCME?e!D z7ds#@{CD>b3BOs>>ou+TE2f0|8dULQ+r?kU(BuoerKM4)_J(P__l>fh2E|3J`2Ybenc|88x89tQJ?$+Zc%Ga|s_0&Pd}5I1W)Kkto8mopSrQ!HOy zJw2u*#UtrGV_8FPvGd6|BZWVL1K8&SGLTtY^R?*x@KxTtcJU?k%|7*O))(s0;LM=I zgK9v6gMQ>?l})hg26|1^Hy(JtX2U&VQo?6<%MDnR zI}^(mhz6pIwNOuV7lBE{yP~+U$lu>9H+p(j*3J%Q{0!a7crsVM=N zkvu|8k4ft?t{clpYkrVTj)yY4f^qPJCJ@#j>MDrP5SF-_%_<)VJhU^ihwi~&Hz$kW zF$-x5EaNu36N!cJ2NvCJb=DaRS?bvzj+Vp&rfQS;398P? zHebQuRA_LvCf{uxqU2DPxr*f?@C&Gp@g_j|D3sF@qR2^4mv~L9{%9uj0d`(07WMO+ z>nkBjw(#W^aQ_26Ti18w^&FGh*z(1e{ z#Jp-wdoT8;UtrOMo)r`nps)v7Rfj(WC6DL4D`q|N)4mcq3&D`F<=h&UWT!?B8JD|i zL#{DbG`=vD1t`QQi0!2XzN+m@2h@;*WZ-h3Qu@_cB$BH?#%QIVSniS(%S<|5qhJH>@9W#bvjO}Y*AB+COQ)%H#;8|jR_REv zf~Kl^L*;`NTds0=4l{*hN;M|HPG0QBlc&n z*sQ5ifA`Tg&>ynZ?0GZ5(Lt*iJ;XW-I?ll5a3%^>Cegg6;`;pzPnAZAw?q07*8iCDVi$f?fcKCo4+Ta=#tO-;y;-a zYpzCZ^CIL;-pzwDW*K6w&WmEdg`UFh`e*%fV?fKCA5I+Q>G5QD=A()yjoN|u$3XIK ze2L9=mPK#v+AjvASsu$(qrq=8cgB(rs9Q zP~$M-Dbn;qVwTA#utb5>YLG9-0O7h4Z78EFanueNU!1|RR?WDJEYl~yt>`h^GV`NN z6=$8!WC(^}o&MV18ch5^{0zOl=lHO$VoI2Lb&0L*U4=84ijtVs3n*?@sc(dG#}yb* zd=PF4PhBiJmj{eT4~J+gxBZPr<2b6_TCc$!=auL~f7NUMrB|2}?UZ3<@`E#^ll+QY zhkyx4IZV|Zt&O@oTe}6w!^FA#!2(yy=U}-dc*fq}TYlOS-$h$6@^*KM&C4w}tnKr^ z%Pw5-eqFLitN4d=$AX*C-o0O+mcG!i?h4ym$gXF^J;6>GE~tkf0-4ObDW_;iPmu^r zg#N$}t`|yDQlt-_FJ1t)XsLv8f?l5PB@+8o9eA?yjawU-TYy(@dpt@T1_l(pv=ih_ zi2n7yt;HQ2vt)*!?7LESNi?jOnnF0lQ-?GJ978(#k4z5)C((VDu$AC-O3D*%`malez4^E&eR}Y^Gm~DYU|67tKSFy&9MDwzS%hoStUcSTX_u z%yrI%`yM`@J4x@~FYx^d#EtPy*ttE*mcwneTQimSVG8l=_$Wk}t}*?t5WEq_vp zpa7>~u0tEl(whZb)2yu4?GKsp!|RIq$<{MB&|dpvf9q2Y_~w2e23-;@VBJEcgulr+6qY*Q8tkK?{z*$B2+N;J4&80K7JafZEOoqXb9 zXD7#W!Ayu9#vb91oS^tUzGcu0sY3ik#H6QjpAO4b-%ND$#M092Y>Kz45blY^`}X)3 z{#(5*-(y_y$xx6dti!;K8rUY4{(l^o(?He@6+|jOe$b|hPuO(@Eo4Tk_zNgG4HnVf zn6|lv9@yUH=u6Mfr+r_8G?XxX06={NvS8CUGvegRrMksTk)?hr-w|2+j{46|$LJ+z z5KesyIW;080?c!%GZ4>8=lb-M^%5AY*YQ# zk);`(#24{8UrcD5zUtRn9T)%t0VIY8NTgpL5MOV-*!09)mmfI6Y<7KlGIEKlfloUs z6>o(?czreI+1^c82Ky&S=FnkVXDf6Wi|5h3Lv+Xd$R?5xVp@pR0 zhK~xUr*^BN^VvUtn!SJMI+I7nhhN;*c2#-(s}fvPd|?d9VtP*jO0KwGa(*pq%#=z>J@8Fyu=xG^59x?0>vvqt4)MM@OOg%x zhg;Y^c|rw~Tbp7h!brCH8l+@ov-Qu(tMG8x;7RO9fQlQ^@QASkv+hq;`+%g&aE5Sa z;^ml^t$|@y@h$*`z7#~eO8Gu4Y_I;={faRh#3<2F<#Qh zqa+DF6f}9xI`}F1;gra2yiR|xwho^AfJvix`_h<&2!N+f*`Pa>B_+YWR1q==Xt6K= zHLYAOXsY{xm{BG&$%8zc#X0emRuiV|BrbgQpI27ZULYv@^P^#v0)zoPj4JBt9jlao zgREn>lwm8tmXfH%fwK;zzaZ#^4-D?Oppp;I+;4N!lj5behAmWf^(9ST8S&?_WQKIW8}=6TJ7EFjlvBw;RO^7#td)W^}mBep~j2zJbGN@P(_HM z9iUIew0Cwx&S6+vOv`5W9fb0{+fX)ST;vW7`dD$XsQmUMBUS0HBZ5?`4It#KzSX(v zS3pIBua?Kmm5K9Ug8{i$n0q|hx*9f%DpK;H-0C7Qg1`=xHw5>?7GPh-FbwBQzX2Jq zjGI<5QB4t|HnrvZDUvD`O)GeWUJI4ZkmcjeKd@AGF)p_iKo8PCr`Mw?o3w1 zizJ9usx_7373=mE-E8A|eB~@aV9WxOn7Og<~)8f^_B4=Q( z9y(HzyyirZiU$2$la8KV@Z(=wTM{$%&=JE=b#(&oe-4VWw09@2jxefy#5QT3N)ipX zVt>ddB%B$Mz=U%bUh5Y{{Vj0~sFoy)U$81yu@43v4iFS5gecD759JC5+nfaLp=f z>zyoRn{f3%B5`+e3*9HwI6BngWI6H(SoblsBL?p0lKCz}UT`tR;m%eVS#Qa9gH>Ek z1j{$T*aFcX;uPEC*2d=}x3Qf>M=ON$naQfyj;U7!gtv@B(iT>#VeFk^ORH=YcR||L zyBbC3k-=`kLanKxves($va-E(-_3x^GBH1o=YW2I0Ri<13ebL@Jso3#|54wTg7v`U zQM-M#g2jrSCu?6dxl$ZeA|#0^yFQWqZg_uGAM#9`mbqQ~n$xVy!eI6^0XHFNbZD(i zG!FUsRGGcmhwQ3rs&gEUBm1}giKo8>*Yg@VEPmGMJwr}Iake5mX+LQjA1dMN>wKOj z^)#`!T_Y}Y3)jBCww;7C3BcqDY}h2>#r*J zCl9sPbHM82%yBcKiTz^BPt5cnN)PW?Dn`pN8x4_)+GGOBnzYF=Cb9P}DgIWH|2}-| zIs3a?XnSv7h$^my#rYPgV|AihQQ)R$05j5dWUOm`#LDtv#}@-SFM&sxTGJ4{*%@ce zbCL^j@k>K6!vG-FGX(b44PLdHT`KKo| z)kjR$64>+L?ie)6mDlfiy`fl(X8)Glx@MMR=7A2XW?1iY2AvI&Piy?uI<&)l<3t1} z9_bXiVxe^EXw6*TZtLpn55EazzvqaP-<&buvCi+lN#tx%!dM|*`YZl#IER~sk613) z!h+2mr&f7{q2#45R7f%xMH|v=X~6uZkh>azC&@E zUsn@OA9Fra4aj+hM^Hs^>*s+g&UZ9zT_@R0X0hh2zs2oVn#OMAYVq)|r)8`qU6UE( z%A=?eh<7X^MhPdudd3Rpgd258zq1W5Yar`30Eg;f{I&vRyvR8(q$#E7E|6aEB6mfWKrNnBGG)?jG>B3_ExHE z$#}kWZFb90HQx`L$P76-4SVZXN@-h9QlWBO=P-Vr^Hm6qep)W>|YmV$Jr1B`Zat|PhC9>k_CPN-ql`mB>= zTkLyur)8>o?VGqUntjn*GB#mJyYy>4u-M_UzmL`DALG{!OLRA+$?1-lvgTLwdx!h) zQC=3H>i-dGJ6Olh=WRQv1N%pHjrzWU7R}D7X3}p zOu3o2;le=bZ@pamPuiw#b^50}btVpsUd-&L=jgdQU)TfdytamMEHId9Fj|xY7#gV` zo|f3+rM-CU@gPlDCpCJ-gauDDH?u%cr|qDo)y. +# +############################################################################## +"""Module that manages map view and vector/raster layer""" + +from . import base +from . import geo_raster_layer +from . import geo_vector_layer +from . import ir_view +from . import ir_model diff --git a/base_geoengine/models/base.py b/base_geoengine/models/base.py new file mode 100644 index 000000000..e02b021d2 --- /dev/null +++ b/base_geoengine/models/base.py @@ -0,0 +1,173 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from odoo import _, api, models +from odoo.exceptions import MissingError, UserError +from odoo.osv.expression import AND + +from .. import fields as geo_fields + +DEFAULT_EXTENT = "-123164.85222423, 5574694.9538936, 1578017.6490538, 6186191.1800898" + +_logger = logging.getLogger(__name__) + + +class Base(models.AbstractModel): + """Extend Base class for to allow definition of geo fields.""" + + _inherit = "base" + + # Array of ash that define layer and data to use + _georepr = [] + + @api.model + def fields_get(self, allfields=None, attributes=None): + """Add geo_type definition for geo fields""" + res = super().fields_get(allfields=allfields, attributes=attributes) + for f_name in res: + field = self._fields.get(f_name) + if field and field.type.startswith("geo_"): + geo_type = { + "type": field.type, + "dim": int(field.dim), + "srid": field.srid, + "geo_type": field.geo_type, + } + # TODO + if field.compute or field.related: + if not field.dim: + geo_type["dim"] = 2 + if not field.srid: + geo_type["srid"] = 3857 + res[f_name]["geo_type"] = geo_type + return res + + @api.model + def _get_geo_view(self): + IrView = self.env["ir.ui.view"] + geo_view = IrView.sudo().search( + [("model", "=", self._name), ("type", "=", "geoengine")], + limit=1, + ) + if not geo_view: + raise UserError( + _( + "No GeoEngine view defined for the model %s. \ + Please create a view or modify view mode" + ) + % self._name, + ) + return geo_view + + @api.model + def set_field_real_name(self, in_tuple): + field_obj = self.env["ir.model.fields"] + if not in_tuple: + return in_tuple + name = field_obj.browse(in_tuple[0]).name + out = (in_tuple[0], name, in_tuple[1]) + return out + + @api.model + def get_geoengine_layers(self, view_id=None, view_type="geoengine", **options): + view_obj = self.env["ir.ui.view"] + + if not view_id: + view = self._get_geo_view() + else: + view = view_obj.browse(view_id) + geoengine_layers = { + "backgrounds": [], + "actives": [], + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + + for layer in view.raster_layer_ids: + layer_dict = layer.read()[0] + geoengine_layers["backgrounds"].append(layer_dict) + for layer in view.vector_layer_ids: + layer_dict = layer.read()[0] + layer_dict["attribute_field_id"] = self.set_field_real_name( + layer_dict.get("attribute_field_id", False) + ) + layer_dict["geo_field_id"] = self.set_field_real_name( + layer_dict.get("geo_field_id", False) + ) + layer_dict["resModel"] = layer._name + layer_dict["model"] = layer.model_id.model + layer_dict["model_domain"] = layer.model_domain + geoengine_layers["actives"].append(layer_dict) + return geoengine_layers + + @api.model + def get_edit_info_for_geo_column(self, column): + raster_obj = self.env["geoengine.raster.layer"] + + field = self._fields.get(column) + if not field or not isinstance(field, geo_fields.GeoField): + raise ValueError( + _("%s column does not exists or is not a geo field") % column + ) + view = self._get_geo_view() + raster = raster_obj.search( + [("view_id", "=", view.id), ("use_to_edit", "=", True)], limit=1 + ) + if not raster: + raster = raster_obj.search([("view_id", "=", view.id)], limit=1) + if not raster: + raise MissingError(_("No raster layer for view %s") % (view.name,)) + return { + "edit_raster": raster.read()[0], + "srid": field.srid, + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + + @api.model + def geo_search( + self, domain=None, geo_domain=None, offset=0, limit=None, order=None + ): + """Perform a geo search it allows direct domain: + geo_search( + domain=[('name', 'ilike', 'toto']), + geo_domain=[('the_point', 'geo_intersect', + myshaply_obj or mywkt or mygeojson)]) + + We can also support indirect geo_domain ( + ‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + + The supported operators are : + * geo_greater + * geo_lesser + * geo_equal + * geo_touch + * geo_within + * geo_contains + * geo_intersect""" + # First we do a standard search in order to apply security rules + # and do a search on standard attributes + # Limit and offset are managed after, we may loose a lot of performance + # here + _logger.debug( + _("geo_search is deprecated: uses search method defined on base model") + ) + domain = domain or [] + geo_domain = geo_domain or [] + search_domain = domain or [] + if domain and geo_domain: + search_domain = AND([domain, geo_domain]) + elif geo_domain: + search_domain = geo_domain + + if not search_domain: + raise ValueError(_("You must at least provide one of domain or geo_domain")) + + return self.search(search_domain, limit=limit, offset=offset, order=order) diff --git a/base_geoengine/models/geo_raster_layer.py b/base_geoengine/models/geo_raster_layer.py new file mode 100644 index 000000000..c7d98662e --- /dev/null +++ b/base_geoengine/models/geo_raster_layer.py @@ -0,0 +1,90 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class GeoRasterLayerType(models.Model): + _name = "geoengine.raster.layer.type" + _description = "Raster Layer Type" + + name = fields.Char(translate=True, required=True) + code = fields.Char(required=True) + service = fields.Char(required=True) + + +class GeoRasterLayer(models.Model): + _name = "geoengine.raster.layer" + _description = "Raster Layer" + _order = "sequence ASC, name" + + raster_type = fields.Selection( + [ + ("osm", "OpenStreetMap"), + ("wmts", "WMTS"), + ("d_wms", "Distant WMS"), + ("odoo", "Odoo field"), + ], + string="Raster layer type", + default="osm", + required=True, + ) + name = fields.Char("Layer Name", translate=True, required=True) + url = fields.Char("Service URL") + + # technical field to display or not wmts options + is_wmts = fields.Boolean(compute="_compute_is_wmts") + # technical field to display or not wms options + is_wms = fields.Boolean(compute="_compute_is_wms") + # wmts options + matrix_set = fields.Char("Matrix set") + format_suffix = fields.Char("Format", help="eg. png") + request_encoding = fields.Char("Request encoding", help="eg. REST") + projection = fields.Char(help="eg. EPSG:21781") + units = fields.Char(help="eg. m") # Not used + resolutions = fields.Char() + max_extent = fields.Char("Max extent") + dimensions = fields.Char(help="List of dimensions separated by ','") + params = fields.Char(help="Dictiorary of values for dimensions as JSON") + + # wms options + params_wms = fields.Char(help="Need to provide at least a LAYERS param") + server_type = fields.Char( + help="The type of the remote WMS server: mapserver, \ + geoserver, carmentaserver, or qgis", + ) + + # technical field to display or not layer type -- Not used + has_type = fields.Boolean(compute="_compute_has_type") + type_id = fields.Many2one( + "geoengine.raster.layer.type", "Layer", domain="[('service', '=', raster_type)]" + ) + type = fields.Char(related="type_id.code") + sequence = fields.Integer("Layer priority", default=6) + overlay = fields.Boolean("Is overlay layer?") + field_id = fields.Many2one( + "ir.model.fields", + "Odoo layer field to use", + domain=[("ttype", "ilike", "geo_"), ("model", "=", "view_id.model")], + ) + view_id = fields.Many2one( + "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True + ) + use_to_edit = fields.Boolean("Use to edit") + opacity = fields.Float(default=1.0) + + @api.depends("raster_type", "is_wmts") + def _compute_has_type(self): + for rec in self: + rec.has_type = rec.raster_type == "is_wmts" + + @api.depends("raster_type") + def _compute_is_wmts(self): + for rec in self: + rec.is_wmts = rec.raster_type == "wmts" + + @api.depends("raster_type") + def _compute_is_wms(self): + for rec in self: + rec.is_wms = rec.raster_type == "d_wms" diff --git a/base_geoengine/models/geo_vector_layer.py b/base_geoengine/models/geo_vector_layer.py new file mode 100644 index 000000000..f7c90460c --- /dev/null +++ b/base_geoengine/models/geo_vector_layer.py @@ -0,0 +1,157 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + +SUPPORTED_ATT = [ + "float", + "integer", + "integer_big", + "related", + "function", + "date", + "datetime", + "char", + "text", + "selection", +] + +NUMBER_ATT = ["float", "integer", "integer_big"] + + +class GeoVectorLayer(models.Model): + _name = "geoengine.vector.layer" + _description = "Vector Layer" + _order = "sequence ASC, name" + + geo_repr = fields.Selection( + [ + ("basic", "Basic"), + # Actually we have to think if we should separate it for colored + ("proportion", "Proportional Symbol"), + ("colored", "Colored range/Chroma.js"), + ], + string="Representation mode", + required=True, + ) + + classification = fields.Selection( + [ + ("unique", "Unique value"), + ("interval", "Interval"), + ("quantile", "Quantile"), + ("custom", "Custom"), + ], + string="Classification mode", + required=False, + ) + name = fields.Char("Layer Name", translate=True, required=True) + begin_color = fields.Char("Begin color class", required=False, help="hex value") + end_color = fields.Char( + "End color class", required=False, help="hex value", default="#FF680A" + ) + nb_class = fields.Integer("Number of class", default=1) + geo_field_id = fields.Many2one( + "ir.model.fields", + "Geo field", + required=True, + ondelete="cascade", + domain=[("ttype", "ilike", "geo_")], + ) + attribute_field_id = fields.Many2one( + "ir.model.fields", "Attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] + ) + model_id = fields.Many2one( + "ir.model", + "Model to use", + store=True, + readonly=False, + compute="_compute_model_id", + ) + model_name = fields.Char(related="model_id.model", readonly=True) + + view_id = fields.Many2one( + "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True + ) + sequence = fields.Integer("Layer Priority", default=6) + readonly = fields.Boolean("Layer is read only") + display_polygon_labels = fields.Boolean("Display Labels on Polygon") + active_on_startup = fields.Boolean( + help="Layer will be shown on startup if checked." + ) + layer_opacity = fields.Float(default=1.0) + model_domain = fields.Char(default="[]") + model_view_id = fields.Many2one( + "ir.ui.view", + "Model view", + domain=[("type", "=", "geoengine")], + compute="_compute_model_view_id", + readonly=False, + ) + layer_transparent = fields.Boolean() + + @api.constrains("geo_field_id", "model_id") + def _check_geo_field_id(self): + for rec in self: + if rec.model_id: + if not rec.geo_field_id.model_id == rec.model_id: + raise ValidationError( + _( + "The geo_field_id must be a field in %s model", + rec.model_id.display_name, + ) + ) + + @api.constrains("geo_repr", "attribute_field_id") + def _check_geo_repr(self): + for rec in self: + if ( + rec.attribute_field_id + and rec.attribute_field_id.ttype not in NUMBER_ATT + ): + if ( + rec.geo_repr == "colored" + and rec.classification != "unique" + or rec.geo_repr == "proportion" + ): + raise ValidationError( + _( + "You need to select a numeric field", + ) + ) + + @api.constrains("attribute_field_id", "geo_field_id") + def _check_if_attribute_in_geo_field(self): + for rec in self: + if rec.attribute_field_id and rec.geo_field_id: + if rec.attribute_field_id.model != rec.geo_field_id.model: + raise ValidationError( + _( + "You need to provide an attribute that exists in %s model", + rec.geo_field_id.model_id.display_name, + ) + ) + + @api.depends("model_id") + def _compute_model_view_id(self): + for rec in self: + if rec.model_id: + for view in rec.model_id.view_ids: + if view.type == "geoengine": + rec.model_view_id = view + else: + rec.model_view_id = "" + + @api.depends("geo_field_id", "view_id") + def _compute_model_id(self): + for rec in self: + if rec.view_id and rec.geo_field_id: + if rec.view_id.model != rec.geo_field_id.model: + rec.model_id = rec.geo_field_id.model_id + else: + rec.model_id = "" + else: + rec.model_id = "" diff --git a/base_geoengine/models/ir_model.py b/base_geoengine/models/ir_model.py new file mode 100644 index 000000000..ba3f44218 --- /dev/null +++ b/base_geoengine/models/ir_model.py @@ -0,0 +1,51 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2023 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + +from odoo.addons import base + +if "geoengine" not in base.models.ir_actions.VIEW_TYPES: + base.models.ir_actions.VIEW_TYPES.append(("geoengine", "Geoengine")) + +GEO_TYPES = [ + ("geo_polygon", "geo_polygon"), + ("geo_multi_polygon", "geo_multi_polygon"), + ("geo_point", "geo_point"), + ("geo_multi_point", "geo_multi_point"), + ("geo_line", "geo_line"), + ("geo_multi_line", "geo_multi_line"), +] + +GEO_TYPES_ONDELETE = { + "geo_polygon": "cascade", + "geo_multi_polygon": "cascade", + "geo_point": "cascade", + "geo_multi_point": "cascade", + "geo_line": "cascade", + "geo_multi_line": "cascade", +} + +POSTGIS_GEO_TYPES = [ + ("Point", "Point"), + ("MultiPoint", "MultiPoint"), + ("LineString", "LineString"), + ("MultiLineString", "MultiLineString"), + ("Polygon", "Polygon"), + ("MultiPolygon", "MultiPolygon"), +] + + +class IrModelField(models.Model): + _inherit = "ir.model.fields" + + srid = fields.Integer("srid", required=False) + geo_type = fields.Selection(POSTGIS_GEO_TYPES, string="PostGIs type") + dim = fields.Selection( + [("2", "2"), ("3", "3"), ("4", "4")], string="PostGIs Dimension", default="2" + ) + gist_index = fields.Boolean("Create gist index") + ttype = fields.Selection( + selection_add=GEO_TYPES, + ondelete=GEO_TYPES_ONDELETE, + ) diff --git a/base_geoengine/models/ir_view.py b/base_geoengine/models/ir_view.py new file mode 100644 index 000000000..aaec60ac7 --- /dev/null +++ b/base_geoengine/models/ir_view.py @@ -0,0 +1,39 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016-2023 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class IrUIView(models.Model): + _inherit = "ir.ui.view" + + type = fields.Selection( + selection_add=[("geoengine", "GeoEngine")], + ondelete={"geoengine": "cascade"}, + ) + + raster_layer_ids = fields.One2many( + "geoengine.raster.layer", "view_id", "Raster layers", required=False + ) + + vector_layer_ids = fields.One2many( + "geoengine.vector.layer", "view_id", "Vector layers", required=True + ) + + projection = fields.Char(default="EPSG:3857", required=True) + default_extent = fields.Char( + "Default map extent", + default="-123164.85222423, 5574694.9538936, 1578017.6490538, 6186191.1800898", + ) + default_zoom = fields.Integer("Default map zoom") + restricted_extent = fields.Char("Restricted map extent") + + def _is_qweb_based_view(self, view_type): + if view_type == "geoengine": + return True + return super()._is_qweb_based_view(view_type) + + def _get_view_info(self): + res = super()._get_view_info() + res.update({"geoengine": {"icon": "fa fa-globe"}}) + return res diff --git a/base_geoengine/pyproject.toml b/base_geoengine/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/base_geoengine/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/base_geoengine/readme/CONTRIBUTORS.md b/base_geoengine/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..7313dd40f --- /dev/null +++ b/base_geoengine/readme/CONTRIBUTORS.md @@ -0,0 +1,25 @@ +- Nicolas Bessi \<\> +- Frederic Junod \<\> +- Yannick Payot \<\> +- Sandy Carter \<\> +- Laurent Mignon \<\> +- Jonathan Nemry \<\> +- David Lasley \<\> +- Daniel Reis \<\> +- Matthieu Dietrich \<\> +- Alan Ramos \<\> +- Damien Crier \<\> +- Cyril Gaudin \<\> +- Pierre Verkest \<\> +- Benjamin Willig \<\> +- Devendra Kavthekar \<\> +- Emanuel Cino \<\> +- Thomas Nowicki \<\> +- Alexandre Saunier \<\> +- Sandip Mangukiya \<\> +- Samuel Kouff \<\> +- [APSL-Nagarro](https://www.apsl.tech): + - Antoni Marroig \<\> + - Miquel Alzanillas \<\> +- Red Butay \<\> +- Sergio Sancho \<\> diff --git a/base_geoengine/readme/DESCRIPTION.md b/base_geoengine/readme/DESCRIPTION.md new file mode 100644 index 000000000..3af0efdc1 --- /dev/null +++ b/base_geoengine/readme/DESCRIPTION.md @@ -0,0 +1,16 @@ +GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. +It will allow you to : + +- Visualize and query your business information on map +- Perform GeoBI and spatial query +- Configure your spatial layers and spatial datasources +- Extend Odoo models with spatial columns + +GeoEngine relies on [OpenLayers](http://openlayers.org) and +[PostgGIS](http://postgis.refractions.net/) technologies. + +Postgis is used to store spatial information in databases. OpenLayer is +used to represent spatial data in other words to show maps and the +different spatial layers. The GeoEngine module acts as a data provider +and as an OpenLayers configurator. It also provides a complete extension +to Odoo ORM. diff --git a/base_geoengine/readme/HISTORY.md b/base_geoengine/readme/HISTORY.md new file mode 100644 index 000000000..77872b7ff --- /dev/null +++ b/base_geoengine/readme/HISTORY.md @@ -0,0 +1,123 @@ +## 16.0.1.0.0 (2023-03-20) + +- LayerSwitcher has been removed as it was not really practical. A + LayerPanel is now active. +- The geo_search method is now deprecated and replaced by the standard + odoo search method. +- The widget "geo_edit_map" attribute is no longer necessary as the + field is automatically detected by his type. We can also provide an + option attribute that allows us to pass an opacity and a color as + parameters. + +``` xml +
+ + + + + +
+``` + +- The method geo_search is now deprecated. We now need to use the + standard odoo search method. + +``` python +obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) +``` + +- We can now pass to the geoengine view a template to display the + information we want to see when clicking on a feature. + +``` xml + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+``` + +- We can now pass a model to use to a layer to display other information + on the map. + +``` xml + + + [('state', '=', 'hs')] + + HS retail machines + + basic + + #FF0000 + + 0.8 + +``` + +- There is some new features in the LayerPanel. + +1. If you are logged in as an admin, you have the possibility to edit + the layer by clicking on the edit button. This will open a dialog + box. Changes will appear in real time on the view. +2. If you are logged in as an admin, you can also change the domain of + the layer. If you are logged in as a user, changes will not be + persisted in the database. Changes will appear in real time on the + view. +3. If you are logged in as an admin, you can also change the sequence + of the layers by sliding them over each other. If you are logged in + as a user, changes will not be persisted in the database. + +- Widget domain is now implemented for geo field This means that the + geo-operators are also implemented and that there is the possibility + to add a sub-domain. If we want to add a domain that includes all the + records that are displayed in the geoengine view (active_ids). We can + use the two new operators : "in active_ids" and "not in active_ids". + These will automatically replace the marker with ids. Note that the + widget will indicate that the domain is invalid because of the marker. +- Creation of the RecordsPanel. This panel allows you to retrieve all + active records. You can click on record to get the movement to the + selected record. Two magnifying glass are also available. You can + click on the left one to zoom on the record. You can click on the + right one to get the original zoom. +- A search bar is also available. It allows you to perform a search into + the RecordsPanel. +- A button to open/close the panels is also available. +- The module has been translated in French. +- Now you can now make the geoengine view editable. Simply add editable + attribute in the geoengine view. + +``` xml + + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+ +Thanks to that, you can create new records by drawing them directly in the geoengine view. You can also edit record in the same view. +``` diff --git a/base_geoengine/readme/INSTALL.md b/base_geoengine/readme/INSTALL.md new file mode 100644 index 000000000..c72a805b7 --- /dev/null +++ b/base_geoengine/readme/INSTALL.md @@ -0,0 +1,19 @@ +To install this module, you need to have [PostGIS](http://postgis.net/) +installed. + +On Ubuntu: + + .. code-block:: bash + +> sudo apt-get install postgis + +The module also requires two additional python libs: + +- [Shapely](http://pypi.python.org/pypi/Shapely) +- [geojson](http://pypi.python.org/pypi/geojson) + +When you will install the module this two additional libs will be +installed. + +For a complete documentation please refer to the [public +documenation](http://oca.github.io/geospatial/index.html) diff --git a/base_geoengine/readme/ROADMAP.md b/base_geoengine/readme/ROADMAP.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/base_geoengine/readme/ROADMAP.md @@ -0,0 +1 @@ + diff --git a/base_geoengine/readme/USAGE.md b/base_geoengine/readme/USAGE.md new file mode 100644 index 000000000..6ddda6d33 --- /dev/null +++ b/base_geoengine/readme/USAGE.md @@ -0,0 +1,80 @@ +## Geoengine Demo + +1. As a user/admin, when I am in the Geoengine Demo module and I go to + the ZIP menu. When I click on an item in the list view, I get to the + form view showing me the different information about the ZIP. We can + see its ZIP, city, priority, total sales and his spatial + representation. +2. As a user, I can't modify the information in the form view. +3. As an admin, I can modify the information in the form view. I can + click on the bin button to clear the map and I can draw a new shape. +4. As a user, when I go the "Retail machines" tab and there are no + items to display, it does not show me anything. +5. As an admin, when I go the "Retail machines" tab and there are no + items to display, the list view of the retail machines suggests to + me to add a new line. +6. As a user/admin, if there are items to be displayed in the "Retail + machines" tab then I can click on an item and the retail machines + form view will be displayed. We can see its spatial representation + by going to "The point" tab and its attributes in "Attributes" tab. +7. As a user/admin, when I go to the geoengine zip view by clicking on + the map button at the top right of the screen. The geoengine view + appears with the first 80 results displayed on the map. The vector + layers selected are those defined as "active on startup" by the + admin. The selected raster layer is the first one that is not an + overlay layer. +8. As a user/admin, when I hover over an area on the map, the area + changes its style. +9. As a user/admin, when I click on an area, a popup appears an I can + see the different information about the area. If I click on the + cross, the popup will disappear. If I click somewhere else on the + map, the popup will also disappear. If I click on the about button, + then the form view will be displayed. +10. As a user/admin, when I use the paging system, then the results + displayed on the map are different (corresponding to the request). +11. As a user/admin, if we use the search bar, we can search results by + his zip or his city. +12. As an admin, if I change the sequence of layers with the handle + button then the change are persisted in database. +13. As a user, if I change the sequence of layers with the handle button + then the change are not persisted in database. There are just the + changes in the display. +14. As an admin, if I change the domain of a layer with the filter + button then the change are persisted in database. +15. As a user, if I change the domain of a layer with the filter button + then the change are not persisted in database. There are just the + changes in the display. +16. As an admin, I have the possibility to edit the layer with its + corresponding button. +17. As a user/admin, I can open/close LayerPanel with its button. +18. As a user/admin, I can open/close RecordsPanel with its button. +19. As a user/admin, when I click on a record in RecordsPanel, a move is + made on the map to the selected record. +20. As a user/admin, when I click on a record in RecordsPanel, I can + also click on the left magnifying glass to zoom on the record. +21. As a user/admin, when I click on a record in RecordsPanel, I can + also click on the right magnifying glass to get the original zoom. +22. As a user/admin, I can use the search bar to search in the + RecordsPanel. +23. As an admin,If the geoengine view is in edit mode, I can create new + records by drawing them in the view. +24. As an admin, If the geoengine view is in edit mode, I can modify its + spatial representation. + +## Geoengine Backend + +1. As an admin, if I go into the configuration of the raster layers and + it has elements, I can click on one and see its information. +2. As an admin, if I want to create a new raster layer, I can click on + "NEW" and fill out the form. The required fields for OpenStreetMap + type are "Layer Name" and "Related View". If we want to have a WMTS + (Web Map Tile Service) raster type. The required fields in addition + to the precedents are "Service URL", "Matrix set","Format", + "Projection" and "Resolutions". If we take WMS (Web Map Service) + raster type, then the required fields are "Layer Name", "Related + View", "Service URL", "Params", "Server Type". +3. As an admin,if I go into the configuration of the vector layers and + it has elements, I can click on one and see its information. +4. As an admin, if I want to create a new vector layer, I can click on + "NEW" and fill out the form. The required fields are "Layer Name", + "Related View", "Geo field" and "Representation mode". diff --git a/base_geoengine/security/data.xml b/base_geoengine/security/data.xml new file mode 100644 index 000000000..066eead19 --- /dev/null +++ b/base_geoengine/security/data.xml @@ -0,0 +1,20 @@ + + + + Geoengine User + + + + Geoengine Admin + + + + + + + + + + + + diff --git a/base_geoengine/security/ir.model.access.csv b/base_geoengine/security/ir.model.access.csv new file mode 100644 index 000000000..44559f50e --- /dev/null +++ b/base_geoengine/security/ir.model.access.csv @@ -0,0 +1,9 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_geo_user_vector_user,geoengine.user.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_vector_user,geoengine.admin.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_raster_user,geoengine.user.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_raster_user,geoengine.admin.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_raster_type_user,geoengine.user.raster.layer.type,base_geoengine.model_geoengine_raster_layer_type,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_raster_type_user,geoengine.admin.raster.layer.type,base_geoengine.model_geoengine_raster_layer_type,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_allmodels,ir.model,base.model_ir_model,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_user_allviews,ir.ui.view,base.model_ir_ui_view,base_geoengine.group_geoengine_user,1,0,0,0 diff --git a/base_geoengine/static/description/icon.png b/base_geoengine/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b698310eefcab016c8372b688f495daacd3fe746 GIT binary patch literal 130328 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%0Aj5`*?xx_dV0 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 r#?5d*H!pjPiQ)gh{vW@AZ28Ba(=vW3ul + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Geospatial support for Odoo

+ +

Beta License: AGPL-3 OCA/geospatial Translate me on Weblate Try me on Runboat

+

GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. +It will allow you to :

+
    +
  • Visualize and query your business information on map
  • +
  • Perform GeoBI and spatial query
  • +
  • Configure your spatial layers and spatial datasources
  • +
  • Extend Odoo models with spatial columns
  • +
+

GeoEngine relies on OpenLayers and +PostgGIS technologies.

+

Postgis is used to store spatial information in databases. OpenLayer is +used to represent spatial data in other words to show maps and the +different spatial layers. The GeoEngine module acts as a data provider +and as an OpenLayers configurator. It also provides a complete extension +to Odoo ORM.

+

Table of contents

+ +
+

Installation

+

To install this module, you need to have +PostGIS installed.

+

On Ubuntu:

+
+.. code-block:: bash
+
+ +
+sudo apt-get install postgis
+

The module also requires two additional python libs:

+ +

When you will install the module this two additional libs will be +installed.

+

For a complete documentation please refer to the public +documenation

+
+
+

Usage

+
+

Geoengine Demo

+
    +
  1. As a user/admin, when I am in the Geoengine Demo module and I go to +the ZIP menu. When I click on an item in the list view, I get to the +form view showing me the different information about the ZIP. We can +see its ZIP, city, priority, total sales and his spatial +representation.
  2. +
  3. As a user, I can’t modify the information in the form view.
  4. +
  5. As an admin, I can modify the information in the form view. I can +click on the bin button to clear the map and I can draw a new shape.
  6. +
  7. As a user, when I go the “Retail machines” tab and there are no +items to display, it does not show me anything.
  8. +
  9. As an admin, when I go the “Retail machines” tab and there are no +items to display, the list view of the retail machines suggests to +me to add a new line.
  10. +
  11. As a user/admin, if there are items to be displayed in the “Retail +machines” tab then I can click on an item and the retail machines +form view will be displayed. We can see its spatial representation +by going to “The point” tab and its attributes in “Attributes” tab.
  12. +
  13. As a user/admin, when I go to the geoengine zip view by clicking on +the map button at the top right of the screen. The geoengine view +appears with the first 80 results displayed on the map. The vector +layers selected are those defined as “active on startup” by the +admin. The selected raster layer is the first one that is not an +overlay layer.
  14. +
  15. As a user/admin, when I hover over an area on the map, the area +changes its style.
  16. +
  17. As a user/admin, when I click on an area, a popup appears an I can +see the different information about the area. If I click on the +cross, the popup will disappear. If I click somewhere else on the +map, the popup will also disappear. If I click on the about button, +then the form view will be displayed.
  18. +
  19. As a user/admin, when I use the paging system, then the results +displayed on the map are different (corresponding to the request).
  20. +
  21. As a user/admin, if we use the search bar, we can search results by +his zip or his city.
  22. +
  23. As an admin, if I change the sequence of layers with the handle +button then the change are persisted in database.
  24. +
  25. As a user, if I change the sequence of layers with the handle button +then the change are not persisted in database. There are just the +changes in the display.
  26. +
  27. As an admin, if I change the domain of a layer with the filter +button then the change are persisted in database.
  28. +
  29. As a user, if I change the domain of a layer with the filter button +then the change are not persisted in database. There are just the +changes in the display.
  30. +
  31. As an admin, I have the possibility to edit the layer with its +corresponding button.
  32. +
  33. As a user/admin, I can open/close LayerPanel with its button.
  34. +
  35. As a user/admin, I can open/close RecordsPanel with its button.
  36. +
  37. As a user/admin, when I click on a record in RecordsPanel, a move is +made on the map to the selected record.
  38. +
  39. As a user/admin, when I click on a record in RecordsPanel, I can +also click on the left magnifying glass to zoom on the record.
  40. +
  41. As a user/admin, when I click on a record in RecordsPanel, I can +also click on the right magnifying glass to get the original zoom.
  42. +
  43. As a user/admin, I can use the search bar to search in the +RecordsPanel.
  44. +
  45. As an admin,If the geoengine view is in edit mode, I can create new +records by drawing them in the view.
  46. +
  47. As an admin, If the geoengine view is in edit mode, I can modify its +spatial representation.
  48. +
+
+
+

Geoengine Backend

+
    +
  1. As an admin, if I go into the configuration of the raster layers and +it has elements, I can click on one and see its information.
  2. +
  3. As an admin, if I want to create a new raster layer, I can click on +“NEW” and fill out the form. The required fields for OpenStreetMap +type are “Layer Name” and “Related View”. If we want to have a WMTS +(Web Map Tile Service) raster type. The required fields in addition +to the precedents are “Service URL”, “Matrix set”,”Format”, +“Projection” and “Resolutions”. If we take WMS (Web Map Service) +raster type, then the required fields are “Layer Name”, “Related +View”, “Service URL”, “Params”, “Server Type”.
  4. +
  5. As an admin,if I go into the configuration of the vector layers and +it has elements, I can click on one and see its information.
  6. +
  7. As an admin, if I want to create a new vector layer, I can click on +“NEW” and fill out the form. The required fields are “Layer Name”, +“Related View”, “Geo field” and “Representation mode”.
  8. +
+
+
+ +
+

Changelog

+
+

16.0.1.0.0 (2023-03-20)

+
    +
  • LayerSwitcher has been removed as it was not really practical. A +LayerPanel is now active.
  • +
  • The geo_search method is now deprecated and replaced by the standard +odoo search method.
  • +
  • The widget “geo_edit_map” attribute is no longer necessary as the +field is automatically detected by his type. We can also provide an +option attribute that allows us to pass an opacity and a color as +parameters.
  • +
+
+<form>
+    <notebook colspan="4">
+        <page string="Geometry">
+            <field name="the_geom" options="{'opacity': 0.8, 'color': '#0000FF' }" />
+        </page>
+    </notebook>
+</form>
+
+
    +
  • The method geo_search is now deprecated. We now need to use the +standard odoo search method.
  • +
+
+obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})])
+
+
    +
  • We can now pass to the geoengine view a template to display the +information we want to see when clicking on a feature.
  • +
+
+<geoengine>
+    <field name="name" />
+    <field name="city" />
+    <field name="total_sales" />
+    <field name="the_geom" />
+    <templates>
+        <t t-name="info_box">
+            <field name="city" widget="badge" />
+            <ul>
+                <li>ZIP : <field name="name" />
+                </li>
+                <li>Total Sales: <field name="total_sales" />
+                </li>
+            </ul>
+        </t>
+    </templates>
+</geoengine>
+
+
    +
  • We can now pass a model to use to a layer to display other information +on the map.
  • +
+
+<record id="geoengine_vector_layer_hs_retail_machines" model="geoengine.vector.layer">
+    <field name="model_id" ref="base_geoengine_demo.model_geoengine_demo_automatic_retailing_machine"/>
+    <field name="model_domain">[('state', '=', 'hs')]</field>
+    <field name="geo_field_id" ref="base_geoengine_demo.field_geoengine_demo_automatic_retailing_machine__the_point"/>
+    <field name="name">HS retail machines</field>
+    <field name="view_id" ref="ir_ui_view_resbetterzipgeoview0" />
+    <field name="geo_repr">basic</field>
+    <field name="attribute_field_id" ref="base_geoengine_demo.field_geoengine_demo_automatic_retailing_machine__name"/>
+    <field name="begin_color">#FF0000</field>
+    <field name="display_polygon_labels" eval="0" />
+    <field name="layer_opacity">0.8</field>
+</record>
+
+
    +
  • There is some new features in the LayerPanel.
  • +
+
    +
  1. If you are logged in as an admin, you have the possibility to edit +the layer by clicking on the edit button. This will open a dialog +box. Changes will appear in real time on the view.
  2. +
  3. If you are logged in as an admin, you can also change the domain of +the layer. If you are logged in as a user, changes will not be +persisted in the database. Changes will appear in real time on the +view.
  4. +
  5. If you are logged in as an admin, you can also change the sequence of +the layers by sliding them over each other. If you are logged in as a +user, changes will not be persisted in the database.
  6. +
+
    +
  • Widget domain is now implemented for geo field This means that the +geo-operators are also implemented and that there is the possibility +to add a sub-domain. If we want to add a domain that includes all the +records that are displayed in the geoengine view (active_ids). We can +use the two new operators : “in active_ids” and “not in active_ids”. +These will automatically replace the marker with ids. Note that the +widget will indicate that the domain is invalid because of the marker.
  • +
  • Creation of the RecordsPanel. This panel allows you to retrieve all +active records. You can click on record to get the movement to the +selected record. Two magnifying glass are also available. You can +click on the left one to zoom on the record. You can click on the +right one to get the original zoom.
  • +
  • A search bar is also available. It allows you to perform a search into +the RecordsPanel.
  • +
  • A button to open/close the panels is also available.
  • +
  • The module has been translated in French.
  • +
  • Now you can now make the geoengine view editable. Simply add editable +attribute in the geoengine view.
  • +
+
+<geoengine editable="1">
+    <field name="name" />
+    <field name="city" />
+    <field name="total_sales" />
+    <field name="the_geom" />
+    <field name="display_name" />
+    <templates>
+      <t t-name="info_box">
+        <field name="city" widget="badge" />
+        <ul>
+          <li>ZIP : <field name="name" />
+          </li>
+          <li>Total Sales: <field name="total_sales" />
+          </li>
+        </ul>
+      </t>
+    </templates>
+  </geoengine>
+
+Thanks to that, you can create new records by drawing them directly in the geoengine view. You can also edit record in the same view.
+
+
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/geospatial project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/base_geoengine/static/img/map-marker.png b/base_geoengine/static/img/map-marker.png new file mode 100644 index 0000000000000000000000000000000000000000..0968935837fa762f01d85bafabe1dfbc87a0577a GIT binary patch literal 356 zcmV-q0h|7bP)EJ|4{M*jlpEtwfi7A4BSKnla_RTy4x z9jANW>)!hgJoVJ+KIi#<&pr2?E`K0Kv5PCz@PH~R=qL+cLLHwed4hqW@WmG3FwfAN z7e1`99UMwcU;v#51mHaX1qeV<5fjUzJBf+@(4Tz)K zq9;=juDG5u=dDFgrr;(RPo&I=pI@iUON>oF_jfj`_u(?AKcXj(Ur+rvI1C0fuFYn4&As* z5LDVFfb|G|i>`JG`tceFR@(`0#vGn;q`)8S|Hc255)&&(r._clipped=!0),r[n]=e(r[n],0,255)):3===n&&(r[n]=e(r[n],0,1));return r}for(var a={},f=0,o=["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"];f=3?Array.prototype.slice.call(r):"object"==c(r[0])&&n?n.split("").filter((function(n){return void 0!==r[0][n]})).map((function(n){return r[0][n]})):r[0].slice(0)}function l(r){if(r.length<2)return null;var n=r.length-1;return"string"==c(r[n])?r[n].toLowerCase():null}var h=Math.PI,s=Math.min,d=Math.max,b=function(r){return Math.round(100*r)/100},g=function(r){return Math.round(100*r)/100},v=2*h,p=h/3,m=h/180,y=180/h,w={format:{},autodetect:[]},k=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=this;if("object"===c(r[0])&&r[0].constructor&&r[0].constructor===this.constructor)return r[0];var a=l(r),f=!1;if(!a){f=!0,w.sorted||(w.autodetect=w.autodetect.sort((function(r,n){return n.p-r.p})),w.sorted=!0);for(var o=0,u=w.autodetect;o4?r[4]:1;return 1===f?[0,0,0,o]:[e>=1?0:255*(1-e)*(1-f),t>=1?0:255*(1-t)*(1-f),a>=1?0:255*(1-a)*(1-f),o]},w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"cmyk"))&&4===r.length)return"cmyk"}});var _=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t,a=(r=i(r,"rgba"))[0],f=r[1],o=r[2],u=s(a/=255,f/=255,o/=255),c=d(a,f,o),l=(c+u)/2;return c===u?(e=0,t=Number.NaN):e=l<.5?(c-u)/(c+u):(c-u)/(2-c-u),a==c?t=(f-o)/(c-u):f==c?t=2+(o-a)/(c-u):o==c&&(t=4+(a-f)/(c-u)),(t*=60)<0&&(t+=360),r.length>3&&void 0!==r[3]?[t,e,l,r[3]]:[t,e,l]},A={Kn:18,labWhitePoint:"d65",Xn:.95047,Yn:1,Zn:1.08883,t0:.137931034,t1:.206896552,t2:.12841855,t3:.008856452,kE:216/24389,kKE:8,kK:24389/27,RefWhiteRGB:{X:.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:.4124564390896922,m01:.21267285140562253,m02:.0193338955823293,m10:.357576077643909,m11:.715152155287818,m12:.11919202588130297,m20:.18043748326639894,m21:.07217499330655958,m22:.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-.9692660305051868,m02:.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-.2040259135167538,m20:-.498531409556016,m21:.041556017530349834,m22:1.0572251882231791},As:.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:.8951,m01:-.7502,m02:.0389,m10:.2664,m11:1.7135,m12:-.0685,m20:-.1614,m21:.0367,m22:1.0296},MtxAdaptMaI:{m00:.9869929054667123,m01:.43230526972339456,m02:-.008528664575177328,m10:-.14705425642099013,m11:.5183602715367776,m12:.04004282165408487,m20:.15996265166373125,m21:.0492912282128556,m22:.9684866957875502}},j=new Map([["a",[1.0985,.35585]],["b",[1.0985,.35585]],["c",[.98074,1.18232]],["d50",[.96422,.82521]],["d55",[.95682,.92149]],["d65",[.95047,1.08883]],["e",[1,1,1]],["f2",[.99186,.67393]],["f7",[.95041,1.08747]],["f11",[1.00962,.6435]],["icc",[.96422,.82521]]]);function E(r){var n=j.get(String(r).toLowerCase());if(!n)throw new Error("unknown Lab illuminant "+r);A.labWhitePoint=r,A.Xn=n[0],A.Zn=n[1]}function R(){return A.labWhitePoint}var O=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgb"),t=e[0],a=e[1],f=e[2],o=e.slice(3),u=F(t,a,f),c=function(r,n,e){var t=A.Xn,a=A.Yn,f=A.Zn,o=A.kE,u=A.kK,c=r/t,i=n/a,l=e/f,h=c>o?Math.pow(c,1/3):(u*c+16)/116,s=i>o?Math.pow(i,1/3):(u*i+16)/116,d=l>o?Math.pow(l,1/3):(u*l+16)/116;return[116*s-16,500*(h-s),200*(s-d)]}(u[0],u[1],u[2]);return[c[0],c[1],c[2]].concat(o.length>0&&o[0]<1?[o[0]]:[])};function P(r){var n=Math.sign(r);return((r=Math.abs(r))<=.04045?r/12.92:Math.pow((r+.055)/1.055,2.4))*n}var F=function(r,n,e){r=P(r/255),n=P(n/255),e=P(e/255);var t=A.MtxRGB2XYZ,a=A.MtxAdaptMa,f=A.MtxAdaptMaI,o=A.Xn,u=A.Yn,c=A.Zn,i=A.As,l=A.Bs,h=A.Cs,s=r*t.m00+n*t.m10+e*t.m20,d=r*t.m01+n*t.m11+e*t.m21,b=r*t.m02+n*t.m12+e*t.m22,g=o*a.m00+u*a.m10+c*a.m20,v=o*a.m01+u*a.m11+c*a.m21,p=o*a.m02+u*a.m12+c*a.m22,m=s*a.m00+d*a.m10+b*a.m20,y=s*a.m01+d*a.m11+b*a.m21,w=s*a.m02+d*a.m12+b*a.m22;return y*=v/l,w*=p/h,[s=(m*=g/i)*f.m00+y*f.m10+w*f.m20,d=m*f.m01+y*f.m11+w*f.m21,b=m*f.m02+y*f.m12+w*f.m22]},L=Math.sqrt,B=Math.atan2,G=Math.round,Y=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lab"),t=e[0],a=e[1],f=e[2],o=L(a*a+f*f),u=(B(f,a)*y+360)%360;return 0===G(1e4*o)&&(u=Number.NaN),[t,o,u]},q=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgb"),t=e[0],a=e[1],f=e[2],o=e.slice(3),u=O(t,a,f),c=u[0],l=u[1],h=u[2],s=Y(c,l,h);return[s[0],s[1],s[2]].concat(o.length>0&&o[0]<1?[o[0]]:[])};function C(r,n){var e=r.length;Array.isArray(r[0])||(r=[r]),Array.isArray(n[0])||(n=n.map((function(r){return[r]})));var t=n[0].length,a=n[0].map((function(r,e){return n.map((function(r){return r[e]}))})),f=r.map((function(r){return a.map((function(n){return Array.isArray(r)?r.reduce((function(r,e,t){return r+e*(n[t]||0)}),0):n.reduce((function(n,e){return n+e*r}),0)}))}));return 1===e&&(f=f[0]),1===t?f.map((function(r){return r[0]})):f}var X=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t,a=i(r,"rgb"),f=a[0],o=a[1],u=a[2],c=a.slice(3),l=F(f,o,u);return(e=[[.210454268309314,.7936177747023054,-.0040720430116193],[1.9779985324311684,-2.42859224204858,.450593709617411],[.0259040424655478,.7827717124575296,-.8086757549230774]],t=C([[.819022437996703,.3619062600528904,-.1288737815209879],[.0329836539323885,.9292868615863434,.0361446663506424],[.0481771893596242,.2642395317527308,.6335478284694309]],l),C(e,t.map((function(r){return Math.cbrt(r)})))).concat(c.length>0&&c[0]<1?[c[0]]:[])};var Z=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgb"),t=e[0],a=e[1],f=e[2],o=e.slice(3),u=X(t,a,f),c=u[0],l=u[1],h=u[2],s=Y(c,l,h);return[s[0],s[1],s[2]].concat(o.length>0&&o[0]<1?[o[0]]:[])},$=Math.round,S=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgba"),t=l(r)||"rgb";if("hsl"===t.substr(0,3))return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"hsla"),t=l(r)||"lsa";return e[0]=b(e[0]||0)+"deg",e[1]=b(100*e[1])+"%",e[2]=b(100*e[2])+"%","hsla"===t||e.length>3&&e[3]<1?(e[3]="/ "+(e.length>3?e[3]:1),t="hsla"):e.length=3,t.substr(0,3)+"("+e.join(" ")+")"}(_(e),t);if("lab"===t.substr(0,3)){var a=R();E("d50");var f=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lab"),t=l(r)||"lab";return e[0]=b(e[0])+"%",e[1]=b(e[1]),e[2]=b(e[2]),"laba"===t||e.length>3&&e[3]<1?e[3]="/ "+(e.length>3?e[3]:1):e.length=3,"lab("+e.join(" ")+")"}(O(e),t);return E(a),f}if("lch"===t.substr(0,3)){var o=R();E("d50");var u=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lch"),t=l(r)||"lab";return e[0]=b(e[0])+"%",e[1]=b(e[1]),e[2]=isNaN(e[2])?"none":b(e[2])+"deg","lcha"===t||e.length>3&&e[3]<1?e[3]="/ "+(e.length>3?e[3]:1):e.length=3,"lch("+e.join(" ")+")"}(q(e),t);return E(o),u}return"oklab"===t.substr(0,5)?function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lab");return e[0]=b(100*e[0])+"%",e[1]=g(e[1]),e[2]=g(e[2]),e.length>3&&e[3]<1?e[3]="/ "+(e.length>3?e[3]:1):e.length=3,"oklab("+e.join(" ")+")"}(X(e)):"oklch"===t.substr(0,5)?function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lch");return e[0]=b(100*e[0])+"%",e[1]=g(e[1]),e[2]=isNaN(e[2])?"none":b(e[2])+"deg",e.length>3&&e[3]<1?e[3]="/ "+(e.length>3?e[3]:1):e.length=3,"oklch("+e.join(" ")+")"}(Z(e)):(e[0]=$(e[0]),e[1]=$(e[1]),e[2]=$(e[2]),("rgba"===t||e.length>3&&e[3]<1)&&(e[3]="/ "+(e.length>3?e[3]:1),t="rgba"),t.substr(0,3)+"("+e.slice(0,"rgb"===t?3:4).join(" ")+")")},W=function(){for(var r,n=[],e=arguments.length;e--;)n[e]=arguments[e];var t,a,f,o=(n=i(n,"hsl"))[0],u=n[1],c=n[2];if(0===u)t=a=f=255*c;else{var l=[0,0,0],h=[0,0,0],s=c<.5?c*(1+u):c+u-c*u,d=2*c-s,b=o/360;l[0]=b+1/3,l[1]=b,l[2]=b-1/3;for(var g=0;g<3;g++)l[g]<0&&(l[g]+=1),l[g]>1&&(l[g]-=1),6*l[g]<1?h[g]=d+6*(s-d)*l[g]:2*l[g]<1?h[g]=s:3*l[g]<2?h[g]=d+(s-d)*(2/3-l[g])*6:h[g]=d;t=(r=[255*h[0],255*h[1],255*h[2]])[0],a=r[1],f=r[2]}return n.length>3?[t,a,f,n[3]]:[t,a,f,1]},I=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=(r=i(r,"lab"))[0],t=r[1],a=r[2],f=K(e,t,a),o=f[0],u=f[1],c=f[2],l=U(o,u,c);return[l[0],l[1],l[2],r.length>3?r[3]:1]},K=function(r,n,e){var t=A.kE,a=A.kK,f=A.kKE,o=A.Xn,u=A.Yn,c=A.Zn,i=(r+16)/116,l=.002*n+i,h=i-.005*e,s=l*l*l,d=h*h*h;return[(s>t?s:(116*l-16)/a)*o,(r>f?Math.pow((r+16)/116,3):r/a)*u,(d>t?d:(116*h-16)/a)*c]},z=function(r){var n=Math.sign(r);return((r=Math.abs(r))<=.0031308?12.92*r:1.055*Math.pow(r,1/2.4)-.055)*n},U=function(r,n,e){var t=A.MtxAdaptMa,a=A.MtxAdaptMaI,f=A.MtxXYZ2RGB,o=A.RefWhiteRGB,u=A.Xn,c=A.Yn,i=A.Zn,l=u*t.m00+c*t.m10+i*t.m20,h=u*t.m01+c*t.m11+i*t.m21,s=u*t.m02+c*t.m12+i*t.m22,d=o.X*t.m00+o.Y*t.m10+o.Z*t.m20,b=o.X*t.m01+o.Y*t.m11+o.Z*t.m21,g=o.X*t.m02+o.Y*t.m12+o.Z*t.m22,v=(r*t.m00+n*t.m10+e*t.m20)*(d/l),p=(r*t.m01+n*t.m11+e*t.m21)*(b/h),m=(r*t.m02+n*t.m12+e*t.m22)*(g/s),y=v*a.m00+p*a.m10+m*a.m20,w=v*a.m01+p*a.m11+m*a.m21,k=v*a.m02+p*a.m12+m*a.m22;return[255*z(y*f.m00+w*f.m10+k*f.m20),255*z(y*f.m01+w*f.m11+k*f.m21),255*z(y*f.m02+w*f.m12+k*f.m22)]},V=Math.sin,D=Math.cos,T=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"lch"),t=e[0],a=e[1],f=e[2];return isNaN(f)&&(f=0),[t,D(f*=m)*a,V(f)*a]},H=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=(r=i(r,"lch"))[0],t=r[1],a=r[2],f=T(e,t,a),o=f[0],u=f[1],c=f[2],l=I(o,u,c);return[l[0],l[1],l[2],r.length>3?r[3]:1]},J=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t,a=(r=i(r,"lab"))[0],f=r[1],o=r[2],u=r.slice(3),c=(e=[[1.2268798758459243,-.5578149944602171,.2813910456659647],[-.0405757452148008,1.112286803280317,-.0717110580655164],[-.0763729366746601,-.4214933324022432,1.5869240198367816]],t=C([[1,.3963377773761749,.2158037573099136],[1,-.1055613458156586,-.0638541728258133],[1,-.0894841775298119,-1.2914855480194092]],[a,f,o]),C(e,t.map((function(r){return Math.pow(r,3)})))),l=c[0],h=c[1],s=c[2],d=U(l,h,s);return[d[0],d[1],d[2]].concat(u.length>0&&u[0]<1?[u[0]]:[])};var Q=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=(r=i(r,"lch"))[0],t=r[1],a=r[2],f=r.slice(3),o=T(e,t,a),u=o[0],c=o[1],l=o[2],h=J(u,c,l);return[h[0],h[1],h[2]].concat(f.length>0&&f[0]<1?[f[0]]:[])},rr=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,nr=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,er=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,tr=/\s*/.source,ar=/\s+/.source,fr=/\s*,\s*/.source,or=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,ur=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,cr=new RegExp("^rgba?\\("+tr+[rr,rr,rr].join(ar)+ur+"\\)$"),ir=new RegExp("^rgb\\("+tr+[rr,rr,rr].join(fr)+tr+"\\)$"),lr=new RegExp("^rgba\\("+tr+[rr,rr,rr,nr].join(fr)+tr+"\\)$"),hr=new RegExp("^hsla?\\("+tr+[or,er,er].join(ar)+ur+"\\)$"),sr=new RegExp("^hsl?\\("+tr+[or,er,er].join(fr)+tr+"\\)$"),dr=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,br=new RegExp("^lab\\("+tr+[nr,nr,nr].join(ar)+ur+"\\)$"),gr=new RegExp("^lch\\("+tr+[nr,nr,or].join(ar)+ur+"\\)$"),vr=new RegExp("^oklab\\("+tr+[nr,nr,nr].join(ar)+ur+"\\)$"),pr=new RegExp("^oklch\\("+tr+[nr,nr,or].join(ar)+ur+"\\)$"),mr=Math.round,yr=function(r){return r.map((function(r,n){return n<=2?e(mr(r),0,255):r}))},wr=function(r,n,e,t){return void 0===n&&(n=0),void 0===e&&(e=100),void 0===t&&(t=!1),"string"==typeof r&&r.endsWith("%")&&(r=parseFloat(r.substring(0,r.length-1))/100,r=t?n+.5*(r+1)*(e-n):n+r*(e-n)),+r},kr=function(r,n){return"none"===r?n:r},Mr=function(r){if("transparent"===(r=r.toLowerCase().trim()))return[0,0,0,0];var n;if(w.format.named)try{return w.format.named(r)}catch(r){}if((n=r.match(cr))||(n=r.match(ir))){for(var e=n.slice(1,4),t=0;t<3;t++)e[t]=+wr(kr(e[t],0),0,255);e=yr(e);var a=void 0!==n[4]?+wr(n[4],0,1):1;return e[3]=a,e}if(n=r.match(lr)){for(var f=n.slice(1,5),o=0;o<4;o++)f[o]=+wr(f[o],0,255);return f}if((n=r.match(hr))||(n=r.match(sr))){var u=n.slice(1,4);u[0]=+kr(u[0].replace("deg",""),0),u[1]=.01*+wr(kr(u[1],0),0,100),u[2]=.01*+wr(kr(u[2],0),0,100);var c=yr(W(u)),i=void 0!==n[4]?+wr(n[4],0,1):1;return c[3]=i,c}if(n=r.match(dr)){var l=n.slice(1,4);l[1]*=.01,l[2]*=.01;for(var h=W(l),s=0;s<3;s++)h[s]=mr(h[s]);return h[3]=+n[4],h}if(n=r.match(br)){var d=n.slice(1,4);d[0]=wr(kr(d[0],0),0,100),d[1]=wr(kr(d[1],0),-125,125,!0),d[2]=wr(kr(d[2],0),-125,125,!0);var b=R();E("d50");var g=yr(I(d));E(b);var v=void 0!==n[4]?+wr(n[4],0,1):1;return g[3]=v,g}if(n=r.match(gr)){var p=n.slice(1,4);p[0]=wr(p[0],0,100),p[1]=wr(kr(p[1],0),0,150,!1),p[2]=+kr(p[2].replace("deg",""),0);var m=R();E("d50");var y=yr(H(p));E(m);var k=void 0!==n[4]?+wr(n[4],0,1):1;return y[3]=k,y}if(n=r.match(vr)){var M=n.slice(1,4);M[0]=wr(kr(M[0],0),0,1),M[1]=wr(kr(M[1],0),-.4,.4,!0),M[2]=wr(kr(M[2],0),-.4,.4,!0);var N=yr(J(M)),x=void 0!==n[4]?+wr(n[4],0,1):1;return N[3]=x,N}if(n=r.match(pr)){var _=n.slice(1,4);_[0]=wr(kr(_[0],0),0,1),_[1]=wr(kr(_[1],0),0,.4,!1),_[2]=+kr(_[2].replace("deg",""),0);var A=yr(Q(_)),j=void 0!==n[4]?+wr(n[4],0,1):1;return A[3]=j,A}};Mr.test=function(r){return cr.test(r)||hr.test(r)||br.test(r)||gr.test(r)||vr.test(r)||pr.test(r)||ir.test(r)||lr.test(r)||sr.test(r)||dr.test(r)||"transparent"===r},k.prototype.css=function(r){return S(this._rgb,r)};var Nr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["css"])))};M.css=Nr,w.format.css=Mr,w.autodetect.push({p:5,test:function(r){for(var n=[],e=arguments.length-1;e-- >0;)n[e]=arguments[e+1];if(!n.length&&"string"===c(r)&&Mr.test(r))return"css"}}),w.format.gl=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgba");return e[0]*=255,e[1]*=255,e[2]*=255,e};var xr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["gl"])))};M.gl=xr,k.prototype.gl=function(){var r=this._rgb;return[r[0]/255,r[1]/255,r[2]/255,r[3]]};var _r=Math.floor;k.prototype.hcg=function(){return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t=i(r,"rgb"),a=t[0],f=t[1],o=t[2],u=s(a,f,o),c=d(a,f,o),l=c-u,h=100*l/255,b=u/(255-l)*100;return 0===l?e=Number.NaN:(a===c&&(e=(f-o)/l),f===c&&(e=2+(o-a)/l),o===c&&(e=4+(a-f)/l),(e*=60)<0&&(e+=360)),[e,h,b]}(this._rgb)};var Ar=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hcg"])))};M.hcg=Ar,w.format.hcg=function(){for(var r,n,e,t,a,f,o=[],u=arguments.length;u--;)o[u]=arguments[u];var c,l,h,s=(o=i(o,"hcg"))[0],d=o[1],b=o[2];b*=255;var g=255*d;if(0===d)c=l=h=b;else{360===s&&(s=0),s>360&&(s-=360),s<0&&(s+=360);var v=_r(s/=60),p=s-v,m=b*(1-d),y=m+g*(1-p),w=m+g*p,k=m+g;switch(v){case 0:c=(r=[k,w,m])[0],l=r[1],h=r[2];break;case 1:c=(n=[y,k,m])[0],l=n[1],h=n[2];break;case 2:c=(e=[m,k,w])[0],l=e[1],h=e[2];break;case 3:c=(t=[m,y,k])[0],l=t[1],h=t[2];break;case 4:c=(a=[w,m,k])[0],l=a[1],h=a[2];break;case 5:c=(f=[k,m,y])[0],l=f[1],h=f[2]}}return[c,l,h,o.length>3?o[3]:1]},w.autodetect.push({p:1,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"hcg"))&&3===r.length)return"hcg"}});var jr=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,Er=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,Rr=function(r){if(r.match(jr)){4!==r.length&&7!==r.length||(r=r.substr(1)),3===r.length&&(r=(r=r.split(""))[0]+r[0]+r[1]+r[1]+r[2]+r[2]);var n=parseInt(r,16);return[n>>16,n>>8&255,255&n,1]}if(r.match(Er)){5!==r.length&&9!==r.length||(r=r.substr(1)),4===r.length&&(r=(r=r.split(""))[0]+r[0]+r[1]+r[1]+r[2]+r[2]+r[3]+r[3]);var e=parseInt(r,16);return[e>>24&255,e>>16&255,e>>8&255,Math.round((255&e)/255*100)/100]}throw new Error("unknown hex color: "+r)},Or=Math.round,Pr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgba"),t=e[0],a=e[1],f=e[2],o=e[3],u=l(r)||"auto";void 0===o&&(o=1),"auto"===u&&(u=o<1?"rgba":"rgb");var c="000000"+((t=Or(t))<<16|(a=Or(a))<<8|(f=Or(f))).toString(16);c=c.substr(c.length-6);var h="0"+Or(255*o).toString(16);switch(h=h.substr(h.length-2),u.toLowerCase()){case"rgba":return"#"+c+h;case"argb":return"#"+h+c;default:return"#"+c}};k.prototype.hex=function(r){return Pr(this._rgb,r)};var Fr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hex"])))};M.hex=Fr,w.format.hex=Rr,w.autodetect.push({p:4,test:function(r){for(var n=[],e=arguments.length-1;e-- >0;)n[e]=arguments[e+1];if(!n.length&&"string"===c(r)&&[3,4,5,6,7,8,9].indexOf(r.length)>=0)return"hex"}});var Lr=Math.cos,Br=Math.min,Gr=Math.sqrt,Yr=Math.acos;k.prototype.hsi=function(){return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t=i(r,"rgb"),a=t[0],f=t[1],o=t[2],u=Br(a/=255,f/=255,o/=255),c=(a+f+o)/3,l=c>0?1-u/c:0;return 0===l?e=NaN:(e=(a-f+(a-o))/2,e/=Gr((a-f)*(a-f)+(a-o)*(f-o)),e=Yr(e),o>f&&(e=v-e),e/=v),[360*e,l,c]}(this._rgb)};var qr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hsi"])))};M.hsi=qr,w.format.hsi=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var t,a,f,o=(r=i(r,"hsi"))[0],u=r[1],c=r[2];return isNaN(o)&&(o=0),isNaN(u)&&(u=0),o>360&&(o-=360),o<0&&(o+=360),(o/=360)<1/3?a=1-((f=(1-u)/3)+(t=(1+u*Lr(v*o)/Lr(p-v*o))/3)):o<2/3?f=1-((t=(1-u)/3)+(a=(1+u*Lr(v*(o-=1/3))/Lr(p-v*o))/3)):t=1-((a=(1-u)/3)+(f=(1+u*Lr(v*(o-=2/3))/Lr(p-v*o))/3)),[255*(t=e(c*t*3)),255*(a=e(c*a*3)),255*(f=e(c*f*3)),r.length>3?r[3]:1]},w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"hsi"))&&3===r.length)return"hsi"}}),k.prototype.hsl=function(){return _(this._rgb)};var Cr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hsl"])))};M.hsl=Cr,w.format.hsl=W,w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"hsl"))&&3===r.length)return"hsl"}});var Xr=Math.floor,Zr=Math.min,$r=Math.max;k.prototype.hsv=function(){return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e,t,a,f=(r=i(r,"rgb"))[0],o=r[1],u=r[2],c=Zr(f,o,u),l=$r(f,o,u),h=l-c;return a=l/255,0===l?(e=Number.NaN,t=0):(t=h/l,f===l&&(e=(o-u)/h),o===l&&(e=2+(u-f)/h),u===l&&(e=4+(f-o)/h),(e*=60)<0&&(e+=360)),[e,t,a]}(this._rgb)};var Sr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hsv"])))};M.hsv=Sr,w.format.hsv=function(){for(var r,n,e,t,a,f,o=[],u=arguments.length;u--;)o[u]=arguments[u];var c,l,h,s=(o=i(o,"hsv"))[0],d=o[1],b=o[2];if(b*=255,0===d)c=l=h=b;else{360===s&&(s=0),s>360&&(s-=360),s<0&&(s+=360);var g=Xr(s/=60),v=s-g,p=b*(1-d),m=b*(1-d*v),y=b*(1-d*(1-v));switch(g){case 0:c=(r=[b,y,p])[0],l=r[1],h=r[2];break;case 1:c=(n=[m,b,p])[0],l=n[1],h=n[2];break;case 2:c=(e=[p,b,y])[0],l=e[1],h=e[2];break;case 3:c=(t=[p,m,b])[0],l=t[1],h=t[2];break;case 4:c=(a=[y,p,b])[0],l=a[1],h=a[2];break;case 5:c=(f=[b,p,m])[0],l=f[1],h=f[2]}}return[c,l,h,o.length>3?o[3]:1]},w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"hsv"))&&3===r.length)return"hsv"}}),k.prototype.lab=function(){return O(this._rgb)};var Wr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["lab"])))};Object.assign(M,{lab:Wr,getLabWhitePoint:R,setLabWhitePoint:E}),w.format.lab=I,w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"lab"))&&3===r.length)return"lab"}});k.prototype.lch=function(){return q(this._rgb)},k.prototype.hcl=function(){return q(this._rgb).reverse()};var Ir=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["lch"])))},Kr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["hcl"])))};Object.assign(M,{lch:Ir,hcl:Kr}),w.format.lch=H,w.format.hcl=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"hcl").reverse();return H.apply(void 0,e)},["lch","hcl"].forEach((function(r){return w.autodetect.push({p:2,test:function(){for(var n=[],e=arguments.length;e--;)n[e]=arguments[e];if("array"===c(n=i(n,r))&&3===n.length)return r}})}));k.prototype.num=function(){return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgb");return(e[0]<<16)+(e[1]<<8)+e[2]}(this._rgb)};var zr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["num"])))};Object.assign(M,{num:zr}),w.format.num=function(r){if("number"==c(r)&&r>=0&&r<=16777215)return[r>>16,r>>8&255,255&r,1];throw new Error("unknown num color: "+r)},w.autodetect.push({p:5,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if(1===r.length&&"number"===c(r[0])&&r[0]>=0&&r[0]<=16777215)return"num"}});var Ur=Math.round;k.prototype.rgb=function(r){return void 0===r&&(r=!0),!1===r?this._rgb.slice(0,3):this._rgb.slice(0,3).map(Ur)},k.prototype.rgba=function(r){return void 0===r&&(r=!0),this._rgb.slice(0,4).map((function(n,e){return e<3?!1===r?n:Ur(n):n}))};var Vr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["rgb"])))};Object.assign(M,{rgb:Vr}),w.format.rgb=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];var e=i(r,"rgba");return void 0===e[3]&&(e[3]=1),e},w.autodetect.push({p:3,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"rgba"))&&(3===r.length||4===r.length&&"number"==c(r[3])&&r[3]>=0&&r[3]<=1))return"rgb"}});var Dr=Math.log,Tr=function(r){var n,e,t,a=r/100;return a<66?(n=255,e=a<6?0:-155.25485562709179-.44596950469579133*(e=a-2)+104.49216199393888*Dr(e),t=a<20?0:.8274096064007395*(t=a-10)-254.76935184120902+115.67994401066147*Dr(t)):(n=351.97690566805693+.114206453784165*(n=a-55)-40.25366309332127*Dr(n),e=325.4494125711974+.07943456536662342*(e=a-50)-28.0852963507957*Dr(e),t=255),[n,e,t,1]},Hr=Math.round;k.prototype.temp=k.prototype.kelvin=k.prototype.temperature=function(){return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];for(var e,t=i(r,"rgb"),a=t[0],f=t[2],o=1e3,u=4e4;u-o>.4;){var c=Tr(e=.5*(u+o));c[2]/c[0]>=f/a?u=e:o=e}return Hr(e)}(this._rgb)};var Jr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["temp"])))};Object.assign(M,{temp:Jr,kelvin:Jr,temperature:Jr}),w.format.temp=w.format.kelvin=w.format.temperature=Tr,k.prototype.oklab=function(){return X(this._rgb)};var Qr=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["oklab"])))};Object.assign(M,{oklab:Qr}),w.format.oklab=J,w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"oklab"))&&3===r.length)return"oklab"}}),k.prototype.oklch=function(){return Z(this._rgb)};var rn=function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];return new(Function.prototype.bind.apply(k,[null].concat(r,["oklch"])))};Object.assign(M,{oklch:rn}),w.format.oklch=Q,w.autodetect.push({p:2,test:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if("array"===c(r=i(r,"oklch"))&&3===r.length)return"oklch"}});var nn={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};k.prototype.name=function(){for(var r=Pr(this._rgb,"rgb"),n=0,e=Object.keys(nn);n0;)n[e]=arguments[e+1];if(!n.length&&"string"===c(r)&&nn[r.toLowerCase()])return"named"}}),k.prototype.alpha=function(r,n){return void 0===n&&(n=!1),void 0!==r&&"number"===c(r)?n?(this._rgb[3]=r,this):new k([this._rgb[0],this._rgb[1],this._rgb[2],r],"rgb"):this._rgb[3]},k.prototype.clipped=function(){return this._rgb._clipped||!1},k.prototype.darken=function(r){void 0===r&&(r=1);var n=this.lab();return n[0]-=A.Kn*r,new k(n,"lab").alpha(this.alpha(),!0)},k.prototype.brighten=function(r){return void 0===r&&(r=1),this.darken(-r)},k.prototype.darker=k.prototype.darken,k.prototype.brighter=k.prototype.brighten,k.prototype.get=function(r){var n=r.split("."),e=n[0],t=n[1],a=this[e]();if(t){var f=e.indexOf(t)-("ok"===e.substr(0,2)?2:0);if(f>-1)return a[f];throw new Error("unknown channel "+t+" in mode "+e)}return a};var en=Math.pow;k.prototype.luminance=function(r,n){if(void 0===n&&(n="rgb"),void 0!==r&&"number"===c(r)){if(0===r)return new k([0,0,0,this._rgb[3]],"rgb");if(1===r)return new k([255,255,255,this._rgb[3]],"rgb");var e=this.luminance(),t=20,a=function(e,f){var o=e.interpolate(f,.5,n),u=o.luminance();return Math.abs(r-u)<1e-7||!t--?o:u>r?a(e,o):a(o,f)},f=(e>r?a(new k([0,0,0]),this):a(this,new k([255,255,255]))).rgb();return new k(f.concat([this._rgb[3]]))}return tn.apply(void 0,this._rgb.slice(0,3))};var tn=function(r,n,e){return.2126*(r=an(r))+.7152*(n=an(n))+.0722*(e=an(e))},an=function(r){return(r/=255)<=.03928?r/12.92:en((r+.055)/1.055,2.4)},fn={};function on(r,n,e){void 0===e&&(e=.5);for(var t=[],a=arguments.length-3;a-- >0;)t[a]=arguments[a+3];var f=t[0]||"lrgb";if(fn[f]||t.length||(f=Object.keys(fn)[0]),!fn[f])throw new Error("interpolation mode "+f+" is not defined");return"object"!==c(r)&&(r=new k(r)),"object"!==c(n)&&(n=new k(n)),fn[f](r,n,e).alpha(r.alpha()+e*(n.alpha()-r.alpha()))}k.prototype.mix=k.prototype.interpolate=function(r,n){void 0===n&&(n=.5);for(var e=[],t=arguments.length-2;t-- >0;)e[t]=arguments[t+2];return on.apply(void 0,[this,r,n].concat(e))},k.prototype.premultiply=function(r){void 0===r&&(r=!1);var n=this._rgb,e=n[3];return r?(this._rgb=[n[0]*e,n[1]*e,n[2]*e,e],this):new k([n[0]*e,n[1]*e,n[2]*e,e],"rgb")},k.prototype.saturate=function(r){void 0===r&&(r=1);var n=this.lch();return n[1]+=A.Kn*r,n[1]<0&&(n[1]=0),new k(n,"lch").alpha(this.alpha(),!0)},k.prototype.desaturate=function(r){return void 0===r&&(r=1),this.saturate(-r)},k.prototype.set=function(r,n,e){void 0===e&&(e=!1);var t=r.split("."),a=t[0],f=t[1],o=this[a]();if(f){var u=a.indexOf(f)-("ok"===a.substr(0,2)?2:0);if(u>-1){if("string"==c(n))switch(n.charAt(0)){case"+":case"-":o[u]+=+n;break;case"*":o[u]*=+n.substr(1);break;case"/":o[u]/=+n.substr(1);break;default:o[u]=+n}else{if("number"!==c(n))throw new Error("unsupported value for Color.set");o[u]=n}var i=new k(o,a);return e?(this._rgb=i._rgb,this):i}throw new Error("unknown channel "+f+" in mode "+a)}return o},k.prototype.tint=function(r){void 0===r&&(r=.5);for(var n=[],e=arguments.length-1;e-- >0;)n[e]=arguments[e+1];return on.apply(void 0,[this,"white",r].concat(n))},k.prototype.shade=function(r){void 0===r&&(r=.5);for(var n=[],e=arguments.length-1;e-- >0;)n[e]=arguments[e+1];return on.apply(void 0,[this,"black",r].concat(n))};fn.rgb=function(r,n,e){var t=r._rgb,a=n._rgb;return new k(t[0]+e*(a[0]-t[0]),t[1]+e*(a[1]-t[1]),t[2]+e*(a[2]-t[2]),"rgb")};var un=Math.sqrt,cn=Math.pow;fn.lrgb=function(r,n,e){var t=r._rgb,a=t[0],f=t[1],o=t[2],u=n._rgb,c=u[0],i=u[1],l=u[2];return new k(un(cn(a,2)*(1-e)+cn(c,2)*e),un(cn(f,2)*(1-e)+cn(i,2)*e),un(cn(o,2)*(1-e)+cn(l,2)*e),"rgb")};function ln(r,n,e,t){var a,f,o,u,c,i,l,h,s,d,b,g,v;return"hsl"===t?(o=r.hsl(),u=n.hsl()):"hsv"===t?(o=r.hsv(),u=n.hsv()):"hcg"===t?(o=r.hcg(),u=n.hcg()):"hsi"===t?(o=r.hsi(),u=n.hsi()):"lch"===t||"hcl"===t?(t="hcl",o=r.hcl(),u=n.hcl()):"oklch"===t&&(o=r.oklch().reverse(),u=n.oklch().reverse()),"h"!==t.substr(0,1)&&"oklch"!==t||(c=(a=o)[0],l=a[1],s=a[2],i=(f=u)[0],h=f[1],d=f[2]),isNaN(c)||isNaN(i)?isNaN(c)?isNaN(i)?g=Number.NaN:(g=i,1!=s&&0!=s||"hsv"==t||(b=h)):(g=c,1!=d&&0!=d||"hsv"==t||(b=l)):g=c+e*(i>c&&i-c>180?i-(c+360):i180?i+360-c:i-c),void 0===b&&(b=l+e*(h-l)),v=s+e*(d-s),new k("oklch"===t?[v,b,g]:[g,b,v],t)}fn.lab=function(r,n,e){var t=r.lab(),a=n.lab();return new k(t[0]+e*(a[0]-t[0]),t[1]+e*(a[1]-t[1]),t[2]+e*(a[2]-t[2]),"lab")};var hn=function(r,n,e){return ln(r,n,e,"lch")};fn.lch=hn,fn.hcl=hn;fn.num=function(r,n,e){var t=r.num(),a=n.num();return new k(t+e*(a-t),"num")};fn.hcg=function(r,n,e){return ln(r,n,e,"hcg")};fn.hsi=function(r,n,e){return ln(r,n,e,"hsi")};fn.hsl=function(r,n,e){return ln(r,n,e,"hsl")};fn.hsv=function(r,n,e){return ln(r,n,e,"hsv")};fn.oklab=function(r,n,e){var t=r.oklab(),a=n.oklab();return new k(t[0]+e*(a[0]-t[0]),t[1]+e*(a[1]-t[1]),t[2]+e*(a[2]-t[2]),"oklab")};fn.oklch=function(r,n,e){return ln(r,n,e,"oklch")};var sn=Math.pow,dn=Math.sqrt,bn=Math.PI,gn=Math.cos,vn=Math.sin,pn=Math.atan2;var mn=function(r,n){for(var e=r.length,a=[0,0,0,0],f=0;f.9999999&&(a[3]=1),new k(t(a))},yn=Math.pow;function wn(r){var n="rgb",t=M("#ccc"),a=0,f=[0,1],o=[],u=[0,0],i=!1,l=[],h=!1,s=0,d=1,b=!1,g={},v=!0,p=1,m=function(r){if((r=r||["#fff","#000"])&&"string"===c(r)&&M.brewer&&M.brewer[r.toLowerCase()]&&(r=M.brewer[r.toLowerCase()]),"array"===c(r)){1===r.length&&(r=[r[0],r[0]]),r=r.slice(0);for(var n=0;n2){var b=function(r){if(null!=i){for(var n=i.length-1,e=0;e=i[e];)e++;return e-1}return 0}(r);h=b/(i.length-2)}else h=d!==s?(r-s)/(d-s):1;h=w(h),a||(h=y(h)),1!==p&&(h=yn(h,p)),h=e(h=u[0]+h*(1-u[0]-u[1]),0,1);var m=Math.floor(1e4*h);if(v&&g[m])f=g[m];else{if("array"===c(l))for(var k=0;k=N&&k===o.length-1){f=l[k];break}if(h>N&&h2){var c=r.map((function(n,e){return e/(r.length-1)})),i=r.map((function(r){return(r-s)/(d-s)}));i.every((function(r,n){return c[n]===r}))||(w=function(r){if(r<=0||r>=1)return r;for(var n=0;r>=i[n+1];)n++;var e=(r-i[n])/(i[n+1]-i[n]);return c[n]+e*(c[n+1]-c[n])})}}return f=[s,d],x},x.mode=function(r){return arguments.length?(n=r,N(),x):n},x.range=function(r,n){return m(r),x},x.out=function(r){return h=r,x},x.spread=function(r){return arguments.length?(a=r,x):a},x.correctLightness=function(r){return null==r&&(r=!0),b=r,N(),y=b?function(r){for(var n=k(0,!0).lab()[0],e=k(1,!0).lab()[0],t=n>e,a=k(r,!0).lab()[0],f=n+(e-n)*r,o=a-f,u=0,c=1,i=20;Math.abs(o)>.01&&i-- >0;)t&&(o*=-1),o<0?(u=r,r+=.5*(c-r)):(c=r,r+=.5*(u-r)),a=k(r,!0).lab()[0],o=a-f;return r}:function(r){return r},x},x.padding=function(r){return null!=r?("number"===c(r)&&(r=[r,r]),u=r,x):u},x.colors=function(n,e){arguments.length<2&&(e="hex");var t=[];if(0===arguments.length)t=l.slice(0);else if(1===n)t=[x(.5)];else if(n>1){var a=f[0],o=f[1]-a;t=function(r,n){for(var e=[],t=ra;t?f++:f--)e.push(f);return e}(0,n).map((function(r){return x(a+r/(n-1)*o)}))}else{r=[];var u=[];if(i&&i.length>2)for(var c=1,h=i.length,s=1<=h;s?ch;s?c++:c--)u.push(.5*(i[c-1]+i[c]));else u=f;t=u.map((function(r){return x(r)}))}return M[e]&&(t=t.map((function(r){return r[e]()}))),t},x.cache=function(r){return null!=r?(v=r,x):v},x.gamma=function(r){return null!=r?(p=r,x):p},x.nodata=function(r){return null!=r?(t=M(r),x):t},x}var kn=function(r,n,e){if(!kn[e])throw new Error("unknown blend mode "+e);return kn[e](r,n)},Mn=function(r){return function(n,e){var t=M(e).rgb(),a=M(n).rgb();return M.rgb(r(t,a))}},Nn=function(r){return function(n,e){var t=[];return t[0]=r(n[0],e[0]),t[1]=r(n[1],e[1]),t[2]=r(n[2],e[2]),t}};kn.normal=Mn(Nn((function(r){return r}))),kn.multiply=Mn(Nn((function(r,n){return r*n/255}))),kn.screen=Mn(Nn((function(r,n){return 255*(1-(1-r/255)*(1-n/255))}))),kn.overlay=Mn(Nn((function(r,n){return n<128?2*r*n/255:255*(1-2*(1-r/255)*(1-n/255))}))),kn.darken=Mn(Nn((function(r,n){return r>n?n:r}))),kn.lighten=Mn(Nn((function(r,n){return r>n?r:n}))),kn.dodge=Mn(Nn((function(r,n){return 255===r||(r=n/255*255/(1-r/255))>255?255:r}))),kn.burn=Mn(Nn((function(r,n){return 255*(1-(1-n/255)/(r/255))})));var xn=Math.pow,_n=Math.sin,An=Math.cos;var jn=Math.floor,En=Math.random;var Rn=Math.log,On=Math.pow,Pn=Math.floor,Fn=Math.abs;function Ln(r,n){void 0===n&&(n=null);var e={min:Number.MAX_VALUE,max:-1*Number.MAX_VALUE,sum:0,values:[],count:0};return"object"===c(r)&&(r=Object.values(r)),r.forEach((function(r){n&&"object"===c(r)&&(r=r[n]),null==r||isNaN(r)||(e.values.push(r),e.sum+=r,re.max&&(e.max=r),e.count+=1)})),e.domain=[e.min,e.max],e.limits=function(r,n){return Bn(e,r,n)},e}function Bn(r,n,e){void 0===n&&(n="equal"),void 0===e&&(e=7),"array"==c(r)&&(r=Ln(r));var t=r.min,a=r.max,f=r.values.sort((function(r,n){return r-n}));if(1===e)return[t,a];var o=[];if("c"===n.substr(0,1)&&(o.push(t),o.push(a)),"e"===n.substr(0,1)){o.push(t);for(var u=1;u 0");var i=Math.LOG10E*Rn(t),l=Math.LOG10E*Rn(a);o.push(t);for(var h=1;h200&&(w=!1)}for(var Y={},q=0;q=360;)b-=360;o[d]=b}else o[d]=o[d]/u[d];return s/=t,new k(o,n).alpha(s>.99999?1:s,!0)},bezier:function(r){var n=function(r){var n,e,t,a,f,o,u;if(2===(r=r.map((function(r){return new k(r)}))).length)n=r.map((function(r){return r.lab()})),f=n[0],o=n[1],a=function(r){var n=[0,1,2].map((function(n){return f[n]+r*(o[n]-f[n])}));return new k(n,"lab")};else if(3===r.length)e=r.map((function(r){return r.lab()})),f=e[0],o=e[1],u=e[2],a=function(r){var n=[0,1,2].map((function(n){return(1-r)*(1-r)*f[n]+2*(1-r)*r*o[n]+r*r*u[n]}));return new k(n,"lab")};else if(4===r.length){var c;t=r.map((function(r){return r.lab()})),f=t[0],o=t[1],u=t[2],c=t[3],a=function(r){var n=[0,1,2].map((function(n){return(1-r)*(1-r)*(1-r)*f[n]+3*(1-r)*(1-r)*r*o[n]+3*(1-r)*r*r*u[n]+r*r*r*c[n]}));return new k(n,"lab")}}else{if(!(r.length>=5))throw new RangeError("No point in running bezier with only one color.");var i,l,h;i=r.map((function(r){return r.lab()})),h=r.length-1,l=function(r){for(var n=[1,1],e=1;et?(e+.05)/(t+.05):(t+.05)/(e+.05)},contrastAPCA:function(r,n){r=new k(r),n=new k(n),r.alpha()<1&&(r=on(n,r,r.alpha(),"rgb"));var e=Yn.apply(void 0,r.rgb()),t=Yn.apply(void 0,n.rgb()),a=e>=Gn?e:e+Math.pow(Gn-e,1.414),f=t>=Gn?t:t+Math.pow(Gn-t,1.414),o=Math.pow(f,.56)-Math.pow(a,.57),u=Math.pow(f,.65)-Math.pow(a,.62),c=Math.abs(f-a)<5e-4?0:a0?c-.027:c+.027)},cubehelix:function(r,n,e,a,f){void 0===r&&(r=300),void 0===n&&(n=-1.5),void 0===e&&(e=1),void 0===a&&(a=1),void 0===f&&(f=[0,1]);var o,u=0;"array"===c(f)?o=f[1]-f[0]:(o=0,f=[f,f]);var i=function(c){var i=v*((r+120)/360+n*c),l=xn(f[0]+o*c,a),h=(0!==u?e[0]+c*u:e)*l*(1-l)/2,s=An(i),d=_n(i);return M(t([255*(l+h*(-.14861*s+1.78277*d)),255*(l+h*(-.29227*s-.90649*d)),255*(l+h*(1.97294*s)),1]))};return i.start=function(n){return null==n?r:(r=n,i)},i.rotations=function(r){return null==r?n:(n=r,i)},i.gamma=function(r){return null==r?a:(a=r,i)},i.hue=function(r){return null==r?e:("array"===c(e=r)?0===(u=e[1]-e[0])&&(e=e[1]):u=0,i)},i.lightness=function(r){return null==r?f:("array"===c(r)?(f=r,o=r[1]-r[0]):(f=[r,r],o=0),i)},i.scale=function(){return M.scale(i)},i.hue(e),i},deltaE:function(r,n,e,t,a){void 0===e&&(e=1),void 0===t&&(t=1),void 0===a&&(a=1);var f=function(r){return 360*r/(2*zn)},o=function(r){return 2*zn*r/360};r=new k(r),n=new k(n);var u=Array.from(r.lab()),c=u[0],i=u[1],l=u[2],h=Array.from(n.lab()),s=h[0],d=h[1],b=h[2],g=(c+s)/2,v=(qn(Cn(i,2)+Cn(l,2))+qn(Cn(d,2)+Cn(b,2)))/2,p=.5*(1-qn(Cn(v,7)/(Cn(v,7)+Cn(25,7)))),m=i*(1+p),y=d*(1+p),w=qn(Cn(m,2)+Cn(l,2)),M=qn(Cn(y,2)+Cn(b,2)),N=(w+M)/2,x=f($n(l,m)),_=f($n(b,y)),A=x>=0?x:x+360,j=_>=0?_:_+360,E=Sn(A-j)>180?(A+j+360)/2:(A+j)/2,R=1-.17*Wn(o(E-30))+.24*Wn(o(2*E))+.32*Wn(o(3*E+6))-.2*Wn(o(4*E-63)),O=j-A;O=Sn(O)<=180?O:j<=A?O+360:O-360,O=2*qn(w*M)*In(o(O)/2);var P=s-c,F=M-w,L=1+.015*Cn(g-50,2)/qn(20+Cn(g-50,2)),B=1+.045*N,G=1+.015*N*R,Y=30*Kn(-Cn((E-275)/25,2)),q=-(2*qn(Cn(N,7)/(Cn(N,7)+Cn(25,7))))*In(2*o(Y)),C=qn(Cn(P/(e*L),2)+Cn(F/(t*B),2)+Cn(O/(a*G),2)+q*(F/(t*B))*(O/(a*G)));return Zn(0,Xn(100,C))},distance:function(r,n,e){void 0===e&&(e="lab"),r=new k(r),n=new k(n);var t=r.get(e),a=n.get(e),f=0;for(var o in t){var u=(t[o]||0)-(a[o]||0);f+=u*u}return Math.sqrt(f)},input:w,interpolate:on,limits:Bn,mix:on,random:function(){for(var r="#",n=0;n<6;n++)r+="0123456789abcdef".charAt(jn(16*En()));return new k(r,"hex")},scale:wn,scales:Un,valid:function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];try{return new(Function.prototype.bind.apply(k,[null].concat(r))),!0}catch(r){return!1}},cmyk:x,css:Nr,gl:xr,hcg:Ar,hex:Fr,hsi:qr,hsl:Cr,hsv:Sr,lab:Wr,lch:Ir,hcl:Kr,num:zr,rgb:Vr,temp:Jr,kelvin:Jr,temperature:Jr,oklab:Qr,oklch:rn,getLabWhitePoint:R,setLabWhitePoint:E}),M})); diff --git a/base_geoengine/static/lib/geostats-2.1.0/geostats.css b/base_geoengine/static/lib/geostats-2.1.0/geostats.css new file mode 100644 index 000000000..a1bad4e69 --- /dev/null +++ b/base_geoengine/static/lib/geostats-2.1.0/geostats.css @@ -0,0 +1,24 @@ +.geostats-legend div { + margin:3px 10px 5px 10px; + clear:left; +} + +.geostats-legend-title { + font-weight: bold; + margin-bottom: 4px; +} + +.geostats-legend-block { + border: 1px solid #555555; + display: block; + float: left; + height: 12px; + margin: 0 5px 0 20px; + width: 20px; +} + +.geostats-legend-counter { + font-size: 0.8em; + color:#666; + font-style: italic; +} diff --git a/base_geoengine/static/lib/geostats-2.1.0/geostats.js b/base_geoengine/static/lib/geostats-2.1.0/geostats.js new file mode 100755 index 000000000..0da331884 --- /dev/null +++ b/base_geoengine/static/lib/geostats-2.1.0/geostats.js @@ -0,0 +1,1435 @@ +/** +* geostats() is a tiny and standalone javascript library for classification +* Project page - https://github.com/simogeo/geostats +* Copyright (c) 2011 Simon Georget, http://www.intermezzo-coop.eu +* Licensed under the MIT license +*/ + + +(function (definition) { + // This file will function properly as a + + + + + + + + +
+
+
+
+
+

+ Prerequisite +

+
+
+
+
+
+
+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/api_doc.html b/base_geoengine/doc/build/api_doc.html new file mode 100644 index 000000000..67b55a830 --- /dev/null +++ b/base_geoengine/doc/build/api_doc.html @@ -0,0 +1,775 @@ + + + + + + + API — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + +
+
+
+
+
+

+ API +

+
+ +

+ GeoColumns +

+
+
+ class base_geoengine.geo_field.Geom(string, + geo_type, dim=2, srid=900913, + gist_index=True, **args) +
+
+

+ This class adds a new type of columns to ORM. It enable POSTGIS + geometry type support. +

+
+
+ create_geo_column(cursor, col_name, geo_column, + table, model) +
+

Create a columns of type the geom

+
+ +
+
+ entry_to_shape(value, same_type=False) +
+

Transform input into an object

+
+ +
+
+ load_geo(wkb) +
+
+

+ This function is used to load geometry into browse record + after read was done +

+
+
+ +
+
+ manage_db_column(cursor, col_name, geo_columns, + table, model) +
+

In charge of managing geom column type

+
+ +
+
+ set(cr, + obj, res_id, name, value, + user=None, context=None) +
+
+

+ This function used to write and create value into database + value can be geojson, wkt, shapely geomerty object. If + geo_direct_write in context you can pass diretly WKT +

+
+
+ +
+
+ set_geo(value) +
+
+

+ This function is used to transform data in order to be + compatible with the create function. It is also use in + expression.py in order to represent value. +

+
+
+ +
+
+ update_geo_column(cursor, col_name, geo_column, + table, model) +
+
+

+ Update a column of type the geom does. !! not do a lot of test + yet +

+
+
+
+
+ + +
+
+ class base_geoengine.geo_point.GeoPoint(string, + dim=2, srid=900913, gist_index=True, + **args) +
+
+

+ This class adds a new type of columns to ORM. It enables POSTGIS + geometry type support +

+
+
+ + +
+
+ class base_geoengine.geo_line.GeoLine(string, + dim=2, srid=900913, gist_index=True, + **args) +
+
+

+ This class adds a new type of columns to ORM. It enables POSTGIS + geometry type support +

+
+
+ + +
+
+ class base_geoengine.geo_multiline.GeoMultiLine(string, + dim=2, srid=900913, gist_index=True, + **args) +
+
+

+ This class adds a new type of columns to ORM. It enables POSTGIS + geometry type support +

+
+
+ + +
+
+ class base_geoengine.geo_polygon.GeoPolygon(string, + dim=2, srid=900913, gist_index=True, + **args) +
+
+

+ This class adds a new type of columns to ORM. It enables POSTGIS + geometry type support +

+
+
+ + +
+
+ class base_geoengine.geo_multipolygon.GeoMultiPolygon(string, dim=2, srid=900913, + gist_index=True, **args) +
+
+

+ This class adds a new type of columns to ORM. It enables POSTGIS + geometry type support +

+
+
+
+
+ +

+ View Management +

+

Module that manages map view and vector/raster layer

+ +
+
+

+ GEO ORM MODEL +

+
+
+ class base_geoengine.geo_model.GeoModel(pool, + cr) +
+
+
+
+ fields_get(cursor, + uid, allfields=None, context=None) +
+

Add geo_type definition for geo fields

+
+ +
+
+ fields_view_get(cursor, uid, view_id=None, + view_type='form', context=None, + toolbar=False, submenu=False) +
+
+

+ Returns information about the available fields of the class. + If view type == ‘map’ returns geographical columns + available +

+
+
+ +
+ +
+

+ Perform a geo search it allows direct domain: geo_search(r, + uid, domaine=[(‘name’, ‘ilike’, + ‘toto’]), geo_domain=[(‘the_point’, + ‘geo_intersect’, myshaply_obj or mywkt or + mygeojson)]. +

+

+ We can also support indirect geo_domain (‘geom’, + ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }). +

+
+
The supported operators are :
+
+
    +
  • geo_greater
  • +
  • geo_lesser
  • +
  • geo_equal
  • +
  • geo_touch
  • +
  • geo_within
  • +
  • geo_intersect
  • +
+
+
+
+
+
+
+
+
+ +

+ GEO ORM OPERATORS +

+
+ +
+

+ Perform a geo search it allows direct domain: geo_search(r, uid, + domaine=[(‘name’, ‘ilike’, + ‘toto’]), geo_domain=[(‘the_point’, + ‘geo_intersect’, myshaply_obj or mywkt or mygeojson)] +

+

+ We can also support indirect geo_domain (‘geom’, ‘geo_operator’, + {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) +

+
+
The supported operators are :
+
+
    +
  • geo_greater
  • +
  • geo_lesser
  • +
  • geo_equal
  • +
  • geo_touch
  • +
  • geo_within
  • +
  • geo_intersect
  • +
+
+
+
+
+ +
+
+ class base_geoengine.geo_operators.GeoOperator(geo_field) +
+
+
+
+ get_geo_equal_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_equal operator

+
+ +
+
+ get_geo_greater_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_greater operator

+
+ +
+
+ get_geo_intersect_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_intersec operator

+
+ +
+
+ get_geo_lesser_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_lesser operator

+
+ +
+
+ get_geo_touch_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_touch operator

+
+ +
+
+ get_geo_within_sql(table, col, value, + rel_col=None, rel_model=None) +
+

Returns raw sql for geo_within operator

+
+ +
+
+ get_rel_field(rel_col, rel_model) +
+
+

+ Retrieves the expression to use in PostGIS statement for a + spatial rel search +

+
+
+
+
+
+
+ +

+ GEO helper +

+
+
+ base_geoengine.geo_helper.geo_convertion_helper.value_to_shape(value) +
+

Transforms input into a Shapely object.

+
+
+
+
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

+ Postgisify an exisiting database +

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/genindex.html b/base_geoengine/doc/build/genindex.html new file mode 100644 index 000000000..600d02249 --- /dev/null +++ b/base_geoengine/doc/build/genindex.html @@ -0,0 +1,464 @@ + + + + + + + Index — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + +
+
+
+
+

Index

+ +
+ B + | C | + E | + F | + G | + L | + M | + S | + U | V +
+

B

+ + + + + +
+
+
+ base_geoengine.geo_field (module) +
+ +
+ base_geoengine.geo_helper.geo_convertion_helper (module) +
+ +
+ base_geoengine.geo_line (module) +
+ +
+ base_geoengine.geo_multiline (module) +
+ +
+ base_geoengine.geo_multipolygon (module) +
+ +
+ base_geoengine.geo_operators (module) +
+
+
+
+
+ base_geoengine.geo_point (module) +
+ +
+ base_geoengine.geo_polygon (module) +
+ +
+ base_geoengine.geo_view (module) +
+ +
+ base_geoengine.geo_view.geo_raster_layer (module) +
+ +
+ base_geoengine.geo_view.geo_vector_layer (module) +
+ +
+ base_geoengine.geo_view.ir_view (module) +
+
+
+ +

C

+ + + + +
+
+
+ create_geo_column() (base_geoengine.geo_field.Geom method) +
+
+
+ +

E

+ + + + +
+
+
+ entry_to_shape() (base_geoengine.geo_field.Geom method) +
+
+
+ +

F

+ + + + + +
+
+
+ fields_get() (base_geoengine.geo_model.GeoModel method) +
+
+
+
+
+ fields_view_get() (base_geoengine.geo_model.GeoModel method) +
+
+
+ +

G

+ + + + + +
+
+
+ geo_search() (base_geoengine.geo_model.GeoModel method) +
+ +
+
+
+ (in module base_geoengine.geo_operators) +
+
+
+ +
+ GeoLine (class in base_geoengine.geo_line) +
+ +
+ Geom (class in base_geoengine.geo_field) +
+ +
+ GeoModel (class in base_geoengine.geo_model) +
+ +
+ GeoMultiLine (class in base_geoengine.geo_multiline) +
+ +
+ GeoMultiPolygon (class in base_geoengine.geo_multipolygon) +
+ +
+ GeoOperator (class in base_geoengine.geo_operators) +
+ +
+ GeoPoint (class in base_geoengine.geo_point) +
+
+
+
+
+ GeoPolygon (class in base_geoengine.geo_polygon) +
+ +
+ get_geo_equal_sql() (base_geoengine.geo_operators.GeoOperator + method) +
+ +
+ get_geo_greater_sql() (base_geoengine.geo_operators.GeoOperator + method) +
+ +
+ get_geo_intersect_sql() + (base_geoengine.geo_operators.GeoOperator method) +
+ +
+ get_geo_lesser_sql() (base_geoengine.geo_operators.GeoOperator + method) +
+ +
+ get_geo_touch_sql() (base_geoengine.geo_operators.GeoOperator + method) +
+ +
+ get_geo_within_sql() (base_geoengine.geo_operators.GeoOperator + method) +
+ +
+ get_rel_field() (base_geoengine.geo_operators.GeoOperator + method) +
+
+
+ +

L

+ + + + +
+
+
+ load_geo() (base_geoengine.geo_field.Geom method) +
+
+
+ +

M

+ + + + +
+
+
+ manage_db_column() (base_geoengine.geo_field.Geom method) +
+
+
+ +

S

+ + + + + +
+
+
+ set() (base_geoengine.geo_field.Geom method) +
+
+
+
+
+ set_geo() (base_geoengine.geo_field.Geom method) +
+
+
+ +

U

+ + + + +
+
+
+ update_geo_column() (base_geoengine.geo_field.Geom method) +
+
+
+ +

V

+ + + + +
+
+
+ value_to_shape() (in module + base_geoengine.geo_helper.geo_convertion_helper) +
+
+
+
+
+
+
+
+ + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/index.html b/base_geoengine/doc/build/index.html new file mode 100644 index 000000000..38b55564f --- /dev/null +++ b/base_geoengine/doc/build/index.html @@ -0,0 +1,249 @@ + + + + + + + + Welcome to OpenERP GeoEngine’s documentation! — OpenERP GeoEngine 0.3 + documentation + + + + + + + + + + + + + + + +
+
+
+
+
+

+ Welcome to OpenERP GeoEngine’s documentation! +

+

Contents:

+ +
+
+

+ Indices and tables +

+ +
+
+
+
+
+
+

Table Of Contents

+ + +

Next topic

+

+ What is GeoEngine ? +

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/installation.html b/base_geoengine/doc/build/installation.html new file mode 100644 index 000000000..a80c40adb --- /dev/null +++ b/base_geoengine/doc/build/installation.html @@ -0,0 +1,205 @@ + + + + + + + Installation — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + + +
+
+
+
+
+

+ Installation +

+
+

+ PostGIS database template +

+

+ In order to create databases from the OpenERP client, you have to + create a PostGis database template. Under windows, this template is + already available in installer. +

+

+ On other *NIX, system you simply have to launch the create_postgis_template.sh + script available in the base_geoengine module in the scripts folder. + This should be done by a PostgreSQL superuser. +

+

In order to test the success:

+
+
+psql -l
+template_postgis | owner | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
+
+

+ If you want to install GeoEngine on an exisiting database, please + refer to the Postgisify section. +

+
+
+

+ OpenERP +

+

Add the template as an argument to OpenERP server:

+
+
+
--db-template=template_postgis
+
+
+
+

or in config file:

+
+
+
db_template = template_postgis
+
+
+
+

Do not forget to add the GeoEngine modules to your addons path.

+

+ Then install (eventually update module list) the base GeoEngine module + form the OpenERP client. +

+
+
+
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

+ Prerequisites +

+

Next topic

+

+ Postgisify an exisiting database +

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/objects.inv b/base_geoengine/doc/build/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..e054944429407487424e785ed28ed31a8ed50e21 GIT binary patch literal 638 zcmV-^0)hP_AX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkUaAj^q zQcxgAWp71pXK8L_3L_v^WpZ_Ab7^j8AbM*2P1yxCOA4fPxylldz}8wmmwDen$o9G#+ZLsNoHu&s|(r zTJ69%snuwuQoE6894%9#Um9;)FTBqM## zFzGIlkc|rPjxL$Tsig(Tw{hc7V$m3U^c z*ssqSt&m%rf)(1q3Fvj~4JjzG83ly(u`8uSpQ|v{W@=h)YGZy`AXw}B9z_>Ziu62P z(=vb;({(PTCcn + + + + + + + Postgisify an exisiting database — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + + + +
+
+
+
+
+

+ Postgisify an exisiting database +

+

+ If you want to install the GeoEngine on an existing database, you have + to run the sql commands available in the base_geoengine module under the + postgis_sql folder using a PostgreSQL super user: +

+
+
+psql -U superuser my database -f postgis.sql
+psql -U superuser my database -f spatial_ref_sys.sql
+
+

+ In order to test if the installation is sucessfull log into you database + and: +

+
+
+SELECT * from GEOMETRY_COLUMNS;
+SELECT * from spatial_ref_sys;
+
+
+
+
+
+
+
+

Previous topic

+

+ Installation +

+

Next topic

+

API

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/prerequisite.html b/base_geoengine/doc/build/prerequisite.html new file mode 100644 index 000000000..32f676fd4 --- /dev/null +++ b/base_geoengine/doc/build/prerequisite.html @@ -0,0 +1,181 @@ + + + + + + + Prerequisites — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + + +
+
+
+
+
+

+ Prerequisites +

+
+

+ Python +

+

geojson:

+
pip install geojson
+

Shapely:

+
+
pip install Shapely==1.2.13
+
+

For Mac user: do not forget the following directive:

+
+
+
ARCHFLAGS="-arch i386 -arch x86_64"
+
+
+
+
+
+

+ PostGIS 1.5 +

+

+ Please refer to + PostGIS installation directive + or to your OS package system. +

+
+
+
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

+ What is GeoEngine ? +

+

Next topic

+

+ Installation +

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/py-modindex.html b/base_geoengine/doc/build/py-modindex.html new file mode 100644 index 000000000..4fc4efcc8 --- /dev/null +++ b/base_geoengine/doc/build/py-modindex.html @@ -0,0 +1,265 @@ + + + + + + + Python Module Index — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + +
+
+
+
+

Python Module Index

+ +
+ b +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ b +
+ + + base_geoengine + + +
+     + base_geoengine.geo_field + + +
+     + base_geoengine.geo_helper.geo_convertion_helper + + +
+     + base_geoengine.geo_line + + +
+     + base_geoengine.geo_multiline + + +
+     + base_geoengine.geo_multipolygon + + +
+     + base_geoengine.geo_operators + + +
+     + base_geoengine.geo_point + + +
+     + base_geoengine.geo_polygon + + +
+     + base_geoengine.geo_view + + +
+     + base_geoengine.geo_view.geo_raster_layer + + +
+     + base_geoengine.geo_view.geo_vector_layer + + +
+     + base_geoengine.geo_view.ir_view + + +
+
+
+
+
+
+ + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/search.html b/base_geoengine/doc/build/search.html new file mode 100644 index 000000000..20e90b731 --- /dev/null +++ b/base_geoengine/doc/build/search.html @@ -0,0 +1,95 @@ + + + + + + + Search — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + + +
+
+
+
+

Search

+
+ +

Please activate JavaScript to enable the search functionality.

+
+

+ From here you can search these documents. Enter your search words into the + box below and click "search". Note that the search function will + automatically search for all of the words. Pages containing fewer words + won't appear in the result list. +

+
+ + + +
+ +
+
+
+
+
+
+
+
+
+ + + + diff --git a/base_geoengine/doc/build/searchindex.js b/base_geoengine/doc/build/searchindex.js new file mode 100644 index 000000000..1fd753e72 --- /dev/null +++ b/base_geoengine/doc/build/searchindex.js @@ -0,0 +1,357 @@ +Search.setIndex({ + objects: { + "base_geoengine.geo_operators": { + geo_search: [3, 2, 1, ""], + GeoOperator: [3, 3, 1, ""], + }, + "base_geoengine.geo_field": {Geom: [3, 3, 1, ""]}, + base_geoengine: { + geo_multiline: [3, 0, 1, ""], + geo_polygon: [3, 0, 1, ""], + geo_multipolygon: [3, 0, 1, ""], + geo_operators: [3, 0, 1, ""], + geo_line: [3, 0, 1, ""], + geo_field: [3, 0, 1, ""], + geo_point: [3, 0, 1, ""], + geo_view: [3, 0, 1, ""], + }, + "base_geoengine.geo_view": { + ir_view: [3, 0, 1, ""], + geo_vector_layer: [3, 0, 1, ""], + geo_raster_layer: [3, 0, 1, ""], + }, + "base_geoengine.geo_multiline": {GeoMultiLine: [3, 3, 1, ""]}, + "base_geoengine.geo_model.GeoModel": { + geo_search: [3, 1, 1, ""], + fields_view_get: [3, 1, 1, ""], + fields_get: [3, 1, 1, ""], + }, + "base_geoengine.geo_helper": {geo_convertion_helper: [3, 0, 1, ""]}, + "base_geoengine.geo_helper.geo_convertion_helper": { + value_to_shape: [3, 2, 1, ""], + }, + "base_geoengine.geo_multipolygon": {GeoMultiPolygon: [3, 3, 1, ""]}, + "base_geoengine.geo_line": {GeoLine: [3, 3, 1, ""]}, + "base_geoengine.geo_field.Geom": { + create_geo_column: [3, 1, 1, ""], + set: [3, 1, 1, ""], + set_geo: [3, 1, 1, ""], + update_geo_column: [3, 1, 1, ""], + entry_to_shape: [3, 1, 1, ""], + manage_db_column: [3, 1, 1, ""], + load_geo: [3, 1, 1, ""], + }, + "base_geoengine.geo_polygon": {GeoPolygon: [3, 3, 1, ""]}, + "base_geoengine.geo_model": {GeoModel: [3, 3, 1, ""]}, + "base_geoengine.geo_operators.GeoOperator": { + get_geo_greater_sql: [3, 1, 1, ""], + get_rel_field: [3, 1, 1, ""], + get_geo_within_sql: [3, 1, 1, ""], + get_geo_intersect_sql: [3, 1, 1, ""], + get_geo_equal_sql: [3, 1, 1, ""], + get_geo_lesser_sql: [3, 1, 1, ""], + get_geo_touch_sql: [3, 1, 1, ""], + }, + "base_geoengine.geo_point": {GeoPoint: [3, 3, 1, ""]}, + }, + terms: { + oper: [3, 0], + create_geo_column: 3, + code: [], + forget: [2, 5], + just: [], + show: 4, + api: [3, 0], + queri: 4, + geo_touch: 3, + my_funct: [], + shape: [3, 5], + myshaply_obj: 3, + archflag: 5, + entry_to_shap: 3, + follow: 5, + geocolumn: [3, 0], + yet: 3, + postggi: 4, + geooper: 3, + postgis_sql: 1, + field: 3, + brows: 3, + configur: 4, + should: 2, + add: [3, 4, 2], + busi: 4, + under: [1, 2], + input: 3, + folder: [1, 2], + create_postgis_templ: 2, + template_postgi: 2, + string: 3, + python: [0, 5], + nix: 2, + databs: [], + col_nam: 3, + none: 3, + get_geo_equal_sql: 3, + datasourc: 4, + utf: 2, + geometry_column: 1, + geo: [3, 0], + geo_equ: 3, + geo_direct_writ: 3, + wont: [], + dim: 3, + document: 0, + name: 3, + success: 2, + sucess: [], + list: 2, + geograph: 3, + geomodel: 3, + get_geo_within_sql: 3, + view_typ: 3, + vector: 3, + geo_within: 3, + have: [1, 2], + geomerti: 3, + complet: 4, + geo_model: 3, + page: 0, + view: [3, 0], + pleas: [2, 5], + x86_64: 5, + domain: 3, + set: 3, + geo_domain: 3, + abil: [], + gist_index: 3, + geomultipolygon: 3, + direct: [3, 5], + geo_search: 3, + pass: 3, + geoengin: [0, 1, 2, 4], + indirect: 3, + server: 2, + geo_less: 3, + compat: 3, + index: 0, + what: [0, 4], + toto: 3, + helper: [3, 0], + charg: 3, + databas: [3, 0, 1, 2, 4], + section: 2, + definit: 3, + content: 0, + geo_point: 3, + i386: 5, + stuff: [], + geom: 3, + poli: 3, + rel: 3, + allfield: 3, + print: [], + new: 3, + geo_typ: 3, + res_id: 3, + refer: [2, 5], + after: 3, + run: 1, + extend: 4, + view_id: 3, + same_typ: 3, + extens: 4, + pip: 5, + base: 2, + geo_great: 3, + prerequisit: [0, 5], + offset: 3, + postgi: [0, 1, 2, 3, 4, 5], + path: 2, + super: 1, + valu: 3, + load_geo: 3, + raster: 3, + search: [3, 0], + spatial_ref_si: 1, + postgresql: [1, 2], + allreadi: [], + launch: 2, + column: [3, 4], + geopoint: 3, + technolog: 4, + mac: 5, + manag: [3, 0], + orm: [3, 0, 4], + context: 3, + act: 4, + geometri: 3, + the_point: 3, + col: 3, + mywkt: 3, + load: 3, + serach: [], + fields_view_get: 3, + simpli: 2, + get_geo_greater_sql: 3, + modul: [3, 0, 1, 2, 4], + contect: [], + transform: 3, + srid: 3, + geo_polygon: 3, + done: [3, 2], + owner: 2, + openlay: 4, + fields_get: 3, + your: [4, 2, 5], + select: 1, + geo_multipolygon: 3, + from: [1, 2], + log: 1, + zip: 3, + script: 2, + openerp: [0, 2, 4], + data: [3, 4], + support: 3, + update_geo_column: 3, + geo_lin: 3, + system: [2, 5], + geo_field: 3, + avail: [3, 1, 2], + reli: 4, + window: 2, + toolbar: 3, + lot: 3, + base_geoengin: [3, 1, 2], + instal: [0, 1, 2, 5], + store: 4, + fals: 3, + function: 3, + head: [], + wkb: 3, + db_templat: 2, + statement: 3, + geolin: 3, + capabilit: 4, + en_u: 2, + enabl: 3, + about: 3, + you: [3, 4, 1, 2], + visual: 4, + indic: 0, + alreadi: 2, + obj: 3, + value_to_shap: 3, + true: 3, + addon: 2, + psql: [1, 2], + geo_multilin: 3, + word: 4, + look: [], + raw: 3, + provid: 4, + type: 3, + work: [], + cursor: 3, + record: 3, + limit: 3, + can: 3, + rel_model: 3, + rel_col: 3, + def: [], + layer: [3, 4], + uid: 3, + creat: [3, 2], + geo_intersec: 3, + retriev: 3, + arg: 3, + argument: 2, + templat: [0, 2], + repres: [3, 4], + geobi: 4, + exist: 1, + file: 2, + tabl: [3, 0], + get_geo_lesser_sql: 3, + return: 3, + postgisifi: [0, 1, 2], + get_geo_touch_sql: 3, + packag: 5, + geopolygon: 3, + form: [3, 2], + want: [1, 2], + inform: [3, 4], + perform: [3, 4], + titl: [], + ilik: 3, + geojson: [3, 5], + wkt: 3, + write: 3, + also: [3, 4], + other: [4, 2], + read: 3, + spatial: [3, 4], + test: [3, 1, 2], + geo_help: 3, + eventu: 2, + config: 2, + geo_intersect: 3, + updat: [3, 2], + get_geo_intersect_sql: 3, + map: [3, 4], + express: 3, + thi: [3, 2], + set_geo: 3, + object: 3, + sucessful: 1, + superus: [1, 2], + manage_db_column: 3, + diretli: 3, + succ: [], + geo_column: 3, + user: [3, 1, 5], + exisit: [0, 1, 2], + sql: [3, 1], + mygeojson: 3, + arch: 5, + class: 3, + pool: 3, + welcom: 0, + submenu: 3, + utf8: 2, + get_rel_field: 3, + geomultilin: 3, + doe: 3, + geo_convertion_help: 3, + receiv: [], + client: 2, + command: 1, + allow: [3, 4], + geo_oper: 3, + model: [3, 0, 4], + order: [3, 1, 2], + }, + objtypes: {0: "py:module", 1: "py:method", 2: "py:function", 3: "py:class"}, + titles: [ + "Welcome to OpenERP GeoEngine’s documentation!", + "Postgisify an exisiting database", + "Installation", + "API", + "What is GeoEngine ?", + "Prerequisites", + ], + objnames: { + 0: ["py", "module", "Python module"], + 1: ["py", "method", "Python method"], + 2: ["py", "function", "Python function"], + 3: ["py", "class", "Python class"], + }, + filenames: [ + "index", + "postgisify", + "installation", + "api_doc", + "what_is_geoengine", + "prerequisite", + ], +}); diff --git a/base_geoengine/doc/build/what_is_geoengine.html b/base_geoengine/doc/build/what_is_geoengine.html new file mode 100644 index 000000000..580002120 --- /dev/null +++ b/base_geoengine/doc/build/what_is_geoengine.html @@ -0,0 +1,169 @@ + + + + + + + What is GeoEngine ? — OpenERP GeoEngine 0.3 documentation + + + + + + + + + + + + + + + +
+
+
+
+
+

+ What is GeoEngine ? +

+

+ GeoEngine is an OpenERP module that adds spatial/GIS capabilites to + OpenERP. It will allow you to : +

+
    +
  • Visualize and query your business information on map
  • +
  • Perform GeoBI and spatial query
  • +
  • Configure your spatial layers and spatial datasources
  • +
  • Extend OpenERP models with spatial columns
  • +
+

+ GeoEngine relies on + OpenLayers + and + PostgGIS + technologies. +

+

+ Postgis is used to store spatial information in databases. OpenLayer is + used to represent spatial data in other words to show maps. The + GeoEngine module acts as a data provider and as an OpenLayers + configurator. It also provides a complete extension to OpenERP ORM. +

+ _images/core_architecture.jpg +
+
+
+
+
+
+

Previous topic

+

+ Welcome to OpenERP GeoEngine’s documentation! +

+

Next topic

+

+ Prerequisites +

+

This Page

+ + + +
+
+
+
+ + + + diff --git a/base_geoengine/doc/make.bat b/base_geoengine/doc/make.bat new file mode 100644 index 000000000..ee7469def --- /dev/null +++ b/base_geoengine/doc/make.bat @@ -0,0 +1,170 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenERPGeoEngine.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenERPGeoEngine.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/base_geoengine/doc/source/_static/_images/core_architecture.jpg b/base_geoengine/doc/source/_static/_images/core_architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..326593defeb882307dbbc49532f17c86a7e24b42 GIT binary patch literal 114343 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

rfkFL#zrjKrvHG-qg}uIeDg> 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

+i;2U@GGDq_zL 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 aM+p$ZfB$N?`X5Vnj>P}}v;+G-^uGWw%%I!= literal 0 HcmV?d00001 diff --git a/base_geoengine/doc/source/api_doc.rst b/base_geoengine/doc/source/api_doc.rst new file mode 100644 index 000000000..56c5af9a2 --- /dev/null +++ b/base_geoengine/doc/source/api_doc.rst @@ -0,0 +1,63 @@ +====== +API +====== + +*********** +GeoColumns +*********** +.. automodule:: base_geoengine.geo_field + :members: + +.. automodule:: base_geoengine.geo_point + :members: + +.. automodule:: base_geoengine.geo_line + :members: + +.. automodule:: base_geoengine.geo_multiline + :members: + +.. automodule:: base_geoengine.geo_polygon + :members: + +.. automodule:: base_geoengine.geo_multipolygon + :members: + +**************** +View Management +**************** + +.. automodule:: base_geoengine.geo_view + :members: + +.. automodule:: base_geoengine.geo_view.geo_raster_layer + :members: + +.. automodule:: base_geoengine.geo_view.geo_vector_layer + :members: + +.. automodule:: base_geoengine.geo_view.ir_view + :members: + +************** +GEO ORM MODEL +************** +.. autoclass:: base_geoengine.geo_model.GeoModel + :members: + +****************** +GEO ORM OPERATORS +****************** + +.. automodule:: base_geoengine.geo_operators + :members: + +.. autoclass:: base_geoengine.geo_operators.GeoOperator + :members: + +*********** +GEO helper +*********** + +.. automodule:: base_geoengine.geo_helper.geo_convertion_helper + :members: diff --git a/base_geoengine/doc/source/conf.py b/base_geoengine/doc/source/conf.py new file mode 100644 index 000000000..e3dff0aec --- /dev/null +++ b/base_geoengine/doc/source/conf.py @@ -0,0 +1,245 @@ +# flake8: noqa +# +# OpenERP GeoEngine documentation build configuration file, created by +# sphinx-quickstart on Mon Mar 5 09:15:25 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import os +import sys + +import sphinx_bootstrap_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + + +odoo_root = "/home/travis/odoo-" + os.environ["VERSION"] +sphinxodoo_root_path = os.path.abspath(odoo_root) +sphinxodoo_addons_path = [ + os.path.abspath(os.path.join(odoo_root, "openerp", "addons")), + os.path.abspath(os.path.join(odoo_root, "addons")), + os.path.abspath(os.environ["TRAVIS_BUILD_DIR"]), +] +geo_path = os.environ["TRAVIS_BUILD_DIR"] +addons = [ + x + for x in os.listdir(geo_path) + if not x.startswith(".") and os.path.isdir(os.path.join(geo_path, x)) +] +sphinxodoo_addons = addons +sys.path.append(os.environ["TRAVIS_BUILD_DIR"]) +# -- General configuration ---------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ["sphinx.ext.autodoc", "sphinxodoo.ext.autodoc"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix of source filenames. +source_suffix = ".rst" + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "Odoo Geospatial" +copyright = "2015, Nicolas Bessi, Odoo Community Association (OCA)" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = "0.3" +# The full version, including alpha/beta/rc tags. +release = "0.3" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "bootstrap" +html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = "OpenERPGeoEnginedoc" + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +# latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +# latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ( + "index", + "OpenERPGeoEngine.tex", + "Odoo Geospatial Documentation", + "Odoo Community Association (OCA), Nicolas Bessi", + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +# latex_preamble = '' + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + "index", + "openerpgeoengine", + "Odoo Geospatial Documentation", + ["Odoo Community Association (OCA), Nicolas Bessi"], + 1, + ) +] diff --git a/base_geoengine/doc/source/index.rst b/base_geoengine/doc/source/index.rst new file mode 100644 index 000000000..44f6d7ac0 --- /dev/null +++ b/base_geoengine/doc/source/index.rst @@ -0,0 +1,31 @@ +.. OpenERP GeoEngine documentation master file, created by + sphinx-quickstart on Mon Mar 5 09:15:25 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Odoo Geospatial's documentation +========================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + what_is_geoengine + prerequisite + installation + postgisify + api_doc + + How to use GeoEngine + Modules presentations + API presentation + Manage your layer from client + Create a geocolumn from client + + +Indices and tables +================== +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/base_geoengine/doc/source/installation.rst b/base_geoengine/doc/source/installation.rst new file mode 100644 index 000000000..1beaa90b2 --- /dev/null +++ b/base_geoengine/doc/source/installation.rst @@ -0,0 +1,12 @@ +================= +Installation +================= + +Once prerequisites are installed you still have to apply fixes pending to be merge in +Odoo Core before being able to use it: :: + + git pull origin pull/5620/head + git cherry-pick 676e4b8d + +This fix is already merged in the OCB (Odoo Community Backports) branch. +If you are using it there is no need to install the fix yourself. diff --git a/base_geoengine/doc/source/postgisify.rst b/base_geoengine/doc/source/postgisify.rst new file mode 100644 index 000000000..8aaf6ec63 --- /dev/null +++ b/base_geoengine/doc/source/postgisify.rst @@ -0,0 +1,16 @@ +********************************* +Postgisify an exisiting database +********************************* + +If you want to install the GeoEngine on an existing database you have two options. + +If you are using a PostgreSQL super user it should work out of the box. +If you are using a standard user you have to connect to your database and run: :: + + CREATE EXTENSION postgis + CREATE EXTENSION postgis_topology + +In order to test if the installation is sucessfull log into you database and:: + + SELECT * from GEOMETRY_COLUMNS; + SELECT * from spatial_ref_sys; diff --git a/base_geoengine/doc/source/prerequisite.rst b/base_geoengine/doc/source/prerequisite.rst new file mode 100644 index 000000000..416707f17 --- /dev/null +++ b/base_geoengine/doc/source/prerequisite.rst @@ -0,0 +1,30 @@ +================= +Prerequisites +================= +*************** +Python +*************** +geojson: + +:: + + pip install geojson + +Shapely: + +:: + + pip install Shapely==1.2.13 + +For Mac user: do not forget the following directive: + +:: + + ARCHFLAGS="-arch i386 -arch x86_64" + + +*************** +PostGIS 2.0 +*************** + +Please refer to `PostGIS installation directive `_ or to your OS package system. diff --git a/base_geoengine/doc/source/what_is_geoengine.rst b/base_geoengine/doc/source/what_is_geoengine.rst new file mode 100644 index 000000000..cb64b8cbc --- /dev/null +++ b/base_geoengine/doc/source/what_is_geoengine.rst @@ -0,0 +1,16 @@ +=================== +What is GeoEngine ? +=================== + +GeoEngine is an OpenERP module that adds spatial/GIS capabilites to OpenERP. It will allow you to : + +* Visualize and query your business information on map +* Perform GeoBI and spatial query +* Configure your spatial layers and spatial datasources +* Extend OpenERP models with spatial columns + +GeoEngine relies on `OpenLayers `_ and `PostgGIS `_ technologies. + +Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps. The GeoEngine module acts as a data provider and as an OpenLayers configurator. It also provides a complete extension to OpenERP ORM. + +.. image:: _static/_images/core_architecture.jpg diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py new file mode 100644 index 000000000..cd90f105c --- /dev/null +++ b/base_geoengine/fields.py @@ -0,0 +1,278 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging +from operator import attrgetter + +from odoo import _, fields +from odoo.tools import sql + +from .geo_db import create_geo_column +from .geo_helper import geo_convertion_helper as convert + +logger = logging.getLogger(__name__) +try: + import geojson + from shapely.geometry import Point + from shapely.geometry.base import BaseGeometry + from shapely.wkb import loads as wkbloads +except ImportError: + logger.warning("Shapely or geojson are not available in the sys path") + + +class GeoField(fields.Field): + """The field descriptor contains the field definition common to all + specialized fields for geolocalization. Subclasses must define a type + and a geo_type. The type is the name of the corresponding column type, + the geo_type is the name of the corresponding type in the GIS system. + """ + + geo_type = None + + @property + def column_format(self): + return "ST_GeomFromText(%s, {})".format(self.srid) + + @property + def column_type(self): + return ("geometry", "geometry") + + _slots = {"dim": 2, "srid": 3857, "gist_index": True} + + def convert_to_column(self, value, record, values=None): + """Convert value to database format + + value can be geojson, wkt, shapely geometry object. + If geo_direct_write in context you can pass diretly WKT""" + if not value: + return None + shape_to_write = self.entry_to_shape(value, same_type=True) + if shape_to_write.is_empty: + return None + else: + return shape_to_write.wkt + + def convert_to_cache(self, value, record, validate=True): + val = value + if isinstance(value, BaseGeometry): + val = value.wkb_hex + return val + + def convert_to_record(self, value, record): + """Value may be: + - a GeoJSON string when field onchange is triggered + - a geometry object hexcode from cache + - a unicode containing dict + """ + if not value: + return False + return convert.value_to_shape(value, use_wkb=True) + + def convert_to_read(self, value, record, use_name_get=True): + if not isinstance(value, BaseGeometry): + # read hexadecimal value from database + shape = self.load_geo(value) + else: + shape = value + if not shape or shape.is_empty: + return False + return geojson.dumps(shape) + + # + # Field description + # + + # properties used by get_description() + _description_dim = property(attrgetter("dim")) + _description_srid = property(attrgetter("srid")) + _description_gist_index = property(attrgetter("gist_index")) + + @classmethod + def load_geo(cls, wkb): + """Load geometry into browse record after read was done""" + return wkbloads(wkb, hex=True) if wkb else False + + def entry_to_shape(self, value, same_type=False): + """Transform input into an object""" + shape = convert.value_to_shape(value) + if same_type and not shape.is_empty: + if shape.geom_type.lower() != self.geo_type.lower(): + msg = _("Geo Value %s must be of the same type %s as fields") + raise TypeError(msg % (shape.geom_type.lower(), self.geo_type.lower())) + return shape + + def update_geo_db_column(self, model): + """Update the column type in the database.""" + cr = model._cr + query = """SELECT srid, type, coord_dimension + FROM geometry_columns + WHERE f_table_name = %s + AND f_geometry_column = %s""" + cr.execute(query, (model._table, self.name)) + check_data = cr.fetchone() + if not check_data: + raise TypeError( + "geometry_columns table seems to be corrupted." + " SRID check is not possible" + ) + if check_data[0] != self.srid: + raise TypeError( + "Reprojection of column is not implemented." + " We can not change srid %s to %s" % (self.srid, check_data[0]) + ) + elif check_data[1] != self.geo_type: + raise TypeError( + "Geo type modification is not implemented." + " We can not change type %s to %s" % (check_data[1], self.geo_type) + ) + elif check_data[2] != self.dim: + raise TypeError( + "Geo dimention modification is not implemented." + " We can not change dimention %s to %s" % (check_data[2], self.dim) + ) + if self.gist_index: + cr.execute( + "SELECT indexname FROM pg_indexes WHERE indexname = %s", + (self._postgis_index_name(model._table, self.name),), + ) + index = cr.fetchone() + if index: + return True + self._create_index(cr, model._table, self.name) + return True + + def update_db_column(self, model, column): + """Create/update the column corresponding to ``self``. + + For creation of geo column + + :param model: an instance of the field's model + :param column: the column's configuration (dict) + if it exists, or ``None`` + """ + # the column does not exist, create it + + if not column: + create_geo_column( + model._cr, + model._table, + self.name, + self.geo_type, + self.srid, + self.dim, + self.string, + ) + return + + if column["udt_name"] == self.column_type[0]: + return + + self.update_geo_db_column(model) + + if column["udt_name"] in self.column_cast_from: + sql.convert_column(model._cr, model._table, self.name, self.column_type[1]) + else: + newname = (self.name + "_moved{}").format + i = 0 + while sql.column_exists(model._cr, model._table, newname(i)): + i += 1 + if column["is_nullable"] == "NO": + sql.drop_not_null(model._cr, model._table, self.name) + sql.rename_column(model._cr, model._table, self.name, newname(i)) + sql.create_column( + model._cr, model._table, self.name, self.column_type[1], self.string + ) + + +class GeoLine(GeoField): + """Field for POSTGIS geometry Line type""" + + type = "geo_line" + geo_type = "LINESTRING" + + @classmethod + def from_points(cls, cr, point1, point2, srid=None): + """ + Converts given points in parameter to a line. + :param cr: DB cursor + :param point1: Point (BaseGeometry) + :param point2: Point (BaseGeometry) + :param srid: SRID + :return: LINESTRING Object + """ + sql = """ + SELECT + ST_MakeLine( + ST_GeomFromText(%(wkt1)s, %(srid)s), + ST_GeomFromText(%(wkt2)s, %(srid)s) + ) + """ + cr.execute( + sql, + { + "wkt1": point1.wkt, + "wkt2": point2.wkt, + "srid": srid or cls._slots["srid"], + }, + ) + res = cr.fetchone() + return cls.load_geo(res[0]) + + +class GeoPoint(GeoField): + """Field for POSTGIS geometry Point type""" + + type = "geo_point" + geo_type = "POINT" + + @classmethod + def from_latlon(cls, cr, latitude, longitude): + """Convert a (latitude, longitude) into an UTM coordinate Point:""" + pt = Point(longitude, latitude) + cr.execute( + """ + SELECT + ST_Transform( + ST_GeomFromText(%(wkt)s, 4326), + %(srid)s) + """, + {"wkt": pt.wkt, "srid": cls._slots["srid"]}, + ) + res = cr.fetchone() + return cls.load_geo(res[0]) + + +class GeoPolygon(GeoField): + """Field for POSTGIS geometry Polygon type""" + + type = "geo_polygon" + geo_type = "POLYGON" + + +class GeoMultiLine(GeoField): + """Field for POSTGIS geometry MultiLine type""" + + type = "geo_multi_line" + geo_type = "MULTILINESTRING" + + +class GeoMultiPoint(GeoField): + """Field for POSTGIS geometry MultiPoint type""" + + type = "geo_multi_point" + geo_type = "MULTIPOINT" + + +class GeoMultiPolygon(GeoField): + """Field for POSTGIS geometry MultiPolygon type""" + + type = "geo_multi_polygon" + geo_type = "MULTIPOLYGON" + + +fields.GeoLine = GeoLine +fields.GeoPoint = GeoPoint +fields.GeoPolygon = GeoPolygon +fields.GeoMultiLine = GeoMultiLine +fields.GeoMultiPoint = GeoMultiPoint +fields.GeoMultiPolygon = GeoMultiPolygon diff --git a/base_geoengine/geo_db.py b/base_geoengine/geo_db.py new file mode 100644 index 000000000..7a36c1ef2 --- /dev/null +++ b/base_geoengine/geo_db.py @@ -0,0 +1,92 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +"""Helper to setup Postgis""" +import logging + +from odoo import _ +from odoo.exceptions import MissingError +from odoo.tools import sql + +logger = logging.getLogger("geoengine.sql") +_schema = logging.getLogger("odoo.schema") + + +def init_postgis(cr): + """Initialize postgis + Add PostGIS support to the database. PostGIS is a spatial database + extender for PostgreSQL object-relational database. It adds support for + geographic objects allowing location queries to be run in SQL. + """ + cr.execute( + """ + SELECT + tablename + FROM + pg_tables + WHERE + tablename='spatial_ref_sys'; + """ + ) + check = cr.fetchone() + if check: + return {} + try: + cr.execute( + """ + CREATE EXTENSION postgis; + CREATE EXTENSION postgis_topology; + """ + ) + except Exception: + raise MissingError( + _( + "Error, can not automatically initialize spatial postgis" + " support. Database user may have to be superuser and" + " postgres/postgis extensions with their devel header have" + " to be installed. If you do not want Odoo to connect with a" + " super user you can manually prepare your database. To do" + " this, open a client to your database using a super user and" + " run:\n" + "CREATE EXTENSION postgis;\n" + "CREATE EXTENSION postgis_topology;\n" + ) + ) + + +def create_geo_column(cr, tablename, columnname, geotype, srid, dim, comment=None): + """Create a geometry column with the given type. + + :params: srid: geometry's projection srid + :params: dim: geometry's dimension (2D or 3D) + """ + cr.execute( + "SELECT AddGeometryColumn( %s, %s, %s, %s, %s)", + (tablename, columnname, srid, geotype, dim), + ) + if comment: + # pylint: disable=E8103 + cr.execute( + 'COMMENT ON COLUMN "{}"."{}" IS %s'.format(tablename, columnname), + (comment,), + ) + _schema.debug( + "Table %r: added geometry column %r of type %s", tablename, columnname, geotype + ) + + +def _postgis_index_name(table, col_name): + return "{}_{}_gist_index".format(table, col_name) + + +def create_geo_index(cr, columnname, tablename): + """Create the given index unless it exists.""" + indexname = _postgis_index_name(tablename, columnname) + if sql.index_exists(cr, indexname): + return + # pylint: disable=E8103 + cr.execute( + "CREATE INDEX {} ON {} USING GIST ( {} )".format( + indexname, tablename, columnname + ) + ) + _schema.debug("Table %r: created index %r", tablename, indexname) diff --git a/base_geoengine/geo_helper/__init__.py b/base_geoengine/geo_helper/__init__.py new file mode 100644 index 000000000..8f6167161 --- /dev/null +++ b/base_geoengine/geo_helper/__init__.py @@ -0,0 +1 @@ +from . import geo_convertion_helper diff --git a/base_geoengine/geo_helper/geo_convertion_helper.py b/base_geoengine/geo_helper/geo_convertion_helper.py new file mode 100644 index 000000000..2855c7414 --- /dev/null +++ b/base_geoengine/geo_helper/geo_convertion_helper.py @@ -0,0 +1,38 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +try: + import geojson + from shapely import wkb, wkt + from shapely.geometry import shape + from shapely.geometry.base import BaseGeometry +except ImportError: + logger = logging.getLogger(__name__) + logger.warning("Shapely or geojson are not available in the sys path") + + +def value_to_shape(value, use_wkb=False): + """Transforms input into a Shapely object""" + if not value: + return wkt.loads("GEOMETRYCOLLECTION EMPTY") + if isinstance(value, str): + # We try to do this before parsing json exception + # exception are ressource costly + if "{" in value: + geo_dict = geojson.loads(value) + return shape(geo_dict) + elif use_wkb: + return wkb.loads(value, hex=True) + else: + return wkt.loads(value) + elif hasattr(value, "wkt"): + if isinstance(value, BaseGeometry): + return value + else: + return wkt.loads(value.wkt) + else: + raise TypeError( + "Write/create/search geo type must be wkt/geojson " + "string or must respond to wkt" + ) diff --git a/base_geoengine/geo_ir/__init__.py b/base_geoengine/geo_ir/__init__.py new file mode 100644 index 000000000..413bb2380 --- /dev/null +++ b/base_geoengine/geo_ir/__init__.py @@ -0,0 +1 @@ +from . import ir_model diff --git a/base_geoengine/geo_ir/ir_model.py b/base_geoengine/geo_ir/ir_model.py new file mode 100644 index 000000000..46837e9ff --- /dev/null +++ b/base_geoengine/geo_ir/ir_model.py @@ -0,0 +1,51 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2023 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + +from odoo.addons import base + +if "geoengine" not in base.models.ir_actions.VIEW_TYPES: + base.models.ir_actions.VIEW_TYPES.append(("geoengine", "Geoengine")) + +GEO_TYPES = [ + ("geo_polygon", "geo_polygon"), + ("geo_multi_polygon", "geo_multi_polygon"), + ("geo_point", "geo_point"), + ("geo_multi_point", "geo_multi_point"), + ("geo_line", "geo_line"), + ("geo_multi_line", "geo_multi_line"), +] + +GEO_TYPES_ONDELETE = { + "geo_polygon": "cascade", + "geo_multi_polygon": "cascade", + "geo_point": "cascade", + "geo_multi_point": "cascade", + "geo_line": "cascade", + "geo_multi_line": "cascade", +} + +POSTGIS_GEO_TYPES = [ + ("POINT", "POINT"), + ("MULTIPOINT", "MULTIPOINT"), + ("LINESTRING", "LINESTRING"), + ("MULTILINESTRING", "MULTILINESTRING"), + ("POLYGON", "POLYGON"), + ("MULTIPOLYGON", "MULTIPOLYGON"), +] + + +class IrModelField(models.Model): + _inherit = "ir.model.fields" + + srid = fields.Integer("srid", required=False) + geo_type = fields.Selection(POSTGIS_GEO_TYPES, string="PostGIs type") + dim = fields.Selection( + [("2", "2"), ("3", "3"), ("4", "4")], string="PostGIs Dimension", default="2" + ) + gist_index = fields.Boolean("Create gist index") + ttype = fields.Selection( + selection_add=GEO_TYPES, + ondelete=GEO_TYPES_ONDELETE, + ) diff --git a/base_geoengine/geo_ir/ir_model_view.xml b/base_geoengine/geo_ir/ir_model_view.xml new file mode 100644 index 000000000..d9c3ca423 --- /dev/null +++ b/base_geoengine/geo_ir/ir_model_view.xml @@ -0,0 +1,34 @@ + + + + + + ir.model.fields.form.geo + ir.model.fields + + + + + + + + + + + + + + + diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py new file mode 100644 index 000000000..7405b6aa8 --- /dev/null +++ b/base_geoengine/geo_model.py @@ -0,0 +1,175 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import _, api, models +from odoo.exceptions import MissingError, UserError + +from . import fields as geo_fields, geo_operators + +DEFAULT_EXTENT = ( + "-123164.85222423, 5574694.9538936, " "1578017.6490538, 6186191.1800898" +) + + +class GeoModel(models.AbstractModel): + """Extend Base class for to allow definition of geo fields.""" + + _inherit = "base" + + # Array of ash that define layer and data to use + _georepr = [] + + @api.model + def fields_get(self, allfields=None, attributes=None): + """Add geo_type definition for geo fields""" + res = super().fields_get(allfields=allfields, attributes=attributes) + for f_name in res: + field = self._fields.get(f_name) + if field and field.type.startswith("geo_"): + geo_type = { + "type": field.type, + "dim": int(field.dim), + "srid": field.srid, + } + if field.compute or field.related: + if not field.dim: + geo_type["dim"] = 2 + if not field.srid: + geo_type["srid"] = 3857 + res[f_name]["geo_type"] = geo_type + return res + + @api.model + def _get_geo_view(self): + IrView = self.env["ir.ui.view"] + geo_view = IrView.sudo().search( + [("model", "=", self._name), ("type", "=", "geoengine")], + limit=1, + ) + if not geo_view: + raise UserError( + _("No GeoEngine view defined for the model %s") % self._name, + _("Please create a view or modify view mode"), + ) + return geo_view + + @api.model + def fields_view_get( + self, view_id=None, view_type="form", toolbar=False, submenu=False + ): + """Returns information about the available fields of the class. + If view type == 'map' returns geographical columns available""" + view_obj = self.env["ir.ui.view"] + field_obj = self.env["ir.model.fields"] + + def set_field_real_name(in_tuple): + if not in_tuple: + return in_tuple + name = field_obj.browse(in_tuple[0]).name + out = (in_tuple[0], name, in_tuple[1]) + return out + + if view_type == "geoengine": + if not view_id: + view = self._get_geo_view() + else: + view = view_obj.browse(view_id) + res = super().fields_view_get( + view_id=view.id, view_type="form", toolbar=toolbar, submenu=submenu + ) + res["geoengine_layers"] = { + "backgrounds": [], + "actives": [], + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + for layer in view.raster_layer_ids: + layer_dict = layer.read()[0] + res["geoengine_layers"]["backgrounds"].append(layer_dict) + for layer in view.vector_layer_ids: + layer_dict = layer.read()[0] + # get category groups for this vector layer + if layer.geo_repr == "basic" and layer.symbol_ids: + layer_dict["symbols"] = layer.symbol_ids.read( + ["img", "fieldname", "value"] + ) + layer_dict["attribute_field_id"] = set_field_real_name( + layer_dict.get("attribute_field_id", False) + ) + layer_dict["geo_field_id"] = set_field_real_name( + layer_dict.get("geo_field_id", False) + ) + res["geoengine_layers"]["actives"].append(layer_dict) + # adding geo column desc + geo_f_name = layer_dict["geo_field_id"][1] + res["fields"].update(self.fields_get([geo_f_name])) + else: + return super().fields_view_get( + view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu + ) + return res + + @api.model + def get_edit_info_for_geo_column(self, column): + raster_obj = self.env["geoengine.raster.layer"] + + field = self._fields.get(column) + if not field or not isinstance(field, geo_fields.GeoField): + raise ValueError( + _("%s column does not exists or is not a geo field") % column + ) + view = self._get_geo_view() + raster = raster_obj.search( + [("view_id", "=", view.id), ("use_to_edit", "=", True)], limit=1 + ) + if not raster: + raster = raster_obj.search([("view_id", "=", view.id)], limit=1) + if not raster: + raise MissingError(_("No raster layer for view %s") % (view.name,)) + return { + "edit_raster": raster.read()[0], + "geo_type": field.geo_type, + "srid": field.srid, + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + + @api.model + def geo_search( + self, domain=None, geo_domain=None, offset=0, limit=None, order=None + ): + """Perform a geo search it allows direct domain: + geo_search( + domain=[('name', 'ilike', 'toto']), + geo_domain=[('the_point', 'geo_intersect', + myshaply_obj or mywkt or mygeojson)]) + + We can also support indirect geo_domain ( + ‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + + The supported operators are : + * geo_greater + * geo_lesser + * geo_equal + * geo_touch + * geo_within + * geo_contains + * geo_intersect""" + # First we do a standard search in order to apply security rules + # and do a search on standard attributes + # Limit and offset are managed after, we may loose a lot of performance + # here + domain = domain or [] + geo_domain = geo_domain or [] + return geo_operators.geo_search( + self, + domain=domain, + geo_domain=geo_domain, + offset=offset, + limit=limit, + order=order, + ) diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py new file mode 100644 index 000000000..cf950a026 --- /dev/null +++ b/base_geoengine/geo_operators.py @@ -0,0 +1,240 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from .fields import GeoField + +UNION_MAPPING = {"|": "OR", "&": "AND"} + +logger = logging.getLogger("geoengine.sql.debug") + +# TODO Refactor geo_search and dry up the get_**_sql code + + +def _get_geo_func(model, domain): + """Map operator to function we do not want to override __getattr__""" + current_field = model._fields[domain[0]] + if isinstance(current_field, GeoField): + current_operator = GeoOperator(current_field) + attr = "get_{}_sql".format(domain[1]) + if hasattr(current_operator, attr): + return getattr(current_operator, attr) + raise ValueError("Field {} does not support {}".format(current_field, domain[1])) + + +def geo_search(model, domain=None, geo_domain=None, offset=0, limit=None, order=None): + """Perform a geo search it allows direct domain: + geo_search( + domain=[('name', 'ilike', 'toto']), + geo_domain=[('the_point', + 'geo_intersect', + myshaply_obj or mywkt or mygeojson)]) + + We can also support indirect geo_domain + (‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + + The supported operators are : + * geo_greater + * geo_lesser + * geo_equal + * geo_touch + * geo_within + * geo_contains + * geo_intersect + """ + cr = model._cr + domain = domain or [] + geo_domain = geo_domain or [] + model.env["ir.model.access"].check(model._name, "read") + query = model._where_calc(domain, active_test=True) + model._apply_ir_rules(query, "read") + order_by = "" + if order: + order_by = model._generate_order_by(order, query) or "" + from_clause, where_clause, where_clause_params = query.get_sql() + limit_str = limit and " LIMIT %d" % limit or "" + offset_str = offset and " OFFSET %d" % offset or "" + where_clause_arr = [] + if where_clause and where_clause_params: + where_clause_arr.append(where_clause) + # geosearch where clause generation + MODE = "" + UNION = "AND" + JOIN_MODE = "%s %s" + for domain in geo_domain: + if isinstance(domain, str): + if domain == "!": + MODE = "NOT" + if domain in list(UNION_MAPPING.keys()): + UNION = UNION_MAPPING[domain] + if where_clause_arr: + where_clause_arr.append(JOIN_MODE % (MODE, UNION)) + # We start computing geo spation SQL + if isinstance(domain, (list, tuple)): + if isinstance(domain[2], dict): + # We are having indirect geo_operator like (‘geom’, ‘geo_...’, + # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + ref_search = domain[2] + rel_where_statement = [] + for key in ref_search: + i = key.rfind(".") + rel_model = key[0:i] + rel_col = key[i + 1 :] + rel_model = model.env[rel_model] + from_clause += ", {}".format(rel_model._table) + att_where_sql = "" + # we compute the attributes search on spatial rel + if ref_search[key]: + rel_query = rel_model._where_calc( + ref_search[key], active_test=True + ) + rel_res = rel_query.get_sql() + att_where_sql = rel_res[1] + where_clause_params += rel_res[2] + # we compute the spatial search on spatial rel + func = _get_geo_func(model, domain) + spatial_where_sql = func( + model._table, + domain[0], + domain[2], + rel_col=rel_col, + rel_model=rel_model, + ) + if att_where_sql: + rel_where_statement.append( + "({} AND {})".format(att_where_sql, spatial_where_sql) + ) + else: + rel_where_statement.append("(%s)" % (spatial_where_sql)) + where_clause_arr.append("AND ".join(rel_where_statement)) + else: + func = _get_geo_func(model, domain) + where_sql = func(model._table, domain[0], domain[2]) + where_clause_arr.append(where_sql) + if where_clause_arr: + where_statement = " WHERE %s" % (" ".join(where_clause_arr)) + else: + where_statement = "" + # pylint: disable=E8103 + sql = ( + 'SELECT "%s".id FROM ' % model._table + + from_clause + + where_statement + + order_by + + limit_str + + offset_str + ) + # logger.debug(cursor.mogrify(sql, where_clause_params)) + cr.execute(sql, where_clause_params) + res = cr.fetchall() + if res: + return [x[0] for x in res] + else: + return [] + + +class GeoOperator(object): + def __init__(self, geo_field): + self.geo_field = geo_field + + def get_rel_field(self, rel_col, rel_model): + """Retrieves the expression to use in PostGIS statement for a spatial + rel search""" + try: + rel_model._fields[rel_col] + except Exception: + raise Exception( + "Model {} has no column {}".format(rel_model._name, rel_col) + ) + return "{}.{}".format(rel_model._table, rel_col) + + def _get_direct_como_op_sql( + self, table, col, value, rel_col=None, rel_model=None, op="" + ): + """provide raw sql for geater and lesser operators""" + if isinstance(value, (int, float)): + if rel_col and rel_model: + raise Exception( + "Area %s does not support int compare for relation " + "search" % (op,) + ) + return " ST_Area({}.{}) {} {}".format(table, col, op, value) + else: + if rel_col and rel_model is not None: + compare_to = self.get_rel_field(rel_col, rel_model) + else: + base = self.geo_field.entry_to_shape(value, same_type=False) + compare_to = base.wkt + return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText('{}'))".format( + table, col, op, compare_to + ) + + def _get_postgis_comp_sql( + self, table, col, value, rel_col=None, rel_model=None, op="" + ): + """return raw sql for all search based on St_**(a, b) posgis operator""" + if rel_col and rel_model is not None: + compare_to = self.get_rel_field(rel_col, rel_model) + else: + base = self.geo_field.entry_to_shape(value, same_type=False) + srid = self.geo_field.srid + compare_to = "ST_GeomFromText('{}',{})".format(base.wkt, srid) + return " {}({}.{}, {})".format(op, table, col, compare_to) + + def get_geo_greater_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_greater operator + (used for area comparison) + """ + return self._get_direct_como_op_sql( + table, col, value, rel_col, rel_model, op=">" + ) + + def get_geo_lesser_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_lesser operator + (used for area comparison)""" + return self._get_direct_como_op_sql( + table, col, value, rel_col, rel_model, op="<" + ) + + def get_geo_equal_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_equal operator + (used for equality comparison) + """ + if rel_col and rel_model is not None: + compare_to = self.get_rel_field(rel_col, rel_model) + else: + base = self.geo_field.entry_to_shape(value, same_type=False) + compare_to = "ST_GeomFromText('{}')".format(base.wkt) + return " {}.{} = {}".format(table, col, compare_to) + + def get_geo_intersect_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_intersec operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql( + table, col, value, rel_col, rel_model, op="ST_Intersects" + ) + + def get_geo_touch_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_touch operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql( + table, col, value, rel_col, rel_model, op="ST_Touches" + ) + + def get_geo_within_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_within operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql( + table, col, value, rel_col, rel_model, op="ST_Within" + ) + + def get_geo_contains_sql(self, table, col, value, rel_col=None, rel_model=None): + """Returns raw sql for geo_contains operator + (used for spatial comparison) + """ + return self._get_postgis_comp_sql( + table, col, value, rel_col, rel_model, op="ST_Contains" + ) diff --git a/base_geoengine/geo_view/__init__.py b/base_geoengine/geo_view/__init__.py new file mode 100644 index 000000000..88d8c167e --- /dev/null +++ b/base_geoengine/geo_view/__init__.py @@ -0,0 +1,24 @@ +############################################################################## +# +# Author: Nicolas Bessi +# Copyright 2011-2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +"""Module that manages map view and vector/raster layer""" +from . import geo_raster_layer +from . import geo_vector_layer +from . import geo_vector_symbol +from . import ir_view diff --git a/base_geoengine/geo_view/geo_raster_layer.py b/base_geoengine/geo_view/geo_raster_layer.py new file mode 100644 index 000000000..612e3f02f --- /dev/null +++ b/base_geoengine/geo_view/geo_raster_layer.py @@ -0,0 +1,77 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class GeoRasterLayerType(models.Model): + _name = "geoengine.raster.layer.type" + _description = "Raster Layer Type" + + name = fields.Char(translate=True, required=True) + code = fields.Char(required=True) + service = fields.Char(required=True) + + +class GeoRasterLayer(models.Model): + _name = "geoengine.raster.layer" + _description = "Raster Layer" + + raster_type = fields.Selection( + [ + ("osm", "OpenStreetMap"), + ("wmts", "WMTS"), + ("d_wms", "Distant WMS"), + ("odoo", "Odoo field"), + ], + string="Raster layer type", + default="osm", + required=True, + ) + name = fields.Char("Layer Name", size=256, translate=True, required=True) + url = fields.Char("Service URL", size=1024) + + # technical field to display or not wmts options + is_wmts = fields.Boolean(compute="_compute_is_wmts") + # wmts options + matrix_set = fields.Char("matrixSet") + format_suffix = fields.Char("formatSuffix", help="eg. png") + request_encoding = fields.Char("requestEncoding", help="eg. REST") + projection = fields.Char("projection", help="eg. EPSG:21781") + units = fields.Char(help="eg. m") + resolutions = fields.Char("resolutions") + max_extent = fields.Char("max_extent") + dimensions = fields.Char("dimensions", help="List of dimensions separated by ','") + params = fields.Char("params", help="Dictiorary of values for dimensions as JSON") + + # technical field to display or not layer type + has_type = fields.Boolean(compute="_compute_has_type") + type_id = fields.Many2one( + "geoengine.raster.layer.type", "Layer", domain="[('service', '=', raster_type)]" + ) + type = fields.Char(related="type_id.code") + sequence = fields.Integer("layer priority lower on top", default=6) + overlay = fields.Boolean("Is overlay layer?") + field_id = fields.Many2one( + "ir.model.fields", + "Odoo layer field to use", + domain=[("ttype", "ilike", "geo_"), ("model", "=", "view_id.model")], + ) + view_id = fields.Many2one( + "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True + ) + use_to_edit = fields.Boolean("Use to edit") + + @api.depends("raster_type", "is_wmts") + def _compute_has_type(self): + for rec in self: + rec.has_type = rec.raster_type == "is_wmts" + + @api.depends("raster_type") + def _compute_is_wmts(self): + for rec in self: + rec.is_wmts = rec.raster_type == "wmts" + + @api.onchange("raster_type") + def onchange_set_wmts_options(self): + """Abstract method for WMTS modules to set default options""" diff --git a/base_geoengine/geo_view/geo_raster_layer_view.xml b/base_geoengine/geo_view/geo_raster_layer_view.xml new file mode 100644 index 000000000..adc9e57fd --- /dev/null +++ b/base_geoengine/geo_view/geo_raster_layer_view.xml @@ -0,0 +1,93 @@ + + + + + geoengine.raster.layer.form + geoengine.raster.layer + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + geoengine.raster.layer.tree + geoengine.raster.layer + + + + + + + + + + + + Raster Layer + ir.actions.act_window + geoengine.raster.layer + + + + + +
diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py new file mode 100644 index 000000000..09d5d0f0f --- /dev/null +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -0,0 +1,72 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + +SUPPORTED_ATT = [ + "float", + "integer", + "integer_big", + "related", + "function", + "date", + "datetime", + "char", + "text", + "selection", +] + + +class GeoVectorLayer(models.Model): + _name = "geoengine.vector.layer" + _description = "Vector Layer" + + geo_repr = fields.Selection( + [ + ("basic", "Basic"), + # Actually we have to think if we should separate it for colored + ("proportion", "Proportional Symbol"), + ("colored", "Colored range/Chroma.js"), + ], + string="Representation mode", + required=True, + ) + classification = fields.Selection( + [ + ("unique", "Unique value"), + ("interval", "Interval"), + ("quantile", "Quantile"), + ("custom", "Custom"), + ], + string="Classification mode", + required=False, + ) + name = fields.Char("Layer Name", translate=True, required=True) + symbol_ids = fields.One2many("geoengine.vector.symbol", "vector_layer_id") + begin_color = fields.Char( + "Begin color class", size=64, required=False, help="hex value" + ) + end_color = fields.Char( + "End color class", size=64, required=False, help="hex value", default="#FF680A" + ) + nb_class = fields.Integer("Number of class", default=1) + attribute_field_id = fields.Many2one( + "ir.model.fields", "attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] + ) + geo_field_id = fields.Many2one( + "ir.model.fields", + "Geo field", + domain=[("ttype", "ilike", "geo_")], + required=True, + ondelete="cascade", + ) + view_id = fields.Many2one( + "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True + ) + sequence = fields.Integer("layer priority lower on top", default=6) + readonly = fields.Boolean("Layer is read only") + display_polygon_labels = fields.Boolean("Display Labels on Polygon") + active_on_startup = fields.Boolean( + help="Layer will be shown on startup if checked." + ) + layer_opacity = fields.Float("Layer Opacity") diff --git a/base_geoengine/geo_view/geo_vector_layer_view.xml b/base_geoengine/geo_view/geo_vector_layer_view.xml new file mode 100644 index 000000000..5b6a4f5a8 --- /dev/null +++ b/base_geoengine/geo_view/geo_vector_layer_view.xml @@ -0,0 +1,97 @@ + + + + + geoengine.vector.layer.form + geoengine.vector.layer + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + geoengine.vector.layer.tree + geoengine.vector.layer + + + + + + + + + + + + + + + Vector Layer + ir.actions.act_window + geoengine.vector.layer + + + + + +
diff --git a/base_geoengine/geo_view/geo_vector_symbol.py b/base_geoengine/geo_view/geo_vector_symbol.py new file mode 100644 index 000000000..94a2fac57 --- /dev/null +++ b/base_geoengine/geo_view/geo_vector_symbol.py @@ -0,0 +1,19 @@ +# Copyright 2016 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class GeoVectorSymbol(models.Model): + _name = "geoengine.vector.symbol" + _description = "Vector Layer Symbol" + + vector_layer_id = fields.Many2one("geoengine.vector.layer") + fieldname = fields.Char( + "Category field", + help="Name of the char field or selection field used for comparison", + ) + value = fields.Char(help="All object equal to this value will use this symbol") + img = fields.Char( + help="URL of the image to use. You can put an image in your module " + "in static folder e.g. 'base_geoengine/static/img/map-marker.png'" + ) diff --git a/base_geoengine/geo_view/ir_view.py b/base_geoengine/geo_view/ir_view.py new file mode 100644 index 000000000..42b23d0aa --- /dev/null +++ b/base_geoengine/geo_view/ir_view.py @@ -0,0 +1,30 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016-2023 Yannick Payot (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class IrUIView(models.Model): + _inherit = "ir.ui.view" + + type = fields.Selection( + selection_add=[("geoengine", "GeoEngine")], + ondelete={"geoengine": "cascade"}, + ) + + raster_layer_ids = fields.One2many( + "geoengine.raster.layer", "view_id", "Raster layers", required=False + ) + + vector_layer_ids = fields.One2many( + "geoengine.vector.layer", "view_id", "Vector layers", required=True + ) + + projection = fields.Char(default="EPSG:3857", required=True) + default_extent = fields.Char( + "Default map extent", + default="-123164.85222423, 5574694.9538936, 1578017.6490538," + " 6186191.1800898", + ) + default_zoom = fields.Integer("Default map zoom") + restricted_extent = fields.Char("Restricted map extent", size=128) diff --git a/base_geoengine/geo_view/ir_view_view.xml b/base_geoengine/geo_view/ir_view_view.xml new file mode 100644 index 000000000..0d7b2b4e7 --- /dev/null +++ b/base_geoengine/geo_view/ir_view_view.xml @@ -0,0 +1,53 @@ + + + + + geoengine.view.form + ir.ui.view + + + + + + + + + + + + + + + + + + + + + + Views + ir.actions.act_window + ir.ui.view + + + [('type', '=', 'geoengine')] + + + + + diff --git a/base_geoengine/i18n/base_geoengine.pot b/base_geoengine/i18n/base_geoengine.pot new file mode 100644 index 000000000..97fd6f001 --- /dev/null +++ b/base_geoengine/i18n/base_geoengine.pot @@ -0,0 +1,753 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_geoengine +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_geoengine +#: code:addons/base_geoengine/geo_model.py:0 +#, python-format +msgid "%s column does not exists or is not a geo field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Active On Startup" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_symbol__value +msgid "All object equal to this value will use this symbol" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller.js:0 +#, python-format +msgid "Archive" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_base +msgid "Base" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__basic +msgid "Basic" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__begin_color +msgid "Begin color class" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/xml/geoengine.xml:0 +#, python-format +msgid "Bottom-Left" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__fieldname +msgid "Category field" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Classification" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__classification +msgid "Classification mode" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__code +msgid "Code" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__colored +msgid "Colored range/Chroma.js" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Colors" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_view_menu +msgid "Configuration" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__gist_index +msgid "Create gist index" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__create_uid +msgid "Created by" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__create_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__create_date +msgid "Created on" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__custom +msgid "Custom" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_extent +msgid "Default map extent" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__default_zoom +msgid "Default map zoom" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller.js:0 +#, python-format +msgid "Delete" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__params +msgid "Dictiorary of values for dimensions as JSON" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_polygon_labels +msgid "Display Labels on Polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__display_name +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__display_name +msgid "Display Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__d_wms +msgid "Distant WMS" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__end_color +msgid "End color class" +msgstr "" + +#. module: base_geoengine +#: code:addons/base_geoengine/geo_db.py:0 +#, python-format +msgid "" +"Error, can not automatically initialize spatial postgis support. Database user may have to be superuser and postgres/postgis extensions with their devel header have to be installed. If you do not want Odoo to connect with a super user you can manually prepare your database. To do this, open a client to your database using a super user and run:\n" +"CREATE EXTENSION postgis;\n" +"CREATE EXTENSION postgis_topology;\n" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller.js:0 +#, python-format +msgid "Export" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__ttype +msgid "Field Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_model_fields +msgid "Fields" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/xml/geoengine.xml:0 +#, python-format +msgid "Filter selection" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "General" +msgstr "" + +#. module: base_geoengine +#: code:addons/base_geoengine/fields.py:0 +#, python-format +msgid "Geo Value %s must be of the same type %s as fields" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_field_id +msgid "Geo field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_ui_view__type__geoengine +msgid "GeoEngine" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_base_menu +msgid "GeoEngine Backend" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "GeoEngine Data" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_view.js:0 +#, python-format +msgid "Geoengine" +msgstr "" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_admin +msgid "Geoengine Admin" +msgstr "" + +#. module: base_geoengine +#: model:res.groups,name:base_geoengine.group_geoengine_user +msgid "Geoengine User" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__has_type +msgid "Has Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__id +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__id +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__id +msgid "ID" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__img +msgid "Img" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__interval +msgid "Interval" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__is_wmts +msgid "Is Wmts" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__overlay +msgid "Is overlay layer?" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__linestring +msgid "LINESTRING" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer____last_update +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type____last_update +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer____last_update +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol____last_update +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields____last_update +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view____last_update +msgid "Last Modified on" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_uid +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__write_date +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__write_date +msgid "Last Updated on" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__type_id +msgid "Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__name +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__name +msgid "Layer Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__layer_opacity +msgid "Layer Opacity" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Layer data" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__readonly +msgid "Layer is read only" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__active_on_startup +msgid "Layer will be shown on startup if checked." +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "List of dimensions separated by ','" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multilinestring +msgid "MULTILINESTRING" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipoint +msgid "MULTIPOINT" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__multipolygon +msgid "MULTIPOLYGON" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__name +msgid "Name" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_symbol__fieldname +msgid "Name of the char field or selection field used for comparison" +msgstr "" + +#. module: base_geoengine +#: code:addons/base_geoengine/geo_model.py:0 +#, python-format +msgid "No GeoEngine view defined for the model %s" +msgstr "" + +#. module: base_geoengine +#: code:addons/base_geoengine/geo_model.py:0 +#, python-format +msgid "No raster layer for view %s" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__nb_class +msgid "Number of class" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__odoo +msgid "Odoo field" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Odoo layer data (Not implemented)" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__field_id +msgid "Odoo layer field to use" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__osm +msgid "OpenStreetMap" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__point +msgid "POINT" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__geo_type__polygon +msgid "POLYGON" +msgstr "" + +#. module: base_geoengine +#: code:addons/base_geoengine/geo_model.py:0 +#, python-format +msgid "Please create a view or modify view mode" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__dim +msgid "PostGIs Dimension" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__geo_type +msgid "PostGIs type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__projection +msgid "Projection" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__geo_repr__proportion +msgid "Proportional Symbol" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__quantile +msgid "Quantile" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_tree +msgid "Raster" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Raster (Background layers)" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_rater_action +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer +msgid "Raster Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_raster_layer_menu +msgid "Raster Layer Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_raster_layer_type +msgid "Raster Layer Type" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "Raster Layer View" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__raster_type +msgid "Raster layer type" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__raster_layer_ids +msgid "Raster layers" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__view_id +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__view_id +msgid "Related View" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "Representation" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__geo_repr +msgid "Representation mode" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__restricted_extent +msgid "Restricted map extent" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer_type__service +msgid "Service" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__url +msgid "Service URL" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__symbol_ids +msgid "Symbol" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_symbol__img +msgid "" +"URL of the image to use. You can put an image in your module in static " +"folder e.g. 'base_geoengine/static/img/map-marker.png'" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/js/views/geoengine/geoengine_controller.js:0 +#, python-format +msgid "Unarchive" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_vector_layer__classification__unique +msgid "Unique value" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__units +msgid "Units" +msgstr "" + +#. module: base_geoengine +#. openerp-web +#: code:addons/base_geoengine/static/src/xml/geoengine.xml:0 +#, python-format +msgid "Up-Right" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__use_to_edit +msgid "Use to edit" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__value +msgid "Value" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_tree +msgid "Vector" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geoengine_view_form +msgid "Vector (Active layers)" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_raster_action +#: model:ir.model,name:base_geoengine.model_geoengine_vector_layer +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_symbol__vector_layer_id +msgid "Vector Layer" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_vector_layer_menu +msgid "Vector Layer Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_geoengine_vector_symbol +msgid "Vector Layer Symbol" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__vector_layer_ids +msgid "Vector layers" +msgstr "" + +#. module: base_geoengine +#: model:ir.model,name:base_geoengine.model_ir_ui_view +msgid "View" +msgstr "" + +#. module: base_geoengine +#: model:ir.ui.menu,name:base_geoengine.geoengine_view_menu +msgid "View Management" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_ui_view__type +msgid "View Type" +msgstr "" + +#. module: base_geoengine +#: model:ir.actions.act_window,name:base_geoengine.geo_engine_view_action +msgid "Views" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__geoengine_raster_layer__raster_type__wmts +msgid "WMTS" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_raster_view_form +msgid "WMTS options" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__attribute_field_id +msgid "attribute field" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__dimensions +msgid "dimensions" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__projection +msgid "eg. EPSG:21781" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "eg. REST" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__units +msgid "eg. m" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "eg. png" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__format_suffix +msgid "formatSuffix" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_line +msgid "geo_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_line +msgid "geo_multi_line" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_point +msgid "geo_multi_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_multi_polygon +msgid "geo_multi_polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_point +msgid "geo_point" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields.selection,name:base_geoengine.selection__ir_model_fields__ttype__geo_polygon +msgid "geo_polygon" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__begin_color +#: model:ir.model.fields,help:base_geoengine.field_geoengine_vector_layer__end_color +msgid "hex value" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__sequence +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_vector_layer__sequence +msgid "layer priority lower on top" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__matrix_set +msgid "matrixSet" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__max_extent +msgid "max_extent" +msgstr "" + +#. module: base_geoengine +#: model_terms:ir.ui.view,arch_db:base_geoengine.geo_vector_view_form +msgid "module/static/img/icon.png" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__params +msgid "params" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__projection +msgid "projection" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__request_encoding +msgid "requestEncoding" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_geoengine_raster_layer__resolutions +msgid "resolutions" +msgstr "" + +#. module: base_geoengine +#: model:ir.model.fields,field_description:base_geoengine.field_ir_model_fields__srid +msgid "srid" +msgstr "" diff --git a/base_geoengine/images/map-hover.png b/base_geoengine/images/map-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..14799049f5fdfb8e1c2eb438ae4cac0cae7ae593 GIT binary patch literal 113834 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 S_pBWN>X4OGlBf|k4*FkVS&8@n literal 0 HcmV?d00001 diff --git a/base_geoengine/images/map.png b/base_geoengine/images/map.png new file mode 100644 index 0000000000000000000000000000000000000000..17214344b2bd8d32519c22ef8dff339e1345a9a6 GIT binary patch literal 71907 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 +* Frederic Junod +* Yannick Payot +* Sandy Carter +* Laurent Mignon +* Jonathan Nemry +* David Lasley +* Daniel Reis +* Matthieu Dietrich +* Alan Ramos +* Damien Crier +* Cyril Gaudin +* Pierre Verkest +* Benjamin Willig +* Devendra Kavthekar +* Emanuel Cino +* Thomas Nowicki +* Alexandre Saunier +* Sandip Mangukiya diff --git a/base_geoengine/readme/DESCRIPTION.rst b/base_geoengine/readme/DESCRIPTION.rst new file mode 100644 index 000000000..2f8ca6513 --- /dev/null +++ b/base_geoengine/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +Geospatial support based on PostGIS add the ability of server to server +geojson to do geo CRUD and view definition. diff --git a/base_geoengine/readme/INSTALL.rst b/base_geoengine/readme/INSTALL.rst new file mode 100644 index 000000000..227cef314 --- /dev/null +++ b/base_geoengine/readme/INSTALL.rst @@ -0,0 +1,14 @@ + +To install this module, you need to have `PostGIS `_ installed. + +On Ubuntu:: + + sudo apt-get install postgis + +The module also requires two additional python libs: + +* `Shapely `_ + +* `geojson `_ + +for a complete documentation please refer to the `public documenation `_ diff --git a/base_geoengine/readme/ROADMAP.rst b/base_geoengine/readme/ROADMAP.rst new file mode 100644 index 000000000..104d14407 --- /dev/null +++ b/base_geoengine/readme/ROADMAP.rst @@ -0,0 +1,5 @@ +* Google layers have been removed as it was not working anyway. +* Switching from map to form view should be eased to open selected feature. + It should work using `do_switch_view` and this probably requires to set `self.dataset.index` +* A good way to open a record from map should be done with double click. + However selection handlers have difficulties to work nice with click events. diff --git a/base_geoengine/readme/USAGE.rst b/base_geoengine/readme/USAGE.rst new file mode 100644 index 000000000..7319fe161 --- /dev/null +++ b/base_geoengine/readme/USAGE.rst @@ -0,0 +1,16 @@ +Important changes in version 11 +=============================== + +The geometry attributes must now be explicitly mentioned in the list of fields of +the XML geoengine view definitions. For instance:: + + + Some data view + some.model + + + + + + + diff --git a/base_geoengine/security/data.xml b/base_geoengine/security/data.xml new file mode 100644 index 000000000..a5c24bbfc --- /dev/null +++ b/base_geoengine/security/data.xml @@ -0,0 +1,14 @@ + + + + + Geoengine User + + + + Geoengine Admin + + + + + diff --git a/base_geoengine/security/ir.model.access.csv b/base_geoengine/security/ir.model.access.csv new file mode 100644 index 000000000..1998612db --- /dev/null +++ b/base_geoengine/security/ir.model.access.csv @@ -0,0 +1,9 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_geo_user_vector_user,geoengine.user.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_vector_user,geoengine.admin.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_vector_symbol_user,geoengine.user.vector.symbol,base_geoengine.model_geoengine_vector_symbol,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_vector_symbol_user,geoengine.admin.vector.symbol,base_geoengine.model_geoengine_vector_symbol,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_raster_user,geoengine.user.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_raster_user,geoengine.admin.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_admin,1,1,1,1 +access_geo_user_raster_type_user,geoengine.user.raster.layer.type,base_geoengine.model_geoengine_raster_layer_type,base_geoengine.group_geoengine_user,1,0,0,0 +access_geo_admin_raster_type_user,geoengine.admin.raster.layer.type,base_geoengine.model_geoengine_raster_layer_type,base_geoengine.group_geoengine_admin,1,1,1,1 diff --git a/base_geoengine/static/description/icon.png b/base_geoengine/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b698310eefcab016c8372b688f495daacd3fe746 GIT binary patch literal 130328 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%0Aj5`*?xx_dV0 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 r#?5d*H!pjPiQ)gh{vW@AZ28Ba(=vW3ul + + + + + +Geospatial support for Odoo + + + + + + diff --git a/base_geoengine/static/img/map-marker.png b/base_geoengine/static/img/map-marker.png new file mode 100644 index 0000000000000000000000000000000000000000..0968935837fa762f01d85bafabe1dfbc87a0577a GIT binary patch literal 356 zcmV-q0h|7bP)EJ|4{M*jlpEtwfi7A4BSKnla_RTy4x z9jANW>)!hgJoVJ+KIi#<&pr2?E`K0Kv5PCz@PH~R=qL+cLLHwed4hqW@WmG3FwfAN z7e1`99UMwcU;v#51mHaX1qeV<5fjUzJBf+@(4Tz)K zq9;=juDG5u=dDFgrr;(RPo&I=pI@iUON>oF_jfj`_u(?AKcXj(Ur+rvI1C0fuFYn4&As* z5LDVFfb|G|i>`JG`tceFR@(`0#vGn;q`)8S|Hc l2) { + return (l1 + 0.05) / (l2 + 0.05); + } else { + return (l2 + 0.05) / (l1 + 0.05); + } + }; + + chroma.luminance = function(color) { + return chroma(color).luminance(); + }; + + chroma.kelvin = function(k) { + return chroma(temp2rgb(k), 'rgb'); + }; + + chroma.version = '0.8.0'; + + chroma._Color = Color; + + + /** + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + Color = (function() { + function Color() { + var a, arg, args, len, m, me, me_rgb, o, ref, ref1, ref2, ref3, ref4, x, y, z; + me = this; + args = []; + for (o = 0, len = arguments.length; o < len; o++) { + arg = arguments[o]; + if (arg != null) { + args.push(arg); + } + } + if (args.length === 0) { + ref = [255, 0, 255, 1, 'rgb'], x = ref[0], y = ref[1], z = ref[2], a = ref[3], m = ref[4]; + } else if (type(args[0]) === "array") { + if (args[0].length === 3) { + ref1 = args[0], x = ref1[0], y = ref1[1], z = ref1[2]; + a = 1; + } else if (args[0].length === 4) { + ref2 = args[0], x = ref2[0], y = ref2[1], z = ref2[2], a = ref2[3]; + } else { + throw 'unknown input argument'; + } + m = (ref3 = args[1]) != null ? ref3 : 'rgb'; + } else if (type(args[0]) === "string") { + x = args[0]; + m = 'hex'; + } else if (type(args[0]) === "object") { + ref4 = args[0]._rgb, x = ref4[0], y = ref4[1], z = ref4[2], a = ref4[3]; + m = 'rgb'; + } else if (args.length <= 2 && type(args[0]) === "number") { + x = args[0]; + m = 'num'; + } else if (args.length >= 3) { + x = args[0]; + y = args[1]; + z = args[2]; + } + if (args.length === 3) { + m = 'rgb'; + a = 1; + } else if (args.length === 4) { + if (type(args[3]) === "string") { + m = args[3]; + a = 1; + } else if (type(args[3]) === "number") { + m = 'rgb'; + a = args[3]; + } + } else if (args.length === 5) { + a = args[3]; + m = args[4]; + } + if (m !== 'cmyk') { + if (a == null) { + a = 1; + } + } + if (m === 'rgb') { + me._rgb = [x, y, z, a]; + } else if (m === 'gl') { + me._rgb = [x * 255, y * 255, z * 255, a]; + } else if (m === 'hsl') { + me._rgb = hsl2rgb(x, y, z); + me._rgb[3] = a; + } else if (m === 'hsv') { + me._rgb = hsv2rgb(x, y, z); + me._rgb[3] = a; + } else if (m === 'hex') { + me._rgb = hex2rgb(x); + } else if (m === 'lab') { + me._rgb = lab2rgb(x, y, z); + me._rgb[3] = a; + } else if (m === 'lch') { + me._rgb = lch2rgb(x, y, z); + me._rgb[3] = a; + } else if (m === 'hsi') { + me._rgb = hsi2rgb(x, y, z); + me._rgb[3] = a; + } else if (m === 'num') { + me._rgb = num2rgb(x); + } else if (m === 'cmyk') { + me._rgb = cmyk2rgb(x, y, z, a); + } + me_rgb = clip_rgb(me._rgb); + } + + Color.prototype.rgb = function() { + return this._rgb.slice(0, 3); + }; + + Color.prototype.rgba = function() { + return this._rgb; + }; + + Color.prototype.hex = function(mode) { + if (mode == null) { + mode = 'rgb'; + } + return rgb2hex(this._rgb, mode); + }; + + Color.prototype.toString = function() { + return this.name(); + }; + + Color.prototype.hsl = function() { + return rgb2hsl(this._rgb); + }; + + Color.prototype.hsv = function() { + return rgb2hsv(this._rgb); + }; + + Color.prototype.lab = function() { + return rgb2lab(this._rgb); + }; + + Color.prototype.lch = function() { + return rgb2lch(this._rgb); + }; + + Color.prototype.hsi = function() { + return rgb2hsi(this._rgb); + }; + + Color.prototype.gl = function() { + return [this._rgb[0] / 255, this._rgb[1] / 255, this._rgb[2] / 255, this._rgb[3]]; + }; + + Color.prototype.num = function() { + return rgb2num(this._rgb); + }; + + Color.prototype.luminance = function(lum, mode) { + var cur_lum, eps, max_iter, test; + if (mode == null) { + mode = 'rgb'; + } + if (!arguments.length) { + return luminance(this._rgb); + } + if (lum === 0) { + this._rgb = [0, 0, 0, this._rgb[3]]; + } + if (lum === 1) { + this._rgb = [255, 255, 255, this._rgb[3]]; + } + cur_lum = luminance(this._rgb); + eps = 1e-7; + max_iter = 20; + test = function(l, h) { + var lm, m; + m = l.interpolate(0.5, h, mode); + lm = m.luminance(); + if (Math.abs(lum - lm) < eps || !max_iter--) { + return m; + } + if (lm > lum) { + return test(l, m); + } + return test(m, h); + }; + this._rgb = (cur_lum > lum ? test(new Color('black'), this) : test(this, new Color('white'))).rgba(); + return this; + }; + + Color.prototype.name = function() { + var h, k; + h = this.hex(); + for (k in chroma.colors) { + if (h === chroma.colors[k]) { + return k; + } + } + return h; + }; + + Color.prototype.alpha = function(alpha) { + if (arguments.length) { + this._rgb[3] = alpha; + return this; + } + return this._rgb[3]; + }; + + Color.prototype.css = function(mode) { + var hsl, me, rgb, rnd; + if (mode == null) { + mode = 'rgb'; + } + me = this; + rgb = me._rgb; + if (mode.length === 3 && rgb[3] < 1) { + mode += 'a'; + } + if (mode === 'rgb') { + return mode + '(' + rgb.slice(0, 3).map(round).join(',') + ')'; + } else if (mode === 'rgba') { + return mode + '(' + rgb.slice(0, 3).map(round).join(',') + ',' + rgb[3] + ')'; + } else if (mode === 'hsl' || mode === 'hsla') { + hsl = me.hsl(); + rnd = function(a) { + return round(a * 100) / 100; + }; + hsl[0] = rnd(hsl[0] || 0); + hsl[1] = rnd(hsl[1] * 100) + '%'; + hsl[2] = rnd(hsl[2] * 100) + '%'; + if (mode.length === 4) { + hsl[3] = rgb[3]; + } + return mode + '(' + hsl.join(',') + ')'; + } + }; + + Color.prototype.interpolate = function(f, col, m) { + + /* + interpolates between colors + f = 0 --> me + f = 1 --> col + */ + var dh, hue, hue0, hue1, lbv, lbv0, lbv1, me, res, sat, sat0, sat1, xyz0, xyz1; + me = this; + if (m == null) { + m = 'rgb'; + } + if (type(col) === "string") { + col = new Color(col); + } + if (m === 'hsl' || m === 'hsv' || m === 'lch' || m === 'hsi') { + if (m === 'hsl') { + xyz0 = me.hsl(); + xyz1 = col.hsl(); + } else if (m === 'hsv') { + xyz0 = me.hsv(); + xyz1 = col.hsv(); + } else if (m === 'hsi') { + xyz0 = me.hsi(); + xyz1 = col.hsi(); + } else if (m === 'lch') { + xyz0 = me.lch(); + xyz1 = col.lch(); + } + if (m.substr(0, 1) === 'h') { + hue0 = xyz0[0], sat0 = xyz0[1], lbv0 = xyz0[2]; + hue1 = xyz1[0], sat1 = xyz1[1], lbv1 = xyz1[2]; + } else { + lbv0 = xyz0[0], sat0 = xyz0[1], hue0 = xyz0[2]; + lbv1 = xyz1[0], sat1 = xyz1[1], hue1 = xyz1[2]; + } + if (!isNaN(hue0) && !isNaN(hue1)) { + if (hue1 > hue0 && hue1 - hue0 > 180) { + dh = hue1 - (hue0 + 360); + } else if (hue1 < hue0 && hue0 - hue1 > 180) { + dh = hue1 + 360 - hue0; + } else { + dh = hue1 - hue0; + } + hue = hue0 + f * dh; + } else if (!isNaN(hue0)) { + hue = hue0; + if ((lbv1 === 1 || lbv1 === 0) && m !== 'hsv') { + sat = sat0; + } + } else if (!isNaN(hue1)) { + hue = hue1; + if ((lbv0 === 1 || lbv0 === 0) && m !== 'hsv') { + sat = sat1; + } + } else { + hue = Number.NaN; + } + if (sat == null) { + sat = sat0 + f * (sat1 - sat0); + } + lbv = lbv0 + f * (lbv1 - lbv0); + if (m.substr(0, 1) === 'h') { + res = new Color(hue, sat, lbv, m); + } else { + res = new Color(lbv, sat, hue, m); + } + } else if (m === 'rgb') { + xyz0 = me._rgb; + xyz1 = col._rgb; + res = new Color(xyz0[0] + f * (xyz1[0] - xyz0[0]), xyz0[1] + f * (xyz1[1] - xyz0[1]), xyz0[2] + f * (xyz1[2] - xyz0[2]), m); + } else if (m === 'num') { + if (!(col instanceof Color)) { + col = new Color(col, m); + } + xyz0 = me._rgb; + xyz1 = col._rgb; + res = new Color(((xyz0[0] + f * (xyz1[0] - xyz0[0])) << 16) + ((xyz0[1] + f * (xyz1[1] - xyz0[1])) << 8) + ((xyz0[2] + f * (xyz1[2] - xyz0[2])) & 0xff), m); + } else if (m === 'lab') { + xyz0 = me.lab(); + xyz1 = col.lab(); + res = new Color(xyz0[0] + f * (xyz1[0] - xyz0[0]), xyz0[1] + f * (xyz1[1] - xyz0[1]), xyz0[2] + f * (xyz1[2] - xyz0[2]), m); + } else { + throw "color mode " + m + " is not supported"; + } + res.alpha(me.alpha() + f * (col.alpha() - me.alpha())); + return res; + }; + + Color.prototype.mix = function(f, col, m) { + return this.interpolate(f, col, m); + }; + + Color.prototype.premultiply = function() { + var a, rgb; + rgb = this.rgb(); + a = this.alpha(); + return chroma(rgb[0] * a, rgb[1] * a, rgb[2] * a, a); + }; + + Color.prototype.darken = function(amount) { + var lch, me; + if (amount == null) { + amount = 20; + } + me = this; + lch = me.lch(); + lch[0] -= amount; + return chroma.lch(lch).alpha(me.alpha()); + }; + + Color.prototype.darker = function(amount) { + return this.darken(amount); + }; + + Color.prototype.brighten = function(amount) { + if (amount == null) { + amount = 20; + } + return this.darken(-amount); + }; + + Color.prototype.brighter = function(amount) { + return this.brighten(amount); + }; + + Color.prototype.saturate = function(amount) { + var lch, me; + if (amount == null) { + amount = 20; + } + me = this; + lch = me.lch(); + lch[1] += amount; + return chroma.lch(lch).alpha(me.alpha()); + }; + + Color.prototype.desaturate = function(amount) { + if (amount == null) { + amount = 20; + } + return this.saturate(-amount); + }; + + Color.prototype.blend = function(col, mode) { + return chroma.blend(this, col, mode); + }; + + Color.prototype.kelvin = function() { + return rgb2temp(this._rgb); + }; + + Color.prototype.cmyk = function() { + return rgb2cmyk(this._rgb); + }; + + return Color; + + })(); + + clip_rgb = function(rgb) { + var i; + for (i in rgb) { + if (i < 3) { + if (rgb[i] < 0) { + rgb[i] = 0; + } + if (rgb[i] > 255) { + rgb[i] = 255; + } + } else if (i === 3) { + if (rgb[i] < 0) { + rgb[i] = 0; + } + if (rgb[i] > 1) { + rgb[i] = 1; + } + } + } + return rgb; + }; + + rgb2cmyk = function() { + var b, c, f, g, k, m, r, ref, y; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = r / 255; + g = g / 255; + b = b / 255; + k = 1 - Math.max(r, Math.max(g, b)); + f = k < 1 ? 1 / (1 - k) : 0; + c = (1 - r - k) * f; + m = (1 - g - k) * f; + y = (1 - b - k) * f; + return [c, m, y, k]; + }; + + cmyk2rgb = function() { + var b, c, g, k, m, r, ref, y; + ref = unpack(arguments), c = ref[0], m = ref[1], y = ref[2], k = ref[3]; + if (k === 1) { + return [0, 0, 0]; + } + r = c >= 1 ? 0 : round(255 * (1 - c) * (1 - k)); + g = m >= 1 ? 0 : round(255 * (1 - m) * (1 - k)); + b = y >= 1 ? 0 : round(255 * (1 - y) * (1 - k)); + return [r, g, b]; + }; + + css2rgb = function(css) { + var aa, ab, hsl, i, m, o, rgb, w; + css = css.toLowerCase(); + if ((chroma.colors != null) && chroma.colors[css]) { + return hex2rgb(chroma.colors[css]); + } + if (m = css.match(/rgb\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)/)) { + rgb = m.slice(1, 4); + for (i = o = 0; o <= 2; i = ++o) { + rgb[i] = +rgb[i]; + } + rgb[3] = 1; + } else if (m = css.match(/rgba\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*,\s*([01]|[01]?\.\d+)\)/)) { + rgb = m.slice(1, 5); + for (i = w = 0; w <= 3; i = ++w) { + rgb[i] = +rgb[i]; + } + } else if (m = css.match(/rgb\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/)) { + rgb = m.slice(1, 4); + for (i = aa = 0; aa <= 2; i = ++aa) { + rgb[i] = round(rgb[i] * 2.55); + } + rgb[3] = 1; + } else if (m = css.match(/rgba\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/)) { + rgb = m.slice(1, 5); + for (i = ab = 0; ab <= 2; i = ++ab) { + rgb[i] = round(rgb[i] * 2.55); + } + rgb[3] = +rgb[3]; + } else if (m = css.match(/hsl\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/)) { + hsl = m.slice(1, 4); + hsl[1] *= 0.01; + hsl[2] *= 0.01; + rgb = hsl2rgb(hsl); + rgb[3] = 1; + } else if (m = css.match(/hsla\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/)) { + hsl = m.slice(1, 4); + hsl[1] *= 0.01; + hsl[2] *= 0.01; + rgb = hsl2rgb(hsl); + rgb[3] = +m[4]; + } + return rgb; + }; + + hex2rgb = function(hex) { + var a, b, g, r, rgb, u; + if (hex.match(/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)) { + if (hex.length === 4 || hex.length === 7) { + hex = hex.substr(1); + } + if (hex.length === 3) { + hex = hex.split(""); + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + u = parseInt(hex, 16); + r = u >> 16; + g = u >> 8 & 0xFF; + b = u & 0xFF; + return [r, g, b, 1]; + } + if (hex.match(/^#?([A-Fa-f0-9]{8})$/)) { + if (hex.length === 9) { + hex = hex.substr(1); + } + u = parseInt(hex, 16); + r = u >> 24 & 0xFF; + g = u >> 16 & 0xFF; + b = u >> 8 & 0xFF; + a = round((u & 0xFF) / 0xFF * 100) / 100; + return [r, g, b, a]; + } + if (rgb = css2rgb(hex)) { + return rgb; + } + throw "unknown color: " + hex; + }; + + hsi2rgb = function(h, s, i) { + + /* + borrowed from here: + http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/hsi2rgb.cpp + */ + var b, g, r, ref; + ref = unpack(arguments), h = ref[0], s = ref[1], i = ref[2]; + h /= 360; + if (h < 1 / 3) { + b = (1 - s) / 3; + r = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + g = 1 - (b + r); + } else if (h < 2 / 3) { + h -= 1 / 3; + r = (1 - s) / 3; + g = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + b = 1 - (r + g); + } else { + h -= 2 / 3; + g = (1 - s) / 3; + b = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + r = 1 - (g + b); + } + r = limit(i * r * 3); + g = limit(i * g * 3); + b = limit(i * b * 3); + return [r * 255, g * 255, b * 255]; + }; + + hsl2rgb = function() { + var b, c, g, h, i, l, o, r, ref, ref1, s, t1, t2, t3; + ref = unpack(arguments), h = ref[0], s = ref[1], l = ref[2]; + if (s === 0) { + r = g = b = l * 255; + } else { + t3 = [0, 0, 0]; + c = [0, 0, 0]; + t2 = l < 0.5 ? l * (1 + s) : l + s - l * s; + t1 = 2 * l - t2; + h /= 360; + t3[0] = h + 1 / 3; + t3[1] = h; + t3[2] = h - 1 / 3; + for (i = o = 0; o <= 2; i = ++o) { + if (t3[i] < 0) { + t3[i] += 1; + } + if (t3[i] > 1) { + t3[i] -= 1; + } + if (6 * t3[i] < 1) { + c[i] = t1 + (t2 - t1) * 6 * t3[i]; + } else if (2 * t3[i] < 1) { + c[i] = t2; + } else if (3 * t3[i] < 2) { + c[i] = t1 + (t2 - t1) * ((2 / 3) - t3[i]) * 6; + } else { + c[i] = t1; + } + } + ref1 = [round(c[0] * 255), round(c[1] * 255), round(c[2] * 255)], r = ref1[0], g = ref1[1], b = ref1[2]; + } + return [r, g, b]; + }; + + hsv2rgb = function() { + var b, f, g, h, i, p, q, r, ref, ref1, ref2, ref3, ref4, ref5, ref6, s, t, v; + ref = unpack(arguments), h = ref[0], s = ref[1], v = ref[2]; + v *= 255; + if (s === 0) { + r = g = b = v; + } else { + if (h === 360) { + h = 0; + } + if (h > 360) { + h -= 360; + } + if (h < 0) { + h += 360; + } + h /= 60; + i = floor(h); + f = h - i; + p = v * (1 - s); + q = v * (1 - s * f); + t = v * (1 - s * (1 - f)); + switch (i) { + case 0: + ref1 = [v, t, p], r = ref1[0], g = ref1[1], b = ref1[2]; + break; + case 1: + ref2 = [q, v, p], r = ref2[0], g = ref2[1], b = ref2[2]; + break; + case 2: + ref3 = [p, v, t], r = ref3[0], g = ref3[1], b = ref3[2]; + break; + case 3: + ref4 = [p, q, v], r = ref4[0], g = ref4[1], b = ref4[2]; + break; + case 4: + ref5 = [t, p, v], r = ref5[0], g = ref5[1], b = ref5[2]; + break; + case 5: + ref6 = [v, p, q], r = ref6[0], g = ref6[1], b = ref6[2]; + } + } + r = round(r); + g = round(g); + b = round(b); + return [r, g, b]; + }; + + K = 18; + + X = 0.950470; + + Y = 1; + + Z = 1.088830; + + lab2lch = function() { + var a, b, c, h, l, ref; + ref = unpack(arguments), l = ref[0], a = ref[1], b = ref[2]; + c = Math.sqrt(a * a + b * b); + h = (Math.atan2(b, a) / Math.PI * 180 + 360) % 360; + return [l, c, h]; + }; + + lab2rgb = function(l, a, b) { + + /* + adapted to match d3 implementation + */ + var g, r, ref, ref1, x, y, z; + if (l !== void 0 && l.length === 3) { + ref = l, l = ref[0], a = ref[1], b = ref[2]; + } + if (l !== void 0 && l.length === 3) { + ref1 = l, l = ref1[0], a = ref1[1], b = ref1[2]; + } + y = (l + 16) / 116; + x = y + a / 500; + z = y - b / 200; + x = lab_xyz(x) * X; + y = lab_xyz(y) * Y; + z = lab_xyz(z) * Z; + r = xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z); + g = xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z); + b = xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z); + return [limit(r, 0, 255), limit(g, 0, 255), limit(b, 0, 255), 1]; + }; + + lab_xyz = function(x) { + if (x > 0.206893034) { + return x * x * x; + } else { + return (x - 4 / 29) / 7.787037; + } + }; + + xyz_rgb = function(r) { + return round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * pow(r, 1 / 2.4) - 0.055)); + }; + + lch2lab = function() { + + /* + Convert from a qualitative parameter h and a quantitative parameter l to a 24-bit pixel. These formulas were invented by David Dalrymple to obtain maximum contrast without going out of gamut if the parameters are in the range 0-1. + A saturation multiplier was added by Gregor Aisch + */ + var c, h, l, ref; + ref = unpack(arguments), l = ref[0], c = ref[1], h = ref[2]; + h = h * Math.PI / 180; + return [l, Math.cos(h) * c, Math.sin(h) * c]; + }; + + lch2rgb = function(l, c, h) { + var L, a, b, g, r, ref, ref1; + ref = lch2lab(l, c, h), L = ref[0], a = ref[1], b = ref[2]; + ref1 = lab2rgb(L, a, b), r = ref1[0], g = ref1[1], b = ref1[2]; + return [limit(r, 0, 255), limit(g, 0, 255), limit(b, 0, 255)]; + }; + + luminance = function(r, g, b) { + var ref; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = luminance_x(r); + g = luminance_x(g); + b = luminance_x(b); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + }; + + luminance_x = function(x) { + x /= 255; + if (x <= 0.03928) { + return x / 12.92; + } else { + return Math.pow((x + 0.055) / 1.055, 2.4); + } + }; + + num2rgb = function(num) { + var b, g, r; + if (type(num) === "number" && num >= 0 && num <= 0xFFFFFF) { + r = num >> 16; + g = (num >> 8) & 0xFF; + b = num & 0xFF; + return [r, g, b, 1]; + } + throw "unknown num color: " + num; + }; + + rgb2hex = function(channels, mode) { + var a, b, g, hxa, r, str, u; + if (mode == null) { + mode = 'rgb'; + } + r = channels[0], g = channels[1], b = channels[2], a = channels[3]; + u = r << 16 | g << 8 | b; + str = "000000" + u.toString(16); + str = str.substr(str.length - 6); + hxa = '0' + round(a * 255).toString(16); + hxa = hxa.substr(hxa.length - 2); + return "#" + (function() { + switch (mode.toLowerCase()) { + case 'rgba': + return str + hxa; + case 'argb': + return hxa + str; + default: + return str; + } + })(); + }; + + rgb2hsi = function() { + + /* + borrowed from here: + http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/rgb2hsi.cpp + */ + var TWOPI, b, g, h, i, min, r, ref, s; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + TWOPI = Math.PI * 2; + r /= 255; + g /= 255; + b /= 255; + min = Math.min(r, g, b); + i = (r + g + b) / 3; + s = 1 - min / i; + if (s === 0) { + h = 0; + } else { + h = ((r - g) + (r - b)) / 2; + h /= Math.sqrt((r - g) * (r - g) + (r - b) * (g - b)); + h = Math.acos(h); + if (b > g) { + h = TWOPI - h; + } + h /= TWOPI; + } + return [h * 360, s, i]; + }; + + rgb2hsl = function(r, g, b) { + var h, l, max, min, ref, s; + if (r !== void 0 && r.length >= 3) { + ref = r, r = ref[0], g = ref[1], b = ref[2]; + } + r /= 255; + g /= 255; + b /= 255; + min = Math.min(r, g, b); + max = Math.max(r, g, b); + l = (max + min) / 2; + if (max === min) { + s = 0; + h = Number.NaN; + } else { + s = l < 0.5 ? (max - min) / (max + min) : (max - min) / (2 - max - min); + } + if (r === max) { + h = (g - b) / (max - min); + } else if (g === max) { + h = 2 + (b - r) / (max - min); + } else if (b === max) { + h = 4 + (r - g) / (max - min); + } + h *= 60; + if (h < 0) { + h += 360; + } + return [h, s, l]; + }; + + rgb2hsv = function() { + var b, delta, g, h, max, min, r, ref, s, v; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + min = Math.min(r, g, b); + max = Math.max(r, g, b); + delta = max - min; + v = max / 255.0; + if (max === 0) { + h = Number.NaN; + s = 0; + } else { + s = delta / max; + if (r === max) { + h = (g - b) / delta; + } + if (g === max) { + h = 2 + (b - r) / delta; + } + if (b === max) { + h = 4 + (r - g) / delta; + } + h *= 60; + if (h < 0) { + h += 360; + } + } + return [h, s, v]; + }; + + rgb2lab = function() { + var b, g, r, ref, ref1, x, y, z; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + ref1 = rgb2xyz(r, g, b), x = ref1[0], y = ref1[1], z = ref1[2]; + return [116 * y - 16, 500 * (x - y), 200 * (y - z)]; + }; + + rgb_xyz = function(r) { + if ((r /= 255) <= 0.04045) { + return r / 12.92; + } else { + return Math.pow((r + 0.055) / 1.055, 2.4); + } + }; + + xyz_lab = function(x) { + if (x > 0.008856) { + return Math.pow(x, 1 / 3); + } else { + return 7.787037 * x + 4 / 29; + } + }; + + rgb2xyz = function() { + var b, g, r, ref, x, y, z; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = rgb_xyz(r); + g = rgb_xyz(g); + b = rgb_xyz(b); + x = xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / X); + y = xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / Y); + z = xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / Z); + return [x, y, z]; + }; + + rgb2lch = function() { + var a, b, g, l, r, ref, ref1; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + ref1 = rgb2lab(r, g, b), l = ref1[0], a = ref1[1], b = ref1[2]; + return lab2lch(l, a, b); + }; + + rgb2num = function() { + var b, g, r, ref; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + return (r << 16) + (g << 8) + b; + }; + + temp2rgb = function(kelvin) { + var b, g, r, temp; + temp = kelvin / 100; + if (temp < 66) { + r = 255; + g = -155.25485562709179 - 0.44596950469579133 * (g = temp - 2) + 104.49216199393888 * log(g); + b = temp < 20 ? 0 : -254.76935184120902 + 0.8274096064007395 * (b = temp - 10) + 115.67994401066147 * log(b); + } else { + r = 351.97690566805693 + 0.114206453784165 * (r = temp - 55) - 40.25366309332127 * log(r); + g = 325.4494125711974 + 0.07943456536662342 * (g = temp - 50) - 28.0852963507957 * log(g); + b = 255; + } + return clip_rgb([r, g, b]); + }; + + rgb2temp = function() { + var b, eps, g, maxTemp, minTemp, r, ref, rgb, temp; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + minTemp = 1000; + maxTemp = 40000; + eps = 0.4; + while (maxTemp - minTemp > eps) { + temp = (maxTemp + minTemp) * 0.5; + rgb = temp2rgb(temp); + if ((rgb[2] / rgb[0]) >= (b / r)) { + maxTemp = temp; + } else { + minTemp = temp; + } + } + return round(temp); + }; + + + /* + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + chroma.scale = function(colors, positions) { + var _colorCache, _colors, _correctLightness, _domain, _fixed, _max, _min, _mode, _nacol, _numClasses, _out, _pos, _spread, classifyValue, f, getClass, getColor, resetCache, setColors, setDomain, tmap; + _mode = 'rgb'; + _nacol = chroma('#ccc'); + _spread = 0; + _fixed = false; + _domain = [0, 1]; + _colors = []; + _out = false; + _pos = []; + _min = 0; + _max = 1; + _correctLightness = false; + _numClasses = 0; + _colorCache = {}; + setColors = function(colors, positions) { + var c, col, o, ref, ref1, ref2, w; + if (colors == null) { + colors = ['#ddd', '#222']; + } + if ((colors != null) && type(colors) === 'string' && (((ref = chroma.brewer) != null ? ref[colors] : void 0) != null)) { + colors = chroma.brewer[colors]; + } + if (type(colors) === 'array') { + colors = colors.slice(0); + for (c = o = 0, ref1 = colors.length - 1; 0 <= ref1 ? o <= ref1 : o >= ref1; c = 0 <= ref1 ? ++o : --o) { + col = colors[c]; + if (type(col) === "string") { + colors[c] = chroma(col); + } + } + if (positions != null) { + _pos = positions; + } else { + _pos = []; + for (c = w = 0, ref2 = colors.length - 1; 0 <= ref2 ? w <= ref2 : w >= ref2; c = 0 <= ref2 ? ++w : --w) { + _pos.push(c / (colors.length - 1)); + } + } + } + resetCache(); + return _colors = colors; + }; + setDomain = function(domain) { + if (domain == null) { + domain = []; + } + + /* + * use this if you want to display a limited number of data classes + * possible methods are "equalinterval", "quantiles", "custom" + */ + _domain = domain; + _min = domain[0]; + _max = domain[domain.length - 1]; + resetCache(); + if (domain.length === 2) { + return _numClasses = 0; + } else { + return _numClasses = domain.length - 1; + } + }; + getClass = function(value) { + var i, n; + if (_domain != null) { + n = _domain.length - 1; + i = 0; + while (i < n && value >= _domain[i]) { + i++; + } + return i - 1; + } + return 0; + }; + tmap = function(t) { + return t; + }; + classifyValue = function(value) { + var i, maxc, minc, n, val; + val = value; + if (_domain.length > 2) { + n = _domain.length - 1; + i = getClass(value); + minc = _domain[0] + (_domain[1] - _domain[0]) * (0 + _spread * 0.5); + maxc = _domain[n - 1] + (_domain[n] - _domain[n - 1]) * (1 - _spread * 0.5); + val = _min + ((_domain[i] + (_domain[i + 1] - _domain[i]) * 0.5 - minc) / (maxc - minc)) * (_max - _min); + } + return val; + }; + getColor = function(val, bypassMap) { + var c, col, f0, i, k, o, p, ref, t; + if (bypassMap == null) { + bypassMap = false; + } + if (isNaN(val)) { + return _nacol; + } + if (!bypassMap) { + if (_domain.length > 2) { + c = getClass(val); + t = c / (_numClasses - 1); + } else { + t = f0 = _min !== _max ? (val - _min) / (_max - _min) : 0; + t = f0 = (val - _min) / (_max - _min); + t = Math.min(1, Math.max(0, t)); + } + } else { + t = val; + } + if (!bypassMap) { + t = tmap(t); + } + k = Math.floor(t * 10000); + if (_colorCache[k]) { + col = _colorCache[k]; + } else { + if (type(_colors) === 'array') { + for (i = o = 0, ref = _pos.length - 1; 0 <= ref ? o <= ref : o >= ref; i = 0 <= ref ? ++o : --o) { + p = _pos[i]; + if (t <= p) { + col = _colors[i]; + break; + } + if (t >= p && i === _pos.length - 1) { + col = _colors[i]; + break; + } + if (t > p && t < _pos[i + 1]) { + t = (t - p) / (_pos[i + 1] - p); + col = chroma.interpolate(_colors[i], _colors[i + 1], t, _mode); + break; + } + } + } else if (type(_colors) === 'function') { + col = _colors(t); + } + _colorCache[k] = col; + } + return col; + }; + resetCache = function() { + return _colorCache = {}; + }; + setColors(colors, positions); + f = function(v) { + var c; + c = getColor(v); + if (_out && c[_out]) { + return c[_out](); + } else { + return c; + } + }; + f.domain = function(domain, classes, mode, key) { + var d; + if (mode == null) { + mode = 'e'; + } + if (!arguments.length) { + return _domain; + } + if (classes != null) { + d = chroma.analyze(domain, key); + if (classes === 0) { + domain = [d.min, d.max]; + } else { + domain = chroma.limits(d, mode, classes); + } + } + setDomain(domain); + return f; + }; + f.mode = function(_m) { + if (!arguments.length) { + return _mode; + } + _mode = _m; + resetCache(); + return f; + }; + f.range = function(colors, _pos) { + setColors(colors, _pos); + return f; + }; + f.out = function(_o) { + _out = _o; + return f; + }; + f.spread = function(val) { + if (!arguments.length) { + return _spread; + } + _spread = val; + return f; + }; + f.correctLightness = function(v) { + if (!arguments.length) { + return _correctLightness; + } + _correctLightness = v; + resetCache(); + if (_correctLightness) { + tmap = function(t) { + var L0, L1, L_actual, L_diff, L_ideal, max_iter, pol, t0, t1; + L0 = getColor(0, true).lab()[0]; + L1 = getColor(1, true).lab()[0]; + pol = L0 > L1; + L_actual = getColor(t, true).lab()[0]; + L_ideal = L0 + (L1 - L0) * t; + L_diff = L_actual - L_ideal; + t0 = 0; + t1 = 1; + max_iter = 20; + while (Math.abs(L_diff) > 1e-2 && max_iter-- > 0) { + (function() { + if (pol) { + L_diff *= -1; + } + if (L_diff < 0) { + t0 = t; + t += (t1 - t) * 0.5; + } else { + t1 = t; + t += (t0 - t) * 0.5; + } + L_actual = getColor(t, true).lab()[0]; + return L_diff = L_actual - L_ideal; + })(); + } + return t; + }; + } else { + tmap = function(t) { + return t; + }; + } + return f; + }; + f.colors = function(out) { + var i, len, o, ref, samples, w; + if (out == null) { + out = 'hex'; + } + colors = []; + samples = []; + if (_domain.length > 2) { + for (i = o = 1, ref = _domain.length; 1 <= ref ? o < ref : o > ref; i = 1 <= ref ? ++o : --o) { + samples.push((_domain[i - 1] + _domain[i]) * 0.5); + } + } else { + samples = _domain; + } + for (w = 0, len = samples.length; w < len; w++) { + i = samples[w]; + colors.push(f(i)[out]()); + } + return colors; + }; + return f; + }; + + if (chroma.scales == null) { + chroma.scales = {}; + } + + chroma.scales.cool = function() { + return chroma.scale([chroma.hsl(180, 1, .9), chroma.hsl(250, .7, .4)]); + }; + + chroma.scales.hot = function() { + return chroma.scale(['#000', '#f00', '#ff0', '#fff'], [0, .25, .75, 1]).mode('rgb'); + }; + + + /* + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + chroma.analyze = function(data, key, filter) { + var add, k, len, o, r, val, visit; + r = { + min: Number.MAX_VALUE, + max: Number.MAX_VALUE * -1, + sum: 0, + values: [], + count: 0 + }; + if (filter == null) { + filter = function() { + return true; + }; + } + add = function(val) { + if ((val != null) && !isNaN(val)) { + r.values.push(val); + r.sum += val; + if (val < r.min) { + r.min = val; + } + if (val > r.max) { + r.max = val; + } + r.count += 1; + } + }; + visit = function(val, k) { + if (filter(val, k)) { + if ((key != null) && type(key) === 'function') { + return add(key(val)); + } else if ((key != null) && type(key) === 'string' || type(key) === 'number') { + return add(val[key]); + } else { + return add(val); + } + } + }; + if (type(data) === 'array') { + for (o = 0, len = data.length; o < len; o++) { + val = data[o]; + visit(val); + } + } else { + for (k in data) { + val = data[k]; + visit(val, k); + } + } + r.domain = [r.min, r.max]; + r.limits = function(mode, num) { + return chroma.limits(r, mode, num); + }; + return r; + }; + + chroma.limits = function(data, mode, num) { + var aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, assignments, best, centroids, cluster, clusterSizes, dist, i, j, kClusters, limits, max, max_log, min, min_log, mindist, n, nb_iters, newCentroids, o, p, pb, pr, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, repeat, sum, tmpKMeansBreaks, value, values, w; + if (mode == null) { + mode = 'equal'; + } + if (num == null) { + num = 7; + } + if (type(data) === 'array') { + data = chroma.analyze(data); + } + min = data.min; + max = data.max; + sum = data.sum; + values = data.values.sort(function(a, b) { + return a - b; + }); + limits = []; + if (mode.substr(0, 1) === 'c') { + limits.push(min); + limits.push(max); + } + if (mode.substr(0, 1) === 'e') { + limits.push(min); + for (i = o = 1, ref = num - 1; 1 <= ref ? o <= ref : o >= ref; i = 1 <= ref ? ++o : --o) { + limits.push(min + (i / num) * (max - min)); + } + limits.push(max); + } else if (mode.substr(0, 1) === 'l') { + if (min <= 0) { + throw 'Logarithmic scales are only possible for values > 0'; + } + min_log = Math.LOG10E * log(min); + max_log = Math.LOG10E * log(max); + limits.push(min); + for (i = w = 1, ref1 = num - 1; 1 <= ref1 ? w <= ref1 : w >= ref1; i = 1 <= ref1 ? ++w : --w) { + limits.push(pow(10, min_log + (i / num) * (max_log - min_log))); + } + limits.push(max); + } else if (mode.substr(0, 1) === 'q') { + limits.push(min); + for (i = aa = 1, ref2 = num - 1; 1 <= ref2 ? aa <= ref2 : aa >= ref2; i = 1 <= ref2 ? ++aa : --aa) { + p = values.length * i / num; + pb = floor(p); + if (pb === p) { + limits.push(values[pb]); + } else { + pr = p - pb; + limits.push(values[pb] * pr + values[pb + 1] * (1 - pr)); + } + } + limits.push(max); + } else if (mode.substr(0, 1) === 'k') { + + /* + implementation based on + http://code.google.com/p/figue/source/browse/trunk/figue.js#336 + simplified for 1-d input values + */ + n = values.length; + assignments = new Array(n); + clusterSizes = new Array(num); + repeat = true; + nb_iters = 0; + centroids = null; + centroids = []; + centroids.push(min); + for (i = ab = 1, ref3 = num - 1; 1 <= ref3 ? ab <= ref3 : ab >= ref3; i = 1 <= ref3 ? ++ab : --ab) { + centroids.push(min + (i / num) * (max - min)); + } + centroids.push(max); + while (repeat) { + for (j = ac = 0, ref4 = num - 1; 0 <= ref4 ? ac <= ref4 : ac >= ref4; j = 0 <= ref4 ? ++ac : --ac) { + clusterSizes[j] = 0; + } + for (i = ad = 0, ref5 = n - 1; 0 <= ref5 ? ad <= ref5 : ad >= ref5; i = 0 <= ref5 ? ++ad : --ad) { + value = values[i]; + mindist = Number.MAX_VALUE; + for (j = ae = 0, ref6 = num - 1; 0 <= ref6 ? ae <= ref6 : ae >= ref6; j = 0 <= ref6 ? ++ae : --ae) { + dist = Math.abs(centroids[j] - value); + if (dist < mindist) { + mindist = dist; + best = j; + } + } + clusterSizes[best]++; + assignments[i] = best; + } + newCentroids = new Array(num); + for (j = af = 0, ref7 = num - 1; 0 <= ref7 ? af <= ref7 : af >= ref7; j = 0 <= ref7 ? ++af : --af) { + newCentroids[j] = null; + } + for (i = ag = 0, ref8 = n - 1; 0 <= ref8 ? ag <= ref8 : ag >= ref8; i = 0 <= ref8 ? ++ag : --ag) { + cluster = assignments[i]; + if (newCentroids[cluster] === null) { + newCentroids[cluster] = values[i]; + } else { + newCentroids[cluster] += values[i]; + } + } + for (j = ah = 0, ref9 = num - 1; 0 <= ref9 ? ah <= ref9 : ah >= ref9; j = 0 <= ref9 ? ++ah : --ah) { + newCentroids[j] *= 1 / clusterSizes[j]; + } + repeat = false; + for (j = ai = 0, ref10 = num - 1; 0 <= ref10 ? ai <= ref10 : ai >= ref10; j = 0 <= ref10 ? ++ai : --ai) { + if (newCentroids[j] !== centroids[i]) { + repeat = true; + break; + } + } + centroids = newCentroids; + nb_iters++; + if (nb_iters > 200) { + repeat = false; + } + } + kClusters = {}; + for (j = aj = 0, ref11 = num - 1; 0 <= ref11 ? aj <= ref11 : aj >= ref11; j = 0 <= ref11 ? ++aj : --aj) { + kClusters[j] = []; + } + for (i = ak = 0, ref12 = n - 1; 0 <= ref12 ? ak <= ref12 : ak >= ref12; i = 0 <= ref12 ? ++ak : --ak) { + cluster = assignments[i]; + kClusters[cluster].push(values[i]); + } + tmpKMeansBreaks = []; + for (j = al = 0, ref13 = num - 1; 0 <= ref13 ? al <= ref13 : al >= ref13; j = 0 <= ref13 ? ++al : --al) { + tmpKMeansBreaks.push(kClusters[j][0]); + tmpKMeansBreaks.push(kClusters[j][kClusters[j].length - 1]); + } + tmpKMeansBreaks = tmpKMeansBreaks.sort(function(a, b) { + return a - b; + }); + limits.push(tmpKMeansBreaks[0]); + for (i = am = 1, ref14 = tmpKMeansBreaks.length - 1; am <= ref14; i = am += 2) { + if (!isNaN(tmpKMeansBreaks[i])) { + limits.push(tmpKMeansBreaks[i]); + } + } + } + return limits; + }; + + + /** + ColorBrewer colors for chroma.js + + Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The + Pennsylvania State University. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed + under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. See the License for the + specific language governing permissions and limitations under the License. + + @preserve + */ + + chroma.brewer = brewer = { + OrRd: ['#fff7ec', '#fee8c8', '#fdd49e', '#fdbb84', '#fc8d59', '#ef6548', '#d7301f', '#b30000', '#7f0000'], + PuBu: ['#fff7fb', '#ece7f2', '#d0d1e6', '#a6bddb', '#74a9cf', '#3690c0', '#0570b0', '#045a8d', '#023858'], + BuPu: ['#f7fcfd', '#e0ecf4', '#bfd3e6', '#9ebcda', '#8c96c6', '#8c6bb1', '#88419d', '#810f7c', '#4d004b'], + Oranges: ['#fff5eb', '#fee6ce', '#fdd0a2', '#fdae6b', '#fd8d3c', '#f16913', '#d94801', '#a63603', '#7f2704'], + BuGn: ['#f7fcfd', '#e5f5f9', '#ccece6', '#99d8c9', '#66c2a4', '#41ae76', '#238b45', '#006d2c', '#00441b'], + YlOrBr: ['#ffffe5', '#fff7bc', '#fee391', '#fec44f', '#fe9929', '#ec7014', '#cc4c02', '#993404', '#662506'], + YlGn: ['#ffffe5', '#f7fcb9', '#d9f0a3', '#addd8e', '#78c679', '#41ab5d', '#238443', '#006837', '#004529'], + Reds: ['#fff5f0', '#fee0d2', '#fcbba1', '#fc9272', '#fb6a4a', '#ef3b2c', '#cb181d', '#a50f15', '#67000d'], + RdPu: ['#fff7f3', '#fde0dd', '#fcc5c0', '#fa9fb5', '#f768a1', '#dd3497', '#ae017e', '#7a0177', '#49006a'], + Greens: ['#f7fcf5', '#e5f5e0', '#c7e9c0', '#a1d99b', '#74c476', '#41ab5d', '#238b45', '#006d2c', '#00441b'], + YlGnBu: ['#ffffd9', '#edf8b1', '#c7e9b4', '#7fcdbb', '#41b6c4', '#1d91c0', '#225ea8', '#253494', '#081d58'], + Purples: ['#fcfbfd', '#efedf5', '#dadaeb', '#bcbddc', '#9e9ac8', '#807dba', '#6a51a3', '#54278f', '#3f007d'], + GnBu: ['#f7fcf0', '#e0f3db', '#ccebc5', '#a8ddb5', '#7bccc4', '#4eb3d3', '#2b8cbe', '#0868ac', '#084081'], + Greys: ['#ffffff', '#f0f0f0', '#d9d9d9', '#bdbdbd', '#969696', '#737373', '#525252', '#252525', '#000000'], + YlOrRd: ['#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c', '#bd0026', '#800026'], + PuRd: ['#f7f4f9', '#e7e1ef', '#d4b9da', '#c994c7', '#df65b0', '#e7298a', '#ce1256', '#980043', '#67001f'], + Blues: ['#f7fbff', '#deebf7', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#08519c', '#08306b'], + PuBuGn: ['#fff7fb', '#ece2f0', '#d0d1e6', '#a6bddb', '#67a9cf', '#3690c0', '#02818a', '#016c59', '#014636'], + Spectral: ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2'], + RdYlGn: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850', '#006837'], + RdBu: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061'], + PiYG: ['#8e0152', '#c51b7d', '#de77ae', '#f1b6da', '#fde0ef', '#f7f7f7', '#e6f5d0', '#b8e186', '#7fbc41', '#4d9221', '#276419'], + PRGn: ['#40004b', '#762a83', '#9970ab', '#c2a5cf', '#e7d4e8', '#f7f7f7', '#d9f0d3', '#a6dba0', '#5aae61', '#1b7837', '#00441b'], + RdYlBu: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee090', '#ffffbf', '#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695'], + BrBG: ['#543005', '#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e', '#003c30'], + RdGy: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#ffffff', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a'], + PuOr: ['#7f3b08', '#b35806', '#e08214', '#fdb863', '#fee0b6', '#f7f7f7', '#d8daeb', '#b2abd2', '#8073ac', '#542788', '#2d004b'], + Set2: ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3', '#a6d854', '#ffd92f', '#e5c494', '#b3b3b3'], + Accent: ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666'], + Set1: ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00', '#ffff33', '#a65628', '#f781bf', '#999999'], + Set3: ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd', '#ccebc5', '#ffed6f'], + Dark2: ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666'], + Paired: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928'], + Pastel2: ['#b3e2cd', '#fdcdac', '#cbd5e8', '#f4cae4', '#e6f5c9', '#fff2ae', '#f1e2cc', '#cccccc'], + Pastel1: ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4', '#fed9a6', '#ffffcc', '#e5d8bd', '#fddaec', '#f2f2f2'] + }; + + + /** + X11 color names + + http://www.w3.org/TR/css3-color/#svg-color + */ + + chroma.colors = colors = { + indigo: "#4b0082", + gold: "#ffd700", + hotpink: "#ff69b4", + firebrick: "#b22222", + indianred: "#cd5c5c", + yellow: "#ffff00", + mistyrose: "#ffe4e1", + darkolivegreen: "#556b2f", + olive: "#808000", + darkseagreen: "#8fbc8f", + pink: "#ffc0cb", + tomato: "#ff6347", + lightcoral: "#f08080", + orangered: "#ff4500", + navajowhite: "#ffdead", + lime: "#00ff00", + palegreen: "#98fb98", + darkslategrey: "#2f4f4f", + greenyellow: "#adff2f", + burlywood: "#deb887", + seashell: "#fff5ee", + mediumspringgreen: "#00fa9a", + fuchsia: "#ff00ff", + papayawhip: "#ffefd5", + blanchedalmond: "#ffebcd", + chartreuse: "#7fff00", + dimgray: "#696969", + black: "#000000", + peachpuff: "#ffdab9", + springgreen: "#00ff7f", + aquamarine: "#7fffd4", + white: "#ffffff", + orange: "#ffa500", + lightsalmon: "#ffa07a", + darkslategray: "#2f4f4f", + brown: "#a52a2a", + ivory: "#fffff0", + dodgerblue: "#1e90ff", + peru: "#cd853f", + lawngreen: "#7cfc00", + chocolate: "#d2691e", + crimson: "#dc143c", + forestgreen: "#228b22", + darkgrey: "#a9a9a9", + lightseagreen: "#20b2aa", + cyan: "#00ffff", + mintcream: "#f5fffa", + silver: "#c0c0c0", + antiquewhite: "#faebd7", + mediumorchid: "#ba55d3", + skyblue: "#87ceeb", + gray: "#808080", + darkturquoise: "#00ced1", + goldenrod: "#daa520", + darkgreen: "#006400", + floralwhite: "#fffaf0", + darkviolet: "#9400d3", + darkgray: "#a9a9a9", + moccasin: "#ffe4b5", + saddlebrown: "#8b4513", + grey: "#808080", + darkslateblue: "#483d8b", + lightskyblue: "#87cefa", + lightpink: "#ffb6c1", + mediumvioletred: "#c71585", + slategrey: "#708090", + red: "#ff0000", + deeppink: "#ff1493", + limegreen: "#32cd32", + darkmagenta: "#8b008b", + palegoldenrod: "#eee8aa", + plum: "#dda0dd", + turquoise: "#40e0d0", + lightgrey: "#d3d3d3", + lightgoldenrodyellow: "#fafad2", + darkgoldenrod: "#b8860b", + lavender: "#e6e6fa", + maroon: "#800000", + yellowgreen: "#9acd32", + sandybrown: "#f4a460", + thistle: "#d8bfd8", + violet: "#ee82ee", + navy: "#000080", + magenta: "#ff00ff", + dimgrey: "#696969", + tan: "#d2b48c", + rosybrown: "#bc8f8f", + olivedrab: "#6b8e23", + blue: "#0000ff", + lightblue: "#add8e6", + ghostwhite: "#f8f8ff", + honeydew: "#f0fff0", + cornflowerblue: "#6495ed", + slateblue: "#6a5acd", + linen: "#faf0e6", + darkblue: "#00008b", + powderblue: "#b0e0e6", + seagreen: "#2e8b57", + darkkhaki: "#bdb76b", + snow: "#fffafa", + sienna: "#a0522d", + mediumblue: "#0000cd", + royalblue: "#4169e1", + lightcyan: "#e0ffff", + green: "#008000", + mediumpurple: "#9370db", + midnightblue: "#191970", + cornsilk: "#fff8dc", + paleturquoise: "#afeeee", + bisque: "#ffe4c4", + slategray: "#708090", + darkcyan: "#008b8b", + khaki: "#f0e68c", + wheat: "#f5deb3", + teal: "#008080", + darkorchid: "#9932cc", + deepskyblue: "#00bfff", + salmon: "#fa8072", + darkred: "#8b0000", + steelblue: "#4682b4", + palevioletred: "#db7093", + lightslategray: "#778899", + aliceblue: "#f0f8ff", + lightslategrey: "#778899", + lightgreen: "#90ee90", + orchid: "#da70d6", + gainsboro: "#dcdcdc", + mediumseagreen: "#3cb371", + lightgray: "#d3d3d3", + mediumturquoise: "#48d1cc", + lemonchiffon: "#fffacd", + cadetblue: "#5f9ea0", + lightyellow: "#ffffe0", + lavenderblush: "#fff0f5", + coral: "#ff7f50", + purple: "#800080", + aqua: "#00ffff", + whitesmoke: "#f5f5f5", + mediumslateblue: "#7b68ee", + darkorange: "#ff8c00", + mediumaquamarine: "#66cdaa", + darksalmon: "#e9967a", + beige: "#f5f5dc", + blueviolet: "#8a2be2", + azure: "#f0ffff", + lightsteelblue: "#b0c4de", + oldlace: "#fdf5e6", + rebeccapurple: "#663399" + }; + + + /* + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + type = (function() { + + /* + for browser-safe type checking+ + ported from jQuery's $.type + */ + var classToType, len, name, o, ref; + classToType = {}; + ref = "Boolean Number String Function Array Date RegExp Undefined Null".split(" "); + for (o = 0, len = ref.length; o < len; o++) { + name = ref[o]; + classToType["[object " + name + "]"] = name.toLowerCase(); + } + return function(obj) { + var strType; + strType = Object.prototype.toString.call(obj); + return classToType[strType] || "object"; + }; + })(); + + limit = function(x, min, max) { + if (min == null) { + min = 0; + } + if (max == null) { + max = 1; + } + if (x < min) { + x = min; + } + if (x > max) { + x = max; + } + return x; + }; + + unpack = function(args) { + if (args.length >= 3) { + return args; + } else { + return args[0]; + } + }; + + TWOPI = Math.PI * 2; + + PITHIRD = Math.PI / 3; + + round = Math.round, cos = Math.cos, floor = Math.floor, pow = Math.pow, log = Math.log, sin = Math.sin; + + + /* + interpolates between a set of colors uzing a bezier spline + */ + + bezier = function(colors) { + var I, I0, I1, c, lab0, lab1, lab2, lab3, ref, ref1, ref2; + colors = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(chroma(c)); + } + return results; + })(); + if (colors.length === 2) { + ref = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref[0], lab1 = ref[1]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push(lab0[i] + t * (lab1[i] - lab0[i])); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 3) { + ref1 = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref1[0], lab1 = ref1[1], lab2 = ref1[2]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push((1 - t) * (1 - t) * lab0[i] + 2 * (1 - t) * t * lab1[i] + t * t * lab2[i]); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 4) { + ref2 = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref2[0], lab1 = ref2[1], lab2 = ref2[2], lab3 = ref2[3]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push((1 - t) * (1 - t) * (1 - t) * lab0[i] + 3 * (1 - t) * (1 - t) * t * lab1[i] + 3 * (1 - t) * t * t * lab2[i] + t * t * t * lab3[i]); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 5) { + I0 = bezier(colors.slice(0, 3)); + I1 = bezier(colors.slice(2, 5)); + I = function(t) { + if (t < 0.5) { + return I0(t * 2); + } else { + return I1((t - 0.5) * 2); + } + }; + } + return I; + }; + + chroma.interpolate.bezier = bezier; + + + /* + interpolates between a set of colors uzing a bezier spline + + blend mode formulas taken from: + http://www.venture-ware.com/kevin/coding/lets-learn-math-photoshop-blend-modes/ + */ + + blend = function(bottom, top, mode) { + if (!blend[mode]) { + throw 'unknown blend mode ' + mode; + } + return blend[mode](bottom, top); + }; + + blend_f = function(f) { + return function(bottom, top) { + var c0, c1; + c0 = chroma(top).rgb(); + c1 = chroma(bottom).rgb(); + return chroma(f(c0, c1), 'rgb'); + }; + }; + + each = function(f) { + return function(c0, c1) { + var i, o, out; + out = []; + for (i = o = 0; o <= 3; i = ++o) { + out[i] = f(c0[i], c1[i]); + } + return out; + }; + }; + + normal = function(a, b) { + return a; + }; + + multiply = function(a, b) { + return a * b / 255; + }; + + darken = function(a, b) { + if (a > b) { + return b; + } else { + return a; + } + }; + + lighten = function(a, b) { + if (a > b) { + return a; + } else { + return b; + } + }; + + screen = function(a, b) { + return 255 * (1 - (1 - a / 255) * (1 - b / 255)); + }; + + overlay = function(a, b) { + if (b < 128) { + return 2 * a * b / 255; + } else { + return 255 * (1 - 2 * (1 - a / 255) * (1 - b / 255)); + } + }; + + burn = function(a, b) { + return 255 * (1 - (1 - b / 255) / (a / 255)); + }; + + dodge = function(a, b) { + if (a === 255) { + return 255; + } + a = 255 * (b / 255) / (1 - a / 255); + if (a > 255) { + return 255; + } else { + return a; + } + }; + + blend.normal = blend_f(each(normal)); + + blend.multiply = blend_f(each(multiply)); + + blend.screen = blend_f(each(screen)); + + blend.overlay = blend_f(each(overlay)); + + blend.darken = blend_f(each(darken)); + + blend.lighten = blend_f(each(lighten)); + + blend.dodge = blend_f(each(dodge)); + + blend.burn = blend_f(each(burn)); + + chroma.blend = blend; + + + /* + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + chroma.cubehelix = function(start, rotations, hue, gamma, lightness) { + var dh, dl; + if (start == null) { + start = 300; + } + if (rotations == null) { + rotations = -1.5; + } + if (hue == null) { + hue = 1; + } + if (gamma == null) { + gamma = 1; + } + if (lightness == null) { + lightness = [0, 1]; + } + dl = lightness[1] - lightness[0]; + if (type(hue) === 'array') { + dh = hue[1] - hue[0]; + if (dh === 0) { + hue = hue[1]; + } + } else { + dh = 0; + } + return function(fract) { + var a, amp, b, cos_a, g, h, l, r, sin_a; + a = TWOPI * ((start + 120) / 360 + rotations * fract); + l = pow(lightness[0] + dl * fract, gamma); + h = dh !== 0 ? hue[0] + fract * dh : hue; + amp = h * l * (1 - l) / 2; + cos_a = cos(a); + sin_a = sin(a); + r = l + amp * (-0.14861 * cos_a + 1.78277 * sin_a); + g = l + amp * (-0.29227 * cos_a - 0.90649 * sin_a); + b = l + amp * (+1.97294 * cos_a); + return chroma(clip_rgb([r * 255, g * 255, b * 255])); + }; + }; + +}).call(this); diff --git a/base_geoengine/static/lib/geostats-1.4.0/geostats.css b/base_geoengine/static/lib/geostats-1.4.0/geostats.css new file mode 100644 index 000000000..cba5b487a --- /dev/null +++ b/base_geoengine/static/lib/geostats-1.4.0/geostats.css @@ -0,0 +1,23 @@ +.geostats-legend div { + margin:3px 10px 5px 10px +} + +.geostats-legend-title { + font-weight: bold; + margin-bottom: 4px; +} + +.geostats-legend-block { + border: 1px solid #555555; + display: block; + float: left; + height: 12px; + margin: 0 5px 0 20px; + width: 20px; +} + +.geostats-legend-counter { + font-size: 0.8em; + color:#666; + font-style: italic; +} diff --git a/base_geoengine/static/lib/geostats-1.4.0/geostats.js b/base_geoengine/static/lib/geostats-1.4.0/geostats.js new file mode 100755 index 000000000..f099ce5a8 --- /dev/null +++ b/base_geoengine/static/lib/geostats-1.4.0/geostats.js @@ -0,0 +1,1190 @@ +/** +* geostats() is a tiny and standalone javascript library for classification +* Project page - https://github.com/simogeo/geostats +* Copyright (c) 2011 Simon Georget, http://www.empreinte-urbaine.eu +* Licensed under the MIT license +*/ + + +(function (definition) { + // This file will function properly as a - - - - - - - - -
-
-
-
-
-

- Prerequisite -

-
-
-
-
-
-
-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/api_doc.html b/base_geoengine/doc/build/api_doc.html deleted file mode 100644 index 67b55a830..000000000 --- a/base_geoengine/doc/build/api_doc.html +++ /dev/null @@ -1,775 +0,0 @@ - - - - - - - API — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - -
-
-
-
-
-

- API -

-
- -

- GeoColumns -

-
-
- class base_geoengine.geo_field.Geom(string, - geo_type, dim=2, srid=900913, - gist_index=True, **args) -
-
-

- This class adds a new type of columns to ORM. It enable POSTGIS - geometry type support. -

-
-
- create_geo_column(cursor, col_name, geo_column, - table, model) -
-

Create a columns of type the geom

-
- -
-
- entry_to_shape(value, same_type=False) -
-

Transform input into an object

-
- -
-
- load_geo(wkb) -
-
-

- This function is used to load geometry into browse record - after read was done -

-
-
- -
-
- manage_db_column(cursor, col_name, geo_columns, - table, model) -
-

In charge of managing geom column type

-
- -
-
- set(cr, - obj, res_id, name, value, - user=None, context=None) -
-
-

- This function used to write and create value into database - value can be geojson, wkt, shapely geomerty object. If - geo_direct_write in context you can pass diretly WKT -

-
-
- -
-
- set_geo(value) -
-
-

- This function is used to transform data in order to be - compatible with the create function. It is also use in - expression.py in order to represent value. -

-
-
- -
-
- update_geo_column(cursor, col_name, geo_column, - table, model) -
-
-

- Update a column of type the geom does. !! not do a lot of test - yet -

-
-
-
-
- - -
-
- class base_geoengine.geo_point.GeoPoint(string, - dim=2, srid=900913, gist_index=True, - **args) -
-
-

- This class adds a new type of columns to ORM. It enables POSTGIS - geometry type support -

-
-
- - -
-
- class base_geoengine.geo_line.GeoLine(string, - dim=2, srid=900913, gist_index=True, - **args) -
-
-

- This class adds a new type of columns to ORM. It enables POSTGIS - geometry type support -

-
-
- - -
-
- class base_geoengine.geo_multiline.GeoMultiLine(string, - dim=2, srid=900913, gist_index=True, - **args) -
-
-

- This class adds a new type of columns to ORM. It enables POSTGIS - geometry type support -

-
-
- - -
-
- class base_geoengine.geo_polygon.GeoPolygon(string, - dim=2, srid=900913, gist_index=True, - **args) -
-
-

- This class adds a new type of columns to ORM. It enables POSTGIS - geometry type support -

-
-
- - -
-
- class base_geoengine.geo_multipolygon.GeoMultiPolygon(string, dim=2, srid=900913, - gist_index=True, **args) -
-
-

- This class adds a new type of columns to ORM. It enables POSTGIS - geometry type support -

-
-
-
-
- -

- View Management -

-

Module that manages map view and vector/raster layer

- -
-
-

- GEO ORM MODEL -

-
-
- class base_geoengine.geo_model.GeoModel(pool, - cr) -
-
-
-
- fields_get(cursor, - uid, allfields=None, context=None) -
-

Add geo_type definition for geo fields

-
- -
-
- fields_view_get(cursor, uid, view_id=None, - view_type='form', context=None, - toolbar=False, submenu=False) -
-
-

- Returns information about the available fields of the class. - If view type == ‘map’ returns geographical columns - available -

-
-
- -
- -
-

- Perform a geo search it allows direct domain: geo_search(r, - uid, domaine=[(‘name’, ‘ilike’, - ‘toto’]), geo_domain=[(‘the_point’, - ‘geo_intersect’, myshaply_obj or mywkt or - mygeojson)]. -

-

- We can also support indirect geo_domain (‘geom’, - ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }). -

-
-
The supported operators are :
-
-
    -
  • geo_greater
  • -
  • geo_lesser
  • -
  • geo_equal
  • -
  • geo_touch
  • -
  • geo_within
  • -
  • geo_intersect
  • -
-
-
-
-
-
-
-
-
- -

- GEO ORM OPERATORS -

-
- -
-

- Perform a geo search it allows direct domain: geo_search(r, uid, - domaine=[(‘name’, ‘ilike’, - ‘toto’]), geo_domain=[(‘the_point’, - ‘geo_intersect’, myshaply_obj or mywkt or mygeojson)] -

-

- We can also support indirect geo_domain (‘geom’, ‘geo_operator’, - {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) -

-
-
The supported operators are :
-
-
    -
  • geo_greater
  • -
  • geo_lesser
  • -
  • geo_equal
  • -
  • geo_touch
  • -
  • geo_within
  • -
  • geo_intersect
  • -
-
-
-
-
- -
-
- class base_geoengine.geo_operators.GeoOperator(geo_field) -
-
-
-
- get_geo_equal_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_equal operator

-
- -
-
- get_geo_greater_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_greater operator

-
- -
-
- get_geo_intersect_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_intersec operator

-
- -
-
- get_geo_lesser_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_lesser operator

-
- -
-
- get_geo_touch_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_touch operator

-
- -
-
- get_geo_within_sql(table, col, value, - rel_col=None, rel_model=None) -
-

Returns raw sql for geo_within operator

-
- -
-
- get_rel_field(rel_col, rel_model) -
-
-

- Retrieves the expression to use in PostGIS statement for a - spatial rel search -

-
-
-
-
-
-
- -

- GEO helper -

-
-
- base_geoengine.geo_helper.geo_convertion_helper.value_to_shape(value) -
-

Transforms input into a Shapely object.

-
-
-
-
-
-
-
-
-

Table Of Contents

- - -

Previous topic

-

- Postgisify an exisiting database -

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/genindex.html b/base_geoengine/doc/build/genindex.html deleted file mode 100644 index 600d02249..000000000 --- a/base_geoengine/doc/build/genindex.html +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - Index — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - -
-
-
-
-

Index

- -
- B - | C | - E | - F | - G | - L | - M | - S | - U | V -
-

B

- - - - - -
-
-
- base_geoengine.geo_field (module) -
- -
- base_geoengine.geo_helper.geo_convertion_helper (module) -
- -
- base_geoengine.geo_line (module) -
- -
- base_geoengine.geo_multiline (module) -
- -
- base_geoengine.geo_multipolygon (module) -
- -
- base_geoengine.geo_operators (module) -
-
-
-
-
- base_geoengine.geo_point (module) -
- -
- base_geoengine.geo_polygon (module) -
- -
- base_geoengine.geo_view (module) -
- -
- base_geoengine.geo_view.geo_raster_layer (module) -
- -
- base_geoengine.geo_view.geo_vector_layer (module) -
- -
- base_geoengine.geo_view.ir_view (module) -
-
-
- -

C

- - - - -
-
-
- create_geo_column() (base_geoengine.geo_field.Geom method) -
-
-
- -

E

- - - - -
-
-
- entry_to_shape() (base_geoengine.geo_field.Geom method) -
-
-
- -

F

- - - - - -
-
-
- fields_get() (base_geoengine.geo_model.GeoModel method) -
-
-
-
-
- fields_view_get() (base_geoengine.geo_model.GeoModel method) -
-
-
- -

G

- - - - - -
-
-
- geo_search() (base_geoengine.geo_model.GeoModel method) -
- -
-
-
- (in module base_geoengine.geo_operators) -
-
-
- -
- GeoLine (class in base_geoengine.geo_line) -
- -
- Geom (class in base_geoengine.geo_field) -
- -
- GeoModel (class in base_geoengine.geo_model) -
- -
- GeoMultiLine (class in base_geoengine.geo_multiline) -
- -
- GeoMultiPolygon (class in base_geoengine.geo_multipolygon) -
- -
- GeoOperator (class in base_geoengine.geo_operators) -
- -
- GeoPoint (class in base_geoengine.geo_point) -
-
-
-
-
- GeoPolygon (class in base_geoengine.geo_polygon) -
- -
- get_geo_equal_sql() (base_geoengine.geo_operators.GeoOperator - method) -
- -
- get_geo_greater_sql() (base_geoengine.geo_operators.GeoOperator - method) -
- -
- get_geo_intersect_sql() - (base_geoengine.geo_operators.GeoOperator method) -
- -
- get_geo_lesser_sql() (base_geoengine.geo_operators.GeoOperator - method) -
- -
- get_geo_touch_sql() (base_geoengine.geo_operators.GeoOperator - method) -
- -
- get_geo_within_sql() (base_geoengine.geo_operators.GeoOperator - method) -
- -
- get_rel_field() (base_geoengine.geo_operators.GeoOperator - method) -
-
-
- -

L

- - - - -
-
-
- load_geo() (base_geoengine.geo_field.Geom method) -
-
-
- -

M

- - - - -
-
-
- manage_db_column() (base_geoengine.geo_field.Geom method) -
-
-
- -

S

- - - - - -
-
-
- set() (base_geoengine.geo_field.Geom method) -
-
-
-
-
- set_geo() (base_geoengine.geo_field.Geom method) -
-
-
- -

U

- - - - -
-
-
- update_geo_column() (base_geoengine.geo_field.Geom method) -
-
-
- -

V

- - - - -
-
-
- value_to_shape() (in module - base_geoengine.geo_helper.geo_convertion_helper) -
-
-
-
-
-
-
-
- - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/index.html b/base_geoengine/doc/build/index.html deleted file mode 100644 index 38b55564f..000000000 --- a/base_geoengine/doc/build/index.html +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - Welcome to OpenERP GeoEngine’s documentation! — OpenERP GeoEngine 0.3 - documentation - - - - - - - - - - - - - - - -
-
-
-
-
-

- Welcome to OpenERP GeoEngine’s documentation! -

-

Contents:

- -
-
-

- Indices and tables -

- -
-
-
-
-
-
-

Table Of Contents

- - -

Next topic

-

- What is GeoEngine ? -

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/installation.html b/base_geoengine/doc/build/installation.html deleted file mode 100644 index a80c40adb..000000000 --- a/base_geoengine/doc/build/installation.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - Installation — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - - -
-
-
-
-
-

- Installation -

-
-

- PostGIS database template -

-

- In order to create databases from the OpenERP client, you have to - create a PostGis database template. Under windows, this template is - already available in installer. -

-

- On other *NIX, system you simply have to launch the create_postgis_template.sh - script available in the base_geoengine module in the scripts folder. - This should be done by a PostgreSQL superuser. -

-

In order to test the success:

-
-
-psql -l
-template_postgis | owner | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
-
-

- If you want to install GeoEngine on an exisiting database, please - refer to the Postgisify section. -

-
-
-

- OpenERP -

-

Add the template as an argument to OpenERP server:

-
-
-
--db-template=template_postgis
-
-
-
-

or in config file:

-
-
-
db_template = template_postgis
-
-
-
-

Do not forget to add the GeoEngine modules to your addons path.

-

- Then install (eventually update module list) the base GeoEngine module - form the OpenERP client. -

-
-
-
-
-
-
-
-

Table Of Contents

- - -

Previous topic

-

- Prerequisites -

-

Next topic

-

- Postgisify an exisiting database -

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/objects.inv b/base_geoengine/doc/build/objects.inv deleted file mode 100644 index e054944429407487424e785ed28ed31a8ed50e21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 638 zcmV-^0)hP_AX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkUaAj^q zQcxgAWp71pXK8L_3L_v^WpZ_Ab7^j8AbM*2P1yxCOA4fPxylldz}8wmmwDen$o9G#+ZLsNoHu&s|(r zTJ69%snuwuQoE6894%9#Um9;)FTBqM## zFzGIlkc|rPjxL$Tsig(Tw{hc7V$m3U^c z*ssqSt&m%rf)(1q3Fvj~4JjzG83ly(u`8uSpQ|v{W@=h)YGZy`AXw}B9z_>Ziu62P z(=vb;({(PTCcn - - - - - - - Postgisify an exisiting database — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - - - -
-
-
-
-
-

- Postgisify an exisiting database -

-

- If you want to install the GeoEngine on an existing database, you have - to run the sql commands available in the base_geoengine module under the - postgis_sql folder using a PostgreSQL super user: -

-
-
-psql -U superuser my database -f postgis.sql
-psql -U superuser my database -f spatial_ref_sys.sql
-
-

- In order to test if the installation is sucessfull log into you database - and: -

-
-
-SELECT * from GEOMETRY_COLUMNS;
-SELECT * from spatial_ref_sys;
-
-
-
-
-
-
-
-

Previous topic

-

- Installation -

-

Next topic

-

API

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/prerequisite.html b/base_geoengine/doc/build/prerequisite.html deleted file mode 100644 index 32f676fd4..000000000 --- a/base_geoengine/doc/build/prerequisite.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - Prerequisites — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - - -
-
-
-
-
-

- Prerequisites -

-
-

- Python -

-

geojson:

-
pip install geojson
-

Shapely:

-
-
pip install Shapely==1.2.13
-
-

For Mac user: do not forget the following directive:

-
-
-
ARCHFLAGS="-arch i386 -arch x86_64"
-
-
-
-
-
-

- PostGIS 1.5 -

-

- Please refer to - PostGIS installation directive - or to your OS package system. -

-
-
-
-
-
-
-
-

Table Of Contents

- - -

Previous topic

-

- What is GeoEngine ? -

-

Next topic

-

- Installation -

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/py-modindex.html b/base_geoengine/doc/build/py-modindex.html deleted file mode 100644 index 4fc4efcc8..000000000 --- a/base_geoengine/doc/build/py-modindex.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - - Python Module Index — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - -
-
-
-
-

Python Module Index

- -
- b -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- b -
- - - base_geoengine - - -
-     - base_geoengine.geo_field - - -
-     - base_geoengine.geo_helper.geo_convertion_helper - - -
-     - base_geoengine.geo_line - - -
-     - base_geoengine.geo_multiline - - -
-     - base_geoengine.geo_multipolygon - - -
-     - base_geoengine.geo_operators - - -
-     - base_geoengine.geo_point - - -
-     - base_geoengine.geo_polygon - - -
-     - base_geoengine.geo_view - - -
-     - base_geoengine.geo_view.geo_raster_layer - - -
-     - base_geoengine.geo_view.geo_vector_layer - - -
-     - base_geoengine.geo_view.ir_view - - -
-
-
-
-
-
- - -
-
-
-
- - - - diff --git a/base_geoengine/doc/build/search.html b/base_geoengine/doc/build/search.html deleted file mode 100644 index 20e90b731..000000000 --- a/base_geoengine/doc/build/search.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - Search — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - - -
-
-
-
-

Search

-
- -

Please activate JavaScript to enable the search functionality.

-
-

- From here you can search these documents. Enter your search words into the - box below and click "search". Note that the search function will - automatically search for all of the words. Pages containing fewer words - won't appear in the result list. -

-
- - - -
- -
-
-
-
-
-
-
-
-
- - - - diff --git a/base_geoengine/doc/build/searchindex.js b/base_geoengine/doc/build/searchindex.js deleted file mode 100644 index 1fd753e72..000000000 --- a/base_geoengine/doc/build/searchindex.js +++ /dev/null @@ -1,357 +0,0 @@ -Search.setIndex({ - objects: { - "base_geoengine.geo_operators": { - geo_search: [3, 2, 1, ""], - GeoOperator: [3, 3, 1, ""], - }, - "base_geoengine.geo_field": {Geom: [3, 3, 1, ""]}, - base_geoengine: { - geo_multiline: [3, 0, 1, ""], - geo_polygon: [3, 0, 1, ""], - geo_multipolygon: [3, 0, 1, ""], - geo_operators: [3, 0, 1, ""], - geo_line: [3, 0, 1, ""], - geo_field: [3, 0, 1, ""], - geo_point: [3, 0, 1, ""], - geo_view: [3, 0, 1, ""], - }, - "base_geoengine.geo_view": { - ir_view: [3, 0, 1, ""], - geo_vector_layer: [3, 0, 1, ""], - geo_raster_layer: [3, 0, 1, ""], - }, - "base_geoengine.geo_multiline": {GeoMultiLine: [3, 3, 1, ""]}, - "base_geoengine.geo_model.GeoModel": { - geo_search: [3, 1, 1, ""], - fields_view_get: [3, 1, 1, ""], - fields_get: [3, 1, 1, ""], - }, - "base_geoengine.geo_helper": {geo_convertion_helper: [3, 0, 1, ""]}, - "base_geoengine.geo_helper.geo_convertion_helper": { - value_to_shape: [3, 2, 1, ""], - }, - "base_geoengine.geo_multipolygon": {GeoMultiPolygon: [3, 3, 1, ""]}, - "base_geoengine.geo_line": {GeoLine: [3, 3, 1, ""]}, - "base_geoengine.geo_field.Geom": { - create_geo_column: [3, 1, 1, ""], - set: [3, 1, 1, ""], - set_geo: [3, 1, 1, ""], - update_geo_column: [3, 1, 1, ""], - entry_to_shape: [3, 1, 1, ""], - manage_db_column: [3, 1, 1, ""], - load_geo: [3, 1, 1, ""], - }, - "base_geoengine.geo_polygon": {GeoPolygon: [3, 3, 1, ""]}, - "base_geoengine.geo_model": {GeoModel: [3, 3, 1, ""]}, - "base_geoengine.geo_operators.GeoOperator": { - get_geo_greater_sql: [3, 1, 1, ""], - get_rel_field: [3, 1, 1, ""], - get_geo_within_sql: [3, 1, 1, ""], - get_geo_intersect_sql: [3, 1, 1, ""], - get_geo_equal_sql: [3, 1, 1, ""], - get_geo_lesser_sql: [3, 1, 1, ""], - get_geo_touch_sql: [3, 1, 1, ""], - }, - "base_geoengine.geo_point": {GeoPoint: [3, 3, 1, ""]}, - }, - terms: { - oper: [3, 0], - create_geo_column: 3, - code: [], - forget: [2, 5], - just: [], - show: 4, - api: [3, 0], - queri: 4, - geo_touch: 3, - my_funct: [], - shape: [3, 5], - myshaply_obj: 3, - archflag: 5, - entry_to_shap: 3, - follow: 5, - geocolumn: [3, 0], - yet: 3, - postggi: 4, - geooper: 3, - postgis_sql: 1, - field: 3, - brows: 3, - configur: 4, - should: 2, - add: [3, 4, 2], - busi: 4, - under: [1, 2], - input: 3, - folder: [1, 2], - create_postgis_templ: 2, - template_postgi: 2, - string: 3, - python: [0, 5], - nix: 2, - databs: [], - col_nam: 3, - none: 3, - get_geo_equal_sql: 3, - datasourc: 4, - utf: 2, - geometry_column: 1, - geo: [3, 0], - geo_equ: 3, - geo_direct_writ: 3, - wont: [], - dim: 3, - document: 0, - name: 3, - success: 2, - sucess: [], - list: 2, - geograph: 3, - geomodel: 3, - get_geo_within_sql: 3, - view_typ: 3, - vector: 3, - geo_within: 3, - have: [1, 2], - geomerti: 3, - complet: 4, - geo_model: 3, - page: 0, - view: [3, 0], - pleas: [2, 5], - x86_64: 5, - domain: 3, - set: 3, - geo_domain: 3, - abil: [], - gist_index: 3, - geomultipolygon: 3, - direct: [3, 5], - geo_search: 3, - pass: 3, - geoengin: [0, 1, 2, 4], - indirect: 3, - server: 2, - geo_less: 3, - compat: 3, - index: 0, - what: [0, 4], - toto: 3, - helper: [3, 0], - charg: 3, - databas: [3, 0, 1, 2, 4], - section: 2, - definit: 3, - content: 0, - geo_point: 3, - i386: 5, - stuff: [], - geom: 3, - poli: 3, - rel: 3, - allfield: 3, - print: [], - new: 3, - geo_typ: 3, - res_id: 3, - refer: [2, 5], - after: 3, - run: 1, - extend: 4, - view_id: 3, - same_typ: 3, - extens: 4, - pip: 5, - base: 2, - geo_great: 3, - prerequisit: [0, 5], - offset: 3, - postgi: [0, 1, 2, 3, 4, 5], - path: 2, - super: 1, - valu: 3, - load_geo: 3, - raster: 3, - search: [3, 0], - spatial_ref_si: 1, - postgresql: [1, 2], - allreadi: [], - launch: 2, - column: [3, 4], - geopoint: 3, - technolog: 4, - mac: 5, - manag: [3, 0], - orm: [3, 0, 4], - context: 3, - act: 4, - geometri: 3, - the_point: 3, - col: 3, - mywkt: 3, - load: 3, - serach: [], - fields_view_get: 3, - simpli: 2, - get_geo_greater_sql: 3, - modul: [3, 0, 1, 2, 4], - contect: [], - transform: 3, - srid: 3, - geo_polygon: 3, - done: [3, 2], - owner: 2, - openlay: 4, - fields_get: 3, - your: [4, 2, 5], - select: 1, - geo_multipolygon: 3, - from: [1, 2], - log: 1, - zip: 3, - script: 2, - openerp: [0, 2, 4], - data: [3, 4], - support: 3, - update_geo_column: 3, - geo_lin: 3, - system: [2, 5], - geo_field: 3, - avail: [3, 1, 2], - reli: 4, - window: 2, - toolbar: 3, - lot: 3, - base_geoengin: [3, 1, 2], - instal: [0, 1, 2, 5], - store: 4, - fals: 3, - function: 3, - head: [], - wkb: 3, - db_templat: 2, - statement: 3, - geolin: 3, - capabilit: 4, - en_u: 2, - enabl: 3, - about: 3, - you: [3, 4, 1, 2], - visual: 4, - indic: 0, - alreadi: 2, - obj: 3, - value_to_shap: 3, - true: 3, - addon: 2, - psql: [1, 2], - geo_multilin: 3, - word: 4, - look: [], - raw: 3, - provid: 4, - type: 3, - work: [], - cursor: 3, - record: 3, - limit: 3, - can: 3, - rel_model: 3, - rel_col: 3, - def: [], - layer: [3, 4], - uid: 3, - creat: [3, 2], - geo_intersec: 3, - retriev: 3, - arg: 3, - argument: 2, - templat: [0, 2], - repres: [3, 4], - geobi: 4, - exist: 1, - file: 2, - tabl: [3, 0], - get_geo_lesser_sql: 3, - return: 3, - postgisifi: [0, 1, 2], - get_geo_touch_sql: 3, - packag: 5, - geopolygon: 3, - form: [3, 2], - want: [1, 2], - inform: [3, 4], - perform: [3, 4], - titl: [], - ilik: 3, - geojson: [3, 5], - wkt: 3, - write: 3, - also: [3, 4], - other: [4, 2], - read: 3, - spatial: [3, 4], - test: [3, 1, 2], - geo_help: 3, - eventu: 2, - config: 2, - geo_intersect: 3, - updat: [3, 2], - get_geo_intersect_sql: 3, - map: [3, 4], - express: 3, - thi: [3, 2], - set_geo: 3, - object: 3, - sucessful: 1, - superus: [1, 2], - manage_db_column: 3, - diretli: 3, - succ: [], - geo_column: 3, - user: [3, 1, 5], - exisit: [0, 1, 2], - sql: [3, 1], - mygeojson: 3, - arch: 5, - class: 3, - pool: 3, - welcom: 0, - submenu: 3, - utf8: 2, - get_rel_field: 3, - geomultilin: 3, - doe: 3, - geo_convertion_help: 3, - receiv: [], - client: 2, - command: 1, - allow: [3, 4], - geo_oper: 3, - model: [3, 0, 4], - order: [3, 1, 2], - }, - objtypes: {0: "py:module", 1: "py:method", 2: "py:function", 3: "py:class"}, - titles: [ - "Welcome to OpenERP GeoEngine’s documentation!", - "Postgisify an exisiting database", - "Installation", - "API", - "What is GeoEngine ?", - "Prerequisites", - ], - objnames: { - 0: ["py", "module", "Python module"], - 1: ["py", "method", "Python method"], - 2: ["py", "function", "Python function"], - 3: ["py", "class", "Python class"], - }, - filenames: [ - "index", - "postgisify", - "installation", - "api_doc", - "what_is_geoengine", - "prerequisite", - ], -}); diff --git a/base_geoengine/doc/build/what_is_geoengine.html b/base_geoengine/doc/build/what_is_geoengine.html deleted file mode 100644 index 580002120..000000000 --- a/base_geoengine/doc/build/what_is_geoengine.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - What is GeoEngine ? — OpenERP GeoEngine 0.3 documentation - - - - - - - - - - - - - - - -
-
-
-
-
-

- What is GeoEngine ? -

-

- GeoEngine is an OpenERP module that adds spatial/GIS capabilites to - OpenERP. It will allow you to : -

-
    -
  • Visualize and query your business information on map
  • -
  • Perform GeoBI and spatial query
  • -
  • Configure your spatial layers and spatial datasources
  • -
  • Extend OpenERP models with spatial columns
  • -
-

- GeoEngine relies on - OpenLayers - and - PostgGIS - technologies. -

-

- Postgis is used to store spatial information in databases. OpenLayer is - used to represent spatial data in other words to show maps. The - GeoEngine module acts as a data provider and as an OpenLayers - configurator. It also provides a complete extension to OpenERP ORM. -

- _images/core_architecture.jpg -
-
-
-
-
-
-

Previous topic

-

- Welcome to OpenERP GeoEngine’s documentation! -

-

Next topic

-

- Prerequisites -

-

This Page

- - - -
-
-
-
- - - - diff --git a/base_geoengine/doc/make.bat b/base_geoengine/doc/make.bat deleted file mode 100644 index ee7469def..000000000 --- a/base_geoengine/doc/make.bat +++ /dev/null @@ -1,170 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenERPGeoEngine.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenERPGeoEngine.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/base_geoengine/doc/source/_static/_images/core_architecture.jpg b/base_geoengine/doc/source/_static/_images/core_architecture.jpg deleted file mode 100644 index 326593defeb882307dbbc49532f17c86a7e24b42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114343 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

rfkFL#zrjKrvHG-qg}uIeDg> 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

+

Geospatial support for Odoo

+ + +

Beta License: AGPL-3 OCA/geospatial Translate me on Weblate Try me on Runbot

+

Geospatial support based on PostGIS add the ability of server to server +geojson to do geo CRUD and view definition.

+

Table of contents

+ +
+

Installation

+

To install this module, you need to have PostGIS installed.

+

On Ubuntu:

+
+sudo apt-get install postgis
+
+

The module also requires two additional python libs:

+ +

for a complete documentation please refer to the public documenation

+
+
+

Usage

+
+
+

Important changes in version 11

+

The geometry attributes must now be explicitly mentioned in the list of fields of +the XML geoengine view definitions. For instance:

+
+<record id="some_model_geo_view" model="ir.ui.view">
+  <field name="name">Some data view</field>
+  <field name="model">some.model</field>
+  <field name="arch" type="xml">
+    <geoengine>
+      <field name="name" select="1"/>
+      <field name="the_geom"/>
+    </geoengine>
+  </field>
+</record>
+
+
+
+

Known issues / Roadmap

+
    +
  • Google layers have been removed as it was not working anyway.
  • +
  • Switching from map to form view should be eased to open selected feature. +It should work using do_switch_view and this probably requires to set self.dataset.index
  • +
  • A good way to open a record from map should be done with double click. +However selection handlers have difficulties to work nice with click events.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/geospatial project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+i;2U@GGDq_zL z^G+H@nes!Ry6X%V$13%3?cL()OrCAfLxr&{>Sg^!DpfK{HfCm&>Vnxb@9Gnu>pfM2 zEDyh=s6sIuaA(5yS4MIk>mnY`sXMwiOjV+%$CjN_-YCE^jAGH?ygMi6pwc&tx}WxZ zN-Yehiyv$RYZvHm3_hI9eePCf87dNKIju?a+oO>UqX)8hih7KU%*^j=g(<}gzI)?7 za^;>j&*bv0DPFwUy={l)#=YG}*fXj2{^%^5*W^X@!%8?!2cdE??78svRbtEM5(@ms zyHJ;A%y=z>lTel?6J|>PGE=gTJ)Sn;az*s z?+fYqu0r)A?g}sKyWJJoJeoE--<12ry%8&Z5}tS22!1Z%jQoDVvaKM9$A|-_v$nWf zrU0+rFi*p0>eQP+A^$DxI%eOKYF59Ac%(IYrb`eEqr$yw6>b7*`|Z6;O798_wmmF18gOCMONtLSK6$$OaYNOU zZKsABPUp0G&I`b>=j$%~enFxJn!h}4u__4dWXB<@0QhFAAE)sI83&o7f{+=cs=@0a=2 z#xa$ZL@{5RR^=a!=nM4SD}2K1Es*UGKgy}*!?!l7OsIRuoyMp|T4QE)dyw%c!b`=0 z2hR7;4f}gvu@9-nQ0X~(-gIU7fG|Y|Ja#Uq)8+B&^p!C{5lHMxg}$gt1=M1;G>=1& zrnk*`{<3}QH0q2L{htUj?gEi$q9i8C!`=!(K9$i*5G9_8Ol!!cQvj|MVqXB=qf0*b z(i&hQb!?{GlNqgfFz#cv;w;xQPOeIgK8_ft=NBaiyI(ZC-@D?Dree8SUH3?AjSy zLtw!Muj|k+bKV$-IQV0%tNHQyN2CvM<%M`&C?OXeB|`CDR>(Z!ZDreD!j*<@m94EO z&GGeBZtV#wXq5;@sHlu>B|A2tg*@9RN7pYuce?k{Qme@^=R?r{S1#x)?< zP1W_P>GlDkS`vZ{XCvj>J$v)9znz$KlKW+B$17S8c$mihawvU)MWmK?CU8E?np7t~ z?xQ1I!Rs~zS%@R(&jVcbmSDb03k_W$X!!_6KOEW^f7GHrX{CgE_yzv}b@)3(M^x1U z#+Yc$Y7U{}3{t9#dN0hJg9eHxb`gz%EyJLaFI{r+xFBGL_y%DVJ*{F*q1$NGs3MF+ z^Htkz_AvTVq^vom7qk%B(79zXdAfL+9ARcl4?~wW$$0j_4q`il3jM!B7Ly5xSSKp^ zuZQEaB@b@~srLh)Ph%VsZ_r1S#{f_Es`SR1wtjzvIn*~2xG(2 zdJ{_KPY$n_gGQp~bge)SX2-}8lz7_u&P}3dQVn6?FqHKADIY$j2}W0G_0GV27?+0% zGE=UgFw3v1D0zKM{$9fqk-7$m((yz5xzBUSEbbS&K^nYDAp|OjQuTb{%!qpVb1@5c z^o52e&6I*q)C8^)r7$kv@VBn+q)vkoRVB$xXTC=6kmA?2mCNS!d3pUBDw-50FHTs;m1|A4NuBiUVs@ z<)GvPF94+Q6!meTaCZgg2 z=xoTcPns&!hMajl|0Su_1lpoOEiqnbQ@<_+@Od9pq6f=u@9&T^snB61l>huxESS8D zvBM>+IiIYTr&#rzpRVucL!II{b!i<0GPy)b_GAxzg*8YfcX5Zsf4bePv<#iNLeACf zGXt0)o8zEugri0Ks*6 zQ96c&uA>(Re8s~oSb&?NI!QRL>Qv?UZi(6NC1pe90GtT&jwhv7s}M$1+pHkozM%B7O9Vwe^$@gSxG#|5Sji7L}RNV@3!u>>6v%sNQ3$$aH;O z-o$4( zE%^u5+|L@nsB=5Uz28HZ{7l#aamQNxVuypxC11;F8GsbrHH}aleLOgDqPzce;J|Rf zzYd&E5DmWFy+a$*{~eMWzT;Dg5WxeT{W&aj0YN(rwlNEoFk!DQV(wK=OnZ(bD$v_q z0uv8gI{;ej<}(m}<6$+Agfw7bP00Ot;hU;311xiV3S8#0LrM8tt~Z}f$T1k*@k8lA zF4^!?w%&_XBV=(lxfrvK~;&e``VJjT@2fC7ZF=177~V+vH|D-?>xap zU9-uEiEBw@HWpMTiQZL-yfad2L;YEo|ktoV>}#~ zNq=dRkzxwA(L9EW2$oZEJf(^z&y%oY8h>VnL#Kvcz*&u9`ima z=nyGa^Oy!Tu}s$9^ZrHxZM8M0_02VgY|elF!Q$s-kH@(1MJRQe@gQJi(|cB=IG;KU zoWtbES1%=lJ(XX}A|1pP9-|avX#E{R8$3w%K^z0~ zK-2}$73RRv&Pb9RF^`RBA<8o7!|BsEa$tV1+DUw z!1yPV9S*N0w$FzNTxpjpq;TuVg*Jr___{#usfRQ7k2br-Ue;!Ln}M{a5KW{~$0QN1Tms;VS}d?8zb7+AfVkgL zm_VhW1GI{%bwtA%cWLshe+?$J4~8c_GO>*>lt@cf!X#<9c}Rag_L`vjAWXns zi?ya?4kSjogCQ5uEkD0za_j_WmDTG?60(|g;T-GPrH$57Wi1i)NrBCqw|%LpjHFIL z)3f&jT@zCK&X{eRcd7bRHI$&6|H>t{H88tu(4(4RYmS%T4qfZg767;PX#$RR_5;iP z;&%vHR*5Le^9)fn2_^EP!O^^-RPcas)d6nfMRui;8>c3&Gkr!hoOfm+jGY9(Bw#06 z0un6C-&+Aqf>sLdFCXqF{h=qmKVI{)}ZoCEO7p{Go5kt_1{AWa*Fx%!yA z=;P3r6DIT>A;H&NlENCP(nM$aNC&+o!Ek z){w4KWVTMEpBxi(g9a?hZUF;md~nfv3x+|iNKQ5!=Y@q5PbxJ$Mbt~Cd882#%g{Bf zONm(oepbAzVG8-uiSu-yj4X2=rdriby*PMvrOuGh?#sf>l|TFRdYnf_X9J%ocC88h z+!oa?`K%A5o;MtPqvOtlf58*DEO!DvkIQjaLZs_1lq*!;R6tm#jeg9N&u`%#zItl7 zKe&r#=JJ6H2@IOOL}hG@)&o5uB~-+Sc%f6kiLkBBOK056s2E1Av%R_|`mKc7+~Ivi zWnyj~>ZrHnZ>>Nm8%b3C$IoHMT?M2m$(Y! z7SzvK=RRQb)@zLCY0(HY=2bS_NSZ|WdYR{LDjHW>RRe8I!4P3D=fWx=W@D8 z!sWp$i8jS1755D7Gf!njb?{bLQG>kdl0JI|A8oD85--g%r-D+3VmJ#N4?NESfM*j}X}2Sm33cVK^q-=uZ}M z7m*W{W0HWG_sQfgowS>=A+VFsl7YrORaZLJv($r;C6ki%1>Yg+<$mN)S;Mt8c^3Bt z8MJQ7EZN@W3pmPclRDNj3|*2sJFi13W?csvyDi6AD)l^2v20`yXhXE-;YHW}BqJBo z2L}ZcY$mLOk9|9y?m+9yovY-ME)?`?^DM2PNTD}4}re3OJUydFD)-yJ#RwG8~w-hH-|%DPz>=sX^rup0g*Av!OMWE1qUHT1LtnIe`Zu zvV4|tdGX^$XF2^gWV@?!GsFGzC>>e9t;&}wCb5iZ1#S}^0K?Ol~$;xiu^4nXA zJ$n1iT9cPQ4$>986L=N?*Nhb!c_lMObZGh%si zqdlpQZ@Z^FJDv@36B2SR2_g&QW3G~3C*r-5ENm@31>&#dSNnbx;LAB>^vl9>7LWk zK&cb1Pu&c}Bc0Nw;1|j5<7`9(ma^GX7}FV;fSE?)P8TKTTY54pD}c0|DZ~+Kr_jc* zMkW>MLvoMga}(1kKe>BgN_4! ziT?~^oioCWD5s5I5g3MBtR4SkX2;I-`iyML{kr3auF&t#wK?IC8!vwGHfC^{cGAt9 zVOydiNoS#xb*|*_C!xw9BrfzGh(yOrS-2MDoYoLtF_qQ`7NDjIoOGf%*KqAcE+^i^ z$^9`t4zVBrgw15;jab!}zOxCQoru*Nz?1DyhReScneJ-4?Z=YO0c&40gf~gd6i~+7 zk0tE!QZzsFRAzkYC{uSDAiDJ z`XxVt8E6TlEC37ohx?uvVXW@SK}^(y!vTb{&#ig2KX-_U?Avc9MD|yC!O)a$DIvyU|4o! zhXS~01X28l!&%aJo9AxwQ~Mga2b8EmpPD5mptdAxm8)NrT@1n7O2~0K>m&O30Y&?2 zw!NW)hseZ1{LKlX3)ah#lcN{0p17KKbZXGwaO5i1p##KYf!1$#B;$&u>C@5smT>PM zpRj1^4mXQxK?t;dJf`iaW(7ylqVeb{26enr;W&x6GIKb7sVvzt`p%fQyY{3We1E4K zZXL5xInZjew;B=eZAbA+X@*GFc~UmT?wmk{93HHdD38muv9q(YF*6mG$;4eX&lww( zbGPNs3x9kvuk5x&Z{gcJ706+2<$?<2^)ld;@eV5%X*-nq3}+raR~Vu!qaJz^Y0Q0| zID(-$Cv~bI9H)SJ{wcfRG&y5iE4d^_>>EMG%6#*zp;GWw@9Wo$uG=`$hCl1&pz^^` zs`e7^m`!@9zy};as_r`HNHdLUEBo_HC9lV%hEBa;Je9QyeYHpD1^0TwK@MSDDdqvr zORm7qB5PjS3Fm65g+y3#So{;x#^O@0xQZ1C*`HoS-pd|o2w;= zJFcCy5bL$JEMYy#EpXaZ&Yh&)Bs>^wP4#O#i)#GPmN=)iReosDaUVx&ov3LW6sz zk;`{b9EOWmihHdcWEB^0(s%Bw)Ql3ktS?>|^XgL+&F8HBer;0h)$@D5Vi8N7s9fgj zk4&rkve8MZVtV@To~svBg~S>;D4#MhYPCCG`uOuDR?1^p?Pj>!T^rdf$~`<-`ut&! zH*)SbUL$d@MWX_r7E-r(v}xOO>d-zFc`8p`>Pr=1c|smCM@41PM==TG9I_Aw*J zJ1~&AT;n^|#kFzIF3NadK75Dt0$70@S|!?%KpW>&B^-;sUAZ8$03--E5CFJeSQ;t) zROouE*rQ-duIE{4r5{DMfuNdCE=8d98&E1`BAL#YuOzCoKmN#DOAsq1FV-5LSZ}%C z$JViy`DS3ZKZ1yb@*>diIh;dEl|m(8ttLd&6?%Ot?csbna5lr`#J# z&$Yg}-Q(sWI^E_g(X4;i%kV-nxp!DR@G_KjZn(r-ID9%{x*%+&B_4gcjsNp);FNf1 zJ3U*Iph*-0a7=wCnbZnYB@L>0KTm3Bcmsm!9^QZ{t0eC5%Ny1wMhsP|zLh-S|J)`L zc1Z?n=wwDXikIlU-j_Y1kG(UKHdo-}Q%Jle%qMa!pL+NB@L>CGmE}j6Yoa6;|p(H%$_=-i4@H3r2StJpE2#r&i7RAeEw5`Zj3{`qTAZlb>~VAC zJLH=6Vz2uGaD(uncKV2T;TMRo96`*}Rhiu~LY38EMw&pHHyQD>FFY{lCKkJf_wW{; z0u}9mt6?iThhIh2)oI^q;jjW=uTK?t>K4UDlC}x~Rur&q`#C^Fe^YU84T;wqjwc<3 z9Yc)AsFMK<%Zvkp&DGA2@XeWCfFTQXV-WDcle6|w-dJgF5cy0ErnwHu zvB-9(RcFDGjcK_*yB?y;caz%W-u@F4PhD8Ed!6DoRP;aOVb8uqBwISpyQGfS;z}e| z%^v1SM?8>{-OsJ{(X2V17GXYq91m~Q_=@+^A1vbFAs_lwM0hEDY-IRLcH`pol9h5I zl4N+-SLp2?sWTOfq;m0DOlqd13{6nRe0dw2b#tV6uU_-P*E9DY-yV5^3w&4`xIy>! zkic+JuD2%*mQf;P!4O(h8PKa1e(f3e*UP$68eLN|@4v*luqz52B)0=F3yeov0i5>I zal1~AzA)~d7ttn{U-CrNcrGUg&V~+(QA~SskqTs#609V~&XC)Cb7fe^_Dio>;Izl= zWIt8vIgCh#hf(IgpRg^B*lV4wDu8RlI({gZh_b@0N@C9>WySJymsZ9N3@Avzu=Qgn0x@aXr&azH^E4k@tk8pkETFJhvG&BgHf`h<&vgMC3z_ zI!=MG4?*x-oM-yQ2p1nzMCj}3CYav2mOV6n?9P}X)l#0}cZjO{dF-~kGTs4&WLA1O zAhHea`m;Id{o{+((blGC~$&o03lqKaYIVSZ#Ut zfSZbvK7qu=bTK<%BwcHEo#dksDXk?ygqR*TM0YHb13&8h zVtnZLvNwTspfPL?6ffyH* zf2V%v;~l{H<>P@u683@osdFhge(mC)h!G1TEV1k;C9lh&($!I%6iyQjvr}n- zqQJaDjsb*SmWXv~rqxGDD3$k>suC3`&PjTh>2+M_P$wyp`_k!PNyi(0L0eQx-;A@B zNs*H^+x&9EVCOH6CnDvc+P2F|Oshy793bFx>CQD|GT7;5p+lYmpvQMWw6{vo| z5bT*M{YCLCi{z7$H_jJju?2p36PkQE@XNJV;f0}toc(<+LkYB=7D?^mw>px52>jdI zc8K1ZDyIe0pNiW#9exyN#5w%_*3o<|eb0Eb`I_qOwe+2DJx4W(_mjFpi`50#ilE zHQNQgw7wr~YXI&1uAe_iuG7l6hY?JbLHvi`O?~p^#ZNE-nUSsPnnwpe*2k4eNd&YY?DRVn3 zGG*V={rXRK7To;J34+NCvwyd9*nud8rp-^?#bm`=ZAgqoT~Ui4t2x{)G3_}%NqB@_ zjXJ&6fMcGnidhDf`(on0GZz?IPlcVQ3G?uA&2mx}vz)8z_Pz7!+u<)W)e)k#!dtV9 zE*t9YoTbTYewOzPM0>VonUp#>=GJQXA>}+`)gGE_RlI9{Q}Qe~W+FQ?S}|Cg zTU&^Hdr@>dY{FysY$=chCIWo);v3Bv^LyprP%9 zZNC*Q{gwjg%6-AG;HTE8S7Az@3b};~G`v(fk@!Vj0t^W0` zLkGVdh99?zFA(^m@@@X6rG!LgNJw3}K0og|r6(k};#-i(O;*Z{3}ljSi?aDMF~jb?51uYtW9MCl7$M`aqA+Q0ecJXj<`1j*cB(YG)Z1&fEnmF zt+phHdbuEp#abUoqx&y?zjpVg zKjqCv;#XZ)e~XCzcOhif9bW+2^I?*JvMWt{H)5)uzsE3Qz0=Wsn>m2D3HWw_D3p$g zfxl*yQ2>OF5yYJYh^f&}L8fU(kO2`ZcLW}e^n`9O_rO)4-j9obi;Kw4bllmzK)qq0 zsQt9jf} zm_O7cTydqY(v2WHgnwqLBlP;V`--+|E$LD&YdI+#fV3uN-E3=$_nZ)o`7?U=)N{D* z(RoaE`z}yy_q*7SxKyvJY-txpO@F~lk`KWH;yAbL(d>(yy1;4u;+KSS*6mNnY>2KA z?h4pQl}VKUa`m^!24+!)=+i_Wv(5=2Ih!pLFY+G#vgj}Rd2+(= zK-f`1*wkXZt~iDRRT;MjA@%i+|96Oa{NcLq5NHkkBkjQ@*JObF%$Y}QR5jNxOT)KJ z;v-DeF-~f);=l5M6ifu=qb_C6Ur)BzrvA8(%k* zvPIr9G%4pMJd&fD@9`oB$A@GMRYT^{Jwq^bv}ezyrS2(P&tA{{_X$JdFKt}x^(sA$ zM76j`DV`h`>ad4ik}Gs}!acuJ6zExjnR&>9DWeD&3KSWlo*fc`QpL~+n7Mj^RB4Sl z!WX~_ZS%>B9;eF=gB!n_sf-;#^`+5H<2-XXu5e1|yQ^aH_KGDU!kT40S`6Psu_X#|fXx9iw>esC#e9;E?Wa(KsCE)+?o zilEoDiG0$}mfGj#gq+U`*Gw)SkSl)$hSoGAjA(=Rpx*90j(32K^#gjs zI3U|sYf#!oq}PRCFbaWOTdZ=jAuJerLGwIG-;T+K#H1_>b?*8b$o#ZzR{pmX*2ja zBj2-kjPba_{mEk_8jGV41Uf;WA4Q5?Vj&wulDD$=!_1cDU|Wvrgc+o{_zlb!%%bWd zY>s>cE7X}Pgt`G>!J7fu!pqS2KuY0+F^K!E6Abz*VcWE_9xOH(0kuFxb3VuhRhUht zv*<>&?j`!D7lv#dULA3_!II{h(w>PC)ZMbRlo`H#V3^g2XD7n@fG2{UxwNAj?S)yc zwNSe)?ZFUt{@%p8)mz|(Smik9F;kn$TQ_IJq1@_$k&5_+?6>Mu$Ff4pQ)5y`nzlqU zKM6?cJM(54fVE2>A(?&ex~PS*4*L~m{@PtMwOjpQB};LR{OV%ZsBh} zG0vCM$0G=W7IJJ3ZU)k{H`VSov))uML&L8+tJH_gF}DOHK%|YCdboMLrZr$R9@my2 zMnFZp|I3c`Kl5rPMsY<)D&KWg0WLXt_BEvAYu>hPJ+KN`Q zeC;2>vs4szeIkEG(gF^W=S}Fnq1Qbaso#Br9;xIPe)op)^j!zacR2#JV*(yja~5n# z5BVJ%MD6c?F|B^yzh2mP;@)Rb!;4ce3T}eem9k5~G7L{~E?weK?vQ#bTBMNnD$;CQ zw6}ipKC6tZgR`vrBq6tNMQA0=e&02&FMS)6TH0f$FclArL*RPC*HWeK$!40u0tUO% zb=F-rgHtXrHLhLj>18@_+0deB)j}t>W@z<&4(D~NL3p%ThNdCdLujAaZ0|K7(*msX zQ_b9AConsD$U}7q7+FPll?4Yf;USpFW@$Y}mCa=4Z{zFxD}Y7X9O&d_lB7LnfpQuR zD}D?Iiy*9(=tU4^BGv$fS+qA#!3Ftyi$FsA(GOTQVu*(mHSvJw8@WaOTk}SNG;2`2 zUO1xb6q>vR0NUSr`t4pAmfEye$pXYqRelD`J-kaW{x#u$w+3$-UTIo+nrBmK+7KMl zf4GGpT(ycVD0)C)^OZ>mzU#fo}Vm~qcOU)>_&&dCvo;PJe(^-Kw1nQA0aQb{%12)Ou z{|bWHJ|YNjCRoz~D-eOV;&azzr69byB7d4Qf2g_qmSqhfCix&dD!Hu*Av{^rwmu=E z_#ZSc9q?~Y9<{{(Y#yioXZOAEf9`tqw}twD#`3uVU6QMRA$N0nbE2Xtwk3GzB{B-KcA*Y!t z29%$7xJu!R%TpX`=ag5hSZc=^jEnfMUNzhM`dc)PL%L4z{_Q)E$%@B!r9)$yjI5VA z14a}a;h7gioZm-E@)!a9!mIiUUlQn_zYY)>mPyz}ICnyC?m%w4Rqd)eUOON01iAZMWpi(x@ge8)Ah&1V z;xV}<Sbb&S2B(J`&nEAW7l8pBxEs*PU@52ak6YFJ@uHo*1nviPllxdEoXoTo z|21j%Iad$d4?AeiaKeRW_ecHT@YDYOC#3wp)9t?+xu*Z!$Mj$QxPLY+Uj3&t_3!`A z|4P^Yd`7bTd8V#ECH2VtHt#8>9YKDt7Z3BpH*%257#WFV(ZoR$M*6;66?zo910Myh z(mbWf3%vE7529fX0{tdoclDWFAk8THur2@|3YOmOUJ`?<^ zP-D+-FkmVW{$+Ptkp`h+4k+wI;$+*=eux%3`_GPhIS8}2H=(CTgQDkm+aS=0ewqS) zd;Lvi+EJVSE015Q)?XX`^Jj|SE>)M&$ma2V?I0j|{bqFk>+tOPNX5aW$U#k|(;tO; z?6|EePG7$8?b#-KPZeGDd@fU;=RQLNE8UJHj;1gbk139ejTzJI&c4IEhm&}q&Rgoi zUpygX*#X#%sw@?=;%$AEUNa|9r0|Id`+equn&Ui78O-Vf38N_ zPRotRo;YxyaBSsTNqO0&;Pan7%qi#gSM%Z(ErbrssHBLF4%1zR2ph{;7k{)pPyCwt zWweC;T%a3UMGAi8(!fNR8=YxAZvS#(mCL;{r902%KVDF#_P!T*#r~q2w04IiG;bz> ze4t; zlsy{gWFCAv@57-tS@#v@KAuxUgbTd&SV&+chM{BJAQF6XU+1(LgLaH(6xhbbM z0VPF{b4Go_!%D5sUT<0SF8O15UU`An&DYmFdyIMjBW7CXF4vYBO}+qd3v+q(Y%`s5 z7%eC4ETG1Ap&V=Y@?m+sU$3DG{`nZ+397)^nY|$t$B)P_*s8)bV?nC}GjtST z>pU|oc=(j*d>0oZST{j&nffaQ1b+N@qqdVTaE9sSQGO_HAlVkSf(pA@9)01?zQtDP8 z#YdvlIjcV7tr}gmst4+BG^kbuBLvT#R{o+!QCEldnm3f4f(@;1->pI#Mn6&bWHBv2oBqEDz$Rahe*QyiP1kftNOCme2ap-&@RaL(1lOwal; zqZ?XNbr+m;i{m|HD_ULb1WV?f^VC|5=E>0BCpZysIZeHgt&<&$b&el{vyS1*aL z)I&Ds!Q~{@FQ#Esvu_m}syyibD((I|pMM@*J5uq#dVl~YAP)Y|qwLRbe*0=y+}^q7 aM+p$ZfB$N?`X5Vnj>P}}v;+G-^uGWw%%I!= diff --git a/base_geoengine/doc/source/api_doc.rst b/base_geoengine/doc/source/api_doc.rst deleted file mode 100644 index 56c5af9a2..000000000 --- a/base_geoengine/doc/source/api_doc.rst +++ /dev/null @@ -1,63 +0,0 @@ -====== -API -====== - -*********** -GeoColumns -*********** -.. automodule:: base_geoengine.geo_field - :members: - -.. automodule:: base_geoengine.geo_point - :members: - -.. automodule:: base_geoengine.geo_line - :members: - -.. automodule:: base_geoengine.geo_multiline - :members: - -.. automodule:: base_geoengine.geo_polygon - :members: - -.. automodule:: base_geoengine.geo_multipolygon - :members: - -**************** -View Management -**************** - -.. automodule:: base_geoengine.geo_view - :members: - -.. automodule:: base_geoengine.geo_view.geo_raster_layer - :members: - -.. automodule:: base_geoengine.geo_view.geo_vector_layer - :members: - -.. automodule:: base_geoengine.geo_view.ir_view - :members: - -************** -GEO ORM MODEL -************** -.. autoclass:: base_geoengine.geo_model.GeoModel - :members: - -****************** -GEO ORM OPERATORS -****************** - -.. automodule:: base_geoengine.geo_operators - :members: - -.. autoclass:: base_geoengine.geo_operators.GeoOperator - :members: - -*********** -GEO helper -*********** - -.. automodule:: base_geoengine.geo_helper.geo_convertion_helper - :members: diff --git a/base_geoengine/doc/source/conf.py b/base_geoengine/doc/source/conf.py deleted file mode 100644 index e3dff0aec..000000000 --- a/base_geoengine/doc/source/conf.py +++ /dev/null @@ -1,245 +0,0 @@ -# flake8: noqa -# -# OpenERP GeoEngine documentation build configuration file, created by -# sphinx-quickstart on Mon Mar 5 09:15:25 2012. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import os -import sys - -import sphinx_bootstrap_theme - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - - -odoo_root = "/home/travis/odoo-" + os.environ["VERSION"] -sphinxodoo_root_path = os.path.abspath(odoo_root) -sphinxodoo_addons_path = [ - os.path.abspath(os.path.join(odoo_root, "openerp", "addons")), - os.path.abspath(os.path.join(odoo_root, "addons")), - os.path.abspath(os.environ["TRAVIS_BUILD_DIR"]), -] -geo_path = os.environ["TRAVIS_BUILD_DIR"] -addons = [ - x - for x in os.listdir(geo_path) - if not x.startswith(".") and os.path.isdir(os.path.join(geo_path, x)) -] -sphinxodoo_addons = addons -sys.path.append(os.environ["TRAVIS_BUILD_DIR"]) -# -- General configuration ---------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ["sphinx.ext.autodoc", "sphinxodoo.ext.autodoc"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "Odoo Geospatial" -copyright = "2015, Nicolas Bessi, Odoo Community Association (OCA)" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = "0.3" -# The full version, including alpha/beta/rc tags. -release = "0.3" - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = "bootstrap" -html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = "OpenERPGeoEnginedoc" - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -# latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -# latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ( - "index", - "OpenERPGeoEngine.tex", - "Odoo Geospatial Documentation", - "Odoo Community Association (OCA), Nicolas Bessi", - "manual", - ) -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Additional stuff for the LaTeX preamble. -# latex_preamble = '' - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ( - "index", - "openerpgeoengine", - "Odoo Geospatial Documentation", - ["Odoo Community Association (OCA), Nicolas Bessi"], - 1, - ) -] diff --git a/base_geoengine/doc/source/index.rst b/base_geoengine/doc/source/index.rst deleted file mode 100644 index 44f6d7ac0..000000000 --- a/base_geoengine/doc/source/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. OpenERP GeoEngine documentation master file, created by - sphinx-quickstart on Mon Mar 5 09:15:25 2012. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Odoo Geospatial's documentation -========================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - what_is_geoengine - prerequisite - installation - postgisify - api_doc - - How to use GeoEngine - Modules presentations - API presentation - Manage your layer from client - Create a geocolumn from client - - -Indices and tables -================== -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/base_geoengine/doc/source/installation.rst b/base_geoengine/doc/source/installation.rst deleted file mode 100644 index 1beaa90b2..000000000 --- a/base_geoengine/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -================= -Installation -================= - -Once prerequisites are installed you still have to apply fixes pending to be merge in -Odoo Core before being able to use it: :: - - git pull origin pull/5620/head - git cherry-pick 676e4b8d - -This fix is already merged in the OCB (Odoo Community Backports) branch. -If you are using it there is no need to install the fix yourself. diff --git a/base_geoengine/doc/source/postgisify.rst b/base_geoengine/doc/source/postgisify.rst deleted file mode 100644 index 8aaf6ec63..000000000 --- a/base_geoengine/doc/source/postgisify.rst +++ /dev/null @@ -1,16 +0,0 @@ -********************************* -Postgisify an exisiting database -********************************* - -If you want to install the GeoEngine on an existing database you have two options. - -If you are using a PostgreSQL super user it should work out of the box. -If you are using a standard user you have to connect to your database and run: :: - - CREATE EXTENSION postgis - CREATE EXTENSION postgis_topology - -In order to test if the installation is sucessfull log into you database and:: - - SELECT * from GEOMETRY_COLUMNS; - SELECT * from spatial_ref_sys; diff --git a/base_geoengine/doc/source/prerequisite.rst b/base_geoengine/doc/source/prerequisite.rst deleted file mode 100644 index 416707f17..000000000 --- a/base_geoengine/doc/source/prerequisite.rst +++ /dev/null @@ -1,30 +0,0 @@ -================= -Prerequisites -================= -*************** -Python -*************** -geojson: - -:: - - pip install geojson - -Shapely: - -:: - - pip install Shapely==1.2.13 - -For Mac user: do not forget the following directive: - -:: - - ARCHFLAGS="-arch i386 -arch x86_64" - - -*************** -PostGIS 2.0 -*************** - -Please refer to `PostGIS installation directive `_ or to your OS package system. diff --git a/base_geoengine/doc/source/what_is_geoengine.rst b/base_geoengine/doc/source/what_is_geoengine.rst deleted file mode 100644 index cb64b8cbc..000000000 --- a/base_geoengine/doc/source/what_is_geoengine.rst +++ /dev/null @@ -1,16 +0,0 @@ -=================== -What is GeoEngine ? -=================== - -GeoEngine is an OpenERP module that adds spatial/GIS capabilites to OpenERP. It will allow you to : - -* Visualize and query your business information on map -* Perform GeoBI and spatial query -* Configure your spatial layers and spatial datasources -* Extend OpenERP models with spatial columns - -GeoEngine relies on `OpenLayers `_ and `PostgGIS `_ technologies. - -Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps. The GeoEngine module acts as a data provider and as an OpenLayers configurator. It also provides a complete extension to OpenERP ORM. - -.. image:: _static/_images/core_architecture.jpg diff --git a/base_geoengine/geo_db.py b/base_geoengine/geo_db.py index 7a36c1ef2..7ad01871d 100644 --- a/base_geoengine/geo_db.py +++ b/base_geoengine/geo_db.py @@ -37,7 +37,7 @@ def init_postgis(cr): CREATE EXTENSION postgis_topology; """ ) - except Exception: + except Exception as exc: raise MissingError( _( "Error, can not automatically initialize spatial postgis" @@ -50,7 +50,7 @@ def init_postgis(cr): "CREATE EXTENSION postgis;\n" "CREATE EXTENSION postgis_topology;\n" ) - ) + ) from exc def create_geo_column(cr, tablename, columnname, geotype, srid, dim, comment=None): diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 91ac2edf8..3cafbee08 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -97,7 +97,7 @@ def set_field_real_name(in_tuple): ) geoengine_layers["actives"].append(layer_dict) # adding geo column desc - layer_dict["geo_field_id"][1] + # layer_dict["geo_field_id"][1] return geoengine_layers # @api.model diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index 55b5aa517..d9f3efab5 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -46,7 +46,9 @@ def geo_search(model, domain=None, geo_domain=None, offset=0, limit=None, order= domain = domain or [] geo_domain = geo_domain or [] model.env["ir.model.access"].check(model._name, "read") - # _where_calc = Computes the WHERE clause needed to implement an OpenERP domain. :param list domain: the domain to compute, active_test: whether the default filtering of records with + # _where_calc = Computes the WHERE clause needed to implement an OpenERP domain. + # :param list domain: the domain to compute, active_test: whether the default + # filtering of records with query = model._where_calc(domain, active_test=True) # Add what's missing in query to implement all appropriate ir.rules model._apply_ir_rules(query, "read") @@ -147,7 +149,7 @@ def get_rel_field(self, rel_col, rel_model): except Exception: raise Exception( "Model {} has no column {}".format(rel_model._name, rel_col) - ) + ) from None return "{}.{}".format(rel_model._table, rel_col) def _get_direct_como_op_sql( diff --git a/base_geoengine/geo_view/geo_raster_layer_view.xml b/base_geoengine/geo_view/geo_raster_layer_view.xml index adc9e57fd..4e30481fd 100644 --- a/base_geoengine/geo_view/geo_raster_layer_view.xml +++ b/base_geoengine/geo_view/geo_raster_layer_view.xml @@ -66,7 +66,7 @@ geoengine.raster.layer.tree geoengine.raster.layer - + diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py index 5ea5820e4..f305b6bb4 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -67,4 +67,4 @@ class GeoVectorLayer(models.Model): active_on_startup = fields.Boolean( help="Layer will be shown on startup if checked." ) - layer_opacity = fields.Float("Layer Opacity") + layer_opacity = fields.Float() diff --git a/base_geoengine/geo_view/geo_vector_layer_view.xml b/base_geoengine/geo_view/geo_vector_layer_view.xml index 5b6a4f5a8..97881920e 100644 --- a/base_geoengine/geo_view/geo_vector_layer_view.xml +++ b/base_geoengine/geo_view/geo_vector_layer_view.xml @@ -67,7 +67,7 @@ geoengine.vector.layer.tree geoengine.vector.layer - + diff --git a/base_geoengine/readme/DESCRIPTION.rst b/base_geoengine/readme/DESCRIPTION.rst index 2f8ca6513..03cfdbf00 100644 --- a/base_geoengine/readme/DESCRIPTION.rst +++ b/base_geoengine/readme/DESCRIPTION.rst @@ -1,2 +1,18 @@ +=================== +What is GeoEngine ? +=================== + +GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. It will allow you to : + +* Visualize and query your business information on map +* Perform GeoBI and spatial query +* Configure your spatial layers and spatial datasources +* Extend Odoo models with spatial columns + +GeoEngine relies on `OpenLayers `_ and `PostgGIS `_ technologies. + +Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps. The GeoEngine module acts as a data provider and as an OpenLayers configurator. +It also provides a complete extension to Odoo ORM. + Geospatial support based on PostGIS add the ability of server to server geojson to do geo CRUD and view definition. diff --git a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js index 5f059255b..956f7393c 100644 --- a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js +++ b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js @@ -4,7 +4,7 @@ import {loadJS} from "@web/core/assets"; import {registry} from "@web/core/registry"; import {useService} from "@web/core/utils/hooks"; -const {Component, onWillStart, useRef, onMounted, onRendered} = owl; +const {Component, onWillStart, onMounted, onRendered} = owl; export class FieldGeoEngineEditMap extends Component { setup() { From 48040910775d6c960c3d5a8500787082d16fbcb4 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 6 Mar 2023 08:53:36 +0100 Subject: [PATCH 18/98] [IMP][FIX] base_geoengine: start model tests and fix retail machines view in geo_edit_map --- base_geoengine/geo_model.py | 56 ---- base_geoengine/tests/__init__.py | 1 + base_geoengine/tests/models.py | 33 +++ base_geoengine/tests/test_model.py | 451 +++++++++++++++++++++++++++++ 4 files changed, 485 insertions(+), 56 deletions(-) create mode 100644 base_geoengine/tests/__init__.py create mode 100644 base_geoengine/tests/models.py create mode 100644 base_geoengine/tests/test_model.py diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 3cafbee08..975dc02eb 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -100,62 +100,6 @@ def set_field_real_name(in_tuple): # layer_dict["geo_field_id"][1] return geoengine_layers - # @api.model - # def _get_view(self, view_id=None, view_type='form', **options): - # """Returns information about the available fields of the class. - # If view type == 'map' returns geographical columns available""" - # view_obj = self.env["ir.ui.view"] - # field_obj = self.env["ir.model.fields"] - - # def set_field_real_name(in_tuple): - # if not in_tuple: - # return in_tuple - # name = field_obj.browse(in_tuple[0]).name - # out = (in_tuple[0], name, in_tuple[1]) - # return out - - # if view_type == "geoengine": - # if not view_id: - # view = self._get_geo_view() - # else: - # view = view_obj.browse(view_id) - # res = super()._get_view( - # view_id=view.id, view_type="form", **options - # ) - # res["geoengine_layers"] = { - # "backgrounds": [], - # "actives": [], - # "projection": view.projection, - # "restricted_extent": view.restricted_extent, - # "default_extent": view.default_extent or DEFAULT_EXTENT, - # "default_zoom": view.default_zoom, - # } - # for layer in view.raster_layer_ids: - # layer_dict = layer.read()[0] - # res["geoengine_layers"]["backgrounds"].append(layer_dict) - # for layer in view.vector_layer_ids: - # layer_dict = layer.read()[0] - # # get category groups for this vector layer - # if layer.geo_repr == "basic" and layer.symbol_ids: - # layer_dict["symbols"] = layer.symbol_ids.read( - # ["img", "fieldname", "value"] - # ) - # layer_dict["attribute_field_id"] = set_field_real_name( - # layer_dict.get("attribute_field_id", False) - # ) - # layer_dict["geo_field_id"] = set_field_real_name( - # layer_dict.get("geo_field_id", False) - # ) - # res["geoengine_layers"]["actives"].append(layer_dict) - # # adding geo column desc - # geo_f_name = layer_dict["geo_field_id"][1] - # res["fields"].update(self.fields_get([geo_f_name])) - # else: - # return super()._get_view( - # view_id=view_id, view_type=view_type, **options - # ) - # return res - @api.model def get_edit_info_for_geo_column(self, column): raster_obj = self.env["geoengine.raster.layer"] diff --git a/base_geoengine/tests/__init__.py b/base_geoengine/tests/__init__.py new file mode 100644 index 000000000..fce09e0ca --- /dev/null +++ b/base_geoengine/tests/__init__.py @@ -0,0 +1 @@ +from . import test_model diff --git a/base_geoengine/tests/models.py b/base_geoengine/tests/models.py new file mode 100644 index 000000000..92a19ba21 --- /dev/null +++ b/base_geoengine/tests/models.py @@ -0,0 +1,33 @@ +from odoo import fields, models + + +class GeoModelTest(models.Model): + _name = "geo.model.test" + name = fields.Char("GeoModelTest") + geo_multi_polygon = fields.GeoMultiPolygon() + geo_polygon = fields.GeoPolygon() + geo_line = fields.GeoLine() + geo_point = fields.GeoPoint() + geo_multi_line = fields.GeoMultiLine() + geo_multi_point = fields.GeoMultiPoint() + + +class DummyZip(models.Model): + _name = "dummy.zip" + _description = "Geoengine demo ZIP" + + name = fields.Char("ZIP", index=True, required=True) + city = fields.Char(index=True, required=True) + the_geom = fields.GeoMultiPolygon("NPA Shape") + the_poly = fields.GeoPolygon() + + +class RetailMachine(models.Model): + _name = "retail.machine" + _description = "Geoengine demo retailing machine" + + the_point = fields.GeoPoint("Coordinate") + total_sales = fields.Float("Total sale", index=True) + money_level = fields.Char(index=True) + state = fields.Selection([("hs", "HS"), ("ok", "OK")], index=True) + name = fields.Char("Serial number", required=True) diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py new file mode 100644 index 000000000..1bb3c3018 --- /dev/null +++ b/base_geoengine/tests/test_model.py @@ -0,0 +1,451 @@ +from odoo_test_helper import FakeModelLoader +from shapely import wkt + +from odoo.tests.common import TransactionCase + + +class TestModel(TransactionCase): + @classmethod + def setUpClass(cls): + super(TestModel, cls).setUpClass() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + + from .models import DummyZip, GeoModelTest, RetailMachine + + cls.loader.update_registry((GeoModelTest, DummyZip, RetailMachine)) + cls.geo_model = cls.env["geo.model.test"].create({}) + cls.env["dummy.zip"].create( + { + "name": "1146", + "city": "Mollens (VD))", + "the_geom": "MULTIPOLYGON (((711089.693203108 5873735.48072837, " + + "711092.576313001 5873519.88384687," + + "711067.054090924 5873435.51305599,710995.218898879 5873198.04330687," + + "710996.388615927 5873110.64387336,711039.179454242 5873060.22832024," + + "711042.287896265 5872936.43418925,711026.423105771 5872819.67065428," + + "711261.754450894 5872597.025222,711241.609394529 5872474.38185775," + + "711059.74912495 5872499.61499977,710956.020676372 5872329.22952511," + + "710692.244689654 5872290.70879558,710486.478264092 5871933.93784652," + + "710024.93171231 5872025.28274803,710005.024342666 5871778.82753806," + + "709728.110667306 5871639.59028651,709724.582871056 5871578.36223351," + + "709682.212415895 5871490.38595657,709610.808017364 5871402.01470814," + + "709552.306572401 5871356.73905814,709495.853317159 5871313.04976156," + + "709236.521364341 5871163.84756429,709195.304008703 5871128.42409022," + + "709150.409305552 5871089.84044459,709093.837273492 5871008.051534," + + "709008.015634898 5870883.97195414,708922.106609628 5870795.4022844," + + "708836.258869397 5870702.46391409,708174.672218121 5871197.33373336," + + "707846.164800298 5870800.97891085,707605.589841331 5870979.71730235," + + "706369.331113847 5871966.12906172,706306.149363559 5872332.34885008," + + "705390.804735349 5873401.94343156,704603.284854186 5873838.0955764," + + "704092.91256737 5873980.90856737,704011.87512573 5873857.35915706," + + "703030.73225885 5874621.40143472,702006.482932752 5874937.39404808," + + "702849.34839414 5875420.27638601,705799.405382342 5875341.31671473," + + "707632.65678248 5875553.44607092,708858.019414722 5875286.16417218," + + "709639.976192618 5874932.54154212,709800.865455979 5874636.00773277," + + "710188.467536495 5874437.27183537,710138.406154331 5874271.93819522," + + "710464.959230515 5874290.93364989,711089.693203108 5873735.48072837)))", + } + ) + + cls.env["dummy.zip"].create( + { + "name": "1169", + "city": "Yens", + "the_geom": "MULTIPOLYGON (((712499.646588959 5867275.9182732," + + "713419.026718887 5867001.27747293,714015.722251894 5866538.88540113," + + "714694.030364397 5866492.43868073,714765.262342783 5865922.7082706," + + "714997.785886538 5865558.90341594,715151.666992536 5865665.71173242," + + "715609.031373263 5865079.20249973,715885.038705088 5865053.65786512," + + "716495.789172412 5864492.40980924,716976.367311019 5864008.08379334," + + "716781.749152281 5863910.99389739,716608.651725694 5863833.09642092," + + "716518.052861577 5863201.78267731,716064.089435707 5863535.02734419," + + "715643.594094414 5862954.76617529,715325.079468014 5863244.60059218," + + "715203.241075229 5863130.96403033,715274.223325112 5862913.60004965," + + "714897.772002756 5862635.12980843,714563.017533803 5862610.39226806," + + "714258.266707042 5862620.95887512,714249.030777221 5862438.94330443," + + "713724.197313172 5862641.59763197,713517.069387174 5862507.90536999," + + "712861.144693087 5862860.12184101,713026.004126525 5862898.68588355," + + "712886.267874965 5863045.26900106,712827.103281182 5863131.79990304," + + "712738.929710136 5863217.94640341,712691.900706143 5863250.04961387," + + "712592.546151257 5863317.87261312,712504.368398659 5863404.01855574," + + "712405.215033586 5863533.04505435,712371.521154897 5863576.88960266," + + "712355.411589612 5863605.09059754,712223.007660214 5863836.87550522," + + "712156.578632893 5863923.31295655,712134.435332338 5863952.12551606," + + "712134.049617032 5863981.22835121,712079.319781245 5864066.52919356," + + "712059.980001849 5864096.67295644,712051.318250669 5864144.84287664," + + "712044.316598475 5864183.7895569,711908.743067266 5864560.40002656," + + "711809.521376786 5864821.06690256,711185.861440992 5865020.84754387," + + "710829.505021716 5865627.41104201,710236.389289627 5865815.90923937," + + "710091.432898977 5866557.84150433,709133.629951634 5866771.90114324," + + "709458.164419682 5866919.01207252,709913.809001053 5867137.78068809," + + "710889.333222594 5868419.19110438,711446.96086477 5867965.10731405," + + "711555.097159712 5867474.42262634,711838.254231148 5867572.85286263," + + "711873.968689887 5867287.95989594,712499.646588959 5867275.9182732)))", + } + ) + + cls.env["retail.machine"].create( + { + "name": "34", + "total_sales": 734.0, + "money_level": "low", + "the_point": "POINT(711341.795470746 5866150.25857961)", + "state": "ok", + } + ) + + cls.env["retail.machine"].create( + { + "name": "33", + "total_sales": 492.0, + "money_level": "low", + "the_point": "POINT(711652.69365366 5866548.27641024)", + "state": "ok", + } + ) + + cls.env["retail.machine"].create( + { + "name": "18", + "total_sales": 892.0, + "money_level": "high", + "the_point": "POINT(708451.36372351 5872547.88349207)", + "state": "ok", + } + ) + + cls.env["retail.machine"].create( + { + "name": "23", + "total_sales": 1781.0, + "money_level": "high", + "the_point": "POINT(708037.67602773 5873788.9465794)", + "state": "ok", + } + ) + + cls.env["retail.machine"].create( + { + "name": "21", + "total_sales": 1533.0, + "money_level": "high", + "the_point": "POINT(706962.088018701 5873623.47150109)", + "state": "ok", + } + ) + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super(TestModel, cls).tearDownClass() + + def test_create_multipolygon(self): + """Create a multi polygon""" + multi_polygon = """MULTIPOLYGON (((726469.938970306 5873145.03456248, + 726520.174105436 5872946.03059195,726394.076006275 5872675.04267336, + 726404.709252018 5872259.98652277,726212.557712441 5871801.78900894, + 726471.645243121 5871748.01187117,726384.798016214 5871474.60597039, + 726524.862821204 5871416.52279756,726560.408193573 5870936.9668625, + 726765.583679957 5870941.58021817,726800.675791552 5870794.8818083, + 726830.398385972 5870610.25496982,726667.324961485 5870525.33567258, + 726559.158856422 5870713.41380138,726483.618814776 5870842.15916191, + 726282.880000044 5870874.76667995,726075.942331799 5870940.79690473, + 726060.620082161 5870636.20922038,725995.373875086 5870504.36168216, + 725871.917698916 5870508.73664946,725866.910956205 5870440.22483982, + 725760.074408205 5870513.2465806,724947.130321146 5870506.55170525, + 724956.64886783 5870684.35364044,724709.437725183 5870717.82930599, + 724640.837901402 5870502.91208435,723632.716917063 5871035.58668793, + 723353.587063504 5870580.71145654,722975.340414945 5870644.60022452, + 723063.193608096 5871187.48904965,723286.565782157 5871691.25884814, + 722865.254617585 5871951.28387527,722963.962738856 5872074.84140304, + 722831.245902295 5872122.76389775,722813.837916803 5872242.00526964, + 722827.655983236 5872300.44254147,722913.370119188 5872418.02105384, + 722942.233783707 5872432.93796481,722984.741992683 5872520.85895895, + 723012.381471722 5872637.73702376,723086.082443995 5872667.76380156, + 723157.229378648 5872668.62290333,723214.748202491 5872698.34771906, + 723250.508284339 5872761.5280976,723286.16249158 5872815.86084868, + 723315.028102666 5872830.77719621,723502.328395902 5872819.6206505, + 723518.483057357 5872818.65863173,723567.82777813 5872844.15493286, + 723749.413939088 5872937.98130854,723848.429817139 5873019.41326079, + 723893.228455684 5873056.25562596,724000.782399525 5873179.05937195, + 724022.179653074 5873203.48913931,724167.213521721 5873219.79321866, + 724240.443943894 5873257.62460164,724345.033870514 5873311.65740904, + 724427.033053176 5873354.0176493,724458.116953997 5873354.38826826, + 724601.342527281 5873356.09453768,724659.368258544 5873356.78513641, + 724699.259216658 5873263.86039926,724734.038257937 5873182.84407915, + 724769.196071982 5873148.4004069,724792.808935311 5873125.2670227, + 724828.594968331 5873107.84535952,724909.660761314 5873068.37954232, + 724968.429515518 5873010.80204763,724969.116329931 5872952.53572905, + 725027.883915669 5872894.95858978,725144.902548535 5872823.50310579, + 725202.982873244 5872824.19072548,725231.165281494 5872845.9215328, + 725260.549561619 5872868.5770444,725323.492507265 5872998.67536266, + 725345.617620278 5873044.40573114,725374.316461685 5873073.88235996, + 725461.097697554 5873104.044911,725548.221016413 5873105.07306152, + 725593.723206956 5873117.05713947,725633.818030441 5873127.61507632, + 725664.044374598 5873135.57621915,725715.023293758 5873205.45921561, + 725835.567474206 5873370.70034401,725849.407491127 5873429.14029691, + 725878.279489341 5873444.04917682,725936.874293492 5873401.02996477, + 725995.978527806 5873314.30901098,726070.62161125 5873140.35732493, + 726085.312084189 5873125.96087534,726100.002508819 5873111.56442448, + 726217.015284978 5873040.09276485,726304.138055426 5873041.11333845, + 726469.938970306 5873145.03456248)))""" + multi_polygon_loaded = wkt.loads(multi_polygon) + self.geo_model.geo_multi_polygon = multi_polygon + self.assertTrue( + self.geo_model.geo_multi_polygon.equals_exact( + multi_polygon_loaded, tolerance=0.2 + ) + ) + + multi_polygon_geojson = """{"type":"MultiPolygon","coordinates":[[[ + [726469.938970306,5873145.03456248],[726520.174105436,5872946.03059195], + [726394.076006275,5872675.04267336],[726404.709252018,5872259.98652277], + [726212.557712441,5871801.78900894],[726471.645243121,5871748.01187117], + [726384.798016214,5871474.60597039],[726524.862821204,5871416.52279756], + [726560.408193573,5870936.9668625],[726765.583679957,5870941.58021817], + [726800.675791552,5870794.8818083],[726830.398385972,5870610.25496982], + [726667.324961485,5870525.33567258],[726559.158856422,5870713.41380138], + [726483.618814776,5870842.15916191],[726282.880000044,5870874.76667995], + [726075.942331799,5870940.79690473],[726060.620082161,5870636.20922038], + [725995.373875086,5870504.36168216],[725871.917698916,5870508.73664946], + [725866.910956205,5870440.22483982],[725760.074408205,5870513.2465806], + [724947.130321146,5870506.55170525],[724956.64886783,5870684.35364044], + [724709.437725183,5870717.82930599],[724640.837901402,5870502.91208435], + [723632.716917063,5871035.58668793],[723353.587063504,5870580.71145654], + [722975.340414945,5870644.60022452],[723063.193608096,5871187.48904965], + [723286.565782157,5871691.25884814],[722865.254617585,5871951.28387527], + [722963.962738856,5872074.84140304],[722831.245902295,5872122.76389775], + [722813.837916803,5872242.00526964],[722827.655983236,5872300.44254147], + [722913.370119188,5872418.02105384],[722942.233783707,5872432.93796481], + [722984.741992683,5872520.85895895],[723012.381471722,5872637.73702376], + [723086.082443995,5872667.76380156],[723157.229378648,5872668.62290333], + [723214.748202491,5872698.34771906],[723250.508284339,5872761.5280976], + [723286.16249158,5872815.86084868],[723315.028102666,5872830.77719621], + [723502.328395902,5872819.6206505],[723518.483057357,5872818.65863173], + [723567.82777813,5872844.15493286],[723749.413939088,5872937.98130854], + [723848.429817139,5873019.41326079],[723893.228455684,5873056.25562596], + [724000.782399525,5873179.05937195],[724022.179653074,5873203.48913931], + [724167.213521721,5873219.79321866],[724240.443943894,5873257.62460164], + [724345.033870514,5873311.65740904],[724427.033053176,5873354.0176493], + [724458.116953997,5873354.38826826],[724601.342527281,5873356.09453768], + [724659.368258544,5873356.78513641],[724699.259216658,5873263.86039926], + [724734.038257937,5873182.84407915],[724769.196071982,5873148.4004069], + [724792.808935311,5873125.2670227],[724828.594968331,5873107.84535952], + [724909.660761314,5873068.37954232],[724968.429515518,5873010.80204763], + [724969.116329931,5872952.53572905],[725027.883915669,5872894.95858978], + [725144.902548535,5872823.50310579],[725202.982873244,5872824.19072548], + [725231.165281494,5872845.9215328],[725260.549561619,5872868.5770444], + [725323.492507265,5872998.67536266],[725345.617620278,5873044.40573114], + [725374.316461685,5873073.88235996],[725461.097697554,5873104.044911], + [725548.221016413,5873105.07306152],[725593.723206956,5873117.05713947], + [725633.818030441,5873127.61507632],[725664.044374598,5873135.57621915], + [725715.023293758,5873205.45921561],[725835.567474206,5873370.70034401], + [725849.407491127,5873429.14029691],[725878.279489341,5873444.04917682], + [725936.874293492,5873401.02996477],[725995.978527806,5873314.30901098], + [726070.62161125,5873140.35732493],[726085.312084189,5873125.96087534], + [726100.002508819,5873111.56442448],[726217.015284978,5873040.09276485], + [726304.138055426,5873041.11333845],[726469.938970306,5873145.03456248]]]]}""" + self.geo_model.geo_multi_polygon = multi_polygon_geojson + self.assertTrue( + self.geo_model.geo_multi_polygon.equals_exact( + multi_polygon_loaded, tolerance=0.2 + ) + ) + + def test_create_polygon(self): + """Create a polygon""" + polygon = """POLYGON((-95.80078125000001 40.09488212232117, + -95.07568359375001 36.68604127658193, + -90.439453125 37.80544394934273,-91.03271484375001 39.97712009843963, + -95.80078125000001 40.09488212232117))""" + polygon_loaded = wkt.loads(polygon) + self.geo_model.geo_polygon = polygon + self.assertTrue( + self.geo_model.geo_polygon.equals_exact(polygon_loaded, tolerance=0.2) + ) + + polygon_geojson = """{"type":"Polygon","coordinates":[[ + [-95.80078125000001,40.09488212232117], + [-95.07568359375001,36.68604127658193],[-90.439453125,37.80544394934273], + [-91.03271484375001,39.97712009843963],[-95.80078125000001,40.09488212232117]]]}""" + self.geo_model.geo_polygon = polygon_geojson + self.assertTrue( + self.geo_model.geo_polygon.equals_exact(polygon_loaded, tolerance=0.2) + ) + + def test_create_line(self): + """Create a line""" + line = """LINESTRING(-98.81103515625001 38.97649248553944, + -90.06591796875 38.99357205820945)""" + self.geo_model.geo_line = line + line_loaded = wkt.loads(line) + self.assertTrue( + self.geo_model.geo_line.equals_exact(line_loaded, tolerance=0.2) + ) + + line_geojson = """{"type":"LineString","coordinates":[ + [-98.81103515625001,38.97649248553944], + [-90.06591796875,38.99357205820945]]}""" + self.geo_model.geo_line = line_geojson + self.assertTrue( + self.geo_model.geo_line.equals_exact(line_loaded, tolerance=0.2) + ) + + def test_create_point(self): + """Create a point""" + point = "POINT(-99.2724609375 38.25543637637949)" + self.geo_model.geo_point = point + point_loaded = wkt.loads(point) + self.assertTrue( + self.geo_model.geo_point.equals_exact(point_loaded, tolerance=0.2) + ) + + point_geosjon = ( + '{ "type": "Point", "coordinates": [-99.2724609375, 38.25543637637949] }' + ) + self.geo_model.geo_point = point_geosjon + self.assertTrue( + self.geo_model.geo_point.equals_exact(point_loaded, tolerance=0.2) + ) + + def test_create_multi_line(self): + """Create multiline""" + multi_line = ( + "MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))" + ) + self.geo_model.geo_multi_line = multi_line + multi_line_loaded = wkt.loads(multi_line) + self.assertTrue( + self.geo_model.geo_multi_line.equals_exact(multi_line_loaded, tolerance=0.2) + ) + + multi_line_geojson = """{"type":"MultiLineString","coordinates":[[ + [10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]]}""" + self.geo_model.geo_multi_line = multi_line_geojson + self.assertTrue( + self.geo_model.geo_multi_line.equals_exact(multi_line_loaded, tolerance=0.2) + ) + + def test_create_multi_point(self): + """Create multipoint""" + multi_point = "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" + self.geo_model.geo_multi_point = multi_point + multi_point_loaded = wkt.loads(multi_point) + self.assertTrue( + self.geo_model.geo_multi_point.equals_exact( + multi_point_loaded, tolerance=0.2 + ) + ) + + multi_point_geojson = ( + '{"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]]}' + ) + self.geo_model.geo_multi_point = multi_point_geojson + self.assertTrue( + self.geo_model.geo_multi_point.equals_exact( + multi_point_loaded, tolerance=0.2 + ) + ) + + def test_delete(self): + self.geo_model.unlink() + self.assertFalse(self.geo_model.exists()) + + def test_geo_search_intersect(self): + retails = self.env["retail.machine"] + zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) + + result = retails.geo_search( + geo_domain=[ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, + ) + ] + ) + self.assertEqual(len(result), 2) + + zip_item = self.env["dummy.zip"].search([("name", "ilike", "1146")]) + result = retails.geo_search( + geo_domain=[ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, + ) + ] + ) + self.assertEqual(len(result), 3) + + def test_geo_search_contains(self): + zip_item = self.env["dummy.zip"] + retails = self.env["retail.machine"].search([("name", "ilike", "34")]) + result = [] + for rec in retails: + result = zip_item.geo_search( + geo_domain=[("the_geom", "geo_contains", rec.the_point)], + ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Yens") + + retails = self.env["retail.machine"].search([("name", "ilike", "21")]) + result = [] + for rec in retails: + result = zip_item.geo_search( + geo_domain=[("the_geom", "geo_contains", rec.the_point)], + ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Mollens (VD))") + + def test_geo_search_touch(self): + zip_item = self.env["dummy.zip"] + + self.env["dummy.zip"].create( + { + "name": "10000", + "city": "Poly1", + "the_poly": "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))", + } + ) + + poly2 = self.env["dummy.zip"].create( + { + "name": "11000", + "city": "Poly2", + "the_poly": "POLYGON ((1 0, 1 1, 2 1, 2 0, 1 0))", + } + ) + + result = zip_item.geo_search( + geo_domain=[("the_poly", "geo_touch", poly2.the_poly)] + ) + + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Poly1") + + self.env["dummy.zip"].create( + { + "name": "1192", + "city": "Multi1", + "the_geom": """MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)), + ((1 0, 1 1, 2 1, 2 0, 1 0)))""", + } + ) + + multi_poly_2 = self.env["dummy.zip"].create( + { + "name": "6708", + "city": "Multi2", + "the_geom": """MULTIPOLYGON (((2 0, 2 1, 3 1, 3 0, 2 0)), + ((3 0, 3 1, 4 1, 4 0, 3 0)))""", + } + ) + + result = zip_item.geo_search( + geo_domain=[("the_geom", "geo_touch", multi_poly_2.the_geom)] + ) + + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Multi1") From b550b42d079873a1905f6956f86e8b883a5e3bba Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 6 Mar 2023 11:20:46 +0100 Subject: [PATCH 19/98] [IMP] base_geoengine: end model tests --- base_geoengine/tests/test_model.py | 132 +++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 9 deletions(-) diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 1bb3c3018..c6801356c 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -1,5 +1,7 @@ +import geojson from odoo_test_helper import FakeModelLoader from shapely import wkt +from shapely.geometry import shape from odoo.tests.common import TransactionCase @@ -140,7 +142,7 @@ def tearDownClass(cls): cls.loader.restore_registry() super(TestModel, cls).tearDownClass() - def test_create_multipolygon(self): + def test_create_multipolygon_wkt_format(self): """Create a multi polygon""" multi_polygon = """MULTIPOLYGON (((726469.938970306 5873145.03456248, 726520.174105436 5872946.03059195,726394.076006275 5872675.04267336, @@ -198,6 +200,7 @@ def test_create_multipolygon(self): ) ) + def test_create_multipolygon_geojson_format(self): multi_polygon_geojson = """{"type":"MultiPolygon","coordinates":[[[ [726469.938970306,5873145.03456248],[726520.174105436,5872946.03059195], [726394.076006275,5872675.04267336],[726404.709252018,5872259.98652277], @@ -246,6 +249,8 @@ def test_create_multipolygon(self): [726070.62161125,5873140.35732493],[726085.312084189,5873125.96087534], [726100.002508819,5873111.56442448],[726217.015284978,5873040.09276485], [726304.138055426,5873041.11333845],[726469.938970306,5873145.03456248]]]]}""" + geo_dict = geojson.loads(multi_polygon_geojson) + multi_polygon_loaded = shape(geo_dict) self.geo_model.geo_multi_polygon = multi_polygon_geojson self.assertTrue( self.geo_model.geo_multi_polygon.equals_exact( @@ -253,7 +258,7 @@ def test_create_multipolygon(self): ) ) - def test_create_polygon(self): + def test_create_polygon_wkt_format(self): """Create a polygon""" polygon = """POLYGON((-95.80078125000001 40.09488212232117, -95.07568359375001 36.68604127658193, @@ -265,16 +270,19 @@ def test_create_polygon(self): self.geo_model.geo_polygon.equals_exact(polygon_loaded, tolerance=0.2) ) + def test_create_polygon_geojson_format(self): polygon_geojson = """{"type":"Polygon","coordinates":[[ [-95.80078125000001,40.09488212232117], [-95.07568359375001,36.68604127658193],[-90.439453125,37.80544394934273], [-91.03271484375001,39.97712009843963],[-95.80078125000001,40.09488212232117]]]}""" + geo_dict = geojson.loads(polygon_geojson) + polygon_loaded = shape(geo_dict) self.geo_model.geo_polygon = polygon_geojson self.assertTrue( self.geo_model.geo_polygon.equals_exact(polygon_loaded, tolerance=0.2) ) - def test_create_line(self): + def test_create_line_wkt_format(self): """Create a line""" line = """LINESTRING(-98.81103515625001 38.97649248553944, -90.06591796875 38.99357205820945)""" @@ -284,15 +292,18 @@ def test_create_line(self): self.geo_model.geo_line.equals_exact(line_loaded, tolerance=0.2) ) + def test_create_line_geosjon_format(self): line_geojson = """{"type":"LineString","coordinates":[ [-98.81103515625001,38.97649248553944], [-90.06591796875,38.99357205820945]]}""" + geo_dict = geojson.loads(line_geojson) + line_loaded = shape(geo_dict) self.geo_model.geo_line = line_geojson self.assertTrue( self.geo_model.geo_line.equals_exact(line_loaded, tolerance=0.2) ) - def test_create_point(self): + def test_create_point_wkt_format(self): """Create a point""" point = "POINT(-99.2724609375 38.25543637637949)" self.geo_model.geo_point = point @@ -301,15 +312,18 @@ def test_create_point(self): self.geo_model.geo_point.equals_exact(point_loaded, tolerance=0.2) ) + def test_create_point_geosjon_format(self): point_geosjon = ( '{ "type": "Point", "coordinates": [-99.2724609375, 38.25543637637949] }' ) + geo_dict = geojson.loads(point_geosjon) + point_loaded = shape(geo_dict) self.geo_model.geo_point = point_geosjon self.assertTrue( self.geo_model.geo_point.equals_exact(point_loaded, tolerance=0.2) ) - def test_create_multi_line(self): + def test_create_multi_line_wkt_format(self): """Create multiline""" multi_line = ( "MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))" @@ -320,14 +334,17 @@ def test_create_multi_line(self): self.geo_model.geo_multi_line.equals_exact(multi_line_loaded, tolerance=0.2) ) + def test_create_multi_line_geojson_format(self): multi_line_geojson = """{"type":"MultiLineString","coordinates":[[ [10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]]}""" + geo_dict = geojson.loads(multi_line_geojson) + multi_line_loaded = shape(geo_dict) self.geo_model.geo_multi_line = multi_line_geojson self.assertTrue( self.geo_model.geo_multi_line.equals_exact(multi_line_loaded, tolerance=0.2) ) - def test_create_multi_point(self): + def test_create_multi_point_wkt_format(self): """Create multipoint""" multi_point = "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" self.geo_model.geo_multi_point = multi_point @@ -338,9 +355,12 @@ def test_create_multi_point(self): ) ) + def test_create_multo_point_geosjson_format(self): multi_point_geojson = ( '{"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]]}' ) + geo_dict = geojson.loads(multi_point_geojson) + multi_point_loaded = shape(geo_dict) self.geo_model.geo_multi_point = multi_point_geojson self.assertTrue( self.geo_model.geo_multi_point.equals_exact( @@ -352,7 +372,7 @@ def test_delete(self): self.geo_model.unlink() self.assertFalse(self.geo_model.exists()) - def test_geo_search_intersect(self): + def test_geo_search_intersect_for_zip_1169(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) @@ -367,6 +387,8 @@ def test_geo_search_intersect(self): ) self.assertEqual(len(result), 2) + def test_geo_search_intersect_for_zip_1149(self): + retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1146")]) result = retails.geo_search( geo_domain=[ @@ -379,7 +401,7 @@ def test_geo_search_intersect(self): ) self.assertEqual(len(result), 3) - def test_geo_search_contains(self): + def test_geo_search_contains_for_retails_34(self): zip_item = self.env["dummy.zip"] retails = self.env["retail.machine"].search([("name", "ilike", "34")]) result = [] @@ -390,6 +412,8 @@ def test_geo_search_contains(self): find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Yens") + def test_geo_search_contains_for_retails_21(self): + zip_item = self.env["dummy.zip"] retails = self.env["retail.machine"].search([("name", "ilike", "21")]) result = [] for rec in retails: @@ -399,7 +423,41 @@ def test_geo_search_contains(self): find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mollens (VD))") - def test_geo_search_touch(self): + def test_geo_search_within_for_retails_34(self): + retails = self.env["retail.machine"] + zip_item = self.env["dummy.zip"].search([("city", "ilike", "Yens")]) + result = [] + for rec in zip_item: + result = retails.geo_search( + domain=[("name", "ilike", "34")], + geo_domain=[("the_point", "geo_within", rec.the_geom)], + ) + find = self.env["retail.machine"].search([("id", "=", result[0])]) + self.assertEqual(find.name, "34") + + def test_geo_search_within_for_retails_21(self): + retails = self.env["retail.machine"] + zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) + result = [] + for rec in zip_item: + result = retails.geo_search( + domain=[("name", "ilike", "21")], + geo_domain=[("the_point", "geo_within", rec.the_geom)], + ) + find = self.env["retail.machine"].search([("id", "=", result[0])]) + self.assertEqual(find.name, "21") + + def test_geo_search_equals(self): + zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) + result = [] + result = zip_item.geo_search( + domain=[("city", "ilike", "Mollens (VD))")], + geo_domain=[("the_geom", "geo_equal", zip_item.the_geom)], + ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Mollens (VD))") + + def test_geo_search_touch_polygon(self): zip_item = self.env["dummy.zip"] self.env["dummy.zip"].create( @@ -425,6 +483,8 @@ def test_geo_search_touch(self): find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Poly1") + def test_geo_search_touch_multi_polygon(self): + zip_item = self.env["dummy.zip"] self.env["dummy.zip"].create( { "name": "1192", @@ -449,3 +509,57 @@ def test_geo_search_touch(self): find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Multi1") + + def test_geo_search_greater_multi_polygon(self): + zip_item = self.env["dummy.zip"] + mp1 = self.env["dummy.zip"].create( + { + "name": "1192", + "city": "Mp1", + "the_geom": """MULTIPOLYGON (((0 0, 0 5, 5 5, 5 0, 0 0)), + ((1 1, 2 1, 2 2, 1 2, 1 1)), ((3 3, 4 3, 4 4, 3 4, 3 3)))""", + } + ) + + self.env["dummy.zip"].create( + { + "name": "6708", + "city": "Mp2", + "the_geom": """MULTIPOLYGON (((-5 -5, -5 10, 10 10, 10 -5, -5 -5)), + ((-4 -4, -3 -4, -3 -3, -4 -3, -4 -4)), ((6 6, 7 6, 7 7, 6 7, 6 6)))""", + } + ) + + result = zip_item.geo_search( + domain=[("city", "ilike", "Mp2")], + geo_domain=[("the_geom", "geo_greater", mp1.the_geom)], + ) + + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Mp2") + + def test_geo_search_lesser_multi_polygon(self): + zip_item = self.env["dummy.zip"] + self.env["dummy.zip"].create( + { + "name": "1192", + "city": "Mp1", + "the_geom": """MULTIPOLYGON (((0 0, 0 5, 5 5, 5 0, 0 0)), + ((1 1, 2 1, 2 2, 1 2, 1 1)), ((3 3, 4 3, 4 4, 3 4, 3 3)))""", + } + ) + + mp2 = self.env["dummy.zip"].create( + { + "name": "6708", + "city": "Mp2", + "the_geom": """MULTIPOLYGON (((-5 -5, -5 10, 10 10, 10 -5, -5 -5)), + ((-4 -4, -3 -4, -3 -3, -4 -3, -4 -4)), ((6 6, 7 6, 7 7, 6 7, 6 6)))""", + } + ) + result = zip_item.geo_search( + domain=[("city", "ilike", "Mp1")], + geo_domain=[("the_geom", "geo_lesser", mp2.the_geom)], + ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) + self.assertEqual(find.city, "Mp1") From 42221bd92b3e04a809e0c677846a4c6fd7e6d3a4 Mon Sep 17 00:00:00 2001 From: Lindsay Date: Wed, 27 May 2020 08:57:00 +0200 Subject: [PATCH 20/98] changing the default SRID (correction of the previous one) --- base_geoengine/fields.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index 55732b576..c4e097172 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -13,7 +13,7 @@ logger = logging.getLogger(__name__) try: import geojson - from shapely.geometry import Point + from shapely.geometry import Point, asShape from shapely.geometry.base import BaseGeometry from shapely.wkb import loads as wkbloads except ImportError: @@ -98,6 +98,8 @@ def convert_to_read(self, value, record, use_name_get=True): @classmethod def load_geo(cls, wkb): """Load geometry into browse record after read was done""" + if isinstance(wkb, BaseGeometry): + return wkb return wkbloads(wkb, hex=True) if wkb else False def entry_to_shape(self, value, same_type=False): @@ -253,6 +255,37 @@ def from_latlon(cls, cr, latitude, longitude): res = cr.fetchone() return cls.load_geo(res[0]) + @classmethod + def to_latlon(cls, cr, geopoint): + """Convert a UTM coordinate point to (latitude, longitude):""" + # Line to execute to retrieve longitude, latitude from UTM in postgres command line: + # SELECT ST_X(geom), ST_Y(geom) FROM (SELECT ST_TRANSFORM(ST_SetSRID( + # ST_MakePoint(601179.61612, 6399375,681364), 900913), 4326) as geom) g; + if isinstance(geopoint, BaseGeometry): + geo_point_instance = geopoint + else: + geo_point_instance = asShape(geojson.loads(geopoint)) + cr.execute( + """ + SELECT + ST_TRANSFORM( + ST_SetSRID( + ST_MakePoint( + %(coord_x)s, %(coord_y)s + ), + %(srid)s + ), 4326)""", + { + "coord_x": geo_point_instance.x, + "coord_y": geo_point_instance.y, + "srid": cls._slots["srid"], + }, + ) + + res = cr.fetchone() + point_latlon = cls.load_geo(res[0]) + return point_latlon.x, point_latlon.y + class GeoPolygon(GeoField): """Field for POSTGIS geometry Polygon type""" From 88a59f4499adb1a946f983f52dbefa633fac1665 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 6 Mar 2023 16:45:55 +0100 Subject: [PATCH 21/98] [IMP] base_geoengine: add tests from_lat_lonand to_lat_lon --- base_geoengine/fields.py | 7 ++++--- base_geoengine/tests/test_model.py | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index c4e097172..d1cec890c 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -1,6 +1,7 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import json import logging from operator import attrgetter @@ -13,7 +14,7 @@ logger = logging.getLogger(__name__) try: import geojson - from shapely.geometry import Point, asShape + from shapely.geometry import Point, shape from shapely.geometry.base import BaseGeometry from shapely.wkb import loads as wkbloads except ImportError: @@ -264,7 +265,7 @@ def to_latlon(cls, cr, geopoint): if isinstance(geopoint, BaseGeometry): geo_point_instance = geopoint else: - geo_point_instance = asShape(geojson.loads(geopoint)) + geo_point_instance = shape(json.loads(geopoint)) cr.execute( """ SELECT @@ -278,7 +279,7 @@ def to_latlon(cls, cr, geopoint): { "coord_x": geo_point_instance.x, "coord_y": geo_point_instance.y, - "srid": cls._slots["srid"], + "srid": cls.srid, }, ) diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index c6801356c..f5911648e 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -5,6 +5,8 @@ from odoo.tests.common import TransactionCase +from ..fields import GeoPoint + class TestModel(TransactionCase): @classmethod @@ -563,3 +565,25 @@ def test_geo_search_lesser_multi_polygon(self): ) find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mp1") + + def test_from_lat_lon(self): + latitude = 49.72842315886126 + longitude = 5.400488376617026 + + # This is computed with postgis in postgres: + + expected_coordinates = [601179.61612, 6399375.681364] + + geo_point = GeoPoint.from_latlon(self.env.cr, latitude, longitude) + + self.assertAlmostEqual(geo_point.x, expected_coordinates[0], 4) + self.assertAlmostEqual(geo_point.y, expected_coordinates[1], 4) + + def test_to_lat_lon(self): + + geo_point = '{ "type": "Point", "coordinates": [601179.61612, 6399375.681364] }' + + longitude, latitude = GeoPoint.to_latlon(self.env.cr, geo_point) + + self.assertAlmostEqual(latitude, 49.72842315886126, 4) + self.assertAlmostEqual(longitude, 5.400488376617026, 4) From 638b3bd243c6fc925bf7cd029728907f0dea7c57 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Tue, 7 Mar 2023 14:12:07 +0100 Subject: [PATCH 22/98] [IMP] base_geoengine: refactor geo_search --- base_geoengine/geo_operators.py | 69 ++++++++++++++++++++ base_geoengine/tests/test_model.py | 101 ++++++++++++++--------------- 2 files changed, 116 insertions(+), 54 deletions(-) diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index d9f3efab5..c353cdfac 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -2,6 +2,11 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging +from shapely.geometry.base import BaseGeometry + +from odoo.osv import expression +from odoo.osv.expression import TERM_OPERATORS + from .fields import GeoField UNION_MAPPING = {"|": "OR", "&": "AND"} @@ -10,6 +15,70 @@ # TODO Refactor geo_search and dry up the get_**_sql code +original__leaf_to_sql = expression.expression._expression__leaf_to_sql + +GEO_OPERATORS = ( + "geo_greater", + "geo_lesser", + "geo_equal", + "geo_touch", + "geo_within", + "geo_contains", + "geo_intersect", +) +term_operators_list = list(TERM_OPERATORS) +for op in GEO_OPERATORS: + term_operators_list.append(op) + +expression.TERM_OPERATORS = tuple(term_operators_list) + +# TODO: check if left match with others + + +def __leaf_to_sql(self, leaf, model, alias): + left, operator, right = leaf + + current_field = model._fields[left] + if isinstance(current_field, GeoField): + table_alias = '"%s"' % alias + aliased_column = f"{table_alias}.{left}" + if isinstance(right, BaseGeometry): + base = current_field.entry_to_shape(right, same_type=False) + srid = current_field.srid + match operator: + case "geo_greater": + query = f" ST_Area({aliased_column}) > ST_Area(ST_GeomFromText(%s))" + params = [base.wkt] + case "geo_lesser": + query = f" ST_Area({aliased_column}) < ST_Area(ST_GeomFromText(%s))" + params = [base.wkt] + case "geo_equal": + query = f" {aliased_column} = ST_GeomFromText(%s)" + params = [base.wkt] + case "geo_touch": + op = f"ST_Touches(ST_SetSRID({aliased_column},{srid})" + query = f" {op}, ST_GeomFromText(%s, %s))" + params = [base.wkt, srid] + case "geo_within": + op = f"ST_Within(ST_SetSRID({aliased_column},{srid})" + query = f" {op}, ST_GeomFromText(%s, %s))" + params = [base.wkt, srid] + case "geo_contains": + op = f"ST_Contains(ST_SetSRID({aliased_column},{srid})" + query = f" {op}, ST_GeomFromText(%s, %s))" + params = [base.wkt, srid] + case "geo_intersect": + op = f"ST_Intersects(ST_SetSRID({aliased_column},{srid})" + query = f" {op}, ST_GeomFromText(%s, %s))" + params = [base.wkt, srid] + return query, params + else: + raise ValueError("Invalid field %r domain term %r" % (right, leaf)) + return original__leaf_to_sql(self, leaf=leaf, model=model, alias=alias) + + +expression.expression._expression__leaf_to_sql = __leaf_to_sql + def _get_geo_func(model, domain): """Map operator to function we do not want to override __getattr__""" diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index f5911648e..c37b355a0 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -1,3 +1,5 @@ +import logging + import geojson from odoo_test_helper import FakeModelLoader from shapely import wkt @@ -7,6 +9,8 @@ from ..fields import GeoPoint +_logger = logging.getLogger(__name__) + class TestModel(TransactionCase): @classmethod @@ -357,7 +361,7 @@ def test_create_multi_point_wkt_format(self): ) ) - def test_create_multo_point_geosjson_format(self): + def test_create_multi_point_geosjson_format(self): multi_point_geojson = ( '{"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]]}' ) @@ -374,43 +378,34 @@ def test_delete(self): self.geo_model.unlink() self.assertFalse(self.geo_model.exists()) + def test_geo_search_bad_right_request(self): + retails = self.env["retail.machine"] + with self.assertRaises(ValueError), retails.search( + [("the_point", "geo_greater", 10)] + ): + _logger.info("Success") + def test_geo_search_intersect_for_zip_1169(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) - - result = retails.geo_search( - geo_domain=[ - ( - "the_point", - "geo_intersect", - {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, - ) - ] - ) - self.assertEqual(len(result), 2) + result = retails.search([("the_point", "geo_intersect", zip_item.the_geom)]) + self.assertEqual(len(result.ids), 2) def test_geo_search_intersect_for_zip_1149(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1146")]) - result = retails.geo_search( - geo_domain=[ - ( - "the_point", - "geo_intersect", - {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, - ) - ] - ) - self.assertEqual(len(result), 3) + result = retails.search([("the_point", "geo_intersect", zip_item.the_geom)]) + self.assertEqual(len(result.ids), 3) def test_geo_search_contains_for_retails_34(self): zip_item = self.env["dummy.zip"] retails = self.env["retail.machine"].search([("name", "ilike", "34")]) result = [] for rec in retails: - result = zip_item.geo_search( - geo_domain=[("the_geom", "geo_contains", rec.the_point)], + result.extend( + zip_item.search([("the_geom", "geo_contains", rec.the_point)]).ids ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Yens") @@ -419,9 +414,10 @@ def test_geo_search_contains_for_retails_21(self): retails = self.env["retail.machine"].search([("name", "ilike", "21")]) result = [] for rec in retails: - result = zip_item.geo_search( - geo_domain=[("the_geom", "geo_contains", rec.the_point)], + result.extend( + zip_item.search([("the_geom", "geo_contains", rec.the_point)]).ids ) + find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mollens (VD))") @@ -430,10 +426,12 @@ def test_geo_search_within_for_retails_34(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Yens")]) result = [] for rec in zip_item: - result = retails.geo_search( - domain=[("name", "ilike", "34")], - geo_domain=[("the_point", "geo_within", rec.the_geom)], + result.extend( + retails.search( + [("name", "ilike", "34"), ("the_point", "geo_within", rec.the_geom)] + ).ids ) + find = self.env["retail.machine"].search([("id", "=", result[0])]) self.assertEqual(find.name, "34") @@ -442,20 +440,23 @@ def test_geo_search_within_for_retails_21(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) result = [] for rec in zip_item: - result = retails.geo_search( - domain=[("name", "ilike", "21")], - geo_domain=[("the_point", "geo_within", rec.the_geom)], + result.extend( + retails.search( + [("name", "ilike", "21"), ("the_point", "geo_within", rec.the_geom)] + ).ids ) + find = self.env["retail.machine"].search([("id", "=", result[0])]) self.assertEqual(find.name, "21") def test_geo_search_equals(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) - result = [] - result = zip_item.geo_search( - domain=[("city", "ilike", "Mollens (VD))")], - geo_domain=[("the_geom", "geo_equal", zip_item.the_geom)], - ) + result = zip_item.search( + [ + ("city", "ilike", "Mollens (VD))"), + ("the_geom", "geo_equal", zip_item.the_geom), + ] + ).ids find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mollens (VD))") @@ -477,10 +478,7 @@ def test_geo_search_touch_polygon(self): "the_poly": "POLYGON ((1 0, 1 1, 2 1, 2 0, 1 0))", } ) - - result = zip_item.geo_search( - geo_domain=[("the_poly", "geo_touch", poly2.the_poly)] - ) + result = zip_item.search([("the_poly", "geo_touch", poly2.the_poly)]).ids find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Poly1") @@ -504,10 +502,7 @@ def test_geo_search_touch_multi_polygon(self): ((3 0, 3 1, 4 1, 4 0, 3 0)))""", } ) - - result = zip_item.geo_search( - geo_domain=[("the_geom", "geo_touch", multi_poly_2.the_geom)] - ) + result = zip_item.search([("the_geom", "geo_touch", multi_poly_2.the_geom)]).ids find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Multi1") @@ -531,11 +526,9 @@ def test_geo_search_greater_multi_polygon(self): ((-4 -4, -3 -4, -3 -3, -4 -3, -4 -4)), ((6 6, 7 6, 7 7, 6 7, 6 6)))""", } ) - - result = zip_item.geo_search( - domain=[("city", "ilike", "Mp2")], - geo_domain=[("the_geom", "geo_greater", mp1.the_geom)], - ) + result = zip_item.search( + [("city", "ilike", "Mp2"), ("the_geom", "geo_greater", mp1.the_geom)] + ).ids find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mp2") @@ -559,10 +552,10 @@ def test_geo_search_lesser_multi_polygon(self): ((-4 -4, -3 -4, -3 -3, -4 -3, -4 -4)), ((6 6, 7 6, 7 7, 6 7, 6 6)))""", } ) - result = zip_item.geo_search( - domain=[("city", "ilike", "Mp1")], - geo_domain=[("the_geom", "geo_lesser", mp2.the_geom)], - ) + result = zip_item.search( + [("city", "ilike", "Mp1"), ("the_geom", "geo_lesser", mp2.the_geom)] + ).ids + find = self.env["dummy.zip"].search([("id", "=", result[0])]) self.assertEqual(find.city, "Mp1") From 6d6515ad55c96c9d0d527364b85dfdb1f0cdfe26 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Tue, 7 Mar 2023 15:46:37 +0100 Subject: [PATCH 23/98] [FIX] base_geoengine: current_field __leaf_to_sql --- base_geoengine/geo_operators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index c353cdfac..b836a6f8b 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -38,8 +38,8 @@ def __leaf_to_sql(self, leaf, model, alias): left, operator, right = leaf - current_field = model._fields[left] - if isinstance(current_field, GeoField): + current_field = model._fields.get(left) + if current_field and isinstance(current_field, GeoField): table_alias = '"%s"' % alias aliased_column = f"{table_alias}.{left}" if isinstance(right, BaseGeometry): From 58ffa2ce5333b05b05ab7437c29fd6851054ef6b Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Wed, 8 Mar 2023 09:46:57 +0100 Subject: [PATCH 24/98] [FIX] base_geoengine: Display Labels on Polygon --- .../geoengine_renderer.esm.js | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 96f86404d..d058ed146 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -287,7 +287,7 @@ export class GeoengineRenderer extends Component { this.geometryFields.forEach((geo_field) => delete attributes[geo_field]); if (cfg.display_polygon_labels === true) { - attributes.label = item[cfg.attribute_field_id[1]]; + attributes.label = item._values[cfg.attribute_field_id[1]]; } else { attributes.label = ""; } @@ -374,6 +374,11 @@ export class GeoengineRenderer extends Component { style: (feature) => { const value = feature.get("attributes")[indicator]; const color_idx = this.getClass(value, vals); + var label_text = feature.values_.attributes.label; + if (label_text === false) { + label_text = ""; + } + styles_map[colors[color_idx]][0].text_.text_ = label_text.toString(); return styles_map[colors[color_idx]]; }, }; @@ -418,7 +423,6 @@ export class GeoengineRenderer extends Component { var value = feature.get("attributes")[indicator]; return styles_map[value]; }, - legend: "", }; } @@ -429,16 +433,7 @@ export class GeoengineRenderer extends Component { const {fill, stroke} = this.createFillAndStroke(color); - var olStyleText = new ol.style.Text({ - text: "", - fill: new ol.style.Fill({ - color: "#000000", - }), - stroke: new ol.style.Stroke({ - color: "#FFFFFF", - width: 5, - }), - }); + var olStyleText = this.createStyleText(); var styles = [ new ol.style.Style({ image: new ol.style.Circle({ @@ -460,9 +455,21 @@ export class GeoengineRenderer extends Component { styles[0].text_.text_ = label_text; return styles; }, - legend: "", }; } + createStyleText() { + return new ol.style.Text({ + text: "", + fill: new ol.style.Fill({ + color: "#000000", + }), + stroke: new ol.style.Stroke({ + color: "#FFFFFF", + width: 5, + }), + }); + } + /** * Create feature style based on the color table. * @param {*} colors @@ -475,6 +482,7 @@ export class GeoengineRenderer extends Component { return; } const {fill, stroke} = this.createFillAndStroke(color); + var olStyleText = this.createStyleText(); const styles = [ new ol.style.Style({ image: new ol.style.Circle({ @@ -484,6 +492,7 @@ export class GeoengineRenderer extends Component { }), fill: fill, stroke: stroke, + text: olStyleText, }), ]; styles_map[color] = styles; From 539ec395de8aebc3d6af789d0387d4174ef0775e Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Wed, 8 Mar 2023 15:00:25 +0100 Subject: [PATCH 25/98] [FIX] base_geoengine: fix srid --- base_geoengine/fields.py | 2 +- base_geoengine/geo_operators.py | 2 +- base_geoengine/tests/test_model.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index d1cec890c..92a341b53 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -52,7 +52,7 @@ def convert_to_column(self, value, record, values=None): if shape_to_write.is_empty: return None else: - return shape_to_write.wkt + return f"SRID={self.srid};{shape_to_write.wkt}" def convert_to_cache(self, value, record, validate=True): val = value diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index b836a6f8b..f415507f1 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -53,7 +53,7 @@ def __leaf_to_sql(self, leaf, model, alias): query = f" ST_Area({aliased_column}) < ST_Area(ST_GeomFromText(%s))" params = [base.wkt] case "geo_equal": - query = f" {aliased_column} = ST_GeomFromText(%s)" + query = f" {aliased_column} = ST_GeomFromText(%s, {srid})" params = [base.wkt] case "geo_touch": op = f"ST_Touches(ST_SetSRID({aliased_column},{srid})" diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index c37b355a0..3f2f0714c 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -453,7 +453,7 @@ def test_geo_search_equals(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) result = zip_item.search( [ - ("city", "ilike", "Mollens (VD))"), + ("name", "=", "1146"), ("the_geom", "geo_equal", zip_item.the_geom), ] ).ids From ce6476d55dd80b33f8ce981f4bec2503dcaa0ae5 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Thu, 9 Mar 2023 15:42:49 +0100 Subject: [PATCH 26/98] [FIX] base_geoengine: fix column definition at install Before this change, simple geometry column were created without inforamtion regarding the geo type nor the defined SRID. Without these information, the srid has to be expliciltely set when converting data to column format. --- base_geoengine/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index 92a341b53..5290cb8dd 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -39,7 +39,7 @@ def column_format(self): @property def column_type(self): - return ("geometry", "geometry") + return ("geometry", f"geometry({self.geo_type}, {self.srid})") def convert_to_column(self, value, record, values=None): """Convert value to database format @@ -52,7 +52,7 @@ def convert_to_column(self, value, record, values=None): if shape_to_write.is_empty: return None else: - return f"SRID={self.srid};{shape_to_write.wkt}" + return shape_to_write.wkt def convert_to_cache(self, value, record, validate=True): val = value From 3f11eaf6f170e2323af4362c296cdd76e6756546 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Thu, 9 Mar 2023 15:55:26 +0100 Subject: [PATCH 27/98] [IMP] base_geoengine: geo_search is deprecated, normal search method had to be use. Add the possibility to have a right internal domain on the right --- base_geoengine/__init__.py | 1 + base_geoengine/deprecated.py | 133 +++++++++++++++ base_geoengine/expressions.py | 107 ++++++++++++ base_geoengine/fields.py | 4 - base_geoengine/geo_model.py | 11 +- base_geoengine/geo_operators.py | 262 +++++------------------------ base_geoengine/tests/test_model.py | 34 +++- 7 files changed, 317 insertions(+), 235 deletions(-) create mode 100644 base_geoengine/deprecated.py create mode 100644 base_geoengine/expressions.py diff --git a/base_geoengine/__init__.py b/base_geoengine/__init__.py index 3f12aa8e5..feac882cf 100644 --- a/base_geoengine/__init__.py +++ b/base_geoengine/__init__.py @@ -5,4 +5,5 @@ from . import geo_helper from . import geo_ir from . import fields +from . import expressions from .geo_db import init_postgis diff --git a/base_geoengine/deprecated.py b/base_geoengine/deprecated.py new file mode 100644 index 000000000..b81d26220 --- /dev/null +++ b/base_geoengine/deprecated.py @@ -0,0 +1,133 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from .fields import GeoField +from .geo_operators import GeoOperator + +UNION_MAPPING = {"|": "OR", "&": "AND"} + + +def _get_geo_func(model, domain): + """Map operator to function we do not want to override __getattr__""" + current_field = model._fields[domain[0]] + if isinstance(current_field, GeoField): + current_operator = GeoOperator(current_field) + attr = "get_{}_sql".format(domain[1]) + if hasattr(current_operator, attr): + return getattr(current_operator, attr) + raise ValueError("Field {} does not support {}".format(current_field, domain[1])) + + +def geo_search(model, domain=None, geo_domain=None, offset=0, limit=None, order=None): + """Deprecated! uses normal search method... + Perform a geo search it allows direct domain: + geo_search( + domain=[('name', 'ilike', 'toto']), + geo_domain=[('the_point', + 'geo_intersect', + myshaply_obj or mywkt or mygeojson)]) + + We can also support indirect geo_domain + (‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + + The supported operators are : + * geo_greater + * geo_lesser + * geo_equal + * geo_touch + * geo_within + * geo_contains + * geo_intersect + """ + cr = model._cr + domain = domain or [] + geo_domain = geo_domain or [] + model.env["ir.model.access"].check(model._name, "read") + # _where_calc = Computes the WHERE clause needed to implement an OpenERP domain. + # :param list domain: the domain to compute, active_test: whether the default + # filtering of records with + query = model._where_calc(domain, active_test=True) + # Add what's missing in query to implement all appropriate ir.rules + model._apply_ir_rules(query, "read") + order_by = "" + if order: + order_by = model._generate_order_by(order, query) or "" + from_clause, where_clause, where_clause_params = query.get_sql() + limit_str = limit and " LIMIT %d" % limit or "" + offset_str = offset and " OFFSET %d" % offset or "" + where_clause_arr = [] + if where_clause and where_clause_params: + where_clause_arr.append(where_clause) + # geosearch where clause generation + MODE = "" + UNION = "AND" + JOIN_MODE = "%s %s" + for domain in geo_domain: + if isinstance(domain, str): + if domain == "!": + MODE = "NOT" + if domain in list(UNION_MAPPING.keys()): + UNION = UNION_MAPPING[domain] + if where_clause_arr: + where_clause_arr.append(JOIN_MODE % (MODE, UNION)) + # We start computing geo spation SQL + if isinstance(domain, (list, tuple)): + if isinstance(domain[2], dict): # si à droite c'est un dict + # We are having indirect geo_operator like (‘geom’, ‘geo_...’, + # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + ref_search = domain[2] + rel_where_statement = [] + for key in ref_search: + i = key.rfind(".") + rel_model = key[0:i] + rel_col = key[i + 1 :] + rel_model = model.env[rel_model] + from_clause += ", {}".format(rel_model._table) + att_where_sql = "" + # we compute the attributes search on spatial rel + if ref_search[key]: + rel_query = rel_model._where_calc( + ref_search[key], active_test=True + ) + rel_res = rel_query.get_sql() + att_where_sql = rel_res[1] + where_clause_params += rel_res[2] + # we compute the spatial search on spatial rel + func = _get_geo_func(model, domain) + spatial_where_sql = func( + model._table, + domain[0], + domain[2], + rel_col=rel_col, + rel_model=rel_model, + ) + if att_where_sql: + rel_where_statement.append( + "({} AND {})".format(att_where_sql, spatial_where_sql) + ) + else: + rel_where_statement.append("(%s)" % (spatial_where_sql)) + where_clause_arr.append("AND ".join(rel_where_statement)) + else: + func = _get_geo_func(model, domain) + where_sql = func(model._table, domain[0], domain[2]) + where_clause_arr.append(where_sql) + if where_clause_arr: + where_statement = " WHERE %s" % (" ".join(where_clause_arr)) + else: + where_statement = "" + # pylint: disable=E8103 + sql = ( + 'SELECT "%s".id FROM ' % model._table + + from_clause + + where_statement + + order_by + + limit_str + + offset_str + ) + # logger.debug(cursor.mogrify(sql, where_clause_params)) + cr.execute(sql, where_clause_params) + res = cr.fetchall() + if res: + return [x[0] for x in res] + else: + return [] diff --git a/base_geoengine/expressions.py b/base_geoengine/expressions.py new file mode 100644 index 000000000..44dfcea9e --- /dev/null +++ b/base_geoengine/expressions.py @@ -0,0 +1,107 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.osv import expression +from odoo.osv.expression import TERM_OPERATORS + +from .fields import GeoField +from .geo_operators import GeoOperator + +original__leaf_to_sql = expression.expression._expression__leaf_to_sql + +GEO_OPERATORS = { + "geo_greater": ">", + "geo_lesser": "<", + "geo_equal": "=", + "geo_touch": "ST_Touches", + "geo_within": "ST_Within", + "geo_contains": "ST_Contains", + "geo_intersect": "ST_Intersects", +} +term_operators_list = list(TERM_OPERATORS) +for op in GEO_OPERATORS: + term_operators_list.append(op) + +expression.TERM_OPERATORS = tuple(term_operators_list) + + +def __leaf_to_sql(self, leaf, model, alias): + left, operator, right = leaf + + if isinstance(leaf, (list, tuple)): + current_field = model._fields.get(left) + current_operator = GeoOperator(current_field) + if current_field and isinstance(current_field, GeoField): + params = [] + if isinstance(right, dict): + # We are having indirect geo_operator like (‘geom’, ‘geo_...’, + # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + ref_search = right + sub_queries = [] + for key in ref_search: + i = key.rfind(".") + rel_model = key[0:i] + rel_col = key[i + 1 :] + rel_model = model.env[rel_model] + # we compute the attributes search on spatial rel + if ref_search[key]: + rel_query = rel_model._where_calc( + ref_search[key], active_test=True + ) + model._apply_ir_rules(rel_query, "read") + if len(GEO_OPERATORS[operator]) > 1: + rel_query.add_where( + f'{GEO_OPERATORS[operator]}("{alias}"."{left}", {rel_col})' + ) + else: + rel_query.add_where( + f'"{alias}"."{left}" {GEO_OPERATORS[operator]} {rel_col}' + ) + subquery, subparams = rel_query.subselect("1") + sub_queries.append(f"EXISTS({subquery})") + params += subparams + query = " AND ".join(sub_queries) + else: + query = get_geo_func( + current_operator, operator, left, right, params, model._table + ) + return query, params + return original__leaf_to_sql(self, leaf=leaf, model=model, alias=alias) + + +def get_geo_func( + current_operator, operator, left, right, params, table, rel_col=None, rel_model=None +): + match operator: + case "geo_greater": + query = current_operator.get_geo_greater_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_lesser": + query = current_operator.get_geo_lesser_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_equal": + query = current_operator.get_geo_equal_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_touch": + query = current_operator.get_geo_touch_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_within": + query = current_operator.get_geo_within_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_contains": + query = current_operator.get_geo_contains_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + case "geo_intersect": + query = current_operator.get_geo_intersect_sql( + table, left, right, params, rel_col=rel_col, rel_model=rel_model + ) + return query + + +expression.expression._expression__leaf_to_sql = __leaf_to_sql diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index 5290cb8dd..ed9dc40f7 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -33,10 +33,6 @@ class GeoField(fields.Field): srid = 3857 gist_index = True - @property - def column_format(self): - return "ST_GeomFromText(%s, {})".format(self.srid) - @property def column_type(self): return ("geometry", f"geometry({self.geo_type}, {self.srid})") diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 975dc02eb..766c79bbd 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -1,15 +1,19 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + from odoo import _, api, models from odoo.exceptions import MissingError, UserError -from . import fields as geo_fields, geo_operators +from . import deprecated, fields as geo_fields DEFAULT_EXTENT = ( "-123164.85222423, 5574694.9538936, " "1578017.6490538, 6186191.1800898" ) +_logger = logging.getLogger(__name__) + class GeoModel(models.AbstractModel): """Extend Base class for to allow definition of geo fields.""" @@ -151,9 +155,12 @@ def geo_search( # and do a search on standard attributes # Limit and offset are managed after, we may loose a lot of performance # here + _logger.debug( + "geo_search is deprecated: uses search method defined on base model" + ) domain = domain or [] geo_domain = geo_domain or [] - return geo_operators.geo_search( + return deprecated.geo_search( self, domain=domain, geo_domain=geo_domain, diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index f415507f1..376d1417a 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -2,208 +2,12 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from shapely.geometry.base import BaseGeometry - -from odoo.osv import expression -from odoo.osv.expression import TERM_OPERATORS - -from .fields import GeoField - UNION_MAPPING = {"|": "OR", "&": "AND"} logger = logging.getLogger("geoengine.sql.debug") -# TODO Refactor geo_search and dry up the get_**_sql code - -original__leaf_to_sql = expression.expression._expression__leaf_to_sql - -GEO_OPERATORS = ( - "geo_greater", - "geo_lesser", - "geo_equal", - "geo_touch", - "geo_within", - "geo_contains", - "geo_intersect", -) -term_operators_list = list(TERM_OPERATORS) -for op in GEO_OPERATORS: - term_operators_list.append(op) - -expression.TERM_OPERATORS = tuple(term_operators_list) - -# TODO: check if left match with others - - -def __leaf_to_sql(self, leaf, model, alias): - left, operator, right = leaf - - current_field = model._fields.get(left) - if current_field and isinstance(current_field, GeoField): - table_alias = '"%s"' % alias - aliased_column = f"{table_alias}.{left}" - if isinstance(right, BaseGeometry): - base = current_field.entry_to_shape(right, same_type=False) - srid = current_field.srid - match operator: - case "geo_greater": - query = f" ST_Area({aliased_column}) > ST_Area(ST_GeomFromText(%s))" - params = [base.wkt] - case "geo_lesser": - query = f" ST_Area({aliased_column}) < ST_Area(ST_GeomFromText(%s))" - params = [base.wkt] - case "geo_equal": - query = f" {aliased_column} = ST_GeomFromText(%s, {srid})" - params = [base.wkt] - case "geo_touch": - op = f"ST_Touches(ST_SetSRID({aliased_column},{srid})" - query = f" {op}, ST_GeomFromText(%s, %s))" - params = [base.wkt, srid] - case "geo_within": - op = f"ST_Within(ST_SetSRID({aliased_column},{srid})" - query = f" {op}, ST_GeomFromText(%s, %s))" - params = [base.wkt, srid] - case "geo_contains": - op = f"ST_Contains(ST_SetSRID({aliased_column},{srid})" - query = f" {op}, ST_GeomFromText(%s, %s))" - params = [base.wkt, srid] - case "geo_intersect": - op = f"ST_Intersects(ST_SetSRID({aliased_column},{srid})" - query = f" {op}, ST_GeomFromText(%s, %s))" - params = [base.wkt, srid] - return query, params - else: - raise ValueError("Invalid field %r domain term %r" % (right, leaf)) - return original__leaf_to_sql(self, leaf=leaf, model=model, alias=alias) - - -expression.expression._expression__leaf_to_sql = __leaf_to_sql - -def _get_geo_func(model, domain): - """Map operator to function we do not want to override __getattr__""" - current_field = model._fields[domain[0]] - if isinstance(current_field, GeoField): - current_operator = GeoOperator(current_field) - attr = "get_{}_sql".format(domain[1]) - if hasattr(current_operator, attr): - return getattr(current_operator, attr) - raise ValueError("Field {} does not support {}".format(current_field, domain[1])) - - -def geo_search(model, domain=None, geo_domain=None, offset=0, limit=None, order=None): - """Perform a geo search it allows direct domain: - geo_search( - domain=[('name', 'ilike', 'toto']), - geo_domain=[('the_point', - 'geo_intersect', - myshaply_obj or mywkt or mygeojson)]) - - We can also support indirect geo_domain - (‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) - - The supported operators are : - * geo_greater - * geo_lesser - * geo_equal - * geo_touch - * geo_within - * geo_contains - * geo_intersect - """ - cr = model._cr - domain = domain or [] - geo_domain = geo_domain or [] - model.env["ir.model.access"].check(model._name, "read") - # _where_calc = Computes the WHERE clause needed to implement an OpenERP domain. - # :param list domain: the domain to compute, active_test: whether the default - # filtering of records with - query = model._where_calc(domain, active_test=True) - # Add what's missing in query to implement all appropriate ir.rules - model._apply_ir_rules(query, "read") - order_by = "" - if order: - order_by = model._generate_order_by(order, query) or "" - from_clause, where_clause, where_clause_params = query.get_sql() - limit_str = limit and " LIMIT %d" % limit or "" - offset_str = offset and " OFFSET %d" % offset or "" - where_clause_arr = [] - if where_clause and where_clause_params: - where_clause_arr.append(where_clause) - # geosearch where clause generation - MODE = "" - UNION = "AND" - JOIN_MODE = "%s %s" - for domain in geo_domain: - if isinstance(domain, str): - if domain == "!": - MODE = "NOT" - if domain in list(UNION_MAPPING.keys()): - UNION = UNION_MAPPING[domain] - if where_clause_arr: - where_clause_arr.append(JOIN_MODE % (MODE, UNION)) - # We start computing geo spation SQL - if isinstance(domain, (list, tuple)): - if isinstance(domain[2], dict): - # We are having indirect geo_operator like (‘geom’, ‘geo_...’, - # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) - ref_search = domain[2] - rel_where_statement = [] - for key in ref_search: - i = key.rfind(".") - rel_model = key[0:i] - rel_col = key[i + 1 :] - rel_model = model.env[rel_model] - from_clause += ", {}".format(rel_model._table) - att_where_sql = "" - # we compute the attributes search on spatial rel - if ref_search[key]: - rel_query = rel_model._where_calc( - ref_search[key], active_test=True - ) - rel_res = rel_query.get_sql() - att_where_sql = rel_res[1] - where_clause_params += rel_res[2] - # we compute the spatial search on spatial rel - func = _get_geo_func(model, domain) - spatial_where_sql = func( - model._table, - domain[0], - domain[2], - rel_col=rel_col, - rel_model=rel_model, - ) - if att_where_sql: - rel_where_statement.append( - "({} AND {})".format(att_where_sql, spatial_where_sql) - ) - else: - rel_where_statement.append("(%s)" % (spatial_where_sql)) - where_clause_arr.append("AND ".join(rel_where_statement)) - else: - func = _get_geo_func(model, domain) - where_sql = func(model._table, domain[0], domain[2]) - where_clause_arr.append(where_sql) - if where_clause_arr: - where_statement = " WHERE %s" % (" ".join(where_clause_arr)) - else: - where_statement = "" - # pylint: disable=E8103 - sql = ( - 'SELECT "%s".id FROM ' % model._table - + from_clause - + where_statement - + order_by - + limit_str - + offset_str - ) - # logger.debug(cursor.mogrify(sql, where_clause_params)) - cr.execute(sql, where_clause_params) - res = cr.fetchall() - if res: - return [x[0] for x in res] - else: - return [] +# Deprecated : use the standard search. class GeoOperator(object): @@ -222,7 +26,7 @@ def get_rel_field(self, rel_col, rel_model): return "{}.{}".format(rel_model._table, rel_col) def _get_direct_como_op_sql( - self, table, col, value, rel_col=None, rel_model=None, op="" + self, table, col, value, params, rel_col=None, rel_model=None, op="" ): """provide raw sql for geater and lesser operators""" if isinstance(value, (int, float)): @@ -235,15 +39,19 @@ def _get_direct_como_op_sql( else: if rel_col and rel_model is not None: compare_to = self.get_rel_field(rel_col, rel_model) + return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText('{}'))".format( + table, col, op, compare_to + ) else: base = self.geo_field.entry_to_shape(value, same_type=False) compare_to = base.wkt - return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText('{}'))".format( - table, col, op, compare_to - ) + params.append(base.wkt) + return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText(%s))".format( + table, col, op + ) def _get_postgis_comp_sql( - self, table, col, value, rel_col=None, rel_model=None, op="" + self, table, col, value, params, rel_col=None, rel_model=None, op="" ): """return raw sql for all search based on St_**(a, b) posgis operator""" if rel_col and rel_model is not None: @@ -251,28 +59,33 @@ def _get_postgis_comp_sql( else: base = self.geo_field.entry_to_shape(value, same_type=False) srid = self.geo_field.srid - compare_to = "ST_GeomFromText('{}',{})".format(base.wkt, srid) - return " {}(ST_SetSRID({}.{},{}), {})".format( - op, table, col, srid, compare_to - ) + params.append(base.wkt) + params.append(srid) + return f"{op}({table}.{col}, ST_GeomFromText(%s, %s))" return " {}({}.{}, {})".format(op, table, col, compare_to) - def get_geo_greater_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_greater_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_greater operator (used for area comparison) """ return self._get_direct_como_op_sql( - table, col, value, rel_col, rel_model, op=">" + table, col, value, params, rel_col, rel_model, op=">" ) - def get_geo_lesser_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_lesser_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_lesser operator (used for area comparison)""" return self._get_direct_como_op_sql( - table, col, value, rel_col, rel_model, op="<" + table, col, value, params, rel_col, rel_model, op="<" ) - def get_geo_equal_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_equal_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_equal operator (used for equality comparison) """ @@ -280,37 +93,46 @@ def get_geo_equal_sql(self, table, col, value, rel_col=None, rel_model=None): compare_to = self.get_rel_field(rel_col, rel_model) else: base = self.geo_field.entry_to_shape(value, same_type=False) - compare_to = "ST_GeomFromText('{}')".format(base.wkt) + compare_to = "ST_GeomFromText(%s)" + params.append(base.wkt) return " {}.{} = {}".format(table, col, compare_to) - def get_geo_intersect_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_intersect_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_intersec operator (used for spatial comparison) """ return self._get_postgis_comp_sql( - table, col, value, rel_col, rel_model, op="ST_Intersects" + table, col, value, params, rel_col, rel_model, op="ST_Intersects" ) - def get_geo_touch_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_touch_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_touch operator (used for spatial comparison) """ return self._get_postgis_comp_sql( - table, col, value, rel_col, rel_model, op="ST_Touches" + table, col, value, params, rel_col, rel_model, op="ST_Touches" ) - def get_geo_within_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_within_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_within operator (used for spatial comparison) """ return self._get_postgis_comp_sql( - table, col, value, rel_col, rel_model, op="ST_Within" + table, col, value, params, rel_col, rel_model, op="ST_Within" ) - def get_geo_contains_sql(self, table, col, value, rel_col=None, rel_model=None): + def get_geo_contains_sql( + self, table, col, value, params, rel_col=None, rel_model=None + ): """Returns raw sql for geo_contains operator (used for spatial comparison) """ return self._get_postgis_comp_sql( - table, col, value, rel_col, rel_model, op="ST_Contains" + table, col, value, params, rel_col, rel_model, op="ST_Contains" ) diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 3f2f0714c..8a380779f 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -378,13 +378,6 @@ def test_delete(self): self.geo_model.unlink() self.assertFalse(self.geo_model.exists()) - def test_geo_search_bad_right_request(self): - retails = self.env["retail.machine"] - with self.assertRaises(ValueError), retails.search( - [("the_point", "geo_greater", 10)] - ): - _logger.info("Success") - def test_geo_search_intersect_for_zip_1169(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) @@ -453,8 +446,11 @@ def test_geo_search_equals(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) result = zip_item.search( [ - ("name", "=", "1146"), - ("the_geom", "geo_equal", zip_item.the_geom), + ( + "the_geom", + "geo_equal", + {"dummy.zip.the_geom": [("name", "ilike", "1146")]}, + ), ] ).ids find = self.env["dummy.zip"].search([("id", "=", result[0])]) @@ -580,3 +576,23 @@ def test_to_lat_lon(self): self.assertAlmostEqual(latitude, 49.72842315886126, 4) self.assertAlmostEqual(longitude, 5.400488376617026, 4) + + def test_deprecated_geo_search__intersect_for_zip_1169(self): + retails = self.env["retail.machine"] + zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) + result = retails.geo_search([("the_point", "geo_intersect", zip_item.the_geom)]) + self.assertEqual(len(result), 2) + + def test_deprecated_geo_search__intersect_for_zip_1169_with_dict(self): + retails = self.env["retail.machine"] + zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) + result = retails.geo_search( + [ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, + ) + ] + ) + self.assertEqual(len(result), 2) From dcea2fb3db22f44e1295655583afe37243cd5fc8 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Fri, 10 Mar 2023 11:27:20 +0100 Subject: [PATCH 28/98] [FIX] base_geoengine: fix __leaf_to_sql by adding our own where_calc method with our alias to perform search method and fix tests --- base_geoengine/deprecated.py | 133 ---------------- base_geoengine/expressions.py | 82 ++++++---- base_geoengine/geo_model.py | 21 +-- base_geoengine/geo_operators.py | 126 ++++------------ base_geoengine/tests/test_model.py | 234 +++++++++++++++++++++-------- 5 files changed, 268 insertions(+), 328 deletions(-) delete mode 100644 base_geoengine/deprecated.py diff --git a/base_geoengine/deprecated.py b/base_geoengine/deprecated.py deleted file mode 100644 index b81d26220..000000000 --- a/base_geoengine/deprecated.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from .fields import GeoField -from .geo_operators import GeoOperator - -UNION_MAPPING = {"|": "OR", "&": "AND"} - - -def _get_geo_func(model, domain): - """Map operator to function we do not want to override __getattr__""" - current_field = model._fields[domain[0]] - if isinstance(current_field, GeoField): - current_operator = GeoOperator(current_field) - attr = "get_{}_sql".format(domain[1]) - if hasattr(current_operator, attr): - return getattr(current_operator, attr) - raise ValueError("Field {} does not support {}".format(current_field, domain[1])) - - -def geo_search(model, domain=None, geo_domain=None, offset=0, limit=None, order=None): - """Deprecated! uses normal search method... - Perform a geo search it allows direct domain: - geo_search( - domain=[('name', 'ilike', 'toto']), - geo_domain=[('the_point', - 'geo_intersect', - myshaply_obj or mywkt or mygeojson)]) - - We can also support indirect geo_domain - (‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) - - The supported operators are : - * geo_greater - * geo_lesser - * geo_equal - * geo_touch - * geo_within - * geo_contains - * geo_intersect - """ - cr = model._cr - domain = domain or [] - geo_domain = geo_domain or [] - model.env["ir.model.access"].check(model._name, "read") - # _where_calc = Computes the WHERE clause needed to implement an OpenERP domain. - # :param list domain: the domain to compute, active_test: whether the default - # filtering of records with - query = model._where_calc(domain, active_test=True) - # Add what's missing in query to implement all appropriate ir.rules - model._apply_ir_rules(query, "read") - order_by = "" - if order: - order_by = model._generate_order_by(order, query) or "" - from_clause, where_clause, where_clause_params = query.get_sql() - limit_str = limit and " LIMIT %d" % limit or "" - offset_str = offset and " OFFSET %d" % offset or "" - where_clause_arr = [] - if where_clause and where_clause_params: - where_clause_arr.append(where_clause) - # geosearch where clause generation - MODE = "" - UNION = "AND" - JOIN_MODE = "%s %s" - for domain in geo_domain: - if isinstance(domain, str): - if domain == "!": - MODE = "NOT" - if domain in list(UNION_MAPPING.keys()): - UNION = UNION_MAPPING[domain] - if where_clause_arr: - where_clause_arr.append(JOIN_MODE % (MODE, UNION)) - # We start computing geo spation SQL - if isinstance(domain, (list, tuple)): - if isinstance(domain[2], dict): # si à droite c'est un dict - # We are having indirect geo_operator like (‘geom’, ‘geo_...’, - # {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) - ref_search = domain[2] - rel_where_statement = [] - for key in ref_search: - i = key.rfind(".") - rel_model = key[0:i] - rel_col = key[i + 1 :] - rel_model = model.env[rel_model] - from_clause += ", {}".format(rel_model._table) - att_where_sql = "" - # we compute the attributes search on spatial rel - if ref_search[key]: - rel_query = rel_model._where_calc( - ref_search[key], active_test=True - ) - rel_res = rel_query.get_sql() - att_where_sql = rel_res[1] - where_clause_params += rel_res[2] - # we compute the spatial search on spatial rel - func = _get_geo_func(model, domain) - spatial_where_sql = func( - model._table, - domain[0], - domain[2], - rel_col=rel_col, - rel_model=rel_model, - ) - if att_where_sql: - rel_where_statement.append( - "({} AND {})".format(att_where_sql, spatial_where_sql) - ) - else: - rel_where_statement.append("(%s)" % (spatial_where_sql)) - where_clause_arr.append("AND ".join(rel_where_statement)) - else: - func = _get_geo_func(model, domain) - where_sql = func(model._table, domain[0], domain[2]) - where_clause_arr.append(where_sql) - if where_clause_arr: - where_statement = " WHERE %s" % (" ".join(where_clause_arr)) - else: - where_statement = "" - # pylint: disable=E8103 - sql = ( - 'SELECT "%s".id FROM ' % model._table - + from_clause - + where_statement - + order_by - + limit_str - + offset_str - ) - # logger.debug(cursor.mogrify(sql, where_clause_params)) - cr.execute(sql, where_clause_params) - res = cr.fetchall() - if res: - return [x[0] for x in res] - else: - return [] diff --git a/base_geoengine/expressions.py b/base_geoengine/expressions.py index 44dfcea9e..552183485 100644 --- a/base_geoengine/expressions.py +++ b/base_geoengine/expressions.py @@ -1,8 +1,12 @@ # Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import random +import string + from odoo.osv import expression from odoo.osv.expression import TERM_OPERATORS +from odoo.tools import Query from .fields import GeoField from .geo_operators import GeoOperator @@ -45,18 +49,34 @@ def __leaf_to_sql(self, leaf, model, alias): rel_model = model.env[rel_model] # we compute the attributes search on spatial rel if ref_search[key]: - rel_query = rel_model._where_calc( - ref_search[key], active_test=True + rel_alias = ( + rel_model._table + + "_" + + "".join(random.choices(string.ascii_lowercase, k=5)) + ) + rel_query = where_calc( + rel_model, + ref_search[key], + active_test=True, + alias=rel_alias, ) model._apply_ir_rules(rel_query, "read") - if len(GEO_OPERATORS[operator]) > 1: + if operator == "geo_equal": rel_query.add_where( - f'{GEO_OPERATORS[operator]}("{alias}"."{left}", {rel_col})' + f'"{alias}"."{left}" {GEO_OPERATORS[operator]} ' + f"{rel_alias}.{rel_col}" + ) + elif operator in ("geo_greater", "geo_lesser"): + rel_query.add_where( + f"ST_Area({alias}.{left}) {GEO_OPERATORS[operator]} " + f"ST_Area({rel_alias}.{rel_col})" ) else: rel_query.add_where( - f'"{alias}"."{left}" {GEO_OPERATORS[operator]} {rel_col}' + f'{GEO_OPERATORS[operator]}("{alias}"."{left}", ' + f"{rel_alias}.{rel_col})" ) + subquery, subparams = rel_query.subselect("1") sub_queries.append(f"EXISTS({subquery})") params += subparams @@ -69,38 +89,42 @@ def __leaf_to_sql(self, leaf, model, alias): return original__leaf_to_sql(self, leaf=leaf, model=model, alias=alias) -def get_geo_func( - current_operator, operator, left, right, params, table, rel_col=None, rel_model=None -): +def get_geo_func(current_operator, operator, left, right, params, table): match operator: case "geo_greater": - query = current_operator.get_geo_greater_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_greater_sql(table, left, right, params) case "geo_lesser": - query = current_operator.get_geo_lesser_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_lesser_sql(table, left, right, params) case "geo_equal": - query = current_operator.get_geo_equal_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_equal_sql(table, left, right, params) case "geo_touch": - query = current_operator.get_geo_touch_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_touch_sql(table, left, right, params) case "geo_within": - query = current_operator.get_geo_within_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_within_sql(table, left, right, params) case "geo_contains": - query = current_operator.get_geo_contains_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_contains_sql(table, left, right, params) case "geo_intersect": - query = current_operator.get_geo_intersect_sql( - table, left, right, params, rel_col=rel_col, rel_model=rel_model - ) + query = current_operator.get_geo_intersect_sql(table, left, right, params) + case _: + raise NotImplementedError(f"The operator {operator} is not supported") + return query + + +def where_calc(model, domain, active_test=True, alias=None): + """ + This method is copied from base, we need to create our own query. + """ + # if the object has an active field ('active', 'x_active'), filter out all + # inactive records unless they were explicitly asked for + if model._active_name and active_test and model._context.get("active_test", True): + # the item[0] trick below works for domain items and '&'/'|'/'!' + # operators too + if not any(item[0] == model._active_name for item in domain): + domain = [(model._active_name, "=", 1)] + domain + + query = Query(model.env.cr, alias, model._table) + if domain: + return expression.expression(domain, model, alias=alias, query=query).query return query diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 766c79bbd..53ce11ec7 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -5,8 +5,9 @@ from odoo import _, api, models from odoo.exceptions import MissingError, UserError +from odoo.osv.expression import AND -from . import deprecated, fields as geo_fields +from . import fields as geo_fields DEFAULT_EXTENT = ( "-123164.85222423, 5574694.9538936, " "1578017.6490538, 6186191.1800898" @@ -160,11 +161,13 @@ def geo_search( ) domain = domain or [] geo_domain = geo_domain or [] - return deprecated.geo_search( - self, - domain=domain, - geo_domain=geo_domain, - offset=offset, - limit=limit, - order=order, - ) + search_domain = domain or [] + if domain and geo_domain: + search_domain = AND([domain, geo_domain]) + elif geo_domain: + search_domain = geo_domain + + if not search_domain: + raise ValueError("You must at least provide one of domain or geo_domain") + + return self.search(search_domain, limit=limit, offset=offset, order=order) diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index 376d1417a..ad449dfc8 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -1,138 +1,76 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging - -UNION_MAPPING = {"|": "OR", "&": "AND"} - -logger = logging.getLogger("geoengine.sql.debug") - - -# Deprecated : use the standard search. class GeoOperator(object): def __init__(self, geo_field): self.geo_field = geo_field - def get_rel_field(self, rel_col, rel_model): - """Retrieves the expression to use in PostGIS statement for a spatial - rel search""" - try: - rel_model._fields[rel_col] - except Exception: - raise Exception( - "Model {} has no column {}".format(rel_model._name, rel_col) - ) from None - return "{}.{}".format(rel_model._table, rel_col) - - def _get_direct_como_op_sql( - self, table, col, value, params, rel_col=None, rel_model=None, op="" - ): + def _get_direct_como_op_sql(self, table, col, value, params, op=""): """provide raw sql for geater and lesser operators""" if isinstance(value, (int, float)): - if rel_col and rel_model: - raise Exception( - "Area %s does not support int compare for relation " - "search" % (op,) - ) return " ST_Area({}.{}) {} {}".format(table, col, op, value) - else: - if rel_col and rel_model is not None: - compare_to = self.get_rel_field(rel_col, rel_model) - return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText('{}'))".format( - table, col, op, compare_to - ) - else: - base = self.geo_field.entry_to_shape(value, same_type=False) - compare_to = base.wkt - params.append(base.wkt) - return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText(%s))".format( - table, col, op - ) - - def _get_postgis_comp_sql( - self, table, col, value, params, rel_col=None, rel_model=None, op="" - ): - """return raw sql for all search based on St_**(a, b) posgis operator""" - if rel_col and rel_model is not None: - compare_to = self.get_rel_field(rel_col, rel_model) else: base = self.geo_field.entry_to_shape(value, same_type=False) - srid = self.geo_field.srid params.append(base.wkt) - params.append(srid) - return f"{op}({table}.{col}, ST_GeomFromText(%s, %s))" - return " {}({}.{}, {})".format(op, table, col, compare_to) + return " ST_Area({}.{}) {} ST_Area(ST_GeomFromText(%s))".format( + table, col, op + ) - def get_geo_greater_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def _get_postgis_comp_sql(self, table, col, value, params, op=""): + """return raw sql for all search based on St_**(a, b) posgis operator""" + base = self.geo_field.entry_to_shape(value, same_type=False) + srid = self.geo_field.srid + params.append(base.wkt) + params.append(srid) + return f"{op}({table}.{col}, ST_GeomFromText(%s, %s))" + + def get_geo_greater_sql(self, table, col, value, params): """Returns raw sql for geo_greater operator (used for area comparison) """ - return self._get_direct_como_op_sql( - table, col, value, params, rel_col, rel_model, op=">" - ) + return self._get_direct_como_op_sql(table, col, value, params, op=">") - def get_geo_lesser_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def get_geo_lesser_sql(self, table, col, value, params): """Returns raw sql for geo_lesser operator (used for area comparison)""" - return self._get_direct_como_op_sql( - table, col, value, params, rel_col, rel_model, op="<" - ) + return self._get_direct_como_op_sql(table, col, value, params, op="<") def get_geo_equal_sql( - self, table, col, value, params, rel_col=None, rel_model=None + self, + table, + col, + value, + params, ): """Returns raw sql for geo_equal operator (used for equality comparison) """ - if rel_col and rel_model is not None: - compare_to = self.get_rel_field(rel_col, rel_model) - else: - base = self.geo_field.entry_to_shape(value, same_type=False) - compare_to = "ST_GeomFromText(%s)" - params.append(base.wkt) + base = self.geo_field.entry_to_shape(value, same_type=False) + compare_to = "ST_GeomFromText(%s)" + params.append(base.wkt) return " {}.{} = {}".format(table, col, compare_to) - def get_geo_intersect_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def get_geo_intersect_sql(self, table, col, value, params): """Returns raw sql for geo_intersec operator (used for spatial comparison) """ - return self._get_postgis_comp_sql( - table, col, value, params, rel_col, rel_model, op="ST_Intersects" - ) + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Intersects") - def get_geo_touch_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def get_geo_touch_sql(self, table, col, value, params): """Returns raw sql for geo_touch operator (used for spatial comparison) """ - return self._get_postgis_comp_sql( - table, col, value, params, rel_col, rel_model, op="ST_Touches" - ) + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Touches") - def get_geo_within_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def get_geo_within_sql(self, table, col, value, params): """Returns raw sql for geo_within operator (used for spatial comparison) """ - return self._get_postgis_comp_sql( - table, col, value, params, rel_col, rel_model, op="ST_Within" - ) + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Within") - def get_geo_contains_sql( - self, table, col, value, params, rel_col=None, rel_model=None - ): + def get_geo_contains_sql(self, table, col, value, params): """Returns raw sql for geo_contains operator (used for spatial comparison) """ - return self._get_postgis_comp_sql( - table, col, value, params, rel_col, rel_model, op="ST_Contains" - ) + return self._get_postgis_comp_sql(table, col, value, params, op="ST_Contains") diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 8a380779f..4c0d0ae9e 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -378,72 +378,143 @@ def test_delete(self): self.geo_model.unlink() self.assertFalse(self.geo_model.exists()) - def test_geo_search_intersect_for_zip_1169(self): + def test_search_intersect_for_zip_1169(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) result = retails.search([("the_point", "geo_intersect", zip_item.the_geom)]) self.assertEqual(len(result.ids), 2) + result = retails.search( + [ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, + ) + ] + ) + self.assertEqual(len(result.ids), 2) + + def test_search_intersect_with_dict_id(self): + retails = self.env["retail.machine"] + result = retails.search( + [ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "in", ["1"])]}, + ) + ] + ) + self.assertEqual(len(result.ids), 3) + result = retails.search( + [ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "in", ["2"])]}, + ) + ] + ) + self.assertEqual(len(result.ids), 2) + result = retails.search( + [ + ( + "the_point", + "geo_intersect", + {"dummy.zip.the_geom": [("id", "in", ["1", "2"])]}, + ) + ] + ) + self.assertEqual(len(result.ids), 5) - def test_geo_search_intersect_for_zip_1149(self): + def test_search_intersect_for_zip_1169_with_multiple_domain(self): + retails = self.env["retail.machine"] + result = retails.search( + [ + ( + "the_point", + "geo_intersect", + { + "dummy.zip.the_geom": [ + ("id", "in", ["1", "2"]), + ("name", "ilike", "1169"), + ] + }, + ) + ] + ) + self.assertEqual(len(result.ids), 2) + + def test_search_intersect_for_zip_1149(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1146")]) result = retails.search([("the_point", "geo_intersect", zip_item.the_geom)]) self.assertEqual(len(result.ids), 3) - def test_geo_search_contains_for_retails_34(self): + def test_search_contains_for_retails_34(self): zip_item = self.env["dummy.zip"] - retails = self.env["retail.machine"].search([("name", "ilike", "34")]) - result = [] - for rec in retails: - result.extend( - zip_item.search([("the_geom", "geo_contains", rec.the_point)]).ids - ) + retails = self.env["retail.machine"].search([("name", "=", "34")]) + result = zip_item.search([("the_geom", "geo_contains", retails.the_point)]) - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Yens") + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Yens") - def test_geo_search_contains_for_retails_21(self): + result = zip_item.search( + [ + ( + "the_geom", + "geo_contains", + {"retail.machine.the_point": [("id", "=", retails.id)]}, + ) + ] + ) + + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Yens") + + def test_search_contains_for_retails_21(self): zip_item = self.env["dummy.zip"] retails = self.env["retail.machine"].search([("name", "ilike", "21")]) - result = [] - for rec in retails: - result.extend( - zip_item.search([("the_geom", "geo_contains", rec.the_point)]).ids - ) - - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Mollens (VD))") + result = zip_item.search([("the_geom", "geo_contains", retails.the_point)]) + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mollens (VD))") - def test_geo_search_within_for_retails_34(self): + def test_search_within_for_retails_34(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("city", "ilike", "Yens")]) - result = [] - for rec in zip_item: - result.extend( - retails.search( - [("name", "ilike", "34"), ("the_point", "geo_within", rec.the_geom)] - ).ids - ) + result = retails.search( + [("name", "ilike", "34"), ("the_point", "geo_within", zip_item.the_geom)] + ) - find = self.env["retail.machine"].search([("id", "=", result[0])]) - self.assertEqual(find.name, "34") + self.assertEqual(1, len(result)) + self.assertEqual(result.name, "34") - def test_geo_search_within_for_retails_21(self): + result = retails.search( + [ + ("name", "ilike", "34"), + ( + "the_point", + "geo_within", + {"dummy.zip.the_geom": [("id", "=", zip_item.id)]}, + ), + ] + ) + + self.assertEqual(1, len(result)) + self.assertEqual(result.name, "34") + + def test_search_within_for_retails_21(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) - result = [] - for rec in zip_item: - result.extend( - retails.search( - [("name", "ilike", "21"), ("the_point", "geo_within", rec.the_geom)] - ).ids - ) - - find = self.env["retail.machine"].search([("id", "=", result[0])]) - self.assertEqual(find.name, "21") + result = retails.search( + [("name", "ilike", "21"), ("the_point", "geo_within", zip_item.the_geom)] + ) + self.assertEqual(1, len(result)) + self.assertEqual(result.name, "21") - def test_geo_search_equals(self): + def test_search_equals(self): zip_item = self.env["dummy.zip"].search([("city", "ilike", "Mollens (VD))")]) + result = zip_item.search( [ ( @@ -452,11 +523,12 @@ def test_geo_search_equals(self): {"dummy.zip.the_geom": [("name", "ilike", "1146")]}, ), ] - ).ids - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Mollens (VD))") + ) - def test_geo_search_touch_polygon(self): + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mollens (VD))") + + def test_search_touch_polygon(self): zip_item = self.env["dummy.zip"] self.env["dummy.zip"].create( @@ -474,12 +546,19 @@ def test_geo_search_touch_polygon(self): "the_poly": "POLYGON ((1 0, 1 1, 2 1, 2 0, 1 0))", } ) - result = zip_item.search([("the_poly", "geo_touch", poly2.the_poly)]).ids + result = zip_item.search([("the_poly", "geo_touch", poly2.the_poly)]) - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Poly1") + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Poly1") - def test_geo_search_touch_multi_polygon(self): + result = zip_item.search( + [("the_poly", "geo_touch", {"dummy.zip.the_poly": [("id", "=", poly2.id)]})] + ) + + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Poly1") + + def test_search_touch_multi_polygon(self): zip_item = self.env["dummy.zip"] self.env["dummy.zip"].create( { @@ -498,12 +577,12 @@ def test_geo_search_touch_multi_polygon(self): ((3 0, 3 1, 4 1, 4 0, 3 0)))""", } ) - result = zip_item.search([("the_geom", "geo_touch", multi_poly_2.the_geom)]).ids + result = zip_item.search([("the_geom", "geo_touch", multi_poly_2.the_geom)]) - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Multi1") + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Multi1") - def test_geo_search_greater_multi_polygon(self): + def test_search_greater_multi_polygon(self): zip_item = self.env["dummy.zip"] mp1 = self.env["dummy.zip"].create( { @@ -524,12 +603,25 @@ def test_geo_search_greater_multi_polygon(self): ) result = zip_item.search( [("city", "ilike", "Mp2"), ("the_geom", "geo_greater", mp1.the_geom)] - ).ids + ) + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mp2") + + result = zip_item.search( + [ + ("city", "ilike", "Mp2"), + ( + "the_geom", + "geo_greater", + {"dummy.zip.the_geom": [("id", "=", mp1.id)]}, + ), + ] + ) - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Mp2") + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mp2") - def test_geo_search_lesser_multi_polygon(self): + def test_search_lesser_multi_polygon(self): zip_item = self.env["dummy.zip"] self.env["dummy.zip"].create( { @@ -550,10 +642,24 @@ def test_geo_search_lesser_multi_polygon(self): ) result = zip_item.search( [("city", "ilike", "Mp1"), ("the_geom", "geo_lesser", mp2.the_geom)] - ).ids + ) - find = self.env["dummy.zip"].search([("id", "=", result[0])]) - self.assertEqual(find.city, "Mp1") + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mp1") + + result = zip_item.search( + [ + ("city", "ilike", "Mp1"), + ( + "the_geom", + "geo_lesser", + {"dummy.zip.the_geom": [("id", "=", mp2.id)]}, + ), + ] + ) + + self.assertEqual(1, len(result)) + self.assertEqual(result.city, "Mp1") def test_from_lat_lon(self): latitude = 49.72842315886126 @@ -580,14 +686,16 @@ def test_to_lat_lon(self): def test_deprecated_geo_search__intersect_for_zip_1169(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) - result = retails.geo_search([("the_point", "geo_intersect", zip_item.the_geom)]) + result = retails.geo_search( + geo_domain=[("the_point", "geo_intersect", zip_item.the_geom)] + ) self.assertEqual(len(result), 2) def test_deprecated_geo_search__intersect_for_zip_1169_with_dict(self): retails = self.env["retail.machine"] zip_item = self.env["dummy.zip"].search([("name", "ilike", "1169")]) result = retails.geo_search( - [ + geo_domain=[ ( "the_point", "geo_intersect", From e6ab1cda2f9dee824740ae81ff6250171f0aa008 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 13 Mar 2023 10:55:18 +0100 Subject: [PATCH 29/98] [FIX] base_geoengine: fix fields SRID --- base_geoengine/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index ed9dc40f7..83a628d6e 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -48,7 +48,7 @@ def convert_to_column(self, value, record, values=None): if shape_to_write.is_empty: return None else: - return shape_to_write.wkt + return f"SRID={self.srid};{shape_to_write.wkt}" def convert_to_cache(self, value, record, validate=True): val = value From 9a988f730105aa13e34ede9d36b61435b1049a39 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Tue, 14 Mar 2023 08:25:33 +0100 Subject: [PATCH 30/98] [IMP] base_geoengine : Access rules --- base_geoengine/security/data.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/base_geoengine/security/data.xml b/base_geoengine/security/data.xml index a5c24bbfc..37b6ba5fb 100644 --- a/base_geoengine/security/data.xml +++ b/base_geoengine/security/data.xml @@ -11,4 +11,12 @@ + + + + + + + + From 56c6022dfe8903b1dcff46252f5f5c9c142a0e09 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Wed, 15 Mar 2023 15:49:06 +0100 Subject: [PATCH 31/98] [IMP] base_geoengine: Allows to define a model on the vector layer to apply the specified model --- base_geoengine/geo_model.py | 2 + base_geoengine/geo_view/geo_vector_layer.py | 36 +++- .../geo_view/geo_vector_layer_view.xml | 18 +- .../geoengine_controller.esm.js | 15 +- .../geoengine_renderer.esm.js | 185 ++++++++++++++---- .../layers_panel/layers_panel.esm.js | 1 - 6 files changed, 209 insertions(+), 48 deletions(-) diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 53ce11ec7..7b0380139 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -100,6 +100,8 @@ def set_field_real_name(in_tuple): layer_dict["geo_field_id"] = set_field_real_name( layer_dict.get("geo_field_id", False) ) + layer_dict["model"] = layer.model_id.model + layer_dict["model_domain"] = layer.model_domain geoengine_layers["actives"].append(layer_dict) # adding geo column desc # layer_dict["geo_field_id"][1] diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py index f305b6bb4..ae1ed23d6 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -1,7 +1,8 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError SUPPORTED_ATT = [ "float", @@ -49,7 +50,7 @@ class GeoVectorLayer(models.Model): ) nb_class = fields.Integer("Number of class", default=1) attribute_field_id = fields.Many2one( - "ir.model.fields", "attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] + "ir.model.fields", "Attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] ) geo_field_id = fields.Many2one( "ir.model.fields", @@ -68,3 +69,34 @@ class GeoVectorLayer(models.Model): help="Layer will be shown on startup if checked." ) layer_opacity = fields.Float() + model_domain = fields.Char(default="[]") + model_id = fields.Many2one("ir.model", "Model to use") + model_view_id = fields.Many2one( + "ir.ui.view", + "Model view", + domain=[("type", "=", "geoengine")], + compute="_compute_model_view_id", + readonly=False, + ) + + @api.constrains("geo_field_id", "model_id") + def _check_geo_field_id(self): + for rec in self: + if rec.model_id: + if not rec.geo_field_id.model_id == rec.model_id: + raise ValidationError( + _( + "The geo_field_id must be a field in %s model", + rec.model_id.display_name, + ) + ) + + @api.depends("model_id") + def _compute_model_view_id(self): + for rec in self: + if rec.model_id: + for view in rec.model_id.view_ids: + if view.type == "geoengine": + rec.model_view_id = view + else: + rec.model_view_id = "" diff --git a/base_geoengine/geo_view/geo_vector_layer_view.xml b/base_geoengine/geo_view/geo_vector_layer_view.xml index 97881920e..fdd7ad444 100644 --- a/base_geoengine/geo_view/geo_vector_layer_view.xml +++ b/base_geoengine/geo_view/geo_vector_layer_view.xml @@ -20,6 +20,11 @@ + + + + + @@ -28,9 +33,9 @@ attrs="{'invisible': [('geo_repr', '!=', 'basic')]}" > - - - + + + - + - - diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js index 4c05b46a6..2f5934bb6 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js @@ -2,11 +2,14 @@ import {Layout} from "@web/search/layout"; import {useModel} from "@web/views/model"; import {usePager} from "@web/search/pager_hook"; +import {useService} from "@web/core/utils/hooks"; const {Component} = owl; export class GeoengineController extends Component { setup() { + this.actionService = useService("action"); + this.view = useService("view"); this.model = useModel(this.props.Model, { activeFields: this.props.archInfo.activeFields, resModel: this.props.resModel, @@ -28,9 +31,15 @@ export class GeoengineController extends Component { }; }); } - async openRecord(record) { - const activeIds = this.model.root.records.map((datapoint) => datapoint.resId); - this.props.selectRecord(record.resId, {activeIds}); + + async openRecord(resModel, resId) { + const {views} = await this.view.loadViews({resModel, views: [[false, "form"]]}); + this.actionService.doAction({ + type: "ir.actions.act_window", + res_model: resModel, + views: [[views.form.id, "form"]], + res_id: resId, + }); } } diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index d058ed146..fa41cbf56 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -3,6 +3,11 @@ import {loadCSS, loadJS, templates} from "@web/core/assets"; import {GeoengineRecord} from "../geoengine_record/geoengine_record.esm"; import {LayersPanel} from "../layers_panel/layers_panel.esm"; import {store} from "../../../store.esm"; +import {useService} from "@web/core/utils/hooks"; +import {registry} from "@web/core/registry"; +import {RelationalModel} from "@web/views/relational_model"; +import pyUtils from "web.py_utils"; + const {Component, onWillStart, onMounted, onRendered, reactive, mount} = owl; /* CONSTANTS */ @@ -21,10 +26,19 @@ export class GeoengineRenderer extends Component { // When a change is issued in the store the onLayerChanged method is called. this.store = reactive(store, () => this.onLayerChanged()); + this.orm = useService("orm"); + this.view = useService("view"); + + this.services = {}; + for (const key of RelationalModel.services) { + this.services[key] = useService(key); + } + + this.cfg_models = []; onWillStart(() => Promise.all([this.loadJsFiles(), this.loadCssFiles()])); - onMounted(async () => { + onMounted(() => { // Retrives all vector layers in the store. this.geometryFields = this.store .getVectors() @@ -129,7 +143,6 @@ export class GeoengineRenderer extends Component { style: this.selectStyle, }); this.selectClick.on("select", (e) => { - console.log(e); const features = e.target.getFeatures(); this.updateInfoBox(features); }); @@ -146,26 +159,48 @@ export class GeoengineRenderer extends Component { } if (feature !== undefined) { var attributes = feature.get("attributes"); - this.record = this.props.data.records.find( - (record) => record._values.id === attributes.id - ); + + if (this.cfg_models.includes(feature.get("model"))) { + this.mountGeoengineRecord( + popup, + this.archInfo, + this.archInfo.templateDocs, + this.model.root, + attributes + ); + } else { + this.mountGeoengineRecord( + popup, + this.props.archInfo, + this.props.archInfo.templateDocs, + this.props.data, + attributes + ); + } + var coord = ol.extent.getCenter(feature.getGeometry().getExtent()); this.overlay.setPosition(coord); - mount(GeoengineRecord, popup, { - env: this.env, - props: { - archInfo: this.props.archInfo, - record: this.record, - templates: this.props.archInfo.templateDocs, - }, - templates, - }); } } else { this.hidePopup(); } } + mountGeoengineRecord(popup, archInfo, templateDocs, model, attributes) { + this.record = model.records.find( + (record) => record._values.id === attributes.id + ); + mount(GeoengineRecord, popup, { + env: this.env, + props: { + archInfo, + record: this.record, + templates: templateDocs, + }, + templates, + }); + } + clickToHidePopup() { this.selectClick.getFeatures().clear(); this.hidePopup(); @@ -201,7 +236,7 @@ export class GeoengineRenderer extends Component { } onInfoBoxClicked() { - this.props.openRecord(this.record); + this.props.openRecord(this.record.resModel, this.record.resId); } onLayerChanged() { @@ -234,19 +269,20 @@ export class GeoengineRenderer extends Component { }); } - renderVectorLayers() { + async renderVectorLayers() { const data = this.props.data.records; this.map.getLayers().forEach((layer) => { if (layer.get("title") === "Overlays") { this.map.removeLayer(layer); } }); - const vectorLayers = this.createVectorLayers(data); + const vectorLayers = await this.createVectorLayers(data); + const result = await Promise.all(vectorLayers); this.overlaysGroup = new ol.layer.Group({ title: "Overlays", - layers: vectorLayers, + layers: result, }); - vectorLayers.forEach((vlayer) => { + result.forEach((vlayer) => { this.store.getVectors().forEach((vector) => { if (vlayer.values_.title === vector.name) { vlayer.setVisible(vector.isVisible); @@ -255,8 +291,12 @@ export class GeoengineRenderer extends Component { }); this.map.addLayer(this.overlaysGroup); + this.updateZoom(data, result); + } + + updateZoom(data, result) { if (data.length) { - var extent = vectorLayers[0].getSource().getExtent(); + var extent = result[0].getSource().getExtent(); var infinite_extent = [Infinity, Infinity, -Infinity, -Infinity]; if (extent !== infinite_extent) { var map_view = this.map.getView(); @@ -273,47 +313,120 @@ export class GeoengineRenderer extends Component { .map((layer) => this.createVectorLayer(layer, data)); } - createVectorLayer(cfg, data) { + async createVectorLayer(cfg, data) { if (!data.length) { return new ol.layer.Vector({ source: new ol.source.Vector(), title: cfg.name, }); } + const styleInfo = this.styleVectorLayer(cfg, data); + var lv = new ol.layer.Vector({ + title: cfg.name, + active_on_startup: cfg.active_on_startup, + style: styleInfo.style, + }); + if (cfg.model) { + this.cfg_models.push(cfg.model); + const fields_to_read = [cfg.geo_field_id[1]]; + if (cfg.attribute_field_id) { + fields_to_read.push(cfg.attribute_field_id[1]); + } + const domain = this.evalModelDomain(cfg); + await this.loadView(cfg, domain); + this.orm.searchRead(cfg.model, [domain][0], fields_to_read).then((res) => { + this.addSourceToLayer(res, cfg, lv); + }); + } else { + this.addSourceToLayer(data, cfg, lv); + } + if (cfg.layer_opacity) { + lv.setOpacity(cfg.layer_opacity); + } + return lv; + } + addSourceToLayer(res, cfg, lv) { this.vectorSource = new ol.source.Vector(); + this.addFeatureToSource(res, cfg); + lv.setSource(this.vectorSource); + } + + evalModelDomain(cfg) { + let domain = []; + if (cfg.model_domain.includes("active_ids")) { + domain = pyUtils.py_eval(cfg.model_domain, { + active_ids: this.props.data.records.map( + (datapoint) => `${datapoint.resId}` + ), + }); + } else { + domain = pyUtils.py_eval(cfg.model_domain); + } + return domain; + } + + async loadView(cfg, domain) { + const viewRegistry = registry.category("views"); + const fields = await this.view.loadFields(cfg.model, { + attributes: [ + "store", + "searchable", + "type", + "string", + "relation", + "selection", + "related", + ], + }); + const {relatedModels, views} = await this.view.loadViews({ + resModel: cfg.model, + views: [[false, "geoengine"]], + }); + const {ArchParser, Model} = viewRegistry.get("geoengine"); + this.archInfo = new ArchParser().parse( + views.geoengine.arch, + relatedModels, + cfg.model + ); + const searchParams = { + activeFields: this.archInfo.activeFields, + resModel: cfg.model, + fields: fields, + }; + this.model = new Model(this.env, searchParams, this.services); + await this.model.load({domain}); + } + + addFeatureToSource(data, cfg) { data.forEach((item) => { - var attributes = _.clone(item._values); + var attributes = + item._values === undefined ? _.clone(item) : _.clone(item._values); this.geometryFields.forEach((geo_field) => delete attributes[geo_field]); if (cfg.display_polygon_labels === true) { - attributes.label = item._values[cfg.attribute_field_id[1]]; + attributes.label = + item._values === undefined + ? item[cfg.attribute_field_id[1]] + : item._values[cfg.attribute_field_id[1]]; } else { attributes.label = ""; } - const json_geometry = item._values[cfg.geo_field_id[1]]; + const json_geometry = + item._values === undefined + ? item[cfg.geo_field_id[1]] + : item._values[cfg.geo_field_id[1]]; if (json_geometry) { const feature = new ol.Feature({ geometry: new ol.format.GeoJSON().readGeometry(json_geometry), attributes: attributes, + model: cfg.model, }); this.vectorSource.addFeature(feature); } }); - const styleInfo = this.styleVectorLayer(cfg, data); - var lv = new ol.layer.Vector({ - source: this.vectorSource, - title: cfg.name, - active_on_startup: cfg.active_on_startup, - style: styleInfo.style, - }); - this.vectorSources.push(this.vectorSource); - if (cfg.layer_opacity) { - lv.setOpacity(cfg.layer_opacity); - } - return lv; } styleVectorLayer(cfg, data) { diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js index 161947673..33e2ea07b 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js @@ -53,7 +53,6 @@ export class LayersPanel extends Component { * @param {*} layer */ onVectorChange(layer) { - console.log("je passe"); const indexVector = store .getVectors() .findIndex((vector) => vector.name === layer.name); From 18fd28fb2f6f78546bb56d06db87e73af7c55d77 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Wed, 15 Mar 2023 17:08:14 +0100 Subject: [PATCH 32/98] [FIX] base_geoengine: fix priority and add domain on geo_field_id --- base_geoengine/geo_view/geo_vector_layer.py | 6 +- .../geo_view/geo_vector_layer_view.xml | 112 ++++++++++-------- .../geoengine_renderer.esm.js | 1 + 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py index ae1ed23d6..feb196057 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -52,17 +52,18 @@ class GeoVectorLayer(models.Model): attribute_field_id = fields.Many2one( "ir.model.fields", "Attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] ) + model_id = fields.Many2one("ir.model", "Model to use") geo_field_id = fields.Many2one( "ir.model.fields", "Geo field", - domain=[("ttype", "ilike", "geo_")], + domain="[('ttype', 'ilike', 'geo_'),('model_id', '=', model_id)]", required=True, ondelete="cascade", ) view_id = fields.Many2one( "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True ) - sequence = fields.Integer("layer priority lower on top", default=6) + sequence = fields.Integer("Layer priority lower on top", default=6) readonly = fields.Boolean("Layer is read only") display_polygon_labels = fields.Boolean("Display Labels on Polygon") active_on_startup = fields.Boolean( @@ -70,7 +71,6 @@ class GeoVectorLayer(models.Model): ) layer_opacity = fields.Float() model_domain = fields.Char(default="[]") - model_id = fields.Many2one("ir.model", "Model to use") model_view_id = fields.Many2one( "ir.ui.view", "Model view", diff --git a/base_geoengine/geo_view/geo_vector_layer_view.xml b/base_geoengine/geo_view/geo_vector_layer_view.xml index fdd7ad444..cf2a66ab2 100644 --- a/base_geoengine/geo_view/geo_vector_layer_view.xml +++ b/base_geoengine/geo_view/geo_vector_layer_view.xml @@ -6,65 +6,73 @@ geoengine.vector.layer
- - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - + name="symbol_ids" + attrs="{'invisible': [('geo_repr', '!=', 'basic')]}" + > + + + + + + - - + + + + + + + +
diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index fa41cbf56..4efd124e8 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -343,6 +343,7 @@ export class GeoengineRenderer extends Component { if (cfg.layer_opacity) { lv.setOpacity(cfg.layer_opacity); } + lv.setZIndex(cfg.sequence); return lv; } From 1d8390cde2e754f453ffb07b3e9273d77edf37a8 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Wed, 15 Mar 2023 17:10:48 +0100 Subject: [PATCH 33/98] [IMP] base_geoengine: this code seems not to be used --- base_geoengine/geo_view/geo_vector_layer.py | 1 - base_geoengine/geo_view/geo_vector_layer_view.xml | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py index feb196057..ddb2577a5 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -43,7 +43,6 @@ class GeoVectorLayer(models.Model): required=False, ) name = fields.Char("Layer Name", translate=True, required=True) - symbol_ids = fields.One2many("geoengine.vector.symbol", "vector_layer_id") begin_color = fields.Char("Begin color class", required=False, help="hex value") end_color = fields.Char( "End color class", required=False, help="hex value", default="#FF680A" diff --git a/base_geoengine/geo_view/geo_vector_layer_view.xml b/base_geoengine/geo_view/geo_vector_layer_view.xml index cf2a66ab2..e297daa01 100644 --- a/base_geoengine/geo_view/geo_vector_layer_view.xml +++ b/base_geoengine/geo_view/geo_vector_layer_view.xml @@ -32,19 +32,6 @@ - - - - - - - Date: Thu, 16 Mar 2023 13:03:25 +0100 Subject: [PATCH 34/98] [ADD] base_geoengine : add copyright --- base_geoengine/fields.py | 1 + base_geoengine/geo_model.py | 1 + base_geoengine/geo_operators.py | 1 + base_geoengine/geo_view/geo_raster_layer.py | 1 + base_geoengine/geo_view/geo_vector_layer.py | 1 + .../src/js/views/geoengine/geoengine_arch_parser.esm.js | 5 +++++ .../static/src/js/views/geoengine/geoengine_compiler.esm.js | 5 +++++ .../geoengine_controller/geoengine_controller.esm.js | 5 +++++ .../views/geoengine/geoengine_record/geoengine_record.esm.js | 5 +++++ .../geoengine/geoengine_renderer/geoengine_renderer.esm.js | 5 +++++ .../static/src/js/views/geoengine/geoengine_view.esm.js | 4 ++++ .../src/js/views/geoengine/layers_panel/layers_panel.esm.js | 5 +++++ .../geoengine_edit_map/field_geoengine_edit_map.esm.js | 4 ++++ base_geoengine/tests/__init__.py | 1 + base_geoengine/tests/models.py | 1 + base_geoengine/tests/test_model.py | 1 + 16 files changed, 46 insertions(+) diff --git a/base_geoengine/fields.py b/base_geoengine/fields.py index 83a628d6e..319d514ea 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/fields.py @@ -1,5 +1,6 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import json import logging diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 7b0380139..6efc66068 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -1,5 +1,6 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging diff --git a/base_geoengine/geo_operators.py b/base_geoengine/geo_operators.py index ad449dfc8..d3078e1ac 100644 --- a/base_geoengine/geo_operators.py +++ b/base_geoengine/geo_operators.py @@ -1,4 +1,5 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/base_geoengine/geo_view/geo_raster_layer.py b/base_geoengine/geo_view/geo_raster_layer.py index d2d2da841..504ff1bad 100644 --- a/base_geoengine/geo_view/geo_raster_layer.py +++ b/base_geoengine/geo_view/geo_raster_layer.py @@ -1,5 +1,6 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/geo_view/geo_vector_layer.py index ddb2577a5..4bf2e7ad5 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/geo_view/geo_vector_layer.py @@ -1,5 +1,6 @@ # Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import _, api, fields, models from odoo.exceptions import ValidationError diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js index a497a6284..7d9439773 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {addFieldDependencies} from "@web/views/utils"; import {Field} from "@web/views/fields/field"; import {Widget} from "@web/views/widgets/widget"; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_compiler.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_compiler.esm.js index a97551c78..85a567e4e 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_compiler.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_compiler.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {ViewCompiler} from "@web/views/view_compiler"; export class GeoengineCompiler extends ViewCompiler {} diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js index 2f5934bb6..f2c0732e2 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {Layout} from "@web/search/layout"; import {useModel} from "@web/views/model"; import {usePager} from "@web/search/pager_hook"; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js index 0b2a53d41..b984a1384 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {Field} from "@web/views/fields/field"; import {GeoengineCompiler} from "../geoengine_compiler.esm"; import {INFO_BOX_ATTRIBUTE} from "../geoengine_arch_parser.esm"; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 4efd124e8..2abfce1f6 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {loadCSS, loadJS, templates} from "@web/core/assets"; import {GeoengineRecord} from "../geoengine_record/geoengine_record.esm"; import {LayersPanel} from "../layers_panel/layers_panel.esm"; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js index 001650f84..20940599d 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_view.esm.js @@ -1,5 +1,9 @@ /** @odoo-module */ +/** + * Copyright 2023 ACSONE SA/NV + */ + import {_lt} from "@web/core/l10n/translation"; import {GeoengineController} from "./geoengine_controller/geoengine_controller.esm"; import {GeoengineRenderer} from "./geoengine_renderer/geoengine_renderer.esm"; diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js index 33e2ea07b..e2ab8518b 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js @@ -1,4 +1,9 @@ /** @odoo-module */ + +/** + * Copyright 2023 ACSONE SA/NV + */ + import {CheckBox} from "@web/core/checkbox/checkbox"; import {store} from "../../../store.esm"; import {useService} from "@web/core/utils/hooks"; diff --git a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js index 956f7393c..36b67715c 100644 --- a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js +++ b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js @@ -1,5 +1,9 @@ /** @odoo-module **/ +/** + * Copyright 2023 ACSONE SA/NV + */ + import {loadJS} from "@web/core/assets"; import {registry} from "@web/core/registry"; import {useService} from "@web/core/utils/hooks"; diff --git a/base_geoengine/tests/__init__.py b/base_geoengine/tests/__init__.py index fce09e0ca..5f4a3174c 100644 --- a/base_geoengine/tests/__init__.py +++ b/base_geoengine/tests/__init__.py @@ -1 +1,2 @@ +# Copyright 2023 ACSONE SA/NV from . import test_model diff --git a/base_geoengine/tests/models.py b/base_geoengine/tests/models.py index 92a19ba21..5126c1e36 100644 --- a/base_geoengine/tests/models.py +++ b/base_geoengine/tests/models.py @@ -1,3 +1,4 @@ +# Copyright 2023 ACSONE SA/NV from odoo import fields, models diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 4c0d0ae9e..b3ac3bfe4 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -1,3 +1,4 @@ +# Copyright 2023 ACSONE SA/NV import logging import geojson From 6f2d0ddb0aa1f18e9af381e202491710e9e4c65a Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Thu, 16 Mar 2023 13:04:42 +0100 Subject: [PATCH 35/98] [FIX] base_geoengine: Use different types of source for rasters layers --- base_geoengine/geo_model.py | 5 - base_geoengine/geo_view/geo_raster_layer.py | 29 ++-- .../geo_view/geo_raster_layer_view.xml | 128 +++++++++++------- .../geoengine_renderer.esm.js | 90 ++++++++++-- 4 files changed, 180 insertions(+), 72 deletions(-) diff --git a/base_geoengine/geo_model.py b/base_geoengine/geo_model.py index 6efc66068..5c67ba5b5 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/geo_model.py @@ -90,11 +90,6 @@ def set_field_real_name(in_tuple): geoengine_layers["backgrounds"].append(layer_dict) for layer in view.vector_layer_ids: layer_dict = layer.read()[0] - # get category groups for this vector layer - if layer.geo_repr == "basic" and layer.symbol_ids: - layer_dict["symbols"] = layer.symbol_ids.read( - ["img", "fieldname", "value"] - ) layer_dict["attribute_field_id"] = set_field_real_name( layer_dict.get("attribute_field_id", False) ) diff --git a/base_geoengine/geo_view/geo_raster_layer.py b/base_geoengine/geo_view/geo_raster_layer.py index 504ff1bad..93266dacc 100644 --- a/base_geoengine/geo_view/geo_raster_layer.py +++ b/base_geoengine/geo_view/geo_raster_layer.py @@ -34,16 +34,24 @@ class GeoRasterLayer(models.Model): # technical field to display or not wmts options is_wmts = fields.Boolean(compute="_compute_is_wmts") + # technical field to display or not wms options + is_wms = fields.Boolean(compute="_compute_is_wms") # wmts options - matrix_set = fields.Char("matrixSet") - format_suffix = fields.Char("formatSuffix", help="eg. png") - request_encoding = fields.Char("requestEncoding", help="eg. REST") - projection = fields.Char("projection", help="eg. EPSG:21781") + matrix_set = fields.Char("Matrix set") + format_suffix = fields.Char("Format", help="eg. png") + request_encoding = fields.Char("Request encoding", help="eg. REST") + projection = fields.Char(help="eg. EPSG:21781") units = fields.Char(help="eg. m") - resolutions = fields.Char("resolutions") - max_extent = fields.Char("max_extent") - dimensions = fields.Char("dimensions", help="List of dimensions separated by ','") - params = fields.Char("params", help="Dictiorary of values for dimensions as JSON") + resolutions = fields.Char() + max_extent = fields.Char("Max extent") + dimensions = fields.Char(help="List of dimensions separated by ','") + params = fields.Char(help="Dictiorary of values for dimensions as JSON") + + # wms options + params_wms = fields.Char("Params", help="Need to provide at least a LAYERS param") + server_type = fields.Char( + help="The type of the remote WMS server: mapserver, geoserver, carmentaserver, or qgis", + ) # technical field to display or not layer type has_type = fields.Boolean(compute="_compute_has_type") @@ -73,6 +81,11 @@ def _compute_is_wmts(self): for rec in self: rec.is_wmts = rec.raster_type == "wmts" + @api.depends("raster_type") + def _compute_is_wms(self): + for rec in self: + rec.is_wms = rec.raster_type == "d_wms" + @api.onchange("raster_type") def onchange_set_wmts_options(self): """Abstract method for WMTS modules to set default options""" diff --git a/base_geoengine/geo_view/geo_raster_layer_view.xml b/base_geoengine/geo_view/geo_raster_layer_view.xml index 4e30481fd..2ed31b484 100644 --- a/base_geoengine/geo_view/geo_raster_layer_view.xml +++ b/base_geoengine/geo_view/geo_raster_layer_view.xml @@ -6,58 +6,84 @@ geoengine.raster.layer
- - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + > + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 2abfce1f6..9a9b28d52 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -114,14 +114,88 @@ export class GeoengineRenderer extends Component { } createBackgroundLayers(backgrounds) { + const source = []; + source.push(new ol.layer.Tile({source: new ol.source.OSM()})); const backgroundLayers = backgrounds.map((background) => { - if (background.raster_type === "osm") { - return new ol.layer.Tile({ - title: background.name, - visible: !background.overlay, - type: "base", - source: new ol.source.OSM(), - }); + switch (background.raster_type) { + case "osm": + return new ol.layer.Tile({ + title: background.name, + visible: !background.overlay, + type: "base", + source: new ol.source.OSM(), + }); + case "wmts": + const tilegrid_opt = {}; + const source_opt = { + layer: background.name, + matrixSet: background.matrix_set, + attributions: "OUI", + }; + const layer_opt = { + title: background.name, + visible: !background.overlay, + type: "base", + style: "default", + }; + const urls_wmts = background.url.split(","); + if (urls_wmts.length > 1) { + source_opt.urls = urls_wmts; + } else { + source_opt.url = urls_wmts[0]; + } + if (background.format_suffix) { + source_opt.format = background.format_suffix; + } + if (background.request_encoding) { + source_opt.request_encoding = background.request_encoding; + } + if (background.projection) { + source_opt.projection = ol.proj.get(background.projection); + if (source_opt.projection) { + const projectionExtent = source_opt.projection.getExtent(); + tilegrid_opt.origin = + ol.extent.getTopLeft(projectionExtent); + } + } + if (background.resolutions) { + tilegrid_opt.resolutions = background.resolutions + .split(",") + .map(Number); + const nbRes = tilegrid_opt.resolutions.length; + const matrixIds = new Array(nbRes); + for (let i = 0; i < nbRes; i++) { + matrixIds[i] = i; + } + tilegrid_opt.matrixIds = matrixIds; + } + if (background.max_extent) { + const extent = background.max_extent.split(",").map(Number); + layer_opt.extent = extent; + tilegrid_opt.extent = extent; + } + if (background.params) { + source_opt.dimensions = JSON.parse(background.params); + } + source_opt.tileGrid = new ol.tilegrid.WMTS(tilegrid_opt); + layer_opt.source = new ol.source.WMTS(source_opt); + return new ol.layer.Tile(layer_opt); + case "d_wms": + const source_opt_wms = { + params: JSON.parse(background.params_wms), + serverType: background.server_type, + }; + const urls = background.url.split(","); + if (urls.length > 1) { + source_opt_wms.urls = urls; + } else { + source_opt_wms.url = urls[0]; + } + return new ol.layer.Tile({ + title: background.name, + visible: !background.overlay, + source: new ol.source.TileWMS(source_opt_wms), + }); } return undefined; }); @@ -130,7 +204,7 @@ export class GeoengineRenderer extends Component { if (index !== -1) { backgroundLayers.splice(index, 1); } - return backgroundLayers; + return source.concat(backgroundLayers); } setupControls() { From 16ecf3d06834cfa40a310b6b25bb6735b9bc5231 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Thu, 16 Mar 2023 15:07:46 +0100 Subject: [PATCH 36/98] [ADD] base_geoengine: add the possibility to specify a color and an opacity on geo_fields --- .../geoengine_renderer.esm.js | 5 ++ .../geoengine_renderer/geoengine_renderer.xml | 2 +- .../layers_panel/layers_panel.esm.js | 3 + .../field_geoengine_edit_map.esm.js | 55 +++++++++++++------ 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 9a9b28d52..3ede1f0bb 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -739,4 +739,9 @@ export class GeoengineRenderer extends Component { } GeoengineRenderer.template = "base_geoengine.GeoengineRenderer"; +GeoengineRenderer.props = { + archInfo: {type: Object, optional: false}, + data: {type: Object, optional: false}, + openRecord: {type: Function, optional: false}, +}; GeoengineRenderer.components = {LayersPanel, GeoengineRecord}; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml index 8ed6dc365..b9b1e41a1 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml @@ -2,7 +2,7 @@
- +
diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js index e2ab8518b..7de67ec5e 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js @@ -81,4 +81,7 @@ export class LayersPanel extends Component { } LayersPanel.template = "base_geoengine.LayersPanel"; +LayersPanel.props = { + model: {type: String, optional: false}, +}; LayersPanel.components = {CheckBox}; diff --git a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js index 36b67715c..062b3e4f2 100644 --- a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js +++ b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js @@ -7,6 +7,7 @@ import {loadJS} from "@web/core/assets"; import {registry} from "@web/core/registry"; import {useService} from "@web/core/utils/hooks"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; const {Component, onWillStart, onMounted, onRendered} = owl; @@ -18,9 +19,7 @@ export class FieldGeoEngineEditMap extends Component { this.id = `map_${Date.now()}`; this.orm = useService("orm"); - onWillStart(async () => { - return loadJS(["/base_geoengine/static/lib/ol-7.2.2/ol.js"]); - }); + onWillStart(() => Promise.all([this.loadJsFiles()])); // Is executed when component is mounted. onMounted(async () => { @@ -45,29 +44,41 @@ export class FieldGeoEngineEditMap extends Component { }); } + async loadJsFiles() { + const files = [ + "/base_geoengine/static/lib/ol-7.2.2/ol.js", + "/base_geoengine/static/lib/chromajs-2.4.2/chroma.js", + ]; + for (const file of files) { + await loadJS(file); + } + } + /** * Displays geo data on the map using the collection of features. */ createVectorLayer() { this.features = new ol.Collection(); this.source = new ol.source.Vector({features: this.features}); + const colorHex = this.props.color !== undefined ? this.props.color : "#ee9900"; + const opacity = this.props.opacity !== undefined ? this.props.opacity : 1; + const color = chroma(colorHex).alpha(opacity).css(); + const fill = new ol.style.Fill({ + color: color, + }); + const stroke = new ol.style.Stroke({ + color, + width: 2, + }); return new ol.layer.Vector({ source: this.source, style: new ol.style.Style({ - fill: new ol.style.Fill({ - color: "#ee9900", - opacity: 0.7, - }), - stroke: new ol.style.Stroke({ - color: "#ee9900", - width: 3, - opacity: 1, - }), + fill, + stroke, image: new ol.style.Circle({ - radius: 7, - fill: new ol.style.Fill({ - color: "#ffcc33", - }), + radius: 5, + fill, + stroke, }), }), }); @@ -214,6 +225,18 @@ export class FieldGeoEngineEditMap extends Component { } FieldGeoEngineEditMap.template = "base_geoengine.FieldGeoEngineEditMap"; +FieldGeoEngineEditMap.props = { + ...standardFieldProps, + opacity: {type: Number, optional: true}, + color: {type: String, optional: true}, +}; + +FieldGeoEngineEditMap.extractProps = ({attrs}) => { + return { + opacity: attrs.options.opacity, + color: attrs.options.color, + }; +}; export class FieldGeoEngineEditMapMultiPolygon extends FieldGeoEngineEditMap { setup() { From 70330e95c59c3765c1818e5d5363d341b951bdaf Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 20 Mar 2023 13:55:34 +0100 Subject: [PATCH 37/98] [IMP] base_geoengine: readme, refactor and documentation --- base_geoengine/README.rst | 173 +++++++++++++---- base_geoengine/__init__.py | 11 +- base_geoengine/__manifest__.py | 10 +- base_geoengine/geo_helper/__init__.py | 1 - base_geoengine/geo_ir/__init__.py | 1 - .../{geo_view => models}/__init__.py | 7 + base_geoengine/{ => models}/expressions.py | 7 + base_geoengine/{ => models}/fields.py | 2 +- .../geo_convertion_helper.py | 0 base_geoengine/{ => models}/geo_db.py | 0 base_geoengine/{ => models}/geo_model.py | 2 - base_geoengine/{ => models}/geo_operators.py | 0 .../{geo_view => models}/geo_raster_layer.py | 4 +- .../{geo_view => models}/geo_vector_layer.py | 12 +- .../{geo_view => models}/geo_vector_symbol.py | 0 base_geoengine/{geo_ir => models}/ir_model.py | 0 .../{geo_view => models}/ir_view.py | 0 base_geoengine/readme/CONTRIBUTORS.rst | 1 + base_geoengine/readme/DESCRIPTION.rst | 6 +- base_geoengine/readme/HISTORY.rst | 57 ++++++ base_geoengine/readme/INSTALL.rst | 4 +- base_geoengine/readme/ROADMAP.rst | 6 +- base_geoengine/readme/USAGE.rst | 57 ++++-- base_geoengine/static/src/css/style.css | 4 + base_geoengine/static/src/js/store.esm.js | 17 +- .../geoengine/geoengine_arch_parser.esm.js | 2 +- .../geoengine_controller.esm.js | 13 +- .../geoengine_record/geoengine_record.esm.js | 7 + .../geoengine_renderer.esm.js | 175 +++++++++++++----- .../geoengine_renderer/geoengine_renderer.xml | 4 +- .../layers_panel/layers_panel.esm.js | 9 +- .../field_geoengine_edit_map.esm.js | 23 ++- base_geoengine/tests/models.py | 6 + base_geoengine/tests/test_model.py | 5 +- .../geo_raster_layer_view.xml | 4 +- .../geo_vector_layer_view.xml | 0 .../{geo_ir => views}/ir_model_view.xml | 0 .../{geo_view => views}/ir_view_view.xml | 0 38 files changed, 473 insertions(+), 157 deletions(-) delete mode 100644 base_geoengine/geo_helper/__init__.py delete mode 100644 base_geoengine/geo_ir/__init__.py rename base_geoengine/{geo_view => models}/__init__.py (85%) rename base_geoengine/{ => models}/expressions.py (95%) rename base_geoengine/{ => models}/fields.py (99%) rename base_geoengine/{geo_helper => models}/geo_convertion_helper.py (100%) rename base_geoengine/{ => models}/geo_db.py (100%) rename base_geoengine/{ => models}/geo_model.py (98%) rename base_geoengine/{ => models}/geo_operators.py (100%) rename base_geoengine/{geo_view => models}/geo_raster_layer.py (96%) rename base_geoengine/{geo_view => models}/geo_vector_layer.py (91%) rename base_geoengine/{geo_view => models}/geo_vector_symbol.py (100%) rename base_geoengine/{geo_ir => models}/ir_model.py (100%) rename base_geoengine/{geo_view => models}/ir_view.py (100%) create mode 100644 base_geoengine/readme/HISTORY.rst rename base_geoengine/{geo_view => views}/geo_raster_layer_view.xml (96%) rename base_geoengine/{geo_view => views}/geo_vector_layer_view.xml (100%) rename base_geoengine/{geo_ir => views}/ir_model_view.xml (100%) rename base_geoengine/{geo_view => views}/ir_view_view.xml (100%) diff --git a/base_geoengine/README.rst b/base_geoengine/README.rst index 32d886dc6..de2200c73 100644 --- a/base_geoengine/README.rst +++ b/base_geoengine/README.rst @@ -14,19 +14,33 @@ Geospatial support for Odoo :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fgeospatial-lightgray.png?logo=github - :target: https://github.com/OCA/geospatial/tree/14.0/base_geoengine + :target: https://github.com/OCA/geospatial/tree/16.0/base_geoengine :alt: OCA/geospatial .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/geospatial-14-0/geospatial-14-0-base_geoengine + :target: https://translation.odoo-community.org/projects/geospatial-16-0/geospatial-16-0-base_geoengine :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/115/14.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/geospatial&target_branch=16.0 + :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| -Geospatial support based on PostGIS add the ability of server to server -geojson to do geo CRUD and view definition. +=================== +What is GeoEngine ? +=================== + +GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. It will allow you to : + +* Visualize and query your business information on map +* Perform GeoBI and spatial query +* Configure your spatial layers and spatial datasources +* Extend Odoo models with spatial columns + +GeoEngine relies on `OpenLayers `_ and `PostgGIS `_ technologies. + +Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps +and the different spatial layers. The GeoEngine module acts as a data provider and as an OpenLayers configurator. +It also provides a complete extension to Odoo ORM. **Table of contents** @@ -49,36 +63,123 @@ The module also requires two additional python libs: * `geojson `_ -for a complete documentation please refer to the `public documenation `_ +When you will install the module this two additional libs will be installed. + +For a complete documentation please refer to the `public documenation `_ Usage ===== -Important changes in version 11 -=============================== - -The geometry attributes must now be explicitly mentioned in the list of fields of -the XML geoengine view definitions. For instance:: - - - Some data view - some.model - - - - - - - +-------------- +Geoengine Demo +-------------- +1. As a user/admin, when I am in the Geoengine Demo module and I go to the ZIP menu. +When I click on an item in the list view, I get to the form view showing me the different +information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial +representation. +2. As a user, I can't modify the information in the form view. +3. As an admin, I can modify the information in the form view. I can click on the bin button to clear +the map and I can draw a new shape. +4. As a user, when I go the "Retail machines" tab and there are no items to display, it does not +show me anything. +5. As an admin, when I go the "Retail machines" tab and there are no items to display, the list view of +the retail machines suggests to me to add a new line. +6. As a user/admin, if there are items to be displayed in the "Retail machines" tab then I can click on an +item and the retail machines form view will be displayed. We can see its spatial representation by going +to "The point" tab and its attributes in "Attributes" tab. +7. As a user/admin, when I go to the geoengine zip view by clicking on the map button at the top right of the +screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers +selected are those defined as "active on startup" by the admin. The selected raster layer is the first +one that is not an overlay layer. +8. As a user/admin, when I hover over an area on the map, the area changes its style. +9. As a user/admin, when I click on an area, a popup appears an I can see the different information about the +area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the +popup will also disappear. If I click on the about button, then the form view will be displayed. +10. As a user/admin, when I use the paging system, then the results displayed on the map are different +(corresponding to the request). +11. As a user/admin, if we use the search bar, we can search results by his zip or his city. + +------------------ +Geoengine Backend +------------------ +1. As an admin, if I go into the configuration of the raster layers and it has elements, I can click +on one and see its information. +2. As an admin, if I want to create a new raster layer, I can click on "NEW" and fill out the form. The +required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a +WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", +"Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the +required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". +3. As an admin,if I go into the configuration of the vector layers and it has elements, I can click +on one and see its information. +4. As an admin, if I want to create a new vector layer, I can click on "NEW" and fill out the form. The +required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". Known issues / Roadmap ====================== -* Google layers have been removed as it was not working anyway. -* Switching from map to form view should be eased to open selected feature. - It should work using `do_switch_view` and this probably requires to set `self.dataset.index` -* A good way to open a record from map should be done with double click. - However selection handlers have difficulties to work nice with click events. +* Allow editing of a layer through a modal window from the geoengine view. + +Changelog +========= + +======================= +16.0.1.0.0 (2023-03-20) +======================= +* LayerSwitcher has been removed as it was not really practical. A LayerPanel is now active. +* The geo_search method is now deprecated and replaced by the standard odoo search method. +* The widget "geo_edit_map" attribute is no longer necessary as the field is automatically detected by + his type. We can also provide an option attribute that allows us to pass an opacity and a color as + parameters. + +.. code-block::xml +
+ + + + + +
+ +* The method geo_search is now deprecated. We now need to use the standard odoo search method. + obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) +* We can now pass to the geoengine view a template to display the information we want + to see when clicking on a feature. + +.. code-block::xml + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+ +* We can now pass a model to use to a layer to display other information on the map. + +.. code-block::xml + + + [('state', '=', 'hs')] + + HS retail machines + + basic + + #FF0000 + + 0.8 + + Bug Tracker =========== @@ -86,21 +187,23 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. Credits ======= +------- Authors -~~~~~~~ +------- * Camptocamp * ACSONE SA/NV +------------ Contributors -~~~~~~~~~~~~ +------------ * Nicolas Bessi * Frederic Junod @@ -121,9 +224,11 @@ Contributors * Thomas Nowicki * Alexandre Saunier * Sandip Mangukiya +* Samuel Kouff +----------- Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -135,6 +240,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/geospatial `_ project on GitHub. +This module is part of the `OCA/geospatial `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_geoengine/__init__.py b/base_geoengine/__init__.py index feac882cf..8a6557806 100644 --- a/base_geoengine/__init__.py +++ b/base_geoengine/__init__.py @@ -1,9 +1,2 @@ -"""The GeoEngine module""" -from . import geo_model -from . import geo_operators -from . import geo_view -from . import geo_helper -from . import geo_ir -from . import fields -from . import expressions -from .geo_db import init_postgis +from . import models +from .models.geo_db import init_postgis diff --git a/base_geoengine/__manifest__.py b/base_geoengine/__manifest__.py index df46d9186..7a0269081 100644 --- a/base_geoengine/__manifest__.py +++ b/base_geoengine/__manifest__.py @@ -1,5 +1,6 @@ # Copyright 2011-2015 Nicolas Bessi (Camptocamp SA) # Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Geospatial support for Odoo", @@ -12,10 +13,10 @@ "data": [ "security/data.xml", "views/base_geoengine_view.xml", - "geo_ir/ir_model_view.xml", - "geo_view/ir_view_view.xml", - "geo_view/geo_raster_layer_view.xml", - "geo_view/geo_vector_layer_view.xml", + "views/ir_model_view.xml", + "views/ir_view_view.xml", + "views/geo_raster_layer_view.xml", + "views/geo_vector_layer_view.xml", "security/ir.model.access.csv", ], "assets": { @@ -30,7 +31,6 @@ ] }, "external_dependencies": {"python": ["shapely", "geojson", "simplejson"]}, - "qweb": ["static/src/xml/geoengine.xml"], "installable": True, "pre_init_hook": "init_postgis", } diff --git a/base_geoengine/geo_helper/__init__.py b/base_geoengine/geo_helper/__init__.py deleted file mode 100644 index 8f6167161..000000000 --- a/base_geoengine/geo_helper/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import geo_convertion_helper diff --git a/base_geoengine/geo_ir/__init__.py b/base_geoengine/geo_ir/__init__.py deleted file mode 100644 index 413bb2380..000000000 --- a/base_geoengine/geo_ir/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import ir_model diff --git a/base_geoengine/geo_view/__init__.py b/base_geoengine/models/__init__.py similarity index 85% rename from base_geoengine/geo_view/__init__.py rename to base_geoengine/models/__init__.py index 88d8c167e..8be8e499f 100644 --- a/base_geoengine/geo_view/__init__.py +++ b/base_geoengine/models/__init__.py @@ -18,7 +18,14 @@ # ############################################################################## """Module that manages map view and vector/raster layer""" +from . import geo_model +from . import geo_operators +from . import fields +from . import geo_db +from . import expressions from . import geo_raster_layer from . import geo_vector_layer from . import geo_vector_symbol from . import ir_view +from . import ir_model +from . import geo_convertion_helper diff --git a/base_geoengine/expressions.py b/base_geoengine/models/expressions.py similarity index 95% rename from base_geoengine/expressions.py rename to base_geoengine/models/expressions.py index 552183485..2f78d4dea 100644 --- a/base_geoengine/expressions.py +++ b/base_geoengine/models/expressions.py @@ -30,6 +30,10 @@ def __leaf_to_sql(self, leaf, model, alias): + """ + This method has been monkey patched in order to be able to include + geo_operators into the Odoo search method. + """ left, operator, right = leaf if isinstance(leaf, (list, tuple)): @@ -90,6 +94,9 @@ def __leaf_to_sql(self, leaf, model, alias): def get_geo_func(current_operator, operator, left, right, params, table): + """ + This method will call the SQL query corresponding to the requested geo operator + """ match operator: case "geo_greater": query = current_operator.get_geo_greater_sql(table, left, right, params) diff --git a/base_geoengine/fields.py b/base_geoengine/models/fields.py similarity index 99% rename from base_geoengine/fields.py rename to base_geoengine/models/fields.py index 319d514ea..91ac8491d 100644 --- a/base_geoengine/fields.py +++ b/base_geoengine/models/fields.py @@ -9,8 +9,8 @@ from odoo import _, fields from odoo.tools import sql +from . import geo_convertion_helper as convert from .geo_db import create_geo_column -from .geo_helper import geo_convertion_helper as convert logger = logging.getLogger(__name__) try: diff --git a/base_geoengine/geo_helper/geo_convertion_helper.py b/base_geoengine/models/geo_convertion_helper.py similarity index 100% rename from base_geoengine/geo_helper/geo_convertion_helper.py rename to base_geoengine/models/geo_convertion_helper.py diff --git a/base_geoengine/geo_db.py b/base_geoengine/models/geo_db.py similarity index 100% rename from base_geoengine/geo_db.py rename to base_geoengine/models/geo_db.py diff --git a/base_geoengine/geo_model.py b/base_geoengine/models/geo_model.py similarity index 98% rename from base_geoengine/geo_model.py rename to base_geoengine/models/geo_model.py index 5c67ba5b5..3462982c6 100644 --- a/base_geoengine/geo_model.py +++ b/base_geoengine/models/geo_model.py @@ -99,8 +99,6 @@ def set_field_real_name(in_tuple): layer_dict["model"] = layer.model_id.model layer_dict["model_domain"] = layer.model_domain geoengine_layers["actives"].append(layer_dict) - # adding geo column desc - # layer_dict["geo_field_id"][1] return geoengine_layers @api.model diff --git a/base_geoengine/geo_operators.py b/base_geoengine/models/geo_operators.py similarity index 100% rename from base_geoengine/geo_operators.py rename to base_geoengine/models/geo_operators.py diff --git a/base_geoengine/geo_view/geo_raster_layer.py b/base_geoengine/models/geo_raster_layer.py similarity index 96% rename from base_geoengine/geo_view/geo_raster_layer.py rename to base_geoengine/models/geo_raster_layer.py index 93266dacc..7131a9f5a 100644 --- a/base_geoengine/geo_view/geo_raster_layer.py +++ b/base_geoengine/models/geo_raster_layer.py @@ -41,7 +41,7 @@ class GeoRasterLayer(models.Model): format_suffix = fields.Char("Format", help="eg. png") request_encoding = fields.Char("Request encoding", help="eg. REST") projection = fields.Char(help="eg. EPSG:21781") - units = fields.Char(help="eg. m") + units = fields.Char(help="eg. m") # Not used resolutions = fields.Char() max_extent = fields.Char("Max extent") dimensions = fields.Char(help="List of dimensions separated by ','") @@ -53,7 +53,7 @@ class GeoRasterLayer(models.Model): help="The type of the remote WMS server: mapserver, geoserver, carmentaserver, or qgis", ) - # technical field to display or not layer type + # technical field to display or not layer type -- Not used has_type = fields.Boolean(compute="_compute_has_type") type_id = fields.Many2one( "geoengine.raster.layer.type", "Layer", domain="[('service', '=', raster_type)]" diff --git a/base_geoengine/geo_view/geo_vector_layer.py b/base_geoengine/models/geo_vector_layer.py similarity index 91% rename from base_geoengine/geo_view/geo_vector_layer.py rename to base_geoengine/models/geo_vector_layer.py index 4bf2e7ad5..767141445 100644 --- a/base_geoengine/geo_view/geo_vector_layer.py +++ b/base_geoengine/models/geo_vector_layer.py @@ -2,6 +2,8 @@ # Copyright 2016 Yannick Payot (Camptocamp SA) # Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import json + from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -56,9 +58,9 @@ class GeoVectorLayer(models.Model): geo_field_id = fields.Many2one( "ir.model.fields", "Geo field", - domain="[('ttype', 'ilike', 'geo_'),('model_id', '=', model_id)]", required=True, ondelete="cascade", + domain=[("ttype", "ilike", "geo_")], ) view_id = fields.Many2one( "ir.ui.view", "Related View", domain=[("type", "=", "geoengine")], required=True @@ -100,3 +102,11 @@ def _compute_model_view_id(self): rec.model_view_id = view else: rec.model_view_id = "" + + @api.depends("model_id") + def _compute_geo_field_domain(self): + for rec in self: + domain = [("ttype", "ilike", "geo_")] + if rec.model_id: + domain = [] + rec.geo_field_id_domain = json.dumps(domain) diff --git a/base_geoengine/geo_view/geo_vector_symbol.py b/base_geoengine/models/geo_vector_symbol.py similarity index 100% rename from base_geoengine/geo_view/geo_vector_symbol.py rename to base_geoengine/models/geo_vector_symbol.py diff --git a/base_geoengine/geo_ir/ir_model.py b/base_geoengine/models/ir_model.py similarity index 100% rename from base_geoengine/geo_ir/ir_model.py rename to base_geoengine/models/ir_model.py diff --git a/base_geoengine/geo_view/ir_view.py b/base_geoengine/models/ir_view.py similarity index 100% rename from base_geoengine/geo_view/ir_view.py rename to base_geoengine/models/ir_view.py diff --git a/base_geoengine/readme/CONTRIBUTORS.rst b/base_geoengine/readme/CONTRIBUTORS.rst index 77a7463ae..724ef7470 100644 --- a/base_geoengine/readme/CONTRIBUTORS.rst +++ b/base_geoengine/readme/CONTRIBUTORS.rst @@ -17,3 +17,4 @@ * Thomas Nowicki * Alexandre Saunier * Sandip Mangukiya +* Samuel Kouff diff --git a/base_geoengine/readme/DESCRIPTION.rst b/base_geoengine/readme/DESCRIPTION.rst index 03cfdbf00..7d9384690 100644 --- a/base_geoengine/readme/DESCRIPTION.rst +++ b/base_geoengine/readme/DESCRIPTION.rst @@ -11,8 +11,6 @@ GeoEngine is an Odoo module that adds spatial/GIS capabilites to Odoo. It will a GeoEngine relies on `OpenLayers `_ and `PostgGIS `_ technologies. -Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps. The GeoEngine module acts as a data provider and as an OpenLayers configurator. +Postgis is used to store spatial information in databases. OpenLayer is used to represent spatial data in other words to show maps +and the different spatial layers. The GeoEngine module acts as a data provider and as an OpenLayers configurator. It also provides a complete extension to Odoo ORM. - -Geospatial support based on PostGIS add the ability of server to server -geojson to do geo CRUD and view definition. diff --git a/base_geoengine/readme/HISTORY.rst b/base_geoengine/readme/HISTORY.rst new file mode 100644 index 000000000..3532ee9e4 --- /dev/null +++ b/base_geoengine/readme/HISTORY.rst @@ -0,0 +1,57 @@ +======================= +16.0.1.0.0 (2023-03-20) +======================= +* LayerSwitcher has been removed as it was not really practical. A LayerPanel is now active. +* The geo_search method is now deprecated and replaced by the standard odoo search method. +* The widget "geo_edit_map" attribute is no longer necessary as the field is automatically detected by + his type. We can also provide an option attribute that allows us to pass an opacity and a color as + parameters. + +.. code-block::xml +
+ + + + + +
+ +* The method geo_search is now deprecated. We now need to use the standard odoo search method. + obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) +* We can now pass to the geoengine view a template to display the information we want + to see when clicking on a feature. + +.. code-block::xml + + + + + + + + +
    +
  • ZIP : +
  • +
  • Total Sales: +
  • +
+
+
+
+ +* We can now pass a model to use to a layer to display other information on the map. + +.. code-block::xml + + + [('state', '=', 'hs')] + + HS retail machines + + basic + + #FF0000 + + 0.8 + diff --git a/base_geoengine/readme/INSTALL.rst b/base_geoengine/readme/INSTALL.rst index 227cef314..4655b8546 100644 --- a/base_geoengine/readme/INSTALL.rst +++ b/base_geoengine/readme/INSTALL.rst @@ -11,4 +11,6 @@ The module also requires two additional python libs: * `geojson `_ -for a complete documentation please refer to the `public documenation `_ +When you will install the module this two additional libs will be installed. + +For a complete documentation please refer to the `public documenation `_ diff --git a/base_geoengine/readme/ROADMAP.rst b/base_geoengine/readme/ROADMAP.rst index 104d14407..4fd41d7ab 100644 --- a/base_geoengine/readme/ROADMAP.rst +++ b/base_geoengine/readme/ROADMAP.rst @@ -1,5 +1 @@ -* Google layers have been removed as it was not working anyway. -* Switching from map to form view should be eased to open selected feature. - It should work using `do_switch_view` and this probably requires to set `self.dataset.index` -* A good way to open a record from map should be done with double click. - However selection handlers have difficulties to work nice with click events. +* Allow editing of a layer through a modal window from the geoengine view. diff --git a/base_geoengine/readme/USAGE.rst b/base_geoengine/readme/USAGE.rst index 7319fe161..ef2b68f52 100644 --- a/base_geoengine/readme/USAGE.rst +++ b/base_geoengine/readme/USAGE.rst @@ -1,16 +1,43 @@ -Important changes in version 11 -=============================== +-------------- +Geoengine Demo +-------------- +1. As a user/admin, when I am in the Geoengine Demo module and I go to the ZIP menu. +When I click on an item in the list view, I get to the form view showing me the different +information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial +representation. +2. As a user, I can't modify the information in the form view. +3. As an admin, I can modify the information in the form view. I can click on the bin button to clear +the map and I can draw a new shape. +4. As a user, when I go the "Retail machines" tab and there are no items to display, it does not +show me anything. +5. As an admin, when I go the "Retail machines" tab and there are no items to display, the list view of +the retail machines suggests to me to add a new line. +6. As a user/admin, if there are items to be displayed in the "Retail machines" tab then I can click on an +item and the retail machines form view will be displayed. We can see its spatial representation by going +to "The point" tab and its attributes in "Attributes" tab. +7. As a user/admin, when I go to the geoengine zip view by clicking on the map button at the top right of the +screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers +selected are those defined as "active on startup" by the admin. The selected raster layer is the first +one that is not an overlay layer. +8. As a user/admin, when I hover over an area on the map, the area changes its style. +9. As a user/admin, when I click on an area, a popup appears an I can see the different information about the +area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the +popup will also disappear. If I click on the about button, then the form view will be displayed. +10. As a user/admin, when I use the paging system, then the results displayed on the map are different +(corresponding to the request). +11. As a user/admin, if we use the search bar, we can search results by his zip or his city. -The geometry attributes must now be explicitly mentioned in the list of fields of -the XML geoengine view definitions. For instance:: - - - Some data view - some.model - - - - - - - +------------------ +Geoengine Backend +------------------ +1. As an admin, if I go into the configuration of the raster layers and it has elements, I can click +on one and see its information. +2. As an admin, if I want to create a new raster layer, I can click on "NEW" and fill out the form. The +required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a +WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", +"Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the +required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". +3. As an admin,if I go into the configuration of the vector layers and it has elements, I can click +on one and see its information. +4. As an admin, if I want to create a new vector layer, I can click on "NEW" and fill out the form. The +required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". diff --git a/base_geoengine/static/src/css/style.css b/base_geoengine/static/src/css/style.css index 5eb73fde0..0680d634d 100644 --- a/base_geoengine/static/src/css/style.css +++ b/base_geoengine/static/src/css/style.css @@ -363,3 +363,7 @@ margin-bottom: 0.125rem; margin-left: 1.5em; } + +#popup-closer { + cursor: pointer; +} diff --git a/base_geoengine/static/src/js/store.esm.js b/base_geoengine/static/src/js/store.esm.js index e7943c302..f69eeb635 100644 --- a/base_geoengine/static/src/js/store.esm.js +++ b/base_geoengine/static/src/js/store.esm.js @@ -2,6 +2,10 @@ const {reactive} = owl; class Store { + /** + * Set raster layers to the store. + * @param {*} rasters + */ setRasters(rasters) { const newRasters = rasters.map((raster) => { Object.defineProperty(raster, "isVisible", { @@ -14,10 +18,18 @@ class Store { this.rasters = newRasters; } + /** + * This is called when a raster layer is changed. This will notify observers of the change. + * @param {*} newRastersLayer + */ onRasterLayerChanged(newRastersLayer) { this.rasters = newRastersLayer; } + /** + * This is called when a vector layer is changed. This will notify observers of the change. + * @param {*} newRastersLayer + */ onVectorLayerChanged(newVectorsLayers) { this.vectors = newVectorsLayers; } @@ -25,7 +37,10 @@ class Store { getRasters() { return this.rasters; } - + /** + * Set vector layers to the store. + * @param {*} rasters + */ setVectors(vectors) { const newVectors = vectors.map((vector) => { Object.defineProperty(vector, "isVisible", { diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js index 7d9439773..1d1cb383b 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_arch_parser.esm.js @@ -18,7 +18,7 @@ export class GeoengineArchParser extends XMLParser { * @param {*} arch * @param {*} models * @param {*} modelName - * @returns + * @returns {Object} */ parse(arch, models, modelName) { const xmlDoc = this.parseXML(arch); diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js index f2c0732e2..4197c9c81 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js @@ -12,6 +12,9 @@ import {useService} from "@web/core/utils/hooks"; const {Component} = owl; export class GeoengineController extends Component { + /** + * Setup the controller by using the useModel hook. + */ setup() { this.actionService = useService("action"); this.view = useService("view"); @@ -22,6 +25,10 @@ export class GeoengineController extends Component { limit: this.props.limit, }); + /** + * Allow you to display records on the map thanks to the paging located + * at the top right of the screen. + */ usePager(() => { const list = this.model.root; const {count, limit, offset} = list; @@ -36,7 +43,11 @@ export class GeoengineController extends Component { }; }); } - + /** + * Allow you to open the form editing view for the filled-in model. + * @param {*} resModel + * @param {*} resId + */ async openRecord(resModel, resId) { const {views} = await this.view.loadViews({resModel, views: [[false, "form"]]}); this.actionService.doAction({ diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js index b984a1384..7ee9e5e99 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_record/geoengine_record.esm.js @@ -21,6 +21,9 @@ function getValue(record, fieldName) { } export class GeoengineRecord extends Component { + /** + * Setup the record by compiling the arch and the info-box template. + */ setup() { const {archInfo, templates} = this.props; const {arch} = archInfo; @@ -32,6 +35,10 @@ export class GeoengineRecord extends Component { onWillUpdateProps(this.createRecord); } + /** + * Create record with formatter. + * @param {*} props + */ createRecord(props) { const {record} = props; this.record = Object.create(null); diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 3ede1f0bb..dad0f736e 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -18,9 +18,7 @@ const {Component, onWillStart, onMounted, onRendered, reactive, mount} = owl; /* CONSTANTS */ const DEFAULT_BEGIN_COLOR = "#FFFFFF"; const DEFAULT_END_COLOR = "#000000"; -// For prop symbols only const DEFAULT_MIN_SIZE = 5; -// For prop symbols only const DEFAULT_MAX_SIZE = 15; // For choroplets only const DEFAULT_NUM_CLASSES = 5; @@ -34,6 +32,7 @@ export class GeoengineRenderer extends Component { this.orm = useService("orm"); this.view = useService("view"); + // For related model we need to load all the service needed by RelationalModel this.services = {}; for (const key of RelationalModel.services) { this.services[key] = useService(key); @@ -41,6 +40,8 @@ export class GeoengineRenderer extends Component { this.cfg_models = []; + // Load all js and css files + onWillStart(() => Promise.all([this.loadJsFiles(), this.loadCssFiles()])); onMounted(() => { @@ -101,7 +102,10 @@ export class GeoengineRenderer extends Component { this.registerInteraction(); } } - + /** + * Create the info-box overlay that can be displayed over the map and + * attached to a single map location. + */ createOverlay() { this.overlay = new ol.Overlay({ element: document.getElementById("popup"), @@ -130,7 +134,6 @@ export class GeoengineRenderer extends Component { const source_opt = { layer: background.name, matrixSet: background.matrix_set, - attributions: "OUI", }; const layer_opt = { title: background.name, @@ -196,22 +199,24 @@ export class GeoengineRenderer extends Component { visible: !background.overlay, source: new ol.source.TileWMS(source_opt_wms), }); + default: + return undefined; } - return undefined; }); - // Pour le moment pour que ça marche car je prend pas en compte toute les types. - const index = backgroundLayers.findIndex((layer) => layer === undefined); - if (index !== -1) { - backgroundLayers.splice(index, 1); - } return source.concat(backgroundLayers); } + /** + * Add 'ScaleLine' control. + */ setupControls() { const scaleLine = new ol.control.ScaleLine(); this.map.addControl(scaleLine); } - + /** + * Add 2 interactions. The first is for the hovering of the elements. + * The second is for the click on the feature. + */ registerInteraction() { var selectPointerMove = new ol.interaction.Select({ condition: ol.events.condition.pointerMove, @@ -229,6 +234,40 @@ export class GeoengineRenderer extends Component { this.map.addInteraction(selectPointerMove); } + /** + * This is the style that is set when selecting or clicking on a feature. + * @param {*} feature + * @returns style + */ + selectStyle(feature) { + var geometryType = feature.getGeometry().getType(); + switch (geometryType) { + case "Point": + return new ol.style.Style({ + image: new ol.style.Circle({ + radius: 3 * 2, + fill: new ol.style.Fill({ + color: [0, 153, 255, 1], + }), + stroke: new ol.style.Stroke({ + color: [255, 255, 255, 1], + width: 3 / 2, + }), + }), + zIndex: Infinity, + }); + case "MultiPolygon": + return new ol.style.Style({ + fill: new ol.style.Fill({ + color: "rgba(255, 175, 126, 0.8)", + }), + }); + } + } + /** + * Allow you to display the info box on the map. + * @param {*} features + */ updateInfoBox(features) { const feature = features.item(0); if (feature !== undefined) { @@ -265,6 +304,14 @@ export class GeoengineRenderer extends Component { } } + /** + * Allow you to mount geoengine record. This displays the record in the info box template. + * @param {*} popup + * @param {*} archInfo + * @param {*} templateDocs + * @param {*} model + * @param {*} attributes + */ mountGeoengineRecord(popup, archInfo, templateDocs, model, attributes) { this.record = model.records.find( (record) => record._values.id === attributes.id @@ -280,44 +327,30 @@ export class GeoengineRenderer extends Component { }); } + /** + * Allow you to hide the popup by clicking on the cross. + */ clickToHidePopup() { this.selectClick.getFeatures().clear(); this.hidePopup(); } + hidePopup() { this.overlay.setPosition(undefined); } - selectStyle(feature) { - var geometryType = feature.getGeometry().getType(); - switch (geometryType) { - case "Point": - return new ol.style.Style({ - image: new ol.style.Circle({ - radius: 3 * 2, - fill: new ol.style.Fill({ - color: [0, 153, 255, 1], - }), - stroke: new ol.style.Stroke({ - color: [255, 255, 255, 1], - width: 3 / 2, - }), - }), - zIndex: Infinity, - }); - case "MultiPolygon": - return new ol.style.Style({ - fill: new ol.style.Fill({ - color: "rgba(255, 175, 126, 0.8)", - }), - }); - } - } - + /** + * When you click on the arrow button, it calls the controller's + * openRecord method. + */ onInfoBoxClicked() { this.props.openRecord(this.record.resModel, this.record.resId); } + /** + * Allows you to change the visibility of layers. This method is called + * when the user changes layers. + */ onLayerChanged() { this.map .getLayers() @@ -373,6 +406,11 @@ export class GeoengineRenderer extends Component { this.updateZoom(data, result); } + /** + * Adapts the zoom according to the result obtained. + * @param {*} data + * @param {*} result + */ updateZoom(data, result) { if (data.length) { var extent = result[0].getSource().getExtent(); @@ -405,17 +443,9 @@ export class GeoengineRenderer extends Component { active_on_startup: cfg.active_on_startup, style: styleInfo.style, }); + // If we want to use an other model in the layer if (cfg.model) { - this.cfg_models.push(cfg.model); - const fields_to_read = [cfg.geo_field_id[1]]; - if (cfg.attribute_field_id) { - fields_to_read.push(cfg.attribute_field_id[1]); - } - const domain = this.evalModelDomain(cfg); - await this.loadView(cfg, domain); - this.orm.searchRead(cfg.model, [domain][0], fields_to_read).then((res) => { - this.addSourceToLayer(res, cfg, lv); - }); + await this.useRelatedModel(cfg, lv); } else { this.addSourceToLayer(data, cfg, lv); } @@ -426,14 +456,45 @@ export class GeoengineRenderer extends Component { return lv; } + /** + * This method is called when a layer uses another model. + * @param {*} cfg + * @param {*} lv + */ + async useRelatedModel(cfg, lv) { + this.cfg_models.push(cfg.model); + const fields_to_read = [cfg.geo_field_id[1]]; + if (cfg.attribute_field_id) { + fields_to_read.push(cfg.attribute_field_id[1]); + } + const domain = this.evalModelDomain(cfg); + await this.loadView(cfg, domain); + this.orm.searchRead(cfg.model, [domain][0], fields_to_read).then((res) => { + this.addSourceToLayer(res, cfg, lv); + }); + } + + /** + * Set source to the given layer. + * @param {*} res + * @param {*} cfg + * @param {*} lv + */ addSourceToLayer(res, cfg, lv) { this.vectorSource = new ol.source.Vector(); this.addFeatureToSource(res, cfg); lv.setSource(this.vectorSource); } + /** + * Evaluates the domain passed to the layer model. + * @param {*} cfg + * @returns {Array} + */ evalModelDomain(cfg) { let domain = []; + // We can put active_ids in our domain to get all ids of all the + // element displayed. if (cfg.model_domain.includes("active_ids")) { domain = pyUtils.py_eval(cfg.model_domain, { active_ids: this.props.data.records.map( @@ -445,7 +506,11 @@ export class GeoengineRenderer extends Component { } return domain; } - + /** + * Loads the view of the model that is passed to the layer. + * @param {*} cfg + * @param {*} domain + */ async loadView(cfg, domain) { const viewRegistry = registry.category("views"); const fields = await this.view.loadFields(cfg.model, { @@ -529,6 +594,8 @@ export class GeoengineRenderer extends Component { var end_color_hex = cfg.end_color || DEFAULT_END_COLOR; var begin_color = chroma(begin_color_hex).alpha(opacity).css(); var end_color = chroma(end_color_hex).alpha(opacity).css(); + // Function that maps numeric values to a color palette. + // This scale function is only used when geo_repr is basic var scale = chroma.scale([begin_color, end_color]); var serie = new geostats(values); var vals = null; @@ -536,6 +603,7 @@ export class GeoengineRenderer extends Component { case "unique": case "custom": vals = serie.getClassUniqueValues(); + // "RdYlBu" is a set of colors scale = chroma.scale("RdYlBu").domain([0, vals.length], vals.length); break; case "quantile": @@ -664,7 +732,7 @@ export class GeoengineRenderer extends Component { } /** - * Create feature style based on the color table. + * Create a feature style based on the color table. * @param {*} colors * @returns */ @@ -703,7 +771,12 @@ export class GeoengineRenderer extends Component { }); return {fill, stroke}; } - + /** + * Allows you to find the index of the color to be used according to its value. + * @param {*} val + * @param {*} a + * @returns {Number} + */ getClass(val, a) { // Classification uniqueValues var idx = a.indexOf(val); @@ -730,7 +803,7 @@ export class GeoengineRenderer extends Component { * Extracts the values of the field corresponding to the attribute field. * @param {*} cfg, the layer. * @param {*} data, all of the records - * @returns + * @returns {Array} */ extractLayerValues(cfg, data) { var indicator = cfg.attribute_field_id[1]; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml index b9b1e41a1..ca3c83c2c 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml @@ -17,8 +17,8 @@
+ class="btn btn-secondary fa o_external_button fa-arrow-right w-50" + />
diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js index 7de67ec5e..0d7b6f7e9 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js @@ -16,7 +16,8 @@ export class LayersPanel extends Component { this.orm = useService("orm"); /** - * Call the model method "get_geoengine_layers" to get all the layers in the database and add them to the store. + * Call the model method "get_geoengine_layers" to get all the layers + * in the database and add them to the store. */ onWillStart(async () => { const result = await this.orm.call( @@ -33,7 +34,7 @@ export class LayersPanel extends Component { } /** - * Is called when a raster layer is changed. The raster layer is set to visible and then + * This is called when a raster layer is changed. The raster layer is set to visible and then * the method notifies the store of the change. * @param {*} layer */ @@ -53,7 +54,7 @@ export class LayersPanel extends Component { } /** - * Is called when a vector layer is changed. The vector layer is set to visible and then + * This is called when a vector layer is changed. The vector layer is set to visible and then * the method notifies the store of the change. * @param {*} layer */ @@ -71,7 +72,7 @@ export class LayersPanel extends Component { } /** - * Returns wether the layer is visible or not. + * Returns whether the layer is visible or not. * @param {*} layer * @returns */ diff --git a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js index 062b3e4f2..d65c522a1 100644 --- a/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js +++ b/base_geoengine/static/src/js/widgets/geoengine_edit_map/field_geoengine_edit_map.esm.js @@ -85,7 +85,7 @@ export class FieldGeoEngineEditMap extends Component { } /** - * Call the method that create the layer to display the geo data on the map. + * Call the method that creates the layer to display the geo data on the map. */ createLayers() { this.vectorLayer = this.createVectorLayer(); @@ -93,6 +93,7 @@ export class FieldGeoEngineEditMap extends Component { /** * Allows you to centre the area defined for the user. + * If there is an item to display. */ updateMapZoom() { if (this.source) { @@ -108,7 +109,8 @@ export class FieldGeoEngineEditMap extends Component { } /** - * Is executed after component is rendered. + * Allows you to centre the area defined for the user. + * If there is not item to display. */ updateMapEmpty() { var map_view = this.map.getView(); @@ -123,12 +125,11 @@ export class FieldGeoEngineEditMap extends Component { * Based on the value passed in props, adds a new feature to the collection. * @param {*} value */ - setValue(value) { if (this.map) { /** - * If the value to be displayed is equal to the one passed in props do nothing - * otherwise clear the map and displaye the new value. + * If the value to be displayed is equal to the one passed in props, do nothing + * otherwise clear the map and display the new value. */ if (this.displayValue == value) return; this.displayValue = value; @@ -148,8 +149,8 @@ export class FieldGeoEngineEditMap extends Component { } /** - * Is triggered when the view changed. When we have finished drawing our geo data or when we clear - * the map. + * This is triggered when the view changed. When we have finished drawing our geo data, or + * when we clear the map. */ onUIChange() { var value = null; @@ -182,7 +183,7 @@ export class FieldGeoEngineEditMap extends Component { } /** - * Create the trash button that clear the map. + * Create the trash button that clears the map. * @returns the div in which the button is located. */ createTrashControl() { @@ -200,7 +201,7 @@ export class FieldGeoEngineEditMap extends Component { } /** - * Displays the map in the div provided + * Displays the map in the div provided. */ renderMap() { this.map = new ol.Map({ @@ -220,7 +221,9 @@ export class FieldGeoEngineEditMap extends Component { internalProjection: this.map.getView().getProjection(), externalProjection: "EPSG:" + this.srid, }); - this.setupControls(); + if (!this.props.readonly) { + this.setupControls(); + } } } diff --git a/base_geoengine/tests/models.py b/base_geoengine/tests/models.py index 5126c1e36..6faa039f6 100644 --- a/base_geoengine/tests/models.py +++ b/base_geoengine/tests/models.py @@ -3,6 +3,8 @@ class GeoModelTest(models.Model): + """GeoModel for testing""" + _name = "geo.model.test" name = fields.Char("GeoModelTest") geo_multi_polygon = fields.GeoMultiPolygon() @@ -14,6 +16,8 @@ class GeoModelTest(models.Model): class DummyZip(models.Model): + """DummyZip model for testing""" + _name = "dummy.zip" _description = "Geoengine demo ZIP" @@ -24,6 +28,8 @@ class DummyZip(models.Model): class RetailMachine(models.Model): + """RetailMachine model for testing""" + _name = "retail.machine" _description = "Geoengine demo retailing machine" diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index b3ac3bfe4..3c9c30e60 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -1,5 +1,4 @@ # Copyright 2023 ACSONE SA/NV -import logging import geojson from odoo_test_helper import FakeModelLoader @@ -8,9 +7,7 @@ from odoo.tests.common import TransactionCase -from ..fields import GeoPoint - -_logger = logging.getLogger(__name__) +from ..models.fields import GeoPoint class TestModel(TransactionCase): diff --git a/base_geoengine/geo_view/geo_raster_layer_view.xml b/base_geoengine/views/geo_raster_layer_view.xml similarity index 96% rename from base_geoengine/geo_view/geo_raster_layer_view.xml rename to base_geoengine/views/geo_raster_layer_view.xml index 2ed31b484..edc22106b 100644 --- a/base_geoengine/geo_view/geo_raster_layer_view.xml +++ b/base_geoengine/views/geo_raster_layer_view.xml @@ -18,7 +18,7 @@ name="url" colspan="4" widget="url" - attrs="{'required': [('is_wmts', '=', True)]}" + attrs="{'required': ['|',('is_wmts', '=', True),('is_wms', '=', True)]}" /> @@ -40,7 +40,7 @@ name="projection" attrs="{'required': [('is_wmts', '=', True)]}" /> - + Date: Mon, 20 Mar 2023 14:01:29 +0100 Subject: [PATCH 38/98] [FIX] base_geoengine: fix readme --- base_geoengine/README.rst | 66 +++++++++++++++++-------------- base_geoengine/readme/HISTORY.rst | 15 +++++-- base_geoengine/readme/USAGE.rst | 42 ++++++++++---------- 3 files changed, 68 insertions(+), 55 deletions(-) diff --git a/base_geoengine/README.rst b/base_geoengine/README.rst index de2200c73..decf63401 100644 --- a/base_geoengine/README.rst +++ b/base_geoengine/README.rst @@ -74,45 +74,45 @@ Usage Geoengine Demo -------------- 1. As a user/admin, when I am in the Geoengine Demo module and I go to the ZIP menu. -When I click on an item in the list view, I get to the form view showing me the different -information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial -representation. + When I click on an item in the list view, I get to the form view showing me the different + information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial + representation. 2. As a user, I can't modify the information in the form view. 3. As an admin, I can modify the information in the form view. I can click on the bin button to clear -the map and I can draw a new shape. + the map and I can draw a new shape. 4. As a user, when I go the "Retail machines" tab and there are no items to display, it does not -show me anything. + show me anything. 5. As an admin, when I go the "Retail machines" tab and there are no items to display, the list view of -the retail machines suggests to me to add a new line. -6. As a user/admin, if there are items to be displayed in the "Retail machines" tab then I can click on an -item and the retail machines form view will be displayed. We can see its spatial representation by going -to "The point" tab and its attributes in "Attributes" tab. + the retail machines suggests to me to add a new line. +6. As a user/admin, if there are items to be displayed in the "Retail machines" tab then I can click on an + item and the retail machines form view will be displayed. We can see its spatial representation by going + to "The point" tab and its attributes in "Attributes" tab. 7. As a user/admin, when I go to the geoengine zip view by clicking on the map button at the top right of the -screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers -selected are those defined as "active on startup" by the admin. The selected raster layer is the first -one that is not an overlay layer. -8. As a user/admin, when I hover over an area on the map, the area changes its style. + screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers + selected are those defined as "active on startup" by the admin. The selected raster layer is the first + one that is not an overlay layer. +8. As a user/admin, when I hover over an area on the map, the area changes its style. 9. As a user/admin, when I click on an area, a popup appears an I can see the different information about the -area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the -popup will also disappear. If I click on the about button, then the form view will be displayed. + area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the + popup will also disappear. If I click on the about button, then the form view will be displayed. 10. As a user/admin, when I use the paging system, then the results displayed on the map are different -(corresponding to the request). + (corresponding to the request). 11. As a user/admin, if we use the search bar, we can search results by his zip or his city. ------------------ Geoengine Backend ------------------ 1. As an admin, if I go into the configuration of the raster layers and it has elements, I can click -on one and see its information. + on one and see its information. 2. As an admin, if I want to create a new raster layer, I can click on "NEW" and fill out the form. The -required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a -WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", -"Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the -required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". + required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a + WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", + "Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the + required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". 3. As an admin,if I go into the configuration of the vector layers and it has elements, I can click -on one and see its information. + on one and see its information. 4. As an admin, if I want to create a new vector layer, I can click on "NEW" and fill out the form. The -required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". + required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". Known issues / Roadmap ====================== @@ -131,7 +131,8 @@ Changelog his type. We can also provide an option attribute that allows us to pass an opacity and a color as parameters. -.. code-block::xml +.. code-block:: xml +
@@ -140,12 +141,17 @@ Changelog
-* The method geo_search is now deprecated. We now need to use the standard odoo search method. - obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) -* We can now pass to the geoengine view a template to display the information we want +* The method geo_search is now deprecated. We now need to use the standard odoo search method. + +.. code-block:: python + + obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) + +* We can now pass to the geoengine view a template to display the information we want to see when clicking on a feature. -.. code-block::xml +.. code-block:: xml + @@ -166,7 +172,8 @@ Changelog * We can now pass a model to use to a layer to display other information on the map. -.. code-block::xml +.. code-block:: xml + [('state', '=', 'hs')] @@ -180,7 +187,6 @@ Changelog 0.8 - Bug Tracker =========== diff --git a/base_geoengine/readme/HISTORY.rst b/base_geoengine/readme/HISTORY.rst index 3532ee9e4..b80a6354d 100644 --- a/base_geoengine/readme/HISTORY.rst +++ b/base_geoengine/readme/HISTORY.rst @@ -7,7 +7,8 @@ his type. We can also provide an option attribute that allows us to pass an opacity and a color as parameters. -.. code-block::xml +.. code-block:: xml +
@@ -17,11 +18,16 @@ * The method geo_search is now deprecated. We now need to use the standard odoo search method. - obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) + +.. code-block:: python + + obj.search([("the_point","geo_intersect",{"dummy.zip.the_geom": [("id", "=", rec.id)]})]) + * We can now pass to the geoengine view a template to display the information we want to see when clicking on a feature. -.. code-block::xml +.. code-block:: xml + @@ -42,7 +48,8 @@ * We can now pass a model to use to a layer to display other information on the map. -.. code-block::xml +.. code-block:: xml + [('state', '=', 'hs')] diff --git a/base_geoengine/readme/USAGE.rst b/base_geoengine/readme/USAGE.rst index ef2b68f52..e98d4a4f2 100644 --- a/base_geoengine/readme/USAGE.rst +++ b/base_geoengine/readme/USAGE.rst @@ -2,42 +2,42 @@ Geoengine Demo -------------- 1. As a user/admin, when I am in the Geoengine Demo module and I go to the ZIP menu. -When I click on an item in the list view, I get to the form view showing me the different -information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial -representation. + When I click on an item in the list view, I get to the form view showing me the different + information about the ZIP. We can see its ZIP, city, priority, total sales and his spatial + representation. 2. As a user, I can't modify the information in the form view. 3. As an admin, I can modify the information in the form view. I can click on the bin button to clear -the map and I can draw a new shape. + the map and I can draw a new shape. 4. As a user, when I go the "Retail machines" tab and there are no items to display, it does not -show me anything. + show me anything. 5. As an admin, when I go the "Retail machines" tab and there are no items to display, the list view of -the retail machines suggests to me to add a new line. + the retail machines suggests to me to add a new line. 6. As a user/admin, if there are items to be displayed in the "Retail machines" tab then I can click on an -item and the retail machines form view will be displayed. We can see its spatial representation by going -to "The point" tab and its attributes in "Attributes" tab. + item and the retail machines form view will be displayed. We can see its spatial representation by going + to "The point" tab and its attributes in "Attributes" tab. 7. As a user/admin, when I go to the geoengine zip view by clicking on the map button at the top right of the -screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers -selected are those defined as "active on startup" by the admin. The selected raster layer is the first -one that is not an overlay layer. + screen. The geoengine view appears with the first 80 results displayed on the map. The vector layers + selected are those defined as "active on startup" by the admin. The selected raster layer is the first + one that is not an overlay layer. 8. As a user/admin, when I hover over an area on the map, the area changes its style. 9. As a user/admin, when I click on an area, a popup appears an I can see the different information about the -area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the -popup will also disappear. If I click on the about button, then the form view will be displayed. + area. If I click on the cross, the popup will disappear. If I click somewhere else on the map, the + popup will also disappear. If I click on the about button, then the form view will be displayed. 10. As a user/admin, when I use the paging system, then the results displayed on the map are different -(corresponding to the request). + (corresponding to the request). 11. As a user/admin, if we use the search bar, we can search results by his zip or his city. ------------------ Geoengine Backend ------------------ 1. As an admin, if I go into the configuration of the raster layers and it has elements, I can click -on one and see its information. + on one and see its information. 2. As an admin, if I want to create a new raster layer, I can click on "NEW" and fill out the form. The -required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a -WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", -"Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the -required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". + required fields for OpenStreetMap type are "Layer Name" and "Related View". If we want to have a + WMTS (Web Map Tile Service) raster type. The required fields in addition to the precedents are "Service URL", + "Matrix set","Format", "Projection" and "Resolutions". If we take WMS (Web Map Service) raster type, then the + required fields are "Layer Name", "Related View", "Service URL", "Params", "Server Type". 3. As an admin,if I go into the configuration of the vector layers and it has elements, I can click -on one and see its information. + on one and see its information. 4. As an admin, if I want to create a new vector layer, I can click on "NEW" and fill out the form. The -required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". + required fields are "Layer Name", "Related View", "Geo field" and "Representation mode". From 19fbe652fb285366fbe0e36b6fe1d9432083a07f Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 20 Mar 2023 16:07:45 +0100 Subject: [PATCH 39/98] [IMP] base_geoengine: moving unnecessary files from the models folder --- base_geoengine/__init__.py | 6 +- base_geoengine/{models => }/expressions.py | 0 base_geoengine/{models => }/fields.py | 0 .../{models => }/geo_convertion_helper.py | 0 base_geoengine/{models => }/geo_db.py | 0 base_geoengine/{models => }/geo_operators.py | 0 base_geoengine/models/__init__.py | 8 +- base_geoengine/models/geo_model.py | 169 ------------------ base_geoengine/security/ir.model.access.csv | 2 - 9 files changed, 6 insertions(+), 179 deletions(-) rename base_geoengine/{models => }/expressions.py (100%) rename base_geoengine/{models => }/fields.py (100%) rename base_geoengine/{models => }/geo_convertion_helper.py (100%) rename base_geoengine/{models => }/geo_db.py (100%) rename base_geoengine/{models => }/geo_operators.py (100%) delete mode 100644 base_geoengine/models/geo_model.py diff --git a/base_geoengine/__init__.py b/base_geoengine/__init__.py index 8a6557806..205ee0f38 100644 --- a/base_geoengine/__init__.py +++ b/base_geoengine/__init__.py @@ -1,2 +1,6 @@ from . import models -from .models.geo_db import init_postgis +from . import expressions +from . import fields +from . import geo_convertion_helper +from . import geo_operators +from .geo_db import init_postgis diff --git a/base_geoengine/models/expressions.py b/base_geoengine/expressions.py similarity index 100% rename from base_geoengine/models/expressions.py rename to base_geoengine/expressions.py diff --git a/base_geoengine/models/fields.py b/base_geoengine/fields.py similarity index 100% rename from base_geoengine/models/fields.py rename to base_geoengine/fields.py diff --git a/base_geoengine/models/geo_convertion_helper.py b/base_geoengine/geo_convertion_helper.py similarity index 100% rename from base_geoengine/models/geo_convertion_helper.py rename to base_geoengine/geo_convertion_helper.py diff --git a/base_geoengine/models/geo_db.py b/base_geoengine/geo_db.py similarity index 100% rename from base_geoengine/models/geo_db.py rename to base_geoengine/geo_db.py diff --git a/base_geoengine/models/geo_operators.py b/base_geoengine/geo_operators.py similarity index 100% rename from base_geoengine/models/geo_operators.py rename to base_geoengine/geo_operators.py diff --git a/base_geoengine/models/__init__.py b/base_geoengine/models/__init__.py index 8be8e499f..6fa5a4716 100644 --- a/base_geoengine/models/__init__.py +++ b/base_geoengine/models/__init__.py @@ -18,14 +18,8 @@ # ############################################################################## """Module that manages map view and vector/raster layer""" -from . import geo_model -from . import geo_operators -from . import fields -from . import geo_db -from . import expressions +from . import base from . import geo_raster_layer from . import geo_vector_layer -from . import geo_vector_symbol from . import ir_view from . import ir_model -from . import geo_convertion_helper diff --git a/base_geoengine/models/geo_model.py b/base_geoengine/models/geo_model.py deleted file mode 100644 index 3462982c6..000000000 --- a/base_geoengine/models/geo_model.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) -# Copyright 2016 Yannick Payot (Camptocamp SA) -# Copyright 2023 ACSONE SA/NV -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging - -from odoo import _, api, models -from odoo.exceptions import MissingError, UserError -from odoo.osv.expression import AND - -from . import fields as geo_fields - -DEFAULT_EXTENT = ( - "-123164.85222423, 5574694.9538936, " "1578017.6490538, 6186191.1800898" -) - -_logger = logging.getLogger(__name__) - - -class GeoModel(models.AbstractModel): - """Extend Base class for to allow definition of geo fields.""" - - _inherit = "base" - - # Array of ash that define layer and data to use - _georepr = [] - - @api.model - def fields_get(self, allfields=None, attributes=None): - """Add geo_type definition for geo fields""" - res = super().fields_get(allfields=allfields, attributes=attributes) - for f_name in res: - field = self._fields.get(f_name) - if field and field.type.startswith("geo_"): - geo_type = { - "type": field.type, - "dim": int(field.dim), - "srid": field.srid, - } - # TODO - if field.compute or field.related: - if not field.dim: - geo_type["dim"] = 2 - if not field.srid: - geo_type["srid"] = 3857 - res[f_name]["geo_type"] = geo_type - return res - - @api.model - def _get_geo_view(self): - IrView = self.env["ir.ui.view"] - geo_view = IrView.sudo().search( - [("model", "=", self._name), ("type", "=", "geoengine")], - limit=1, - ) - if not geo_view: - raise UserError( - _("No GeoEngine view defined for the model %s") % self._name, - _("Please create a view or modify view mode"), - ) - return geo_view - - @api.model - def get_geoengine_layers(self, view_id=None, view_type="geoengine", **options): - view_obj = self.env["ir.ui.view"] - field_obj = self.env["ir.model.fields"] - - def set_field_real_name(in_tuple): - if not in_tuple: - return in_tuple - name = field_obj.browse(in_tuple[0]).name - out = (in_tuple[0], name, in_tuple[1]) - return out - - if not view_id: - view = self._get_geo_view() - else: - view = view_obj.browse(view_id) - geoengine_layers = { - "backgrounds": [], - "actives": [], - "projection": view.projection, - "restricted_extent": view.restricted_extent, - "default_extent": view.default_extent or DEFAULT_EXTENT, - "default_zoom": view.default_zoom, - } - - for layer in view.raster_layer_ids: - layer_dict = layer.read()[0] - geoengine_layers["backgrounds"].append(layer_dict) - for layer in view.vector_layer_ids: - layer_dict = layer.read()[0] - layer_dict["attribute_field_id"] = set_field_real_name( - layer_dict.get("attribute_field_id", False) - ) - layer_dict["geo_field_id"] = set_field_real_name( - layer_dict.get("geo_field_id", False) - ) - layer_dict["model"] = layer.model_id.model - layer_dict["model_domain"] = layer.model_domain - geoengine_layers["actives"].append(layer_dict) - return geoengine_layers - - @api.model - def get_edit_info_for_geo_column(self, column): - raster_obj = self.env["geoengine.raster.layer"] - - field = self._fields.get(column) - if not field or not isinstance(field, geo_fields.GeoField): - raise ValueError( - _("%s column does not exists or is not a geo field") % column - ) - view = self._get_geo_view() - raster = raster_obj.search( - [("view_id", "=", view.id), ("use_to_edit", "=", True)], limit=1 - ) - if not raster: - raster = raster_obj.search([("view_id", "=", view.id)], limit=1) - if not raster: - raise MissingError(_("No raster layer for view %s") % (view.name,)) - return { - "edit_raster": raster.read()[0], - "srid": field.srid, - "projection": view.projection, - "restricted_extent": view.restricted_extent, - "default_extent": view.default_extent or DEFAULT_EXTENT, - "default_zoom": view.default_zoom, - } - - @api.model - def geo_search( - self, domain=None, geo_domain=None, offset=0, limit=None, order=None - ): - """Perform a geo search it allows direct domain: - geo_search( - domain=[('name', 'ilike', 'toto']), - geo_domain=[('the_point', 'geo_intersect', - myshaply_obj or mywkt or mygeojson)]) - - We can also support indirect geo_domain ( - ‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) - - The supported operators are : - * geo_greater - * geo_lesser - * geo_equal - * geo_touch - * geo_within - * geo_contains - * geo_intersect""" - # First we do a standard search in order to apply security rules - # and do a search on standard attributes - # Limit and offset are managed after, we may loose a lot of performance - # here - _logger.debug( - "geo_search is deprecated: uses search method defined on base model" - ) - domain = domain or [] - geo_domain = geo_domain or [] - search_domain = domain or [] - if domain and geo_domain: - search_domain = AND([domain, geo_domain]) - elif geo_domain: - search_domain = geo_domain - - if not search_domain: - raise ValueError("You must at least provide one of domain or geo_domain") - - return self.search(search_domain, limit=limit, offset=offset, order=order) diff --git a/base_geoengine/security/ir.model.access.csv b/base_geoengine/security/ir.model.access.csv index 1998612db..6b6865ee4 100644 --- a/base_geoengine/security/ir.model.access.csv +++ b/base_geoengine/security/ir.model.access.csv @@ -1,8 +1,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_geo_user_vector_user,geoengine.user.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_user,1,0,0,0 access_geo_admin_vector_user,geoengine.admin.vector.layer,base_geoengine.model_geoengine_vector_layer,base_geoengine.group_geoengine_admin,1,1,1,1 -access_geo_user_vector_symbol_user,geoengine.user.vector.symbol,base_geoengine.model_geoengine_vector_symbol,base_geoengine.group_geoengine_user,1,0,0,0 -access_geo_admin_vector_symbol_user,geoengine.admin.vector.symbol,base_geoengine.model_geoengine_vector_symbol,base_geoengine.group_geoengine_admin,1,1,1,1 access_geo_user_raster_user,geoengine.user.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_user,1,0,0,0 access_geo_admin_raster_user,geoengine.admin.raster.layer,base_geoengine.model_geoengine_raster_layer,base_geoengine.group_geoengine_admin,1,1,1,1 access_geo_user_raster_type_user,geoengine.user.raster.layer.type,base_geoengine.model_geoengine_raster_layer_type,base_geoengine.group_geoengine_user,1,0,0,0 From 1ff9c3c06ec68e1a3b75fc2635578f7096ca0cd6 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 20 Mar 2023 16:15:16 +0100 Subject: [PATCH 40/98] [ADD] base_geoengine: order the vector layer in relation to the sequence --- base_geoengine/models/base.py | 169 ++++++++++++++++++ base_geoengine/models/geo_vector_layer.py | 1 + base_geoengine/models/geo_vector_symbol.py | 19 -- .../geoengine_renderer.esm.js | 5 +- 4 files changed, 174 insertions(+), 20 deletions(-) create mode 100644 base_geoengine/models/base.py delete mode 100644 base_geoengine/models/geo_vector_symbol.py diff --git a/base_geoengine/models/base.py b/base_geoengine/models/base.py new file mode 100644 index 000000000..3974b9b21 --- /dev/null +++ b/base_geoengine/models/base.py @@ -0,0 +1,169 @@ +# Copyright 2011-2012 Nicolas Bessi (Camptocamp SA) +# Copyright 2016 Yannick Payot (Camptocamp SA) +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from odoo import _, api, models +from odoo.exceptions import MissingError, UserError +from odoo.osv.expression import AND + +from .. import fields as geo_fields + +DEFAULT_EXTENT = ( + "-123164.85222423, 5574694.9538936, " "1578017.6490538, 6186191.1800898" +) + +_logger = logging.getLogger(__name__) + + +class Base(models.AbstractModel): + """Extend Base class for to allow definition of geo fields.""" + + _inherit = "base" + + # Array of ash that define layer and data to use + _georepr = [] + + @api.model + def fields_get(self, allfields=None, attributes=None): + """Add geo_type definition for geo fields""" + res = super().fields_get(allfields=allfields, attributes=attributes) + for f_name in res: + field = self._fields.get(f_name) + if field and field.type.startswith("geo_"): + geo_type = { + "type": field.type, + "dim": int(field.dim), + "srid": field.srid, + } + # TODO + if field.compute or field.related: + if not field.dim: + geo_type["dim"] = 2 + if not field.srid: + geo_type["srid"] = 3857 + res[f_name]["geo_type"] = geo_type + return res + + @api.model + def _get_geo_view(self): + IrView = self.env["ir.ui.view"] + geo_view = IrView.sudo().search( + [("model", "=", self._name), ("type", "=", "geoengine")], + limit=1, + ) + if not geo_view: + raise UserError( + _("No GeoEngine view defined for the model %s") % self._name, + _("Please create a view or modify view mode"), + ) + return geo_view + + @api.model + def get_geoengine_layers(self, view_id=None, view_type="geoengine", **options): + view_obj = self.env["ir.ui.view"] + field_obj = self.env["ir.model.fields"] + + def set_field_real_name(in_tuple): + if not in_tuple: + return in_tuple + name = field_obj.browse(in_tuple[0]).name + out = (in_tuple[0], name, in_tuple[1]) + return out + + if not view_id: + view = self._get_geo_view() + else: + view = view_obj.browse(view_id) + geoengine_layers = { + "backgrounds": [], + "actives": [], + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + + for layer in view.raster_layer_ids: + layer_dict = layer.read()[0] + geoengine_layers["backgrounds"].append(layer_dict) + for layer in view.vector_layer_ids: + layer_dict = layer.read()[0] + layer_dict["attribute_field_id"] = set_field_real_name( + layer_dict.get("attribute_field_id", False) + ) + layer_dict["geo_field_id"] = set_field_real_name( + layer_dict.get("geo_field_id", False) + ) + layer_dict["model"] = layer.model_id.model + layer_dict["model_domain"] = layer.model_domain + geoengine_layers["actives"].append(layer_dict) + return geoengine_layers + + @api.model + def get_edit_info_for_geo_column(self, column): + raster_obj = self.env["geoengine.raster.layer"] + + field = self._fields.get(column) + if not field or not isinstance(field, geo_fields.GeoField): + raise ValueError( + _("%s column does not exists or is not a geo field") % column + ) + view = self._get_geo_view() + raster = raster_obj.search( + [("view_id", "=", view.id), ("use_to_edit", "=", True)], limit=1 + ) + if not raster: + raster = raster_obj.search([("view_id", "=", view.id)], limit=1) + if not raster: + raise MissingError(_("No raster layer for view %s") % (view.name,)) + return { + "edit_raster": raster.read()[0], + "srid": field.srid, + "projection": view.projection, + "restricted_extent": view.restricted_extent, + "default_extent": view.default_extent or DEFAULT_EXTENT, + "default_zoom": view.default_zoom, + } + + @api.model + def geo_search( + self, domain=None, geo_domain=None, offset=0, limit=None, order=None + ): + """Perform a geo search it allows direct domain: + geo_search( + domain=[('name', 'ilike', 'toto']), + geo_domain=[('the_point', 'geo_intersect', + myshaply_obj or mywkt or mygeojson)]) + + We can also support indirect geo_domain ( + ‘geom’, ‘geo_operator’, {‘res.zip.poly’: [‘id’, ‘in’, [1,2,3]] }) + + The supported operators are : + * geo_greater + * geo_lesser + * geo_equal + * geo_touch + * geo_within + * geo_contains + * geo_intersect""" + # First we do a standard search in order to apply security rules + # and do a search on standard attributes + # Limit and offset are managed after, we may loose a lot of performance + # here + _logger.debug( + "geo_search is deprecated: uses search method defined on base model" + ) + domain = domain or [] + geo_domain = geo_domain or [] + search_domain = domain or [] + if domain and geo_domain: + search_domain = AND([domain, geo_domain]) + elif geo_domain: + search_domain = geo_domain + + if not search_domain: + raise ValueError("You must at least provide one of domain or geo_domain") + + return self.search(search_domain, limit=limit, offset=offset, order=order) diff --git a/base_geoengine/models/geo_vector_layer.py b/base_geoengine/models/geo_vector_layer.py index 767141445..9234b436b 100644 --- a/base_geoengine/models/geo_vector_layer.py +++ b/base_geoengine/models/geo_vector_layer.py @@ -24,6 +24,7 @@ class GeoVectorLayer(models.Model): _name = "geoengine.vector.layer" _description = "Vector Layer" + _order = "sequence ASC, name" geo_repr = fields.Selection( [ diff --git a/base_geoengine/models/geo_vector_symbol.py b/base_geoengine/models/geo_vector_symbol.py deleted file mode 100644 index 94a2fac57..000000000 --- a/base_geoengine/models/geo_vector_symbol.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2016 Yannick Payot (Camptocamp SA) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models - - -class GeoVectorSymbol(models.Model): - _name = "geoengine.vector.symbol" - _description = "Vector Layer Symbol" - - vector_layer_id = fields.Many2one("geoengine.vector.layer") - fieldname = fields.Char( - "Category field", - help="Name of the char field or selection field used for comparison", - ) - value = fields.Char(help="All object equal to this value will use this symbol") - img = fields.Char( - help="URL of the image to use. You can put an image in your module " - "in static folder e.g. 'base_geoengine/static/img/map-marker.png'" - ) diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index dad0f736e..fd09dacea 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -413,7 +413,10 @@ export class GeoengineRenderer extends Component { */ updateZoom(data, result) { if (data.length) { - var extent = result[0].getSource().getExtent(); + var extent = result + .find((res) => res.values_.visible === true) + .getSource() + .getExtent(); var infinite_extent = [Infinity, Infinity, -Infinity, -Infinity]; if (extent !== infinite_extent) { var map_view = this.map.getView(); From 7aae222ea9c5447088ff2bef79e32bcaca9d35d8 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Mon, 20 Mar 2023 16:22:00 +0100 Subject: [PATCH 41/98] [FIX] base_geoengine: fix tests --- base_geoengine/tests/test_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 3c9c30e60..12faceb2a 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -7,7 +7,7 @@ from odoo.tests.common import TransactionCase -from ..models.fields import GeoPoint +from ..fields import GeoPoint class TestModel(TransactionCase): From 49f51ef4ac864fcd67999a246913dfea00caf387 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Tue, 28 Mar 2023 16:46:31 +0200 Subject: [PATCH 42/98] [IMP] base_geoengine: setting up and extending the domain widget on the model_domain field of the vector layer --- base_geoengine/models/geo_vector_layer.py | 10 +- .../geoengine_renderer.esm.js | 20 ++- ...selector_field_input_for_active_ids.esm.js | 20 +++ ...in_selector_field_input_for_active_ids.xml | 11 ++ .../domain_selector_geo_field.esm.js | 95 ++++++++++++++ .../domain_selector_geo_field.xml | 8 ++ .../domain_selector_geo_field_dialog.esm.js | 32 +++++ .../domain_selector_geo_field_dialog.xml | 10 ++ .../domain_selector_geo_field_input.esm.js | 118 ++++++++++++++++++ .../domain_selector_geo_field_input.xml | 21 ++++ .../domain_selector_number_field.esm.js | 77 ++++++++++++ .../domain_selector_number_field.xml | 20 +++ .../domain_selector_operators.esm.js | 9 ++ .../views/geo_vector_layer_view.xml | 8 +- 14 files changed, 444 insertions(+), 15 deletions(-) create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.xml create mode 100644 base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_operators.esm.js diff --git a/base_geoengine/models/geo_vector_layer.py b/base_geoengine/models/geo_vector_layer.py index 9234b436b..bc9d008e0 100644 --- a/base_geoengine/models/geo_vector_layer.py +++ b/base_geoengine/models/geo_vector_layer.py @@ -2,7 +2,6 @@ # Copyright 2016 Yannick Payot (Camptocamp SA) # Copyright 2023 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import json from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -56,6 +55,7 @@ class GeoVectorLayer(models.Model): "ir.model.fields", "Attribute field", domain=[("ttype", "in", SUPPORTED_ATT)] ) model_id = fields.Many2one("ir.model", "Model to use") + model_name = fields.Char(related="model_id.model", readonly=True) geo_field_id = fields.Many2one( "ir.model.fields", "Geo field", @@ -103,11 +103,3 @@ def _compute_model_view_id(self): rec.model_view_id = view else: rec.model_view_id = "" - - @api.depends("model_id") - def _compute_geo_field_domain(self): - for rec in self: - domain = [("ttype", "ilike", "geo_")] - if rec.model_id: - domain = [] - rec.geo_field_id_domain = json.dumps(domain) diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index fd09dacea..64ffc721c 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -11,7 +11,7 @@ import {store} from "../../../store.esm"; import {useService} from "@web/core/utils/hooks"; import {registry} from "@web/core/registry"; import {RelationalModel} from "@web/views/relational_model"; -import pyUtils from "web.py_utils"; +import {evaluateExpr} from "@web/core/py_js/py"; const {Component, onWillStart, onMounted, onRendered, reactive, mount} = owl; @@ -498,14 +498,24 @@ export class GeoengineRenderer extends Component { let domain = []; // We can put active_ids in our domain to get all ids of all the // element displayed. - if (cfg.model_domain.includes("active_ids")) { - domain = pyUtils.py_eval(cfg.model_domain, { - active_ids: this.props.data.records.map( + if (cfg.model_domain.includes("{ACTIVE_IDS}")) { + const start = cfg.model_domain.search("ACTIVE_IDS") - 2; + let newDomain = + cfg.model_domain.slice(0, start) + cfg.model_domain.slice(start + 2); + const end = newDomain.search("ACTIVE_IDS") + 10; + newDomain = newDomain.slice(0, end) + newDomain.slice(end + 2); + if (newDomain.includes("in active_ids")) { + newDomain = newDomain.replace("in active_ids", "in"); + } else if (newDomain.includes("not in active_ids")) { + newDomain = newDomain.replace("not in active_ids", "not in"); + } + domain = evaluateExpr(newDomain, { + ACTIVE_IDS: this.props.data.records.map( (datapoint) => `${datapoint.resId}` ), }); } else { - domain = pyUtils.py_eval(cfg.model_domain); + domain = evaluateExpr(cfg.model_domain); } return domain; } diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm.js new file mode 100644 index 000000000..628103daa --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm.js @@ -0,0 +1,20 @@ +/** @odoo-module **/ + +/** + * Copyright 2023 ACSONE SA/NV + */ + +const {Component, onRendered} = owl; +/** + * This class is extended from DomainSelectorFieldInput. + * It allows you to set a default value for the field and a readonly property for the active_ids value. + */ +export class DomainSelectorFieldInputForActiveIds extends Component { + setup() { + onRendered(() => { + this.props.update({value: this.props.value}); + }); + } +} +DomainSelectorFieldInputForActiveIds.template = + "base_geoengine.DomainSelectorFieldInputForActiveIds"; diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.xml b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.xml new file mode 100644 index 000000000..d7c1ab472 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js new file mode 100644 index 000000000..27a400225 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.esm.js @@ -0,0 +1,95 @@ +/** @odoo-module **/ + +/** + * Copyright 2023 ACSONE SA/NV + */ + +import {_lt} from "@web/core/l10n/translation"; +import {registry} from "@web/core/registry"; +import {DomainSelectorGeoFieldInput} from "../domain_selector_geo_field_input/domain_selector_geo_field_input.esm"; +import {Component} from "@odoo/owl"; +import {onDidChange} from "../domain_selector_operators.esm"; + +const dsf = registry.category("domain_selector/fields"); + +/** + * This class allows you to adapt the right-hand operand and the operator of the domain + * if the selected field is of type geo_field. + */ +export class DomainSelectorGeoField extends Component {} +Object.assign(DomainSelectorGeoField, { + template: "base_geoengine.DomainSelectorGeoField", + components: { + DomainSelectorGeoFieldInput, + }, + + onDidTypeChange() { + return {value: ""}; + }, + + getOperators() { + return [ + { + category: "geospatial", + label: _lt("geo_contains"), + value: "geo_contains", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "geospatial", + label: _lt("geo_greater"), + value: "geo_greater", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "geospatial", + label: _lt("geo_equal"), + value: "geo_equal", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "geospatial", + label: _lt("geo_touch"), + value: "geo_touch", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "geospatial", + label: _lt("geo_within"), + value: "geo_within", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "geospatial", + label: _lt("geo_intersect"), + value: "geo_intersect", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + ]; + }, +}); + +dsf.add("geo_multi_polygon", DomainSelectorGeoField); +dsf.add("geo_multi_point", DomainSelectorGeoField); +dsf.add("geo_multi_line", DomainSelectorGeoField); +dsf.add("geo_polygon", DomainSelectorGeoField); +dsf.add("geo_point", DomainSelectorGeoField); +dsf.add("geo_line", DomainSelectorGeoField); diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.xml b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.xml new file mode 100644 index 000000000..9b59c9236 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field/domain_selector_geo_field.xml @@ -0,0 +1,8 @@ + + + +
+ +
+
+
diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm.js new file mode 100644 index 000000000..28888da8c --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ + +/** + * Copyright 2023 ACSONE SA/NV + */ + +import {DomainSelectorDialog} from "@web/core/domain_selector_dialog/domain_selector_dialog"; +import {_t} from "@web/core/l10n/translation"; + +/** + * This class is extended from DomainSelectorGeoField in order to be able to + * modify the title of the dialog window and to add some props to it. + */ +export class DomainSelectorGeoFieldDialog extends DomainSelectorDialog { + get dialogTitle() { + return _t("Subdomain"); + } +} + +DomainSelectorGeoFieldDialog.template = "base_geoengine.DomainSelectorGeoFieldDialog"; +DomainSelectorDialog.props = { + close: Function, + className: {type: String, optional: true}, + resModel: String, + readonly: {type: Boolean, optional: true}, + isDebugMode: {type: Boolean, optional: true}, + defaultLeafValue: {type: Array, optional: true}, + initialValue: {type: String, optional: true}, + onSelected: {type: Function, optional: true}, + update: Function, + fieldName: String, +}; diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.xml b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.xml new file mode 100644 index 000000000..f93f6b3b9 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js new file mode 100644 index 000000000..4056a266d --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.esm.js @@ -0,0 +1,118 @@ +/** @odoo-module **/ + +/** + * Copyright 2023 ACSONE SA/NV + */ + +import {ModelFieldSelector} from "@web/core/model_field_selector/model_field_selector"; +import {ModelSelector} from "@web/core/model_selector/model_selector"; +import {Domain} from "@web/core/domain"; +import {evaluate} from "@web/core/py_js/py_interpreter"; +import {useOwnedDialogs} from "@web/core/utils/hooks"; +import {DomainSelectorGeoFieldDialog} from "../domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm"; + +const {Component, onWillStart, useState, onWillUpdateProps} = owl; + +/** + * This class correspond to the value of the right operand when a geo_field has + * been selected. + */ +export class DomainSelectorGeoFieldInput extends Component { + setup() { + this.state = useState({ + resModel: "", + fieldName: "", + subField: "", + operator: "", + value: "", + domain: {}, + }); + this.addDialog = useOwnedDialogs(); + + /** + * Before starting, if a value is already selected we had to know the fieldName and + * the resModel. + */ + onWillStart(async () => { + if (this.props.value instanceof Object) { + this.key = Object.keys(this.props.value)[0]; + const index = this.key.lastIndexOf("."); + this.state.fieldName = this.key.substring(index + 1); + this.state.resModel = this.key.substring(0, index); + this.loadDomain(); + } else { + this.state.value = this.props.value; + } + }); + + onWillUpdateProps((nextProps) => this.loadDomain(nextProps)); + } + + /** + * This method allow the domain to be loaded into a state. + * @param {*} nextProps + */ + loadDomain(nextProps) { + const props = nextProps === undefined ? this.props : nextProps; + const key = + this.key === undefined + ? this.state.resModel + "." + this.state.fieldName + : this.key; + this.state.domain = new Domain(props.value[key]); + } + + /** + * This method updates the value of the right operand of the domain. + * @param {*} value + */ + update(value) { + if (value !== undefined) { + const domain = new Domain(value); + const obj = {}; + const jsDomain = evaluate(domain.ast, {}); + obj[this.resModel + "." + this.fieldName] = jsDomain; + this.update({value: obj}); + } + } + + /** + * This method reacts to changes of the sub field name. + * @param {*} fieldName + */ + async onFieldModelChange(fieldName) { + this.state.fieldName = fieldName; + this.update(); + } + + /** + * When we click on the edit button, this launches a dialog window allowing you to + * edit the sub-domain. + */ + display() { + const initialValue = + this.state.domain !== undefined ? this.state.domain.toString() : "[]"; + this.addDialog(DomainSelectorGeoFieldDialog, { + resModel: this.state.resModel, + initialValue, + readonly: false, + isDebugMode: Boolean(this.env.debug), + fieldName: this.state.fieldName, + update: this.props.update, + onSelected: this.update, + }); + } + + /** + * This method react to changes of the sub model. + * @param {*} newModel + */ + onModelChange(newModel) { + this.state.resModel = newModel.technical; + this.state.fieldName = ""; + this.state.subField = ""; + this.update(); + } +} + +DomainSelectorGeoFieldInput.template = "base_geoengine.DomainSelectorGeoFieldInput"; +DomainSelectorGeoFieldInput.components = {ModelFieldSelector, ModelSelector}; diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.xml b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.xml new file mode 100644 index 000000000..b28e5f75d --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_geo_field_input/domain_selector_geo_field_input.xml @@ -0,0 +1,21 @@ + + + +
+ + + +
+
+
diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js new file mode 100644 index 000000000..3b31bb301 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.esm.js @@ -0,0 +1,77 @@ +/** @odoo-module **/ + +/** + * Copyright 2023 ACSONE SA/NV + */ + +import {registry} from "@web/core/registry"; +import {_lt} from "@web/core/l10n/translation"; +import {DomainSelectorFieldInput} from "@web/core/domain_selector/fields/domain_selector_field_input"; +import {DomainSelectorFieldInputForActiveIds} from "../domain_selector_field_input_for_active_ids/domain_selector_field_input_for_active_ids.esm"; +import {DomainSelectorFieldInputWithTags} from "@web/core/domain_selector/fields/domain_selector_field_input_with_tags"; +import {onDidChange} from "../domain_selector_operators.esm"; +const dso = registry.category("domain_selector/operator"); +const dsf = registry.category("domain_selector/fields"); + +const {Component} = owl; + +/** + * This method is extended from DomainSelectorNumberField to add some operators + * ("in active_ids", "not in active_ids", "in", "not in"). + */ +export class DomainSelectorNumberFieldExtend extends Component {} +Object.assign(DomainSelectorNumberFieldExtend, { + template: "base_geoengine.DomainSelectorNumberFieldExtend", + components: { + DomainSelectorFieldInput, + DomainSelectorFieldInputWithTags, + DomainSelectorFieldInputForActiveIds, + }, + + onDidTypeChange() { + return {value: 0}; + }, + getOperators() { + const addOperators = [ + { + category: "active_ids", + label: _lt("in active_ids"), + value: "in active_ids", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + { + category: "active_ids", + label: _lt("not in active_ids"), + value: "not in active_ids", + onDidChange: onDidChange(() => ({value: ""})), + matches({operator}) { + return operator === this.value; + }, + }, + ]; + const operators = [ + "=", + "!=", + ">", + "<", + ">=", + "<=", + "ilike", + "not ilike", + "in", + "not in", + "set", + "not set", + ].map((key) => dso.get(key)); + return addOperators.concat(operators); + }, +}); +dsf.remove("integer"); +dsf.remove("float"); +dsf.remove("monetary"); +dsf.add("integer", DomainSelectorNumberFieldExtend); +dsf.add("float", DomainSelectorNumberFieldExtend); +dsf.add("monetary", DomainSelectorNumberFieldExtend); diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.xml b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.xml new file mode 100644 index 000000000..d2042c31f --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_number_field/domain_selector_number_field.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + +
+ +
+
+
+
diff --git a/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_operators.esm.js b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_operators.esm.js new file mode 100644 index 000000000..f0e5b1575 --- /dev/null +++ b/base_geoengine/static/src/js/widgets/domain_selector_geo_field/domain_selector_operators.esm.js @@ -0,0 +1,9 @@ +/** @odoo-module */ +export function onDidChange(action) { + return function (oldOperator, fieldChange) { + if (this.category !== oldOperator.category) { + return action(fieldChange); + } + return {}; + }; +} diff --git a/base_geoengine/views/geo_vector_layer_view.xml b/base_geoengine/views/geo_vector_layer_view.xml index e297daa01..138d81da2 100644 --- a/base_geoengine/views/geo_vector_layer_view.xml +++ b/base_geoengine/views/geo_vector_layer_view.xml @@ -27,7 +27,13 @@ name="model_view_id" domain="[('mode', '=', 'geoengine')]" /> - + + From 91a1e60dac5674977effaf48f624a3d2c889f2d8 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Thu, 30 Mar 2023 08:18:58 +0200 Subject: [PATCH 43/98] [ADD] base_geoengine: add editing functionnality of domain of a vector layer --- base_geoengine/models/base.py | 1 + .../static/src/js/raster_layers_store.esm.js | 33 +++++++++ ...tore.esm.js => vector_layers_store.esm.js} | 36 ++------- .../geoengine_controller.esm.js | 1 + .../geoengine_renderer.esm.js | 53 ++++++++++--- .../layers_panel/layers_panel.esm.js | 74 +++++++++++++++---- .../geoengine/layers_panel/layers_panel.scss | 8 ++ .../geoengine/layers_panel/layers_panel.xml | 32 ++++++-- .../domain_selector_geo_field_dialog.esm.js | 17 ++++- .../domain_selector_geo_field_input.esm.js | 2 + .../domain_selector_geo_field_input.xml | 2 +- .../views/geo_vector_layer_view.xml | 67 +++++++++++++++++ 12 files changed, 259 insertions(+), 67 deletions(-) create mode 100644 base_geoengine/static/src/js/raster_layers_store.esm.js rename base_geoengine/static/src/js/{store.esm.js => vector_layers_store.esm.js} (56%) create mode 100644 base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.scss diff --git a/base_geoengine/models/base.py b/base_geoengine/models/base.py index 3974b9b21..9de682d3d 100644 --- a/base_geoengine/models/base.py +++ b/base_geoengine/models/base.py @@ -96,6 +96,7 @@ def set_field_real_name(in_tuple): layer_dict["geo_field_id"] = set_field_real_name( layer_dict.get("geo_field_id", False) ) + layer_dict["resModel"] = layer._name layer_dict["model"] = layer.model_id.model layer_dict["model_domain"] = layer.model_domain geoengine_layers["actives"].append(layer_dict) diff --git a/base_geoengine/static/src/js/raster_layers_store.esm.js b/base_geoengine/static/src/js/raster_layers_store.esm.js new file mode 100644 index 000000000..b0afd6690 --- /dev/null +++ b/base_geoengine/static/src/js/raster_layers_store.esm.js @@ -0,0 +1,33 @@ +/** @odoo-module */ +const {reactive} = owl; + +class RasterLayersStore { + /** + * Set raster layers to the store. + * @param {*} rasters + */ + setRasters(rasters) { + const newRasters = rasters.map((raster) => { + Object.defineProperty(raster, "isVisible", { + value: false, + writable: true, + }); + raster.isVisible = !raster.overlay; + return raster; + }); + this.rasters = newRasters; + } + + /** + * This is called when a raster layer is changed. This will notify observers of the change. + * @param {*} newRastersLayer + */ + onRasterLayerChanged(newRastersLayer) { + this.rasters = newRastersLayer; + } + + getRasters() { + return this.rasters; + } +} +export const rasterLayersStore = reactive(new RasterLayersStore()); diff --git a/base_geoengine/static/src/js/store.esm.js b/base_geoengine/static/src/js/vector_layers_store.esm.js similarity index 56% rename from base_geoengine/static/src/js/store.esm.js rename to base_geoengine/static/src/js/vector_layers_store.esm.js index f69eeb635..81414c4b5 100644 --- a/base_geoengine/static/src/js/store.esm.js +++ b/base_geoengine/static/src/js/vector_layers_store.esm.js @@ -1,31 +1,7 @@ /** @odoo-module */ const {reactive} = owl; -class Store { - /** - * Set raster layers to the store. - * @param {*} rasters - */ - setRasters(rasters) { - const newRasters = rasters.map((raster) => { - Object.defineProperty(raster, "isVisible", { - value: false, - writable: true, - }); - raster.isVisible = !raster.overlay; - return raster; - }); - this.rasters = newRasters; - } - - /** - * This is called when a raster layer is changed. This will notify observers of the change. - * @param {*} newRastersLayer - */ - onRasterLayerChanged(newRastersLayer) { - this.rasters = newRastersLayer; - } - +class VectorLayersStore { /** * This is called when a vector layer is changed. This will notify observers of the change. * @param {*} newRastersLayer @@ -34,9 +10,6 @@ class Store { this.vectors = newVectorsLayers; } - getRasters() { - return this.rasters; - } /** * Set vector layers to the store. * @param {*} rasters @@ -47,6 +20,10 @@ class Store { value: false, writable: true, }); + Object.defineProperty(vector, "onDomainChanged", { + value: false, + writable: true, + }); if (vector.active_on_startup) { vector.isVisible = true; } @@ -59,4 +36,5 @@ class Store { return this.vectors; } } -export const store = reactive(new Store()); + +export const vectorLayersStore = reactive(new VectorLayersStore()); diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js index 4197c9c81..7d74e7d1f 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_controller/geoengine_controller.esm.js @@ -55,6 +55,7 @@ export class GeoengineController extends Component { res_model: resModel, views: [[views.form.id, "form"]], res_id: resId, + target: "new", }); } } diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 64ffc721c..aabcde537 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -7,7 +7,8 @@ import {loadCSS, loadJS, templates} from "@web/core/assets"; import {GeoengineRecord} from "../geoengine_record/geoengine_record.esm"; import {LayersPanel} from "../layers_panel/layers_panel.esm"; -import {store} from "../../../store.esm"; +import {rasterLayersStore} from "../../../raster_layers_store.esm"; +import {vectorLayersStore} from "../../../vector_layers_store.esm"; import {useService} from "@web/core/utils/hooks"; import {registry} from "@web/core/registry"; import {RelationalModel} from "@web/views/relational_model"; @@ -27,8 +28,13 @@ export class GeoengineRenderer extends Component { setup() { super.setup(); - // When a change is issued in the store the onLayerChanged method is called. - this.store = reactive(store, () => this.onLayerChanged()); + // When a change is issued in the rasterLayersStore or the vectorLayersStore the LayerChanged method is called. + this.rasterLayersStore = reactive(rasterLayersStore, () => + this.onRasterLayerChanged() + ); + this.vectorLayersStore = reactive(vectorLayersStore, () => + this.onVectorLayerChanged() + ); this.orm = useService("orm"); this.view = useService("view"); @@ -46,7 +52,7 @@ export class GeoengineRenderer extends Component { onMounted(() => { // Retrives all vector layers in the store. - this.geometryFields = this.store + this.geometryFields = this.vectorLayersStore .getVectors() .map((layer) => layer.geo_field_id[1]); @@ -89,7 +95,9 @@ export class GeoengineRenderer extends Component { layers: [ new ol.layer.Group({ title: "Base maps", - layers: this.createBackgroundLayers(this.store.getRasters()), + layers: this.createBackgroundLayers( + this.rasterLayersStore.getRasters() + ), }), ], overlays: [this.overlay], @@ -349,9 +357,9 @@ export class GeoengineRenderer extends Component { /** * Allows you to change the visibility of layers. This method is called - * when the user changes layers. + * when the user changes raster layers. */ - onLayerChanged() { + onRasterLayerChanged() { this.map .getLayers() .getArray() @@ -359,28 +367,49 @@ export class GeoengineRenderer extends Component { .getLayers() .getArray() .forEach((layer) => { - this.store.getRasters().forEach((raster) => { + this.rasterLayersStore.getRasters().forEach((raster) => { if (raster.name === layer.get("title")) { layer.setVisible(raster.isVisible); } }); }); + } - this.map + /** + * Allows you to change the visibility of layers. This method is called + * when the user changes vector layers. + */ + async onVectorLayerChanged() { + await this.map .getLayers() .getArray() .find((layer) => layer.get("title") === "Overlays") .getLayers() .getArray() .forEach((layer) => { - this.store.getVectors().forEach((vector) => { + this.vectorLayersStore.getVectors().forEach((vector) => { if (vector.name === layer.get("title")) { layer.setVisible(vector.isVisible); + if (vector.onDomainChanged) { + this.onVectorLayerModelDomainChanged(vector, layer); + } } }); }); } + onVectorLayerModelDomainChanged(cfg, layer) { + layer.setSource(null); + const fields_to_read = [cfg.geo_field_id[1]]; + if (cfg.attribute_field_id) { + fields_to_read.push(cfg.attribute_field_id[1]); + } + const domain = this.evalModelDomain(cfg); + this.orm.searchRead(cfg.model, [domain][0], fields_to_read).then((res) => { + this.addSourceToLayer(res, cfg, layer); + }); + } + async renderVectorLayers() { const data = this.props.data.records; this.map.getLayers().forEach((layer) => { @@ -395,7 +424,7 @@ export class GeoengineRenderer extends Component { layers: result, }); result.forEach((vlayer) => { - this.store.getVectors().forEach((vector) => { + this.vectorLayersStore.getVectors().forEach((vector) => { if (vlayer.values_.title === vector.name) { vlayer.setVisible(vector.isVisible); } @@ -428,7 +457,7 @@ export class GeoengineRenderer extends Component { } createVectorLayers(data) { - return this.store + return this.vectorLayersStore .getVectors() .map((layer) => this.createVectorLayer(layer, data)); } diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js index 0d7b6f7e9..a0e7f289a 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.esm.js @@ -5,8 +5,11 @@ */ import {CheckBox} from "@web/core/checkbox/checkbox"; -import {store} from "../../../store.esm"; -import {useService} from "@web/core/utils/hooks"; +import {rasterLayersStore} from "../../../raster_layers_store.esm"; +import {vectorLayersStore} from "../../../vector_layers_store.esm"; +import {useOwnedDialogs, useService} from "@web/core/utils/hooks"; +import {DomainSelectorGeoFieldDialog} from "../../../widgets/domain_selector_geo_field/domain_selector_geo_field_dialog/domain_selector_geo_field_dialog.esm"; + const {Component, onWillStart} = owl; export class LayersPanel extends Component { @@ -14,6 +17,10 @@ export class LayersPanel extends Component { super.setup(); this.orm = useService("orm"); + this.actionService = useService("action"); + this.view = useService("view"); + + this.addDialog = useOwnedDialogs(); /** * Call the model method "get_geoengine_layers" to get all the layers @@ -28,8 +35,8 @@ export class LayersPanel extends Component { this.geoengine_layers = result; // Set layers in the store - store.setRasters(this.geoengine_layers.backgrounds); - store.setVectors(this.geoengine_layers.actives); + rasterLayersStore.setRasters(this.geoengine_layers.backgrounds); + vectorLayersStore.setVectors(this.geoengine_layers.actives); }); } @@ -39,10 +46,10 @@ export class LayersPanel extends Component { * @param {*} layer */ onRasterChange(layer) { - const indexRaster = store + const indexRaster = rasterLayersStore .getRasters() .findIndex((raster) => raster.name === layer.name); - const newRasters = store.getRasters().map((item, index) => { + const newRasters = rasterLayersStore.getRasters().map((item, index) => { if (index !== indexRaster) { item.isVisible = false; } else { @@ -50,25 +57,35 @@ export class LayersPanel extends Component { } return item; }); - store.onRasterLayerChanged(newRasters); + rasterLayersStore.onRasterLayerChanged(newRasters); } /** - * This is called when a vector layer is changed. The vector layer is set to visible and then + * This is called when a vector layer is changed. The vector layer is changed by an action and then * the method notifies the store of the change. * @param {*} layer + * @param {*} action + * @param {*} value */ - onVectorChange(layer) { - const indexVector = store + onVectorChange(layer, action, value) { + const indexVector = vectorLayersStore .getVectors() .findIndex((vector) => vector.name === layer.name); - const newVectors = store.getVectors().map((item, index) => { + const newVectors = vectorLayersStore.getVectors().map((item, index) => { if (index === indexVector) { - item.isVisible = !item.isVisible; + switch (action) { + case "onDomainChanged": + item.model_domain = value; + item.onDomainChanged = true; + break; + case "onVisibleChanged": + item.isVisible = value; + break; + } } return item; }); - store.onVectorLayerChanged(newVectors); + vectorLayersStore.onVectorLayerChanged(newVectors); } /** @@ -79,6 +96,37 @@ export class LayersPanel extends Component { getVisibleLayer(layer) { return layer.isVisible; } + + onEditFilterButtonSelected(vector) { + this.addDialog(DomainSelectorGeoFieldDialog, { + resModel: vector.model, + initialValue: vector.model_domain, + readonly: false, + isDebugMode: Boolean(this.env.debug), + model: vector, + update: this.onVectorChange, + onSelected: this.onSelected, + title: "Domain editing", + }); + } + + async onEditButtonSelected(vector) { + console.log(vector); + // Let res = await this.orm.call(vector.resModel, "env.ref", ["geo_vector_geoengine_view_form"]); + // console.log(res); + // // const {views} = await this.view.loadViews({resModel: vector.resModel, views: [[false, "form"]]}); + // // this.actionService.doAction({ + // // type: "ir.actions.act_window", + // // res_model: vector.resModel, + // // views: [[views.form.id, "form"]], + // // res_id: vector.id, + // // target: 'new', + // // }); + } + + onSelected(value) { + this.update(this.model, "onDomainChanged", value); + } } LayersPanel.template = "base_geoengine.LayersPanel"; diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.scss b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.scss new file mode 100644 index 000000000..f6df7f055 --- /dev/null +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.scss @@ -0,0 +1,8 @@ +.btn-edit { + font-size: 1.2em; +} + +.o_layer_panel { + width: 230px; + font-size: 1em; +} diff --git a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml index 9ff5ad147..6a323bdcf 100644 --- a/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml +++ b/base_geoengine/static/src/js/views/geoengine/layers_panel/layers_panel.xml @@ -1,25 +1,41 @@ - +
+
+
+ Vectors +
+
+
    +
  • - - - - - + + + + + +
+ + +
+ +
+
+ Rasters +
+
    +
  • +
    + +
-
- -
-
- Raster -
-
    -
  • -
    - -
    -
  • -
-
+ + +
+ Layers () +
From 5aad6092292e86e9915b7801a0d5bcd15f5ff031 Mon Sep 17 00:00:00 2001 From: Samuel Kouff Date: Tue, 11 Apr 2023 16:05:27 +0200 Subject: [PATCH 48/98] [ADD] base_geoengine: adding records panel --- .../geoengine_renderer.esm.js | 13 ++-- .../geoengine_renderer.scss | 1 - .../geoengine_renderer/geoengine_renderer.xml | 10 ++- .../records_panel/records_panel.esm.js | 59 ++++++++++++++ .../records_panel/records_panel.scss | 20 +++++ .../geoengine/records_panel/records_panel.xml | 76 +++++++++++++++++++ .../search_bar_records.esm.js | 21 +++++ .../search_bar_records/search_bar_records.xml | 27 +++++++ 8 files changed, 218 insertions(+), 9 deletions(-) create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.scss create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/records_panel.xml create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.esm.js create mode 100644 base_geoengine/static/src/js/views/geoengine/records_panel/search_bar_records/search_bar_records.xml diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index 90f544c5d..e5160d9d6 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -7,6 +7,7 @@ import {loadCSS, loadJS, templates} from "@web/core/assets"; import {GeoengineRecord} from "../geoengine_record/geoengine_record.esm"; import {LayersPanel} from "../layers_panel/layers_panel.esm"; +import {RecordsPanel} from "../records_panel/records_panel.esm"; import {rasterLayersStore} from "../../../raster_layers_store.esm"; import {vectorLayersStore} from "../../../vector_layers_store.esm"; import {useService} from "@web/core/utils/hooks"; @@ -59,9 +60,9 @@ export class GeoengineRenderer extends Component { onMounted(() => { // Retrives all vector layers in the store. - this.geometryFields = this.vectorLayersStore - .getVectors() - .map((layer) => layer.geo_field_id[1]); + this.geometryFields = this.vectorLayersStore.vectorsLayers.map( + (layer) => layer.geo_field_id[1] + ); this.vectorSources = []; this.renderMap(); @@ -107,7 +108,7 @@ export class GeoengineRenderer extends Component { new ol.layer.Group({ title: "Base maps", layers: this.createBackgroundLayers( - this.rasterLayersStore.getRasters() + this.rasterLayersStore.rastersLayers ), }), ], @@ -390,7 +391,7 @@ export class GeoengineRenderer extends Component { .getLayers() .getArray() .forEach((layer) => { - this.rasterLayersStore.getRasters().forEach((raster) => { + this.rasterLayersStore.rastersLayers.forEach((raster) => { if (raster.name === layer.get("title")) { layer.setVisible(raster.isVisible); } @@ -949,4 +950,4 @@ GeoengineRenderer.props = { data: {type: Object, optional: false}, openRecord: {type: Function, optional: false}, }; -GeoengineRenderer.components = {LayersPanel, GeoengineRecord}; +GeoengineRenderer.components = {LayersPanel, GeoengineRecord, RecordsPanel}; diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.scss b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.scss index 0be824969..214502b68 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.scss +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.scss @@ -6,7 +6,6 @@ .map_container { width: 100%; height: 100%; - padding: 0; } .view { diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml index 0d9e19066..29630e9e7 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.xml @@ -1,11 +1,17 @@ -
+
-
+
+
diff --git a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js index c6aa0c346..cde519140 100644 --- a/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js +++ b/base_geoengine/static/src/js/views/geoengine/geoengine_renderer/geoengine_renderer.esm.js @@ -985,7 +985,7 @@ export class GeoengineRenderer extends Component { openGroupsByDefault: true, domain: [], orderBy: [], - groupBy: {}, + groupBy: [], resModel: model, fields: fields, }; diff --git a/base_geoengine/tests/test_model.py b/base_geoengine/tests/test_model.py index 114212d0a..8afba32f9 100644 --- a/base_geoengine/tests/test_model.py +++ b/base_geoengine/tests/test_model.py @@ -1,10 +1,10 @@ # Copyright 2023 ACSONE SA/NV import geojson -from odoo_test_helper import FakeModelLoader from shapely import wkt from shapely.geometry import shape +from odoo.orm.model_classes import add_to_registry from odoo.tests.common import TransactionCase from ..fields import GeoPoint @@ -14,12 +14,24 @@ class TestModel(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.loader = FakeModelLoader(cls.env, cls.__module__) - cls.loader.backup_registry() - from .models import DummyZip, GeoModelTest, RetailMachine - cls.loader.update_registry((GeoModelTest, DummyZip, RetailMachine)) + add_to_registry(cls.registry, GeoModelTest) + cls.registry._setup_models__(cls.env.cr, ["geo.model.test"]) + cls.registry.init_models( + cls.env.cr, ["geo.model.test"], {"models_to_check": True} + ) + + add_to_registry(cls.registry, DummyZip) + cls.registry._setup_models__(cls.env.cr, ["dummy.zip"]) + cls.registry.init_models(cls.env.cr, ["dummy.zip"], {"models_to_check": True}) + + add_to_registry(cls.registry, RetailMachine) + cls.registry._setup_models__(cls.env.cr, ["retail.machine"]) + cls.registry.init_models( + cls.env.cr, ["retail.machine"], {"models_to_check": True} + ) + cls.geo_model = cls.env["geo.model.test"].create({}) cls.env["dummy.zip"].create( { @@ -145,7 +157,10 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - cls.loader.restore_registry() + cls.addClassCleanup(cls.registry.__delitem__, "geo.model.test") + cls.addClassCleanup(cls.registry.__delitem__, "retail.machine") + cls.addClassCleanup(cls.registry.__delitem__, "dummy.zip") + super().tearDownClass() def test_create_multipolygon_wkt_format(self):