pyarchinit-photogrammetry 1.3.1__tar.gz → 1.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyarchinit_photogrammetry-1.3.1/src/pyarchinit_photogrammetry.egg-info → pyarchinit_photogrammetry-1.3.2}/PKG-INFO +2 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/pyproject.toml +2 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/__init__.py +1 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/ortho.py +18 -2
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/image_views.py +70 -4
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/main_window.py +93 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/translations/en.json +4 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/gpkg.py +14 -3
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/qfield.py +1 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/qgis_link.py +2 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/plugins/api.py +70 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/plugins/manager.py +4 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2/src/pyarchinit_photogrammetry.egg-info}/PKG-INFO +2 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry.egg-info/requires.txt +1 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_ortho.py +6 -1
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_plugins.py +84 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_qfield.py +26 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/LICENSE +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/README.md +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/setup.cfg +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/ppg_launcher.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/__main__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/_env.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/_native.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/classify.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/learn.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/learned_net.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/learned_worker.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/sam.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/sam_env.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/ai/sam_worker.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/app.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/measures.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/munsell.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/pottery.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/proxies.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/relief.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/sections.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/stones.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/stratigraphy.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/terrain.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/timeline.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/archaeo/us_proposal.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/batch.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/bim/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/bim/ifc.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/cli.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/camera.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/chunk.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/crs.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/document.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/geometry.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/marker.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/paradata.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/pointcloud.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/progress.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/core/versions.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/demo.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/doctor.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/bundle.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/chunks.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/cleaning.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/colmap_log.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/colour.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/confidence.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/crop.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/dem.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/dem_edit.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/dense.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/diagnostics.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/elevation.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/fieldcheck.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/isolate.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/learned.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/masks.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/mesh_cut.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/meshing.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/multispectral.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/nodes.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/normalmap.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/overviews.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/panorama.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/patches.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/precision.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/probe.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/quality.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/region.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/satellite.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/sfm.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/texturing.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/thermal.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/tiepoints.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/tsdf.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/video.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/engine/visibility.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/__main__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/batch_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/calibration_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/dialogs.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/flow_layout.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/i18n.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/icons.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/logging_setup.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/matches_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/model_view.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/multispectral_pane.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/nodes_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/panels.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/plugins_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/pottery_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/resources/logo.svg +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/scene.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/start_page.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/table_export.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/theme.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/timeline_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/undo.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/update_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/us_proposal_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/gui/worker.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/integrations/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/integrations/metashape.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/integrations/photo3d.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/integrations/webodm.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/copc.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/exif.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/exports.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/flythrough.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/i3s.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/mesh_import.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/mesh_ply.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/pdf_report.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/report.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/report_content.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/scans.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/tables.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/io/web.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/markers/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/markers/gcp.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/markers/refine.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/markers/targets.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/plugins/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/plugins/index.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/plugins/scaffold.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/bridge.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/config.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/database.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/demo_db.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/media.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/pyarchinit/pyarchinit5_schema.sql +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/testing/__init__.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/testing/synthetic.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry/updates.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry.egg-info/SOURCES.txt +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry.egg-info/dependency_links.txt +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry.egg-info/entry_points.txt +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/src/pyarchinit_photogrammetry.egg-info/top_level.txt +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_alignment_modes.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_archaeo.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_batch.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_bim_ai.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_bundle.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_chunks.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_classify.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_cleaning.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_colmap_log.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_colour.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_dem_edit.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_dem_fill.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_dem_spikes.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_depth_mesh.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_diagnostics.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_elevation.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_env.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_exports_web.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_fieldcheck.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_fisheye_panorama.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_geometry.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_gui.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_gui_cleaning.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_gui_layers.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_gui_patches.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_gui_start.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_i18n.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_i3s.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_ifc_strat.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_integrations.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_isolate.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_learn.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_learned.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_marker_refine.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_markers.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_masks.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_measures.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_mesh_cut.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_mesh_ply.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_meshing_fallback.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_model_import.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_multispectral.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_munsell.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_native.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_nodes.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_normalmap.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_overviews.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_packaging.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_paradata.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_patches.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_photos.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_pipeline.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_pottery_demo.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_pottery_search.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_precision.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_probe.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_progress_dialog.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_proxies.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_pyarchinit.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_pyarchinit_media.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_quality_video.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_raster_detail.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_reference_cameras.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_region.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_regressions.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_relief.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_report.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_satellite.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_scalebars.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_scans.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_sfm_global_check.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_stones.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_texture.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_thermal.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_tiepoints.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_timeline.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_tools_3d.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_undo.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_updates.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_us_proposal.py +0 -0
- {pyarchinit_photogrammetry-1.3.1 → pyarchinit_photogrammetry-1.3.2}/tests/test_versions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyarchinit-photogrammetry
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Open-source photogrammetry engine for archaeology and BIM, integrated with PyArchInit
|
|
5
5
|
Author-email: Enzo Cocca <enzo.ccc@gmail.com>
|
|
6
6
|
License-Expression: GPL-2.0-or-later
|
|
@@ -32,6 +32,7 @@ Requires-Dist: sqlalchemy>=2.0
|
|
|
32
32
|
Requires-Dist: typer>=0.9
|
|
33
33
|
Requires-Dist: fpdf2>=2.8
|
|
34
34
|
Requires-Dist: openpyxl>=3.1
|
|
35
|
+
Requires-Dist: threadpoolctl>=3.1
|
|
35
36
|
Provides-Extra: mesh
|
|
36
37
|
Requires-Dist: open3d!=0.20.0,>=0.18; extra == "mesh"
|
|
37
38
|
Provides-Extra: bim
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyarchinit-photogrammetry"
|
|
7
|
-
version = "1.3.
|
|
7
|
+
version = "1.3.2"
|
|
8
8
|
description = "Open-source photogrammetry engine for archaeology and BIM, integrated with PyArchInit"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-2.0-or-later"
|
|
@@ -37,6 +37,7 @@ dependencies = [
|
|
|
37
37
|
"typer>=0.9",
|
|
38
38
|
"fpdf2>=2.8", # the processing report as PDF (io.pdf_report)
|
|
39
39
|
"openpyxl>=3.1", # the tables as Excel workbooks (io.tables)
|
|
40
|
+
"threadpoolctl>=3.1", # BLAS on one thread where results must not depend on the threads (engine.ortho)
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[project.optional-dependencies]
|
|
@@ -35,7 +35,7 @@ from .core import (ARCHAEO_CLASSES, ASPRS_CLASSES, Camera, Chunk, Document, Mark
|
|
|
35
35
|
from .core.progress import Cancelled, Progress, print_progress
|
|
36
36
|
from . import demo # noqa: E402 (ppg.demo.create_demo)
|
|
37
37
|
|
|
38
|
-
__version__ = "1.3.
|
|
38
|
+
__version__ = "1.3.2"
|
|
39
39
|
|
|
40
40
|
__all__ = ["app", "Document", "Chunk", "Camera", "Sensor", "Marker", "Projection", "Reference", "ScaleBar",
|
|
41
41
|
"PointCloud", "ASPRS_CLASSES", "ARCHAEO_CLASSES", "Progress", "Cancelled", "print_progress", "__version__"]
|
|
@@ -1203,11 +1203,27 @@ def build_orthomosaic(chunk: Chunk, resolution: float | None = None, surface: st
|
|
|
1203
1203
|
return out_path
|
|
1204
1204
|
|
|
1205
1205
|
|
|
1206
|
+
def _one_blas_thread():
|
|
1207
|
+
"""BLAS on one thread while the tiles are made: OpenBLAS (numpy on Linux and Windows) splits a
|
|
1208
|
+
product among its threads in a way that depends on how many calls run at once, and a row that
|
|
1209
|
+
lands in a remainder block is rounded by another kernel: one bit in a cell's coordinates was
|
|
1210
|
+
enough to pick another photo, so one worker and four gave different pixels. The tiles are
|
|
1211
|
+
already in parallel: one BLAS thread each is also the faster way."""
|
|
1212
|
+
try:
|
|
1213
|
+
from threadpoolctl import threadpool_limits
|
|
1214
|
+
except ImportError: # pragma: no cover - a dependency of the program
|
|
1215
|
+
import contextlib
|
|
1216
|
+
|
|
1217
|
+
return contextlib.nullcontext()
|
|
1218
|
+
return threadpool_limits(limits=1, user_api="blas")
|
|
1219
|
+
|
|
1220
|
+
|
|
1206
1221
|
def _run_tiles(ctx, tiles, workers: int, progress: Progress, put, start: float = 0.03, span: float = 0.9) -> None:
|
|
1207
1222
|
"""Make the tiles in parallel (at most twice the workers waiting) and hand each one to
|
|
1208
|
-
``put(r0, c0, block)`` in this thread as soon as it is ready
|
|
1223
|
+
``put(r0, c0, block)`` in this thread as soon as it is ready; the same pixels with any number
|
|
1224
|
+
of workers (:func:`_one_blas_thread`)."""
|
|
1209
1225
|
done = 0
|
|
1210
|
-
with ThreadPoolExecutor(workers) as pool:
|
|
1226
|
+
with _one_blas_thread(), ThreadPoolExecutor(workers) as pool:
|
|
1211
1227
|
queue = iter(tiles)
|
|
1212
1228
|
running = {}
|
|
1213
1229
|
try:
|
|
@@ -391,8 +391,10 @@ class RasterView(_ZoomView):
|
|
|
391
391
|
file) so that it opens at once; zooming in further, the visible part is read again from the
|
|
392
392
|
file at the resolution of the screen, up to the full one (``detail``), in a thread."""
|
|
393
393
|
|
|
394
|
-
DRAW_MODES = ("polygon", "line", "measure", "quota", "marker", "crop", "patch", "dem_edit", "probe"
|
|
395
|
-
|
|
394
|
+
DRAW_MODES = ("polygon", "line", "measure", "quota", "marker", "crop", "patch", "dem_edit", "probe",
|
|
395
|
+
"req_polygon", "req_line", "req_point")
|
|
396
|
+
AREA_MODES = ("crop", "patch", "dem_edit", "area", "chart", "req_polygon") # drag a box or click a polygon
|
|
397
|
+
REQUEST_MODES = ("req_polygon", "req_line", "req_point") # the drawing lent to a plugin (request_geometry)
|
|
396
398
|
SAM_TOOLS = ("tap", "box", "area")
|
|
397
399
|
|
|
398
400
|
mouse_world = Signal(float, float, object) # x, y, z or None
|
|
@@ -410,6 +412,9 @@ class RasterView(_ZoomView):
|
|
|
410
412
|
quota_clicked = Signal(float, float) # spot height at world x, y
|
|
411
413
|
marker_clicked = Signal(float, float) # a marker at world x, y (the height from the DEM)
|
|
412
414
|
probe_clicked = Signal(float, float) # a measuring point at world x, y (elevation, temperature, bands)
|
|
415
|
+
request_finished = Signal(object) # (N,2) world XY drawn for a request: polygon, line or one point
|
|
416
|
+
request_cancelled = Signal() # Esc during a request
|
|
417
|
+
raster_loaded = Signal() # a raster, an empty frame or nothing is now shown: layers must be drawn again
|
|
413
418
|
photos_at_point = Signal(float, float) # filter the photos that see world x, y
|
|
414
419
|
photos_in_area_requested = Signal() # filter the photos that frame the selected polygon
|
|
415
420
|
sam_click = Signal(float, float, int, bool) # x, y, label (1 add / 0 remove), True = a new object
|
|
@@ -521,6 +526,33 @@ class RasterView(_ZoomView):
|
|
|
521
526
|
self.tr = None
|
|
522
527
|
if text:
|
|
523
528
|
self.scene().addText(text)
|
|
529
|
+
self.raster_loaded.emit()
|
|
530
|
+
|
|
531
|
+
def show_frame(self, bounds, resolution: float, text: str = "") -> None:
|
|
532
|
+
"""An empty frame in world coordinates instead of a raster (``bounds`` = xmin, ymin, xmax,
|
|
533
|
+
ymax; ``resolution`` = metres per pixel of the view): layers and overlays of plugins can be
|
|
534
|
+
drawn on it with no orthophoto or DEM (a geophysical grid before the survey has one)."""
|
|
535
|
+
from rasterio.transform import from_origin
|
|
536
|
+
|
|
537
|
+
x0, y0, x1, y1 = (float(v) for v in bounds)
|
|
538
|
+
if not (x1 > x0 and y1 > y0) or not resolution > 0:
|
|
539
|
+
raise ValueError("an empty frame needs xmin < xmax, ymin < ymax and a positive resolution")
|
|
540
|
+
self._empty_scene()
|
|
541
|
+
w = max(1, int(np.ceil((x1 - x0) / resolution)))
|
|
542
|
+
h = max(1, int(np.ceil((y1 - y0) / resolution)))
|
|
543
|
+
self.path, self.kind, self.z = None, "frame", None
|
|
544
|
+
self.tr = from_origin(x0, y1, resolution, resolution)
|
|
545
|
+
self._src_size = self._base_size = (w, h)
|
|
546
|
+
self._dem_lookup = None
|
|
547
|
+
self.pixmap_item = None
|
|
548
|
+
frame = self.scene().addRect(QRectF(0, 0, w, h), self._pen("#9aa0a6", 1))
|
|
549
|
+
frame.setZValue(-2)
|
|
550
|
+
if text:
|
|
551
|
+
label = self.scene().addText(text)
|
|
552
|
+
label.setPos(4, 4)
|
|
553
|
+
self.setSceneRect(QRectF(0, 0, w, h))
|
|
554
|
+
self.fit()
|
|
555
|
+
self.raster_loaded.emit()
|
|
524
556
|
|
|
525
557
|
def load(self, path: str | Path, kind: str, max_side: int = 6000, bands=None) -> None:
|
|
526
558
|
import rasterio
|
|
@@ -589,6 +621,7 @@ class RasterView(_ZoomView):
|
|
|
589
621
|
self.setSceneRect(QRectF(0, 0, w, h))
|
|
590
622
|
self.fit()
|
|
591
623
|
self._view_changed()
|
|
624
|
+
self.raster_loaded.emit()
|
|
592
625
|
|
|
593
626
|
# ----------------------------------------------------------- full-resolution detail
|
|
594
627
|
def _view_changed(self, *_args) -> None:
|
|
@@ -1201,6 +1234,23 @@ class RasterView(_ZoomView):
|
|
|
1201
1234
|
self.clear_selection()
|
|
1202
1235
|
|
|
1203
1236
|
def keyPressEvent(self, ev) -> None:
|
|
1237
|
+
if self.mode in self.REQUEST_MODES:
|
|
1238
|
+
if ev.key() == Qt.Key.Key_Escape:
|
|
1239
|
+
self.set_mode(self.mode)
|
|
1240
|
+
self.request_cancelled.emit()
|
|
1241
|
+
return
|
|
1242
|
+
if ev.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
|
1243
|
+
self._finish_request()
|
|
1244
|
+
return
|
|
1245
|
+
if ev.key() == Qt.Key.Key_Backspace and self._clicks: # the last vertex away
|
|
1246
|
+
self._clicks.pop()
|
|
1247
|
+
self._click_xy.pop()
|
|
1248
|
+
if self._clicks:
|
|
1249
|
+
self._update_rubber()
|
|
1250
|
+
elif self._rubber is not None:
|
|
1251
|
+
self.scene().removeItem(self._rubber)
|
|
1252
|
+
self._rubber = None
|
|
1253
|
+
return
|
|
1204
1254
|
if self.mode == "sam":
|
|
1205
1255
|
if ev.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
|
1206
1256
|
self.sam_key.emit("accept")
|
|
@@ -1372,6 +1422,9 @@ class RasterView(_ZoomView):
|
|
|
1372
1422
|
self._clicks.append(sp)
|
|
1373
1423
|
self._click_xy.append(xy)
|
|
1374
1424
|
self._update_rubber()
|
|
1425
|
+
if self.mode == "req_point":
|
|
1426
|
+
self._finish_request()
|
|
1427
|
+
return
|
|
1375
1428
|
if self.mode in ("line", "measure") and len(self._clicks) == 2:
|
|
1376
1429
|
a, b = (np.array(p) for p in self._click_xy)
|
|
1377
1430
|
if self.mode == "line":
|
|
@@ -1388,6 +1441,9 @@ class RasterView(_ZoomView):
|
|
|
1388
1441
|
def mouseDoubleClickEvent(self, ev) -> None:
|
|
1389
1442
|
if self.mode == "sam": # a second press: nothing more (Enter accepts the mask)
|
|
1390
1443
|
return
|
|
1444
|
+
if self.mode == "req_line":
|
|
1445
|
+
self._finish_request()
|
|
1446
|
+
return
|
|
1391
1447
|
if self.mode in ("polygon", *self.AREA_MODES) and len(self._click_xy) >= 3:
|
|
1392
1448
|
xy = np.array(self._click_xy)
|
|
1393
1449
|
mode = self.mode
|
|
@@ -1397,8 +1453,18 @@ class RasterView(_ZoomView):
|
|
|
1397
1453
|
super().mouseDoubleClickEvent(ev)
|
|
1398
1454
|
|
|
1399
1455
|
def _area_signal(self, mode: str):
|
|
1400
|
-
return {"patch": self.patch_finished, "dem_edit": self.dem_edit_finished,
|
|
1401
|
-
"
|
|
1456
|
+
return {"patch": self.patch_finished, "dem_edit": self.dem_edit_finished, "area": self.area_finished,
|
|
1457
|
+
"chart": self.chart_finished, "req_polygon": self.request_finished}.get(mode, self.crop_finished)
|
|
1458
|
+
|
|
1459
|
+
def _finish_request(self) -> None:
|
|
1460
|
+
"""The geometry of a request, when it has enough vertices (polygon 3, line 2, point 1)."""
|
|
1461
|
+
need = {"req_polygon": 3, "req_line": 2, "req_point": 1}[self.mode]
|
|
1462
|
+
xy = [p for i, p in enumerate(self._click_xy) if i == 0 or not np.allclose(p, self._click_xy[i - 1])]
|
|
1463
|
+
if len(xy) < need:
|
|
1464
|
+
return
|
|
1465
|
+
mode = self.mode
|
|
1466
|
+
self.set_mode(mode)
|
|
1467
|
+
self.request_finished.emit(np.array(xy, float))
|
|
1402
1468
|
|
|
1403
1469
|
|
|
1404
1470
|
class PhotoView(_ZoomView):
|
|
@@ -11,7 +11,7 @@ import traceback
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
|
-
from PySide6.QtCore import QRectF, QSize, Qt, QTimer, QUrl
|
|
14
|
+
from PySide6.QtCore import QObject, QRectF, QSize, Qt, QTimer, QUrl, Signal
|
|
15
15
|
from PySide6.QtGui import QAction, QActionGroup, QDesktopServices, QKeySequence
|
|
16
16
|
from PySide6.QtWidgets import (QApplication, QDialog, QDialogButtonBox, QDockWidget, QFileDialog, QFrame,
|
|
17
17
|
QInputDialog, QLabel, QMainWindow, QMenu, QMessageBox, QPlainTextEdit, QPushButton,
|
|
@@ -76,6 +76,24 @@ def _it(value: float, decimals: int = 0) -> str:
|
|
|
76
76
|
return number(value, decimals)
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
class _GuiCalls(QObject):
|
|
80
|
+
"""Runs functions in the interface thread: emitted from any thread, received there (queued)."""
|
|
81
|
+
|
|
82
|
+
call = Signal(object)
|
|
83
|
+
|
|
84
|
+
def __init__(self, parent=None):
|
|
85
|
+
super().__init__(parent)
|
|
86
|
+
self.call.connect(self._run, Qt.ConnectionType.QueuedConnection)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _run(job) -> None:
|
|
90
|
+
function, args, kwargs = job
|
|
91
|
+
try:
|
|
92
|
+
function(*args, **kwargs)
|
|
93
|
+
except Exception: # a plugin's function never stops the window
|
|
94
|
+
log.exception("function run in the interface thread failed")
|
|
95
|
+
|
|
96
|
+
|
|
79
97
|
class _StatusBar(QStatusBar):
|
|
80
98
|
"""The status bar: its messages in the language of the interface (also those of the engine)."""
|
|
81
99
|
|
|
@@ -193,6 +211,10 @@ class MainWindow(QMainWindow):
|
|
|
193
211
|
self.ortho_view.area_requested.connect(self._area_selected)
|
|
194
212
|
self.ortho_view.patch_requested.connect(self.patch_with_selection)
|
|
195
213
|
self.ortho_view.line_finished.connect(self._section_drawn)
|
|
214
|
+
self._request = None # the drawing lent by request_geometry: (on_finished, on_cancelled)
|
|
215
|
+
self._gui_calls = _GuiCalls(self)
|
|
216
|
+
self.ortho_view.request_finished.connect(self._request_drawn)
|
|
217
|
+
self.ortho_view.request_cancelled.connect(lambda: self._end_request(cancelled=True))
|
|
196
218
|
self.ortho_view.measured.connect(lambda t: (self.statusBar().showMessage(t, 30000),
|
|
197
219
|
self.log_pane.info(t)))
|
|
198
220
|
self.ortho_view.quota_clicked.connect(self._quota_clicked)
|
|
@@ -567,6 +589,7 @@ class MainWindow(QMainWindow):
|
|
|
567
589
|
self._act(km, tr("Rimuovi tutte le maschere"), lambda: self.masks_remove(selected=False))
|
|
568
590
|
dm = m.addMenu(icon("polygon"), tr("Disegno su ortofoto"))
|
|
569
591
|
self.draw_group = QActionGroup(self)
|
|
592
|
+
self.draw_group.triggered.connect(lambda _a: self._end_request(cancelled=True))
|
|
570
593
|
self.draw_actions: dict[str, QAction] = {}
|
|
571
594
|
for mode, label, ic in (("pan", "Sposta / interroga", "pan"), ("select", "Seleziona", "select"),
|
|
572
595
|
("polygon", "Disegna unita' stratigrafica", "polygon"),
|
|
@@ -1086,6 +1109,75 @@ class MainWindow(QMainWindow):
|
|
|
1086
1109
|
if flag and self.history is not None and not self._task_done:
|
|
1087
1110
|
self.history.record()
|
|
1088
1111
|
|
|
1112
|
+
def mark_modified(self) -> None:
|
|
1113
|
+
"""The project has changes to save (a plugin changed ``chunk.meta`` or its files): the title
|
|
1114
|
+
shows it, *Salva* and the question at closing take it into account, Modifica > Annulla can
|
|
1115
|
+
take it back."""
|
|
1116
|
+
self._dirty(True)
|
|
1117
|
+
|
|
1118
|
+
def call_in_gui(self, function, *args, **kwargs) -> None:
|
|
1119
|
+
"""``function(*args, **kwargs)`` in the interface thread, soon: from a background step or an
|
|
1120
|
+
exporter, for whatever touches the window."""
|
|
1121
|
+
self._gui_calls.call.emit((function, args, kwargs))
|
|
1122
|
+
|
|
1123
|
+
# ---------------------------------------------------------------- drawing lent to plugins
|
|
1124
|
+
def request_geometry(self, kind: str, on_finished, on_cancelled=None, hint: str = "") -> bool:
|
|
1125
|
+
"""Lend the drawing of the 2D view: ``kind`` "polygon" (drag a box, or click the vertices and
|
|
1126
|
+
double click or Enter), "line" (click the vertices, double click or Enter to end) or "point"
|
|
1127
|
+
(one click). ``on_finished(xy)`` gets the vertices, ``(N, 2)`` in the coordinates of the chunk,
|
|
1128
|
+
in the interface thread; ``on_cancelled()`` when Esc, another tool of the drawing bar or another
|
|
1129
|
+
request ends it. Backspace drops the last vertex. Returns False when there is nothing to draw
|
|
1130
|
+
on (no orthophoto, DEM or frame)."""
|
|
1131
|
+
if kind not in ("polygon", "line", "point"):
|
|
1132
|
+
raise ValueError("kind: 'polygon', 'line' or 'point'")
|
|
1133
|
+
self._end_request(cancelled=True)
|
|
1134
|
+
view = self.ortho_view
|
|
1135
|
+
if view.tr is None and self.chunk is not None and (self.chunk.orthomosaic_path or self.chunk.dem_path):
|
|
1136
|
+
self._show_raster("ortho" if self.chunk.orthomosaic_path else "dem")
|
|
1137
|
+
if view.tr is None:
|
|
1138
|
+
self._warn("Costruisci prima l'ortofoto o il DEM.")
|
|
1139
|
+
if on_cancelled is not None:
|
|
1140
|
+
on_cancelled()
|
|
1141
|
+
return False
|
|
1142
|
+
self._request = (on_finished, on_cancelled)
|
|
1143
|
+
for action in self.draw_group.actions(): # no tool of the bar is the one drawing now
|
|
1144
|
+
action.setChecked(False)
|
|
1145
|
+
view.set_mode("req_" + kind)
|
|
1146
|
+
self.show_view(view)
|
|
1147
|
+
default = {"polygon": "Trascina un riquadro, oppure clic per i vertici e doppio clic o Invio per chiudere; "
|
|
1148
|
+
"Esc annulla",
|
|
1149
|
+
"line": "Clic per i vertici, doppio clic o Invio per finire; Backspace toglie l'ultimo, Esc annulla",
|
|
1150
|
+
"point": "Clic sul punto; Esc annulla"}[kind]
|
|
1151
|
+
self.statusBar().showMessage(hint or tr(default), 0)
|
|
1152
|
+
return True
|
|
1153
|
+
|
|
1154
|
+
def _request_drawn(self, xy) -> None:
|
|
1155
|
+
request, self._request = self._request, None
|
|
1156
|
+
self.ortho_view.set_mode("pan")
|
|
1157
|
+
self.draw_actions["pan"].setChecked(True)
|
|
1158
|
+
self.statusBar().clearMessage()
|
|
1159
|
+
if request is not None:
|
|
1160
|
+
try:
|
|
1161
|
+
request[0](np.asarray(xy, float))
|
|
1162
|
+
except Exception as exc:
|
|
1163
|
+
log.exception("the function of a drawing request failed")
|
|
1164
|
+
self._warn(tr("Il disegno non e' stato accettato: {0}", str(exc)))
|
|
1165
|
+
|
|
1166
|
+
def _end_request(self, cancelled: bool = False) -> None:
|
|
1167
|
+
"""A pending request ends (another tool, another request, Esc): its ``on_cancelled``."""
|
|
1168
|
+
request, self._request = self._request, None
|
|
1169
|
+
if request is None:
|
|
1170
|
+
return
|
|
1171
|
+
if self.ortho_view.mode in self.ortho_view.REQUEST_MODES:
|
|
1172
|
+
self.ortho_view.set_mode("pan")
|
|
1173
|
+
self.draw_actions["pan"].setChecked(True)
|
|
1174
|
+
self.statusBar().clearMessage()
|
|
1175
|
+
if cancelled and request[1] is not None:
|
|
1176
|
+
try:
|
|
1177
|
+
request[1]()
|
|
1178
|
+
except Exception:
|
|
1179
|
+
log.exception("the cancel function of a drawing request failed")
|
|
1180
|
+
|
|
1089
1181
|
def _update_title(self) -> None:
|
|
1090
1182
|
name = self.doc.path.name if self.doc.path else tr("senza nome")
|
|
1091
1183
|
site = self.project_site()
|
|
@@ -364,6 +364,7 @@
|
|
|
364
364
|
"Classificazione automatica (regole)": "Automatic classification (rules)",
|
|
365
365
|
"Classificazione con il classificatore": "Classification with the classifier",
|
|
366
366
|
"Classificazione della nuvola": "Classification of the cloud",
|
|
367
|
+
"Clic per i vertici, doppio clic o Invio per finire; Backspace toglie l'ultimo, Esc annulla": "Click the vertices, double click or Enter to end; Backspace drops the last one, Esc cancels",
|
|
367
368
|
"Clic per i vertici, doppio clic per chiudere, tasto destro per annullare": "Click for the vertices, double click to close, right click to cancel",
|
|
368
369
|
"Clic per selezionare, Maiusc/Cmd+clic per aggiungere o togliere, trascina per un riquadro; Canc elimina, Unisci fonde le unita', Esc deseleziona": "Click to select, Shift/Cmd+click to add or remove, drag for a box; Delete deletes, Merge merges the units, Esc deselects",
|
|
369
370
|
"Clic su un punto del modello o della nuvola: le foto che lo vedono, come Filter Photos by Point di Metashape": "Click a point of the model or the cloud: the photos that see it, as Metashape's Filter Photos by Point",
|
|
@@ -372,6 +373,7 @@
|
|
|
372
373
|
"Clic su un punto: un marker con la quota del DEM, proiettato sulle foto che lo vedono (come Aggiungi marker in Metashape); con due marker si fa una barra di scala": "Click a point: a marker with the height of the DEM, projected on the photos that see it (as Add marker in Metashape); two markers make a scale bar",
|
|
373
374
|
"Clic su un punto: un punto di misura con coordinate, quota del DEM, temperatura, bande e indici letti lì a piena risoluzione (layer Punti di misura, esportabile e in QGIS)": "Click on a point: a measuring point with coordinates, DEM elevation, temperature, bands and indices read there at full resolution (layer Measuring points, exportable and in QGIS)",
|
|
374
375
|
"Clic sui vertici dell'area, doppio clic (o Invio) chiude, Esc annulla": "Click the vertices of the area, double click (or Enter) closes, Esc cancels",
|
|
376
|
+
"Clic sul punto; Esc annulla": "Click the point; Esc cancels",
|
|
375
377
|
"Clic sull'ortofoto, termica o multispettrale: un punto con coordinate, quota del DEM, temperatura, bande e indici letti lì a piena risoluzione": "Click on the orthomosaic, thermal or multispectral: a point with coordinates, DEM elevation, temperature, bands and indices read there at full resolution",
|
|
376
378
|
"Codici": "Codes",
|
|
377
379
|
"Collega alle US (selezione multipla):": "Link to the US (multiple selection):",
|
|
@@ -1840,6 +1842,7 @@
|
|
|
1840
1842
|
"Traccia una sezione: Disegno > Traccia sezione, poi due clic sull'ortofoto.": "Trace a section: Drawing > Trace section, then two clicks on the orthophoto.",
|
|
1841
1843
|
"Trascina per spostare, rotella per lo zoom, clic su un elemento per i suoi attributi": "Drag to pan, wheel to zoom, click on a feature for its attributes",
|
|
1842
1844
|
"Trascina un riquadro attorno alla tabella colori (ColorChecker da 24 colori), oppure clic per i vertici e doppio clic per chiudere": "Drag a box around the colour chart (24-patch ColorChecker), or click the vertices and double click to close",
|
|
1845
|
+
"Trascina un riquadro, oppure clic per i vertici e doppio clic o Invio per chiudere; Esc annulla": "Drag a box, or click the vertices and double click or Enter to close; Esc cancels",
|
|
1843
1846
|
"Trascina un riquadro, oppure clic per i vertici e doppio clic per chiudere il poligono: poi scegli i prodotti da esportare ritagliati o da ritagliare nel progetto": "Drag a box, or click for the vertices and double click to close the polygon: then choose the products to export cropped or to crop in the project",
|
|
1844
1847
|
"Trascina un riquadro, oppure clic per i vertici e doppio clic per chiudere: area in pianta e superficie 3D (dal DEM e dal modello), pendenza media, quote": "Drag a box, or click for the vertices and double click to close: plan area and 3D surface (from the DEM and from the model), mean slope, heights",
|
|
1845
1848
|
"Trascina un riquadro, oppure clic per i vertici e doppio clic per chiudere: poi scegli da quali foto prendere i colori dell'area (alberi, veicoli, persone, cuciture)": "Drag a box, or click for the vertices and double click to close: then choose from which photos to take the colours of the area (trees, vehicles, people, seams)",
|
|
@@ -2325,6 +2328,7 @@
|
|
|
2325
2328
|
"Il chunk {0} e' stato prima messo in bolla (come per il DEM).": "The chunk {0} was levelled first (as for the DEM).",
|
|
2326
2329
|
"Il classificatore impara dai punti di cui conosci la classe: con il lazo (vista 3D) assegna la classe giusta ad alcuni gruppi di punti di ogni tipo (almeno due classi), poi addestralo. Usa la geometria attorno a ogni punto a tre scale, l'altezza sul terreno e il colore.\n\nClassi corrette a mano: {0}.\nClassi presenti: {1}.": "The classifier learns from the points whose class you know: with the lasso (3D view) assign the right class to a few groups of points of every kind (at least two classes), then train it. It uses the geometry around every point at three scales, the height above the ground and the colour.\n\nClasses corrected by hand: {0}.\nClasses present: {1}.",
|
|
2327
2330
|
"Il database contiene {0} siti (scavi).": "The database holds {0} sites (excavations).",
|
|
2331
|
+
"Il disegno non e' stato accettato: {0}": "The drawing was not accepted: {0}",
|
|
2328
2332
|
"Il modello importato e' a {0} m dai dati del chunk: controlla il sistema di riferimento, lo spostamento, la scala e l'asse verticale del file. Il modello di prima e' tra le versioni (tasto destro sul modello nell'area di lavoro).": "The imported model lies {0} m from the data of the chunk: check the coordinate system, the shift, the scale and the vertical axis of the file. The previous model is among the versions (right click on the model in the workspace).",
|
|
2329
2333
|
"Il piano a quota {0} m non taglia il modello: nessuna pianta": "The plane at height {0} m does not cut the model: no plan",
|
|
2330
2334
|
"Il prospetto «{0}» non ha piu' i suoi file.": "The elevation «{0}» no longer has its files.",
|
|
@@ -68,6 +68,14 @@ def is_geopackage(path: str | Path) -> bool:
|
|
|
68
68
|
return False
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
def refuse_foreign(path: str | Path) -> None:
|
|
72
|
+
""":class:`FileExistsError` when ``path`` is a file with content that is not a GeoPackage: the
|
|
73
|
+
program never deletes or rewrites a file it did not make."""
|
|
74
|
+
path = Path(path)
|
|
75
|
+
if path.exists() and (path.is_dir() or path.stat().st_size) and not is_geopackage(path):
|
|
76
|
+
raise FileExistsError(f"{path} exists and is not a GeoPackage: it was left as it is, choose another file")
|
|
77
|
+
|
|
78
|
+
|
|
71
79
|
def connect(path: str | Path) -> sqlite3.Connection:
|
|
72
80
|
"""Connection in autocommit mode (transactions are explicit), waiting for other writers."""
|
|
73
81
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -136,12 +144,15 @@ def replace_rows(con: sqlite3.Connection, table: str, columns: list[str], featur
|
|
|
136
144
|
|
|
137
145
|
def write_table(path: str | Path, table: str, geometry_type: str, columns: dict[str, str], features,
|
|
138
146
|
crs: str | None, identifier: str | None = None) -> Path:
|
|
139
|
-
"""Write one feature table into a GeoPackage (created when missing; other tables kept).
|
|
147
|
+
"""Write one feature table into a GeoPackage (created when missing; other tables kept). A file
|
|
148
|
+
that exists and is not a GeoPackage - another database, a document chosen by mistake - is never
|
|
149
|
+
touched: :class:`FileExistsError`. An empty file (left by a save dialog) is used."""
|
|
140
150
|
path = Path(path)
|
|
141
151
|
srs = srs_of(crs)
|
|
142
152
|
new = not is_geopackage(path)
|
|
143
153
|
if new and path.exists():
|
|
144
|
-
path
|
|
154
|
+
refuse_foreign(path)
|
|
155
|
+
path.unlink() # empty: nothing to lose
|
|
145
156
|
con = connect(path)
|
|
146
157
|
try:
|
|
147
158
|
con.execute("BEGIN IMMEDIATE")
|
|
@@ -188,5 +199,5 @@ def read_table(path: str | Path, table: str) -> list[tuple[object, dict]]:
|
|
|
188
199
|
con.close()
|
|
189
200
|
|
|
190
201
|
|
|
191
|
-
__all__ = ["write_table", "is_geopackage", "srs_of", "blob", "create", "ensure_table", "replace_rows", "connect",
|
|
202
|
+
__all__ = ["write_table", "is_geopackage", "refuse_foreign", "srs_of", "blob", "create", "ensure_table", "replace_rows", "connect",
|
|
192
203
|
"quote", "geometry", "read_table"]
|
|
@@ -175,6 +175,7 @@ def export_package(chunk, folder: str | os.PathLike, resolution: float | None =
|
|
|
175
175
|
crs = None if crs_mod.is_local(chunk.crs) else chunk.crs
|
|
176
176
|
gp = folder / GPKG
|
|
177
177
|
if gp.exists():
|
|
178
|
+
gpkg.refuse_foreign(gp) # an earlier package is written again, a file of something else stays
|
|
178
179
|
gp.unlink()
|
|
179
180
|
progress(0.05, "QField: layers")
|
|
180
181
|
units = [(wkt.loads(u["wkt"]), _unit_row(u)) for u in d["units"]]
|
|
@@ -181,6 +181,8 @@ class LiveLink:
|
|
|
181
181
|
|
|
182
182
|
groups = self._group(layers)
|
|
183
183
|
new = not gpkg.is_geopackage(self.path)
|
|
184
|
+
if new:
|
|
185
|
+
gpkg.refuse_foreign(self.path) # never write the drawings into another file of that name
|
|
184
186
|
if new:
|
|
185
187
|
self._signatures = {}
|
|
186
188
|
todo = {t: f for t, f in groups.items() if force or new or self._signatures.get(t) != self._signature(f)}
|
|
@@ -77,6 +77,7 @@ class Contributions:
|
|
|
77
77
|
actions: list = field(default_factory=list)
|
|
78
78
|
commands: dict = field(default_factory=dict)
|
|
79
79
|
exporters: list = field(default_factory=list)
|
|
80
|
+
connections: list = field(default_factory=list) # (signal, slot) disconnected when the plugin goes away
|
|
80
81
|
|
|
81
82
|
|
|
82
83
|
class Context:
|
|
@@ -154,6 +155,75 @@ class Context:
|
|
|
154
155
|
if method is not None:
|
|
155
156
|
method()
|
|
156
157
|
|
|
158
|
+
# ------------------------------------------------------------------ the window (since 1.3.2)
|
|
159
|
+
def request_polygon(self, on_finished: Callable, on_cancelled: Callable | None = None, hint: str = "") -> bool:
|
|
160
|
+
"""Let the user draw a polygon on the 2D view with the program's own tool (drag a box, or click
|
|
161
|
+
the vertices and double click or Enter; Backspace drops the last vertex, Esc cancels):
|
|
162
|
+
``on_finished(xy)`` gets the vertices, an ``(N, 2)`` array in the coordinates of the chunk, in the
|
|
163
|
+
interface thread; ``on_cancelled()`` when the user picks another tool or another request comes.
|
|
164
|
+
``hint``: the text of the status bar. False (and ``on_cancelled``) when there is nothing to draw
|
|
165
|
+
on; in the command line there is no drawing (``RuntimeError``)."""
|
|
166
|
+
return self._request("polygon", on_finished, on_cancelled, hint)
|
|
167
|
+
|
|
168
|
+
def request_line(self, on_finished: Callable, on_cancelled: Callable | None = None, hint: str = "") -> bool:
|
|
169
|
+
"""As :meth:`request_polygon` for a line of two or more vertices (double click or Enter ends)."""
|
|
170
|
+
return self._request("line", on_finished, on_cancelled, hint)
|
|
171
|
+
|
|
172
|
+
def request_point(self, on_finished: Callable, on_cancelled: Callable | None = None, hint: str = "") -> bool:
|
|
173
|
+
"""As :meth:`request_polygon` for one point: ``on_finished`` gets a ``(1, 2)`` array."""
|
|
174
|
+
return self._request("point", on_finished, on_cancelled, hint)
|
|
175
|
+
|
|
176
|
+
def _request(self, kind, on_finished, on_cancelled, hint) -> bool:
|
|
177
|
+
if self.window is None:
|
|
178
|
+
raise RuntimeError("drawing on the view needs the window: not in the command line")
|
|
179
|
+
return self.window.request_geometry(kind, on_finished, on_cancelled, hint)
|
|
180
|
+
|
|
181
|
+
def on_raster_loaded(self, callback: Callable[[], object]) -> None:
|
|
182
|
+
"""``callback()`` each time the 2D view shows another raster, an empty frame or nothing: the
|
|
183
|
+
layers and overlays of a plugin are gone with the old one and are drawn again there.
|
|
184
|
+
Disconnected by itself when the plugin is disabled. Nothing in the command line."""
|
|
185
|
+
view = getattr(self.window, "ortho_view", None)
|
|
186
|
+
if view is None:
|
|
187
|
+
return
|
|
188
|
+
view.raster_loaded.connect(callback)
|
|
189
|
+
self.contributions.connections.append((view.raster_loaded, callback))
|
|
190
|
+
|
|
191
|
+
def show_frame(self, bounds, resolution: float, text: str = "") -> None:
|
|
192
|
+
"""An empty frame on the 2D view (``bounds`` = xmin, ymin, xmax, ymax in the coordinates of the
|
|
193
|
+
chunk, ``resolution`` metres per pixel of the view) when the chunk has no orthophoto or DEM to
|
|
194
|
+
draw on: then layers and overlays can be added as usual."""
|
|
195
|
+
view = getattr(self.window, "ortho_view", None)
|
|
196
|
+
if view is None:
|
|
197
|
+
raise RuntimeError("the 2D view needs the window: not in the command line")
|
|
198
|
+
view.show_frame(bounds, resolution, text)
|
|
199
|
+
|
|
200
|
+
def mark_modified(self) -> None:
|
|
201
|
+
"""The project has changes to save (``chunk.meta`` or files of the plugin changed): the window
|
|
202
|
+
shows it and asks to save at closing. Nothing in the command line, where the plugin saves."""
|
|
203
|
+
method = getattr(self.window, "mark_modified", None)
|
|
204
|
+
if method is not None:
|
|
205
|
+
method()
|
|
206
|
+
|
|
207
|
+
def call_in_gui(self, function: Callable, *args, **kwargs) -> None:
|
|
208
|
+
"""``function(*args, **kwargs)`` in the interface thread, soon: from the function given to
|
|
209
|
+
:meth:`run` or from an exporter, for anything that touches the window. At once in the command
|
|
210
|
+
line."""
|
|
211
|
+
method = getattr(self.window, "call_in_gui", None)
|
|
212
|
+
if method is None:
|
|
213
|
+
function(*args, **kwargs)
|
|
214
|
+
else:
|
|
215
|
+
method(function, *args, **kwargs)
|
|
216
|
+
|
|
217
|
+
def release(self) -> None:
|
|
218
|
+
"""What the plugin connected through the context, disconnected (the manager calls it after
|
|
219
|
+
:meth:`Plugin.deactivate`)."""
|
|
220
|
+
for signal, slot in self.contributions.connections:
|
|
221
|
+
try:
|
|
222
|
+
signal.disconnect(slot)
|
|
223
|
+
except (RuntimeError, TypeError):
|
|
224
|
+
pass
|
|
225
|
+
self.contributions.connections.clear()
|
|
226
|
+
|
|
157
227
|
def run(self, title: str, function: Callable, done: Callable | None = None) -> object:
|
|
158
228
|
"""``function(progress)`` with a progress bar: in the background in the window (``done(result)``
|
|
159
229
|
afterwards, in the interface thread), at once in the command line (``done`` too)."""
|
|
@@ -187,6 +187,8 @@ class Manager:
|
|
|
187
187
|
info.plugin.deactivate()
|
|
188
188
|
except Exception as exc:
|
|
189
189
|
log.warning("plugin %s: deactivate failed: %s", info.name, exc)
|
|
190
|
+
if info.context is not None:
|
|
191
|
+
info.context.release()
|
|
190
192
|
info.active, info.plugin, info.context = False, None, None
|
|
191
193
|
|
|
192
194
|
def remove(self, name: str) -> None:
|
|
@@ -199,6 +201,8 @@ class Manager:
|
|
|
199
201
|
info.plugin.deactivate()
|
|
200
202
|
except Exception:
|
|
201
203
|
pass
|
|
204
|
+
if info.context is not None:
|
|
205
|
+
info.context.release()
|
|
202
206
|
shutil.rmtree(info.location)
|
|
203
207
|
self.plugins = [i for i in self.plugins if i.name != name]
|
|
204
208
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyarchinit-photogrammetry
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Open-source photogrammetry engine for archaeology and BIM, integrated with PyArchInit
|
|
5
5
|
Author-email: Enzo Cocca <enzo.ccc@gmail.com>
|
|
6
6
|
License-Expression: GPL-2.0-or-later
|
|
@@ -32,6 +32,7 @@ Requires-Dist: sqlalchemy>=2.0
|
|
|
32
32
|
Requires-Dist: typer>=0.9
|
|
33
33
|
Requires-Dist: fpdf2>=2.8
|
|
34
34
|
Requires-Dist: openpyxl>=3.1
|
|
35
|
+
Requires-Dist: threadpoolctl>=3.1
|
|
35
36
|
Provides-Extra: mesh
|
|
36
37
|
Requires-Dist: open3d!=0.20.0,>=0.18; extra == "mesh"
|
|
37
38
|
Provides-Extra: bim
|
|
@@ -44,7 +44,12 @@ def test_surfaces_and_workers(processed, scene, tmp_path):
|
|
|
44
44
|
assert src.overviews(1) # pyramids for a quick display
|
|
45
45
|
many = ch.build_orthomosaic(resolution=0.004, workers=4)
|
|
46
46
|
with rasterio.open(many) as src:
|
|
47
|
-
|
|
47
|
+
b = src.read()
|
|
48
|
+
differ = np.any(a != b, axis=0)
|
|
49
|
+
if differ.any(): # say where, if it ever happens again (it did with OpenBLAS splitting products)
|
|
50
|
+
rows, cols = np.nonzero(differ)
|
|
51
|
+
raise AssertionError(f"1 and 4 workers: {int(differ.sum())} pixels differ, rows {rows.min()}-{rows.max()}, "
|
|
52
|
+
f"columns {cols.min()}-{cols.max()}, up to {int(np.abs(a.astype(int) - b).max())}")
|
|
48
53
|
worst = _targets_error(many, scene)
|
|
49
54
|
assert worst < 0.005, f"targets in the orthomosaic off by up to {worst * 1000:.2f} mm"
|
|
50
55
|
# a true orthophoto on the mesh (vertical rays), and from the dense cloud alone
|